7 if (typeof
JSROOT !=
"object") {
8 var e1 =
new Error(
"go4canvas.js requires JSROOT to be already loaded");
9 e1.source =
"go4canvas.js";
13 var myGO4 = {
version:
"6.1.x", web_canvas:
true };
26 if (!BasePainter.prototype.get_main_id) {
29 BasePainter.prototype.get_main_id =
function() {
30 var elem = this.selectDom();
31 if (elem.empty())
return "";
32 var
id = elem.attr(
"id");
34 id =
"go4_element_" +
GO4.id_counter++;
44 BasePainter.prototype.getItemName = BasePainter.prototype.GetItemName;
45 ObjectPainter.prototype.getObject = ObjectPainter.prototype.GetObject;
46 ObjectPainter.prototype.createG = ObjectPainter.prototype.CreateG;
47 ObjectPainter.prototype.axisToSvg = ObjectPainter.prototype.AxisToSvg;
48 ObjectPainter.prototype.svgToAxis = ObjectPainter.prototype.SvgToAxis;
49 ObjectPainter.prototype.getMainPainter = ObjectPainter.prototype.main_painter;
52 findPainter =
function(painter, obj, name, typ) {
53 return painter.FindPainterFor(obj, name, typ);
56 FFormat =
JSROOT.Painter.floatToString;
57 findPainter = (painter, obj, name, typ) => {
58 let pp = painter.getPadPainter();
59 return pp ? pp.findPainterFor(obj, name, typ) : null;
63 GO4.MarkerPainter =
function(divid, marker) {
65 ObjectPainter.call(
this, divid, marker);
67 ObjectPainter.call(
this, marker);
73 GO4.MarkerPainter.prototype = Object.create(ObjectPainter.prototype);
75 GO4.MarkerPainter.prototype.moveDrag =
function(dx,dy) {
78 this.draw_g.select(
'path').attr(
"d",this.markeratt.create(
this.grx,
this.gry));
81 GO4.MarkerPainter.prototype.moveEnd =
function() {
82 var marker = this.getObject();
83 marker.fX = this.svgToAxis(
"x", this.grx);
84 marker.fY = this.svgToAxis(
"y", this.gry);
85 var exec =
"SetXY(" + marker.fX +
"," + marker.fY +
")";
87 this.submitCanvExec(exec);
89 this.WebCanvasExec(exec);
93 GO4.MarkerPainter.prototype.drawMarker =
function() {
94 let g = this.createG();
96 var marker = this.getObject();
98 this.createAttMarker({ attr: marker });
100 this.grx = this.axisToSvg(
"x", marker.fX);
101 this.gry = this.axisToSvg(
"y", marker.fY);
103 var path = this.markeratt.create(this.grx, this.gry);
108 .call(this.markeratt.func);
110 if (typeof this.AddMove ==
'function')
113 JSROOT.require([
'interactive'])
114 .then(inter => inter.addMoveHandler(
this));
117 GO4.MarkerPainter.prototype.fillLabels =
function(marker) {
120 var
main = this.getMainPainter(), hint = null, fx = 0, fy = 0;
122 let rect = this.getFramePainter().getFrameRect();
125 if (main && typeof main.processTooltipEvent ==
'function')
126 hint = main.processTooltipEvent({ enabled:
false, x: this.grx - fx, y: this.gry - fy });
130 if (main && typeof main.ProcessTooltip ==
'function')
131 hint = main.ProcessTooltip({ enabled:
false, x: this.grx - fx, y: this.gry - fy });
135 lbls.push(marker.fxName + ((hint && hint.name) ? (
" : " + hint.name) :
""));
138 lbls.push(
"X = " +
FFormat(marker.fX,
"6.4g"));
141 lbls.push(
"Y = " +
FFormat(marker.fY,
"6.4g"));
143 if (hint && hint.user_info) {
144 if (marker.fbXbinDraw) {
146 if (hint.user_info.binx !== undefined) bin = hint.user_info.binx;
else
147 if (hint.user_info.bin !== undefined) bin = hint.user_info.bin;
148 lbls.push(
"Xbin = " + bin);
151 if (marker.fbYbinDraw) {
152 lbls.push(
"Ybin = " + ((hint.user_info.biny !== undefined) ? hint.user_info.biny :
"<undef>"));
155 if (marker.fbContDraw)
156 lbls.push(
"Cont = " + hint.user_info.cont);
162 GO4.MarkerPainter.prototype.drawLabel =
function() {
164 var marker = this.getObject();
166 if (!marker.fbHasLabel)
return;
171 this.pave =
JSROOT.create(
"TPaveStats");
172 this.pave.fName =
"stats_" + marker.fName;
174 var pad_width = 10, pad_height = 10;
177 let pp = this.getPadPainter();
178 pad_width = pp.getPadWidth();
179 pad_height = pp.getPadHeight();
181 pad_width = this.pad_width();
182 pad_height = this.pad_height();
185 var px = this.grx / pad_width + 0.02,
186 py = this.gry / pad_height - 0.02;
187 JSROOT.extend(this.pave, { fX1NDC: px, fY1NDC: py - 0.15, fX2NDC: px + 0.2, fY2NDC: py, fBorderSize: 1, fFillColor: 0, fFillStyle: 1001 });
190 JSROOT.extend(this.pave, { fFillColor: st.fStatColor, fFillStyle: st.fStatStyle, fTextAngle: 0, fTextSize: st.fStatFontSize,
191 fTextAlign: 12, fTextColor: st.fStatTextColor, fTextFont: st.fStatFont });
196 var lbls = this.fillLabels(marker);
197 for (var k = 0; k < lbls.length; ++k)
198 this.pave.AddText(lbls[k]);
202 pave_painter.redraw();
204 JSROOT.draw(this.divid, this.pave,
"").then(p => {
if (p) p.$secondary =
true; });
207 pave_painter.redraw();
209 JSROOT.draw(this.divid, this.pave,
"",
function(p) {
210 if (p) p.$secondary =
true;
217 GO4.MarkerPainter.prototype.redrawObject =
function(obj) {
218 if (!this.updateObject(obj))
return false;
223 GO4.MarkerPainter.prototype.cleanup =
function(arg) {
227 pp.removeFromPadPrimitives();
233 ObjectPainter.prototype.cleanup.call(
this, arg);
236 GO4.MarkerPainter.prototype.RedrawObject =
function(obj) {
237 if (!this.UpdateObject(obj))
return false;
242 GO4.MarkerPainter.prototype.Cleanup =
function(arg) {
245 if (pp) pp.DeleteThis();
249 ObjectPainter.prototype.Cleanup.call(
this, arg);
254 GO4.MarkerPainter.prototype.redraw =
function() {
278 GO4.MarkerPainter.prototype.processTooltipEvent =
function(pnt) {
279 if (!pnt)
return null;
281 var marker = this.getObject(), fx = 0, fy = 0, marker_sz = 1;
283 let rect = this.getFramePainter().getFrameRect();
286 marker_sz = this.markeratt.getFullSize();
290 marker_sz = this.markeratt.GetFullSize();
293 var hint = { name: marker.fxName,
294 title: marker.fxName,
299 color1: this.markeratt.color };
301 var dist = Math.sqrt(Math.pow(pnt.x - hint.x, 2) + Math.pow(pnt.y - hint.y, 2));
303 hint.menu_dist = dist;
305 if (dist < 2.5 * marker_sz) hint.exact =
true;
308 hint.lines = this.fillLabels(marker);
317 GO4.MarkerPainter.prototype.Redraw =
GO4.MarkerPainter.prototype.redraw;
318 GO4.MarkerPainter.prototype.ProcessTooltip =
GO4.MarkerPainter.prototype.processTooltipEvent;
321 GO4.MarkerPainter.prototype.ShowTooltip =
function(hint) {
324 GO4.drawGo4Marker =
function(divid, obj, option) {
325 var painter =
new GO4.MarkerPainter(divid, obj);
327 painter.drawMarker();
329 painter.addToPadPrimitives();
330 return Promise.resolve(painter);
332 painter.drawMarker();
334 return painter.DrawingReady();
339 if (!ObjectPainter.prototype.matchObjectType)
340 ObjectPainter.prototype.matchObjectType = ObjectPainter.prototype.MatchObjectType
342 GO4.ConditionPainter =
function(divid, cond) {
344 ObjectPainter.call(
this, divid, cond);
346 ObjectPainter.call(
this, cond);
347 this.SetDivId(divid, -1)
353 GO4.ConditionPainter.prototype = Object.create(ObjectPainter.prototype);
355 GO4.ConditionPainter.prototype.Test =
function(x,y) {
357 var cond = this.getObject();
359 return cond.fbResult;
362 return cond.fxCut.IsInside(x,y) ? cond.fbTrue : cond.fbFalse;
364 if ((x < cond.fLow1) || (x > cond.fUp1))
return cond.fbFalse;
366 if ((cond.fiDim==2) && ((y < cond.fLow2) || (y > cond.fUp2)))
return cond.fbFalse;
372 GO4.ConditionPainter.prototype.isPolyCond =
function() {
373 return this.matchObjectType(
"TGo4PolyCond") || this.matchObjectType(
"TGo4ShapedCond");
376 GO4.ConditionPainter.prototype.isEllipseCond =
function() {
377 return this.matchObjectType(
"TGo4ShapedCond");
380 GO4.ConditionPainter.prototype.afterCutDraw =
function(p) {
381 if (!p || !this.snapid || p._oldexec)
return;
382 p.snapid = this.snapid +
"#member_fxCut";
383 p._condpainter =
this;
387 p._oldexec = p.submitCanvExec;
388 p.submitCanvExec =
function(exec, arg) {
389 this._oldexec(exec, arg);
390 p._condpainter.submitCanvExec(
"SetChanged()");
393 p._oldexec = p.WebCanvasExec;
394 p.WebCanvasExec =
function(exec, arg) {
395 this._oldexec(exec, arg);
396 p._condpainter.WebCanvasExec(
"SetChanged()");
402 GO4.ConditionPainter.prototype.drawCondition =
function(interactive) {
404 var cond = this.getObject();
406 if (!cond || !cond.fbVisible)
return;
411 var cutpaint =
findPainter(
this, null, cond.fName,
'TCutG');
415 if (cutpaint.updateObject(cond.fxCut)) cutpaint.redraw();
416 this.afterCutDraw(cutpaint);
418 cond.fxCut.fFillStyle = 3006;
419 cond.fxCut.fFillColor = 2;
420 JSROOT.draw(this.divid, cond.fxCut,
"LF").then(p => this.afterCutDraw(p));
425 if (cutpaint.UpdateObject(cond.fxCut)) cutpaint.redraw();
426 this.afterCutDraw(cutpaint);
428 cond.fxCut.fFillStyle = 3006;
429 cond.fxCut.fFillColor = 2;
430 JSROOT.draw(this.divid, cond.fxCut,
"LF", p =>
this.afterCutDraw(p));
438 let g = this.createG(
true);
440 if ((cond.fFillStyle==1001) && (cond.fFillColor==19)) {
441 cond.fFillStyle = 3006;
445 this.createAttFill({attr: cond});
446 this.createAttLine({attr: cond});
448 this.grx1 = this.axisToSvg(
"x", cond.fLow1);
449 this.grx2 = this.axisToSvg(
"x", cond.fUp1);
451 if (cond.fiDim == 2) {
452 this.gry1 = this.axisToSvg(
"y", cond.fUp2);
453 this.gry2 = this.axisToSvg(
"y", cond.fLow2);
457 this.gry2 =
JSROOT._ ? this.getFramePainter().getFrameHeight() : this.frame_height();
462 .attr(
"x", this.grx1)
463 .attr(
"y", this.gry1)
464 .attr(
"width", this.grx2 - this.grx1)
465 .attr(
"height", this.gry2 - this.gry1)
466 .call(this.lineatt.func)
467 .call(this.fillatt.func);
469 if (typeof this.AddMove ==
'function')
472 JSROOT.require([
'interactive'])
473 .then(inter => inter.addMoveHandler(
this));
476 GO4.ConditionPainter.prototype.moveStart =
function(x,y) {
477 this.swapx = this.swapy =
false;
478 this.dx1 = Math.abs(x-this.grx1) < 5;
479 this.dx2 = Math.abs(x-this.grx2) < 5;
480 this.dy1 = Math.abs(y-this.gry1) < 5;
481 this.dy2 = Math.abs(y-this.gry2) < 5;
482 if (!this.dx1 && !this.dx2 && !this.dy1 && !this.dy2)
483 this.dx1 = this.dx2 = this.dy1 = this.dy2 =
true;
484 if (!this.candy) this.dy1 = this.dy2 =
false;
487 GO4.ConditionPainter.prototype.moveDrag =
function(dx,dy) {
488 if (this.dx1) this.grx1 += dx;
489 if (this.dx2) this.grx2 += dx;
490 if (this.grx1 > this.grx2) {
492 let tempx = this.grx1; this.grx1 = this.grx2; this.grx2 = tempx;
493 tempx = this.dx1; this.dx1 = this.dx2; this.dx2 = tempx;
495 if (this.dy1) this.gry1 += dy;
496 if (this.dy2) this.gry2 += dy;
497 if (this.gry1 > this.gry2) {
499 let tempy = this.gry1; this.gry1 = this.gry2; this.gry2 = tempy;
500 tempy = this.dy1; this.dy1 = this.dy2; this.dy2 = tempy;
502 this.draw_g.select(
'rect').attr(
"x",this.grx1).attr(
"y", this.gry1)
503 .attr(
"width", this.grx2 - this.grx1).attr(
"height", this.gry2 - this.gry1);
506 GO4.ConditionPainter.prototype.moveEnd =
function() {
507 var cond = this.getObject(), exec =
"";
508 if (this.dx1 || this.swapx) { cond.fLow1 = this.svgToAxis(
"x", this.grx1); exec +=
"SetXLow(" + cond.fLow1 +
");;"; }
509 if (this.dx2 || this.swapx) { cond.fUp1 = this.svgToAxis(
"x", this.grx2); exec +=
"SetXUp(" + cond.fUp1 +
");;"; }
510 if (this.dy2 || this.swapy) { cond.fLow2 = this.svgToAxis(
"y", this.gry2); exec +=
"SetYLow(" + cond.fLow2 +
");;"; }
511 if (this.dy1 || this.swapy) { cond.fUp2 = this.svgToAxis(
"y", this.gry1); exec +=
"SetYUp(" + cond.fUp2 +
");;"; }
514 this.submitCanvExec(exec +
"SetChanged()");
516 this.WebCanvasExec(exec +
"SetChanged()");
521 GO4.ConditionPainter.prototype.drawLabel =
function() {
523 var cond = this.getObject(), painter =
this, stat = {};
525 if (!cond.fbLabelDraw || !cond.fbVisible)
return;
530 this.pave =
JSROOT.create(
"TPaveStats");
531 this.pave.fName =
"stats_" + cond.fName;
532 JSROOT.extend(this.pave, { fX1NDC: 0.1, fY1NDC: 0.4, fX2NDC: 0.4, fY2NDC: 0.65, fBorderSize: 1, fFillColor: 0, fFillStyle: 1001 });
535 JSROOT.extend(this.pave, { fFillColor: st.fStatColor, fFillStyle: st.fStatStyle, fTextAngle: 0, fTextSize: st.fStatFontSize,
536 fTextAlign: 12, fTextColor: st.fStatTextColor, fTextFont: st.fStatFont});
541 this.pave.AddText(cond.fName);
543 this.pave.AddText(
"Counts = " + cond.fiCounts);
545 if (cond.fbLimitsDraw)
547 var res = { xmin: 0, xmax: 0, ymin: 0, ymax: 0 };
548 if (cond.fxCut.fNpoints > 0) {
549 res.xmin = res.xmax = cond.fxCut.fX[0];
550 res.ymin = res.ymax = cond.fxCut.fY[0];
551 for (var i=1; i<cond.fxCut.fNpoints; i++) {
552 res.xmin = Math.min(res.xmin, cond.fxCut.fX[i]);
553 res.xmax = Math.max(res.xmax, cond.fxCut.fX[i]);
554 res.ymin = Math.min(res.ymin, cond.fxCut.fY[i]);
555 res.ymax = Math.max(res.ymax, cond.fxCut.fY[i]);
558 this.pave.AddText(
"Xmin = " + res.xmin);
559 this.pave.AddText(
"Xmax = " + res.xmax);
560 this.pave.AddText(
"Ymin = " + res.ymin);
561 this.pave.AddText(
"Ymax = " + res.ymax);
563 this.pave.AddText(
"Xmin = " + cond.fLow1);
564 this.pave.AddText(
"Xmax = " + cond.fUp1);
566 this.pave.AddText(
"Ymin = " + cond.fLow2);
567 this.pave.AddText(
"Ymax = " + cond.fUp2);
572 stat = this.getMainPainter().countStat((x,y) => painter.Test(x,y));
574 stat = this.getMainPainter().CountStat(
function(x,y) {
return painter.Test(x,y); });
577 if (cond.fbIntDraw) this.pave.AddText(
"Integral = " +
FFormat(stat.integral,
"14.7g"));
579 if (cond.fbXMeanDraw) this.pave.AddText(
"Mean x = " +
FFormat(stat.meanx,
"6.4g"));
581 if (cond.fbXRMSDraw) this.pave.AddText(
"RMS x = " +
FFormat(stat.rmsx,
"6.4g"));
584 if (cond.fbYMeanDraw) this.pave.AddText(
"Mean y = " +
FFormat(stat.meany,
"6.4g"));
585 if (cond.fbYRMSDraw) this.pave.AddText(
"RMS y = " +
FFormat(stat.rmsy,
"6.4g"));
588 if (cond.fbXMaxDraw) this.pave.AddText(
"X max = " +
FFormat(stat.xmax,
"6.4g"));
591 if (cond.fbYMaxDraw) this.pave.AddText(
"Y max = " +
FFormat(stat.ymax,
"6.4g"));
592 if (cond.fbCMaxDraw) this.pave.AddText(
"C max = " +
FFormat(stat.wmax,
"14.7g"));
595 JSROOT.draw(this.divid, this.pave,
"");
597 pave_painter.redraw();
599 pave_painter.Redraw();
623 GO4.ConditionPainter.prototype.processTooltipEvent =
function(pnt) {
624 if (!pnt)
return null;
626 var cond = this.getObject();
628 var hint = { name: cond.fName,
639 hint.color1 = this.fillatt.color;
640 hint.color2 = this.lineatt.color;
642 hint.menu_dist = Math.sqrt(Math.pow(pnt.x - (
this.grx1 +
this.grx2)/2, 2) + Math.pow(pnt.y - (
this.gry1 +
this.gry2)/2, 2));
643 hint.exact = (this.grx1 <= pnt.x) && (pnt.x <=
this.grx2) && (this.gry1 <= pnt.y) && (pnt.y <=
this.gry2);
644 if (Math.abs(
this.grx1 - pnt.x) < 5) hint.sidex = -1;
645 if (Math.abs(
this.grx2 - pnt.x) < 5) hint.sidex = 1;
646 if (cond.fiDim == 2) {
647 if (Math.abs(
this.gry1 - pnt.y) < 5) hint.sidey = 1;
648 if (Math.abs(
this.gry2 - pnt.y) < 5) hint.sidey = -1;
653 hint.lines = [
"condition", cond.fName ];
659 GO4.ConditionPainter.prototype.redrawObject =
function(obj) {
660 if (!this.updateObject(obj))
return false;
664 GO4.ConditionPainter.prototype.cleanup =
function(arg) {
668 pp.removeFromPadPrimitives();
674 ObjectPainter.prototype.cleanup.call(
this, arg);
679 GO4.ConditionPainter.prototype.RedrawObject =
function(obj) {
680 if (!this.UpdateObject(obj))
return false;
684 GO4.ConditionPainter.prototype.Cleanup =
function(arg) {
687 if (pp) pp.DeleteThis();
691 ObjectPainter.prototype.Cleanup.call(
this, arg);
693 GO4.ConditionPainter.prototype.ProcessTooltip =
GO4.ConditionPainter.prototype.processTooltipEvent;
697 GO4.ConditionPainter.prototype.redraw =
function() {
698 this.drawCondition();
703 if (!
JSROOT._)
GO4.ConditionPainter.prototype.Redraw =
GO4.ConditionPainter.prototype.redraw;
705 GO4.drawGo4Cond =
function(divid, cond, option) {
707 var condpainter =
new GO4.ConditionPainter(divid, cond);
708 let realid = condpainter.get_main_id();
710 if (
GO4.web_canvas || (option==
'same')) {
711 condpainter.drawCondition();
712 condpainter.drawLabel();
714 condpainter.addToPadPrimitives();
715 return Promise.resolve(condpainter);
717 condpainter.SetDivId(divid);
718 return condpainter.DrawingReady();
723 if (((cond.fxHistoName==
"") || (option==
'editor')) &&
GO4.ConditionEditor) {
725 var h = $(
"#"+realid).height(), w = $(
"#"+realid).width();
726 if ((h<10) && (w>10)) $(
"#"+realid).height(w*0.4);
727 var editor =
new GO4.ConditionEditor(realid, cond);
728 if (
JSROOT._)
return new Promise(resolve => editor.drawEditor(realid, resolve));
729 return editor.drawEditor(realid);
735 $(
'#'+realid).append(
"<br/>Error - did not found hierarchy painter");
739 var histofullpath = null;
741 function TestItem(h) {
742 if ((h._name == cond.fxHistoName) && h._kind && (h._kind.indexOf(
"ROOT.TH")==0))
743 histofullpath =
JSROOT.hpainter.itemFullName(h);
747 JSROOT.hpainter.forEachItem(TestItem);
749 JSROOT.hpainter.ForEach(TestItem);
751 if (histofullpath === null) {
752 $(
'#'+realid).append(
"<br/>Error - did not found histogram " + cond.fxHistoName);
754 histofullpath =
"../../Histograms/" + cond.fxHistoName;
756 let hitem =
JSROOT._ ?
JSROOT.hpainter.findItem({ name: histofullpath, force:
true }) :
JSROOT.hpainter.Find({ name: histofullpath, force: true });
758 hitem._kind =
"ROOT.TH1I";
760 console.log(
"Try histogram" + histofullpath);
764 $(
'#'+realid).append(
"<br/>Drawing histogram " + histofullpath);
765 $(
'#'+realid).empty();
767 function drawCond(hpainter) {
768 if (!hpainter)
return console.log(
"fail to draw histogram " + histofullpath);
769 condpainter.drawCondition();
770 condpainter.drawLabel();
772 condpainter.addToPadPrimitives();
775 condpainter.SetDivId(divid);
776 return condpainter.DrawingReady();
781 return JSROOT.hpainter.display(histofullpath,
"divid:" + realid).then(hp => drawCond(hp));
783 JSROOT.hpainter.display(histofullpath,
"divid:" + realid, drawCond);
787 GO4.drawCondArray =
function(divid, obj, option) {
788 var arr = obj.condarr.arr;
789 var num = obj.fiNumCond;
791 for (var k=0;k<num;++k) {
792 var p =
GO4.drawGo4Cond(divid, arr[k],
"");
793 if (k == 0) first = p;
801 if (
GO4.web_canvas) {
803 jsrp.addDrawFunc({ name:
"TGo4Marker", func:
GO4.drawGo4Marker });
804 jsrp.addDrawFunc({ name:
"TGo4WinCond", func:
GO4.drawGo4Cond });
805 jsrp.addDrawFunc({ name:
"TGo4PolyCond", func:
GO4.drawGo4Cond });
806 jsrp.addDrawFunc({ name:
"TGo4ShapedCond", func:
GO4.drawGo4Cond });
807 jsrp.addDrawFunc({ name:
"TGo4CondArray", func:
GO4.drawCondArray });
int main(int argc, char **argv)
GO4 ConditionEditor prototype isPolyCond
if(!BasePainter.prototype.get_main_id)