6 if ( typeof define ===
"function" && define.amd ) {
7 define( [
'JSRootPainter',
'd3',
'JSRootMath'], factory );
8 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
9 factory(require(
"./JSRootCore.js"), require(
"d3"), require(
"./JSRootMath.js"));
11 if (typeof d3 !=
'object')
12 throw new Error(
'This extension requires d3.js',
'JSRootPainter.more.js');
13 if (typeof JSROOT ==
'undefined')
14 throw new Error(
'JSROOT is not defined',
'JSRootPainter.more.js');
15 if (typeof JSROOT.Painter !=
'object')
16 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.more.js');
19 } (
function(JSROOT, d3) {
23 JSROOT.sources.push(
"more2d");
26 var text = this.GetObject(),
27 w = this.pad_width(), h = this.pad_height(),
28 pos_x = text.fX, pos_y = text.fY,
29 tcolor = this.get_color(text.fTextColor),
31 fact = 1., textsize = text.fTextSize || 0.05,
32 main = this.frame_painter();
34 if (text.TestBit(JSROOT.BIT(14))) {
37 }
else if (main && !main.mode3d) {
39 w = this.frame_width();
40 h = this.frame_height();
41 use_frame =
"upper_layer";
42 }
else if (this.root_pad() !== null) {
49 if (!tcolor) tcolor =
'black';
52 this.CreateG(use_frame);
54 this.draw_g.attr(
"transform",null);
56 this.pos_x = this.AxisToSvg(
"x", pos_x, this.isndc);
57 this.pos_y = this.AxisToSvg(
"y", pos_y, this.isndc);
59 var arg = { align: text.fTextAlign, x: this.pos_x, y: this.pos_y, text: text.fTitle, color: tcolor, latex: 0 };
61 if (text.fTextAngle) arg.rotate = -text.fTextAngle;
63 if (text._typename ==
'TLatex') { arg.latex = 1; fact = 0.9; }
else
64 if (text._typename ==
'TMathText') { arg.latex = 2; fact = 0.8; }
66 this.StartTextDrawing(text.fTextFont, Math.round((textsize>1) ? textsize : textsize*Math.min(w,h)*fact));
70 this.FinishTextDrawing();
72 this.pos_dx = this.pos_dy = 0;
75 this.moveDrag =
function(dx,dy) {
78 this.draw_g.attr(
"transform",
"translate(" + this.pos_dx +
"," + this.pos_dy +
")");
82 this.moveEnd =
function(not_changed) {
83 if (not_changed)
return;
84 var text = this.GetObject();
85 text.fX = this.SvgToAxis(
"x", this.pos_x + this.pos_dx, this.isndc),
86 text.fY = this.SvgToAxis(
"y", this.pos_y + this.pos_dy, this.isndc);
87 this.WebCanvasExec(
"SetX(" + text.fX +
");;SetY(" + text.fY +
");;");
97 var line = this.GetObject(),
98 lineatt =
new JSROOT.TAttLineHandler(line),
99 kLineNDC = JSROOT.BIT(14),
100 isndc = line.TestBit(kLineNDC);
107 .attr(
"x1", this.AxisToSvg(
"x", line.fX1, isndc))
108 .attr(
"y1", this.AxisToSvg(
"y", line.fY1, isndc))
109 .attr(
"x2", this.AxisToSvg(
"x", line.fX2, isndc))
110 .attr(
"y2", this.AxisToSvg(
"y", line.fY2, isndc))
116 function drawPolyLine() {
121 var polyline = this.GetObject(),
122 lineatt =
new JSROOT.TAttLineHandler(polyline),
123 fillatt = this.createAttFill(polyline),
124 kPolyLineNDC = JSROOT.BIT(14),
125 isndc = polyline.TestBit(kPolyLineNDC),
126 cmd =
"", func = this.AxisToSvgFunc(isndc);
128 for (var n=0;n<=polyline.fLastPoint;++n)
129 cmd += ((n>0) ?
"L" :
"M") + func.x(polyline.fX[n]) +
"," + func.y(polyline.fY[n]);
131 if (polyline._typename !=
"TPolyLine") fillatt.SetSolidColor(
"none");
133 if (!fillatt.empty()) cmd+=
"Z";
144 function drawEllipse() {
146 var ellipse = this.GetObject();
148 this.createAttLine({ attr: ellipse });
149 this.createAttFill({ attr: ellipse });
154 var x = this.AxisToSvg(
"x", ellipse.fX1),
155 y = this.AxisToSvg(
"y", ellipse.fY1),
156 rx = this.AxisToSvg(
"x", ellipse.fX1 + ellipse.fR1) - x,
157 ry = y - this.AxisToSvg(
"y", ellipse.fY1 + ellipse.fR2);
159 if (ellipse._typename ==
"TCrown") {
160 if (ellipse.fR1 <= 0) {
162 rx = this.AxisToSvg(
"x", ellipse.fX1 + ellipse.fR2) - x;
164 var rx1 = rx, ry2 = ry,
165 ry1 = y - this.AxisToSvg(
"y", ellipse.fY1 + ellipse.fR1),
166 rx2 = this.AxisToSvg(
"x", ellipse.fX1 + ellipse.fR2) - x;
168 var elem = this.draw_g
169 .attr(
"transform",
"translate("+x+
","+y+
")")
171 .call(this.lineatt.func)
172 .call(this.fillatt.func);
174 if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360)) {
175 elem.attr(
"d",
"M-"+rx1+
",0" +
176 "A"+rx1+
","+ry1+
",0,1,0,"+rx1+
",0" +
177 "A"+rx1+
","+ry1+
",0,1,0,-"+rx1+
",0" +
179 "A"+rx2+
","+ry2+
",0,1,0,"+rx2+
",0" +
180 "A"+rx2+
","+ry2+
",0,1,0,-"+rx2+
",0");
183 var large_arc = (ellipse.fPhimax-ellipse.fPhimin>=180) ? 1 : 0;
185 var a1 = ellipse.fPhimin*Math.PI/180, a2 = ellipse.fPhimax*Math.PI/180,
186 dx1 = Math.round(rx1*Math.cos(a1)), dy1 = Math.round(ry1*Math.sin(a1)),
187 dx2 = Math.round(rx1*Math.cos(a2)), dy2 = Math.round(ry1*Math.sin(a2)),
188 dx3 = Math.round(rx2*Math.cos(a1)), dy3 = Math.round(ry2*Math.sin(a1)),
189 dx4 = Math.round(rx2*Math.cos(a2)), dy4 = Math.round(ry2*Math.sin(a2));
191 elem.attr(
"d",
"M"+dx2+
","+dy2+
192 "A"+rx1+
","+ry1+
",0,"+large_arc+
",0,"+dx1+
","+dy1+
194 "A"+rx2+
","+ry2+
",0,"+large_arc+
",1,"+dx4+
","+dy4+
"Z");
201 if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360) && (ellipse.fTheta == 0)) {
203 this.draw_g.append(
"svg:ellipse")
204 .attr(
"cx", x).attr(
"cy", y)
205 .attr(
"rx", rx).attr(
"ry", ry)
206 .call(this.lineatt.func).call(this.fillatt.func);
212 var ct = Math.cos(ellipse.fTheta*Math.PI/180),
213 st = Math.sin(ellipse.fTheta*Math.PI/180),
214 dx1 = rx * Math.cos(ellipse.fPhimin*Math.PI/180),
215 dy1 = ry * Math.sin(ellipse.fPhimin*Math.PI/180),
216 x1 = dx1*ct - dy1*st,
217 y1 = -dx1*st - dy1*ct,
218 dx2 = rx * Math.cos(ellipse.fPhimax*Math.PI/180),
219 dy2 = ry * Math.sin(ellipse.fPhimax*Math.PI/180),
220 x2 = dx2*ct - dy2*st,
221 y2 = -dx2*st - dy2*ct;
224 .attr(
"transform",
"translate("+x+
","+y+
")")
227 "L" + Math.round(x1) +
"," + Math.round(y1) +
228 "A"+rx+
","+ry +
"," + Math.round(-ellipse.fTheta) +
",1,0," + Math.round(x2) +
"," + Math.round(y2) +
230 .call(this.lineatt.func).call(this.fillatt.func);
236 var pie = this.GetObject();
241 var xc = this.AxisToSvg(
"x", pie.fX),
242 yc = this.AxisToSvg(
"y", pie.fY),
243 rx = this.AxisToSvg(
"x", pie.fX + pie.fRadius) - xc,
244 ry = this.AxisToSvg(
"y", pie.fY + pie.fRadius) - yc;
246 this.draw_g.attr(
"transform",
"translate("+xc+
","+yc+
")");
249 var nb = pie.fPieSlices.length, total = 0,
250 af = (pie.fAngularOffset*Math.PI)/180,
251 x1 = Math.round(rx*Math.cos(af)), y1 = Math.round(ry*Math.sin(af));
253 for (var n=0;n<nb; n++)
254 total += pie.fPieSlices[n].fValue;
256 for (var n=0; n<nb; n++) {
257 var slice = pie.fPieSlices[n],
258 lineatt =
new JSROOT.TAttLineHandler({attr: slice}),
259 fillatt = this.createAttFill(slice);
261 af += slice.fValue/total*2*Math.PI;
262 var x2 = Math.round(rx*Math.cos(af)), y2 = Math.round(ry*Math.sin(af));
266 .attr(
"d",
"M0,0L"+x1+
","+y1+
"A"+rx+
","+ry+
",0,0,0,"+x2+
","+y2+
"z")
277 var box = this.GetObject(),
278 opt = this.OptionsAsString(),
279 draw_line = (opt.toUpperCase().indexOf(
"L")>=0),
280 lineatt = this.createAttLine(box),
281 fillatt = this.createAttFill(box);
286 var x1 = this.AxisToSvg(
"x", box.fX1),
287 x2 = this.AxisToSvg(
"x", box.fX2),
288 y1 = this.AxisToSvg(
"y", box.fY1),
289 y2 = this.AxisToSvg(
"y", box.fY2),
290 xx = Math.min(x1,x2), yy = Math.min(y1,y2),
291 ww = Math.abs(x2-x1), hh = Math.abs(y1-y2);
294 if (!fillatt.empty() && !draw_line) lineatt.color =
"none";
298 .attr(
"x", xx).attr(
"y", yy)
304 if (box.fBorderMode && box.fBorderSize && (fillatt.color!==
'none')) {
305 var pww = box.fBorderSize, phh = box.fBorderSize,
306 side1 =
"M"+xx+
","+yy +
"h"+ww +
"l"+(-pww)+
","+phh +
"h"+(2*pww-ww) +
307 "v"+(hh-2*phh)+
"l"+(-pww)+
","+phh +
"z",
308 side2 =
"M"+(xx+ww)+
","+(yy+hh) +
"v"+(-hh) +
"l"+(-pww)+
","+phh +
"v"+(hh-2*phh)+
309 "h"+(2*pww-ww) +
"l"+(-pww)+
","+phh +
"z";
311 if (box.fBorderMode<0) { var s = side1; side1 = side2; side2 = s; }
313 this.draw_g.append(
"svg:path")
315 .style(
"stroke",
"none")
317 .style(
"fill", d3.rgb(fillatt.color).brighter(0.5).toString());
319 this.draw_g.append(
"svg:path")
321 .style(
"stroke",
"none")
323 .style(
"fill", d3.rgb(fillatt.color).darker(0.5).toString());
329 function drawMarker() {
330 var marker = this.GetObject(),
331 att =
new JSROOT.TAttMarkerHandler(marker),
332 kMarkerNDC = JSROOT.BIT(14),
333 isndc = marker.TestBit(kMarkerNDC);
338 var x = this.AxisToSvg(
"x", marker.fX, isndc),
339 y = this.AxisToSvg(
"y", marker.fY, isndc),
340 path = att.create(x,y);
343 this.draw_g.append(
"svg:path")
350 function drawPolyMarker() {
355 var poly = this.GetObject(),
356 att =
new JSROOT.TAttMarkerHandler(poly),
358 func = this.AxisToSvgFunc();
360 for (var n=0;n<poly.fN;++n)
361 path += att.create(func.x(poly.fX[n]), func.y(poly.fY[n]));
364 this.draw_g.append(
"svg:path")
371 function drawArrow() {
372 var arrow = this.GetObject(), kLineNDC = JSROOT.BIT(14), oo = arrow.fOption;
374 this.wsize = Math.max(3, Math.round(Math.max(
this.pad_width(), this.pad_height()) * arrow.fArrowSize*0.8));
375 this.isndc = arrow.TestBit(kLineNDC);
376 this.angle2 = arrow.fAngle/2/180 * Math.PI;
377 this.beg = this.mid = this.end = 0;
379 if (oo.indexOf(
"<")==0)
380 this.beg = (oo.indexOf(
"<|") == 0) ? 12 : 2;
381 if (oo.indexOf(
"->-")>=0) this.mid = 1;
else
382 if (oo.indexOf(
"-|>-")>=0) this.mid = 11;
else
383 if (oo.indexOf(
"-<-")>=0) this.mid = 2;
else
384 if (oo.indexOf(
"-<|-")>=0) this.mid = 12;
385 if (oo.lastIndexOf(
">") == oo.length-1)
386 this.end = ((oo.lastIndexOf(
"|>") == oo.length-2) && (oo.length>1)) ? 11 : 1;
388 this.createAttLine({ attr: arrow });
392 this.x1 = this.AxisToSvg(
"x", arrow.fX1,
this.isndc,
true);
393 this.y1 = this.AxisToSvg(
"y", arrow.fY1,
this.isndc,
true);
394 this.x2 = this.AxisToSvg(
"x", arrow.fX2,
this.isndc,
true);
395 this.y2 = this.AxisToSvg(
"y", arrow.fY2,
this.isndc,
true);
397 this.rotate =
function(angle, x0, y0) {
398 var dx = this.wsize * Math.cos(angle), dy = this.wsize * Math.sin(angle), res =
"";
399 if ((x0 !== undefined) && (y0 !== undefined)) {
400 res =
"M" + Math.round(x0-dx) +
"," + Math.round(y0-dy);
404 res +=
"l"+Math.round(dx)+
","+Math.round(dy);
405 if (x0 && (y0===undefined)) res+=
"z";
409 this.createPath =
function() {
410 var angle = Math.atan2(this.y2 - this.y1, this.x2 - this.x1),
411 dlen = this.wsize * Math.cos(this.angle2),
412 dx = dlen*Math.cos(angle), dy = dlen*Math.sin(angle),
416 path += this.rotate(angle - Math.PI -
this.angle2,
this.x1,
this.y1) +
417 this.rotate(angle - Math.PI +
this.angle2,
this.beg > 10);
419 if (this.mid % 10 == 2)
420 path += this.rotate(angle - Math.PI -
this.angle2, (
this.x1+
this.x2-dx)/2, (
this.y1+
this.y2-dy)/2) +
421 this.rotate(angle - Math.PI +
this.angle2,
this.mid > 10);
423 if (this.mid % 10 == 1)
424 path += this.rotate(angle - this.angle2, (this.x1+this.x2+dx)/2, (this.y1+this.y2+dy)/2) +
425 this.rotate(angle + this.angle2, this.mid > 10);
428 path += this.rotate(angle - this.angle2, this.x2, this.y2) +
429 this.rotate(angle + this.angle2, this.end > 10);
431 return "M" + Math.round(this.x1 + (this.beg > 10 ? dx : 0)) +
"," +
432 Math.round(this.y1 + (this.beg > 10 ? dy : 0)) +
433 "L" + Math.round(this.x2 - (this.end > 10 ? dx : 0)) +
"," +
434 Math.round(this.y2 - (this.end > 10 ? dy : 0)) +
438 var elem = this.draw_g.append(
"svg:path")
439 .attr(
"d", this.createPath())
440 .call(this.lineatt.func);
442 if ((this.beg > 10) || (this.end > 10)) {
443 this.createAttFill({ attr: arrow });
444 elem.call(this.fillatt.func);
446 elem.style(
'fill',
'none');
450 this.moveStart =
function(x,y) {
451 var fullsize = Math.sqrt(Math.pow(
this.x1-
this.x2,2) + Math.pow(this.y1-this.y2,2)),
452 sz1 = Math.sqrt(Math.pow(x-
this.x1,2) + Math.pow(y-this.y1,2))/fullsize,
453 sz2 = Math.sqrt(Math.pow(x-
this.x2,2) + Math.pow(y-this.y2,2))/fullsize;
454 if (sz1>0.9) this.side = 1;
else if (sz2>0.9) this.side = -1;
else this.side = 0;
458 this.moveDrag =
function(dx,dy) {
459 if (this.side != 1) { this.x1 += dx; this.y1 += dy; }
460 if (this.side != -1) { this.x2 += dx; this.y2 += dy; }
461 this.draw_g.select(
'path').attr(
"d", this.createPath());
465 this.moveEnd =
function(not_changed) {
466 if (not_changed)
return;
467 var arrow = this.GetObject(), exec =
"";
468 arrow.fX1 = this.SvgToAxis(
"x", this.x1, this.isndc);
469 arrow.fX2 = this.SvgToAxis(
"x", this.x2, this.isndc);
470 arrow.fY1 = this.SvgToAxis(
"y", this.y1, this.isndc);
471 arrow.fY2 = this.SvgToAxis(
"y", this.y2, this.isndc);
472 if (this.side != 1) exec +=
"SetX1(" + arrow.fX1 +
");;SetY1(" + arrow.fY1 +
");;";
473 if (this.side != -1) exec +=
"SetX2(" + arrow.fX2 +
");;SetY2(" + arrow.fY2 +
");;";
474 this.WebCanvasExec(exec +
"Notify();;");
482 function drawRooPlot(divid, plot, opt) {
484 var painter =
new JSROOT.TObjectPainter(plot), cnt = -1;
486 function DrawNextItem() {
487 if (++cnt >= plot._items.arr.length)
return painter.DrawingReady();
489 JSROOT.draw(divid, plot._items.arr[cnt], plot._items.opt[cnt], DrawNextItem);
492 JSROOT.draw(divid, plot._hist,
"hist", DrawNextItem);
508 function TF1Painter(tf1) {
509 JSROOT.TObjectPainter.call(
this, tf1);
513 TF1Painter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
515 TF1Painter.prototype.Eval =
function(x) {
516 return this.GetObject().evalPar(x);
526 TF1Painter.prototype.CreateBins =
function(ignore_zoom) {
527 var main = this.frame_painter(),
528 gxmin = 0, gxmax = 0, tf1 = this.GetObject();
530 if (main && !ignore_zoom) {
531 if (main.zoom_xmin !== main.zoom_xmax) {
532 gxmin = main.zoom_xmin;
533 gxmax = main.zoom_xmax;
540 if ((tf1.fSave.length > 0) && !
this.nosave) {
543 var np = tf1.fSave.length - 2,
544 xmin = tf1.fSave[np],
545 xmax = tf1.fSave[np+1],
546 dx = (xmax - xmin) / (np-1),
549 for (var n=0; n < np; ++n) {
550 var xx = xmin + dx*n;
552 if ((gxmin !== gxmax) && ((xx + 2*dx < gxmin) || (xx - 2*dx > gxmax)))
continue;
553 var yy = tf1.fSave[n];
555 if (!isNaN(yy)) res.push({ x : xx, y : yy });
560 var xmin = tf1.fXmin, xmax = tf1.fXmax, logx =
false;
562 if (gxmin !== gxmax) {
563 if (gxmin > xmin) xmin = gxmin;
564 if (gxmax < xmax) xmax = gxmax;
567 if (main && main.logx && (xmin>0) && (xmax>0)) {
569 xmin = Math.log(xmin);
570 xmax = Math.log(xmax);
573 var np = Math.max(tf1.fNpx, 101),
574 dx = (xmax - xmin) / (np - 1),
577 for (var n=0; n < np; n++) {
578 var xx = xmin + n*dx;
579 if (logx) xx = Math.exp(xx);
580 var yy = this.Eval(xx);
581 if (!isNaN(yy)) res.push({ x: xx, y: yy });
586 TF1Painter.prototype.CreateDummyHisto =
function() {
588 var xmin = 0, xmax = 1, ymin = 0, ymax = 1,
589 bins = this.CreateBins(
true);
591 if (bins && (bins.length > 0)) {
593 xmin = xmax = bins[0].x;
594 ymin = ymax = bins[0].y;
596 bins.forEach(
function(bin) {
597 xmin = Math.min(bin.x, xmin);
598 xmax = Math.max(bin.x, xmax);
599 ymin = Math.min(bin.y, ymin);
600 ymax = Math.max(bin.y, ymax);
603 if (ymax > 0.0) ymax *= 1.05;
604 if (ymin < 0.0) ymin *= 1.05;
607 var histo = JSROOT.Create(
"TH1I"),
608 tf1 = this.GetObject();
610 histo.fName = tf1.fName +
"_hist";
611 histo.fTitle = tf1.fTitle;
613 histo.fXaxis.fXmin = xmin;
614 histo.fXaxis.fXmax = xmax;
615 histo.fYaxis.fXmin = ymin;
616 histo.fYaxis.fXmax = ymax;
621 TF1Painter.prototype.ProcessTooltip =
function(pnt) {
624 if ((pnt === null) || (this.bins === null)) {
627 if ((this.bins.length==0) || (pnt.x < this.bins[0].grx) || (pnt.x >
this.bins[
this.bins.length-1].grx)) {
632 if (this.draw_g !== null)
633 this.draw_g.select(
".tooltip_bin").remove();
637 var min = 100000, best = -1, bin;
639 for(var n=0; n<this.bins.length; ++n) {
641 var dist = Math.abs(bin.grx - pnt.x);
642 if (dist < min) { min = dist; best = n; }
645 bin = this.bins[best];
647 var gbin = this.draw_g.select(
".tooltip_bin"),
648 radius = this.lineatt.width + 3;
651 gbin = this.draw_g.append(
"svg:circle")
652 .attr(
"class",
"tooltip_bin")
653 .style(
"pointer-events",
"none")
655 .call(this.lineatt.func)
656 .call(this.fillatt.func);
658 var res = { name: this.GetObject().fName,
659 title: this.GetObject().fTitle,
662 color1: this.lineatt.color,
663 color2: this.fillatt.fillcolor(),
665 exact: (Math.abs(bin.grx - pnt.x) < radius) && (Math.abs(bin.gry - pnt.y) < radius) };
667 res.changed = gbin.property(
"current_bin") !== best;
668 res.menu = res.exact;
669 res.menu_dist = Math.sqrt((bin.grx-pnt.x)*(bin.grx-pnt.x) + (bin.gry-pnt.y)*(bin.gry-pnt.y));
672 gbin.attr(
"cx", bin.grx)
674 .property(
"current_bin", best);
676 var name = this.GetTipName();
677 if (name.length > 0) res.lines.push(name);
679 var pmain = this.frame_painter();
681 res.lines.push(
"x = " + pmain.AxisAsText(
"x",bin.x) +
" y = " + pmain.AxisAsText(
"y",bin.y));
686 TF1Painter.prototype.Redraw =
function() {
688 var w = this.frame_width(),
689 h = this.frame_height(),
690 tf1 = this.GetObject(),
691 fp = this.frame_painter(),
692 pmain = this.main_painter(),
693 name = this.GetTipName(
"\n");
698 this.bins = this.CreateBins(
false);
700 this.createAttLine({ attr: tf1 });
701 this.lineatt.used =
false;
703 this.createAttFill({ attr: tf1, kind: 1 });
704 this.fillatt.used =
false;
707 for(var n=0; n<this.bins.length; ++n) {
708 var bin = this.bins[n];
709 bin.grx = fp.grx(bin.x);
710 bin.gry = fp.gry(bin.y);
713 if (this.bins.length > 2) {
716 if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) {
717 h0 = Math.round(fp.gry(0));
718 if ((h0 > h) || (h0 < 0)) h0 = h;
721 var path = JSROOT.Painter.BuildSvgPath(
"bezier", this.bins, h0, 2);
723 if (this.lineatt.color !=
"none")
724 this.draw_g.append(
"svg:path")
725 .attr(
"class",
"line")
726 .attr(
"d", path.path)
727 .style(
"fill",
"none")
728 .call(this.lineatt.func);
730 if (!this.fillatt.empty())
731 this.draw_g.append(
"svg:path")
732 .attr(
"class",
"area")
733 .attr(
"d", path.path + path.close)
734 .style(
"stroke",
"none")
735 .call(this.fillatt.func);
739 TF1Painter.prototype.CanZoomIn =
function(axis,min,max) {
740 if (axis!==
"x")
return false;
742 var tf1 = this.GetObject();
744 if (tf1.fSave.length > 0) {
747 var nb_points = tf1.fNpx;
749 var xmin = tf1.fSave[nb_points + 1];
750 var xmax = tf1.fSave[nb_points + 2];
752 return Math.abs(xmin - xmax) / nb_points < Math.abs(min - max);
759 TF1Painter.prototype.PerformDraw =
function() {
760 if (this.main_painter() === null) {
761 var histo = this.CreateDummyHisto(), pthis =
this;
762 JSROOT.draw(this.divid, histo,
"AXIS",
function(hpainter) {
763 pthis.SetDivId(pthis.divid);
765 return pthis.DrawingReady();
770 this.SetDivId(this.divid);
772 return this.DrawingReady();
775 function drawFunction(divid, tf1, opt) {
777 var painter =
new TF1Painter(tf1);
779 painter.SetDivId(divid, -1);
780 var d =
new JSROOT.DrawOptions(opt);
781 painter.nosave = d.check(
'NOSAVE');
783 if (JSROOT.Math !== undefined)
784 return painter.PerformDraw();
786 JSROOT.AssertPrerequisites(
"math", painter.PerformDraw.bind(painter));
801 function TGraphPainter(graph) {
802 JSROOT.TObjectPainter.call(
this, graph);
803 this.axes_draw =
false;
805 this.xmin = this.ymin = this.xmax = this.ymax = 0;
806 this.wheel_zoomy =
true;
807 this.is_bent = (graph._typename ==
'TGraphBentErrors');
808 this.has_errors = (graph._typename ==
'TGraphErrors') ||
809 (graph._typename ==
'TGraphAsymmErrors') ||
810 this.is_bent || graph._typename.match(/^RooHist/);
813 TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
815 TGraphPainter.prototype.Redraw =
function() {
819 TGraphPainter.prototype.Cleanup =
function() {
820 delete this.interactive_bin;
822 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
825 TGraphPainter.prototype.DecodeOptions =
function(opt) {
827 if (!opt) opt = this.main_painter() ?
"lp" :
"alp";
829 if ((typeof opt ==
"string") && (opt.indexOf(
"same ")==0))
832 var graph = this.GetObject(),
833 d =
new JSROOT.DrawOptions(opt);
835 if (!this.options) this.options = {};
837 JSROOT.extend(this.options, {
838 Line: 0, Curve: 0, Rect: 0, Mark: 0, Bar: 0, OutRange: 0, EF:0, Fill: 0, NoOpt: 0,
839 MainError: 1, Ends: 1, Axis:
"", PadStats:
false, PadTitle:
false, original: opt
842 var res = this.options;
844 res.PadStats = d.check(
"USE_PAD_STATS");
845 res.PadTitle = d.check(
"USE_PAD_TITLE");
847 res._pfc = d.check(
"PFC");
848 res._plc = d.check(
"PLC");
849 res._pmc = d.check(
"PMC");
851 if (d.check(
'NOOPT')) res.NoOpt = 1;
852 if (d.check(
'L')) res.Line = 1;
853 if (d.check(
'F')) res.Fill = 1;
854 if (d.check(
'A')) res.Axis = d.check(
"I") ?
"A" :
"AXIS";
855 if (d.check(
'X+')) res.Axis +=
"X+";
856 if (d.check(
'Y+')) res.Axis +=
"Y+";
857 if (d.check(
'RX')) res.Axis +=
"RX";
858 if (d.check(
'RY')) res.Axis +=
"RY";
859 if (d.check(
'C')) res.Curve = res.Line = 1;
860 if (d.check(
'*')) res.Mark = 103;
861 if (d.check(
'P0')) res.Mark = 104;
862 if (d.check(
'P')) res.Mark = 1;
863 if (d.check(
'B')) { res.Bar = 1; res.Errors = 0; }
864 if (d.check(
'Z')) { res.Errors = 1; res.Ends = 0; }
865 if (d.check(
'||')) { res.Errors = 1; res.MainError = 0; res.Ends = 1; }
866 if (d.check(
'[]')) { res.Errors = 1; res.MainError = 0; res.Ends = 2; }
867 if (d.check(
'|>')) { res.Errors = 1; res.Ends = 3; }
868 if (d.check(
'>')) { res.Errors = 1; res.Ends = 4; }
869 if (d.check(
'0')) { res.Mark = 1; res.Errors = 1; res.OutRange = 1; }
870 if (d.check(
'1')) {
if (res.Bar == 1) res.Bar = 2; }
871 if (d.check(
'2')) { res.Rect = 1; res.Errors = 0; }
872 if (d.check(
'3')) { res.EF = 1; res.Errors = 0; }
873 if (d.check(
'4')) { res.EF = 2; res.Errors = 0; }
874 if (d.check(
'5')) { res.Rect = 2; res.Errors = 0; }
875 if (d.check(
'X')) res.Errors = 0;
878 if (res.Errors === undefined)
879 res.Errors = this.has_errors ? 1 : 0;
882 if ((res.Mark == 1) && (graph.fMarkerStyle==1)) res.Mark = 101;
885 if (res.Line + res.Fill + res.Mark + res.Bar + res.EF + res.Rect + res.Errors == 0) {
886 if (d.empty()) res.Line = 1;
889 if (graph._typename ==
'TGraphErrors') {
890 if (d3.max(graph.fEX) < 1.0e-300 && d3.max(graph.fEY) < 1.0e-300)
898 var pad = this.root_pad();
899 if (!pad || (pad.fPrimitives && (pad.fPrimitives.arr[0] === graph))) res.Axis =
"AXIS";
900 }
else if (res.Axis.indexOf(
"A")<0) {
901 res.Axis =
"AXIS," + res.Axis;
904 if (res.PadTitle) res.Axis +=
";USE_PAD_TITLE";
906 res.HOptions = res.Axis;
909 TGraphPainter.prototype.CreateBins =
function() {
910 var gr = this.GetObject();
913 var kind = 0, npoints = gr.fNpoints;
914 if ((gr._typename===
"TCutG") && (npoints>3)) npoints--;
916 if (gr._typename ==
'TGraphErrors') kind = 1;
else
917 if (gr._typename ==
'TGraphAsymmErrors' || gr._typename ==
'TGraphBentErrors'
918 || gr._typename.match(/^RooHist/)) kind = 2;
922 for (var p=0; p<npoints; ++p) {
923 var bin = { x: gr.fX[p], y: gr.fY[p], indx: p };
926 bin.exlow = bin.exhigh = gr.fEX[p];
927 bin.eylow = bin.eyhigh = gr.fEY[p];
930 bin.exlow = gr.fEXlow[p];
931 bin.exhigh = gr.fEXhigh[p];
932 bin.eylow = gr.fEYlow[p];
933 bin.eyhigh = gr.fEYhigh[p];
939 this.xmin = this.xmax = bin.x;
940 this.ymin = this.ymax = bin.y;
944 this.xmin = Math.min(this.xmin, bin.x - bin.exlow, bin.x + bin.exhigh);
945 this.xmax = Math.max(this.xmax, bin.x - bin.exlow, bin.x + bin.exhigh);
946 this.ymin = Math.min(this.ymin, bin.y - bin.eylow, bin.y + bin.eyhigh);
947 this.ymax = Math.max(this.ymax, bin.y - bin.eylow, bin.y + bin.eyhigh);
949 this.xmin = Math.min(this.xmin, bin.x);
950 this.xmax = Math.max(this.xmax, bin.x);
951 this.ymin = Math.min(this.ymin, bin.y);
952 this.ymax = Math.max(this.ymax, bin.y);
957 TGraphPainter.prototype.CreateHistogram =
function(only_set_ranges) {
960 var xmin = this.xmin, xmax = this.xmax, ymin = this.ymin, ymax = this.ymax, set_x =
true, set_y =
true;
962 if (xmin >= xmax) xmax = xmin+1;
963 if (ymin >= ymax) ymax = ymin+1;
964 var dx = (xmax-xmin)*0.1, dy = (ymax-ymin)*0.1,
965 uxmin = xmin - dx, uxmax = xmax + dx,
966 minimum = ymin - dy, maximum = ymax + dy;
969 this.options.HOptions = this.options.Axis +
";ymin:" + minimum +
";ymax:" + maximum;
971 if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.9;
972 if ((uxmax>0) && (xmax<=0)) uxmax = 0;
974 var graph = this.GetObject();
976 if (graph.fMinimum != -1111) minimum = ymin = graph.fMinimum;
977 if (graph.fMaximum != -1111) maximum = ymax = graph.fMaximum;
978 if ((minimum < 0) && (ymin >=0)) minimum = 0.9*ymin;
980 var kResetHisto = JSROOT.BIT(17);
982 var histo = graph.fHistogram;
984 if (only_set_ranges) {
985 set_x = only_set_ranges.indexOf(
"x") >= 0;
986 set_y = only_set_ranges.indexOf(
"y") >= 0;
989 if (!graph.TestBit(kResetHisto))
return histo;
990 graph.InvertBit(kResetHisto);
992 graph.fHistogram = histo = JSROOT.CreateHistogram(
"TH1F", 100);
993 histo.fName = graph.fName +
"_h";
994 histo.fTitle = graph.fTitle;
995 histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats;
996 this._own_histogram =
true;
1000 histo.fXaxis.fXmin = uxmin;
1001 histo.fXaxis.fXmax = uxmax;
1004 histo.fYaxis.fXmin = minimum;
1005 histo.fYaxis.fXmax = maximum;
1006 histo.fMinimum = minimum;
1007 histo.fMaximum = maximum;
1016 TGraphPainter.prototype.UnzoomUserRange =
function(dox, doy, doz) {
1017 var graph = this.GetObject();
1018 if (this._own_histogram || !graph)
return false;
1020 var histo = graph.fHistogram;
1021 if (!histo)
return false;
1024 if (dox && (histo.fXaxis.fXmin >
this.xmin) || (histo.fXaxis.fXmax <
this.xmax)) arg +=
"x";
1025 if (doy && (histo.fYaxis.fXmin >
this.ymin) || (histo.fYaxis.fXmax <
this.ymax)) arg +=
"y";
1026 if (!arg)
return false;
1028 this.CreateHistogram(arg);
1029 var hpainter = this.main_painter();
1030 if (hpainter) hpainter.CreateAxisFuncs(
false);
1036 TGraphPainter.prototype.CanOptimize =
function() {
1037 return JSROOT.gStyle.OptimizeDraw > 0 && !this.options.NoOpt;
1041 TGraphPainter.prototype.OptimizeBins =
function(maxpnt, filter_func) {
1042 if ((this.bins.length < 30) && !filter_func)
return this.bins;
1045 if (typeof filter_func ==
'function') {
1046 for (var n = 0; n < this.bins.length; ++n) {
1047 if (filter_func(this.bins[n],n)) {
1048 if (!selbins) selbins = (n==0) ? [] : this.bins.slice(0, n);
1050 if (selbins) selbins.push(this.bins[n]);
1054 if (!selbins) selbins = this.bins;
1056 if (!maxpnt) maxpnt = 500000;
1058 if ((selbins.length < maxpnt) || !
this.CanOptimize())
return selbins;
1059 var step = Math.floor(selbins.length / maxpnt);
1060 if (step < 2) step = 2;
1062 for (var n = 0; n < selbins.length; n+=step)
1063 optbins.push(selbins[n]);
1068 TGraphPainter.prototype.TooltipText =
function(d) {
1069 var pmain = this.frame_painter(), lines = [];
1071 lines.push(this.GetTipName());
1074 lines.push(
"x = " + pmain.AxisAsText(
"x", d.x));
1075 lines.push(
"y = " + pmain.AxisAsText(
"y", d.y));
1077 if (this.options.Errors && (pmain.x_kind==
'normal') && (
'exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0)))
1078 lines.push(
"error x = -" + pmain.AxisAsText(
"x", d.exlow) +
"/+" + pmain.AxisAsText(
"x", d.exhigh));
1080 if ((this.options.Errors || (
this.options.EF > 0)) && (pmain.y_kind==
'normal') && (
'eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0)))
1081 lines.push(
"error y = -" + pmain.AxisAsText(
"y", d.eylow) +
"/+" + pmain.AxisAsText(
"y", d.eyhigh));
1086 TGraphPainter.prototype.get_main =
function() {
1087 var pmain = this.frame_painter();
1089 if (pmain && pmain.grx && pmain.gry)
return pmain;
1093 pad: this.root_pad(),
1094 pw: this.pad_width(),
1095 ph: this.pad_height(),
1096 grx:
function(value) {
1098 value = (value>0) ? JSROOT.log10(value) : this.pad.fUxmin;
1100 value = (value - this.pad.fX1) / (this.pad.fX2 -
this.pad.fX1);
1101 return value*this.pw;
1103 gry:
function(value) {
1105 value = (value>0) ? JSROOT.log10(value) : this.pad.fUymin;
1107 value = (value - this.pad.fY1) / (this.pad.fY2 -
this.pad.fY1);
1108 return (1-value)*this.ph;
1112 return pmain.pad ? pmain : null;
1115 TGraphPainter.prototype.DrawBins =
function() {
1118 pmain = this.get_main(),
1119 w = this.frame_width(),
1120 h = this.frame_height(),
1121 graph = this.GetObject(),
1123 pp = this.pad_painter();
1127 this.CreateG(!pmain.pad_layer);
1129 if (pp && (this.options._pfc ||
this.options._plc ||
this.options._pmc)) {
1130 var icolor = pp.CreateAutoColor(
this);
1132 if (this.options._pfc) { graph.fFillColor = icolor;
delete this.fillatt; }
1133 if (this.options._plc) { graph.fLineColor = icolor;
delete this.lineatt; }
1134 if (this.options._pmc) { graph.fMarkerColor = icolor;
delete this.markeratt; }
1136 this.options._pfc = this.options._plc = this.options._pmc =
false;
1139 this.createAttLine({ attr: graph, can_excl:
true });
1141 this.createAttFill({ attr: graph, kind: 1 });
1142 this.fillatt.used =
false;
1144 this.draw_kind =
"none";
1145 this.marker_size = 0;
1147 if (this.lineatt.excl_side != 0) {
1148 excl_width = this.lineatt.excl_width;
1149 if (this.lineatt.width > 0) this.options.Line = 1;
1152 var drawbins = null;
1154 if (this.options.EF) {
1156 drawbins = this.OptimizeBins((this.options.EF > 1) ? 5000 : 0);
1159 for (var n=0;n<drawbins.length;++n) {
1160 var bin = drawbins[n];
1161 bin.grx = pmain.grx(bin.x);
1162 bin.gry = pmain.gry(bin.y - bin.eylow);
1165 var path1 = JSROOT.Painter.BuildSvgPath((this.options.EF > 1) ?
"bezier" :
"line", drawbins),
1168 for (var n=drawbins.length-1;n>=0;--n) {
1169 var bin = drawbins[n];
1170 bin.gry = pmain.gry(bin.y + bin.eyhigh);
1175 var path2 = JSROOT.Painter.BuildSvgPath((this.options.EF > 1) ?
"Lbezier" :
"Lline", bins2);
1177 this.draw_g.append(
"svg:path")
1178 .attr(
"d", path1.path + path2.path +
"Z")
1179 .style(
"stroke",
"none")
1180 .call(this.fillatt.func);
1181 this.draw_kind =
"lines";
1184 if (this.options.Line == 1 ||
this.options.Fill == 1 || (excl_width!==0)) {
1186 var close_symbol =
"";
1187 if (graph._typename==
"TCutG") this.options.Fill = 1;
1189 if (this.options.Fill == 1) {
1194 if (!drawbins) drawbins = this.OptimizeBins(this.options.Curve ? 5000 : 0);
1196 for (var n=0;n<drawbins.length;++n) {
1197 var bin = drawbins[n];
1198 bin.grx = pmain.grx(bin.x);
1199 bin.gry = pmain.gry(bin.y);
1203 if (this.options.Curve === 1) kind =
"bezier";
else
1204 if (excl_width!==0) kind+=
"calc";
1206 var path = JSROOT.Painter.BuildSvgPath(kind, drawbins);
1208 if (excl_width!==0) {
1210 for (var n=drawbins.length-1;n>=0;--n) {
1211 var bin = drawbins[n];
1212 var dlen = Math.sqrt(bin.dgrx*bin.dgrx + bin.dgry*bin.dgry);
1214 bin.grx += excl_width*bin.dgry/dlen;
1215 bin.gry -= excl_width*bin.dgrx/dlen;
1216 extrabins.push(bin);
1219 var path2 = JSROOT.Painter.BuildSvgPath(
"L" + ((this.options.Curve === 1) ?
"bezier" :
"line"), extrabins);
1221 this.draw_g.append(
"svg:path")
1222 .attr(
"d", path.path + path2.path +
"Z")
1223 .style(
"stroke",
"none")
1224 .call(this.fillatt.func)
1225 .style(
'opacity', 0.75);
1228 if (this.options.Line ||
this.options.Fill) {
1229 var elem = this.draw_g.append(
"svg:path")
1230 .attr(
"d", path.path + close_symbol);
1231 if (this.options.Line)
1232 elem.call(this.lineatt.func);
1234 elem.style(
'stroke',
'none');
1236 if (this.options.Fill)
1237 elem.call(this.fillatt.func);
1239 elem.style(
'fill',
'none');
1242 this.draw_kind =
"lines";
1247 if (this.options.Errors ||
this.options.Rect ||
this.options.Bar) {
1249 drawbins = this.OptimizeBins(5000,
function(pnt,i) {
1251 var grx = pmain.grx(pnt.x);
1254 if (!pthis.options.Bar && ((grx<0) || (grx>w)))
return true;
1256 var gry = pmain.gry(pnt.y);
1258 if (!pthis.options.Bar && !pthis.options.OutRange && ((gry<0) || (gry>h)))
return true;
1260 pnt.grx1 = Math.round(grx);
1261 pnt.gry1 = Math.round(gry);
1263 if (pthis.has_errors) {
1264 pnt.grx0 = Math.round(pmain.grx(pnt.x - pnt.exlow) - grx);
1265 pnt.grx2 = Math.round(pmain.grx(pnt.x + pnt.exhigh) - grx);
1266 pnt.gry0 = Math.round(pmain.gry(pnt.y - pnt.eylow) - gry);
1267 pnt.gry2 = Math.round(pmain.gry(pnt.y + pnt.eyhigh) - gry);
1269 if (pthis.is_bent) {
1270 pnt.grdx0 = Math.round(pmain.gry(pnt.y + graph.fEXlowd[i]) - gry);
1271 pnt.grdx2 = Math.round(pmain.gry(pnt.y + graph.fEXhighd[i]) - gry);
1272 pnt.grdy0 = Math.round(pmain.grx(pnt.x + graph.fEYlowd[i]) - grx);
1273 pnt.grdy2 = Math.round(pmain.grx(pnt.x + graph.fEYhighd[i]) - grx);
1275 pnt.grdx0 = pnt.grdx2 = pnt.grdy0 = pnt.grdy2 = 0;
1282 this.draw_kind =
"nodes";
1285 nodes = this.draw_g.selectAll(
".grpoint")
1289 .attr(
"class",
"grpoint")
1290 .attr(
"transform",
function(d) {
return "translate(" + d.grx1 +
"," + d.gry1 +
")"; });
1293 if (this.options.Bar) {
1295 for (var i=1;i<drawbins.length-1;++i)
1296 drawbins[i].width = Math.max(2, (drawbins[i+1].grx1 - drawbins[i-1].grx1) / 2 - 2);
1299 switch (drawbins.length) {
1301 case 1: drawbins[0].width = w/4;
break;
1302 case 2: drawbins[0].width = drawbins[1].width = (drawbins[1].grx1-drawbins[0].grx1)/2;
break;
1304 drawbins[0].width = drawbins[1].width;
1305 drawbins[drawbins.length-1].width = drawbins[drawbins.length-2].width;
1308 var yy0 = Math.round(pmain.gry(0));
1310 nodes.append(
"svg:rect")
1311 .attr(
"x",
function(d) {
return Math.round(-d.width/2); })
1312 .attr(
"y",
function(d) {
1314 if (pthis.options.Bar!==1)
return 0;
1315 return (d.gry1 > yy0) ? yy0-d.gry1 : 0;
1317 .attr(
"width",
function(d) {
return Math.round(d.width); })
1318 .attr(
"height",
function(d) {
1319 if (pthis.options.Bar!==1)
return h > d.gry1 ? h - d.gry1 : 0;
1320 return Math.abs(yy0 - d.gry1);
1322 .call(this.fillatt.func);
1325 if (this.options.Rect)
1326 nodes.filter(
function(d) {
return (d.exlow > 0) && (d.exhigh > 0) && (d.eylow > 0) && (d.eyhigh > 0); })
1328 .attr(
"x",
function(d) { d.rect =
true;
return d.grx0; })
1329 .attr(
"y",
function(d) {
return d.gry2; })
1330 .attr(
"width",
function(d) {
return d.grx2 - d.grx0; })
1331 .attr(
"height",
function(d) {
return d.gry0 - d.gry2; })
1332 .call(this.fillatt.func)
1333 .call(this.options.Rect === 2 ?
this.lineatt.func :
function() {});
1335 this.error_size = 0;
1337 if (this.options.Errors) {
1339 var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize, bb = 0,
1340 vv = this.options.Ends ?
"m0," + lw +
"v-" + 2*lw :
"",
1341 hh = this.options.Ends ?
"m" + lw +
",0h-" + 2*lw :
"",
1342 vleft = vv, vright = vv, htop = hh, hbottom = hh,
1343 mm = this.options.MainError ?
"M0,0L" :
"M";
1345 switch (this.options.Ends) {
1347 bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66));
1348 vleft =
"m"+bb+
","+lw +
"h-"+bb +
"v-"+2*lw +
"h"+bb;
1349 vright =
"m-"+bb+
","+lw +
"h"+bb +
"v-"+2*lw +
"h-"+bb;
1350 htop =
"m-"+lw+
","+bb +
"v-"+bb +
"h"+2*lw +
"v"+bb;
1351 hbottom =
"m-"+lw+
",-"+bb +
"v"+bb +
"h"+2*lw +
"v-"+bb;
1354 lw = Math.max(lw, Math.round(graph.fMarkerSize*8*0.66));
1355 bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66));
1356 vleft =
"l"+bb+
","+lw +
"v-"+2*lw +
"l-"+bb+
","+lw;
1357 vright =
"l-"+bb+
","+lw +
"v-"+2*lw +
"l"+bb+
","+lw;
1358 htop =
"l-"+lw+
","+bb +
"h"+2*lw +
"l-"+lw+
",-"+bb;
1359 hbottom =
"l-"+lw+
",-"+bb +
"h"+2*lw +
"l-"+lw+
","+bb;
1362 lw = Math.max(lw, Math.round(graph.fMarkerSize*8*0.66));
1363 bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66));
1364 vleft =
"l"+bb+
","+lw +
"m0,-"+2*lw +
"l-"+bb+
","+lw;
1365 vright =
"l-"+bb+
","+lw +
"m0,-"+2*lw +
"l"+bb+
","+lw;
1366 htop =
"l-"+lw+
","+bb +
"m"+2*lw +
",0l-"+lw+
",-"+bb;
1367 hbottom =
"l-"+lw+
",-"+bb +
"m"+2*lw +
",0l-"+lw+
","+bb;
1371 this.error_size = lw;
1373 lw = Math.floor((this.lineatt.width-1)/2);
1374 nodes.filter(
function(d) {
return (d.exlow > 0) || (d.exhigh > 0) || (d.eylow > 0) || (d.eyhigh > 0); })
1376 .call(this.lineatt.func)
1377 .style(
'fill',
"none")
1378 .attr(
"d",
function(d) {
1380 return ((d.exlow > 0) ? mm + (d.grx0+lw) +
"," + d.grdx0 + vleft :
"") +
1381 ((d.exhigh > 0) ? mm + (d.grx2-lw) +
"," + d.grdx2 + vright :
"") +
1382 ((d.eylow > 0) ? mm + d.grdy0 +
"," + (d.gry0-lw) + hbottom :
"") +
1383 ((d.eyhigh > 0) ? mm + d.grdy2 +
"," + (d.gry2+lw) + htop :
"");
1387 if (this.options.Mark) {
1389 var path =
"", pnt, grx, gry;
1391 this.createAttMarker({ attr: graph, style: this.options.Mark - 100 });
1393 this.marker_size = this.markeratt.GetFullSize();
1395 this.markeratt.reset_pos();
1398 var maxnummarker = 1000000 / (this.markeratt.MarkerLength() + 7), step = 1;
1400 if (!drawbins) drawbins = this.OptimizeBins(maxnummarker);
else
1401 if (this.CanOptimize() && (drawbins.length > 1.5*maxnummarker))
1402 step = Math.min(2, Math.round(drawbins.length/maxnummarker));
1404 for (var n=0;n<drawbins.length;n+=step) {
1406 grx = pmain.grx(pnt.x);
1407 if ((grx > -this.marker_size) && (grx < w + this.marker_size)) {
1408 gry = pmain.gry(pnt.y);
1409 if ((gry > -this.marker_size) && (gry < h + this.marker_size))
1410 path += this.markeratt.create(grx, gry);
1414 if (path.length>0) {
1415 this.draw_g.append(
"svg:path")
1417 .call(this.markeratt.func);
1418 if ((nodes===null) && (this.draw_kind==
"none"))
1419 this.draw_kind = (this.options.Mark==101) ?
"path" :
"mark";
1425 TGraphPainter.prototype.ExtractTooltip =
function(pnt) {
1426 if (!pnt)
return null;
1428 if ((this.draw_kind==
"lines") || (this.draw_kind==
"path") || (this.draw_kind==
"mark"))
1429 return this.ExtractTooltipForPath(pnt);
1431 if (this.draw_kind!=
"nodes")
return null;
1433 var width = this.frame_width(),
1434 height = this.frame_height(),
1435 pmain = this.frame_painter(),
1437 findbin = null, best_dist2 = 1e10, best = null,
1438 msize = this.marker_size ? Math.round(this.marker_size/2 + 1.5) : 0;
1440 this.draw_g.selectAll(
'.grpoint').each(
function() {
1441 var d = d3.select(
this).datum();
1442 if (d===undefined)
return;
1443 var dist2 = Math.pow(pnt.x - d.grx1, 2);
1444 if (pnt.nproc===1) dist2 += Math.pow(pnt.y - d.gry1, 2);
1445 if (dist2 >= best_dist2)
return;
1449 if (d.error || d.rect || d.marker) {
1450 rect = { x1: Math.min(-painter.error_size, d.grx0, -msize),
1451 x2: Math.max(painter.error_size, d.grx2, msize),
1452 y1: Math.min(-painter.error_size, d.gry2, -msize),
1453 y2: Math.max(painter.error_size, d.gry0, msize) };
1455 rect = { x1: -d.width/2, x2: d.width/2, y1: 0, y2: height - d.gry1 };
1457 if (painter.options.Bar===1) {
1458 var yy0 = pmain.gry(0);
1459 rect.y1 = (d.gry1 > yy0) ? yy0-d.gry1 : 0;
1460 rect.y2 = (d.gry1 > yy0) ? 0 : yy0-d.gry1;
1463 rect = { x1: -5, x2: 5, y1: -5, y2: 5 };
1465 var matchx = (pnt.x >= d.grx1 + rect.x1) && (pnt.x <= d.grx1 + rect.x2),
1466 matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2);
1468 if (matchx && (matchy || (pnt.nproc > 1))) {
1472 best.exact = matchx && matchy;
1476 if (findbin === null)
return null;
1478 var d = d3.select(findbin).datum();
1480 var res = { name: this.GetObject().fName, title: this.GetObject().fTitle,
1481 x: d.grx1, y: d.gry1,
1482 color1: this.lineatt.color,
1483 lines: this.TooltipText(d),
1484 rect: best, d3bin: findbin };
1486 if (this.fillatt && this.fillatt.used && !
this.fillatt.empty()) res.color2 =
this.fillatt.fillcolor();
1488 if (best.exact) res.exact =
true;
1489 res.menu = res.exact;
1492 res.binindx = d.indx;
1497 TGraphPainter.prototype.ShowTooltip =
function(hint) {
1500 if (this.draw_g) this.draw_g.select(
".tooltip_bin").remove();
1504 if (hint.usepath)
return this.ShowTooltipForPath(hint);
1506 var d = d3.select(hint.d3bin).datum();
1508 var ttrect = this.draw_g.select(
".tooltip_bin");
1511 ttrect = this.draw_g.append(
"svg:rect")
1512 .attr(
"class",
"tooltip_bin h1bin")
1513 .style(
"pointer-events",
"none");
1515 hint.changed = ttrect.property(
"current_bin") !== hint.d3bin;
1518 ttrect.attr(
"x", d.grx1 + hint.rect.x1)
1519 .attr(
"width", hint.rect.x2 - hint.rect.x1)
1520 .attr(
"y", d.gry1 + hint.rect.y1)
1521 .attr(
"height", hint.rect.y2 - hint.rect.y1)
1522 .style(
"opacity",
"0.3")
1523 .property(
"current_bin", hint.d3bin);
1526 TGraphPainter.prototype.ProcessTooltip =
function(pnt) {
1527 var hint = this.ExtractTooltip(pnt);
1528 if (!pnt || !pnt.disabled) this.ShowTooltip(hint);
1532 TGraphPainter.prototype.FindBestBin =
function(pnt) {
1533 if (!this.bins)
return null;
1535 var islines = (this.draw_kind==
"lines"),
1536 ismark = (this.draw_kind==
"mark"),
1540 pmain = this.frame_painter(),
1541 dist, grx, gry, n, bin;
1543 for (n=0;n<this.bins.length;++n) {
1546 grx = pmain.grx(bin.x);
1547 gry = pmain.gry(bin.y);
1549 dist = (pnt.x-grx)*(pnt.x-grx) + (pnt.y-gry)*(pnt.y-gry);
1551 if (dist < bestdist) {
1559 if ((bestdist > 100) && islines) bestbin = null;
1561 var radius = Math.max(this.lineatt.width + 3, 4);
1563 if (this.marker_size > 0) radius = Math.max(this.marker_size, radius);
1566 bestdist = Math.sqrt(Math.pow(pnt.x-pmain.grx(bestbin.x),2) + Math.pow(pnt.y-pmain.gry(bestbin.y),2));
1568 if (!islines && (bestdist > radius)) bestbin = null;
1570 if (!bestbin) bestindx = -1;
1572 var res = { bin: bestbin, indx: bestindx, dist: bestdist, radius: Math.round(radius) };
1574 if (!bestbin && islines) {
1578 function IsInside(x, x1, x2) {
1579 return ((x1>=x) && (x>=x2)) || ((x1<=x) && (x<=x2));
1582 var bin0 = this.bins[0], grx0 = pmain.grx(bin0.x), gry0, posy = 0;
1583 for (n=1;n<this.bins.length;++n) {
1585 grx = pmain.grx(bin.x);
1587 if (IsInside(pnt.x, grx0, grx)) {
1589 gry0 = pmain.gry(bin0.y)
1590 gry = pmain.gry(bin.y);
1592 if (Math.abs(grx - grx0) < 1) {
1595 dist = IsInside(pnt.y, gry0, gry) ? 0 : Math.min(Math.abs(pnt.y-gry0), Math.abs(pnt.y-gry));
1597 posy = gry0 + (pnt.x - grx0) / (grx - grx0) * (gry - gry0);
1598 dist = Math.abs(posy - pnt.y);
1601 if (dist < bestdist) {
1612 if (bestdist < radius*0.5) {
1613 res.linedist = bestdist;
1614 res.closeline =
true;
1621 TGraphPainter.prototype.TestEditable =
function(toggle) {
1622 var obj = this.GetObject(),
1623 kNotEditable = JSROOT.BIT(18);
1625 if (!obj)
return false;
1626 if (toggle) obj.InvertBit(kNotEditable);
1627 return !obj.TestBit(kNotEditable);
1630 TGraphPainter.prototype.ExtractTooltipForPath =
function(pnt) {
1632 if (this.bins === null)
return null;
1634 var best = this.FindBestBin(pnt);
1636 if (!best || (!best.bin && !best.closeline))
return null;
1638 var islines = (this.draw_kind==
"lines"),
1639 ismark = (this.draw_kind==
"mark"),
1640 pmain = this.frame_painter(),
1641 gr = this.GetObject(),
1642 res = { name: gr.fName, title: gr.fTitle,
1643 x: best.bin ? pmain.grx(best.bin.x) : best.linex,
1644 y: best.bin ? pmain.gry(best.bin.y) : best.liney,
1645 color1: this.lineatt.color,
1646 lines: this.TooltipText(best.bin),
1649 res.ismark = ismark;
1650 res.islines = islines;
1652 if (best.closeline) {
1653 res.menu = res.exact =
true;
1654 res.menu_dist = best.linedist;
1655 }
else if (best.bin) {
1656 if (this.options.EF && islines) {
1657 res.gry1 = pmain.gry(best.bin.y - best.bin.eylow);
1658 res.gry2 = pmain.gry(best.bin.y + best.bin.eyhigh);
1660 res.gry1 = res.gry2 = pmain.gry(best.bin.y);
1663 res.binindx = best.indx;
1665 res.radius = best.radius;
1667 res.exact = (Math.abs(pnt.x - res.x) <= best.radius) &&
1668 ((Math.abs(pnt.y - res.gry1) <= best.radius) || (Math.abs(pnt.y - res.gry2) <= best.radius));
1670 res.menu = res.exact;
1671 res.menu_dist = Math.sqrt((pnt.x-res.x)*(pnt.x-res.x) + Math.pow(Math.min(Math.abs(pnt.y-res.gry1),Math.abs(pnt.y-res.gry2)),2));
1674 if (this.fillatt && this.fillatt.used && !
this.fillatt.empty()) res.color2 =
this.fillatt.fillcolor();
1677 res.color1 = this.get_color(gr.fMarkerColor);
1678 if (!res.color2) res.color2 = res.color1;
1684 TGraphPainter.prototype.ShowTooltipForPath =
function(hint) {
1686 var ttbin = this.draw_g.select(
".tooltip_bin");
1688 if (!hint || !hint.bin) {
1694 ttbin = this.draw_g.append(
"svg:g")
1695 .attr(
"class",
"tooltip_bin");
1697 hint.changed = ttbin.property(
"current_bin") !== hint.bin;
1700 ttbin.selectAll(
"*").remove();
1701 ttbin.property(
"current_bin", hint.bin);
1704 ttbin.append(
"svg:rect")
1705 .attr(
"class",
"h1bin")
1706 .style(
"pointer-events",
"none")
1707 .style(
"opacity",
"0.3")
1708 .attr(
"x", Math.round(hint.x - hint.radius))
1709 .attr(
"y", Math.round(hint.y - hint.radius))
1710 .attr(
"width", 2*hint.radius)
1711 .attr(
"height", 2*hint.radius);
1713 ttbin.append(
"svg:circle").attr(
"cy", Math.round(hint.gry1))
1714 if (Math.abs(hint.gry1-hint.gry2) > 1)
1715 ttbin.append(
"svg:circle").attr(
"cy", Math.round(hint.gry2));
1717 var elem = ttbin.selectAll(
"circle")
1718 .attr(
"r", hint.radius)
1719 .attr(
"cx", Math.round(hint.x));
1721 if (!hint.islines) {
1722 elem.style(
'stroke', hint.color1 ==
'black' ?
'green' :
'black').style(
'fill',
'none');
1724 if (this.options.Line)
1725 elem.call(this.lineatt.func);
1727 elem.style(
'stroke',
'black');
1728 if (this.options.Fill)
1729 elem.call(this.fillatt.func);
1731 elem.style(
'fill',
'none');
1738 TGraphPainter.prototype.moveStart =
function(x,y) {
1739 this.pos_dx = this.pos_dy = 0;
1740 var hint = this.ExtractTooltip({x:x, y:y});
1741 if (hint && hint.exact && (hint.binindx !== undefined)) {
1742 this.move_binindx = hint.binindx;
1743 this.move_bin = hint.bin;
1744 var main = this.frame_painter();
1745 this.move_x0 = main ? main.grx(this.move_bin.x) : x;
1746 this.move_y0 = main ? main.gry(this.move_bin.y) : y;
1748 delete this.move_binindx;
1753 TGraphPainter.prototype.moveDrag =
function(dx,dy) {
1757 if (this.move_binindx === undefined) {
1758 this.draw_g.attr(
"transform",
"translate(" + this.pos_dx +
"," + this.pos_dy +
")");
1760 var main = this.frame_painter();
1761 if (main && this.move_bin) {
1762 this.move_bin.x = main.RevertX(this.move_x0 + this.pos_dx);
1763 this.move_bin.y = main.RevertY(this.move_y0 + this.pos_dy);
1770 TGraphPainter.prototype.moveEnd =
function(not_changed) {
1773 if (this.move_binindx === undefined) {
1775 this.draw_g.attr(
"transform", null);
1777 var main = this.frame_painter();
1778 if (main && this.bins && !not_changed) {
1779 for (var k=0;k<this.bins.length;++k) {
1780 var bin = this.bins[k];
1781 bin.x = main.RevertX(main.grx(bin.x) + this.pos_dx);
1782 bin.y = main.RevertY(main.gry(bin.y) + this.pos_dy);
1783 exec +=
"SetPoint(" + bin.indx +
"," + bin.x +
"," + bin.y +
");;";
1784 if ((bin.indx == 0) && this.MatchObjectType(
'TCutG'))
1785 exec +=
"SetPoint(" + (this.GetObject().fNpoints-1) +
"," + bin.x +
"," + bin.y +
");;";
1790 var exec =
"SetPoint(" + this.move_bin.indx +
"," + this.move_bin.x +
"," + this.move_bin.y +
")";
1791 if ((this.move_bin.indx == 0) &&
this.MatchObjectType(
'TCutG'))
1792 exec +=
";;SetPoint(" + (this.GetObject().fNpoints-1) +
"," + this.move_bin.x +
"," +
this.move_bin.y +
")";
1793 delete this.move_binindx;
1796 if (exec && !not_changed)
1797 this.WebCanvasExec(exec);
1800 TGraphPainter.prototype.FillContextMenu =
function(menu) {
1801 JSROOT.TObjectPainter.prototype.FillContextMenu.call(
this, menu);
1804 menu.addchk(this.TestEditable(),
"Editable", this.TestEditable.bind(
this,
true));
1806 return menu.size() > 0;
1809 TGraphPainter.prototype.ExecuteMenuCommand =
function(method, args) {
1810 if (JSROOT.TObjectPainter.prototype.ExecuteMenuCommand.call(
this,method,args))
return true;
1812 var canp = this.canv_painter(), fp = this.frame_painter();
1814 if ((method.fName ==
'RemovePoint') || (method.fName ==
'InsertPoint')) {
1815 var pnt = fp ? fp.GetLastEventPos() : null;
1817 if (!canp || canp._readonly || !fp || !pnt)
return true;
1819 var hint = this.ExtractTooltip(pnt);
1821 if (method.fName ==
'InsertPoint') {
1822 var main = this.frame_painter(),
1823 userx = main && main.RevertX ? main.RevertX(pnt.x) : 0,
1824 usery = main && main.RevertY ? main.RevertY(pnt.y) : 0;
1825 canp.ShowMessage(
'InsertPoint(' + userx.toFixed(3) +
',' + usery.toFixed(3) +
') not yet implemented');
1826 }
else if (this.args_menu_id && hint && (hint.binindx !== undefined)) {
1827 this.WebCanvasExec(
"RemovePoint(" + hint.binindx +
")",
this.args_menu_id);
1836 TGraphPainter.prototype.UpdateObject =
function(obj, opt) {
1837 if (!this.MatchObjectType(obj))
return false;
1839 if ((opt !== undefined) && (opt != this.options.original))
1840 this.DecodeOptions(opt);
1842 var graph = this.GetObject();
1844 graph.fBits = obj.fBits;
1845 graph.fTitle = obj.fTitle;
1848 graph.fNpoints = obj.fNpoints;
1852 if (this.axes_draw) {
1853 var main = this.main_painter(),
1854 fp = this.frame_painter();
1857 if (!fp.zoom_changed_interactive)
1858 main.UpdateObject(obj.fHistogram ||
this.CreateHistogram());
1860 main.GetObject().fTitle = graph.fTitle;
1866 TGraphPainter.prototype.CanZoomIn =
function(axis,min,max) {
1869 var gr = this.GetObject();
1870 if ((gr===null) || (axis!==
"x"))
return false;
1872 for (var n=0; n < gr.fNpoints; ++n)
1873 if ((min < gr.fX[n]) && (gr.fX[n] < max))
return true;
1878 TGraphPainter.prototype.ButtonClick =
function(funcname) {
1880 if (funcname !==
"ToggleZoom")
return false;
1882 var main = this.frame_painter();
1883 if (!main)
return false;
1885 if ((this.xmin===this.xmax) && (this.ymin===this.ymax))
return false;
1887 main.Zoom(this.xmin, this.xmax, this.ymin, this.ymax);
1892 TGraphPainter.prototype.FindFunc =
function() {
1893 var gr = this.GetObject();
1894 if (gr && gr.fFunctions)
1895 for (var i = 0; i < gr.fFunctions.arr.length; ++i) {
1896 var func = gr.fFunctions.arr[i];
1897 if ((func._typename ==
'TF1') || (func._typename ==
'TF2'))
return func;
1902 TGraphPainter.prototype.FindStat =
function() {
1903 var gr = this.GetObject();
1904 if (gr && gr.fFunctions)
1905 for (var i = 0; i < gr.fFunctions.arr.length; ++i) {
1906 var func = gr.fFunctions.arr[i];
1907 if ((func._typename ==
'TPaveStats') && (func.fName ==
'stats'))
return func;
1913 TGraphPainter.prototype.CreateStat =
function() {
1914 var func = this.FindFunc();
1915 if (!func)
return null;
1917 var stats = this.FindStat();
1918 if (stats)
return stats;
1921 var pp = this.canv_painter();
1922 if (pp && pp.normal_canvas)
return null;
1924 if (this.options.PadStats)
return null;
1926 this.create_stats =
true;
1928 var st = JSROOT.gStyle;
1930 stats = JSROOT.Create(
'TPaveStats');
1931 JSROOT.extend(stats, { fName :
'stats',
1933 fOptFit: st.fOptFit || 111,
1936 stats.fX1NDC = st.fStatX - st.fStatW;
1937 stats.fY1NDC = st.fStatY - st.fStatH;
1938 stats.fX2NDC = st.fStatX;
1939 stats.fY2NDC = st.fStatY;
1941 stats.fFillColor = st.fStatColor;
1942 stats.fFillStyle = st.fStatStyle;
1944 stats.fTextAngle = 0;
1945 stats.fTextSize = st.fStatFontSize;
1946 stats.fTextAlign = 12;
1947 stats.fTextColor = st.fStatTextColor;
1948 stats.fTextFont = st.fStatFont;
1950 stats.AddText(func.fName);
1953 this.GetObject().fFunctions.Add(stats);
1958 TGraphPainter.prototype.FillStatistic =
function(stat, dostat, dofit) {
1961 var func = this.FindFunc();
1963 if (!func || !dofit || !this.create_stats)
return false;
1967 stat.FillFunctionStat(func, dofit);
1972 TGraphPainter.prototype.DrawNextFunction =
function(indx, callback) {
1975 var graph = this.GetObject();
1977 if (!graph.fFunctions || (indx >= graph.fFunctions.arr.length))
1978 return JSROOT.CallBack(callback);
1980 var func = graph.fFunctions.arr[indx], opt = graph.fFunctions.opt[indx];
1984 func.$main_painter =
this;
1986 JSROOT.draw(this.divid, func, opt, this.DrawNextFunction.bind(
this, indx+1, callback));
1989 TGraphPainter.prototype.PerformDrawing =
function(divid, hpainter) {
1991 this.axes_draw =
true;
1992 if (!this._own_histogram) this.$primary =
true;
1993 hpainter.$secondary =
true;
1995 this.SetDivId(divid);
1997 if (this.TestEditable()) this.AddMove();
1998 this.DrawNextFunction(0, this.DrawingReady.bind(
this));
2002 function drawGraph(divid, graph, opt) {
2004 var painter =
new TGraphPainter(graph);
2006 painter.SetDivId(divid, -1);
2008 painter.DecodeOptions(opt);
2010 painter.CreateBins();
2012 painter.CreateStat();
2014 if (!painter.main_painter() && painter.options.HOptions) {
2015 JSROOT.draw(divid, painter.CreateHistogram(), painter.options.HOptions, painter.PerformDrawing.bind(painter, divid));
2017 painter.PerformDrawing(divid);
2025 function TGraphPolargramPainter(polargram) {
2026 JSROOT.TooltipHandler.call(
this, polargram);
2027 this.$polargram =
true;
2028 this.zoom_rmin = this.zoom_rmax = 0;
2031 TGraphPolargramPainter.prototype = Object.create(JSROOT.TooltipHandler.prototype);
2033 TGraphPolargramPainter.prototype.translate =
function(angle, radius, keep_float) {
2034 var _rx = this.r(radius), _ry = _rx/this.szx*this.szy,
2036 x: _rx * Math.cos(-angle - this.angle),
2037 y: _ry * Math.sin(-angle - this.angle),
2043 pos.x = Math.round(pos.x);
2044 pos.y = Math.round(pos.y);
2045 pos.rx = Math.round(pos.rx);
2046 pos.ry = Math.round(pos.ry);
2051 TGraphPolargramPainter.prototype.format =
function(radius) {
2054 if (radius === Math.round(radius))
return radius.toString();
2055 if (this.ndig>10)
return radius.toExponential(4);
2057 return radius.toFixed((this.ndig > 0) ? this.ndig : 0);
2060 TGraphPolargramPainter.prototype.AxisAsText =
function(axis, value) {
2063 if (value === Math.round(value))
return value.toString();
2064 if (this.ndig>10)
return value.toExponential(4);
2065 return value.toFixed(this.ndig+2);
2068 value *= 180/Math.PI;
2069 return (value === Math.round(value)) ? value.toString() : value.toFixed(1);
2072 TGraphPolargramPainter.prototype.MouseEvent =
function(kind) {
2073 var layer = this.svg_layer(
"primitives_layer"),
2074 interactive = layer.select(
".interactive_ellipse");
2075 if (interactive.empty())
return;
2079 if (kind !==
'leave') {
2080 var pos = d3.mouse(interactive.node());
2081 pnt = { x: pos[0], y: pos[1], touch:
false };
2084 this.ProcessTooltipEvent(pnt);
2087 TGraphPolargramPainter.prototype.GetFrameRect =
function() {
2088 var pad = this.root_pad(),
2089 w = this.pad_width(),
2090 h = this.pad_height(),
2093 rect.szx = Math.round(Math.max(0.1, 0.5 - Math.max(pad.fLeftMargin, pad.fRightMargin))*w);
2094 rect.szy = Math.round(Math.max(0.1, 0.5 - Math.max(pad.fBottomMargin, pad.fTopMargin))*h);
2096 rect.width = 2*rect.szx;
2097 rect.height = 2*rect.szy;
2098 rect.midx = Math.round(w/2);
2099 rect.midy = Math.round(h/2);
2100 rect.x = rect.midx - rect.szx;
2101 rect.y = rect.midy - rect.szy;
2103 rect.hint_delta_x = rect.szx;
2104 rect.hint_delta_y = rect.szy;
2106 rect.transform =
"translate(" + rect.x +
"," + rect.y +
")";
2111 TGraphPolargramPainter.prototype.MouseWheel =
function() {
2112 d3.event.stopPropagation();
2113 d3.event.preventDefault();
2115 this.ProcessTooltipEvent(null);
2117 var polar = this.GetObject();
2119 if (!d3.event || !polar)
return;
2121 var delta = d3.event.wheelDelta ? -d3.event.wheelDelta : (d3.event.deltaY || d3.event.detail);
2124 delta = (delta<0) ? -0.2 : 0.2;
2126 var rmin = this.scale_rmin, rmax = this.scale_rmax, range = rmax - rmin;
2129 rmax += delta*range;
2131 if ((rmin<polar.fRwrmin) || (rmax>polar.fRwrmax)) rmin = rmax = 0;
2133 if ((this.zoom_rmin != rmin) || (this.zoom_rmax != rmax)) {
2134 this.zoom_rmin = rmin;
2135 this.zoom_rmax = rmax;
2140 TGraphPolargramPainter.prototype.Redraw =
function() {
2141 if (!this.is_main_painter())
return;
2143 var pad = this.root_pad(),
2144 polar = this.GetObject(),
2145 rect = this.GetFrameRect();
2149 this.draw_g.attr(
"transform",
"translate(" + rect.midx +
"," + rect.midy +
")");
2150 this.szx = rect.szx;
2151 this.szy = rect.szy;
2153 this.scale_rmin = polar.fRwrmin;
2154 this.scale_rmax = polar.fRwrmax;
2155 if (this.zoom_rmin != this.zoom_rmax) {
2156 this.scale_rmin = this.zoom_rmin;
2157 this.scale_rmax = this.zoom_rmax;
2160 this.r = d3.scaleLinear().domain([this.scale_rmin, this.scale_rmax]).range([ 0, this.szx ]);
2161 this.angle = polar.fAxisAngle || 0;
2163 var ticks = this.r.ticks(5),
2164 nminor = Math.floor((polar.fNdivRad % 10000) / 100);
2166 this.createAttLine({ attr: polar });
2167 if (!this.gridatt) this.gridatt =
new JSROOT.TAttLineHandler({ color: polar.fLineColor, style: 2, width: 1 });
2169 var range = Math.abs(polar.fRwrmax - polar.fRwrmin);
2170 this.ndig = (range <= 0) ? -3 : Math.round(JSROOT.log10(ticks.length / range));
2173 var lbls = [], indx = 0;
2174 while (indx<ticks.length) {
2175 var lbl = this.format(ticks[indx]);
2176 if (lbls.indexOf(lbl)>=0) {
2177 if (++this.ndig>10)
break;
2178 lbls = []; indx = 0;
continue;
2184 var exclude_last =
false;
2186 if ((ticks[ticks.length-1] < polar.fRwrmax) && (
this.zoom_rmin ==
this.zoom_rmax)) {
2187 ticks.push(polar.fRwrmax);
2188 exclude_last =
true;
2191 this.StartTextDrawing(polar.fRadialLabelFont, Math.round(polar.fRadialTextSize *
this.szy * 2));
2193 for (var n=0;n<ticks.length;++n) {
2194 var rx = this.r(ticks[n]), ry = rx/this.szx*this.szy;
2195 this.draw_g.append(
"ellipse")
2198 .attr(
"rx",Math.round(rx))
2199 .attr(
"ry",Math.round(ry))
2200 .style(
"fill",
"none")
2201 .call(this.lineatt.func);
2203 if ((n < ticks.length-1) || !exclude_last)
2204 this.DrawText({ align: 23, x: Math.round(rx), y: Math.round(polar.fRadialTextSize *
this.szy * 0.5),
2205 text: this.format(ticks[n]), color: this.get_color[polar.fRadialLabelColor], latex: 0 });
2207 if ((nminor>1) && ((n < ticks.length-1) || !exclude_last)) {
2208 var dr = (ticks[1] - ticks[0]) / nminor;
2209 for (var nn=1;nn<nminor;++nn) {
2210 var gridr = ticks[n] + dr*nn;
2211 if (gridr > this.scale_rmax)
break;
2212 rx = this.r(gridr); ry = rx/this.szx*this.szy;
2213 this.draw_g.append(
"ellipse")
2216 .attr(
"rx",Math.round(rx))
2217 .attr(
"ry",Math.round(ry))
2218 .style(
"fill",
"none")
2219 .call(this.gridatt.func);
2224 this.FinishTextDrawing();
2226 var fontsize = Math.round(polar.fPolarTextSize *
this.szy * 2);
2227 this.StartTextDrawing(polar.fPolarLabelFont, fontsize);
2229 var nmajor = polar.fNdivPol % 100;
2230 if ((nmajor !== 8) && (nmajor !== 3)) nmajor = 8;
2232 var lbls = (nmajor==8) ? [
"0",
"#frac{#pi}{4}",
"#frac{#pi}{2}",
"#frac{3#pi}{4}",
"#pi",
"#frac{5#pi}{4}",
"#frac{3#pi}{2}",
"#frac{7#pi}{4}"] : [
"0",
"#frac{2#pi}{3}",
"#frac{4#pi}{3}"],
2233 aligns = [12, 11, 21, 31, 32, 33, 23, 13 ];
2235 for (var n=0;n<nmajor;++n) {
2236 var angle = -n*2*Math.PI/nmajor - this.angle;
2237 this.draw_g.append(
"line")
2240 .attr(
"x2", Math.round(
this.szx*Math.cos(angle)))
2241 .attr(
"y2", Math.round(
this.szy*Math.sin(angle)))
2242 .call(this.lineatt.func);
2244 var aindx = Math.round(16 -angle/Math.PI*4) % 8;
2246 this.DrawText({ align: aligns[aindx],
2247 x: Math.round((this.szx+fontsize)*Math.cos(angle)),
2248 y: Math.round((
this.szy + fontsize/
this.szx*
this.szy)*(Math.sin(angle))),
2250 color: this.get_color[polar.fPolarLabelColor], latex: 1 });
2253 this.FinishTextDrawing();
2255 var nminor = Math.floor((polar.fNdivPol % 10000) / 100);
2258 for (var n=0;n<nmajor*nminor;++n) {
2259 if (n % nminor === 0)
continue;
2260 var angle = -n*2*Math.PI/nmajor/nminor - this.angle;
2261 this.draw_g.append(
"line")
2264 .attr(
"x2", Math.round(
this.szx*Math.cos(angle)))
2265 .attr(
"y2", Math.round(
this.szy*Math.sin(angle)))
2266 .call(this.gridatt.func);
2270 if (JSROOT.BatchMode)
return;
2272 var layer = this.svg_layer(
"primitives_layer"),
2273 interactive = layer.select(
".interactive_ellipse");
2275 if (interactive.empty())
2276 interactive = layer.append(
"g")
2277 .classed(
"most_upper_primitives",
true)
2279 .classed(
"interactive_ellipse",
true)
2282 .style(
"fill",
"none")
2283 .style(
"pointer-events",
"visibleFill")
2284 .on(
'mouseenter', this.MouseEvent.bind(
this,
'enter'))
2285 .on(
'mousemove', this.MouseEvent.bind(
this,
'move'))
2286 .on(
'mouseleave', this.MouseEvent.bind(
this,
'leave'));
2288 interactive.attr(
"rx", this.szx).attr(
"ry", this.szy);
2290 d3.select(interactive.node().parentNode).attr(
"transform", this.draw_g.attr(
"transform"));
2292 if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel)
2293 interactive.on(
"wheel", this.MouseWheel.bind(
this));
2296 function drawGraphPolargram(divid, polargram, opt) {
2298 var painter =
new TGraphPolargramPainter(polargram);
2300 painter.SetDivId(divid, -1);
2302 var main = painter.main_painter();
2305 if (main.GetObject() !== polargram)
2306 console.error(
'Cannot superimpose TGraphPolargram with any other drawings');
2310 painter.SetDivId(divid, 4);
2312 return painter.DrawingReady();
2317 function TGraphPolarPainter(graph) {
2318 JSROOT.TObjectPainter.call(
this, graph);
2321 TGraphPolarPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2323 TGraphPolarPainter.prototype.Redraw =
function() {
2327 TGraphPolarPainter.prototype.DecodeOptions =
function(opt) {
2329 var d =
new JSROOT.DrawOptions(opt ||
"L");
2331 if (!this.options) this.options = {};
2333 JSROOT.extend(this.options, {
2341 this.OptionsStore(opt);
2344 TGraphPolarPainter.prototype.DrawBins =
function() {
2345 var graph = this.GetObject(),
2346 main = this.main_painter();
2348 if (!graph || !main || !main.$polargram)
return;
2350 if (this.options.mark) this.createAttMarker({ attr: graph });
2351 if (this.options.err ||
this.options.line ||
this.options.curve) this.createAttLine({ attr: graph });
2352 if (this.options.fill) this.createAttFill({ attr: graph });
2356 this.draw_g.attr(
"transform", main.draw_g.attr(
"transform"));
2358 var mpath =
"", epath =
"", lpath =
"", bins = [];
2360 for (var n=0;n<graph.fNpoints;++n) {
2362 if (graph.fY[n] > main.scale_rmax)
continue;
2364 if (this.options.err) {
2365 var pos1 = main.translate(graph.fX[n], graph.fY[n] - graph.fEY[n]),
2366 pos2 = main.translate(graph.fX[n], graph.fY[n] + graph.fEY[n]);
2367 epath +=
"M" + pos1.x +
"," + pos1.y +
"L" + pos2.x +
"," + pos2.y;
2369 pos1 = main.translate(graph.fX[n] + graph.fEX[n], graph.fY[n]);
2370 pos2 = main.translate(graph.fX[n] - graph.fEX[n], graph.fY[n]);
2372 epath +=
"M" + pos1.x +
"," + pos1.y +
"A" + pos2.rx +
"," + pos2.ry+
",0,0,1," + pos2.x +
"," + pos2.y;
2375 var pos = main.translate(graph.fX[n], graph.fY[n]);
2377 if (this.options.mark) {
2378 mpath += this.markeratt.create(pos.x, pos.y);
2381 if (this.options.line ||
this.options.fill) {
2382 lpath += (lpath ?
"L" :
"M") + pos.x +
"," + pos.y;
2385 if (this.options.curve) {
2392 if (this.options.fill && lpath)
2393 this.draw_g.append(
"svg:path")
2394 .attr(
"d",lpath +
"Z")
2395 .style(
"stroke",
"none")
2396 .call(this.fillatt.func);
2398 if (this.options.line && lpath)
2399 this.draw_g.append(
"svg:path")
2401 .style(
"fill",
"none")
2402 .call(this.lineatt.func);
2404 if (this.options.curve && bins.length)
2405 this.draw_g.append(
"svg:path")
2406 .attr(
"d", JSROOT.Painter.BuildSvgPath(
"bezier", bins).path)
2407 .style(
"fill",
"none")
2408 .call(this.lineatt.func);
2411 this.draw_g.append(
"svg:path")
2413 .style(
"fill",
"none")
2414 .call(this.lineatt.func);
2417 this.draw_g.append(
"svg:path")
2419 .call(this.markeratt.func);
2423 TGraphPolarPainter.prototype.CreatePolargram =
function() {
2424 var polargram = JSROOT.Create(
"TGraphPolargram"),
2425 gr = this.GetObject();
2427 var rmin = gr.fY[0] || 0, rmax = rmin;
2428 for (var n=0;n<gr.fNpoints;++n) {
2429 rmin = Math.min(rmin, gr.fY[n] - gr.fEY[n]);
2430 rmax = Math.max(rmax, gr.fY[n] + gr.fEY[n]);
2433 polargram.fRwrmin = rmin - (rmax-rmin)*0.1;
2434 polargram.fRwrmax = rmax + (rmax-rmin)*0.1;
2439 TGraphPolarPainter.prototype.ExtractTooltip =
function(pnt) {
2440 if (!pnt)
return null;
2442 var graph = this.GetObject(),
2443 main = this.main_painter(),
2444 best_dist2 = 1e10, bestindx = -1, bestpos = null;
2446 for (var n=0;n<graph.fNpoints;++n) {
2447 var pos = main.translate(graph.fX[n], graph.fY[n]);
2449 var dist2 = (pos.x-pnt.x)*(pos.x-pnt.x) + (pos.y-pnt.y)*(pos.y-pnt.y);
2450 if (dist2<best_dist2) { best_dist2 = dist2; bestindx = n; bestpos = pos; }
2453 var match_distance = 5;
2454 if (this.markeratt && this.markeratt.used) match_distance = this.markeratt.GetFullSize();
2456 if (Math.sqrt(best_dist2) > match_distance)
return null;
2458 var res = { name: this.GetObject().fName, title: this.GetObject().fTitle,
2459 x: bestpos.x, y: bestpos.y,
2460 color1: this.markeratt && this.markeratt.used ? this.markeratt.color : this.lineatt.color,
2461 exact: Math.sqrt(best_dist2) < 4,
2462 lines: [ this.GetTipName() ],
2464 menu_dist: match_distance,
2465 radius: match_distance
2468 res.lines.push(
"r = " + main.AxisAsText(
"r", graph.fY[bestindx]));
2469 res.lines.push(
"phi = " + main.AxisAsText(
"phi",graph.fX[bestindx]));
2471 if (graph.fEY && graph.fEY[bestindx])
2472 res.lines.push(
"error r = " + main.AxisAsText(
"r", graph.fEY[bestindx]));
2474 if (graph.fEX && graph.fEX[bestindx])
2475 res.lines.push(
"error phi = " + main.AxisAsText(
"phi", graph.fEX[bestindx]));
2480 TGraphPolarPainter.prototype.ShowTooltip =
function(hint) {
2482 if (!this.draw_g)
return;
2484 var ttcircle = this.draw_g.select(
".tooltip_bin");
2491 if (ttcircle.empty())
2492 ttcircle = this.draw_g.append(
"svg:ellipse")
2493 .attr(
"class",
"tooltip_bin")
2494 .style(
"pointer-events",
"none");
2496 hint.changed = ttcircle.property(
"current_bin") !== hint.binindx;
2499 ttcircle.attr(
"cx", hint.x)
2501 .attr(
"rx", Math.round(hint.radius))
2502 .attr(
"ry", Math.round(hint.radius))
2503 .style(
"fill",
"none")
2504 .style(
"stroke", hint.color1)
2505 .property(
"current_bin", hint.binindx);
2508 TGraphPolarPainter.prototype.ProcessTooltip =
function(pnt) {
2509 var hint = this.ExtractTooltip(pnt);
2510 if (!pnt || !pnt.disabled) this.ShowTooltip(hint);
2514 TGraphPolarPainter.prototype.PerformDrawing =
function(divid) {
2515 this.SetDivId(divid);
2517 this.DrawingReady();
2520 function drawGraphPolar(divid, graph, opt) {
2522 var painter =
new TGraphPolarPainter(graph);
2524 painter.DecodeOptions(opt);
2526 painter.SetDivId(divid, -1);
2528 var main = painter.main_painter();
2530 if (!main.$polargram) {
2531 console.error(
'Cannot superimpose TGraphPolar with plain histograms');
2534 painter.PerformDrawing(divid);
2539 if (!graph.fPolargram) graph.fPolargram = painter.CreatePolargram();
2541 return JSROOT.draw(divid, graph.fPolargram,
"", painter.PerformDrawing.bind(painter, divid));
2546 function TSplinePainter(spline) {
2547 JSROOT.TObjectPainter.call(
this, spline);
2551 TSplinePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2553 TSplinePainter.prototype.UpdateObject =
function(obj, opt) {
2554 var spline = this.GetObject();
2556 if (spline._typename != obj._typename)
return false;
2558 if (spline !== obj) JSROOT.extend(spline, obj);
2560 if (opt !== undefined) this.DecodeOptions(opt);
2565 TSplinePainter.prototype.Eval =
function(knot, x) {
2566 var dx = x - knot.fX;
2568 if (knot._typename ==
"TSplinePoly3")
2569 return knot.fY + dx*(knot.fB + dx*(knot.fC + dx*knot.fD));
2571 if (knot._typename ==
"TSplinePoly5")
2572 return knot.fY + dx*(knot.fB + dx*(knot.fC + dx*(knot.fD + dx*(knot.fE + dx*knot.fF))));
2574 return knot.fY + dx;
2577 TSplinePainter.prototype.FindX =
function(x) {
2578 var spline = this.GetObject(),
2579 klow = 0, khig = spline.fNp - 1;
2581 if (x <= spline.fXmin)
return 0;
2582 if (x >= spline.fXmax)
return khig;
2586 klow = Math.round((x - spline.fXmin)/spline.fDelta);
2588 if (x < spline.fPoly[klow].fX) {
2589 klow = Math.max(klow-1,0);
2590 }
else if (klow < khig) {
2591 if (x > spline.fPoly[klow+1].fX) ++klow;
2595 while(khig-klow>1) {
2596 var khalf = Math.round((klow+khig)/2);
2597 if(x > spline.fPoly[khalf].fX) klow = khalf;
2604 TSplinePainter.prototype.CreateDummyHisto =
function() {
2606 var xmin = 0, xmax = 1, ymin = 0, ymax = 1,
2607 spline = this.GetObject();
2609 if (spline && spline.fPoly) {
2611 xmin = xmax = spline.fPoly[0].fX;
2612 ymin = ymax = spline.fPoly[0].fY;
2614 spline.fPoly.forEach(
function(knot) {
2615 xmin = Math.min(knot.fX, xmin);
2616 xmax = Math.max(knot.fX, xmax);
2617 ymin = Math.min(knot.fY, ymin);
2618 ymax = Math.max(knot.fY, ymax);
2621 if (ymax > 0.0) ymax *= 1.05;
2622 if (ymin < 0.0) ymin *= 1.05;
2625 var histo = JSROOT.Create(
"TH1I");
2627 histo.fName = spline.fName +
"_hist";
2628 histo.fTitle = spline.fTitle;
2630 histo.fXaxis.fXmin = xmin;
2631 histo.fXaxis.fXmax = xmax;
2632 histo.fYaxis.fXmin = ymin;
2633 histo.fYaxis.fXmax = ymax;
2638 TSplinePainter.prototype.ProcessTooltip =
function(pnt) {
2640 var cleanup =
false,
2641 spline = this.GetObject(),
2642 main = this.frame_painter(),
2643 xx, yy, knot = null, indx = 0;
2645 if ((pnt === null) || !spline || !main) {
2648 xx = main.RevertX(pnt.x);
2649 indx = this.FindX(xx);
2650 knot = spline.fPoly[indx];
2651 yy = this.Eval(knot, xx);
2653 if ((indx < spline.fN-1) && (Math.abs(spline.fPoly[indx+1].fX-xx) < Math.abs(xx-knot.fX))) knot = spline.fPoly[++indx];
2655 if (Math.abs(main.grx(knot.fX) - pnt.x) < 0.5*this.knot_size) {
2656 xx = knot.fX; yy = knot.fY;
2659 if ((xx < spline.fXmin) || (xx > spline.fXmax)) cleanup =
true;
2664 if (this.draw_g !== null)
2665 this.draw_g.select(
".tooltip_bin").remove();
2669 var gbin = this.draw_g.select(
".tooltip_bin"),
2670 radius = this.lineatt.width + 3;
2673 gbin = this.draw_g.append(
"svg:circle")
2674 .attr(
"class",
"tooltip_bin")
2675 .style(
"pointer-events",
"none")
2677 .style(
"fill",
"none")
2678 .call(this.lineatt.func);
2680 var res = { name: this.GetObject().fName,
2681 title: this.GetObject().fTitle,
2684 color1: this.lineatt.color,
2686 exact: (knot !== null) || (Math.abs(main.gry(yy) - pnt.y) < radius) };
2688 res.changed = gbin.property(
"current_xx") !== xx;
2689 res.menu = res.exact;
2690 res.menu_dist = Math.sqrt((res.x-pnt.x)*(res.x-pnt.x) + (res.y-pnt.y)*(res.y-pnt.y));
2693 gbin.attr(
"cx", Math.round(res.x))
2694 .attr(
"cy", Math.round(res.y))
2695 .property(
"current_xx", xx);
2697 var name = this.GetTipName();
2698 if (name.length > 0) res.lines.push(name);
2699 res.lines.push(
"x = " + main.AxisAsText(
"x", xx))
2700 res.lines.push(
"y = " + main.AxisAsText(
"y", yy));
2701 if (knot !== null) {
2702 res.lines.push(
"knot = " + indx);
2703 res.lines.push(
"B = " + JSROOT.FFormat(knot.fB, JSROOT.gStyle.fStatFormat));
2704 res.lines.push(
"C = " + JSROOT.FFormat(knot.fC, JSROOT.gStyle.fStatFormat));
2705 res.lines.push(
"D = " + JSROOT.FFormat(knot.fD, JSROOT.gStyle.fStatFormat));
2706 if ((knot.fE!==undefined) && (knot.fF!==undefined)) {
2707 res.lines.push(
"E = " + JSROOT.FFormat(knot.fE, JSROOT.gStyle.fStatFormat));
2708 res.lines.push(
"F = " + JSROOT.FFormat(knot.fF, JSROOT.gStyle.fStatFormat));
2715 TSplinePainter.prototype.Redraw =
function() {
2717 var w = this.frame_width(),
2718 h = this.frame_height(),
2719 spline = this.GetObject(),
2720 pmain = this.frame_painter(),
2721 name = this.GetTipName(
"\n");
2727 this.createAttLine({ attr: spline });
2729 if (this.options.Line ||
this.options.Curve) {
2731 var npx = Math.max(10, spline.fNpx);
2733 var xmin = Math.max(pmain.scale_xmin, spline.fXmin),
2734 xmax = Math.min(pmain.scale_xmax, spline.fXmax),
2735 indx = this.FindX(xmin),
2739 xmin = Math.log(xmin);
2740 xmax = Math.log(xmax);
2743 for (var n=0;n<npx;++n) {
2744 var xx = xmin + (xmax-xmin)/npx*(n-1);
2745 if (pmain.logx) xx = Math.exp(xx);
2747 while ((indx < spline.fNp-1) && (xx > spline.fPoly[indx+1].fX)) ++indx;
2749 var yy = this.Eval(spline.fPoly[indx], xx);
2751 bins.push({ x: xx, y: yy, grx: pmain.grx(xx), gry: pmain.gry(yy) });
2755 if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) {
2756 h0 = Math.round(pmain.gry(0));
2757 if ((h0 > h) || (h0 < 0)) h0 = h;
2760 var path = JSROOT.Painter.BuildSvgPath(
"bezier", bins, h0, 2);
2762 this.draw_g.append(
"svg:path")
2763 .attr(
"class",
"line")
2764 .attr(
"d", path.path)
2765 .style(
"fill",
"none")
2766 .call(this.lineatt.func);
2769 if (this.options.Mark) {
2774 this.createAttMarker({ attr: spline })
2776 this.markeratt.reset_pos();
2778 this.knot_size = this.markeratt.GetFullSize();
2780 for (var n=0; n<spline.fPoly.length; n++) {
2781 var knot = spline.fPoly[n],
2782 grx = pmain.grx(knot.fX);
2783 if ((grx > -this.knot_size) && (grx < w + this.knot_size)) {
2784 var gry = pmain.gry(knot.fY);
2785 if ((gry > -this.knot_size) && (gry < h + this.knot_size)) {
2786 path += this.markeratt.create(grx, gry);
2792 this.draw_g.append(
"svg:path")
2794 .call(this.markeratt.func);
2799 TSplinePainter.prototype.CanZoomIn =
function(axis,min,max) {
2800 if (axis!==
"x")
return false;
2802 var spline = this.GetObject();
2803 if (!spline)
return false;
2809 TSplinePainter.prototype.DecodeOptions =
function(opt) {
2810 var d =
new JSROOT.DrawOptions(opt);
2812 if (!this.options) this.options = {};
2814 JSROOT.extend(this.options, {
2815 Same: d.check(
'SAME'),
2817 Curve: d.check(
'C'),
2821 this.OptionsStore(opt);
2824 TSplinePainter.prototype.FirstDraw =
function() {
2825 this.SetDivId(this.divid);
2827 return this.DrawingReady();
2830 JSROOT.Painter.drawSpline =
function(divid, spline, opt) {
2832 var painter =
new TSplinePainter(spline);
2834 painter.SetDivId(divid, -1);
2835 painter.DecodeOptions(opt);
2837 if (!painter.main_painter()) {
2838 if (painter.options.Same) {
2839 console.warn(
'TSpline painter requires histogram to be drawn');
2842 var histo = painter.CreateDummyHisto();
2843 JSROOT.draw(divid, histo,
"AXIS", painter.FirstDraw.bind(painter));
2847 return painter.FirstDraw();
2852 function TGraphTimePainter(gr) {
2853 JSROOT.TObjectPainter.call(
this, gr);
2856 TGraphTimePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2858 TGraphTimePainter.prototype.Redraw =
function() {
2859 if (this.step === undefined) this.StartDrawing(
false);
2862 TGraphTimePainter.prototype.DecodeOptions =
function(opt) {
2864 var d =
new JSROOT.DrawOptions(opt ||
"REPEAT");
2866 if (!this.options) this.options = {};
2868 JSROOT.extend(this.options, {
2869 once: d.check(
"ONCE"),
2870 repeat: d.check(
"REPEAT"),
2871 first: d.check(
"FIRST")
2874 this.OptionsStore(opt);
2877 TGraphTimePainter.prototype.DrawPrimitives =
function(indx, callback, ppainter) {
2880 this._doing_primitives =
true;
2883 var lst = this.GetObject().fSteps.arr[this.step];
2886 if (ppainter) ppainter.$grtimeid = this.selfid;
2888 if (!lst || (indx >= lst.arr.length)) {
2889 delete this._doing_primitives;
2890 return JSROOT.CallBack(callback);
2894 var handle = { func: this.DrawPrimitives.bind(
this, indx+1, callback) };
2896 ppainter = JSROOT.draw(this.divid, lst.arr[indx], lst.opt[indx], handle);
2898 if (!handle.completed)
return;
2903 TGraphTimePainter.prototype.Selector =
function(p) {
2904 return p && (p.$grtimeid === this.selfid);
2907 TGraphTimePainter.prototype.ContineDrawing =
function() {
2908 if (!this.options)
return;
2910 var gr = this.GetObject();
2912 if (!this.ready_called) {
2913 this.ready_called =
true;
2914 this.DrawingReady();
2917 if (this.options.first) {
2923 if (this.wait_animation_frame) {
2924 delete this.wait_animation_frame;
2927 var pp = this.pad_painter();
2935 pp.CleanPrimitives(this.Selector.bind(
this));
2938 this.DrawPrimitives(0, this.ContineDrawing.bind(
this));
2939 }
else if (this.running_timeout) {
2940 clearTimeout(this.running_timeout);
2941 delete this.running_timeout;
2943 this.wait_animation_frame =
true;
2945 requestAnimationFrame(this.ContineDrawing.bind(
this));
2948 var sleeptime = gr.fSleepTime;
2949 if (!sleeptime || (sleeptime<100)) sleeptime = 10;
2951 if (++this.step > gr.fSteps.arr.length) {
2952 if (this.options.repeat) {
2954 sleeptime = Math.max(5000, 5*sleeptime);
2961 this.running_timeout = setTimeout(this.ContineDrawing.bind(
this), sleeptime);
2965 TGraphTimePainter.prototype.StartDrawing =
function(once_again) {
2966 if (once_again!==
false) this.SetDivId(this.divid);
2970 this.DrawPrimitives(0, this.ContineDrawing.bind(
this));
2973 JSROOT.Painter.drawGraphTime =
function(divid,gr,opt) {
2975 var painter =
new TGraphTimePainter(gr);
2976 painter.SetDivId(divid,-1);
2978 if (painter.main_painter()) {
2979 console.error(
'Cannot draw graph time on top of other histograms');
2984 console.error(
'Frame histogram not exists');
2988 painter.DecodeOptions(opt);
2990 if (!gr.fFrame.fTitle && gr.fTitle) gr.fFrame.fTitle = gr.fTitle;
2992 painter.selfid =
"grtime" + JSROOT.id_counter++;
2994 JSROOT.draw(divid, gr.fFrame,
"AXIS", painter.StartDrawing.bind(painter));
3002 function TEfficiencyPainter(eff) {
3003 JSROOT.TObjectPainter.call(
this, eff);
3004 this.fBoundary =
'Normal';
3007 TEfficiencyPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
3009 TEfficiencyPainter.prototype.GetEfficiency =
function(bin) {
3010 var obj = this.GetObject(),
3011 total = obj.fTotalHistogram.getBinContent(bin),
3012 passed = obj.fPassedHistogram.getBinContent(bin);
3014 return total ? passed/total : 0;
3028 TEfficiencyPainter.prototype.Normal =
function(total,passed,level,bUpper) {
3029 if (total == 0)
return bUpper ? 1 : 0;
3031 var alpha = (1.0 - level)/2,
3032 average = passed / total,
3033 sigma = Math.sqrt(average * (1 - average) / total),
3034 delta = JSROOT.Math.normal_quantile(1 - alpha,sigma);
3037 return ((average + delta) > 1) ? 1.0 : (average + delta);
3039 return ((average - delta) < 0) ? 0.0 : (average - delta);
3042 TEfficiencyPainter.prototype.GetEfficiencyErrorLow =
function(bin) {
3043 var obj = this.GetObject(),
3044 total = obj.fTotalHistogram.getBinContent(bin),
3045 passed = obj.fPassedHistogram.getBinContent(bin),
3046 eff = this.GetEfficiency(bin);
3048 return eff -
this[this.fBoundary](total,passed, obj.fConfLevel,
false);
3051 TEfficiencyPainter.prototype.GetEfficiencyErrorUp =
function(bin) {
3052 var obj = this.GetObject(),
3053 total = obj.fTotalHistogram.getBinContent(bin),
3054 passed = obj.fPassedHistogram.getBinContent(bin),
3055 eff = this.GetEfficiency(bin);
3057 return this[this.fBoundary]( total, passed, obj.fConfLevel,
true) - eff;
3060 TEfficiencyPainter.prototype.CreateGraph =
function() {
3061 var gr = JSROOT.Create(
'TGraphAsymmErrors');
3062 gr.fName =
"eff_graph";
3066 TEfficiencyPainter.prototype.FillGraph =
function(gr, opt) {
3067 var eff = this.GetObject(),
3068 npoints = eff.fTotalHistogram.fXaxis.fNbins,
3069 option = opt.toLowerCase(),
3070 plot0Bins =
false, j = 0;
3071 if (option.indexOf(
"e0")>=0) plot0Bins =
true;
3072 for (var n=0;n<npoints;++n) {
3073 if (!plot0Bins && eff.fTotalHistogram.getBinContent(n+1) === 0)
continue;
3074 gr.fX[j] = eff.fTotalHistogram.fXaxis.GetBinCenter(n+1);
3075 gr.fY[j] = this.GetEfficiency(n+1);
3076 gr.fEXlow[j] = eff.fTotalHistogram.fXaxis.GetBinCenter(n+1) - eff.fTotalHistogram.fXaxis.GetBinLowEdge(n+1);
3077 gr.fEXhigh[j] = eff.fTotalHistogram.fXaxis.GetBinLowEdge(n+2) - eff.fTotalHistogram.fXaxis.GetBinCenter(n+1);
3078 gr.fEYlow[j] = this.GetEfficiencyErrorLow(n+1);
3079 gr.fEYhigh[j] = this.GetEfficiencyErrorUp(n+1);
3085 JSROOT.Painter.drawEfficiency =
function(divid, eff, opt) {
3087 if (!eff || !eff.fTotalHistogram || (eff.fTotalHistogram._typename.indexOf(
"TH1")!=0))
return null;
3089 var painter =
new TEfficiencyPainter(eff);
3090 painter.options = opt;
3092 var gr = painter.CreateGraph();
3093 painter.FillGraph(gr, opt);
3095 JSROOT.draw(divid, gr, opt,
function() {
3096 painter.SetDivId(divid);
3097 painter.DrawingReady();
3106 function TMultiGraphPainter(mgraph) {
3107 JSROOT.TObjectPainter.call(
this, mgraph);
3108 this.firstpainter = null;
3109 this.autorange =
false;
3113 TMultiGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
3115 TMultiGraphPainter.prototype.Cleanup =
function() {
3117 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
3120 TMultiGraphPainter.prototype.UpdateObject =
function(obj) {
3121 if (!this.MatchObjectType(obj))
return false;
3123 var mgraph = this.GetObject(),
3124 graphs = obj.fGraphs;
3126 mgraph.fTitle = obj.fTitle;
3129 if (this.firstpainter) {
3130 var histo = obj.fHistogram;
3131 if (this.autorange && !histo)
3132 histo = this.ScanGraphsRange(graphs);
3134 if (this.firstpainter.UpdateObject(histo)) isany =
true;
3137 for (var i = 0; i < graphs.arr.length; ++i) {
3138 if (i<this.painters.length)
3139 if (this.painters[i].UpdateObject(graphs.arr[i])) isany =
true;
3143 for (var i = 0; i < obj.fFunctions.arr.length; ++i) {
3144 var func = obj.fFunctions.arr[i];
3145 if (!func || !func._typename || !func.fName)
continue;
3146 var funcpainter = this.FindPainterFor(null, func.fName, func._typename);
3147 if (funcpainter) funcpainter.UpdateObject(func);
3153 TMultiGraphPainter.prototype.ComputeGraphRange =
function(res, gr) {
3155 if (gr.fNpoints == 0)
return;
3157 res.xmin = res.xmax = gr.fX[0];
3158 res.ymin = res.ymax = gr.fY[0];
3161 for (var i=0; i < gr.fNpoints; ++i) {
3162 res.xmin = Math.min(res.xmin, gr.fX[i]);
3163 res.xmax = Math.max(res.xmax, gr.fX[i]);
3164 res.ymin = Math.min(res.ymin, gr.fY[i]);
3165 res.ymax = Math.max(res.ymax, gr.fY[i]);
3170 TMultiGraphPainter.prototype.padtoX =
function(pad, x) {
3172 if (pad.fLogx && (x < 50))
3173 return Math.exp(2.302585092994 * x);
3177 TMultiGraphPainter.prototype.ScanGraphsRange =
function(graphs, histo, pad) {
3178 var mgraph = this.GetObject(),
3179 maximum, minimum, dx, dy, uxmin = 0, uxmax = 0, logx =
false, logy =
false,
3180 time_display =
false, time_format =
"",
3181 rw = { xmin: 0, xmax: 0, ymin: 0, ymax: 0, first:
true };
3186 rw.xmin = pad.fUxmin;
3187 rw.xmax = pad.fUxmax;
3188 rw.ymin = pad.fUymin;
3189 rw.ymax = pad.fUymax;
3193 minimum = histo.fYaxis.fXmin;
3194 maximum = histo.fYaxis.fXmax;
3196 uxmin = this.padtoX(pad, rw.xmin);
3197 uxmax = this.padtoX(pad, rw.xmax);
3200 this.autorange =
true;
3202 for (var i = 0; i < graphs.arr.length; ++i)
3203 this.ComputeGraphRange(rw, graphs.arr[i]);
3205 if (graphs.arr[0] && graphs.arr[0].fHistogram && graphs.arr[0].fHistogram.fXaxis.fTimeDisplay) {
3206 time_display =
true;
3207 time_format = graphs.arr[0].fHistogram.fXaxis.fTimeFormat;
3210 if (rw.xmin == rw.xmax) rw.xmax += 1.;
3211 if (rw.ymin == rw.ymax) rw.ymax += 1.;
3212 dx = 0.05 * (rw.xmax - rw.xmin);
3213 dy = 0.05 * (rw.ymax - rw.ymin);
3214 uxmin = rw.xmin - dx;
3215 uxmax = rw.xmax + dx;
3217 if (rw.ymin <= 0) rw.ymin = 0.001 * rw.ymax;
3218 minimum = rw.ymin / (1 + 0.5 * JSROOT.log10(rw.ymax / rw.ymin));
3219 maximum = rw.ymax * (1 + 0.2 * JSROOT.log10(rw.ymax / rw.ymin));
3221 minimum = rw.ymin - dy;
3222 maximum = rw.ymax + dy;
3224 if (minimum < 0 && rw.ymin >= 0)
3226 if (maximum > 0 && rw.ymax <= 0)
3230 if (uxmin < 0 && rw.xmin >= 0)
3231 uxmin = logx ? 0.9 * rw.xmin : 0;
3232 if (uxmax > 0 && rw.xmax <= 0)
3233 uxmax = logx? 1.1 * rw.xmax : 0;
3235 if (mgraph.fMinimum != -1111)
3236 rw.ymin = minimum = mgraph.fMinimum;
3237 if (mgraph.fMaximum != -1111)
3238 rw.ymax = maximum = mgraph.fMaximum;
3240 if (minimum < 0 && rw.ymin >= 0 && logy) minimum = 0.9 * rw.ymin;
3241 if (maximum > 0 && rw.ymax <= 0 && logy) maximum = 1.1 * rw.ymax;
3242 if (minimum <= 0 && logy) minimum = 0.001 * maximum;
3243 if (!logy && minimum > 0 && minimum < 0.05*maximum) minimum = 0;
3244 if (uxmin <= 0 && logx)
3245 uxmin = (uxmax > 1000) ? 1 : 0.001 * uxmax;
3249 histo = JSROOT.Create(
"TH1I");
3250 histo.fTitle = mgraph.fTitle;
3251 histo.fXaxis.fXmin = uxmin;
3252 histo.fXaxis.fXmax = uxmax;
3253 histo.fXaxis.fTimeDisplay = time_display;
3254 if (time_display) histo.fXaxis.fTimeFormat = time_format;
3257 histo.fYaxis.fXmin = minimum;
3258 histo.fYaxis.fXmax = maximum;
3263 TMultiGraphPainter.prototype.DrawAxis =
function(callback) {
3266 var mgraph = this.GetObject(),
3267 histo = this.ScanGraphsRange(mgraph.fGraphs, mgraph.fHistogram,
this.root_pad());
3271 JSROOT.draw(this.divid, histo,
"AXIS", callback);
3274 TMultiGraphPainter.prototype.DrawNextFunction =
function(indx, callback) {
3277 var mgraph = this.GetObject();
3279 if (!mgraph.fFunctions || (indx >= mgraph.fFunctions.arr.length))
3280 return JSROOT.CallBack(callback);
3282 JSROOT.draw(this.divid, mgraph.fFunctions.arr[indx], mgraph.fFunctions.opt[indx],
3283 this.DrawNextFunction.bind(
this, indx+1, callback));
3286 TMultiGraphPainter.prototype.DrawNextGraph =
function(indx, opt, subp, used_timeout) {
3287 if (subp) this.painters.push(subp);
3289 var graphs = this.GetObject().fGraphs;
3292 if (indx >= graphs.arr.length) {
3293 this._pfc = this._plc = this._pmc =
false;
3294 return this.DrawNextFunction(0, this.DrawingReady.bind(
this));
3298 if ((indx % 500 === 499) && !used_timeout)
3299 return setTimeout(this.DrawNextGraph.bind(
this,indx,opt,null,
true),0);
3302 if (this._pfc || this._plc || this._pmc) {
3303 if (!this.pallette && JSROOT.Painter.GetColorPalette)
3304 this.palette = JSROOT.Painter.GetColorPalette();
3306 var color = this.palette.calcColor(indx, graphs.arr.length+1);
3307 var icolor = this.add_color(color);
3309 if (this._pfc) graphs.arr[indx].fFillColor = icolor;
3310 if (this._plc) graphs.arr[indx].fLineColor = icolor;
3311 if (this._pmc) graphs.arr[indx].fMarkerColor = icolor;
3315 JSROOT.draw(this.divid, graphs.arr[indx], graphs.opt[indx] || opt,
3316 this.DrawNextGraph.bind(
this, indx+1, opt));
3319 JSROOT.Painter.drawMultiGraph =
function(divid, mgraph, opt) {
3321 var painter =
new TMultiGraphPainter(mgraph);
3323 painter.SetDivId(divid, -1);
3325 var d =
new JSROOT.DrawOptions(opt);
3326 d.check(
"3D"); d.check(
"FB");
3328 painter._pfc = d.check(
"PFC");
3329 painter._plc = d.check(
"PLC");
3330 painter._pmc = d.check(
"PMC");
3332 if (d.check(
"A") || !painter.main_painter()) {
3333 painter.DrawAxis(
function(hpainter) {
3334 painter.firstpainter = hpainter;
3335 painter.SetDivId(divid);
3336 painter.DrawNextGraph(0, d.remain());
3339 painter.SetDivId(divid);
3340 painter.DrawNextGraph(0, d.remain());
3348 function drawWebPainting(divid, obj, opt) {
3350 var painter =
new JSROOT.TObjectPainter(obj, opt);
3352 painter.UpdateObject =
function(obj) {
3353 if (!this.MatchObjectType(obj))
return false;
3354 this.draw_object = obj;
3358 painter.ReadAttr =
function(str, names) {
3359 var lastp = 0, obj = { _typename:
"any" };
3360 for (var k=0;k<names.length;++k) {
3361 var p = str.indexOf(
":", lastp+1);
3362 obj[names[k]] = parseInt(str.substr(lastp+1, (p>lastp) ? p-lastp-1 : undefined));
3368 painter.Redraw =
function() {
3370 var obj = this.GetObject(), func = this.AxisToSvgFunc();
3372 if (!obj || !obj.fOper || !func)
return;
3374 var indx = 0, attr = {}, lastpath = null, lastkind =
"none", d =
"",
3375 oper, k, npoints, n, arr = obj.fOper.split(
";");
3377 function check_attributes(painter, kind) {
3378 if (kind == lastkind)
return;
3381 lastpath.attr(
"d", d);
3382 d =
""; lastpath = null; lastkind =
"none";
3388 lastpath = painter.draw_g.append(
"svg:path");
3390 case "f": lastpath.call(painter.fillatt.func).attr(
'stroke',
'none');
break;
3391 case "l": lastpath.call(painter.lineatt.func).attr(
'fill',
'none');
break;
3392 case "m": lastpath.call(painter.markeratt.func);
break;
3398 for (k=0;k<arr.length;++k) {
3402 this.createAttLine({ attr: this.ReadAttr(arr[k], [
"fLineColor",
"fLineStyle",
"fLineWidth"]), force:
true });
3406 this.createAttFill({ attr: this.ReadAttr(arr[k], [
"fFillColor",
"fFillStyle"]), force:
true });
3410 this.createAttMarker({ attr: this.ReadAttr(arr[k], [
"fMarkerColor",
"fMarkerStyle",
"fMarkerSize"]), force:
true })
3414 attr = this.ReadAttr(arr[k], [
"fTextColor",
"fTextFont",
"fTextSize",
"fTextAlign",
"fTextAngle" ]);
3415 if (attr.fTextSize < 0) attr.fTextSize *= -0.001;
3421 check_attributes(
this, (oper ==
"b") ?
"f" :
"l");
3423 var x1 = func.x(obj.fBuf[indx++]),
3424 y1 = func.y(obj.fBuf[indx++]),
3425 x2 = func.x(obj.fBuf[indx++]),
3426 y2 = func.y(obj.fBuf[indx++]);
3428 d +=
"M"+x1+
","+y1+
"h"+(x2-x1)+
"v"+(y2-y1)+
"h"+(x1-x2)+
"z";
3435 check_attributes(
this, oper);
3437 npoints = parseInt(arr[k].substr(1));
3439 for (n=0;n<npoints;++n)
3440 d += ((n>0) ?
"L" :
"M") +
3441 func.x(obj.fBuf[indx++]) +
"," + func.y(obj.fBuf[indx++]);
3443 if (oper ==
"f") d+=
"Z";
3450 check_attributes(
this, oper);
3452 npoints = parseInt(arr[k].substr(1));
3454 this.markeratt.reset_pos();
3455 for (n=0;n<npoints;++n)
3456 d += this.markeratt.create(func.x(obj.fBuf[indx++]), func.y(obj.fBuf[indx++]));
3463 if (attr.fTextSize) {
3467 var height = (attr.fTextSize > 1) ? attr.fTextSize :
this.pad_height() * attr.fTextSize;
3469 var group = this.draw_g.append(
"svg:g");
3471 this.StartTextDrawing(attr.fTextFont, height, group);
3473 var angle = attr.fTextAngle;
3474 if (angle >= 360) angle -= Math.floor(angle/360) * 360;
3476 var txt = arr[k].substr(1);
3480 for (n=0;n<txt.length;n+=2)
3481 res += String.fromCharCode(parseInt(txt.substr(n,2), 16));
3486 this.DrawText({ align: attr.fTextAlign,
3487 x: func.x(obj.fBuf[indx++]),
3488 y: func.y(obj.fBuf[indx++]),
3491 color: JSROOT.Painter.root_colors[attr.fTextColor], latex: 0, draw_g: group });
3493 this.FinishTextDrawing(group);
3499 console.log(
'unsupported operation ' + oper);
3506 painter.SetDivId(divid);
3510 return painter.DrawingReady();
3513 JSROOT.Painter.drawASImage =
function(divid, obj, opt) {
3514 var painter =
new JSROOT.TBasePainter();
3515 painter.SetDivId(divid, -1);
3517 var main = painter.select_main();
3528 painter.SetDivId(divid);
3530 return painter.DrawingReady();
3533 JSROOT.Painter.drawJSImage =
function(divid, obj, opt) {
3534 var painter =
new JSROOT.TBasePainter();
3535 painter.SetDivId(divid, -1);
3537 var main = painter.select_main();
3540 var img = main.append(
"img").attr(
"src", obj.fName).attr(
"title", obj.fTitle || obj.fName);
3542 if (opt && opt.indexOf(
"scale")>=0) {
3543 img.style(
"width",
"100%").style(
"height",
"100%");
3544 }
else if (opt && opt.indexOf(
"center")>=0) {
3545 main.style(
"position",
"relative");
3546 img.attr(
"style",
"margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);");
3549 painter.SetDivId(divid);
3551 return painter.DrawingReady();
3557 JSROOT.Painter.CreateBranchItem =
function(node, branch, tree, parent_branch) {
3558 if (!node || !branch)
return false;
3560 var nb_branches = branch.fBranches ? branch.fBranches.arr.length : 0,
3561 nb_leaves = branch.fLeaves ? branch.fLeaves.arr.length : 0;
3563 function ClearName(arg) {
3564 var pos = arg.indexOf(
"[");
3565 if (pos>0) arg = arg.substr(0, pos);
3566 if (parent_branch && arg.indexOf(parent_branch.fName)==0) {
3567 arg = arg.substr(parent_branch.fName.length);
3568 if (arg[0]===
".") arg = arg.substr(1);
3573 branch.$tree = tree;
3576 _name : ClearName(branch.fName),
3577 _kind :
"ROOT." + branch._typename,
3578 _title : branch.fTitle,
3582 if (!node._childs) node._childs = [];
3584 node._childs.push(subitem);
3586 if (branch._typename===
'TBranchElement')
3587 subitem._title +=
" from " + branch.fClassName +
";" + branch.fClassVersion;
3589 if (nb_branches > 0) {
3590 subitem._more =
true;
3591 subitem._expand =
function(bnode,bobj) {
3593 if (!bobj)
return false;
3595 if (!bnode._childs) bnode._childs = [];
3597 if (bobj.fLeaves && (bobj.fLeaves.arr.length === 1) &&
3598 ((bobj.fType === JSROOT.BranchType.kClonesNode) || (bobj.fType === JSROOT.BranchType.kSTLNode))) {
3599 bobj.fLeaves.arr[0].$branch = bobj;
3600 bnode._childs.push({
3602 _title:
"container size",
3603 _kind:
"ROOT.TLeafElement",
3605 _obj: bobj.fLeaves.arr[0],
3610 for (var i=0; i<bobj.fBranches.arr.length; ++i)
3611 JSROOT.Painter.CreateBranchItem(bnode, bobj.fBranches.arr[i], bobj.$tree, bobj);
3613 var object_class = JSROOT.IO.GetBranchObjectClass(bobj, bobj.$tree,
true),
3614 methods = object_class ? JSROOT.getMethods(object_class) : null;
3616 if (methods && (bobj.fBranches.arr.length>0))
3617 for (var key in methods) {
3618 if (typeof methods[key] !==
'function')
continue;
3619 var s = methods[key].toString();
3620 if ((s.indexOf(
"return")>0) && (s.indexOf(
"function ()")==0))
3621 bnode._childs.push({
3623 _title:
"function " + key +
" of class " + object_class,
3624 _kind:
"ROOT.TBranchFunc",
3625 _obj: { _typename:
"TBranchFunc", branch: bobj, func: key },
3634 }
else if (nb_leaves === 1) {
3635 subitem._icon =
"img_leaf";
3636 subitem._more =
false;
3637 }
else if (nb_leaves > 1) {
3638 subitem._childs = [];
3639 for (var j = 0; j < nb_leaves; ++j) {
3640 branch.fLeaves.arr[j].$branch = branch;
3642 _name : ClearName(branch.fLeaves.arr[j].fName),
3643 _kind :
"ROOT." + branch.fLeaves.arr[j]._typename,
3644 _obj: branch.fLeaves.arr[j]
3646 subitem._childs.push(leafitem);
3653 JSROOT.Painter.TreeHierarchy =
function(node, obj) {
3654 if (obj._typename !=
'TTree' && obj._typename !=
'TNtuple' && obj._typename !=
'TNtupleD' )
return false;
3659 for (var i=0; i<obj.fBranches.arr.length; ++i)
3660 JSROOT.Painter.CreateBranchItem(node, obj.fBranches.arr[i], obj);
3669 JSROOT.Painter.drawTree =
function(divid, obj, opt) {
3671 var painter =
new JSROOT.TObjectPainter(obj),
3672 tree = obj, args = opt;
3674 if (obj._typename ==
"TBranchFunc") {
3676 args = { expr:
"." + obj.func +
"()", branch: obj.branch };
3677 if (opt && opt.indexOf(
"dump")==0) args.expr +=
">>" + opt;
else
3678 if (opt) args.expr += opt;
3679 tree = obj.branch.$tree;
3680 }
else if (obj.$branch) {
3682 args = { expr:
"." + obj.fName + (opt ||
""), branch: obj.$branch };
3683 if ((args.branch.fType === JSROOT.BranchType.kClonesNode) || (args.branch.fType === JSROOT.BranchType.kSTLNode)) {
3686 args.direct_branch =
true;
3689 tree = obj.$branch.$tree;
3690 }
else if (obj.$tree) {
3694 if (!opt && obj.fStreamerType && (obj.fStreamerType !== JSROOT.IO.kTString) &&
3695 (obj.fStreamerType >= JSROOT.IO.kObject) && (obj.fStreamerType <= JSROOT.IO.kAnyP)) opt =
"dump";
3697 args = { expr: opt, branch: obj };
3701 if ((args===
'player') || !args) {
3702 JSROOT.AssertPrerequisites(
"jq2d",
function() {
3703 JSROOT.CreateTreePlayer(painter);
3704 painter.ConfigureTree(tree);
3705 painter.Show(divid);
3706 painter.DrawingReady();
3711 if (typeof args ===
'string') args = { expr: args };
3715 console.error(
'No TTree object available for TTree::Draw');
3716 return painter.DrawingReady();
3719 var callback = painter.DrawingReady.bind(painter);
3720 painter._return_res_painter =
true;
3722 JSROOT.cleanup(divid);
3724 tree.Draw(args,
function(histo, hopt, intermediate) {
3728 if (!args.player) drawid = divid;
else
3729 if (args.create_player === 2) drawid = painter.drawid;
3732 return JSROOT.redraw(drawid, histo, hopt, intermediate ? null : callback);
3734 if (args.create_player === 1) { args.player_intermediate = intermediate;
return; }
3737 args.player_create = 1;
3738 args.player_intermediate = intermediate;
3739 JSROOT.AssertPrerequisites(
"jq2d",
function() {
3740 JSROOT.CreateTreePlayer(painter);
3741 painter.ConfigureTree(tree);
3742 painter.Show(divid, args);
3743 args.create_player = 2;
3744 JSROOT.redraw(painter.drawid, histo, hopt, args.player_intermediate ? null : callback);
3745 painter.SetItemName(
"TreePlayer");
3755 JSROOT.Painter.drawText = drawText;
3756 JSROOT.Painter.drawLine = drawLine;
3757 JSROOT.Painter.drawPolyLine = drawPolyLine;
3758 JSROOT.Painter.drawArrow = drawArrow;
3759 JSROOT.Painter.drawEllipse = drawEllipse;
3760 JSROOT.Painter.drawPie = drawPie;
3761 JSROOT.Painter.drawBox = drawBox;
3762 JSROOT.Painter.drawMarker = drawMarker;
3763 JSROOT.Painter.drawPolyMarker = drawPolyMarker;
3764 JSROOT.Painter.drawWebPainting = drawWebPainting;
3765 JSROOT.Painter.drawRooPlot = drawRooPlot;
3766 JSROOT.Painter.drawGraph = drawGraph;
3767 JSROOT.Painter.drawFunction = drawFunction;
3768 JSROOT.Painter.drawGraphPolar = drawGraphPolar;
3769 JSROOT.Painter.drawGraphPolargram = drawGraphPolargram;
3771 JSROOT.TF1Painter = TF1Painter;
3772 JSROOT.TGraphPainter = TGraphPainter;
3773 JSROOT.TGraphPolarPainter = TGraphPolarPainter;
3774 JSROOT.TMultiGraphPainter = TMultiGraphPainter;
3775 JSROOT.TSplinePainter = TSplinePainter;