5 JSROOT.require(
"painter").then(jsrp => {
8 if (typeof GO4 ==
'undefined')
9 globalThis.GO4 = { version:
"6.1.4", web_canvas: true, id_counter: 1 };
11 function findPainter(painter, obj, name, typ) {
12 let pp = painter.getPadPainter();
13 return pp ? pp.findPainterFor(obj, name, typ) : null;
16 class MarkerPainter
extends JSROOT.ObjectPainter{
17 constructor(dom, marker) {
25 this.draw_g.select(
'path').attr(
"d",this.markeratt.create(
this.grx,
this.gry));
29 let marker = this.getObject();
30 marker.fX = this.svgToAxis(
"x", this.grx);
31 marker.fY = this.svgToAxis(
"y", this.gry);
32 let exec = `SetXY(${marker.fX},${marker.fY})`;
33 this.submitCanvExec(exec);
38 let g = this.createG();
40 let marker = this.getObject();
42 this.createAttMarker({ attr: marker });
44 this.grx = this.axisToSvg(
"x", marker.fX);
45 this.gry = this.axisToSvg(
"y", marker.fY);
47 let path = this.markeratt.create(this.grx, this.gry);
52 .call(this.markeratt.func);
54 if (typeof this.AddMove ==
'function')
57 JSROOT.require([
'interactive'])
58 .then(inter => inter.addMoveHandler(
this));
63 rect = this.getFramePainter().getFrameRect(),
64 main = this.getMainPainter(), hint = null;
66 if (
main && typeof
main.processTooltipEvent ==
'function')
67 hint =
main.processTooltipEvent({ enabled:
false, x: this.grx - rect.x, y: this.gry - rect.y });
69 lbls.push(marker.fxName + ((hint && hint.name) ? (
" : " + hint.name) :
""));
72 lbls.push(
"X = " + jsrp.floatToString(marker.fX,
"6.4g"));
75 lbls.push(
"Y = " + jsrp.floatToString(marker.fY,
"6.4g"));
77 if (hint && hint.user_info) {
78 if (marker.fbXbinDraw) {
80 if (hint.user_info.binx !== undefined) bin = hint.user_info.binx;
else
81 if (hint.user_info.bin !== undefined) bin = hint.user_info.bin;
82 lbls.push(
"Xbin = " + bin);
85 if (marker.fbYbinDraw) {
86 lbls.push(
"Ybin = " + ((hint.user_info.biny !== undefined) ? hint.user_info.biny :
"<undef>"));
89 if (marker.fbContDraw)
90 lbls.push(
"Cont = " + hint.user_info.cont);
98 let marker = this.getObject();
100 if (!marker.fbHasLabel)
return;
102 let pave_painter = findPainter(
this, this.pave);
105 this.pave = JSROOT.create(
"TPaveStats");
106 this.pave.fName =
"stats_" + marker.fName;
108 let pp = this.getPadPainter(),
109 pad_width = pp.getPadWidth(),
110 pad_height = pp.getPadHeight();
112 let px = this.grx / pad_width + 0.02,
113 py = this.gry / pad_height - 0.02;
114 JSROOT.extend(this.pave, { fX1NDC: px, fY1NDC: py - 0.15, fX2NDC: px + 0.2, fY2NDC: py, fBorderSize: 1, fFillColor: 0, fFillStyle: 1001 });
116 let st = JSROOT.gStyle;
117 JSROOT.extend(this.pave, { fFillColor: st.fStatColor, fFillStyle: st.fStatStyle, fTextAngle: 0, fTextSize: st.fStatFontSize,
118 fTextAlign: 12, fTextColor: st.fStatTextColor, fTextFont: st.fStatFont });
123 let lbls = this.fillLabels(marker);
124 for (let k = 0; k < lbls.length; ++k)
125 this.pave.AddText(lbls[k]);
128 pave_painter.redraw();
130 JSROOT.draw(this.divid, this.pave,
"").then(p => {
if (p) p.$secondary =
true; });
134 if (!this.updateObject(obj))
return false;
141 let pp = findPainter(
this, this.pave);
143 pp.removeFromPadPrimitives();
176 processTooltipEvent(pnt) {
177 if (!pnt)
return null;
179 let marker = this.getObject(),
180 rect = this.getFramePainter().getFrameRect(),
183 marker_sz = this.markeratt.getFullSize();
185 let hint = { name: marker.fxName,
186 title: marker.fxName,
191 color1: this.markeratt.color };
193 let dist = Math.sqrt(Math.pow(pnt.x - hint.x, 2) + Math.pow(pnt.y - hint.y, 2));
195 hint.menu_dist = dist;
197 if (dist < 2.5 * marker_sz) hint.exact =
true;
200 hint.lines = this.fillLabels(marker);
211 GO4.drawGo4Marker =
function(dom, obj ) {
212 let painter =
new MarkerPainter(dom, obj);
213 painter.drawMarker();
215 painter.addToPadPrimitives();
216 return Promise.resolve(painter);
221 class ConditionPainter
extends JSROOT.ObjectPainter {
222 constructor(dom, cond) {
229 let cond = this.getObject();
231 return cond.fbResult;
234 return cond.fxCut.IsInside(x,y) ? cond.fbTrue : cond.fbFalse;
236 if ((x < cond.fLow1) || (x > cond.fUp1))
return cond.fbFalse;
238 if ((cond.fiDim==2) && ((y < cond.fLow2) || (y > cond.fUp2)))
return cond.fbFalse;
245 return this.matchObjectType(
"TGo4PolyCond") || this.matchObjectType(
"TGo4ShapedCond");
249 return this.matchObjectType(
"TGo4ShapedCond");
253 if (!p || !this.snapid || p._oldexec)
return;
254 p.snapid = this.snapid +
"#member_fxCut";
255 p._condpainter =
this;
258 p._oldexec = p.submitCanvExec;
259 p.submitCanvExec =
function(exec, arg) {
260 this._oldexec(exec, arg);
261 p._condpainter.submitCanvExec(
"SetChanged()");
265 drawCondition(interactive) {
267 let cond = this.getObject();
269 if (!cond || !cond.fbVisible)
return;
271 if (this.isPolyCond()) {
274 let cutpaint = findPainter(
this, null, cond.fName,
'TCutG');
277 if (cutpaint.updateObject(cond.fxCut)) cutpaint.redraw();
278 this.afterCutDraw(cutpaint);
280 cond.fxCut.fFillStyle = 3006;
281 cond.fxCut.fFillColor = 2;
282 JSROOT.draw(this.divid, cond.fxCut,
"LF").then(p => this.afterCutDraw(p));
290 let g = this.createG(
true);
292 if ((cond.fFillStyle==1001) && (cond.fFillColor==19)) {
293 cond.fFillStyle = 3006;
297 this.createAttFill({attr: cond});
298 this.createAttLine({attr: cond});
300 this.grx1 = this.axisToSvg(
"x", cond.fLow1);
301 this.grx2 = this.axisToSvg(
"x", cond.fUp1);
303 if (cond.fiDim == 2) {
304 this.gry1 = this.axisToSvg(
"y", cond.fUp2);
305 this.gry2 = this.axisToSvg(
"y", cond.fLow2);
309 this.gry2 = this.getFramePainter().getFrameHeight();
314 .attr(
"x", this.grx1)
315 .attr(
"y", this.gry1)
316 .attr(
"width", this.grx2 - this.grx1)
317 .attr(
"height", this.gry2 - this.gry1)
318 .call(this.lineatt.func)
319 .call(this.fillatt.func);
321 if (typeof this.AddMove ==
'function')
324 JSROOT.require([
'interactive'])
325 .then(inter => inter.addMoveHandler(
this));
329 this.swapx = this.swapy =
false;
330 this.dx1 = Math.abs(x-this.grx1) < 5;
331 this.dx2 = Math.abs(x-this.grx2) < 5;
332 this.dy1 = Math.abs(y-this.gry1) < 5;
333 this.dy2 = Math.abs(y-this.gry2) < 5;
334 if (!this.dx1 && !this.dx2 && !this.dy1 && !this.dy2)
335 this.dx1 = this.dx2 = this.dy1 = this.dy2 =
true;
336 if (!this.candy) this.dy1 = this.dy2 =
false;
340 if (this.dx1) this.grx1 += dx;
341 if (this.dx2) this.grx2 += dx;
342 if (this.grx1 > this.grx2) {
344 let tempx = this.grx1; this.grx1 = this.grx2; this.grx2 = tempx;
345 tempx = this.dx1; this.dx1 = this.dx2; this.dx2 = tempx;
347 if (this.dy1) this.gry1 += dy;
348 if (this.dy2) this.gry2 += dy;
349 if (this.gry1 > this.gry2) {
351 let tempy = this.gry1; this.gry1 = this.gry2; this.gry2 = tempy;
352 tempy = this.dy1; this.dy1 = this.dy2; this.dy2 = tempy;
354 this.draw_g.select(
'rect').attr(
"x",this.grx1).attr(
"y", this.gry1)
355 .attr(
"width", this.grx2 - this.grx1).attr(
"height", this.gry2 - this.gry1);
359 let cond = this.getObject(), exec =
"";
360 if (this.dx1 || this.swapx) { cond.fLow1 = this.svgToAxis(
"x", this.grx1); exec +=
"SetXLow(" + cond.fLow1 +
");;"; }
361 if (this.dx2 || this.swapx) { cond.fUp1 = this.svgToAxis(
"x", this.grx2); exec +=
"SetXUp(" + cond.fUp1 +
");;"; }
362 if (this.dy2 || this.swapy) { cond.fLow2 = this.svgToAxis(
"y", this.gry2); exec +=
"SetYLow(" + cond.fLow2 +
");;"; }
363 if (this.dy1 || this.swapy) { cond.fUp2 = this.svgToAxis(
"y", this.gry1); exec +=
"SetYUp(" + cond.fUp2 +
");;"; }
365 this.submitCanvExec(exec +
"SetChanged()");
372 let cond = this.getObject(), painter =
this, stat = {};
374 if (!cond.fbLabelDraw || !cond.fbVisible)
return;
376 let pave_painter = findPainter(
this, this.pave);
379 this.pave = JSROOT.create(
"TPaveStats");
380 this.pave.fName =
"stats_" + cond.fName;
381 JSROOT.extend(this.pave, { fX1NDC: 0.1, fY1NDC: 0.4, fX2NDC: 0.4, fY2NDC: 0.65, fBorderSize: 1, fFillColor: 0, fFillStyle: 1001 });
383 let st = JSROOT.gStyle;
384 JSROOT.extend(this.pave, { fFillColor: st.fStatColor, fFillStyle: st.fStatStyle, fTextAngle: 0, fTextSize: st.fStatFontSize,
385 fTextAlign: 12, fTextColor: st.fStatTextColor, fTextFont: st.fStatFont});
390 this.pave.AddText(cond.fName);
392 this.pave.AddText(
"Counts = " + cond.fiCounts);
394 if (cond.fbLimitsDraw)
395 if (this.isPolyCond()) {
396 let res = { xmin: 0, xmax: 0, ymin: 0, ymax: 0 };
397 if (cond.fxCut.fNpoints > 0) {
398 res.xmin = res.xmax = cond.fxCut.fX[0];
399 res.ymin = res.ymax = cond.fxCut.fY[0];
400 for (let i=1; i<cond.fxCut.fNpoints; i++) {
401 res.xmin = Math.min(res.xmin, cond.fxCut.fX[i]);
402 res.xmax = Math.max(res.xmax, cond.fxCut.fX[i]);
403 res.ymin = Math.min(res.ymin, cond.fxCut.fY[i]);
404 res.ymax = Math.max(res.ymax, cond.fxCut.fY[i]);
407 this.pave.AddText(
"Xmin = " + res.xmin);
408 this.pave.AddText(
"Xmax = " + res.xmax);
409 this.pave.AddText(
"Ymin = " + res.ymin);
410 this.pave.AddText(
"Ymax = " + res.ymax);
412 this.pave.AddText(
"Xmin = " + cond.fLow1);
413 this.pave.AddText(
"Xmax = " + cond.fUp1);
415 this.pave.AddText(
"Ymin = " + cond.fLow2);
416 this.pave.AddText(
"Ymax = " + cond.fUp2);
420 stat = this.getMainPainter().countStat((x,y) => painter.Test(x,y));
422 if (cond.fbIntDraw) this.pave.AddText(
"Integral = " + jsrp.floatToString(stat.integral,
"14.7g"));
424 if (cond.fbXMeanDraw) this.pave.AddText(
"Mean x = " + jsrp.floatToString(stat.meanx,
"6.4g"));
426 if (cond.fbXRMSDraw) this.pave.AddText(
"RMS x = " + jsrp.floatToString(stat.rmsx,
"6.4g"));
429 if (cond.fbYMeanDraw) this.pave.AddText(
"Mean y = " + jsrp.floatToString(stat.meany,
"6.4g"));
430 if (cond.fbYRMSDraw) this.pave.AddText(
"RMS y = " + jsrp.floatToString(stat.rmsy,
"6.4g"));
433 if (cond.fbXMaxDraw) this.pave.AddText(
"X max = " + jsrp.floatToString(stat.xmax,
"6.4g"));
436 if (cond.fbYMaxDraw) this.pave.AddText(
"Y max = " + jsrp.floatToString(stat.ymax,
"6.4g"));
437 if (cond.fbCMaxDraw) this.pave.AddText(
"C max = " + jsrp.floatToString(stat.wmax,
"14.7g"));
440 JSROOT.draw(this.divid, this.pave,
"");
442 pave_painter.redraw();
466 processTooltipEvent(pnt) {
467 if (!pnt)
return null;
469 let cond = this.getObject(),
470 hint = { name: cond.fName,
477 if (this.isPolyCond()) {
481 hint.color1 = this.fillatt.color;
482 hint.color2 = this.lineatt.color;
484 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));
485 hint.exact = (this.grx1 <= pnt.x) && (pnt.x <=
this.grx2) && (this.gry1 <= pnt.y) && (pnt.y <=
this.gry2);
486 if (Math.abs(
this.grx1 - pnt.x) < 5) hint.sidex = -1;
487 if (Math.abs(
this.grx2 - pnt.x) < 5) hint.sidex = 1;
488 if (cond.fiDim == 2) {
489 if (Math.abs(
this.gry1 - pnt.y) < 5) hint.sidey = 1;
490 if (Math.abs(
this.gry2 - pnt.y) < 5) hint.sidey = -1;
495 hint.lines = [
"condition", cond.fName ];
501 if (!this.updateObject(obj))
return false;
508 let pp = findPainter(
this, this.pave);
510 pp.removeFromPadPrimitives();
519 this.drawCondition();
524 let elem = this.selectDom();
525 if (elem.empty())
return "";
526 let
id = elem.attr(
"id");
528 id =
"go4_element_" + GO4.id_counter++;
536 GO4.drawGo4Cond =
function(dom, cond, option) {
538 if (!option) option =
"";
540 let condpainter =
new ConditionPainter(dom, cond),
541 elem = condpainter.selectDom();
543 if (GO4.web_canvas || (option.indexOf(
'same') >= 0) || condpainter.getMainPainter()) {
544 condpainter.drawCondition();
545 condpainter.drawLabel();
546 condpainter.addToPadPrimitives();
547 return Promise.resolve(condpainter);
551 if ((option==
'editor') || !cond.fxHistoName) {
553 if (!GO4.source_dir)
return null;
555 let rect = elem.node().getBoundingClientRect();
556 if ((rect.height < 10) && (rect.width > 10)) elem.style(
"height", Math.round(rect.width*0.4) +
"px");
557 return JSROOT.require(GO4.source_dir +
'html/condition.js').then(() => {
558 let editor =
new GO4.ConditionEditor(dom, cond);
559 return editor.drawEditor();
563 if (!JSROOT.hpainter)
return;
565 let histofullpath = null;
567 JSROOT.hpainter.forEachItem(h => {
568 if ((h._name == cond.fxHistoName) && h._kind && (h._kind.indexOf(
"ROOT.TH")==0))
569 histofullpath = JSROOT.hpainter.itemFullName(h);
572 if (histofullpath === null) {
573 histofullpath =
"../../Histograms/" + cond.fxHistoName;
575 let hitem = JSROOT.hpainter.findItem({ name: histofullpath, force:
true });
577 hitem._kind =
"ROOT.TH1I";
580 function drawCond(hpainter) {
581 if (!hpainter)
return console.log(
"fail to draw histogram " + histofullpath);
582 condpainter.drawCondition();
583 condpainter.drawLabel();
584 condpainter.addToPadPrimitives();
588 return JSROOT.hpainter.display(histofullpath,
"divid:" + condpainter.getDomId()).then(hp => drawCond(hp));
591 GO4.drawCondArray =
function(divid, obj, option) {
592 let arr = obj.condarr.arr,
595 for (let k = 0; k < num; ++k) {
596 let p = GO4.drawGo4Cond(divid, arr[k],
"");
597 if (k == 0) first = p;
604 if (GO4.web_canvas) {
605 jsrp.addDrawFunc({ name:
"TGo4Marker", func: GO4.drawGo4Marker });
606 jsrp.addDrawFunc({ name:
"TGo4WinCond", func: GO4.drawGo4Cond });
607 jsrp.addDrawFunc({ name:
"TGo4PolyCond", func: GO4.drawGo4Cond });
608 jsrp.addDrawFunc({ name:
"TGo4ShapedCond", func: GO4.drawGo4Cond });
609 jsrp.addDrawFunc({ name:
"TGo4CondArray", func: GO4.drawCondArray });
int main(int argc, char **argv)