5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootPainter',
'd3'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 factory(require(
"./JSRootCore.js"), require(
"d3"));
10 if (typeof d3 !=
'object')
11 throw new Error(
'This extension requires d3.js',
'JSRootPainter.v7hist.js');
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootPainter.v7hist.js');
14 if (typeof JSROOT.Painter !=
'object')
15 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.v7hist.js');
18 } (
function(JSROOT, d3) {
22 JSROOT.sources.push(
"v7hist");
27 function THistPainter(histo) {
28 JSROOT.TObjectPainter.call(
this, histo);
29 this.csstype =
"hist";
30 this.draw_content =
true;
33 this.accept_drops =
true;
35 this.zoom_changed_interactive = 0;
38 THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
41 THistPainter.prototype.PrepareFrame =
function(divid) {
42 this.SetDivId(divid, -1);
44 if (!this.frame_painter()) {
45 var pad = this.root_pad(),
46 fr = pad ? pad.fFrame : null;
47 JSROOT.v7.drawFrame(divid, fr);
50 this.SetDivId(divid, 1);
53 THistPainter.prototype.GetHImpl =
function(obj) {
54 if (obj && obj.fHistImpl)
55 return obj.fHistImpl.fIO;
59 THistPainter.prototype.GetHisto =
function() {
60 var obj = this.GetObject(), histo = this.GetHImpl(obj);
62 if (histo && !histo.getBinContent) {
63 console.log(
'histo type', histo._typename);
65 histo.getBin =
function(x, y) {
return (x + this.fAxes._0.fNBins * y); }
66 histo.getBinContent =
function(x, y) {
return this.fStatistics.fBinContent[this.getBin(x, y)]; }
67 histo.getBinError =
function(x,y) {
68 var bin = this.getBin(x,y);
69 if (this.fStatistics.fSumWeightsSquared)
70 return Math.sqrt(this.fStatistics.fSumWeightsSquared[bin]);
71 return Math.sqrt(Math.abs(
this.fStatistics.fBinContent[bin]));
75 histo.getBinContent =
function(bin) {
76 return this.fStatistics.fBinContent[bin];
78 histo.getBinError =
function(bin) {
79 if (this.fStatistics.fSumWeightsSquared)
80 return Math.sqrt(this.fStatistics.fSumWeightsSquared[bin]);
81 return Math.sqrt(Math.abs(
this.getBinContent(bin)));
89 THistPainter.prototype.IsTProfile =
function() {
93 THistPainter.prototype.IsTH1K =
function() {
97 THistPainter.prototype.IsTH2Poly =
function() {
101 THistPainter.prototype.DecodeOptions =
function(opt) {
102 if (!this.options) this.options = { Hist : 1 };
105 THistPainter.prototype.Clear3DScene =
function() {
106 var fp = this.frame_painter();
107 if (fp && typeof fp.Create3DScene ===
'function')
108 fp.Create3DScene(-1);
112 THistPainter.prototype.Cleanup =
function() {
117 delete this.fPalette;
118 delete this.fContour;
121 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
124 THistPainter.prototype.Dimension =
function() {
128 THistPainter.prototype.ScanContent =
function(when_axis_changed) {
134 alert(
"HistPainter.prototype.ScanContent not implemented");
137 THistPainter.prototype.DrawAxes =
function() {
139 var main = this.frame_painter();
140 if (!main)
return false;
142 if (this.is_main_painter() && this.draw_content) {
144 main.xmin = main.xmax = 0;
145 main.ymin = main.ymax = 0;
146 main.zmin = main.zmax = 0;
147 main.SetAxesRanges(this.xmin, this.xmax, this.ymin, this.ymax);
150 return main.DrawAxes(
true);
153 THistPainter.prototype.CheckHistDrawAttributes =
function() {
172 this.createAttFill( { pattern: 0, color: 0 });
174 var lcol = this.v7EvalColor(
"line_color",
"black"),
175 lwidth = this.v7EvalAttr(
"line_width", 1);
177 this.createAttLine({ color: lcol ||
'black', width : parseInt(lwidth) || 1 });
180 THistPainter.prototype.UpdateObject =
function(obj, opt) {
182 var origin = this.GetObject();
184 if (obj !== origin) {
186 if (!this.MatchObjectType(obj))
return false;
188 var horigin = this.GetHImpl(origin),
189 hobj = this.GetHImpl(obj);
191 if (!horigin || !hobj)
return false;
194 horigin.fStatistics = hobj.fStatistics;
205 this.histogram_updated =
true;
210 THistPainter.prototype.GetAxis =
function(name) {
211 var histo = this.GetHisto();
212 if (!histo || !histo.fAxes)
return null;
214 var axis = histo.fAxes._0;
217 case "x": axis = histo.fAxes._0;
break;
218 case "y": axis = histo.fAxes._1;
break;
219 case "z": axis = histo.fAxes._2;
break;
221 if (!axis || axis.GetBinCoord)
return axis;
223 if (axis._typename ==
"ROOT::Experimental::RAxisEquidistant") {
224 axis.min = axis.fLow;
225 axis.max = axis.fLow + (axis.fNBins-2)/axis.fInvBinWidth;
227 axis.GetBinCoord =
function(bin) {
return this.fLow + bin/this.fInvBinWidth; };
228 axis.FindBin =
function(x,add) {
return Math.floor((x - this.fLow)*this.fInvBinWidth + add); };
231 axis.min = axis.fBinBorders[0];
232 axis.max = axis.fBinBorders[axis.fNBins - 2];
233 axis.GetBinCoord =
function(bin) {
234 var indx = Math.round(bin);
235 if (indx <= 0)
return this.fBinBorders[0];
236 if (indx > this.fNBins - 2)
return this.fBinBorders[this.fNBins - 2];
237 if (indx==bin)
return this.fBinBorders[indx];
238 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
239 return this.fBinBorders[indx] * Math.abs(bin-indx2) + this.fBinBorders[indx2] * Math.abs(bin-indx);
241 axis.FindBin =
function(x,add) {
242 for (var k = 1; k < this.fBinBorders.length; ++k)
243 if (x < this.fBinBorders[k])
return Math.floor(k-1+add);
244 return this.fNBins - 2;
251 THistPainter.prototype.CreateAxisFuncs =
function(with_y_axis, with_z_axis) {
255 var histo = this.GetHisto();
258 var axis = this.GetAxis(
"x");
259 this.xmin = axis.min;
260 this.xmax = axis.max;
262 if (!with_y_axis || !this.nbinsy)
return;
264 axis = this.GetAxis(
"y");
265 this.ymin = axis.min;
266 this.ymax = axis.max;
267 if (!with_z_axis || !this.nbinsz)
return;
269 axis = this.GetAxis(
"z");
270 this.zmin = axis.min;
271 this.zmax = axis.max;
274 THistPainter.prototype.AddInteractive =
function() {
277 if (this.is_main_painter()) {
278 var fp = this.frame_painter();
279 if (fp) fp.AddInteractive();
284 THistPainter.prototype.DrawBins =
function() {
285 alert(
"HistPainter.DrawBins not implemented");
288 THistPainter.prototype.ToggleTitle =
function(arg) {
292 THistPainter.prototype.DrawTitle =
function() {
295 THistPainter.prototype.UpdateStatWebCanvas =
function() {
298 THistPainter.prototype.ToggleStat =
function(arg) {
301 THistPainter.prototype.GetSelectIndex =
function(axis, size, add) {
304 main = this.frame_painter(),
305 taxis = this.GetAxis(axis),
306 nbins =
this[
'nbins'+axis] || 0,
307 min = main ? main[
'zoom_' + axis +
'min'] : 0,
308 max = main ? main[
'zoom_' + axis +
'max'] : 0;
310 if ((min !== max) && taxis) {
312 indx = taxis.FindBin(min, add || 0);
314 indx = taxis.FindBin(max, (add || 0) + 0.5);
315 if (indx<0) indx = 0;
else if (indx>nbins) indx = nbins;
317 indx = (size ==
"left") ? 0 : nbins;
323 THistPainter.prototype.FindStat =
function() {
327 THistPainter.prototype.IgnoreStatsFill =
function() {
331 THistPainter.prototype.CreateStat =
function(force) {
335 THistPainter.prototype.ButtonClick =
function(funcname) {
339 if ((this.zoom_xmin !== this.zoom_xmax) || (this.zoom_ymin !== this.zoom_ymax) || (this.zoom_zmin !== this.zoom_zmax)) {
341 var fp = this.frame_painter();
if (fp) fp.zoom_changed_interactive = 0;
344 if (this.draw_content && (typeof this.AutoZoom ===
'function')) {
349 case "ToggleLogX": this.frame_painter().ToggleLog(
"x");
break;
350 case "ToggleLogY": this.frame_painter().ToggleLog(
"y");
break;
351 case "ToggleLogZ": this.frame_painter().ToggleLog(
"z");
break;
352 case "ToggleStatBox": this.ToggleStat();
return true;
break;
357 THistPainter.prototype.FillToolbar =
function(not_shown) {
358 var pp = this.pad_painter();
361 pp.AddButton(JSROOT.ToolbarIcons.auto_zoom,
'Toggle between unzoom and autozoom-in',
'ToggleZoom',
"Ctrl *");
362 pp.AddButton(JSROOT.ToolbarIcons.arrow_right,
"Toggle log x",
"ToggleLogX",
"PageDown");
363 pp.AddButton(JSROOT.ToolbarIcons.arrow_up,
"Toggle log y",
"ToggleLogY",
"PageUp");
364 if (this.Dimension() > 1)
365 pp.AddButton(JSROOT.ToolbarIcons.arrow_diag,
"Toggle log z",
"ToggleLogZ");
366 if (this.draw_content)
367 pp.AddButton(JSROOT.ToolbarIcons.statbox,
'Toggle stat box',
"ToggleStatBox");
368 if (!not_shown) pp.ShowButtons();
371 THistPainter.prototype.Get3DToolTip =
function(indx) {
372 var histo = this.GetHisto(),
373 tip = { bin: indx, name: histo.fName ||
"histo", title: histo.fTitle };
374 switch (this.Dimension()) {
376 tip.ix = indx; tip.iy = 1;
377 tip.value = histo.getBinContent(tip.ix);
378 tip.error = histo.getBinError(indx);
379 tip.lines = this.GetBinTips(indx-1);
382 tip.ix = indx % (this.nbinsx + 2);
383 tip.iy = (indx - tip.ix) / (this.nbinsx + 2);
384 tip.value = histo.getBinContent(tip.ix, tip.iy);
385 tip.error = histo.getBinError(indx);
386 tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1);
389 tip.ix = indx % (this.nbinsx+2);
390 tip.iy = ((indx - tip.ix) / (this.nbinsx+2)) % (this.nbinsy+2);
391 tip.iz = (indx - tip.ix - tip.iy * (this.nbinsx+2)) / (this.nbinsx+2) / (this.nbinsy+2);
392 tip.value = this.GetObject().getBinContent(tip.ix, tip.iy, tip.iz);
393 tip.error = histo.getBinError(indx);
394 tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1, tip.iz-1);
401 THistPainter.prototype.CreateContour =
function(nlevels, zmin, zmax, zminpositive) {
403 if (nlevels<1) nlevels = JSROOT.gStyle.fNumberContours;
408 if (this.root_pad().fLogz) {
409 if (this.colzmax <= 0) this.colzmax = 1.;
410 if (this.colzmin <= 0)
411 if ((zminpositive===undefined) || (zminpositive <= 0))
412 this.colzmin = 0.0001*this.colzmax;
414 this.colzmin = ((zminpositive < 3) || (zminpositive>100)) ? 0.3*zminpositive : 1;
415 if (this.colzmin >= this.colzmax) this.colzmin = 0.0001*this.colzmax;
417 var logmin = Math.log(this.colzmin)/Math.log(10),
418 logmax = Math.log(this.colzmax)/Math.log(10),
419 dz = (logmax-logmin)/nlevels;
420 this.fContour.push(this.colzmin);
421 for (var level=1; level<nlevels; level++)
422 this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10)));
423 this.fContour.push(this.colzmax);
424 this.fCustomContour =
true;
426 if ((this.colzmin === this.colzmax) && (this.colzmin !== 0)) {
427 this.colzmax += 0.01*Math.abs(this.colzmax);
428 this.colzmin -= 0.01*Math.abs(this.colzmin);
430 var dz = (this.colzmax-this.colzmin)/nlevels;
431 for (var level=0; level<=nlevels; level++)
432 this.fContour.push(
this.colzmin + dz*level);
435 var main = this.frame_painter();
437 if (this.Dimension() < 3) {
438 main.zmin = this.zmin = this.colzmin;
439 main.zmax = this.zmax = this.colzmax;
442 main.fContour = this.fContour;
443 main.fCustomContour = this.fCustomContour;
444 main.colzmin = this.colzmin;
445 main.colzmax = this.colzmax;
447 return this.fContour;
450 THistPainter.prototype.GetContour =
function() {
451 if (this.fContour)
return this.fContour;
453 var main = this.frame_painter();
454 if (main && main.fContour) {
455 this.fContour = main.fContour;
456 this.fCustomContour = main.fCustomContour;
457 this.colzmin = main.colzmin;
458 this.colzmax = main.colzmax;
459 return this.fContour;
464 var histo = this.GetHisto(), nlevels = JSROOT.gStyle.fNumberContours,
465 zmin = this.minbin, zmax = this.maxbin, zminpos = this.minposbin;
466 if (zmin === zmax) { zmin = this.gminbin; zmax = this.gmaxbin; zminpos = this.gminposbin }
472 if (main.zoom_zmin != main.zoom_zmax) {
473 zmin = main.zoom_zmin;
474 zmax = main.zoom_zmax;
490 this.fCustomContour =
false;
492 return this.CreateContour(nlevels, zmin, zmax, zminpos);
495 THistPainter.prototype.FillContextMenu =
function(menu) {
497 var histo = this.GetHisto();
499 menu.add(
"header:v7histo::anyname");
501 if (this.draw_content) {
502 menu.addchk(this.ToggleStat(
'only-check'),
"Show statbox",
function() { this.ToggleStat(); });
504 if (typeof this.FillHistContextMenu ==
'function')
505 this.FillHistContextMenu(menu);
508 if (this.options.Mode3D) {
512 menu.add(
"separator");
514 var main = this.main_painter() ||
this,
515 fp = this.frame_painter(),
518 menu.addchk(main.IsTooltipAllowed(),
'Show tooltips',
function() {
519 main.SetTooltipAllowed(
"toggle");
522 menu.addchk(axis_painter.enable_highlight,
'Highlight bins',
function() {
523 axis_painter.enable_highlight = !axis_painter.enable_highlight;
524 if (!axis_painter.enable_highlight && main.BinHighlight3D && main.mode3d) main.BinHighlight3D(null);
527 if (fp && fp.Render3D) {
528 menu.addchk(main.options.FrontBox,
'Front box',
function() {
529 main.options.FrontBox = !main.options.FrontBox;
532 menu.addchk(main.options.BackBox,
'Back box',
function() {
533 main.options.BackBox = !main.options.BackBox;
538 if (this.draw_content) {
539 menu.addchk(!this.options.Zero,
'Suppress zeros',
function() {
540 this.options.Zero = !
this.options.Zero;
544 if ((this.options.Lego==12) || (this.options.Lego==14)) {
545 menu.addchk(this.options.Zscale,
"Z scale",
function() {
548 if (this.FillPaletteMenu) this.FillPaletteMenu(menu);
552 if (main.control && typeof main.control.reset ===
'function')
553 menu.add(
'Reset camera',
function() {
554 main.control.reset();
558 this.FillAttContextMenu(menu);
560 if (this.histogram_updated && this.zoom_changed_interactive)
561 menu.add(
'Let update zoom',
function() {
562 this.zoom_changed_interactive = 0;
570 THistPainter.prototype.getContourIndex =
function(zc) {
572 var cntr = this.GetContour();
574 if (this.fCustomContour) {
575 var l = 0, r = cntr.length-1, mid;
576 if (zc < cntr[0])
return -1;
577 if (zc >= cntr[r])
return r;
579 mid = Math.round((l+r)/2);
580 if (cntr[mid] > zc) r = mid;
else l = mid;
586 if (zc < this.colzmin)
return this.options.Zero ? -1 : 0;
589 if (zc===this.colzmin)
return ((this.colzmin != 0) || !this.options.Zero ||
this.IsTH2Poly()) ? 0 : -1;
591 return Math.floor(0.01+(zc-this.colzmin)*(cntr.length-1)/(
this.colzmax-
this.colzmin));
596 THistPainter.prototype.getContourColor =
function(zc, asindx) {
597 var zindx = this.getContourIndex(zc);
598 if (zindx < 0)
return null;
600 var cntr = this.GetContour(),
601 palette = this.GetPalette(),
602 indx = palette.calcColorIndex(zindx, cntr.length);
604 return asindx ? indx : palette.getColor(indx);
607 THistPainter.prototype.GetPalette =
function(force) {
608 if (!this.fPalette || force)
609 this.fPalette = this.get_palette(
true, this.options.Palette);
610 return this.fPalette;
613 THistPainter.prototype.FillPaletteMenu =
function(menu) {
615 var curr = this.options.Palette, hpainter =
this;
616 if ((curr===null) || (curr===0)) curr = JSROOT.gStyle.Palette;
618 function change(arg) {
619 hpainter.options.Palette = parseInt(arg);
620 hpainter.GetPalette(
true);
624 function add(
id, name, more) {
625 menu.addchk((
id===curr) || more,
'<nobr>' + name +
'</nobr>',
id, change);
628 menu.add(
"sub:Palette");
630 add(50,
"ROOT 5", (curr>=10) && (curr<51));
632 add(52,
"Grayscale", (curr>0) && (curr<10));
633 add(53,
"Dark body radiator");
634 add(54,
"Two-color hue");
636 add(56,
"Inverted dark body radiator");
637 add(57,
"Bird", (curr>112));
638 add(58,
"Cubehelix");
639 add(59,
"Green Red Violet");
640 add(60,
"Blue Red Yellow");
642 add(62,
"Color Printable On Grey");
644 add(64,
"Aquamarine");
651 THistPainter.prototype.DrawColorPalette =
function(enabled, postpone_draw, can_move) {
657 THistPainter.prototype.ToggleColz =
function() {
658 var can_toggle = this.options.Mode3D ? (this.options.Lego === 12 || this.options.Lego === 14 || this.options.Surf === 11 || this.options.Surf === 12) :
659 this.options.Color ||
this.options.Contour;
662 this.options.Zscale = !this.options.Zscale;
663 this.DrawColorPalette(this.options.Zscale,
false,
true);
667 THistPainter.prototype.ToggleMode3D =
function() {
668 this.options.Mode3D = !this.options.Mode3D;
670 if (this.options.Mode3D) {
671 if (!this.options.Surf && !
this.options.Lego && !
this.options.Error) {
672 if ((this.nbinsx>=50) || (this.nbinsy>=50))
673 this.options.Lego = this.options.Color ? 14 : 13;
675 this.options.Lego = this.options.Color ? 12 : 1;
677 this.options.Zero =
false;
681 this.CopyOptionsToOthers();
682 this.InteractiveRedraw(
"pad",
"drawopt");
685 THistPainter.prototype.PrepareColorDraw =
function(args) {
687 if (!args) args = { rounding:
true, extra: 0, middle: 0 };
689 if (args.extra === undefined) args.extra = 0;
690 if (args.middle === undefined) args.middle = 0;
692 var histo = this.GetHisto(), xaxis = this.GetAxis(
"x"), yaxis = this.GetAxis(
"y"),
693 pmain = this.frame_painter(),
694 hdim = this.Dimension(),
695 i, j, x, y, binz, binarea,
697 i1: this.GetSelectIndex(
"x",
"left", 0 - args.extra),
698 i2: this.GetSelectIndex(
"x",
"right", 1 + args.extra),
699 j1: (hdim===1) ? 0 : this.GetSelectIndex(
"y",
"left", 0 - args.extra),
700 j2: (hdim===1) ? 1 : this.GetSelectIndex(
"y",
"right", 1 + args.extra),
701 min: 0, max: 0, sumz: 0, xbar1: 0, xbar2: 1, ybar1: 0, ybar2: 1
703 res.grx =
new Float32Array(res.i2+1);
704 res.gry =
new Float32Array(res.j2+1);
708 res.origx =
new Float32Array(res.i2+1);
709 res.origy =
new Float32Array(res.j2+1);
712 if (args.pixel_density) args.rounding =
true;
715 for (i = res.i1; i <= res.i2; ++i) {
716 x = xaxis.GetBinCoord(i + args.middle);
717 if (pmain.logx && (x <= 0)) { res.i1 = i+1;
continue; }
718 if (res.origx) res.origx[i] = x;
719 res.grx[i] = pmain.grx(x);
720 if (args.rounding) res.grx[i] = Math.round(res.grx[i]);
723 if (res.grx[i] < -pmain.size_xy3d) { res.i1 = i; res.grx[i] = -pmain.size_xy3d; }
724 if (res.grx[i] > pmain.size_xy3d) { res.i2 = i; res.grx[i] = pmain.size_xy3d; }
729 res.gry[0] = pmain.gry(0);
730 res.gry[1] = pmain.gry(1);
732 for (j = res.j1; j <= res.j2; ++j) {
733 y = yaxis.GetBinCoord(j + args.middle);
734 if (pmain.logy && (y <= 0)) { res.j1 = j+1;
continue; }
735 if (res.origy) res.origy[j] = y;
736 res.gry[j] = pmain.gry(y);
737 if (args.rounding) res.gry[j] = Math.round(res.gry[j]);
740 if (res.gry[j] < -pmain.size_xy3d) { res.j1 = j; res.gry[j] = -pmain.size_xy3d; }
741 if (res.gry[j] > pmain.size_xy3d) { res.j2 = j; res.gry[j] = pmain.size_xy3d; }
747 binz = histo.getBinContent(res.i1 + 1, res.j1 + 1);
748 this.maxbin = this.minbin = this.minposbin = null;
750 for (i = res.i1; i < res.i2; ++i) {
751 for (j = res.j1; j < res.j2; ++j) {
752 binz = histo.getBinContent(i + 1, j + 1);
754 if (args.pixel_density) {
755 binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]);
756 if (binarea <= 0)
continue;
757 res.max = Math.max(res.max, binz);
758 if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz;
761 if (this.maxbin===null) {
762 this.maxbin = this.minbin = binz;
764 this.maxbin = Math.max(this.maxbin, binz);
765 this.minbin = Math.min(this.minbin, binz);
768 if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz;
773 this.fContour = null;
774 this.fCustomContour =
false;
781 function TH1Painter(histo) {
782 THistPainter.call(
this, histo);
783 this.wheel_zoomy =
false;
786 TH1Painter.prototype = Object.create(THistPainter.prototype);
788 TH1Painter.prototype.ConvertTH1K =
function() {
789 var histo = this.GetObject();
791 if (histo.fReady)
return;
793 var arr = histo.fArray;
794 histo.fNcells = histo.fXaxis.fNbins + 2;
795 histo.fArray =
new Float64Array(histo.fNcells);
796 for (var n=0;n<histo.fNcells;++n) histo.fArray[n] = 0;
797 for (var n=0;n<histo.fNIn;++n) histo.Fill(arr[n]);
801 TH1Painter.prototype.ScanContent =
function(when_axis_changed) {
804 var histo = this.GetHisto();
807 if (!this.nbinsx && when_axis_changed) when_axis_changed =
false;
809 if (!when_axis_changed) {
810 this.nbinsx = this.GetAxis(
"x").fNBins - 2;
812 this.CreateAxisFuncs(
false);
815 var left = this.GetSelectIndex(
"x",
"left"),
816 right = this.GetSelectIndex(
"x",
"right");
818 if (when_axis_changed) {
819 if ((left === this.scan_xleft) && (right === this.scan_xright))
return;
822 this.scan_xleft = left;
823 this.scan_xright = right;
825 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0, first =
true, value, err;
827 for (var i = 0; i < this.nbinsx; ++i) {
828 value = histo.getBinContent(i+1);
831 if ((i<left) || (i>=right))
continue;
834 if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value;
842 hmin = Math.min(hmin, value - err);
843 hmax = Math.max(hmax, value + err);
847 hsum += histo.getBinContent(0) + histo.getBinContent(this.nbinsx + 1);
849 this.stat_entries = hsum;
854 this.ymin_nz = hmin_nz;
856 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) {
857 this.draw_content =
false;
859 this.draw_content =
true;
862 if (this.draw_content) {
864 if (hmin == 0) { this.ymin = 0; this.ymax = 1; }
865 else if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
866 else { this.ymin = 0; this.ymax = hmin * 2; }
868 var dy = (hmax - hmin) * 0.05;
869 this.ymin = hmin - dy;
870 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
871 this.ymax = hmax + dy;
876 TH1Painter.prototype.CountStat =
function(cond) {
877 var profile = this.IsTProfile(),
878 histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
879 left = this.GetSelectIndex(
"x",
"left"),
880 right = this.GetSelectIndex(
"x",
"right"),
881 stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0,
882 i, xx = 0, w = 0, xmax = null, wmax = null,
883 fp = this.frame_painter(),
884 res = { name:
"histo", meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: 0, entries: this.stat_entries, xmax:0, wmax:0 };
886 for (i = left; i < right; ++i) {
887 xx = xaxis.GetBinCoord(i+0.5);
889 if (cond && !cond(xx))
continue;
892 w = histo.fBinEntries[i + 1];
893 stat_sumwy += histo.fArray[i + 1];
894 stat_sumwy2 += histo.fSumw2[i + 1];
896 w = histo.getBinContent(i + 1);
899 if ((xmax===null) || (w>wmax)) { xmax = xx; wmax = w; }
902 stat_sumwx += w * xx;
903 stat_sumwx2 += w * xx * xx;
907 if (!fp.IsAxisZoomed(
"x") && histo.fTsumw) {
908 stat_sumw = histo.fTsumw;
909 stat_sumwx = histo.fTsumwx;
910 stat_sumwx2 = histo.fTsumwx2;
913 res.integral = stat_sumw;
916 res.meanx = stat_sumwx / stat_sumw;
917 res.meany = stat_sumwy / stat_sumw;
918 res.rmsx = Math.sqrt(Math.abs(stat_sumwx2 / stat_sumw - res.meanx * res.meanx));
919 res.rmsy = Math.sqrt(Math.abs(stat_sumwy2 / stat_sumw - res.meany * res.meany));
930 TH1Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
933 if (this.IgnoreStatsFill())
return false;
935 var data = this.CountStat(),
936 print_name = dostat % 10,
937 print_entries = Math.floor(dostat / 10) % 10,
938 print_mean = Math.floor(dostat / 100) % 10,
939 print_rms = Math.floor(dostat / 1000) % 10,
940 print_under = Math.floor(dostat / 10000) % 10,
941 print_over = Math.floor(dostat / 100000) % 10,
942 print_integral = Math.floor(dostat / 1000000) % 10,
943 print_skew = Math.floor(dostat / 10000000) % 10,
944 print_kurt = Math.floor(dostat / 100000000) % 10;
950 stat.AddText(data.name);
952 if (this.IsTProfile()) {
954 if (print_entries > 0)
955 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
957 if (print_mean > 0) {
958 stat.AddText(
"Mean = " + stat.Format(data.meanx));
959 stat.AddText(
"Mean y = " + stat.Format(data.meany));
963 stat.AddText(
"Std Dev = " + stat.Format(data.rmsx));
964 stat.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
969 if (print_entries > 0)
970 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
973 stat.AddText(
"Mean = " + stat.Format(data.meanx));
976 stat.AddText(
"Std Dev = " + stat.Format(data.rmsx));
979 stat.AddText(
"Underflow = " + stat.Format(histo.getBinContent(0),
"entries"));
982 stat.AddText(
"Overflow = " + stat.Format(histo.getBinContent(
this.nbinsx+1),
"entries"));
984 if (print_integral > 0)
985 stat.AddText(
"Integral = " + stat.Format(data.integral,
"entries"));
988 stat.AddText(
"Skew = <not avail>");
991 stat.AddText(
"Kurt = <not avail>");
999 TH1Painter.prototype.DrawBars =
function(width, height) {
1003 var left = this.GetSelectIndex(
"x",
"left", -1),
1004 right = this.GetSelectIndex(
"x",
"right", 1),
1005 pmain = this.frame_painter(),
1007 histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
1008 i, x1, x2, grx1, grx2, y, gry1, gry2, w,
1009 bars =
"", barsl =
"", barsr =
"",
1010 side = (this.options.BarStyle > 10) ? this.options.BarStyle % 10 : 0;
1012 if (side>4) side = 4;
1013 gry2 = pmain.swap_xy ? 0 : height;
1014 if ((this.options.BaseLine !==
false) && !isNaN(this.options.BaseLine))
1015 if (this.options.BaseLine >= pmain.scale_ymin)
1016 gry2 = Math.round(pmain.gry(
this.options.BaseLine));
1018 for (i = left; i < right; ++i) {
1019 x1 = xaxis.GetBinCoord(i);
1020 x2 = xaxis.GetBinCoord(i+1);
1022 if (pmain.logx && (x2 <= 0))
continue;
1024 grx1 = Math.round(pmain.grx(x1));
1025 grx2 = Math.round(pmain.grx(x2));
1027 y = histo.getBinContent(i+1);
1028 if (pmain.logy && (y < pmain.scale_ymin))
continue;
1029 gry1 = Math.round(pmain.gry(y));
1032 grx1 += Math.round(this.options.fBarOffset/1000*w);
1033 w = Math.round(this.options.fBarWidth/1000*w);
1036 bars +=
"M"+gry2+
","+grx1 +
"h"+(gry1-gry2) +
"v"+w +
"h"+(gry2-gry1) +
"z";
1038 bars +=
"M"+grx1+
","+gry1 +
"h"+w +
"v"+(gry2-gry1) +
"h"+(-w)+
"z";
1042 w = Math.round(w * side / 10);
1043 if (pmain.swap_xy) {
1044 barsl +=
"M"+gry2+
","+grx1 +
"h"+(gry1-gry2) +
"v" + w +
"h"+(gry2-gry1) +
"z";
1045 barsr +=
"M"+gry2+
","+grx2 +
"h"+(gry1-gry2) +
"v" + (-w) +
"h"+(gry2-gry1) +
"z";
1047 barsl +=
"M"+grx1+
","+gry1 +
"h"+w +
"v"+(gry2-gry1) +
"h"+(-w)+
"z";
1048 barsr +=
"M"+grx2+
","+gry1 +
"h"+(-w) +
"v"+(gry2-gry1) +
"h"+w +
"z";
1053 if (this.fillatt.empty()) this.fillatt.SetSolidColor(
"blue");
1055 if (bars.length > 0)
1056 this.draw_g.append(
"svg:path")
1058 .call(this.fillatt.func);
1060 if (barsl.length > 0)
1061 this.draw_g.append(
"svg:path")
1063 .call(this.fillatt.func)
1064 .style(
"fill", d3.rgb(
this.fillatt.color).brighter(0.5).toString());
1066 if (barsr.length > 0)
1067 this.draw_g.append(
"svg:path")
1069 .call(this.fillatt.func)
1070 .style(
"fill", d3.rgb(
this.fillatt.color).darker(0.5).toString());
1073 TH1Painter.prototype.DrawFilledErrors =
function(width, height) {
1076 var left = this.GetSelectIndex(
"x",
"left", -1),
1077 right = this.GetSelectIndex(
"x",
"right", 1),
1078 pmain = this.frame_painter(),
1079 histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
1080 i, x, grx, y, yerr, gry1, gry2,
1081 bins1 = [], bins2 = [];
1083 for (i = left; i < right; ++i) {
1084 x = xaxis.GetBinCoord(i+0.5);
1085 if (pmain.logx && (x <= 0))
continue;
1086 grx = Math.round(pmain.grx(x));
1088 y = histo.getBinContent(i+1);
1089 yerr = histo.getBinError(i+1);
1090 if (pmain.logy && (y-yerr < pmain.scale_ymin))
continue;
1092 gry1 = Math.round(pmain.gry(y + yerr));
1093 gry2 = Math.round(pmain.gry(y - yerr));
1095 bins1.push({grx:grx, gry: gry1});
1096 bins2.unshift({grx:grx, gry: gry2});
1099 var kind = (this.options.ErrorKind === 4) ?
"bezier" :
"line",
1100 path1 = JSROOT.Painter.BuildSvgPath(kind, bins1),
1101 path2 = JSROOT.Painter.BuildSvgPath(
"L"+kind, bins2);
1103 if (this.fillatt.empty()) this.fillatt.setSolidColor(
"blue");
1105 this.draw_g.append(
"svg:path")
1106 .attr(
"d", path1.path + path2.path +
"Z")
1107 .style(
"stroke",
"none")
1108 .call(this.fillatt.func);
1111 TH1Painter.prototype.DrawBins =
function() {
1115 var width = this.frame_width(), height = this.frame_height(), options = this.options;
1117 if (!this.draw_content || (width<=0) || (height<=0))
1118 return this.RemoveDrawG();
1120 this.CheckHistDrawAttributes();
1123 return this.DrawBars(width, height);
1125 if ((options.ErrorKind === 3) || (options.ErrorKind === 4))
1126 return this.DrawFilledErrors(width, height);
1130 var left = this.GetSelectIndex(
"x",
"left", -1),
1131 right = this.GetSelectIndex(
"x",
"right", 2),
1132 pmain = this.frame_painter(),
1133 pthis =
this, histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
1134 res =
"", lastbin =
false,
1135 startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, bestimin, bestimax,
1136 exclude_zero = !options.Zero,
1137 show_errors = options.Error,
1138 show_markers = options.Mark,
1139 show_line = options.Line,
1140 show_text = options.Text,
1141 text_profile = show_text && (this.options.TextKind ==
"E") && this.IsTProfile() && histo.fBinEntries,
1142 path_fill = null, path_err = null, path_marker = null, path_line = null,
1143 endx =
"", endy =
"", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, midx,
1144 mpath =
"", text_col, text_angle, text_size;
1149 if (options.ErrorKind === 2) {
1150 if (this.fillatt.empty()) show_markers =
true;
1151 else path_fill =
"";
1153 if (options.Error) path_err =
"";
1155 if (show_line) path_line =
"";
1159 this.createAttMarker({ attr: histo, style: this.options.MarkStyle });
1160 if (this.markeratt.size > 0) {
1163 this.markeratt.reset_pos();
1165 show_markers =
false;
1170 text_col = this.get_color(histo.fMarkerColor);
1171 text_angle = -1*options.TextAngle;
1174 if ((options.fMarkerSize!==1) && text_angle)
1175 text_size = 0.02 * height * options.fMarkerSize;
1177 if (!text_angle && !options.TextKind) {
1178 var space = width / (right - left + 1);
1179 if (space < 3 * text_size) {
1181 text_size = Math.round(space*0.7);
1185 this.StartTextDrawing(42, text_size, this.draw_g, text_size);
1190 var use_minmax = ((right-left) > 3*width);
1192 if (options.ErrorKind === 1) {
1193 var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize;
1194 endx =
"m0," + lw +
"v-" + 2*lw +
"m0," + lw;
1195 endy =
"m" + lw +
",0h-" + 2*lw +
"m" + lw +
",0";
1196 dend = Math.floor((this.lineatt.width-1)/2);
1199 var draw_markers = show_errors || show_markers;
1201 if (draw_markers || show_text || show_line) use_minmax =
true;
1203 function draw_bin(besti) {
1204 bincont = histo.getBinContent(besti+1);
1205 if (!exclude_zero || (bincont!==0)) {
1206 mx1 = Math.round(pmain.grx(xaxis.GetBinLowEdge(besti+1)));
1207 mx2 = Math.round(pmain.grx(xaxis.GetBinLowEdge(besti+2)));
1208 midx = Math.round((mx1+mx2)/2);
1209 my = Math.round(pmain.gry(bincont));
1212 binerr = histo.getBinError(besti+1);
1213 yerr1 = Math.round(my - pmain.gry(bincont + binerr));
1214 yerr2 = Math.round(pmain.gry(bincont - binerr) - my);
1218 var cont = text_profile ? histo.fBinEntries[besti+1] : bincont;
1221 var lbl = (cont === Math.round(cont)) ? cont.toString() : JSROOT.FFormat(cont, JSROOT.gStyle.fPaintTextFormat);
1224 pthis.DrawText({ align: 12, x: midx, y: Math.round(my - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 });
1226 pthis.DrawText({ align: 22, x: Math.round(mx1 + (mx2-mx1)*0.1), y: Math.round(my-2-text_size), width: Math.round((mx2-mx1)*0.8), height: text_size, text: lbl, color: text_col, latex: 0 });
1230 if (show_line && (path_line !== null))
1231 path_line += ((path_line.length===0) ?
"M" :
"L") + midx +
"," + my;
1234 if ((my >= -yerr1) && (my <= height + yerr2)) {
1235 if (path_fill !== null)
1236 path_fill +=
"M" + mx1 +
","+(my-yerr1) +
1237 "h" + (mx2-mx1) +
"v" + (yerr1+yerr2+1) +
"h-" + (mx2-mx1) +
"z";
1238 if (path_marker !== null)
1239 path_marker += pthis.markeratt.create(midx, my);
1240 if (path_err !== null) {
1241 if (pthis.options.errorX > 0) {
1242 var mmx1 = Math.round(midx - (mx2-mx1)*pthis.options.errorX),
1243 mmx2 = Math.round(midx + (mx2-mx1)*pthis.options.errorX);
1244 path_err +=
"M" + (mmx1+dend) +
","+ my + endx +
"h" + (mmx2-mmx1-2*dend) + endx;
1246 path_err +=
"M" + midx +
"," + (my-yerr1+dend) + endy +
"v" + (yerr1+yerr2-2*dend) + endy;
1253 for (i = left; i <= right; ++i) {
1255 x = xaxis.GetBinCoord(i);
1257 if (pmain.logx && (x <= 0))
continue;
1259 grx = Math.round(pmain.grx(x));
1261 lastbin = (i === right);
1263 if (lastbin && (left<right)) {
1266 y = histo.getBinContent(i+1);
1267 gry = Math.round(pmain.gry(y));
1270 if (res.length === 0) {
1271 bestimin = bestimax = i;
1272 prevx = startx = currx = grx;
1273 prevy = curry_min = curry_max = curry = gry;
1274 res =
"M"+currx+
","+curry;
1277 if ((grx === currx) && !lastbin) {
1278 if (gry < curry_min) bestimax = i;
else
1279 if (gry > curry_max) bestimin = i;
1280 curry_min = Math.min(curry_min, gry);
1281 curry_max = Math.max(curry_max, gry);
1285 if (draw_markers || show_text || show_line) {
1286 if (bestimin === bestimax) { draw_bin(bestimin); }
else
1287 if (bestimin < bestimax) { draw_bin(bestimin); draw_bin(bestimax); }
else {
1288 draw_bin(bestimax); draw_bin(bestimin);
1293 if (!draw_markers && ((curry_min !== curry_max) || (prevy !== curry_min))) {
1295 if (prevx !== currx)
1296 res +=
"h"+(currx-prevx);
1298 if (curry === curry_min) {
1299 if (curry_max !== prevy)
1300 res +=
"v" + (curry_max - prevy);
1301 if (curry_min !== curry_max)
1302 res +=
"v" + (curry_min - curry_max);
1304 if (curry_min !== prevy)
1305 res +=
"v" + (curry_min - prevy);
1306 if (curry_max !== curry_min)
1307 res +=
"v" + (curry_max - curry_min);
1308 if (curry !== curry_max)
1309 res +=
"v" + (curry - curry_max);
1316 if (lastbin && (prevx !== grx))
1317 res +=
"h"+(grx-prevx);
1319 bestimin = bestimax = i;
1320 curry_min = curry_max = curry = gry;
1324 if ((gry !== curry) || lastbin) {
1325 if (grx !== currx) res +=
"h"+(grx-currx);
1326 if (gry !== curry) res +=
"v"+(gry-curry);
1332 var close_path =
"";
1333 if (!this.fillatt.empty()) {
1334 var h0 = height + 3, gry0 = Math.round(pmain.gry(0));
1335 if (gry0 <= 0) h0 = -3;
else if (gry0 < height) h0 = gry0;
1336 close_path =
"L"+currx+
","+h0 +
"L"+startx+
","+h0 +
"Z";
1337 if (res.length>0) res += close_path;
1340 if (draw_markers || show_line) {
1341 if ((path_fill !== null) && (path_fill.length > 0))
1342 this.draw_g.append(
"svg:path")
1343 .attr(
"d", path_fill)
1344 .call(this.fillatt.func);
1346 if ((path_err !== null) && (path_err.length > 0))
1347 this.draw_g.append(
"svg:path")
1348 .attr(
"d", path_err)
1349 .call(this.lineatt.func);
1351 if ((path_line !== null) && (path_line.length > 0)) {
1352 if (!this.fillatt.empty())
1353 this.draw_g.append(
"svg:path")
1354 .attr(
"d", options.Fill ? (path_line + close_path) : res)
1355 .attr(
"stroke",
"none")
1356 .call(this.fillatt.func);
1358 this.draw_g.append(
"svg:path")
1359 .attr(
"d", path_line)
1360 .attr(
"fill",
"none")
1361 .call(this.lineatt.func);
1364 if ((path_marker !== null) && (path_marker.length > 0))
1365 this.draw_g.append(
"svg:path")
1366 .attr(
"d", path_marker)
1367 .call(this.markeratt.func);
1370 if (res && options.Hist) {
1371 this.draw_g.append(
"svg:path")
1373 .style(
"stroke-linejoin",
"miter")
1374 .call(this.lineatt.func)
1375 .call(this.fillatt.func);
1379 this.FinishTextDrawing(this.draw_g);
1383 TH1Painter.prototype.GetBinTips =
function(bin) {
1385 name = this.GetTipName(),
1386 pmain = this.frame_painter(),
1387 histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
1388 x1 = xaxis.GetBinCoord(bin),
1389 x2 = xaxis.GetBinCoord(bin+1),
1390 cont = histo.getBinContent(bin+1),
1391 xlbl =
"", xnormal =
false;
1393 if (name.length>0) tips.push(name);
1395 if (pmain.x_kind ===
'labels') xlbl = pmain.AxisAsText(
"x", x1);
else
1396 if (pmain.x_kind ===
'time') xlbl = pmain.AxisAsText(
"x", (x1+x2)/2);
else
1397 { xnormal =
true; xlbl =
"[" + pmain.AxisAsText(
"x", x1) +
", " + pmain.AxisAsText(
"x", x2) +
")"; }
1399 if (this.options.Error ||
this.options.Mark) {
1400 tips.push(
"x = " + xlbl);
1401 tips.push(
"y = " + pmain.AxisAsText(
"y", cont));
1402 if (this.options.Error) {
1403 if (xnormal) tips.push(
"error x = " + ((x2 - x1) / 2).toPrecision(4));
1404 tips.push(
"error y = " + histo.getBinError(bin + 1).toPrecision(4));
1407 tips.push(
"bin = " + (bin+1));
1408 tips.push(
"x = " + xlbl);
1409 if (histo[
'$baseh']) cont -= histo[
'$baseh'].getBinContent(bin+1);
1410 if (cont === Math.round(cont))
1411 tips.push(
"entries = " + cont);
1413 tips.push(
"entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.fStatFormat));
1419 TH1Painter.prototype.ProcessTooltip =
function(pnt) {
1420 if ((pnt === null) || !this.draw_content || this.options.Mode3D) {
1421 if (this.draw_g !== null)
1422 this.draw_g.select(
".tooltip_bin").remove();
1426 var width = this.frame_width(),
1427 height = this.frame_height(),
1428 pmain = this.frame_painter(),
1430 histo = this.GetHisto(), xaxis = this.GetAxis(
"x"),
1431 findbin = null, show_rect =
true,
1432 grx1, midx, grx2, gry1, midy, gry2, gapx = 2,
1433 left = this.GetSelectIndex(
"x",
"left", -1),
1434 right = this.GetSelectIndex(
"x",
"right", 2),
1435 l = left, r = right;
1437 function GetBinGrX(i) {
1438 var xx = xaxis.GetBinCoord(i);
1439 return (pmain.logx && (xx<=0)) ? null : pmain.grx(xx);
1442 function GetBinGrY(i) {
1443 var yy = histo.getBinContent(i + 1);
1444 if (pmain.logy && (yy < pmain.scale_ymin))
1445 return pmain.swap_xy ? -1000 : 10*height;
1446 return Math.round(pmain.gry(yy));
1449 var pnt_x = pmain.swap_xy ? pnt.y : pnt.x,
1450 pnt_y = pmain.swap_xy ? pnt.x : pnt.y;
1453 var m = Math.round((l+r)*0.5),
1455 if ((xx === null) || (xx < pnt_x - 0.5)) {
1456 if (pmain.swap_xy) r = m;
else l = m;
1457 }
else if (xx > pnt_x + 0.5) {
1458 if (pmain.swap_xy) l = m;
else r = m;
1459 }
else { l++; r--; }
1463 grx1 = GetBinGrX(findbin);
1465 if (pmain.swap_xy) {
1466 while ((l>left) && (GetBinGrX(l-1) < grx1 + 2)) --l;
1467 while ((r<right) && (GetBinGrX(r+1) > grx1 - 2)) ++r;
1469 while ((l>left) && (GetBinGrX(l-1) > grx1 - 2)) --l;
1470 while ((r<right) && (GetBinGrX(r+1) < grx1 + 2)) ++r;
1477 for (var m=l;m<=r;m++) {
1478 var dist = Math.abs(GetBinGrY(m) - pnt_y);
1479 if (dist < best) { best = dist; findbin = m; }
1483 if (best > height/10)
1484 findbin = Math.round(l + (r-l) / height * pnt_y);
1486 grx1 = GetBinGrX(findbin);
1489 grx1 = Math.round(grx1);
1490 grx2 = Math.round(GetBinGrX(findbin+1));
1492 if (this.options.Bar) {
1493 var w = grx2 - grx1;
1494 grx1 += Math.round(this.options.fBarOffset/1000*w);
1495 grx2 = grx1 + Math.round(this.options.fBarWidth/1000*w);
1498 if (grx1 > grx2) { var d = grx1; grx1 = grx2; grx2 = d; }
1500 midx = Math.round((grx1+grx2)/2);
1502 midy = gry1 = gry2 = GetBinGrY(findbin);
1504 if (this.options.Bar) {
1509 gry1 = Math.round(pmain.gry(((
this.options.BaseLine!==
false) && (
this.options.BaseLine > pmain.scale_ymin)) ?
this.options.BaseLine : pmain.scale_ymin));
1511 if (gry1 > gry2) { var d = gry1; gry1 = gry2; gry2 = d; }
1513 if (!pnt.touch && (pnt.nproc === 1))
1514 if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null;
1516 }
else if (this.options.Error ||
this.options.Mark ||
this.options.Line) {
1521 if (this.markeratt) msize = Math.max(msize, this.markeratt.GetFullSize());
1523 if (this.options.Error) {
1524 var cont = histo.getBinContent(findbin+1),
1525 binerr = histo.getBinError(findbin+1);
1527 gry1 = Math.round(pmain.gry(cont + binerr));
1528 gry2 = Math.round(pmain.gry(cont - binerr));
1530 if ((cont==0) && this.IsTProfile()) findbin = null;
1532 var dx = (grx2-grx1)*this.options.errorX;
1533 grx1 = Math.round(midx - dx);
1534 grx2 = Math.round(midx + dx);
1538 if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; }
1540 gry1 = Math.min(gry1, midy - msize);
1541 gry2 = Math.max(gry2, midy + msize);
1543 if (!pnt.touch && (pnt.nproc === 1))
1544 if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null;
1550 show_rect = (pnt.nproc === 1) && (right-left < width);
1555 if (!this.fillatt.empty()) {
1556 gry2 = Math.round(pmain.gry(0));
1557 if (gry2 < 0) gry2 = 0;
else if (gry2 > height) gry2 = height;
1558 if (gry2 < gry1) { var d = gry1; gry1 = gry2; gry2 = d; }
1562 if (((pnt.y < gry1) || (pnt.y > gry2)) && !pnt.touch) findbin = null;
1566 if (findbin!==null) {
1568 if ((findbin === left) && (grx1 > pnt_x + gapx)) findbin = null;
else
1569 if ((findbin === right-1) && (grx2 < pnt_x - gapx)) findbin = null;
else
1571 if ((pnt_x < grx1 - gapx) || (pnt_x > grx2 + gapx)) findbin = null;
else
1573 if (!this.options.Zero && (histo.getBinContent(findbin+1)===0)) findbin = null;
1576 var ttrect = this.draw_g.select(
".tooltip_bin");
1578 if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) {
1583 var res = { name:
"histo", title: histo.fTitle,
1584 x: midx, y: midy, exact:
true,
1585 color1: this.lineatt ? this.lineatt.color :
'green',
1586 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
'blue',
1587 lines: this.GetBinTips(findbin) };
1594 }
else if (show_rect) {
1597 ttrect = this.draw_g.append(
"svg:rect")
1598 .attr(
"class",
"tooltip_bin h1bin")
1599 .style(
"pointer-events",
"none");
1601 res.changed = ttrect.property(
"current_bin") !== findbin;
1604 ttrect.attr(
"x", pmain.swap_xy ? gry1 : grx1)
1605 .attr(
"width", pmain.swap_xy ? gry2-gry1 : grx2-grx1)
1606 .attr(
"y", pmain.swap_xy ? grx1 : gry1)
1607 .attr(
"height", pmain.swap_xy ? grx2-grx1 : gry2-gry1)
1608 .style(
"opacity",
"0.3")
1609 .property(
"current_bin", findbin);
1611 res.exact = (Math.abs(midy - pnt_y) <= 5) || ((pnt_y>=gry1) && (pnt_y<=gry2));
1615 res.menu_dist = Math.sqrt((midx-pnt_x)*(midx-pnt_x) + (midy-pnt_y)*(midy-pnt_y));
1618 var radius = this.lineatt.width + 3;
1621 ttrect = this.draw_g.append(
"svg:circle")
1622 .attr(
"class",
"tooltip_bin")
1623 .style(
"pointer-events",
"none")
1625 .call(this.lineatt.func)
1626 .call(this.fillatt.func);
1628 res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius);
1630 res.menu = res.exact;
1631 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
1633 res.changed = ttrect.property(
"current_bin") !== findbin;
1636 ttrect.attr(
"cx", midx)
1638 .property(
"current_bin", findbin);
1642 res.user_info = { obj: histo, name:
"histo",
1643 bin: findbin, cont: histo.getBinContent(findbin+1),
1644 grx: midx, gry: midy };
1650 TH1Painter.prototype.FillHistContextMenu =
function(menu) {
1652 menu.add(
"Auto zoom-in", this.AutoZoom);
1654 var sett = JSROOT.getDrawSettings(
"ROOT." + this.GetObject()._typename,
'nosame');
1656 menu.addDrawMenu(
"Draw with", sett.opts,
function(arg) {
1657 if (arg===
'inspect')
1658 return this.ShowInspector();
1660 this.DecodeOptions(arg);
1662 if (this.options.need_fillcol &&
this.fillatt &&
this.fillatt.empty())
1663 this.fillatt.Change(5,1001);
1666 this.InteractiveRedraw(
"pad",
"drawopt");
1670 TH1Painter.prototype.AutoZoom =
function() {
1671 var left = this.GetSelectIndex(
"x",
"left", -1),
1672 right = this.GetSelectIndex(
"x",
"right", 1),
1673 dist = right - left, histo = this.GetHisto(), xaxis = this.GetAxis(
"x");
1675 if (dist == 0)
return;
1678 var min = histo.getBinContent(left + 1);
1679 for (var indx = left; indx < right; ++indx)
1680 min = Math.min(min, histo.getBinContent(indx+1));
1681 if (min > 0)
return;
1683 while ((left < right) && (histo.getBinContent(left+1) <= min)) ++left;
1684 while ((left < right) && (histo.getBinContent(right) <= min)) --right;
1687 if ((left === right-1) && (left > 2) && (right < this.nbinsx-2)) {
1691 if ((right - left < dist) && (left < right))
1692 this.frame_painter().Zoom(xaxis.GetBinCoord(left), xaxis.GetBinCoord(right));
1695 TH1Painter.prototype.CanZoomIn =
function(axis,min,max) {
1696 var xaxis = this.GetAxis(
"x");
1698 if ((axis==
"x") && (xaxis.FindBin(max,0.5) - xaxis.FindBin(min,0) > 1))
return true;
1700 if ((axis==
"y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6))
return true;
1706 TH1Painter.prototype.CallDrawFunc =
function(callback, resize) {
1708 var main = this.frame_painter();
1710 if (main && (main.mode3d !==
this.options.Mode3D)) {
1712 this.options.Mode3D = main.mode3d;
1715 var funcname = this.options.Mode3D ?
"Draw3D" :
"Draw2D";
1717 this[funcname](callback, resize);
1720 TH1Painter.prototype.Draw2D =
function(call_back) {
1722 this.Clear3DScene();
1723 this.mode3d =
false;
1727 if (typeof this.DrawColorPalette ===
'function')
1728 this.DrawColorPalette(
false);
1730 if (this.DrawAxes())
1733 console.log(
'FAIL DARWING AXES');
1737 this.AddInteractive();
1738 JSROOT.CallBack(call_back);
1741 TH1Painter.prototype.Draw3D =
function(call_back, resize) {
1743 JSROOT.AssertPrerequisites(
'hist3d',
function() {
1744 this.Draw3D(call_back, resize);
1748 TH1Painter.prototype.Redraw =
function(resize) {
1749 this.CallDrawFunc(null, resize);
1752 function drawHist1(divid, histo, opt) {
1754 var painter =
new TH1Painter(histo);
1756 painter.PrepareFrame(divid);
1758 painter.options = { Hist:
true, Bar:
false, Error:
false, ErrorKind: -1, errorX: 0, Zero:
false, Mark:
false,
1759 Line:
false, Fill:
false, Lego: 0, Surf: 0,
1760 Text:
false, TextAngle: 0, TextKind:
"", AutoColor: 0,
1761 fBarOffset: 0, fBarWidth: 1000, fMarkerSize: 1, BaseLine:
false, Mode3D:
false };
1766 painter.ScanContent();
1770 painter.CallDrawFunc(
function() {
1773 painter.DrawingReady();
1781 function TH2Painter(histo) {
1782 THistPainter.call(
this, histo);
1783 this.fContour = null;
1784 this.fCustomContour =
false;
1785 this.fPalette = null;
1786 this.wheel_zoomy =
true;
1789 TH2Painter.prototype = Object.create(THistPainter.prototype);
1791 TH2Painter.prototype.Cleanup =
function() {
1792 delete this.fCustomContour;
1793 delete this.tt_handle;
1795 THistPainter.prototype.Cleanup.call(
this);
1798 TH2Painter.prototype.Dimension =
function() {
1802 TH2Painter.prototype.ToggleProjection =
function(kind, width) {
1804 if (kind==
"Projections") kind =
"";
1806 if ((typeof kind ==
'string') && (kind.length>1)) {
1807 width = parseInt(kind.substr(1));
1811 if (!width) width = 1;
1813 if (kind && (this.is_projection==kind)) {
1814 if (this.projection_width === width) {
1817 this.projection_width = width;
1822 delete this.proj_hist;
1824 var new_proj = (this.is_projection === kind) ?
"" : kind;
1825 this.is_projection =
"";
1826 this.projection_width = width;
1828 var canp = this.canv_painter();
1829 if (canp) canp.ToggleProjection(this.is_projection, this.RedrawProjection.bind(
this,
"toggling", new_proj));
1832 TH2Painter.prototype.RedrawProjection =
function(ii1, ii2, jj1, jj2) {
1835 if (ii1 ===
"toggling") {
1836 this.is_projection = ii2;
1837 ii1 = ii2 = undefined;
1840 if (!this.is_projection)
return;
1843 TH2Painter.prototype.ExecuteMenuCommand =
function(method, args) {
1844 if (THistPainter.prototype.ExecuteMenuCommand.call(
this,method, args))
return true;
1846 if ((method.fName ==
'SetShowProjectionX') || (method.fName ==
'SetShowProjectionY')) {
1847 this.ToggleProjection(method.fName[17], args && parseInt(args) ? parseInt(args) : 1);
1854 TH2Painter.prototype.FillHistContextMenu =
function(menu) {
1857 menu.add(
"sub:Projections", this.ToggleProjection);
1858 var kind = this.is_projection ||
"";
1859 if (kind) kind += this.projection_width;
1860 var kinds = [
"X1",
"X2",
"X3",
"X5",
"X10",
"Y1",
"Y2",
"Y3",
"Y5",
"Y10"];
1861 for (var k=0;k<kinds.length;++k)
1862 menu.addchk(kind==kinds[k], kinds[k], kinds[k],
this.ToggleProjection);
1863 menu.add(
"endsub:");
1865 menu.add(
"Auto zoom-in", this.AutoZoom);
1867 var sett = JSROOT.getDrawSettings(
"ROOT." + this.GetObject()._typename,
'nosame');
1869 menu.addDrawMenu(
"Draw with", sett.opts,
function(arg) {
1870 if (arg===
'inspect')
1871 return this.ShowInspector();
1872 this.DecodeOptions(arg);
1873 this.InteractiveRedraw(
"pad",
"drawopt");
1876 if (this.options.Color)
1877 this.FillPaletteMenu(menu);
1880 TH2Painter.prototype.ButtonClick =
function(funcname) {
1881 if (THistPainter.prototype.ButtonClick.call(
this, funcname))
return true;
1884 case "ToggleColor": this.ToggleColor();
break;
1885 case "ToggleColorZ": this.ToggleColz();
break;
1886 case "Toggle3D": this.ToggleMode3D();
break;
1887 default:
return false;
1894 TH2Painter.prototype.FillToolbar =
function() {
1895 THistPainter.prototype.FillToolbar.call(
this,
true);
1897 var pp = this.pad_painter();
1900 if (!this.IsTH2Poly())
1901 pp.AddButton(JSROOT.ToolbarIcons.th2color,
"Toggle color",
"ToggleColor");
1902 pp.AddButton(JSROOT.ToolbarIcons.th2colorz,
"Toggle color palette",
"ToggleColorZ");
1903 pp.AddButton(JSROOT.ToolbarIcons.th2draw3d,
"Toggle 3D mode",
"Toggle3D");
1907 TH2Painter.prototype.ToggleColor =
function() {
1909 if (this.options.Mode3D) {
1910 this.options.Mode3D =
false;
1911 this.options.Color =
true;
1913 this.options.Color = !this.options.Color;
1916 this._can_move_colz =
true;
1923 TH2Painter.prototype.AutoZoom =
function() {
1924 if (this.IsTH2Poly())
return;
1926 var i1 = this.GetSelectIndex(
"x",
"left", -1),
1927 i2 = this.GetSelectIndex(
"x",
"right", 1),
1928 j1 = this.GetSelectIndex(
"y",
"left", -1),
1929 j2 = this.GetSelectIndex(
"y",
"right", 1),
1930 i,j, histo = this.GetHisto(), xaxis = this.GetAxis(
"x"), yaxis = this.GetAxis(
"y");
1932 if ((i1 == i2) || (j1 == j2))
return;
1935 var min = histo.getBinContent(i1 + 1, j1 + 1);
1936 for (i = i1; i < i2; ++i)
1937 for (j = j1; j < j2; ++j)
1938 min = Math.min(min, histo.getBinContent(i+1, j+1));
1939 if (min > 0)
return;
1941 var ileft = i2, iright = i1, jleft = j2, jright = j1;
1943 for (i = i1; i < i2; ++i)
1944 for (j = j1; j < j2; ++j)
1945 if (histo.getBinContent(i + 1, j + 1) > min) {
1946 if (i < ileft) ileft = i;
1947 if (i >= iright) iright = i + 1;
1948 if (j < jleft) jleft = j;
1949 if (j >= jright) jright = j + 1;
1952 var xmin, xmax, ymin, ymax, isany =
false;
1954 if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; }
1955 if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; }
1957 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
1958 xmin = xaxis.GetBinCoord(ileft);
1959 xmax = xaxis.GetBinCoord(iright);
1963 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
1964 ymin = yaxis.GetBinCoord(jleft);
1965 ymax = yaxis.GetBinCoord(jright);
1969 if (isany) this.frame_painter().Zoom(xmin, xmax, ymin, ymax);
1972 TH2Painter.prototype.ScanContent =
function(when_axis_changed) {
1975 if (when_axis_changed && this.nbinsx && this.nbinsy)
return;
1977 var i, j, histo = this.GetHisto();
1979 this.nbinsx = this.GetAxis(
"x").fNBins - 2;
1980 this.nbinsy = this.GetAxis(
"y").fNBins - 2;
1984 this.CreateAxisFuncs(
true);
1986 if (this.IsTH2Poly()) {
1987 this.gminposbin = null;
1988 this.gminbin = this.gmaxbin = 0;
1990 for (var n=0, len=histo.fBins.arr.length; n<len; ++n) {
1991 var bin_content = histo.fBins.arr[n].fContent;
1992 if (n===0) this.gminbin = this.gmaxbin = bin_content;
1994 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
1995 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
1997 if (bin_content > 0)
1998 if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content;
2002 this.gminbin = this.gmaxbin = histo.getBinContent(1, 1);
2003 this.gminposbin = null;
2004 for (i = 0; i < this.nbinsx; ++i) {
2005 for (j = 0; j < this.nbinsy; ++j) {
2006 var bin_content = histo.getBinContent(i+1, j+1);
2007 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
2008 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
2009 if (bin_content > 0)
2010 if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content;
2016 if (this.gminposbin === null) this.gminposbin = this.gmaxbin*1e-4;
2018 if (this.options.Axis > 0) {
2019 this.draw_content =
false;
2021 this.draw_content = this.gmaxbin > 0;
2022 if (!this.draw_content && this.options.Zero &&
this.IsTH2Poly()) {
2023 this.draw_content =
true;
2024 this.options.Line = 1;
2029 TH2Painter.prototype.CountStat =
function(cond) {
2030 var histo = this.GetObject(),
2031 stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0,
2032 stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0,
2033 xside, yside, xx, yy, zz,
2034 fp = this.frame_painter(),
2035 res = { name:
"histo", entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix: [0,0,0,0,0,0,0,0,0], xmax: 0, ymax:0, wmax: null };
2037 if (this.IsTH2Poly()) {
2039 var len = histo.fBins.arr.length, i, bin, n, gr, ngr, numgraphs, numpoints,
2040 pmain = this.frame_painter();
2042 for (i=0;i<len;++i) {
2043 bin = histo.fBins.arr[i];
2045 xside = 1; yside = 1;
2047 if (bin.fXmin > pmain.scale_xmax) xside = 2;
else
2048 if (bin.fXmax < pmain.scale_xmin) xside = 0;
2049 if (bin.fYmin > pmain.scale_ymax) yside = 2;
else
2050 if (bin.fYmax < pmain.scale_ymin) yside = 0;
2052 xx = yy = numpoints = 0;
2053 gr = bin.fPoly; numgraphs = 1;
2054 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
2056 for (ngr=0;ngr<numgraphs;++ngr) {
2057 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
2059 for (n=0;n<gr.fNpoints;++n) {
2066 if (numpoints > 1) {
2067 xx = xx / numpoints;
2068 yy = yy / numpoints;
2075 res.matrix[yside * 3 + xside] += zz;
2077 if ((xside != 1) || (yside != 1))
continue;
2079 if ((cond!=null) && !cond(xx,yy))
continue;
2081 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
2084 stat_sumx1 += xx * zz;
2085 stat_sumy1 += yy * zz;
2086 stat_sumx2 += xx * xx * zz;
2087 stat_sumy2 += yy * yy * zz;
2088 stat_sumxy += xx * yy * zz;
2091 var xleft = this.GetSelectIndex(
"x",
"left"),
2092 xright = this.GetSelectIndex(
"x",
"right"),
2093 yleft = this.GetSelectIndex(
"y",
"left"),
2094 yright = this.GetSelectIndex(
"y",
"right"),
2095 xi, yi, xaxis = this.GetAxis(
"x"), yaxis = this.GetAxis(
"y");
2097 for (xi = 0; xi <= this.nbinsx + 1; ++xi) {
2098 xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
2099 xx = xaxis.GetBinCoord(xi - 0.5);
2101 for (yi = 0; yi <= this.nbinsy + 1; ++yi) {
2102 yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
2103 yy = yaxis.GetBinCoord(yi - 0.5);
2105 zz = histo.getBinContent(xi, yi);
2109 res.matrix[yside * 3 + xside] += zz;
2111 if ((xside != 1) || (yside != 1))
continue;
2113 if ((cond!=null) && !cond(xx,yy))
continue;
2115 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
2118 stat_sumx1 += xx * zz;
2119 stat_sumy1 += yy * zz;
2120 stat_sumx2 += xx * xx * zz;
2121 stat_sumy2 += yy * yy * zz;
2122 stat_sumxy += xx * yy * zz;
2127 if (!fp.IsAxisZoomed(
"x") && !fp.IsAxisZoomed(
"y") && (histo.fTsumw > 0)) {
2128 stat_sum0 = histo.fTsumw;
2129 stat_sumx1 = histo.fTsumwx;
2130 stat_sumx2 = histo.fTsumwx2;
2131 stat_sumy1 = histo.fTsumwy;
2132 stat_sumy2 = histo.fTsumwy2;
2133 stat_sumxy = histo.fTsumwxy;
2136 if (stat_sum0 > 0) {
2137 res.meanx = stat_sumx1 / stat_sum0;
2138 res.meany = stat_sumy1 / stat_sum0;
2139 res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx));
2140 res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany));
2143 if (res.wmax===null) res.wmax = 0;
2144 res.integral = stat_sum0;
2146 if (histo.fEntries > 1) res.entries = histo.fEntries;
2151 TH2Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
2154 if (this.IgnoreStatsFill())
return false;
2156 var data = this.CountStat(),
2157 print_name = Math.floor(dostat % 10),
2158 print_entries = Math.floor(dostat / 10) % 10,
2159 print_mean = Math.floor(dostat / 100) % 10,
2160 print_rms = Math.floor(dostat / 1000) % 10,
2161 print_under = Math.floor(dostat / 10000) % 10,
2162 print_over = Math.floor(dostat / 100000) % 10,
2163 print_integral = Math.floor(dostat / 1000000) % 10,
2164 print_skew = Math.floor(dostat / 10000000) % 10,
2165 print_kurt = Math.floor(dostat / 100000000) % 10;
2170 stat.AddText(data.name);
2172 if (print_entries > 0)
2173 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
2175 if (print_mean > 0) {
2176 stat.AddText(
"Mean x = " + stat.Format(data.meanx));
2177 stat.AddText(
"Mean y = " + stat.Format(data.meany));
2180 if (print_rms > 0) {
2181 stat.AddText(
"Std Dev x = " + stat.Format(data.rmsx));
2182 stat.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
2185 if (print_integral > 0)
2186 stat.AddText(
"Integral = " + stat.Format(data.matrix[4],
"entries"));
2188 if (print_skew > 0) {
2189 stat.AddText(
"Skewness x = <undef>");
2190 stat.AddText(
"Skewness y = <undef>");
2194 stat.AddText(
"Kurt = <undef>");
2196 if ((print_under > 0) || (print_over > 0)) {
2197 var m = data.matrix;
2199 stat.AddText(
"" + m[6].toFixed(0) +
" | " + m[7].toFixed(0) +
" | " + m[7].toFixed(0));
2200 stat.AddText(
"" + m[3].toFixed(0) +
" | " + m[4].toFixed(0) +
" | " + m[5].toFixed(0));
2201 stat.AddText(
"" + m[0].toFixed(0) +
" | " + m[1].toFixed(0) +
" | " + m[2].toFixed(0));
2209 TH2Painter.prototype.DrawBinsColor =
function(w,h) {
2210 var histo = this.GetHisto(),
2211 handle = this.PrepareColorDraw(),
2212 colPaths = [], currx = [], curry = [],
2213 colindx, cmd1, cmd2, i, j, binz;
2216 for (i = handle.i1; i < handle.i2; ++i) {
2217 for (j = handle.j1; j < handle.j2; ++j) {
2218 binz = histo.getBinContent(i + 1, j + 1);
2219 colindx = this.getContourColor(binz,
true);
2221 if (!this.options.Zero)
continue;
2222 if ((colindx === null) && this._show_empty_bins) colindx = 0;
2224 if (colindx === null)
continue;
2226 cmd1 =
"M"+handle.grx[i]+
","+handle.gry[j+1];
2227 if (colPaths[colindx] === undefined) {
2228 colPaths[colindx] = cmd1;
2230 cmd2 =
"m" + (handle.grx[i]-currx[colindx]) +
"," + (handle.gry[j+1]-curry[colindx]);
2231 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
2234 currx[colindx] = handle.grx[i];
2235 curry[colindx] = handle.gry[j+1];
2237 colPaths[colindx] +=
"v" + (handle.gry[j] - handle.gry[j+1]) +
2238 "h" + (handle.grx[i+1] - handle.grx[i]) +
2239 "v" + (handle.gry[j+1] - handle.gry[j]) +
"z";
2243 for (colindx=0;colindx<colPaths.length;++colindx)
2244 if (colPaths[colindx] !== undefined)
2247 .attr(
"palette-index", colindx)
2248 .attr(
"fill", this.fPalette.getColor(colindx))
2249 .attr(
"d", colPaths[colindx]);
2254 TH2Painter.prototype.BuildContour =
function(handle, levels, palette, contour_func) {
2255 var histo = this.GetHisto(), ddd = 0,
2260 xarr =
new Float32Array(2*kMAXCONTOUR),
2261 yarr =
new Float32Array(2*kMAXCONTOUR),
2262 itarr =
new Int32Array(2*kMAXCONTOUR),
2263 lj = 0, ipoly, poly, polys = [], np, npmax = 0,
2264 x = [0.,0.,0.,0.], y = [0.,0.,0.,0.], zc = [0.,0.,0.,0.], ir = [0,0,0,0],
2265 i, j, k, n, m, ix, ljfill, count,
2266 xsave, ysave, itars, ix, jx;
2268 function BinarySearch(zc) {
2269 for (var kk=0;kk<levels.length;++kk)
2270 if (zc<levels[kk])
return kk-1;
2271 return levels.length-1;
2274 function PaintContourLine(elev1, icont1, x1, y1, elev2, icont2, x2, y2) {
2276 var vert = (x1 === x2),
2277 tlen = vert ? (y2 - y1) : (x2 - x1),
2279 tdif = elev2 - elev1,
2281 maxii = kMAXCONTOUR/2 -3 + lj,
2283 xlen, pdif, diff, elev;
2285 while (n <= icont2 && ii <= maxii) {
2288 diff = elev - elev1;
2293 yarr[ii] = y1 + xlen;
2295 xarr[ii] = x1 + xlen;
2306 var arrx = handle.original ? handle.origx : handle.grx,
2307 arry = handle.original ? handle.origy : handle.gry;
2309 for (j = handle.j1; j < handle.j2-1; ++j) {
2311 y[1] = y[0] = (arry[j] + arry[j+1])/2;
2312 y[3] = y[2] = (arry[j+1] + arry[j+2])/2;
2314 for (i = handle.i1; i < handle.i2-1; ++i) {
2316 zc[0] = histo.getBinContent(i+1, j+1);
2317 zc[1] = histo.getBinContent(i+2, j+1);
2318 zc[2] = histo.getBinContent(i+2, j+2);
2319 zc[3] = histo.getBinContent(i+1, j+2);
2322 ir[k] = BinarySearch(zc[k]);
2324 if ((ir[0] !== ir[1]) || (ir[1] !== ir[2]) || (ir[2] !== ir[3]) || (ir[3] !== ir[0])) {
2325 x[3] = x[0] = (arrx[i] + arrx[i+1])/2;
2326 x[2] = x[1] = (arrx[i+1] + arrx[i+2])/2;
2328 if (zc[0] <= zc[1]) n = 0;
else n = 1;
2329 if (zc[2] <= zc[3]) m = 2;
else m = 3;
2330 if (zc[n] > zc[m]) n = m;
2333 for (ix=1;ix<=4;ix++) {
2335 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],
2336 zc[m-1],ir[m-1],x[m-1],y[m-1]);
2341 if (zc[0] <= zc[1]) n = 0;
else n = 1;
2342 if (zc[2] <= zc[3]) m = 2;
else m = 3;
2343 if (zc[n] > zc[m]) n = m;
2346 for (ix=1;ix<=4;ix++) {
2349 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],
2350 zc[m-1],ir[m-1],x[m-1],y[m-1]);
2357 for (ix=1; ix<=lj-5; ix +=2) {
2359 while (itarr[ix-1] != itarr[ix]) {
2363 for (jx=ix; jx<=lj-5; jx +=2) {
2364 xarr[jx] = xarr[jx+2];
2365 yarr[jx] = yarr[jx+2];
2366 itarr[jx] = itarr[jx+2];
2370 itarr[lj-3] = itars;
2371 if (count > kMAXCOUNT)
break;
2376 if (count > kMAXCOUNT)
continue;
2378 for (ix=1; ix<=lj-2; ix +=2) {
2380 ipoly = itarr[ix-1];
2382 if ((ipoly >= 0) && (ipoly < levels.length)) {
2383 poly = polys[ipoly];
2385 poly = polys[ipoly] = JSROOT.CreateTPolyLine(kMAXCONTOUR*4,
true);
2387 np = poly.fLastPoint;
2388 if (np < poly.fN-2) {
2389 poly.fX[np+1] = Math.round(xarr[ix-1]); poly.fY[np+1] = Math.round(yarr[ix-1]);
2390 poly.fX[np+2] = Math.round(xarr[ix]); poly.fY[np+2] = Math.round(yarr[ix]);
2391 poly.fLastPoint = np+2;
2392 npmax = Math.max(npmax, poly.fLastPoint+1);
2402 var polysort =
new Int32Array(levels.length), first = 0;
2404 for (ipoly=0;ipoly<levels.length;ipoly++) {
2405 if (levels[ipoly] >= 0) { first = ipoly;
break; }
2409 for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;}
2410 for (ipoly=first;ipoly<levels.length;ipoly++) { polysort[k] = ipoly; k++;}
2412 var xp =
new Float32Array(2*npmax),
2413 yp =
new Float32Array(2*npmax);
2415 for (k=0;k<levels.length;++k) {
2417 ipoly = polysort[k];
2418 poly = polys[ipoly];
2419 if (!poly)
continue;
2421 var colindx = palette.calcColorIndex(ipoly, levels.length),
2422 xx = poly.fX, yy = poly.fY, np = poly.fLastPoint+1,
2423 istart = 0, iminus, iplus, xmin = 0, ymin = 0, nadd;
2429 xp[iminus]= xx[istart]; yp[iminus] = yy[istart];
2430 xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1];
2431 xx[istart] = xx[istart+1] = xmin;
2432 yy[istart] = yy[istart+1] = ymin;
2435 for (i=2;i<np;i+=2) {
2436 if ((iplus < 2*npmax-1) && (xx[i] === xp[iplus]) && (yy[i] === yp[iplus])) {
2438 xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1];
2439 xx[i] = xx[i+1] = xmin;
2440 yy[i] = yy[i+1] = ymin;
2443 if ((iminus > 0) && (xx[i+1] === xp[iminus]) && (yy[i+1] === yp[iminus])) {
2445 xp[iminus] = xx[i]; yp[iminus] = yy[i];
2446 xx[i] = xx[i+1] = xmin;
2447 yy[i] = yy[i+1] = ymin;
2451 if (nadd == 0)
break;
2454 if ((iminus+1 < iplus) && (iminus>=0))
2455 contour_func(colindx, xp, yp, iminus, iplus, ipoly);
2458 for (i=2;i<np;i+=2) {
2459 if (xx[i] !== xmin && yy[i] !== ymin) {
2465 if (istart === 0)
break;
2470 TH2Painter.prototype.DrawBinsContour =
function(frame_w,frame_h) {
2471 var handle = this.PrepareColorDraw({ rounding:
false, extra: 100, original: this.options.Proj != 0 }),
2472 levels = this.GetContour(),
2473 palette = this.GetPalette(),
2474 painter =
this, main = this.frame_painter();
2476 function BuildPath(xp,yp,iminus,iplus) {
2477 var cmd =
"", last = null, pnt = null, i;
2478 for (i=iminus;i<=iplus;++i) {
2480 switch (painter.options.Proj) {
2481 case 1: pnt = main.ProjectAitoff2xy(xp[i], yp[i]);
break;
2482 case 2: pnt = main.ProjectMercator2xy(xp[i], yp[i]);
break;
2483 case 3: pnt = main.ProjectSinusoidal2xy(xp[i], yp[i]);
break;
2484 case 4: pnt = main.ProjectParabolic2xy(xp[i], yp[i]);
break;
2487 pnt.x = main.grx(pnt.x);
2488 pnt.y = main.gry(pnt.y);
2490 pnt = { x: xp[i], y: yp[i] };
2492 pnt.x = Math.round(pnt.x);
2493 pnt.y = Math.round(pnt.y);
2494 if (!cmd) cmd =
"M" + pnt.x +
"," + pnt.y;
2495 else if ((pnt.x != last.x) && (pnt.y != last.y)) cmd +=
"l" + (pnt.x - last.x) +
"," + (pnt.y - last.y);
2496 else if (pnt.x != last.x) cmd +=
"h" + (pnt.x - last.x);
2497 else if (pnt.y != last.y) cmd +=
"v" + (pnt.y - last.y);
2503 if (this.options.Contour===14) {
2504 var dd =
"M0,0h"+frame_w+
"v"+frame_h+
"h-"+frame_w;
2505 if (this.options.Proj) {
2506 var sz = handle.j2 - handle.j1, xd =
new Float32Array(sz*2), yd =
new Float32Array(sz*2);
2507 for (var i=0;i<sz;++i) {
2508 xd[i] = handle.origx[handle.i1];
2509 yd[i] = (handle.origy[handle.j1]*(i+0.5) + handle.origy[handle.j2]*(sz-0.5-i))/sz;
2510 xd[i+sz] = handle.origx[handle.i2];
2511 yd[i+sz] = (handle.origy[handle.j2]*(i+0.5) + handle.origy[handle.j1]*(sz-0.5-i))/sz;
2513 dd = BuildPath(xd,yd,0,2*sz-1);
2518 .attr(
"d", dd +
"z")
2519 .style(
'stroke',
'none')
2520 .style(
"fill", palette.calcColor(0, levels.length));
2523 this.BuildContour(handle, levels, palette,
2524 function(colindx,xp,yp,iminus,iplus) {
2525 var icol = palette.getColor(colindx),
2526 fillcolor = icol, lineatt = null;
2528 switch (painter.options.Contour) {
2530 case 11: fillcolor =
'none'; lineatt =
new JSROOT.TAttLineHandler({ color: icol });
break;
2531 case 12: fillcolor =
'none'; lineatt =
new JSROOT.TAttLineHandler({ color:1, style: (colindx%5 + 1), width: 1 });
break;
2532 case 13: fillcolor =
'none'; lineatt = painter.lineatt;
break;
2536 var elem = painter.draw_g
2538 .attr(
"class",
"th2_contour")
2539 .attr(
"d", BuildPath(xp,yp,iminus,iplus) + (fillcolor ==
'none' ?
"" :
"z"))
2540 .style(
"fill", fillcolor);
2543 elem.call(lineatt.func);
2545 elem.style(
'stroke',
'none');
2549 handle.hide_only_zeros =
true;
2554 TH2Painter.prototype.CreatePolyBin =
function(pmain, bin, text_pos) {
2555 var cmd =
"", ngr, ngraphs = 1, gr = null;
2557 if (bin.fPoly._typename==
'TMultiGraph')
2558 ngraphs = bin.fPoly.fGraphs.arr.length;
2563 bin._sumx = bin._sumy = bin._suml = 0;
2565 function AddPoint(x1,y1,x2,y2) {
2566 var len = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
2567 bin._sumx += (x1+x2)*len/2;
2568 bin._sumy += (y1+y2)*len/2;
2572 for (ngr = 0; ngr < ngraphs; ++ ngr) {
2573 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
2575 var npnts = gr.fNpoints, n,
2576 x = gr.fX, y = gr.fY,
2577 grx = Math.round(pmain.grx(x[0])),
2578 gry = Math.round(pmain.gry(y[0])),
2581 if ((npnts>2) && (x[0]==x[npnts-1]) && (y[0]==y[npnts-1])) npnts--;
2583 cmd +=
"M"+grx+
","+gry;
2585 for (n=1;n<npnts;++n) {
2586 nextx = Math.round(pmain.grx(x[n]));
2587 nexty = Math.round(pmain.gry(y[n]));
2588 if (text_pos) AddPoint(grx,gry, nextx, nexty);
2589 if ((grx!==nextx) || (gry!==nexty)) {
2590 if (grx===nextx) cmd +=
"v" + (nexty - gry);
else
2591 if (gry===nexty) cmd +=
"h" + (nextx - grx);
else
2592 cmd +=
"l" + (nextx - grx) +
"," + (nexty - gry);
2594 grx = nextx; gry = nexty;
2597 if (text_pos) AddPoint(grx, gry, Math.round(pmain.grx(x[0])), Math.round(pmain.gry(y[0])));
2602 if (bin._suml > 0) {
2603 bin._midx = Math.round(bin._sumx / bin._suml);
2604 bin._midy = Math.round(bin._sumy / bin._suml);
2606 bin._midx = Math.round(pmain.grx((bin.fXmin + bin.fXmax)/2));
2607 bin._midy = Math.round(pmain.gry((bin.fYmin + bin.fYmax)/2));
2614 TH2Painter.prototype.DrawPolyBinsColor =
function(w,h) {
2615 var histo = this.GetHisto(),
2616 pmain = this.frame_painter(),
2617 colPaths = [], textbins = [],
2618 colindx, cmd, bin, item,
2619 i, len = histo.fBins.arr.length;
2622 this.fContour = null;
2623 this.fCustomContour =
false;
2626 this.maxbin = this.gmaxbin;
2627 this.minbin = this.gminbin;
2628 this.minposbin = this.gminposbin;
2630 for (i = 0; i < len; ++ i) {
2631 bin = histo.fBins.arr[i];
2632 colindx = this.getContourColor(bin.fContent,
true);
2633 if (colindx === null)
continue;
2634 if (bin.fContent === 0) {
2635 if (!this.options.Zero || !
this.options.Line)
continue;
2640 if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) ||
2641 (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin))
continue;
2643 cmd = this.CreatePolyBin(pmain, bin, this.options.Text && bin.fContent);
2645 if (colPaths[colindx] === undefined)
2646 colPaths[colindx] = cmd;
2648 colPaths[colindx] += cmd;
2650 if (this.options.Text) textbins.push(bin);
2653 for (colindx=0;colindx<colPaths.length;++colindx)
2654 if (colPaths[colindx]) {
2657 .attr(
"palette-index", colindx)
2658 .attr(
"fill", colindx ? this.fPalette.getColor(colindx) :
"none")
2659 .attr(
"d", colPaths[colindx]);
2660 if (this.options.Line)
2661 item.call(this.lineatt.func);
2664 if (textbins.length > 0) {
2665 var text_col = this.get_color(histo.fMarkerColor),
2666 text_angle = -1*this.options.TextAngle,
2667 text_g = this.draw_g.append(
"svg:g").attr(
"class",
"th2poly_text"),
2670 if ((histo.fMarkerSize!==1) && text_angle)
2671 text_size = Math.round(0.02*h*histo.fMarkerSize);
2673 this.StartTextDrawing(42, text_size, text_g, text_size);
2675 for (i = 0; i < textbins.length; ++ i) {
2680 if (!this.options.TextKind) {
2681 lbl = (Math.round(bin.fContent) === bin.fContent) ? bin.fContent.toString() :
2682 JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fPaintTextFormat);
2684 if (bin.fPoly) lbl = bin.fPoly.fName;
2685 if (lbl ===
"Graph") lbl =
"";
2686 if (!lbl) lbl = bin.fNumber;
2689 this.DrawText({ align: 22, x: bin._midx, y: bin._midy, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g });
2692 this.FinishTextDrawing(text_g, null);
2695 return { poly:
true };
2698 TH2Painter.prototype.DrawBinsText =
function(w, h, handle) {
2699 var histo = this.GetHisto(),
2700 i,j,binz,colindx,binw,binh,lbl,posx,posy,sizex,sizey;
2702 if (handle===null) handle = this.PrepareColorDraw({ rounding:
false });
2704 var text_col = this.get_color(histo.fMarkerColor),
2705 text_angle = -1*this.options.TextAngle,
2706 text_g = this.draw_g.append(
"svg:g").attr(
"class",
"th2_text"),
2707 text_size = 20, text_offset = 0,
2708 profile2d = (this.options.TextKind ==
"E") &&
2709 this.MatchObjectType(
'TProfile2D') && (typeof histo.getBinEntries==
'function');
2711 if ((histo.fMarkerSize!==1) && text_angle)
2712 text_size = Math.round(0.02*h*histo.fMarkerSize);
2714 if (this.options.fBarOffset!==0) text_offset = this.options.fBarOffset*1e-3;
2716 this.StartTextDrawing(42, text_size, text_g, text_size);
2718 for (i = handle.i1; i < handle.i2; ++i)
2719 for (j = handle.j1; j < handle.j2; ++j) {
2720 binz = histo.getBinContent(i+1, j+1);
2721 if ((binz === 0) && !this._show_empty_bins)
continue;
2723 binw = handle.grx[i+1] - handle.grx[i];
2724 binh = handle.gry[j] - handle.gry[j+1];
2727 binz = histo.getBinEntries(i+1, j+1);
2729 lbl = (binz === Math.round(binz)) ? binz.toString() :
2730 JSROOT.FFormat(binz, JSROOT.gStyle.fPaintTextFormat);
2733 posx = Math.round(handle.grx[i] + binw*0.5);
2734 posy = Math.round(handle.gry[j+1] + binh*(0.5 + text_offset));
2738 posx = Math.round(handle.grx[i] + binw*0.1);
2739 posy = Math.round(handle.gry[j+1] + binh*(0.1 + text_offset));
2740 sizex = Math.round(binw*0.8);
2741 sizey = Math.round(binh*0.8);
2744 this.DrawText({ align: 22, x: posx, y: posy, width: sizex, height: sizey, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g });
2747 this.FinishTextDrawing(text_g, null);
2749 handle.hide_only_zeros =
true;
2754 TH2Painter.prototype.DrawBinsArrow =
function(w, h) {
2755 var histo = this.GetHisto(), cmd =
"",
2756 i,j,binz,colindx,binw,binh,lbl, loop, dn = 1e-30, dx, dy, xc,yc,
2757 dxn,dyn,x1,x2,y1,y2, anr,si,co,
2758 handle = this.PrepareColorDraw({ rounding:
false }),
2759 scale_x = (handle.grx[handle.i2] - handle.grx[handle.i1])/(handle.i2 - handle.i1 + 1-0.03)/2,
2760 scale_y = (handle.gry[handle.j2] - handle.gry[handle.j1])/(handle.j2 - handle.j1 + 1-0.03)/2;
2762 for (var loop=0;loop<2;++loop)
2763 for (i = handle.i1; i < handle.i2; ++i)
2764 for (j = handle.j1; j < handle.j2; ++j) {
2766 if (i === handle.i1) {
2767 dx = histo.getBinContent(i+2, j+1) - histo.getBinContent(i+1, j+1);
2768 }
else if (i === handle.i2-1) {
2769 dx = histo.getBinContent(i+1, j+1) - histo.getBinContent(i, j+1);
2771 dx = 0.5*(histo.getBinContent(i+2, j+1) - histo.getBinContent(i, j+1));
2773 if (j === handle.j1) {
2774 dy = histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j+1);
2775 }
else if (j === handle.j2-1) {
2776 dy = histo.getBinContent(i+1, j+1) - histo.getBinContent(i+1, j);
2778 dy = 0.5*(histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j));
2782 dn = Math.max(dn, Math.abs(dx), Math.abs(dy));
2784 xc = (handle.grx[i] + handle.grx[i+1])/2;
2785 yc = (handle.gry[j] + handle.gry[j+1])/2;
2786 dxn = scale_x*dx/dn;
2787 dyn = scale_y*dy/dn;
2792 dx = Math.round(x2-x1);
2793 dy = Math.round(y2-y1);
2795 if ((dx!==0) || (dy!==0)) {
2796 cmd +=
"M"+Math.round(x1)+
","+Math.round(y1)+
"l"+dx+
","+dy;
2798 if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
2799 anr = Math.sqrt(2/(dx*dx + dy*dy));
2800 si = Math.round(anr*(dx + dy));
2801 co = Math.round(anr*(dx - dy));
2802 if ((si!==0) && (co!==0))
2803 cmd+=
"l"+(-si)+
","+co +
"m"+si+
","+(-co) +
"l"+(-co)+
","+(-si);
2811 .attr(
"class",
"th2_arrows")
2813 .style(
"fill",
"none")
2814 .call(this.lineatt.func);
2820 TH2Painter.prototype.DrawBinsBox =
function(w,h) {
2822 var histo = this.GetHisto(),
2823 handle = this.PrepareColorDraw({ rounding:
false }),
2824 main = this.frame_painter();
2826 if (main.maxbin === main.minbin) {
2827 main.maxbin = this.gmaxbin;
2828 main.minbin = this.gminbin;
2829 main.minposbin = this.gminposbin;
2831 if (main.maxbin === main.minbin)
2832 main.minbin = Math.min(0, main.maxbin-1);
2834 var absmax = Math.max(Math.abs(main.maxbin), Math.abs(main.minbin)),
2835 absmin = Math.max(0, main.minbin),
2836 i, j, binz, absz, res =
"", cross =
"", btn1 =
"", btn2 =
"",
2837 colindx, zdiff, dgrx, dgry, xx, yy, ww, hh, cmd1, cmd2,
2838 xyfactor = 1, uselogz =
false, logmin = 0, logmax = 1;
2840 if (this.root_pad().fLogz && (absmax>0)) {
2842 logmax = Math.log(absmax);
2843 if (absmin>0) logmin = Math.log(absmin);
else
2844 if ((main.minposbin>=1) && (main.minposbin<100)) logmin = Math.log(0.7);
else
2845 logmin = (main.minposbin > 0) ? Math.log(0.7*main.minposbin) : logmax - 10;
2846 if (logmin >= logmax) logmin = logmax - 10;
2847 xyfactor = 1. / (logmax - logmin);
2849 xyfactor = 1. / (absmax - absmin);
2853 for (i = handle.i1; i < handle.i2; ++i) {
2854 for (j = handle.j1; j < handle.j2; ++j) {
2855 binz = histo.getBinContent(i + 1, j + 1);
2856 absz = Math.abs(binz);
2857 if ((absz === 0) || (absz < absmin))
continue;
2859 zdiff = uselogz ? ((absz>0) ? Math.log(absz) - logmin : 0) : (absz - absmin);
2861 zdiff = 0.5 * ((zdiff < 0) ? 1 : (1 - Math.sqrt(zdiff * xyfactor)));
2863 if (zdiff < 0) zdiff = 0;
2865 ww = handle.grx[i+1] - handle.grx[i];
2866 hh = handle.gry[j] - handle.gry[j+1];
2871 xx = Math.round(handle.grx[i] + dgrx);
2872 yy = Math.round(handle.gry[j+1] + dgry);
2874 ww = Math.max(Math.round(ww - 2*dgrx), 1);
2875 hh = Math.max(Math.round(hh - 2*dgry), 1);
2877 res +=
"M"+xx+
","+yy +
"v"+hh +
"h"+ww +
"v-"+hh +
"z";
2879 if ((binz<0) && (this.options.BoxStyle === 10))
2880 cross +=
"M"+xx+
","+yy +
"l"+ww+
","+hh +
"M"+(xx+ww)+
","+yy +
"l-"+ww+
","+hh;
2882 if ((this.options.BoxStyle === 11) && (ww>5) && (hh>5)) {
2883 var pww = Math.round(ww*0.1),
2884 phh = Math.round(hh*0.1),
2885 side1 =
"M"+xx+
","+yy +
"h"+ww +
"l"+(-pww)+
","+phh +
"h"+(2*pww-ww) +
2886 "v"+(hh-2*phh)+
"l"+(-pww)+
","+phh +
"z",
2887 side2 =
"M"+(xx+ww)+
","+(yy+hh) +
"v"+(-hh) +
"l"+(-pww)+
","+phh +
"v"+(hh-2*phh)+
2888 "h"+(2*pww-ww) +
"l"+(-pww)+
","+phh +
"z";
2889 if (binz<0) { btn2+=side1; btn1+=side2; }
2890 else { btn1+=side1; btn2+=side2; }
2895 if (res.length > 0) {
2896 var elem = this.draw_g.append(
"svg:path")
2898 .call(this.fillatt.func);
2899 if ((this.options.BoxStyle === 11) || !
this.fillatt.empty())
2900 elem.style(
'stroke',
'none');
2902 elem.call(this.lineatt.func);
2905 if ((btn1.length>0) && (
this.fillatt.color !==
'none'))
2906 this.draw_g.append(
"svg:path")
2908 .style(
"stroke",
"none")
2909 .call(this.fillatt.func)
2910 .style(
"fill", d3.rgb(
this.fillatt.color).brighter(0.5).toString());
2913 this.draw_g.append(
"svg:path")
2915 .style(
"stroke",
"none")
2916 .call(this.fillatt.func)
2917 .style(
"fill", this.fillatt.color ===
'none' ?
'red' : d3.rgb(
this.fillatt.color).darker(0.5).toString());
2919 if (cross.length > 0) {
2920 var elem = this.draw_g.append(
"svg:path")
2922 .style(
"fill",
"none");
2923 if (this.lineatt.color !==
'none')
2924 elem.call(this.lineatt.func);
2926 elem.style(
'stroke',
'black');
2932 TH2Painter.prototype.DrawCandle =
function(w,h) {
2933 var histo = this.GetHisto(), yaxis = this.GetAxis(
"y"),
2934 handle = this.PrepareColorDraw(),
2935 pmain = this.frame_painter(),
2936 i, j, y, sum0, sum1, sum2, cont, center, counter, integral, w, pnt,
2937 bars =
"", markers =
"", posy;
2940 if (histo.fMarkerColor === 1) histo.fMarkerColor = histo.fLineColor;
2941 this.createAttMarker({ attr: histo, style: 5 });
2944 this.markeratt.reset_pos();
2949 for (i = handle.i1; i < handle.i2; ++i) {
2954 for (j = 0; j < this.nbinsy; ++j) {
2955 integral += histo.getBinContent(i+1,j+1);
2957 pnt = { bin:i, meany:0, m25y:0, p25y:0, median:0, iqr:0, whiskerp:0, whiskerm:0};
2959 for (j = 0; j < this.nbinsy; ++j) {
2960 cont = histo.getBinContent(i+1,j+1);
2961 posy = yaxis.GetBinCoord(j + 0.5);
2962 if (counter/integral < 0.001 && (counter + cont)/integral >=0.001) pnt.whiskerm = posy;
2963 if (counter/integral < 0.25 && (counter + cont)/integral >=0.25) pnt.m25y = posy;
2964 if (counter/integral < 0.5 && (counter + cont)/integral >=0.5) pnt.median = posy;
2965 if (counter/integral < 0.75 && (counter + cont)/integral >=0.75) pnt.p25y = posy;
2966 if (counter/integral < 0.999 && (counter + cont)/integral >=0.999) pnt.whiskerp = posy;
2972 pnt.meany = sum1/counter;
2974 pnt.iqr = pnt.p25y-pnt.m25y;
2977 if ((pnt.m25y-1.5*pnt.iqr) > pnt.whsikerm) {
2978 pnt.whiskerm = pnt.m25y-1.5*pnt.iqr;
2980 if ((pnt.p25y+1.5*pnt.iqr) < pnt.whiskerp) {
2981 pnt.whiskerp = pnt.p25y+1.5*pnt.iqr;
2985 if (pmain.logy && (pnt.whiskerm<=0))
continue;
2987 w = handle.grx[i+1] - handle.grx[i];
2989 center = (handle.grx[i+1] + handle.grx[i]) / 2 + this.options.fBarOffset/1000*w;
2990 if (this.options.fBarWidth >0) w = w * this.options.fBarWidth / 1000;
2992 pnt.x1 = Math.round(center - w/2);
2993 pnt.x2 = Math.round(center + w/2);
2994 center = Math.round(center);
2996 pnt.y0 = Math.round(pmain.gry(pnt.median));
2998 bars +=
"M" + pnt.x1 +
"," + pnt.y0 +
"h" + (pnt.x2-pnt.x1);
3000 pnt.y1 = Math.round(pmain.gry(pnt.p25y));
3001 pnt.y2 = Math.round(pmain.gry(pnt.m25y));
3004 bars +=
"M" + pnt.x1 +
"," + pnt.y1 +
3005 "v" + (pnt.y2-pnt.y1) +
"h" + (pnt.x2-pnt.x1) +
"v-" + (pnt.y2-pnt.y1) +
"z";
3007 pnt.yy1 = Math.round(pmain.gry(pnt.whiskerp));
3008 pnt.yy2 = Math.round(pmain.gry(pnt.whiskerm));
3011 bars +=
"M" + center +
"," + pnt.y1 +
"v" + (pnt.yy1-pnt.y1);
3012 bars +=
"M" + pnt.x1 +
"," + pnt.yy1 +
"h" + (pnt.x2-pnt.x1);
3015 bars +=
"M" + center +
"," + pnt.y2 +
"v" + (pnt.yy2-pnt.y2);
3016 bars +=
"M" + pnt.x1 +
"," + pnt.yy2 +
"h" + (pnt.x2-pnt.x1);
3019 for (j = 0; j < this.nbinsy; ++j) {
3020 cont = histo.getBinContent(i+1,j+1);
3021 posy = yaxis.GetBinCoord(j + 0.5);
3022 if (cont > 0 && posy < pnt.whiskerm) markers += this.markeratt.create(center, posy);
3023 if (cont > 0 && posy > pnt.whiskerp) markers += this.markeratt.create(center, posy); }
3025 handle.candle.push(pnt);
3028 if (bars.length > 0)
3029 this.draw_g.append(
"svg:path")
3031 .call(this.lineatt.func)
3032 .call(this.fillatt.func);
3034 if (markers.length > 0)
3035 this.draw_g.append(
"svg:path")
3037 .call(this.markeratt.func);
3042 TH2Painter.prototype.DrawBinsScatter =
function(w,h) {
3043 var histo = this.GetHisto(),
3044 handle = this.PrepareColorDraw({ rounding:
true, pixel_density:
true }),
3045 colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [],
3046 colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1.,
3047 scale = this.options.ScatCoef * ((
this.gmaxbin) > 2000 ? 2000. /
this.gmaxbin : 1.);
3049 JSROOT.seed(handle.sumz);
3051 if (scale*handle.sumz < 1e5) {
3054 this.createAttMarker({ attr: histo });
3056 this.markeratt.reset_pos();
3058 var path =
"", k, npix;
3059 for (i = handle.i1; i < handle.i2; ++i) {
3060 cw = handle.grx[i+1] - handle.grx[i];
3061 for (j = handle.j1; j < handle.j2; ++j) {
3062 ch = handle.gry[j] - handle.gry[j+1];
3063 binz = histo.getBinContent(i + 1, j + 1);
3065 npix = Math.round(scale*binz);
3066 if (npix<=0)
continue;
3068 for (k=0;k<npix;++k)
3069 path += this.markeratt.create(
3070 Math.round(handle.grx[i] + cw * JSROOT.random()),
3071 Math.round(handle.gry[j+1] + ch * JSROOT.random()));
3078 .call(this.markeratt.func);
3084 if (this.maxbin > 0.7) factor = 0.7/this.maxbin;
3086 var nlevels = Math.round(handle.max - handle.min);
3087 this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin);
3090 for (i = handle.i1; i < handle.i2; ++i) {
3091 for (j = handle.j1; j < handle.j2; ++j) {
3092 binz = histo.getBinContent(i + 1, j + 1);
3093 if ((binz <= 0) || (binz < this.minbin))
continue;
3095 cw = handle.grx[i+1] - handle.grx[i];
3096 ch = handle.gry[j] - handle.gry[j+1];
3097 if (cw*ch <= 0)
continue;
3099 colindx = this.getContourIndex(binz/cw/ch);
3100 if (colindx < 0)
continue;
3102 cmd1 =
"M"+handle.grx[i]+
","+handle.gry[j+1];
3103 if (colPaths[colindx] === undefined) {
3104 colPaths[colindx] = cmd1;
3105 cell_w[colindx] = cw;
3106 cell_h[colindx] = ch;
3108 cmd2 =
"m" + (handle.grx[i]-currx[colindx]) +
"," + (handle.gry[j+1] - curry[colindx]);
3109 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
3110 cell_w[colindx] = Math.max(cell_w[colindx], cw);
3111 cell_h[colindx] = Math.max(cell_h[colindx], ch);
3114 currx[colindx] = handle.grx[i];
3115 curry[colindx] = handle.gry[j+1];
3117 colPaths[colindx] +=
"v"+ch+
"h"+cw+
"v-"+ch+
"z";
3121 var layer = this.svg_frame().select(
'.main_layer'),
3122 defs = layer.select(
"defs");
3123 if (defs.empty() && (colPaths.length>0))
3124 defs = layer.insert(
"svg:defs",
":first-child");
3126 this.createAttMarker({ attr: histo });
3128 for (colindx=0;colindx<colPaths.length;++colindx)
3129 if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) {
3130 var pattern_class =
"scatter_" + colindx,
3131 pattern = defs.select(
'.' + pattern_class);
3132 if (pattern.empty())
3133 pattern = defs.append(
'svg:pattern')
3134 .attr(
"class", pattern_class)
3135 .attr(
"id",
"jsroot_scatter_pattern_" + JSROOT.id_counter++)
3136 .attr(
"patternUnits",
"userSpaceOnUse");
3138 pattern.selectAll(
"*").remove();
3140 var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]);
3141 if (npix<1) npix = 1;
3143 var arrx =
new Float32Array(npix), arry =
new Float32Array(npix);
3146 arrx[0] = arry[0] = 0.5;
3148 for (var n=0;n<npix;++n) {
3149 arrx[n] = JSROOT.random();
3150 arry[n] = JSROOT.random();
3156 this.markeratt.reset_pos();
3160 for (var n=0;n<npix;++n)
3161 path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]);
3163 pattern.attr(
"width", cell_w[colindx])
3164 .attr(
"height", cell_h[colindx])
3167 .call(this.markeratt.func);
3171 .attr(
"scatter-index", colindx)
3172 .attr(
"fill",
'url(#' + pattern.attr(
"id") +
')')
3173 .attr(
"d", colPaths[colindx]);
3179 TH2Painter.prototype.DrawBins =
function() {
3181 if (!this.draw_content)
3182 return this.RemoveDrawG();
3184 this.CheckHistDrawAttributes();
3188 var w = this.frame_width(),
3189 h = this.frame_height(),
3194 if (this.IsTH2Poly()) {
3195 handle = this.DrawPolyBinsColor(w, h);
3197 if (this.options.Scat)
3198 handle = this.DrawBinsScatter(w, h);
3199 else if (this.options.Color)
3200 handle = this.DrawBinsColor(w, h);
3201 else if (this.options.Box)
3202 handle = this.DrawBinsBox(w, h);
3203 else if (this.options.Arrow)
3204 handle = this.DrawBinsArrow(w, h);
3205 else if (this.options.Contour > 0)
3206 handle = this.DrawBinsContour(w, h);
3207 else if (this.options.Candle)
3208 handle = this.DrawCandle(w, h);
3210 if (this.options.Text)
3211 handle = this.DrawBinsText(w, h, handle);
3214 handle = this.DrawBinsScatter(w, h);
3217 this.tt_handle = handle;
3220 TH2Painter.prototype.GetBinTips =
function (i, j) {
3221 var lines = [], pmain = this.frame_painter(),
3222 xaxis = this.GetAxis(
"y"), yaxis = this.GetAxis(
"y"),
3223 histo = this.GetHisto(),
3224 binz = histo.getBinContent(i+1,j+1);
3226 lines.push(this.GetTipName() ||
"histo<2>");
3228 if (pmain.x_kind ==
'labels')
3229 lines.push(
"x = " + pmain.AxisAsText(
"x", xaxis.GetBinCoord(i)));
3231 lines.push(
"x = [" + pmain.AxisAsText(
"x", xaxis.GetBinCoord(i)) +
", " + pmain.AxisAsText(
"x", xaxis.GetBinCoord(i+1)) +
")");
3233 if (pmain.y_kind ==
'labels')
3234 lines.push(
"y = " + pmain.AxisAsText(
"y", yaxis.GetBinCoord(j)));
3236 lines.push(
"y = [" + pmain.AxisAsText(
"y", yaxis.GetBinCoord(j)) +
", " + pmain.AxisAsText(
"y", yaxis.GetBinCoord(j+1)) +
")");
3238 lines.push(
"bin = " + i +
", " + j);
3240 if (histo.$baseh) binz -= histo.$baseh.getBinContent(i+1,j+1);
3242 if (binz === Math.round(binz))
3243 lines.push(
"entries = " + binz);
3245 lines.push(
"entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat));
3250 TH2Painter.prototype.GetCandleTips =
function(p) {
3251 var lines = [], main = this.frame_painter(), xaxis = this.GetAxis(
"y");
3253 lines.push(this.GetTipName() ||
"histo");
3255 lines.push(
"x = " + main.AxisAsText(
"x", xaxis.GetBinCoord(p.bin)));
3257 lines.push(
'mean y = ' + JSROOT.FFormat(p.meany, JSROOT.gStyle.fStatFormat))
3258 lines.push(
'm25 = ' + JSROOT.FFormat(p.m25y, JSROOT.gStyle.fStatFormat))
3259 lines.push(
'p25 = ' + JSROOT.FFormat(p.p25y, JSROOT.gStyle.fStatFormat))
3264 TH2Painter.prototype.ProvidePolyBinHints =
function(binindx, realx, realy) {
3266 var histo = this.GetHisto(),
3267 bin = histo.fBins.arr[binindx],
3268 pmain = this.frame_painter(),
3269 binname = bin.fPoly.fName,
3270 lines = [], numpoints = 0;
3272 if (binname ===
"Graph") binname =
"";
3273 if (binname.length === 0) binname = bin.fNumber;
3275 if ((realx===undefined) && (realy===undefined)) {
3277 var gr = bin.fPoly, numgraphs = 1;
3278 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
3280 for (var ngr=0;ngr<numgraphs;++ngr) {
3281 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
3283 for (var n=0;n<gr.fNpoints;++n) {
3290 if (numpoints > 1) {
3291 realx = realx / numpoints;
3292 realy = realy / numpoints;
3296 lines.push(this.GetTipName() ||
"histo");
3297 lines.push(
"x = " + pmain.AxisAsText(
"x", realx));
3298 lines.push(
"y = " + pmain.AxisAsText(
"y", realy));
3299 if (numpoints > 0) lines.push(
"npnts = " + numpoints);
3300 lines.push(
"bin = " + binname);
3301 if (bin.fContent === Math.round(bin.fContent))
3302 lines.push(
"content = " + bin.fContent);
3304 lines.push(
"content = " + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fStatFormat));
3308 TH2Painter.prototype.ProcessTooltip =
function(pnt) {
3309 if (!pnt || !this.draw_content || !this.draw_g || !this.tt_handle || this.options.Proj) {
3310 if (this.draw_g !== null)
3311 this.draw_g.select(
".tooltip_bin").remove();
3315 var histo = this.GetHisto(),
3316 h = this.tt_handle, i,
3317 ttrect = this.draw_g.select(
".tooltip_bin");
3322 var pmain = this.frame_painter(),
3323 realx, realy, foundindx = -1;
3325 if (pmain.grx === pmain.x) realx = pmain.x.invert(pnt.x);
3326 if (pmain.gry === pmain.y) realy = pmain.y.invert(pnt.y);
3328 if ((realx!==undefined) && (realy!==undefined)) {
3329 var i, len = histo.fBins.arr.length, bin;
3331 for (i = 0; (i < len) && (foundindx < 0); ++ i) {
3332 bin = histo.fBins.arr[i];
3335 if ((realx < bin.fXmin) || (realx > bin.fXmax) ||
3336 (realy < bin.fYmin) || (realy > bin.fYmax))
continue;
3339 if ((bin.fContent === 0) && !this.options.Zero)
continue;
3341 var gr = bin.fPoly, numgraphs = 1;
3342 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
3344 for (var ngr=0;ngr<numgraphs;++ngr) {
3345 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
3346 if (gr.IsInside(realx,realy)) {
3354 if (foundindx < 0) {
3359 var res = { name:
"histo", title: histo.fTitle ||
"title",
3361 color1: this.lineatt ? this.lineatt.color :
'green',
3362 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
'blue',
3363 exact:
true, menu:
true,
3364 lines: this.ProvidePolyBinHints(foundindx, realx, realy) };
3372 ttrect = this.draw_g.append(
"svg:path")
3373 .attr(
"class",
"tooltip_bin h1bin")
3374 .style(
"pointer-events",
"none");
3376 res.changed = ttrect.property(
"current_bin") !== foundindx;
3379 ttrect.attr(
"d", this.CreatePolyBin(pmain, bin))
3380 .style(
"opacity",
"0.7")
3381 .property(
"current_bin", foundindx);
3385 res.user_info = { obj: histo, name: histo.fName ||
"histo",
3388 grx: pnt.x, gry: pnt.y };
3399 for (i=0;i<h.candle.length;++i) {
3401 if ((p.x1 <= pnt.x) && (pnt.x <= p.x2) && (p.yy1 <= pnt.y) && (pnt.y <= p.yy2))
break;
3404 if (i>=h.candle.length) {
3409 var res = { name: histo.fName ||
"histo", title: histo.fTitle ||
"title",
3411 color1: this.lineatt ? this.lineatt.color :
'green',
3412 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
'blue',
3413 lines: this.GetCandleTips(p), exact:
true, menu:
true };
3421 ttrect = this.draw_g.append(
"svg:rect")
3422 .attr(
"class",
"tooltip_bin h1bin")
3423 .style(
"pointer-events",
"none");
3425 res.changed = ttrect.property(
"current_bin") !== i;
3428 ttrect.attr(
"x", p.x1)
3429 .attr(
"width", p.x2-p.x1)
3431 .attr(
"height", p.yy2- p.yy1)
3432 .style(
"opacity",
"0.7")
3433 .property(
"current_bin", i);
3437 res.user_info = { obj: histo, name: histo.fName ||
"histo",
3438 bin: i+1, cont: p.median, binx: i+1, biny: 1,
3439 grx: pnt.x, gry: pnt.y };
3444 var i, j, binz = 0, colindx = null;
3447 for (i = h.i1; i < h.i2; ++i)
3448 if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1]))
break;
3450 for (j = h.j1; j < h.j2; ++j)
3451 if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j]))
break;
3453 if ((i < h.i2) && (j < h.j2)) {
3454 binz = histo.getBinContent(i+1,j+1);
3455 if (this.is_projection) {
3457 }
else if (h.hide_only_zeros) {
3458 colindx = (binz === 0) && !this._show_empty_bins ? null : 0;
3460 colindx = this.getContourColor(binz,
true);
3461 if ((colindx === null) && (binz === 0) && this._show_empty_bins) colindx = 0;
3465 if (colindx === null) {
3470 var res = { name: histo.fName ||
"histo", title: histo.fTitle ||
"title",
3472 color1: this.lineatt ? this.lineatt.color :
'green',
3473 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
'blue',
3474 lines: this.GetBinTips(i, j), exact:
true, menu:
true };
3476 if (this.options.Color) res.color2 = this.GetPalette().getColor(colindx);
3478 if (pnt.disabled && !
this.is_projection) {
3483 ttrect = this.draw_g.append(
"svg:rect")
3484 .attr(
"class",
"tooltip_bin h1bin")
3485 .style(
"pointer-events",
"none");
3487 var i1 = i, i2 = i+1,
3489 x1 = h.grx[i1], x2 = h.grx[i2],
3490 y1 = h.gry[j2], y2 = h.gry[j1],
3491 binid = i*10000 + j;
3493 if (this.is_projection ==
"X") {
3494 x1 = 0; x2 = this.frame_width();
3495 if (this.projection_width > 1) {
3496 var dd = (this.projection_width-1)/2;
3497 if (j2+dd >= h.j2) { j2 = Math.min(Math.round(j2+dd), h.j2); j1 = Math.max(j2 - this.projection_width, h.j1); }
3498 else { j1 = Math.max(Math.round(j1-dd), h.j1); j2 = Math.min(j1 + this.projection_width, h.j2); }
3500 y1 = h.gry[j2]; y2 = h.gry[j1];
3501 binid = j1*777 + j2*333;
3502 }
else if (this.is_projection ==
"Y") {
3503 y1 = 0; y2 = this.frame_height();
3504 if (this.projection_width > 1) {
3505 var dd = (this.projection_width-1)/2;
3506 if (i2+dd >= h.i2) { i2 = Math.min(Math.round(i2+dd), h.i2); i1 = Math.max(i2 - this.projection_width, h.i1); }
3507 else { i1 = Math.max(Math.round(i1-dd), h.i1); i2 = Math.min(i1 + this.projection_width, h.i2); }
3509 x1 = h.grx[i1], x2 = h.grx[i2],
3510 binid = i1*777 + i2*333;
3513 res.changed = ttrect.property(
"current_bin") !== binid;
3516 ttrect.attr(
"x", x1)
3517 .attr(
"width", x2 - x1)
3519 .attr(
"height", y2 - y1)
3520 .style(
"opacity",
"0.7")
3521 .property(
"current_bin", binid);
3523 if (this.is_projection && res.changed)
3524 this.RedrawProjection(i1, i2, j1, j2);
3528 res.user_info = { obj: histo, name: histo.fName ||
"histo",
3529 bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1,
3530 grx: pnt.x, gry: pnt.y };
3535 TH2Painter.prototype.CanZoomIn =
function(axis,min,max) {
3538 if (axis==
"z")
return true;
3540 var obj = this.GetAxis(axis);
3542 return (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1);
3545 TH2Painter.prototype.Draw2D =
function(call_back, resize) {
3547 this.mode3d =
false;
3548 this.Clear3DScene();
3553 if (this.DrawAxes())
3563 this.AddInteractive();
3565 JSROOT.CallBack(call_back);
3568 TH2Painter.prototype.Draw3D =
function(call_back, resize) {
3570 JSROOT.AssertPrerequisites(
'hist3d',
function() {
3571 this.Draw3D(call_back, resize);
3575 TH2Painter.prototype.CallDrawFunc =
function(callback, resize) {
3577 var main = this.frame_painter();
3579 if (this.options.Mode3D !== main.mode3d) {
3580 this.options.Mode3D = main.mode3d;
3583 var funcname = this.options.Mode3D ?
"Draw3D" :
"Draw2D";
3585 this[funcname](callback, resize);
3588 TH2Painter.prototype.Redraw =
function(resize) {
3589 this.CallDrawFunc(null, resize);
3592 function drawHist2(divid, obj, opt) {
3594 var painter =
new TH2Painter(obj);
3596 painter.PrepareFrame(divid);
3598 painter.options = { Hist:
false, Bar:
false, Error:
false, ErrorKind: -1, errorX: 0, Zero:
false, Mark:
false,
3599 Line:
false, Fill:
false, Lego: 0, Surf: 0,
3600 Text:
true, TextAngle: 0, TextKind:
"",
3601 fBarOffset: 0, fBarWidth: 1000, BaseLine:
false, Mode3D:
false, AutoColor: 0,
3602 Color:
false, Scat:
false, ScatCoef: 1, Candle:
"", Box:
false, BoxStyle: 0, Arrow:
false, Contour: 0, Proj: 0 };
3607 painter.options.Color =
true;
3610 painter.DecodeOptions(opt);
3612 if (painter.IsTH2Poly()) {
3613 if (painter.options.Mode3D) painter.options.Lego = 12;
3614 else if (!painter.options.Color) painter.options.Color =
true;
3617 painter._show_empty_bins =
false;
3619 painter._can_move_colz =
true;
3621 painter.ScanContent();
3625 painter.CallDrawFunc(
function() {
3630 painter.DrawingReady();
3636 JSROOT.v7.THistPainter = THistPainter;
3637 JSROOT.v7.TH1Painter = TH1Painter;
3638 JSROOT.v7.TH2Painter = TH2Painter;
3640 JSROOT.v7.drawHist1 = drawHist1;
3641 JSROOT.v7.drawHist2 = drawHist2;