5 if ( typeof define ===
"function" && define.amd ) {
7 define( [
'JSRootCore',
'd3'], factory );
10 if (typeof JSROOT ==
'undefined')
11 throw new Error(
'JSROOT is not defined',
'JSRootPainter.js');
13 if (typeof d3 !=
'object')
14 throw new Error(
'd3 is not defined',
'JSRootPainter.js');
16 if (typeof JSROOT.Painter ==
'object')
17 throw new Error(
'JSROOT.Painter already defined',
'JSRootPainter.js');
21 } (
function(JSROOT, d3) {
24 if ( typeof define ===
"function" && define.amd )
25 JSROOT.loadScript(
'$$$style/JSRootPainter.css');
28 JSROOT.DrawFuncs = {lst:[], cache:{}};
33 JSROOT.addDrawFunc =
function(_name, _func, _opt) {
34 if ((arguments.length == 1) && (typeof arguments[0] ==
'object')) {
35 JSROOT.DrawFuncs.lst.push(arguments[0]);
38 var handle = { name:_name, func:_func, opt:_opt };
39 JSROOT.DrawFuncs.lst.push(handle);
45 JSROOT.ToolbarIcons = {
46 camera: { path:
'M 152.00,304.00c0.00,57.438, 46.562,104.00, 104.00,104.00s 104.00-46.562, 104.00-104.00s-46.562-104.00-104.00-104.00S 152.00,246.562, 152.00,304.00z M 480.00,128.00L 368.00,128.00 c-8.00-32.00-16.00-64.00-48.00-64.00L 192.00,64.00 c-32.00,0.00-40.00,32.00-48.00,64.00L 32.00,128.00 c-17.60,0.00-32.00,14.40-32.00,32.00l0.00,288.00 c0.00,17.60, 14.40,32.00, 32.00,32.00l 448.00,0.00 c 17.60,0.00, 32.00-14.40, 32.00-32.00L 512.00,160.00 C 512.00,142.40, 497.60,128.00, 480.00,128.00z M 256.00,446.00c-78.425,0.00-142.00-63.574-142.00-142.00c0.00-78.425, 63.575-142.00, 142.00-142.00c 78.426,0.00, 142.00,63.575, 142.00,142.00 C 398.00,382.426, 334.427,446.00, 256.00,446.00z M 480.00,224.00l-64.00,0.00 l0.00-32.00 l 64.00,0.00 L 480.00,224.00 z' },
47 disk: { path:
'M384,0H128H32C14.336,0,0,14.336,0,32v448c0,17.656,14.336,32,32,32h448c17.656,0,32-14.344,32-32V96L416,0H384z M352,160 V32h32v128c0,17.664-14.344,32-32,32H160c-17.664,0-32-14.336-32-32V32h128v128H352z M96,288c0-17.656,14.336-32,32-32h256 c17.656,0,32,14.344,32,32v192H96V288z' },
48 question: { path:
'M256,512c141.375,0,256-114.625,256-256S397.375,0,256,0S0,114.625,0,256S114.625,512,256,512z M256,64 c63.719,0,128,36.484,128,118.016c0,47.453-23.531,84.516-69.891,110.016C300.672,299.422,288,314.047,288,320 c0,17.656-14.344,32-32,32c-17.664,0-32-14.344-32-32c0-40.609,37.25-71.938,59.266-84.031 C315.625,218.109,320,198.656,320,182.016C320,135.008,279.906,128,256,128c-30.812,0-64,20.227-64,64.672 c0,17.664-14.336,32-32,32s-32-14.336-32-32C128,109.086,193.953,64,256,64z M256,449.406c-18.211,0-32.961-14.75-32.961-32.969 c0-18.188,14.75-32.953,32.961-32.953c18.219,0,32.969,14.766,32.969,32.953C288.969,434.656,274.219,449.406,256,449.406z' },
49 undo: { path:
'M450.159,48.042c8.791,9.032,16.983,18.898,24.59,29.604c7.594,10.706,14.146,22.207,19.668,34.489 c5.509,12.296,9.82,25.269,12.92,38.938c3.113,13.669,4.663,27.834,4.663,42.499c0,14.256-1.511,28.863-4.532,43.822 c-3.009,14.952-7.997,30.217-14.953,45.795c-6.955,15.577-16.202,31.52-27.755,47.826s-25.88,32.9-42.942,49.807 c-5.51,5.444-11.787,11.67-18.834,18.651c-7.033,6.98-14.496,14.366-22.39,22.168c-7.88,7.802-15.955,15.825-24.187,24.069 c-8.258,8.231-16.333,16.203-24.252,23.888c-18.3,18.13-37.354,37.016-57.191,56.65l-56.84-57.445 c19.596-19.472,38.54-38.279,56.84-56.41c7.75-7.685,15.772-15.604,24.108-23.757s16.438-16.163,24.33-24.057 c7.894-7.893,15.356-15.33,22.402-22.312c7.034-6.98,13.312-13.193,18.821-18.651c22.351-22.402,39.165-44.648,50.471-66.738 c11.279-22.09,16.932-43.567,16.932-64.446c0-15.785-3.217-31.005-9.638-45.671c-6.422-14.665-16.229-28.504-29.437-41.529 c-3.282-3.282-7.358-6.395-12.217-9.325c-4.871-2.938-10.381-5.503-16.516-7.697c-6.121-2.201-12.815-3.992-20.058-5.373 c-7.242-1.374-14.9-2.064-23.002-2.064c-8.218,0-16.802,0.834-25.788,2.507c-8.961,1.674-18.053,4.429-27.222,8.271 c-9.189,3.842-18.456,8.869-27.808,15.089c-9.358,6.219-18.521,13.819-27.502,22.793l-59.92,60.271l93.797,94.058H0V40.91 l93.27,91.597l60.181-60.532c13.376-15.018,27.222-27.248,41.536-36.697c14.308-9.443,28.608-16.776,42.89-21.992 c14.288-5.223,28.505-8.74,42.623-10.557C294.645,0.905,308.189,0,321.162,0c13.429,0,26.389,1.185,38.84,3.562 c12.478,2.377,24.2,5.718,35.192,10.029c11.006,4.311,21.126,9.404,30.374,15.265C434.79,34.724,442.995,41.119,450.159,48.042z' },
50 arrow_right : { path :
'M30.796,226.318h377.533L294.938,339.682c-11.899,11.906-11.899,31.184,0,43.084c11.887,11.899,31.19,11.893,43.077,0 l165.393-165.386c5.725-5.712,8.924-13.453,8.924-21.539c0-8.092-3.213-15.84-8.924-21.551L338.016,8.925 C332.065,2.975,324.278,0,316.478,0c-7.802,0-15.603,2.968-21.539,8.918c-11.899,11.906-11.899,31.184,0,43.084l113.391,113.384 H30.796c-16.822,0-30.463,13.645-30.463,30.463C0.333,212.674,13.974,226.318,30.796,226.318z' },
51 arrow_up : { path :
'M295.505,629.446V135.957l148.193,148.206c15.555,15.559,40.753,15.559,56.308,0c15.555-15.538,15.546-40.767,0-56.304 L283.83,11.662C276.372,4.204,266.236,0,255.68,0c-10.568,0-20.705,4.204-28.172,11.662L11.333,227.859 c-7.777,7.777-11.666,17.965-11.666,28.158c0,10.192,3.88,20.385,11.657,28.158c15.563,15.555,40.762,15.555,56.317,0 l148.201-148.219v493.489c0,21.993,17.837,39.82,39.82,39.82C277.669,669.267,295.505,651.439,295.505,629.446z' },
52 arrow_diag : { path :
'M279.875,511.994c-1.292,0-2.607-0.102-3.924-0.312c-10.944-1.771-19.333-10.676-20.457-21.71L233.97,278.348 L22.345,256.823c-11.029-1.119-19.928-9.51-21.698-20.461c-1.776-10.944,4.031-21.716,14.145-26.262L477.792,2.149 c9.282-4.163,20.167-2.165,27.355,5.024c7.201,7.189,9.199,18.086,5.024,27.356L302.22,497.527 C298.224,506.426,289.397,511.994,279.875,511.994z M118.277,217.332l140.534,14.294c11.567,1.178,20.718,10.335,21.878,21.896 l14.294,140.519l144.09-320.792L118.277,217.332z' },
53 auto_zoom: { path :
'M505.441,242.47l-78.303-78.291c-9.18-9.177-24.048-9.171-33.216,0c-9.169,9.172-9.169,24.045,0.006,33.217l38.193,38.188 H280.088V80.194l38.188,38.199c4.587,4.584,10.596,6.881,16.605,6.881c6.003,0,12.018-2.297,16.605-6.875 c9.174-9.172,9.174-24.039,0.011-33.217L273.219,6.881C268.803,2.471,262.834,0,256.596,0c-6.229,0-12.202,2.471-16.605,6.881 l-78.296,78.302c-9.178,9.172-9.178,24.045,0,33.217c9.177,9.171,24.051,9.171,33.21,0l38.205-38.205v155.4H80.521l38.2-38.188 c9.177-9.171,9.177-24.039,0.005-33.216c-9.171-9.172-24.039-9.178-33.216,0L7.208,242.464c-4.404,4.403-6.881,10.381-6.881,16.611 c0,6.227,2.477,12.207,6.881,16.61l78.302,78.291c4.587,4.581,10.599,6.875,16.605,6.875c6.006,0,12.023-2.294,16.61-6.881 c9.172-9.174,9.172-24.036-0.005-33.211l-38.205-38.199h152.593v152.063l-38.199-38.211c-9.171-9.18-24.039-9.18-33.216-0.022 c-9.178,9.18-9.178,24.059-0.006,33.222l78.284,78.302c4.41,4.404,10.382,6.881,16.611,6.881c6.233,0,12.208-2.477,16.611-6.881 l78.302-78.296c9.181-9.18,9.181-24.048,0-33.205c-9.174-9.174-24.054-9.174-33.21,0l-38.199,38.188v-152.04h152.051l-38.205,38.199 c-9.18,9.175-9.18,24.037-0.005,33.211c4.587,4.587,10.596,6.881,16.604,6.881c6.01,0,12.024-2.294,16.605-6.875l78.303-78.285 c4.403-4.403,6.887-10.378,6.887-16.611C512.328,252.851,509.845,246.873,505.441,242.47z' },
55 path :
'M28.782,56.902H483.88c15.707,0,28.451-12.74,28.451-28.451C512.331,12.741,499.599,0,483.885,0H28.782 C13.074,0,0.331,12.741,0.331,28.451C0.331,44.162,13.074,56.902,28.782,56.902z' +
56 'M483.885,136.845H28.782c-15.708,0-28.451,12.741-28.451,28.451c0,15.711,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.74,28.451-28.451C512.331,149.586,499.599,136.845,483.885,136.845z' +
57 'M483.885,273.275H28.782c-15.708,0-28.451,12.731-28.451,28.452c0,15.707,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.744,28.451-28.451C512.337,286.007,499.599,273.275,483.885,273.275z' +
58 'M256.065,409.704H30.492c-15.708,0-28.451,12.731-28.451,28.451c0,15.707,12.744,28.451,28.451,28.451h225.585 c15.707,0,28.451-12.744,28.451-28.451C284.516,422.436,271.785,409.704,256.065,409.704z'
62 JSROOT.Toolbar =
function(container, buttons) {
63 if ((container !== undefined) && (typeof container.append ==
'function')) {
64 this.element = container.append(
"div").attr(
'class',
'jsroot');
65 this.addButtons(buttons);
69 JSROOT.Toolbar.prototype.addButtons =
function(buttons) {
72 this.buttonsNames = [];
73 buttons.forEach(
function(buttonGroup) {
74 var group = pthis.element.append(
'div').attr(
'class',
'toolbar-group');
76 buttonGroup.forEach(
function(buttonConfig) {
77 var buttonName = buttonConfig.name;
79 throw new Error(
'must provide button \'name\' in button config');
81 if (pthis.buttonsNames.indexOf(buttonName) !== -1) {
82 throw new Error(
'button name \'' + buttonName +
'\' is taken
');
84 pthis.buttonsNames.push(buttonName);
86 pthis.createButton(group, buttonConfig);
92 JSROOT.Toolbar.prototype.createButton = function(group, config) {
94 var title = config.title;
95 if (title === undefined) title = config.name;
97 if (typeof config.click !== 'function')
98 throw new Error('must provide button \
'click\' function in button config');
100 var button = group.append(
'a')
101 .attr(
'class',
'toolbar-btn')
102 .attr(
'rel',
'tooltip')
103 .attr(
'data-title', title)
104 .on(
'click', config.click);
106 this.createIcon(button, config.icon || JSROOT.ToolbarIcons.question);
109 JSROOT.Toolbar.prototype.createIcon =
function(button, thisIcon) {
110 var size = thisIcon.size || 512;
111 var scale = thisIcon.scale || 1;
113 var svg = button.append(
"svg:svg")
114 .attr(
'height',
'1em')
115 .attr(
'width',
'1em')
116 .attr(
'viewBox', [0, 0, size, size].join(
' '))
118 if (
'recs' in thisIcon) {
120 for (var n=0;n<thisIcon.recs.length;++n) {
121 JSROOT.extend(rec, thisIcon.recs[n]);
122 svg.append(
'rect').attr(
"x", rec.x).attr(
"y", rec.y)
123 .attr(
"width", rec.w).attr(
"height", rec.h)
124 .attr(
"fill", rec.f);
127 var elem = svg.append(
'svg:path').attr(
'd',thisIcon.path);
129 elem.attr(
'transform',
'scale(' + scale +
' ' + scale +
')');
133 JSROOT.Toolbar.prototype.removeAllButtons =
function() {
134 this.element.remove();
142 JSROOT.Painter.createMenu =
function(maincallback, menuname) {
144 document.body.style.cursor =
'wait';
145 JSROOT.AssertPrerequisites(
'jq2d',
function() {
146 document.body.style.cursor =
'auto';
147 JSROOT.Painter.createMenu(maincallback, menuname);
151 JSROOT.Painter.closeMenu =
function(menuname) {
152 if (!menuname) menuname =
'root_ctx_menu';
153 var x = document.getElementById(menuname);
154 if (x) x.parentNode.removeChild(x);
157 JSROOT.Painter.readStyleFromURL =
function(url) {
158 var optimize = JSROOT.GetUrlOption(
"optimize", url);
159 if (optimize==
"") JSROOT.gStyle.OptimizeDraw = 2;
else
160 if (optimize!==null) {
161 JSROOT.gStyle.OptimizeDraw = parseInt(optimize);
162 if (isNaN(JSROOT.gStyle.OptimizeDraw)) JSROOT.gStyle.OptimizeDraw = 2;
165 var inter = JSROOT.GetUrlOption(
"interactive", url);
166 if ((inter==
"") || (inter==
"1")) inter =
"11111";
else
167 if (inter==
"0") inter =
"00000";
168 if ((inter!==null) && (inter.length==5)) {
169 JSROOT.gStyle.Tooltip = parseInt(inter.charAt(0));
170 JSROOT.gStyle.ContextMenu = (inter.charAt(1) !=
'0');
171 JSROOT.gStyle.Zooming = (inter.charAt(2) !=
'0');
172 JSROOT.gStyle.MoveResize = (inter.charAt(3) !=
'0');
173 JSROOT.gStyle.DragAndDrop = (inter.charAt(4) !=
'0');
176 var tt = JSROOT.GetUrlOption(
"tooltip", url);
177 if (tt !== null) JSROOT.gStyle.Tooltip = parseInt(tt);
179 var mathjax = JSROOT.GetUrlOption(
"mathjax", url);
180 if ((mathjax!==null) && (mathjax!=
"0")) JSROOT.gStyle.MathJax = 1;
182 if (JSROOT.GetUrlOption(
"nomenu", url)!=null) JSROOT.gStyle.ContextMenu =
false;
183 if (JSROOT.GetUrlOption(
"noprogress", url)!=null) JSROOT.gStyle.ProgressBox =
false;
184 if (JSROOT.GetUrlOption(
"notouch", url)!=null) JSROOT.touches =
false;
186 JSROOT.gStyle.OptStat = JSROOT.GetUrlOption(
"optstat", url, JSROOT.gStyle.OptStat);
187 JSROOT.gStyle.OptFit = JSROOT.GetUrlOption(
"optfit", url, JSROOT.gStyle.OptFit);
188 JSROOT.gStyle.StatFormat = JSROOT.GetUrlOption(
"statfmt", url, JSROOT.gStyle.StatFormat);
189 JSROOT.gStyle.FitFormat = JSROOT.GetUrlOption(
"fitfmt", url, JSROOT.gStyle.FitFormat);
191 var toolbar = JSROOT.GetUrlOption(
"toolbar", url);
192 if (toolbar !== null)
193 JSROOT.gStyle.ToolBar = (toolbar !==
"0") && (toolbar !==
"false");
195 var palette = JSROOT.GetUrlOption(
"palette", url);
196 if (palette!==null) {
197 palette = parseInt(palette);
198 if (!isNaN(palette) && (palette>0) && (palette<113)) JSROOT.gStyle.Palette = palette;
201 var embed3d = JSROOT.GetUrlOption(
"embed3d", url);
202 if (embed3d !== null) JSROOT.gStyle.Embed3DinSVG = parseInt(embed3d);
204 var webgl = JSROOT.GetUrlOption(
"webgl", url);
205 if ((webgl ===
"0") || (webgl ===
"false")) JSROOT.gStyle.NoWebGL =
false;
else
206 if (webgl ===
"ie") JSROOT.gStyle.NoWebGL = !JSROOT.browser.isIE;
209 JSROOT.Painter.Coord = {
218 JSROOT.Painter.root_colors =
function() {
219 var colorMap = [
'white',
'black',
'red',
'green',
'blue',
'yellow',
'magenta',
'cyan',
'rgb(89,212,84)',
'rgb(89,84,217)',
'white'];
220 colorMap[110] =
'white';
223 {col:11,str:
'c1b7ad4d4d4d6666668080809a9a9ab3b3b3cdcdcde6e6e6f3f3f3cdc8accdc8acc3c0a9bbb6a4b3a697b8a49cae9a8d9c8f83886657b1cfc885c3a48aa9a1839f8daebdc87b8f9a768a926983976e7b857d9ad280809caca6c0d4cf88dfbb88bd9f83c89a7dc08378cf5f61ac8f94a6787b946971d45a549300ff7b00ff6300ff4b00ff3300ff1b00ff0300ff0014ff002cff0044ff005cff0074ff008cff00a4ff00bcff00d4ff00ecff00fffd00ffe500ffcd00ffb500ff9d00ff8500ff6d00ff5500ff3d00ff2600ff0e0aff0022ff003aff0052ff006aff0082ff009aff00b1ff00c9ff00e1ff00f9ff00ffef00ffd700ffbf00ffa700ff8f00ff7700ff6000ff4800ff3000ff1800ff0000'},
224 {col:201,str:
'5c5c5c7b7b7bb8b8b8d7d7d78a0f0fb81414ec4848f176760f8a0f14b81448ec4876f1760f0f8a1414b84848ec7676f18a8a0fb8b814ecec48f1f1768a0f8ab814b8ec48ecf176f10f8a8a14b8b848ecec76f1f1'},
225 {col:390,str:
'ffffcdffff9acdcd9affff66cdcd669a9a66ffff33cdcd339a9a33666633ffff00cdcd009a9a00666600333300'},
226 {col:406,str:
'cdffcd9aff9a9acd9a66ff6666cd66669a6633ff3333cd33339a3333663300ff0000cd00009a00006600003300'},
227 {col:422,str:
'cdffff9affff9acdcd66ffff66cdcd669a9a33ffff33cdcd339a9a33666600ffff00cdcd009a9a006666003333'},
228 {col:590,str:
'cdcdff9a9aff9a9acd6666ff6666cd66669a3333ff3333cd33339a3333660000ff0000cd00009a000066000033'},
229 {col:606,str:
'ffcdffff9affcd9acdff66ffcd66cd9a669aff33ffcd33cd9a339a663366ff00ffcd00cd9a009a660066330033'},
230 {col:622,str:
'ffcdcdff9a9acd9a9aff6666cd66669a6666ff3333cd33339a3333663333ff0000cd00009a0000660000330000'},
231 {col:791,str:
'ffcd9acd9a669a66339a6600cd9a33ffcd66ff9a00ffcd33cd9a00ffcd00ff9a33cd66006633009a3300cd6633ff9a66ff6600ff6633cd3300ff33009aff3366cd00336600339a0066cd339aff6666ff0066ff3333cd0033ff00cdff9a9acd66669a33669a009acd33cdff669aff00cdff339acd00cdff009affcd66cd9a339a66009a6633cd9a66ffcd00ff6633ffcd00cd9a00ffcd33ff9a00cd66006633009a3333cd6666ff9a00ff9a33ff6600cd3300ff339acdff669acd33669a00339a3366cd669aff0066ff3366ff0033cd0033ff339aff0066cd00336600669a339acd66cdff009aff33cdff009acd00cdffcd9aff9a66cd66339a66009a9a33cdcd66ff9a00ffcd33ff9a00cdcd00ff9a33ff6600cd33006633009a6633cd9a66ff6600ff6633ff3300cd3300ffff339acd00666600339a0033cd3366ff669aff0066ff3366cd0033ff0033ff9acdcd669a9a33669a0066cd339aff66cdff009acd009aff33cdff009a'},
232 {col:920,str:
'cdcdcd9a9a9a666666333333'}];
234 for (var indx = 0; indx < moreCol.length; ++indx) {
235 var entry = moreCol[indx];
236 for (var n=0; n < entry.str.length; n+=6) {
237 var num = parseInt(entry.col) + parseInt(n/6);
238 colorMap[num] =
'rgb(' + parseInt(
"0x" +entry.str.slice(n,n+2)) +
"," + parseInt(
"0x" + entry.str.slice(n+2,n+4)) +
"," + parseInt(
"0x" + entry.str.slice(n+4,n+6)) +
")";
245 JSROOT.Painter.MakeColorRGB =
function(col) {
246 if ((col==null) || (col._typename !=
'TColor'))
return null;
247 var rgb = Math.round(col.fRed*255) +
"," + Math.round(col.fGreen*255) +
"," + Math.round(col.fBlue*255);
248 if ((col.fAlpha === undefined) || (col.fAlpha == 1.))
249 rgb =
"rgb(" + rgb +
")";
251 rgb =
"rgba(" + rgb +
"," + col.fAlpha.toFixed(3) +
")";
254 case 'rgb(255,255,255)' : rgb =
'white';
break;
255 case 'rgb(0,0,0)' : rgb =
'black';
break;
256 case 'rgb(255,0,0)' : rgb =
'red';
break;
257 case 'rgb(0,255,0)' : rgb =
'green';
break;
258 case 'rgb(0,0,255)' : rgb =
'blue';
break;
259 case 'rgb(255,255,0)' : rgb =
'yellow';
break;
260 case 'rgb(255,0,255)' : rgb =
'magenta';
break;
261 case 'rgb(0,255,255)' : rgb =
'cyan';
break;
266 JSROOT.Painter.adoptRootColors =
function(objarr) {
267 if (!objarr || !objarr.arr)
return;
269 for (var n = 0; n < objarr.arr.length; ++n) {
270 var col = objarr.arr[n];
271 if ((col==null) || (col._typename !=
'TColor'))
continue;
273 var num = col.fNumber;
274 if ((num<0) || (num>4096))
continue;
276 var rgb = JSROOT.Painter.MakeColorRGB(col);
277 if (rgb == null)
continue;
279 if (JSROOT.Painter.root_colors[num] != rgb)
280 JSROOT.Painter.root_colors[num] = rgb;
284 JSROOT.Painter.root_line_styles =
new Array(
"",
"",
"3,3",
"1,2",
285 "3,4,1,4",
"5,3,1,3",
"5,3,1,3,1,3,1,3",
"5,5",
286 "5,3,1,3,1,3",
"20,5",
"20,10,1,10",
"1,3");
289 JSROOT.Painter.root_markers =
new Array(
291 9, 100, 100, 100, 100,
292 100, 100, 100, 100, 100,
293 100, 100, 100, 100, 100,
294 100, 103, 105, 104, 0,
299 JSROOT.Painter.createAttMarker =
function(attmarker, style) {
301 var marker_color = JSROOT.Painter.root_colors[attmarker.fMarkerColor];
303 if ((style===null) || (style===undefined)) style = attmarker.fMarkerStyle;
305 var res = { x0: 0, y0: 0, color: marker_color, style: style, size: 8, stroke:
true, fill:
true, marker:
"", ndig: 0, used:
true };
307 res.Change =
function(color, style, size) {
309 if (color!==undefined) this.color = color;
310 if (style!==undefined) this.style = style;
311 if (size!==undefined) this.size = size;
else size = this.size;
313 this.x0 = this.y0 = 0;
315 this.reset_pos =
function() {
316 this.lastx = this.lasty = null;
319 if ((this.style === 1) || (this.style === 777)) {
325 this.create =
function(x,y) {
326 var xx = Math.round(x), yy = Math.round(y), m1 =
"M"+xx+
","+yy+
"h1";
327 var m2 = (this.lastx===null) ? m1 : (
"m"+(xx-this.lastx)+
","+(yy-this.lasty)+
"h1");
328 this.lastx = xx+1; this.lasty = yy;
329 return (m2.length < m1.length) ? m2 : m1;
336 var marker_kind = ((this.style>0) && (this.style<JSROOT.Painter.root_markers.length)) ? JSROOT.Painter.root_markers[
this.style] : 100;
337 var shape = marker_kind % 100;
339 this.fill = (marker_kind>=100);
342 case 1: size = this.size = 1;
break;
343 case 6: size = this.size = 2;
break;
344 case 7: size = this.size = 3;
break;
345 default: this.size = size; size*=8;
348 this.ndig = (size>7) ? 0 : ((size>2) ? 1 : 2);
349 if (shape == 6) this.ndig++;
350 var half = (size/2).toFixed(this.ndig), full = size.toFixed(this.ndig);
355 this.marker =
"a"+half+
","+half+
" 0 1,0 "+full+
",0a"+half+
","+half+
" 0 1,0 -"+full+
",0z";
358 var d = (size/3).toFixed(res.ndig);
359 this.x0 = this.y0 = size/6;
360 this.marker =
"h"+d+
"v-"+d+
"h-"+d+
"v-"+d+
"h-"+d+
"v"+d+
"h-"+d+
"v"+d+
"h"+d+
"v"+d+
"h"+d+
"z";
364 this.marker =
"l"+half+
",-"+half+
"l"+half+
","+half+
"l-"+half+
","+half +
"z";
367 this.x0 = this.y0 = -size/2;
368 this.marker =
"v"+full+
"h"+full+
"v-"+full+
"z";
372 this.marker =
"l-"+ half+
",-"+full+
"h"+full+
"z";
376 this.marker =
"l-"+ half+
","+full+
"h"+full+
"z";
380 this.marker =
"l" + (size/3).toFixed(res.ndig)+
","+full +
381 "l-"+ (5/6*size).toFixed(res.ndig) +
",-" + (5/8*size).toFixed(res.ndig) +
383 "l-" + (5/6*size).toFixed(res.ndig) +
"," + (5/8*size).toFixed(res.ndig) +
"z";
386 this.x0 = this.y0 = -size/2;
387 this.marker =
"l"+full+
","+full +
388 "m0,-"+full+
"l-"+full+
","+full+
389 "m0,-"+half+
"h"+full+
"m-"+half+
",-"+half+
"v"+full;
393 this.marker =
"v"+full+
"m-"+half+
",-"+half+
"h"+full;
396 this.x0 = this.y0 = -size/2;
397 this.marker =
"l"+full+
","+full +
"m0,-"+full+
"l-"+full+
","+full;
401 this.marker =
"l"+half+
",-"+half+
"l"+half+
","+half+
"l-"+half+
","+half +
"z";
405 this.create =
function(x,y) {
406 return "M" + (x+this.x0).toFixed(this.ndig)+
"," + (y+this.y0).toFixed(this.ndig) + this.marker;
412 res.Apply =
function(selection) {
413 selection.style(
'stroke', this.stroke ? this.color :
"none");
414 selection.style(
'fill', this.fill ? this.color :
"none");
417 res.func = res.Apply.bind(res);
419 res.Change(marker_color, style, attmarker.fMarkerSize);
424 JSROOT.Painter.createAttLine =
function(attline, borderw, can_excl) {
426 var color = 0, _width = 0, style = 0;
427 if (typeof attline ==
'string') {
428 if (attline==
'black') { color = 1; _width = 1; }
else
429 if (attline==
'none') { _width = 0; }
431 if (typeof attline ==
'object') {
432 if (
'fLineColor' in attline) color = attline.fLineColor;
433 if (
'fLineWidth' in attline) _width = attline.fLineWidth;
434 if (
'fLineStyle' in attline) style = attline.fLineStyle;
436 if ((attline!==undefined) && !isNaN(attline)) {
440 if (borderw!==undefined) _width = borderw;
444 color: JSROOT.Painter.root_colors[color],
446 dash: JSROOT.Painter.root_line_styles[style]
449 if ((_width==0) || (color==0)) line.color =
'none';
454 if (Math.abs(line.width) > 99) {
456 line.excl_side = (line.width < 0) ? -1 : 1;
457 line.excl_width = Math.floor(line.width / 100) * 5;
458 line.width = line.width % 100;
463 if ((line.color === undefined) && (color>0))
464 line.color =
'lightgrey';
466 line.Apply =
function(selection) {
468 if (this.color==
'none') {
469 selection.style(
'stroke', null);
470 selection.style(
'stroke-width', null);
471 selection.style(
'stroke-dasharray', null);
473 selection.style(
'stroke', this.color);
474 selection.style(
'stroke-width', this.width);
475 if (this.dash && (this.dash.length>0))
476 selection.style(
'stroke-dasharray', this.dash);
479 line.func = line.Apply.bind(line);
484 JSROOT.Painter.clearCuts =
function(chopt) {
486 var left = chopt.indexOf(
'[');
487 var right = chopt.indexOf(
']');
488 if ((left>=0) && (right>=0) && (left<right))
489 for (var i = left; i <= right; ++i) chopt[i] =
' ';
493 JSROOT.Painter.root_fonts =
new Array(
'Arial',
'Times New Roman',
494 'bTimes New Roman',
'biTimes New Roman',
'Arial',
495 'oArial',
'bArial',
'boArial',
'Courier New',
496 'oCourier New',
'bCourier New',
'boCourier New',
497 'Symbol',
'Times New Roman',
'Wingdings',
'Symbol',
'Verdana');
499 JSROOT.Painter.getFontDetails =
function(fontIndex, size) {
501 var fontName = JSROOT.Painter.root_fonts[Math.floor(fontIndex / 10)];
503 var res = { name:
"Arial", size: 11, weight: null, style: null };
505 if (size != undefined) res.size = Math.round(size);
507 if (typeof fontName !=
'string') fontName =
"";
509 while (fontName.length > 0) {
510 if (fontName.charAt(0)===
'b') res.weight =
"bold";
else
511 if (fontName.charAt(0)===
'i') res.style =
"italic";
else
512 if (fontName.charAt(0)===
'o') res.style =
"oblique";
else break;
513 fontName = fontName.substr(1);
516 if (fontName ==
'Symbol') {
523 res.SetFont =
function(selection) {
524 selection.attr(
"font-family", this.name)
525 .attr(
"font-size", this.size)
526 .attr(
"xml:space",
"preserve");
527 if (this.weight!=null)
528 selection.attr(
"font-weight", this.weight);
529 if (this.style!=null)
530 selection.attr(
"font-style", this.style);
533 res.asStyle =
function(sz) {
534 return ((sz!=null) ? sz : this.size) +
"px " + this.name;
537 res.stringWidth =
function(svg, line) {
539 var text = svg.append(
"svg:text")
540 .attr(
"xml:space",
"preserve")
544 var w = text.node().getBBox().width;
549 res.func = res.SetFont.bind(res);
554 JSROOT.Painter.chooseTimeFormat =
function(awidth, ticks) {
555 if (awidth < .5)
return ticks ?
"%S.%L" :
"%M:%S.%L";
556 if (awidth < 30)
return ticks ?
"%Mm%S" :
"%H:%M:%S";
557 awidth /= 60;
if (awidth < 30)
return ticks ?
"%Hh%M" :
"%d/%m %H:%M";
558 awidth /= 60;
if (awidth < 12)
return ticks ?
"%d-%Hh" :
"%d/%m/%y %Hh";
559 awidth /= 24;
if (awidth < 15.218425)
return ticks ?
"%d/%m" :
"%d/%m/%y";
560 awidth /= 30.43685;
if (awidth < 6)
return "%d/%m/%y";
561 awidth /= 12;
if (awidth < 2)
return ticks ?
"%m/%y" :
"%d/%m/%y";
565 JSROOT.Painter.getTimeFormat =
function(axis) {
566 var idF = axis.fTimeFormat.indexOf(
'%F');
567 if (idF >= 0)
return axis.fTimeFormat.substr(0, idF);
568 return axis.fTimeFormat;
571 JSROOT.Painter.getTimeOffset =
function(axis) {
572 var idF = axis.fTimeFormat.indexOf(
'%F');
573 if (idF < 0)
return JSROOT.gStyle.TimeOffset;
574 var sof = axis.fTimeFormat.substr(idF + 2);
575 if (sof ==
'1995-01-01 00:00:00s0')
return 788918400000;
577 if ((sof ==
"0") || (sof ==
""))
return 0;
580 var dt =
new Date(0);
581 var pos = sof.indexOf(
"-"); dt.setFullYear(sof.substr(0,pos)); sof = sof.substr(pos+1);
582 pos = sof.indexOf(
"-"); dt.setMonth(parseInt(sof.substr(0,pos))-1); sof = sof.substr(pos+1);
583 pos = sof.indexOf(
" "); dt.setDate(sof.substr(0,pos)); sof = sof.substr(pos+1);
584 pos = sof.indexOf(
":"); dt.setHours(sof.substr(0,pos)); sof = sof.substr(pos+1);
585 pos = sof.indexOf(
":"); dt.setMinutes(sof.substr(0,pos)); sof = sof.substr(pos+1);
586 pos = sof.indexOf(
"s"); dt.setSeconds(sof.substr(0,pos));
587 if (pos>0) { sof = sof.substr(pos+1); dt.setMilliseconds(sof); }
591 JSROOT.Painter.formatExp =
function(label) {
593 if (parseFloat(str) == 1.0)
return '1';
594 if (parseFloat(str) == 10.0)
return '10';
595 var str = str.replace(
'e+',
'x10@');
596 var str = str.replace(
'e-',
'x10@-');
597 var _val = str.substring(0, str.indexOf(
'@'));
598 var _exp = str.substr(str.indexOf(
'@'));
599 _val = _val.replace(
'@',
'');
600 _exp = _exp.replace(
'@',
'');
601 var u, size = _exp.length;
602 for (var j = 0; j < size; ++j) {
603 var u, c = _exp.charAt(j);
604 if (c ==
'+') u =
'\u207A';
else
605 if (c ==
'-') u =
'\u207B';
else {
607 if (e == 1) u = String.fromCharCode(0xB9);
else
608 if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
else
609 u = String.fromCharCode(0x2070 + e);
611 _exp = _exp.replace(c, u);
613 _val = _val.replace(
'1x',
'');
617 JSROOT.Painter.translateExp =
function(str) {
618 var lstr = str.match(/\^{[0-9]*}/gi);
621 for (var i = 0; i < lstr.length; ++i) {
622 symbol = lstr[i].replace(
' ',
'');
623 symbol = symbol.replace(
'^{',
'');
624 symbol = symbol.replace(
'}',
'');
625 var size = symbol.length;
626 for (var j = 0; j < size; ++j) {
627 var c = symbol.charAt(j);
628 var u, e = parseInt(c);
629 if (e == 1) u = String.fromCharCode(0xB9);
630 else if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
631 else u = String.fromCharCode(0x2070 + e);
632 symbol = symbol.replace(c, u);
634 str = str.replace(lstr[i], symbol);
640 JSROOT.Painter.symbols_map = {
646 '#varepsilon' :
'\u03B5',
651 '#varphi' :
'\u03C6',
653 '#lambda' :
'\u03BB',
656 '#omicron' :
'\u03BF',
662 '#upsilon' :
'\u03C5',
663 '#varomega' :
'\u03D6',
672 '#Epsilon' :
'\u0395',
677 '#vartheta' :
'\u03D1',
679 '#Lambda' :
'\u039B',
682 '#Omicron' :
'\u039F',
688 '#Upsilon' :
'\u03A5',
689 '#varsigma' :
'\u03C2',
694 '#varUpsilon' :
'\u03D2',
695 '#epsilon' :
'\u03B5',
706 '#diamond' :
'\u2666',
709 '#leftrightarrow' :
'\u2194',
710 '#leftarrow' :
'\u2190',
711 '#uparrow' :
'\u2191',
712 '#rightarrow' :
'\u2192',
713 '#downarrow' :
'\u2193',
716 '#doublequote' :
'\u2033',
719 '#propto' :
'\u221D',
720 '#partial' :
'\u2202',
721 '#bullet' :
'\u2022',
725 '#approx' :
'\u2248',
729 '#downleftarrow' :
'\u21B5',
731 '#Jgothic' :
'\u2111',
732 '#Rgothic' :
'\u211C',
734 '#otimes' :
'\u2297',
736 '#oslash' :
'\u2205',
739 '#supseteq' :
'\u2287',
740 '#supset' :
'\u2283',
741 '#notsubset' :
'\u2284',
742 '#subseteq' :
'\u2286',
743 '#subset' :
'\u2282',
750 '#ocopyright' :
'\xA9',
751 '#trademark' :
'\u2122',
754 '#upoint' :
'\u22C5',
758 '#Leftrightarrow' :
'\u21D4',
759 '#Leftarrow' :
'\u21D0',
760 '#Uparrow' :
'\u21D1',
761 '#Rightarrow' :
'\u21D2',
762 '#Downarrow' :
'\u21D3',
765 '#copyright' :
'\xA9',
772 '#bottombar' :
'\u230A',
779 '#forall' :
'\u2200',
780 '#exists' :
'\u2203',
801 JSROOT.Painter.translateLaTeX =
function(string) {
803 str = this.translateExp(str);
804 while (str.indexOf(
'^{o}') != -1)
805 str = str.replace(
'^{o}',
'\xBA');
806 var lstr = str.match(/\#sqrt{(.*?)}/gi);
808 for (var i = 0; i < lstr.length; ++i) {
809 var symbol = lstr[i].replace(
' ',
'');
810 symbol = symbol.replace(
'#sqrt{',
'#sqrt');
811 symbol = symbol.replace(
'}',
'');
812 str = str.replace(lstr[i], symbol);
814 lstr = str.match(/\_{(.*?)}/gi);
816 for (var i = 0; i < lstr.length; ++i) {
817 var symbol = lstr[i].replace(
' ',
'');
818 symbol = symbol.replace(
'_{',
'');
819 symbol = symbol.replace(
'}',
'');
820 str = str.replace(lstr[i], symbol);
822 lstr = str.match(/\^{(.*?)}/gi);
824 for (i = 0; i < lstr.length; ++i) {
825 var symbol = lstr[i].replace(
' ',
'');
826 symbol = symbol.replace(
'^{',
'');
827 symbol = symbol.replace(
'}',
'');
828 str = str.replace(lstr[i], symbol);
830 while (str.indexOf(
'#/') != -1)
831 str = str.replace(
'#/', JSROOT.Painter.symbols_map[
'#/']);
832 for ( var x in JSROOT.Painter.symbols_map) {
833 while (str.indexOf(x) != -1)
834 str = str.replace(x, JSROOT.Painter.symbols_map[x]);
838 if ((str.indexOf(
"#splitline{")==0) && (str.charAt(str.length-1)==
"}")) {
839 var pos = str.indexOf(
"}{");
840 if ((pos>0) && (pos == str.lastIndexOf(
"}{"))) {
841 str = str.replace(
"}{",
"\n");
842 str = str.slice(11, str.length-1);
848 JSROOT.Painter.isAnyLatex =
function(str) {
849 return (str.indexOf(
"#")>=0) || (str.indexOf(
"\\")>=0) || (str.indexOf(
"{")>=0);
852 JSROOT.Painter.translateMath =
function(str, kind, color) {
856 str = str.replace(/#LT/g,
"\\langle");
857 str = str.replace(/#GT/g,
"\\rangle");
858 str = str.replace(/#club/g,
"\\clubsuit");
859 str = str.replace(/#spade/g,
"\\spadesuit");
860 str = str.replace(/#heart/g,
"\\heartsuit");
861 str = str.replace(/#diamond/g,
"\\diamondsuit");
862 str = str.replace(/#voidn/g,
"\\wp");
863 str = str.replace(/#voidb/g,
"f");
864 str = str.replace(/#copyright/g,
"(c)");
865 str = str.replace(/#ocopyright/g,
"(c)");
866 str = str.replace(/#trademark/g,
"TM");
867 str = str.replace(/#void3/g,
"TM");
868 str = str.replace(/#oright/g,
"R");
869 str = str.replace(/#void1/g,
"R");
870 str = str.replace(/#3dots/g,
"\\ldots");
871 str = str.replace(/#lbar/g,
"\\mid");
872 str = str.replace(/#void8/g,
"\\mid");
873 str = str.replace(/#divide/g,
"\\div");
874 str = str.replace(/#Jgothic/g,
"\\Im");
875 str = str.replace(/#Rgothic/g,
"\\Re");
876 str = str.replace(/#doublequote/g,
"\"");
877 str = str.replace(/#plus/g,
"+");
879 str = str.replace(/#diamond/g,
"\\diamondsuit");
880 str = str.replace(/#voidn/g,
"\\wp");
881 str = str.replace(/#voidb/g,
"f");
882 str = str.replace(/#copyright/g,
"(c)");
883 str = str.replace(/#ocopyright/g,
"(c)");
884 str = str.replace(/#trademark/g,
"TM");
885 str = str.replace(/#void3/g,
"TM");
886 str = str.replace(/#oright/g,
"R");
887 str = str.replace(/#void1/g,
"R");
888 str = str.replace(/#3dots/g,
"\\ldots");
889 str = str.replace(/#lbar/g,
"\\mid");
890 str = str.replace(/#void8/g,
"\\mid");
891 str = str.replace(/#divide/g,
"\\div");
892 str = str.replace(/#Jgothic/g,
"\\Im");
893 str = str.replace(/#Rgothic/g,
"\\Re");
894 str = str.replace(/#doublequote/g,
"\"");
895 str = str.replace(/#plus/g,
"+");
896 str = str.replace(/#minus/g,
"-");
897 str = str.replace(/#\
898 str = str.replace(/#upoint/g,
".");
899 str = str.replace(/#aa/g,
"\\mathring{a}");
900 str = str.replace(/#AA/g,
"\\mathring{A}");
902 str = str.replace(/#omicron/g,
"o");
903 str = str.replace(/#Alpha/g,
"A");
904 str = str.replace(/#Beta/g,
"B");
905 str = str.replace(/#Epsilon/g,
"E");
906 str = str.replace(/#Zeta/g,
"Z");
907 str = str.replace(/#Eta/g,
"H");
908 str = str.replace(/#Iota/g,
"I");
909 str = str.replace(/#Kappa/g,
"K");
910 str = str.replace(/#Mu/g,
"M");
911 str = str.replace(/#Nu/g,
"N");
912 str = str.replace(/#Omicron/g,
"O");
913 str = str.replace(/#Rho/g,
"P");
914 str = str.replace(/#Tau/g,
"T");
915 str = str.replace(/#Chi/g,
"X");
916 str = str.replace(/#varomega/g,
"\\varpi");
918 str = str.replace(/#corner/g,
"?");
919 str = str.replace(/#ltbar/g,
"?");
920 str = str.replace(/#bottombar/g,
"?");
921 str = str.replace(/#notsubset/g,
"?");
922 str = str.replace(/#arcbottom/g,
"?");
923 str = str.replace(/#cbar/g,
"?");
924 str = str.replace(/#arctop/g,
"?");
925 str = str.replace(/#topbar/g,
"?");
926 str = str.replace(/#arcbar/g,
"?");
927 str = str.replace(/#downleftarrow/g,
"?");
928 str = str.replace(/#splitline/g,
"\\genfrac{}{}{0pt}{}");
929 str = str.replace(/#it/g,
"\\textit");
930 str = str.replace(/#bf/g,
"\\textbf");
932 str = str.replace(/#frac/g,
"\\frac");
935 str = str.replace(/#left{/g,
"\\lbrace");
936 str = str.replace(/#right}/g,
"\\rbrace");
937 str = str.replace(/#left\[/g,
"\\lbrack");
938 str = str.replace(/#right\]/g,
"\\rbrack");
942 str = str.replace(/#\[\]{/g,
"\\lbrack");
943 str = str.replace(/ } /g,
"\\rbrack");
946 str = str.replace(/#\[/g,
"\\lbrack");
947 str = str.replace(/#\]/g,
"\\rbrack");
948 str = str.replace(/#{/g,
"\\lbrace");
949 str = str.replace(/#}/g,
"\\rbrace");
950 str = str.replace(/ /g,
"\\;");
952 for (var x in JSROOT.Painter.symbols_map) {
953 var y =
"\\" + x.substr(1);
954 str = str.replace(
new RegExp(x,
'g'), y);
957 str = str.replace(/\\\^/g,
"\\hat");
960 if (typeof color !=
'string')
return "\\(" + str +
"\\)";
962 if (color.indexOf(
"rgb(")>=0)
963 color = color.replace(/rgb/g,
"[RGB]")
965 .replace(/\)/g,
'}');
966 return "\\(\\color{" + color +
'}' + str +
"\\)";
971 JSROOT.TBasePainter =
function() {
975 JSROOT.TBasePainter.prototype.Cleanup =
function() {
979 JSROOT.TBasePainter.prototype.DrawingReady =
function() {
981 this[
'_ready_called_'] =
true;
982 if (
'_ready_callback_' in
this) {
983 JSROOT.CallBack(
this[
'_ready_callback_'],
this);
984 delete this[
'_ready_callback_'];
985 this[
'_ready_callback_'] = null;
990 JSROOT.TBasePainter.prototype.WhenReady =
function(callback) {
992 if (
'_ready_called_' in
this)
return JSROOT.CallBack(callback,
this);
993 this[
'_ready_callback_'] = callback;
996 JSROOT.TBasePainter.prototype.GetObject =
function() {
1000 JSROOT.TBasePainter.prototype.MatchObjectType =
function(typ) {
1004 JSROOT.TBasePainter.prototype.UpdateObject =
function(obj) {
1008 JSROOT.TBasePainter.prototype.RedrawPad =
function(resize) {
1011 JSROOT.TBasePainter.prototype.RedrawObject =
function(obj) {
1012 if (this.UpdateObject(obj)) {
1013 var current = document.body.style.cursor;
1014 document.body.style.cursor =
'wait';
1016 document.body.style.cursor = current;
1020 JSROOT.TBasePainter.prototype.CheckResize =
function(arg) {
1024 JSROOT.TBasePainter.prototype.select_main =
function() {
1026 if ((this.divid === null) || (this.divid === undefined))
return d3.select(null);
1027 if ((typeof this.divid ==
"string") &&
1028 (this.divid.charAt(0) !=
"#"))
return d3.select(
"#" + this.divid);
1029 return d3.select(this.divid);
1032 JSROOT.TBasePainter.prototype.main_visible_rect =
function() {
1035 var render_to = this.select_main();
1037 var rect = render_to.node().getBoundingClientRect();
1042 res.width = Math.round(rect.width -
this.GetStyleValue(render_to,
'padding-left') - this.GetStyleValue(render_to,
'padding-right'));
1043 res.height = Math.round(rect.height -
this.GetStyleValue(render_to,
'padding-top') - this.GetStyleValue(render_to,
'padding-bottom'));
1048 JSROOT.TBasePainter.prototype.SetDivId =
function(divid) {
1051 if (arguments.length > 0)
1053 var main = this.select_main();
1054 var chld = main.node() ? main.node().firstChild : null;
1055 if (chld) chld.painter =
this;
1058 JSROOT.TBasePainter.prototype.SetItemName =
function(name, opt) {
1059 if (typeof name ===
'string') this._hitemname = name;
1060 else delete this._hitemname;
1062 if (typeof opt ===
'string') this._hdrawopt = opt;
1065 JSROOT.TBasePainter.prototype.GetItemName =
function() {
1066 return (
'_hitemname' in
this) ? this._hitemname : null;
1069 JSROOT.TBasePainter.prototype.GetItemDrawOpt =
function() {
1070 return (
'_hdrawopt' in
this) ? this._hdrawopt :
"";
1073 JSROOT.TBasePainter.prototype.CanZoomIn =
function(axis,left,right) {
1078 JSROOT.TBasePainter.prototype.GetStyleValue =
function(select, name) {
1079 var value = select.style(name);
1080 if (!value)
return 0;
1081 value = parseFloat(value.replace(
"px",
""));
1082 return isNaN(value) ? 0 : value;
1087 JSROOT.TObjectPainter =
function(obj) {
1088 JSROOT.TBasePainter.call(
this);
1092 this.draw_object = ((obj!==undefined) && (typeof obj ==
'object')) ? obj : null;
1095 JSROOT.TObjectPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
1097 JSROOT.TObjectPainter.prototype.GetObject =
function() {
1098 return this.draw_object;
1101 JSROOT.TObjectPainter.prototype.MatchObjectType =
function(arg) {
1102 if ((arg === undefined) || (arg === null) || (this.draw_object===null))
return false;
1103 if (typeof arg ===
'string')
return this.draw_object._typename === arg;
1104 return (typeof arg ===
'object') && (this.draw_object._typename === arg._typename);
1107 JSROOT.TObjectPainter.prototype.SetItemName =
function(name, opt) {
1108 JSROOT.TBasePainter.prototype.SetItemName.call(
this, name, opt);
1109 if (name==
"")
return;
1110 var can = this.svg_canvas();
1111 if (!can.empty()) can.select(
"title").text(name);
1112 else this.select_main().attr(
"title", name);
1115 JSROOT.TObjectPainter.prototype.UpdateObject =
function(obj) {
1118 if (!this.MatchObjectType(obj))
return false;
1119 JSROOT.extend(this.GetObject(), obj);
1123 JSROOT.TObjectPainter.prototype.GetTipName =
function(append) {
1124 var res = this.GetItemName();
1125 if (res===null) res =
"";
1126 if ((res.length === 0) && (
'fName' in
this.GetObject()))
1127 res = this.GetObject().fName;
1128 if (res.lenght > 20) res = res.substr(0,17)+
"...";
1129 if ((res.length > 0) && (append!==undefined)) res += append;
1133 JSROOT.TObjectPainter.prototype.pad_painter =
function(active_pad) {
1134 var can = active_pad ? this.svg_pad() : this.svg_canvas();
1135 return can.empty() ? null : can.property(
'pad_painter');
1138 JSROOT.TObjectPainter.prototype.CheckResize =
function(arg) {
1140 var pad_painter = this.pad_painter();
1142 return pad_painter.CheckCanvasResize(arg,
false);
1146 JSROOT.TObjectPainter.prototype.RemoveDrawG =
function() {
1148 if (this.draw_g != null) {
1149 this.draw_g.remove();
1157 JSROOT.TObjectPainter.prototype.RecreateDrawG =
function(take_pad, layer) {
1160 d3.selectAll(this.draw_g.node().childNodes).
remove();
1163 if (typeof layer !=
'string') layer =
"text_layer";
1164 if (layer.charAt(0) ==
".") layer = layer.substr(1);
1165 this.draw_g = this.svg_layer(layer).append(
"svg:g");
1167 if (typeof layer !=
'string') layer =
".main_layer";
1168 if (layer.charAt(0) !=
".") layer =
"." + layer;
1169 this.draw_g = this.svg_frame().select(layer).append(
"svg:g");
1173 if (this.draw_object!==null) {
1174 this.draw_g.attr(
'objname', this.draw_object.fName);
1175 this.draw_g.attr(
'objtype', this.draw_object._typename);
1182 JSROOT.TObjectPainter.prototype.svg_canvas =
function() {
1183 return this.select_main().select(
".root_canvas");
1187 JSROOT.TObjectPainter.prototype.svg_pad =
function(pad_name) {
1188 var c = this.svg_canvas();
1189 if (pad_name === undefined) pad_name = this.pad_name;
1190 if ((pad_name.length > 0) && !c.empty())
1191 c = c.select(
".subpads_layer").select(
"[pad=" + pad_name +
']');
1196 JSROOT.TObjectPainter.prototype.svg_layer =
function(name, pad_name) {
1197 var svg = this.svg_pad(pad_name);
1198 if (svg.empty())
return svg;
1200 var node = svg.node().firstChild;
1202 while (node!==null) {
1203 var elem = d3.select(node);
1204 if (elem.classed(name))
return elem;
1205 node = node.nextSibling;
1208 return d3.select(null);
1211 JSROOT.TObjectPainter.prototype.root_pad =
function() {
1212 var pad_painter = this.pad_painter(
true);
1213 return pad_painter ? pad_painter.pad : null;
1217 JSROOT.TObjectPainter.prototype.ConvertToNDC =
function(axis, value, isndc) {
1218 var pad = this.root_pad();
1219 if (isndc == null) isndc =
false;
1221 if (isndc || (pad==null))
return value;
1225 value = (value>0) ? JSROOT.log10(value) : pad.fUymin;
1226 return (value - pad.fY1) / (pad.fY2 - pad.fY1);
1229 value = (value>0) ? JSROOT.log10(value) : pad.fUxmin;
1230 return (value - pad.fX1) / (pad.fX2 - pad.fX1);
1236 JSROOT.TObjectPainter.prototype.AxisToSvg =
function(axis, value, ndc) {
1237 var main = this.main_painter();
1238 if ((main!=null) && !ndc)
1239 return axis==
"y" ? main.gry(value) : main.grx(value);
1240 if (!ndc) value = this.ConvertToNDC(axis, value);
1241 if (axis==
"y")
return (1-value)*this.pad_height();
1242 return value*this.pad_width();
1245 JSROOT.TObjectPainter.prototype.PadToSvg =
function(axis, value, ndc) {
1246 return this.AxisToSvg(axis,value,ndc);
1250 JSROOT.TObjectPainter.prototype.svg_frame =
function() {
1251 return this.svg_pad().select(
".root_frame");
1254 JSROOT.TObjectPainter.prototype.frame_painter =
function() {
1255 var res = this.svg_frame().property(
'frame_painter');
1256 return (res===undefined) ? null : res;
1259 JSROOT.TObjectPainter.prototype.pad_width =
function(pad_name) {
1260 var res = this.svg_pad(pad_name).property(
"draw_width");
1261 return isNaN(res) ? 0 : res;
1264 JSROOT.TObjectPainter.prototype.pad_height =
function(pad_name) {
1265 var res = this.svg_pad(pad_name).property(
"draw_height");
1266 return isNaN(res) ? 0 : res;
1269 JSROOT.TObjectPainter.prototype.frame_x =
function() {
1270 var res = parseInt(this.svg_frame().attr(
"x"));
1271 return isNaN(res) ? 0 : res;
1274 JSROOT.TObjectPainter.prototype.frame_y =
function() {
1275 var res = parseInt(this.svg_frame().attr(
"y"));
1276 return isNaN(res) ? 0 : res;
1279 JSROOT.TObjectPainter.prototype.frame_width =
function() {
1280 var res = parseInt(this.svg_frame().attr(
"width"));
1281 return isNaN(res) ? 0 : res;
1284 JSROOT.TObjectPainter.prototype.frame_height =
function() {
1285 var res = parseInt(this.svg_frame().attr(
"height"));
1286 return isNaN(res) ? 0 : res;
1289 JSROOT.TObjectPainter.prototype.embed_3d =
function() {
1295 if (JSROOT.gStyle.Embed3DinSVG < 2)
return JSROOT.gStyle.Embed3DinSVG;
1296 if (JSROOT.browser.isFirefox )
1297 return JSROOT.gStyle.Embed3DinSVG;
1301 JSROOT.TObjectPainter.prototype.size_for_3d =
function(can3d) {
1304 if (can3d === undefined) can3d = this.embed_3d();
1306 var pad = this.svg_pad();
1308 var clname = this.pad_name;
1309 if (clname ==
'') clname =
'canvas';
1310 clname =
"draw3d_" + clname;
1315 var rect = this.main_visible_rect();
1317 if ((rect.height<10) && (rect.width>10)) {
1318 rect.height = Math.round(0.66*rect.width);
1319 this.select_main().style(
'height', rect.height +
"px");
1321 rect.x = 0; rect.y = 0; rect.clname = clname; rect.can3d = -1;
1326 if (can3d == 0) elem = this.svg_canvas();
1328 var size = { x: 0, y: 0, width: 100, height:100, clname: clname, can3d: can3d };
1330 if (this.frame_painter()!==null) {
1331 elem = this.svg_frame();
1332 size.x = elem.property(
"draw_x");
1333 size.y = elem.property(
"draw_y");
1336 size.width = elem.property(
"draw_width");
1337 size.height = elem.property(
"draw_height");
1339 if ((this.frame_painter()===null) && (can3d > 0)) {
1340 size.x = Math.round(size.x + size.width*0.1);
1341 size.y = Math.round(size.y + size.height*0.1);
1342 size.width = Math.round(size.width*0.8);
1343 size.height = Math.round(size.height*0.8);
1347 this.CalcAbsolutePosition(this.svg_pad(), size);
1352 JSROOT.TObjectPainter.prototype.clear_3d_canvas =
function() {
1353 var can3d = this.svg_pad().property(
'can3d');
1354 if (can3d === null)
return;
1356 this.svg_pad().property(
'can3d', null);
1358 var size = this.size_for_3d(can3d);
1360 if (size.can3d === 0) {
1361 d3.select(this.svg_canvas().node().nextSibling).remove();
1362 this.svg_canvas().style(
'display', null);
1364 if (this.svg_pad().empty())
return;
1366 this.apply_3d_size(size).remove();
1368 this.svg_frame().style(
'display', null);
1372 JSROOT.TObjectPainter.prototype.add_3d_canvas =
function(size, canv) {
1374 if ((canv == null) || (size.can3d < -1))
return;
1376 if (size.can3d === -1) {
1379 var main = this.select_main().node();
1380 if (main !== null) {
1381 main.appendChild(canv);
1382 canv[
'painter'] =
this;
1388 this.svg_pad().property(
'can3d', size.can3d);
1390 if (size.can3d === 0) {
1391 this.svg_canvas().style(
'display',
'none');
1393 this.svg_canvas().node().parentNode.appendChild(canv);
1395 if (this.svg_pad().empty())
return;
1398 this.svg_frame().style(
'display',
'none');
1400 var elem = this.apply_3d_size(size);
1402 elem.attr(
'title',
'').node().appendChild(canv);
1406 JSROOT.TObjectPainter.prototype.apply_3d_size =
function(size, onlyget) {
1408 if (size.can3d < 0)
return d3.select(null);
1412 if (size.can3d > 1) {
1414 var layer = this.svg_layer(
"special_layer");
1416 elem = layer.select(
"." + size.clname);
1417 if (onlyget)
return elem;
1420 elem = layer.append(
"foreignObject").attr(
"class", size.clname);
1422 elem.attr(
'x', size.x)
1424 .attr(
'width', size.width)
1425 .attr(
'height', size.height)
1426 .attr(
'viewBox',
"0 0 " + size.width +
" " + size.height)
1427 .attr(
'preserveAspectRatio',
'xMidYMid');
1430 elem = d3.select(this.svg_canvas().node().parentNode).select(
"." + size.clname);
1431 if (onlyget)
return elem;
1434 this.svg_canvas().property(
'redraw_by_resize',
true);
1437 elem = d3.select(this.svg_canvas().node().parentNode)
1438 .append(
'div').attr(
"class", size.clname);
1441 elem.style(
'position',
'absolute')
1442 .style(
'left', size.x +
'px')
1443 .style(
'top', size.y +
'px')
1444 .style(
'width', size.width +
'px')
1445 .style(
'height', size.height +
'px');
1453 JSROOT.TObjectPainter.prototype.main_painter =
function() {
1454 if (this.main === null) {
1455 var svg_p = this.svg_pad();
1456 if (!svg_p.empty()) {
1457 this.main = svg_p.property(
'mainpainter');
1458 if (this.main === undefined) this.main = null;
1464 JSROOT.TObjectPainter.prototype.is_main_painter =
function() {
1465 return this === this.main_painter();
1468 JSROOT.TObjectPainter.prototype.SetDivId =
function(divid, is_main) {
1480 if (divid !== undefined)
1483 if ((is_main === null) || (is_main === undefined)) is_main = 0;
1485 this.create_canvas =
false;
1488 var svg_c = this.svg_canvas();
1490 if (svg_c.empty() && (is_main > 0) && (is_main!==5)) {
1491 JSROOT.Painter.drawCanvas(divid, null, ((is_main == 2) || (is_main == 4)) ?
"noframe" :
"");
1492 svg_c = this.svg_canvas();
1493 this.create_canvas =
true;
1496 if (svg_c.empty()) {
1497 if ((is_main < 0) || (is_main===5) || this.iscan)
return;
1498 var main = this.select_main();
1499 if (main.node() && main.node().firstChild)
1500 main.node().firstChild.painter =
this;
1505 this.pad_name = svg_c.property(
'current_pad');
1507 if (is_main < 0)
return;
1510 if (this.svg_frame().select(
".main_layer").empty() && ((is_main == 1) || (is_main == 3))) {
1511 JSROOT.Painter.drawFrame(divid, null);
1512 if (this.svg_frame().empty())
return alert(
"Fail to draw dummy TFrame");
1515 var svg_p = this.svg_pad();
1516 if (svg_p.empty())
return;
1518 if (svg_p.property(
'pad_painter') !==
this)
1519 svg_p.property(
'pad_painter').painters.push(
this);
1521 if (((is_main === 1) || (is_main === 4) || (is_main === 5)) && (svg_p.property(
'mainpainter') == null))
1523 svg_p.property(
'mainpainter',
this);
1526 JSROOT.TObjectPainter.prototype.CalcAbsolutePosition =
function(sel, pos) {
1527 while (!sel.empty() && !sel.classed(
'root_canvas')) {
1528 if (sel.classed(
'root_frame') || sel.classed(
'root_pad')) {
1529 pos.x += sel.property(
"draw_x");
1530 pos.y += sel.property(
"draw_y");
1532 sel = d3.select(sel.node().parentNode);
1538 JSROOT.TObjectPainter.prototype.createAttFill =
function(attfill, pattern, color, kind) {
1544 var fill = { color:
"none", colorindx: 0, pattern: 0, used:
true, kind: 2 };
1546 if (kind!==undefined) fill.kind = kind;
1548 fill.Apply =
function(selection) {
1551 selection.style(
'fill', this.color);
1553 if (
'opacity' in
this)
1554 selection.style(
'opacity', this.opacity);
1556 if (
'antialias' in
this)
1557 selection.style(
'antialias', this.antialias);
1559 fill.func = fill.Apply.bind(fill);
1561 fill.Change =
function(color, pattern, svg) {
1562 if ((color !== undefined) && !isNaN(color))
1563 this.colorindx = color;
1565 if ((pattern !== undefined) && !isNaN(pattern)) {
1566 this.pattern = pattern;
1567 delete this.opacity;
1568 delete this.antialias;
1571 if (this.pattern < 1001) {
1572 this.color =
'none';
1576 if ((this.pattern === 1001) && (this.colorindx===0) && (this.kind===1)) {
1577 this.color =
'none';
1581 this.color = JSROOT.Painter.root_colors[this.colorindx];
1582 if (typeof this.color !=
'string') this.color =
"none";
1584 if (this.pattern === 1001)
return true;
1586 if ((this.pattern >= 4000) && (this.pattern <= 4100)) {
1588 this.opacity = (this.pattern - 4000)/100;
1592 if ((svg===undefined) || svg.empty() || (this.pattern < 3000) || (this.pattern > 3025))
return false;
1594 var
id =
"pat_" + this.pattern +
"_" + this.colorindx;
1596 var defs = svg.select(
'defs');
1598 defs = svg.insert(
"svg:defs",
":first-child");
1600 var line_color = this.color;
1601 this.color =
"url(#" +
id +
")";
1602 this.antialias =
false;
1604 if (!defs.select(
"."+
id).empty())
return true;
1606 var patt = defs.append(
'svg:pattern').attr(
"id",
id).attr(
"class",
id).attr(
"patternUnits",
"userSpaceOnUse");
1608 switch (this.pattern) {
1610 patt.attr(
"width", 2).attr(
"height", 2);
1611 patt.append(
'svg:rect').attr(
"x", 0).attr(
"y", 0).attr(
"width", 1).attr(
"height", 1);
1612 patt.append(
'svg:rect').attr(
"x", 1).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1);
1615 patt.attr(
"width", 4).attr(
"height", 2);
1616 patt.append(
'svg:rect').attr(
"x", 1).attr(
"y", 0).attr(
"width", 1).attr(
"height", 1);
1617 patt.append(
'svg:rect').attr(
"x", 3).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1);
1620 patt.attr(
"width", 4).attr(
"height", 4);
1621 patt.append(
'svg:rect').attr(
"x", 2).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1);
1622 patt.append(
'svg:rect').attr(
"x", 0).attr(
"y", 3).attr(
"width", 1).attr(
"height", 1);
1625 patt.attr(
"width", 8).attr(
"height", 8);
1626 patt.append(
"svg:line").attr(
"x1", 0).attr(
"y1", 0).attr(
"x2", 8).attr(
"y2", 8);
1629 patt.attr(
"width", 4).attr(
"height", 4);
1630 patt.append(
"svg:line").attr(
"x1", 1).attr(
"y1", 0).attr(
"x2", 1).attr(
"y2", 3);
1633 patt.attr(
"width", 4).attr(
"height", 4);
1634 patt.append(
"svg:line").attr(
"x1", 0).attr(
"y1", 1).attr(
"x2", 3).attr(
"y2", 1);
1637 patt.attr(
"width", 10).attr(
"height", 10);
1638 patt.append(
"svg:line").attr(
"x1", 0).attr(
"y1", 2).attr(
"x2", 10).attr(
"y2", 2);
1639 patt.append(
"svg:line").attr(
"x1", 0).attr(
"y1", 7).attr(
"x2", 10).attr(
"y2", 7);
1640 patt.append(
"svg:line").attr(
"x1", 2).attr(
"y1", 0).attr(
"x2", 2).attr(
"y2", 2);
1641 patt.append(
"svg:line").attr(
"x1", 7).attr(
"y1", 2).attr(
"x2", 7).attr(
"y2", 7);
1642 patt.append(
"svg:line").attr(
"x1", 2).attr(
"y1", 7).attr(
"x2", 2).attr(
"y2", 10);
1646 patt.attr(
"width", 10).attr(
"height", 10);
1647 patt.append(
"svg:line").attr(
"x1", 0).attr(
"y1", 5).attr(
"x2", 5).attr(
"y2", 5);
1648 patt.append(
"svg:line").attr(
"x1", 5).attr(
"y1", 5).attr(
"x2", 5).attr(
"y2", 0);
1649 patt.append(
"svg:line").attr(
"x1", 5).attr(
"y1", 10).attr(
"x2", 10).attr(
"y2", 10);
1650 patt.append(
"svg:line").attr(
"x1", 10).attr(
"y1", 10).attr(
"x2", 10).attr(
"y2", 5);
1653 patt.attr(
"width", 8).attr(
"height", 8);
1654 patt.append(
"svg:line").attr(
"x1", 8).attr(
"y1", 0).attr(
"x2", 0).attr(
"y2", 8);
1658 patt.selectAll(
'line').style(
"stroke",line_color).style(
"stroke-width", 1);
1659 patt.selectAll(
'rect').style(
"fill",line_color);
1664 if ((attfill!==null) && (typeof attfill ==
'object')) {
1665 if (
'fFillStyle' in attfill) pattern = attfill.fFillStyle;
1666 if (
'fFillColor' in attfill) color = attfill.fFillColor;
1669 fill.Change(color, pattern, this.svg_canvas());
1674 JSROOT.TObjectPainter.prototype.ForEachPainter =
function(userfunc) {
1677 var main = this.select_main();
1678 var painter = (main.node() && main.node().firstChild) ? main.node().firstChild[
'painter'] : null;
1679 if (painter!=null)
return userfunc(painter);
1681 var pad_painter = this.pad_painter(
true);
1682 if (pad_painter == null)
return;
1684 userfunc(pad_painter);
1685 if (
'painters' in pad_painter)
1686 for (var k = 0; k < pad_painter.painters.length; ++k)
1687 userfunc(pad_painter.painters[k]);
1690 JSROOT.TObjectPainter.prototype.Cleanup =
function() {
1692 this.select_main().html(
"");
1695 JSROOT.TObjectPainter.prototype.RedrawPad =
function() {
1698 var pad_painter = this.pad_painter(
true);
1699 if (pad_painter) pad_painter.Redraw();
1702 JSROOT.TObjectPainter.prototype.SwitchTooltip =
function(on) {
1703 var fp = this.frame_painter();
1704 if (fp) fp.ProcessTooltipEvent(null, on);
1707 JSROOT.TObjectPainter.prototype.AddDrag =
function(callback) {
1708 if (!JSROOT.gStyle.MoveResize)
return;
1712 var rect_width =
function() {
return Number(pthis.draw_g.attr(
"width")); }
1713 var rect_height =
function() {
return Number(pthis.draw_g.attr(
"height")); }
1715 var acc_x = 0, acc_y = 0, pad_w = 1, pad_h = 1, drag_tm = null;
1717 function detectRightButton(event) {
1718 if (
'buttons' in event)
return event.buttons === 2;
1719 else if (
'which' in event)
return event.which === 3;
1720 else if (
'button' in event)
return event.button === 2;
1724 var resize_corner1 = this.draw_g.select(
'.resize_corner1');
1725 if (resize_corner1.empty())
1726 resize_corner1 = this.draw_g
1728 .attr(
'class',
'resize_corner1')
1729 .attr(
"d",
"M2,2 h15 v-5 h-20 v20 h5 Z");
1731 var resize_corner2 = this.draw_g.select(
'.resize_corner2');
1732 if (resize_corner2.empty())
1733 resize_corner2 = this.draw_g
1735 .attr(
'class',
'resize_corner2')
1736 .attr(
"d",
"M-2,-2 h-15 v5 h20 v-20 h-5 Z");
1738 resize_corner1.style(
"opacity",
"0")
1739 .style(
"cursor",
"nw-resize");
1741 resize_corner2.style(
"opacity",
"0")
1742 .style(
"cursor",
"se-resize")
1743 .attr(
"transform",
"translate(" + rect_width() +
"," + rect_height() +
")");
1745 var drag_rect = null;
1747 function complete_drag() {
1748 drag_rect.style(
"cursor",
"auto");
1750 var oldx = Number(pthis.draw_g.attr(
"x")),
1751 oldy = Number(pthis.draw_g.attr(
"y")),
1752 newx = Number(drag_rect.attr(
"x")),
1753 newy = Number(drag_rect.attr(
"y")),
1754 newwidth = Number(drag_rect.attr(
"width")),
1755 newheight = Number(drag_rect.attr(
"height"));
1757 var change_size = (newwidth !== rect_width()) || (newheight !== rect_height());
1758 var change_pos = (newx !== oldx) || (newy !== oldy);
1760 pthis.draw_g.attr(
'x', newx).attr(
'y', newy)
1761 .attr(
"transform",
"translate(" + newx +
"," + newy +
")")
1762 .attr(
'width', newwidth).attr(
'height', newheight);
1767 pthis.SwitchTooltip(
true);
1769 resize_corner2.attr(
"transform",
"translate(" + newwidth +
"," + newheight +
")");
1771 if (change_size || change_pos) {
1772 if (change_size && (
'resize' in callback)) callback.resize(newwidth, newheight);
1773 if (change_pos && (
'move' in callback)) callback.move(newx, newy, newx - oldxx, newy-oldy);
1775 if (change_size || change_pos) {
1776 if (
'obj' in callback) {
1777 callback.obj.fX1NDC = newx / pthis.pad_width();
1778 callback.obj.fX2NDC = (newx + newwidth) / pthis.pad_width();
1779 callback.obj.fY1NDC = 1 - (newy + newheight) / pthis.pad_height();
1780 callback.obj.fY2NDC = 1 - newy / pthis.pad_height();
1782 if (
'redraw' in callback) callback.redraw();
1786 return change_size || change_pos;
1789 var drag_move = d3.behavior.drag().origin(Object)
1790 .on(
"dragstart",
function() {
1791 if (detectRightButton(d3.event.sourceEvent))
return;
1793 JSROOT.Painter.closeMenu();
1795 pthis.SwitchTooltip(
false);
1797 d3.event.sourceEvent.preventDefault();
1798 d3.event.sourceEvent.stopPropagation();
1800 acc_x = 0; acc_y = 0;
1801 pad_w = pthis.pad_width() - rect_width();
1802 pad_h = pthis.pad_height() - rect_height();
1804 drag_tm =
new Date();
1806 drag_rect = d3.select(pthis.draw_g.node().parentNode).append(
"rect")
1807 .classed(
"zoom",
true)
1808 .attr(
"x", pthis.draw_g.attr(
"x"))
1809 .attr(
"y", pthis.draw_g.attr(
"y"))
1810 .attr(
"width", rect_width())
1811 .attr(
"height", rect_height())
1812 .style(
"cursor",
"move")
1813 .style(
"pointer-events",
"none");
1814 }).on(
"drag",
function() {
1815 if (drag_rect == null)
return;
1817 d3.event.sourceEvent.preventDefault();
1819 var x = Number(drag_rect.attr(
"x")), y = Number(drag_rect.attr(
"y"));
1820 var dx = d3.event.dx, dy = d3.event.dy;
1822 if ((acc_x<0) && (dx>0)) { acc_x+=dx; dx=0;
if (acc_x>0) { dx=acc_x; acc_x=0; }}
1823 if ((acc_x>0) && (dx<0)) { acc_x+=dx; dx=0;
if (acc_x<0) { dx=acc_x; acc_x=0; }}
1824 if ((acc_y<0) && (dy>0)) { acc_y+=dy; dy=0;
if (acc_y>0) { dy=acc_y; acc_y=0; }}
1825 if ((acc_y>0) && (dy<0)) { acc_y+=dy; dy=0;
if (acc_y<0) { dy=acc_y; acc_y=0; }}
1827 if (x+dx<0) { acc_x+=(x+dx); x=0; }
else
1828 if (x+dx>pad_w) { acc_x+=(x+dx-pad_w); x=pad_w; }
else x+=dx;
1830 if (y+dy<0) { acc_y+=(y+dy); y = 0; }
else
1831 if (y+dy>pad_h) { acc_y+=(y+dy-pad_h); y=pad_h; }
else y+=dy;
1833 drag_rect.attr(
"x", x).attr(
"y", y);
1835 d3.event.sourceEvent.stopPropagation();
1836 }).on(
"dragend",
function() {
1837 if (drag_rect==null)
return;
1839 d3.event.sourceEvent.preventDefault();
1841 if (complete_drag() ===
false)
1842 if(callback[
'ctxmenu'] && ((
new Date()).getTime() - drag_tm.getTime() > 600)) {
1843 var rrr = resize_corner2.node().getBoundingClientRect();
1844 pthis.ShowContextMenu(
'main', { clientX: rrr.left, clientY: rrr.top } );
1848 var drag_resize = d3.behavior.drag().origin(Object)
1849 .on(
"dragstart",
function() {
1850 if (detectRightButton(d3.event.sourceEvent))
return;
1852 d3.event.sourceEvent.stopPropagation();
1853 d3.event.sourceEvent.preventDefault();
1855 pthis.SwitchTooltip(
false);
1857 acc_x = 0; acc_y = 0;
1858 pad_w = pthis.pad_width();
1859 pad_h = pthis.pad_height();
1860 drag_rect = d3.select(pthis.draw_g.node().parentNode).append(
"rect")
1861 .classed(
"zoom",
true)
1862 .attr(
"x", pthis.draw_g.attr(
"x"))
1863 .attr(
"y", pthis.draw_g.attr(
"y"))
1864 .attr(
"width", rect_width())
1865 .attr(
"height", rect_height())
1866 .style(
"cursor", d3.select(
this).style(
"cursor"));
1867 }).on(
"drag",
function() {
1868 if (drag_rect == null)
return;
1870 d3.event.sourceEvent.preventDefault();
1872 var w = Number(drag_rect.attr(
"width")), h = Number(drag_rect.attr(
"height")),
1873 x = Number(drag_rect.attr(
"x")), y = Number(drag_rect.attr(
"y"));
1874 var dx = d3.event.dx, dy = d3.event.dy;
1875 if ((acc_x<0) && (dx>0)) { acc_x+=dx; dx=0;
if (acc_x>0) { dx=acc_x; acc_x=0; }}
1876 if ((acc_x>0) && (dx<0)) { acc_x+=dx; dx=0;
if (acc_x<0) { dx=acc_x; acc_x=0; }}
1877 if ((acc_y<0) && (dy>0)) { acc_y+=dy; dy=0;
if (acc_y>0) { dy=acc_y; acc_y=0; }}
1878 if ((acc_y>0) && (dy<0)) { acc_y+=dy; dy=0;
if (acc_y<0) { dy=acc_y; acc_y=0; }}
1880 if (d3.select(
this).classed(
'resize_corner1')) {
1881 if (x+dx < 0) { acc_x += (x+dx); w += x; x = 0; }
else
1882 if (w-dx < 0) { acc_x -= (w-dx); x += w; w = 0; }
else { x+=dx; w-=dx; }
1883 if (y+dy < 0) { acc_y += (y+dy); h += y; y = 0; }
else
1884 if (h-dy < 0) { acc_y -= (h-dy); y += h; h = 0; }
else { y+=dy; h-=dy; }
1886 if (x+w+dx > pad_w) { acc_x += (x+w+dx-pad_w); w = pad_w-x; }
else
1887 if (w+dx < 0) { acc_x += (w+dx); w = 0; }
else w += dx;
1888 if (y+h+dy > pad_h) { acc_y += (y+h+dy-pad_h); h = pad_h-y; }
else
1889 if (h+dy < 0) { acc_y += (h+dy); h=0; }
else h += dy;
1892 drag_rect.attr(
"x", x).attr(
"y", y).attr(
"width", w).attr(
"height", h);
1894 d3.event.sourceEvent.stopPropagation();
1895 }).on(
"dragend",
function() {
1896 if (drag_rect == null)
return;
1898 d3.event.sourceEvent.preventDefault();
1903 if (!(
'only_resize' in callback)) {
1904 this.draw_g.style(
"cursor",
"move").call(drag_move);
1907 resize_corner1.call(drag_resize);
1908 resize_corner2.call(drag_resize);
1911 JSROOT.TObjectPainter.prototype.startTouchMenu =
function(kind) {
1914 var arr = d3.touches(this.svg_frame().node());
1915 if (arr.length != 1)
return;
1917 if (!kind || (kind==
"")) kind =
"main";
1918 var fld =
"touch_" + kind;
1920 d3.event.preventDefault();
1921 d3.event.stopPropagation();
1923 this[fld] = { dt:
new Date(), pos: arr[0] };
1925 this.svg_frame().on(
"touchcancel", this.endTouchMenu.bind(
this, kind))
1926 .on(
"touchend", this.endTouchMenu.bind(
this, kind));
1929 JSROOT.TObjectPainter.prototype.endTouchMenu =
function(kind) {
1930 var fld =
"touch_" + kind;
1932 if (! (fld in
this))
return;
1934 d3.event.preventDefault();
1935 d3.event.stopPropagation();
1937 var diff =
new Date().getTime() -
this[fld].dt.getTime();
1939 this.svg_frame().on(
"touchcancel", null)
1940 .on(
"touchend", null);
1943 var rect = this.svg_frame().node().getBoundingClientRect();
1944 this.ShowContextMenu(kind, { clientX: rect.left +
this[fld].pos[0],
1945 clientY: rect.top +
this[fld].pos[1] } );
1951 JSROOT.TObjectPainter.prototype.AddColorMenuEntry =
function(menu, name, value, set_func, fill_kind) {
1952 if (value === undefined)
return;
1953 menu.add(
"sub:"+name,
function() {
1955 var useid = (typeof value !==
'string');
1956 var col = prompt(
"Enter color " + (useid ?
"(only id number)" :
"(name or id)"), value);
1957 if (col == null)
return;
1958 var
id = parseInt(col);
1959 if (!isNaN(
id) && (JSROOT.Painter.root_colors[
id] !== undefined)) {
1960 col = JSROOT.Painter.root_colors[id];
1964 set_func.bind(
this)(useid ?
id : col);
1966 var useid = (typeof value !==
'string');
1967 for (var n=-1;n<11;++n) {
1968 if ((n<0) && useid)
continue;
1969 if ((n==10) && (fill_kind!==1))
continue;
1970 var col = (n<0) ?
'none' : JSROOT.Painter.root_colors[n];
1971 if ((n==0) && (fill_kind==1)) col =
'none';
1972 var svg =
"<svg width='100' height='18' style='margin:0px;background-color:" + col +
"'><text x='4' y='12' style='font-size:12px' fill='" + (n==1 ?
"white" :
"black") +
"'>"+col+
"</text></svg>";
1973 menu.addchk((value == (useid ? n : col)), svg, (useid ? n : col), set_func);
1975 menu.add(
"endsub:");
1978 JSROOT.TObjectPainter.prototype.AddSizeMenuEntry =
function(menu, name, min, max, step, value, set_func) {
1979 if (value === undefined)
return;
1981 menu.add(
"sub:"+name,
function() {
1983 var entry = value.toFixed(4);
1984 if (step>=0.1) entry = value.toFixed(2);
1985 if (step>=1) entry = value.toFixed(0);
1986 var val = prompt(
"Enter value of " + name, entry);
1987 if (val==null)
return;
1988 var val = parseFloat(val);
1989 if (!isNaN(val)) set_func.bind(
this)((step>=1) ? Math.round(val) : val);
1991 for (var val=min;val<=max;val+=step) {
1992 var entry = val.toFixed(2);
1993 if (step>=0.1) entry = val.toFixed(1);
1994 if (step>=1) entry = val.toFixed(0);
1995 menu.addchk((Math.abs(value - val) < step/2), entry, val, set_func);
1997 menu.add(
"endsub:");
2001 JSROOT.TObjectPainter.prototype.FillAttContextMenu =
function(menu, preffix) {
2006 if (!preffix) preffix =
"";
2008 if (this.lineatt && this.lineatt.used) {
2009 menu.add(
"sub:"+preffix+
"Line att");
2010 this.AddSizeMenuEntry(menu,
"width", 1, 10, 1, this.lineatt.width,
2011 function(arg) {
this.lineatt.width = parseInt(arg); this.Redraw(); }.bind(
this));
2012 this.AddColorMenuEntry(menu,
"color", this.lineatt.color,
2013 function(arg) {
this.lineatt.color = arg;
this.Redraw(); }.bind(
this));
2014 menu.add(
"sub:style",
function() {
2015 var
id = prompt(
"Enter line style id (1-solid)", 1);
2016 if (
id == null)
return;
2018 if (isNaN(
id) || (JSROOT.Painter.root_line_styles[
id] === undefined))
return;
2019 this.lineatt.dash = JSROOT.Painter.root_line_styles[id];
2022 for (var n=1;n<11;++n) {
2023 var style = JSROOT.Painter.root_line_styles[n];
2025 var svg =
"<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + n +
"</text><line x1='30' y1='8' x2='100' y2='8' stroke='black' stroke-width='3' stroke-dasharray='" + style +
"'></line></svg>";
2027 menu.addchk((this.lineatt.dash==style), svg, style,
function(arg) {
this.lineatt.dash = arg;
this.Redraw(); }.bind(
this));
2029 menu.add(
"endsub:");
2030 menu.add(
"endsub:");
2032 if ((
'excl_side' in this.lineatt) && (this.lineatt.excl_side!==0)) {
2033 menu.add(
"sub:Exclusion");
2034 menu.add(
"sub:side");
2035 for (var side=-1;side<=1;++side)
2036 menu.addchk((
this.lineatt.excl_side==side), side, side,
function(arg) {
2037 this.lineatt.excl_side = parseInt(arg);
2038 if ((this.lineatt.excl_width===0) && (
this.lineatt.excl_side!=0))
this.lineatt.excl_width = 20;
2041 menu.add(
"endsub:");
2043 this.AddSizeMenuEntry(menu,
"width", 10, 100, 10, this.lineatt.excl_width,
2044 function(arg) {
this.lineatt.excl_width = parseInt(arg); this.Redraw(); }.bind(
this));
2046 menu.add(
"endsub:");
2050 if (this.fillatt && this.fillatt.used) {
2051 menu.add(
"sub:"+preffix+
"Fill att");
2052 this.AddColorMenuEntry(menu,
"color", this.fillatt.colorindx,
2053 function(arg) {
this.fillatt.Change(parseInt(arg), undefined, this.svg_canvas()); this.Redraw(); }.bind(
this), this.fillatt.kind);
2054 menu.add(
"sub:style",
function() {
2055 var
id = prompt(
"Enter fill style id (1001-solid, 3000..3010)", this.fillatt.pattern);
2056 if (
id == null)
return;
2058 if (isNaN(
id))
return;
2059 this.fillatt.Change(undefined,
id, this.svg_canvas());
2063 var supported = [1, 1001, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3010, 3021, 3022];
2065 var clone = JSROOT.clone(this.fillatt);
2066 if (clone.colorindx<=0) clone.colorindx = 1;
2068 for (var n=0; n<supported.length; ++n) {
2070 clone.Change(undefined, supported[n], this.svg_canvas());
2072 var svg =
"<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() +
"</text><rect x='40' y='0' width='60' height='18' stroke='none' fill='" + clone.color +
"'></rect></svg>";
2074 menu.addchk(this.fillatt.pattern == supported[n], svg, supported[n],
function(arg) {
2075 this.fillatt.Change(undefined, parseInt(arg), this.svg_canvas());
2079 menu.add(
"endsub:");
2080 menu.add(
"endsub:");
2083 if (this.markeratt && this.markeratt.used) {
2084 menu.add(
"sub:"+preffix+
"Marker att");
2085 this.AddColorMenuEntry(menu,
"color", this.markeratt.color,
2086 function(arg) {
this.markeratt.Change(arg); this.Redraw(); }.bind(
this));
2087 this.AddSizeMenuEntry(menu,
"size", 0.5, 6, 0.5, this.markeratt.size,
2088 function(arg) {
this.markeratt.Change(undefined, undefined, parseFloat(arg)); this.Redraw(); }.bind(
this));
2090 menu.add(
"sub:style");
2091 var supported = [1,2,3,4,5,6,7,8,21,22,23,24,25,26,27,28,29,30,31,32,33,34];
2093 var clone = JSROOT.clone(this.markeratt);
2094 for (var n=0; n<supported.length; ++n) {
2095 clone.Change(undefined, supported[n], 1.7);
2097 var svg =
"<svg width='60' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() +
"</text><path stroke='black' fill='" + (clone.fill ?
"black" :
"none") +
"' d='" + clone.create(40,8) +
"'></path></svg>";
2099 menu.addchk(this.markeratt.style == supported[n], svg, supported[n],
2100 function(arg) {
this.markeratt.Change(undefined, parseInt(arg)); this.Redraw(); }.bind(
this));
2102 menu.add(
"endsub:");
2103 menu.add(
"endsub:");
2107 JSROOT.TObjectPainter.prototype.TextAttContextMenu =
function(menu, prefix) {
2110 var obj = this.GetObject();
2111 if (!obj || !(
'fTextColor' in obj))
return;
2113 menu.add(
"sub:" + (prefix ? prefix :
"Text"));
2114 this.AddColorMenuEntry(menu,
"color", obj.fTextColor,
2115 function(arg) {
this.GetObject().fTextColor = parseInt(arg); this.Redraw(); }.bind(
this));
2117 var align = [11, 12, 13, 21, 22, 23, 31, 32, 33],
2118 hnames = [
'left',
'centered' ,
'right'],
2119 vnames = [
'bottom',
'centered',
'top'];
2121 menu.add(
"sub:align");
2122 for (var n=0; n<align.length; ++n) {
2123 menu.addchk(align[n] == obj.fTextAlign,
2126 function(arg) {
this.GetObject().fTextAlign = parseInt(arg); this.Redraw(); }.bind(
this));
2128 menu.add(
"endsub:");
2130 menu.add(
"sub:font");
2131 for (var n=1; n<16; ++n) {
2132 menu.addchk(n == Math.floor(obj.fTextFont/10), n, n,
2133 function(arg) { this.GetObject().fTextFont = parseInt(arg)*10+2; this.Redraw(); }.bind(
this));
2135 menu.add(
"endsub:");
2137 menu.add(
"endsub:");
2141 JSROOT.TObjectPainter.prototype.FillContextMenu =
function(menu) {
2143 var title = this.GetTipName();
2144 if (this.GetObject() && (
'_typename' in this.GetObject()))
2145 title = this.GetObject()._typename +
"::" + title;
2147 menu.add(
"header:"+ title);
2149 this.FillAttContextMenu(menu);
2151 return menu.size() > 0;
2155 JSROOT.TObjectPainter.prototype.FindInPrimitives =
function(objname) {
2159 var painter = this.pad_painter(
true);
2160 if ((painter === null) || (painter.pad === null))
return null;
2162 if (painter.pad.fPrimitives !== null)
2163 for (var n=0;n<painter.pad.fPrimitives.arr.length;++n) {
2164 var prim = painter.pad.fPrimitives.arr[n];
2165 if ((
'fName' in prim) && (prim.fName === objname))
return prim;
2171 JSROOT.TObjectPainter.prototype.FindPainterFor =
function(selobj,selname) {
2176 var painter = this.pad_painter(
true);
2177 var painters = (painter === null) ? null : painter.painters;
2178 if (painters === null)
return null;
2180 for (var n = 0; n < painters.length; ++n) {
2181 var pobj = painters[n].GetObject();
2182 if (pobj===null)
continue;
2184 if (selobj && (pobj === selobj))
return painters[n];
2186 if (selname && (
'fName' in pobj) && (pobj.fName == selname))
return painters[n];
2192 JSROOT.TObjectPainter.prototype.ConfigureUserTooltipCallback =
function(call_back, user_timeout) {
2197 if ((call_back === undefined) || (typeof call_back !==
'function')) {
2198 delete this.UserTooltipCallback;
2202 if (user_timeout===undefined) user_timeout = 500;
2204 this.UserTooltipCallback = call_back;
2205 this.UserTooltipTimeout = user_timeout;
2208 JSROOT.TObjectPainter.prototype.IsUserTooltipCallback =
function() {
2209 return typeof this.UserTooltipCallback ==
'function';
2212 JSROOT.TObjectPainter.prototype.ProvideUserTooltip =
function(data) {
2214 if (!this.IsUserTooltipCallback())
return;
2216 if (this.UserTooltipTimeout <= 0)
2217 return this.UserTooltipCallback(data);
2219 if (typeof this.UserTooltipTHandle !=
'undefined') {
2220 clearTimeout(this.UserTooltipTHandle);
2221 delete this.UserTooltipTHandle;
2225 return this.UserTooltipCallback(data);
2227 this.UserTooltipTHandle = setTimeout(
function(d) {
2229 delete this.UserTooltipTHandle;
2230 this.UserTooltipCallback(d);
2231 }.bind(
this, data), this.UserTooltipTimeout);
2234 JSROOT.TObjectPainter.prototype.Redraw =
function() {
2240 JSROOT.TObjectPainter.prototype.StartTextDrawing =
function(font_face, font_size, draw_g) {
2243 if (!draw_g) draw_g = this.draw_g;
2245 var font = JSROOT.Painter.getFontDetails(font_face, font_size);
2247 draw_g.call(font.func);
2249 draw_g.property(
'text_font', font);
2250 draw_g.property(
'mathjax_use',
false);
2251 draw_g.property(
'text_factor', 0.);
2252 draw_g.property(
'max_text_width', 0);
2255 JSROOT.TObjectPainter.prototype.TextScaleFactor =
function(value, draw_g) {
2257 if (!draw_g) draw_g = this.draw_g;
2258 if (value && (value > draw_g.property(
'text_factor'))) draw_g.property(
'text_factor', value);
2261 JSROOT.TObjectPainter.prototype.GetBoundarySizes =
function(elem) {
2266 if (elem===null) { console.warn(
'empty node in GetBoundarySizes');
return { width:0, height:0 }; }
2267 var box = elem.getBoundingClientRect();
2268 if (parseInt(box.width) > 0) box = elem.getBBox();
2269 var res = { width : parseInt(box.width), height : parseInt(box.height) };
2270 if (
'left' in box) { res.x = parseInt(box.left); res.y = parseInt(box.right); }
else
2271 if (
'x' in box) { res.x = parseInt(box.x); res.y = parseInt(box.y); }
2275 JSROOT.TObjectPainter.prototype.FinishTextDrawing =
function(draw_g, call_ready) {
2276 if (!draw_g) draw_g = this.draw_g;
2281 if (draw_g.property(
'mathjax_use')) {
2282 draw_g.property(
'mathjax_use',
false);
2284 var missing =
false;
2285 svgs = draw_g.selectAll(
".math_svg");
2287 svgs.each(
function() {
2288 var fo_g = d3.select(
this);
2289 if (fo_g.node().parentNode !== draw_g.node())
return;
2290 var entry = fo_g.property(
'_element');
2291 if (d3.select(entry).select(
"svg").empty()) missing =
true;
2296 JSROOT.AssertPrerequisites(
'mathjax',
function() {
2297 if (typeof MathJax ==
'object')
2298 MathJax.Hub.Queue([
"FinishTextDrawing", pthis, draw_g, call_ready]);
2304 if (svgs==null) svgs = draw_g.selectAll(
".math_svg");
2306 var painter =
this, svg_factor = 0.;
2309 var f = draw_g.property(
'text_factor');
2310 if ((f>0) && ((f<0.9) || (f>1.))) {
2311 var font = draw_g.property(
'text_font');
2312 font.size = Math.floor(font.size/f);
2313 draw_g.call(font.func);
2317 svgs.each(
function() {
2318 var fo_g = d3.select(
this);
2319 if (fo_g.node().parentNode !== draw_g.node())
return;
2320 var entry = fo_g.property(
'_element'),
2321 rotate = fo_g.property(
'_rotate');
2323 fo_g.property(
'_element', null);
2325 var vvv = d3.select(entry).select(
"svg");
2327 JSROOT.console(
'MathJax SVG ouptut error');
2332 document.body.removeChild(entry);
2334 fo_g.append(
function() {
return vvv.node(); });
2336 if (fo_g.property(
'_scale')) {
2337 var box = painter.GetBoundarySizes(fo_g.node());
2338 svg_factor = Math.max(svg_factor, 1.05*box.width / fo_g.property(
'_width'),
2339 1.05*box.height / fo_g.property(
'_height'));
2343 svgs.each(
function() {
2344 var fo_g = d3.select(
this);
2346 if (fo_g.node().parentNode !== draw_g.node())
return;
2348 if (svg_factor > 0.) {
2349 var m = fo_g.select(
"svg");
2350 var mw = m.attr(
"width"), mh = m.attr(
"height");
2351 if ((typeof mw ==
'string') && (typeof mh ==
'string') && (mw.indexOf(
"ex") > 0) && (mh.indexOf(
"ex") > 0)) {
2352 mw = parseFloat(mw.substr(0,mw.length-2));
2353 mh = parseFloat(mh.substr(0,mh.length-2));
2354 if ((mw>0) && (mh>0)) {
2355 m.attr(
"width", (mw/svg_factor).toFixed(2)+
"ex");
2356 m.attr(
"height", (mh/svg_factor).toFixed(2)+
"ex");
2359 JSROOT.console(
'Fail to downscale MathJax output');
2363 var box = painter.GetBoundarySizes(fo_g.node()),
2364 align = fo_g.property(
'_align'),
2365 rotate = fo_g.property(
'_rotate'),
2366 fo_w = fo_g.property(
'_width'),
2367 fo_h = fo_g.property(
'_height'),
2368 tr = { x: fo_g.property(
'_x'), y: fo_g.property(
'_y') };
2370 var sign = { x:1, y:1 }, nx =
"x", ny =
"y";
2371 if (rotate == 180) { sign.x = sign.y = -1; }
else
2372 if ((rotate == 270) || (rotate == 90)) {
2373 sign.x = (rotate===270) ? -1 : 1;
2378 if (!fo_g.property(
'_scale')) fo_w = fo_h = 0;
2380 if (align[0] ==
'middle') tr[nx] += sign.x*(fo_w - box.width)/2;
else
2381 if (align[0] ==
'end') tr[nx] += sign.x*(fo_w - box.width);
2383 if (align[1] ==
'middle') tr[ny] += sign.y*(fo_h - box.height)/2;
else
2384 if (align[1] ==
'bottom') tr[ny] += sign.y*(fo_h - box.height);
2386 var trans =
"translate("+tr.x+
","+tr.y+
")";
2387 if (rotate!==0) trans +=
" rotate("+rotate+
",0,0)";
2389 fo_g.attr(
'transform', trans).attr(
'visibility', null);
2393 draw_g.selectAll(
'.hidden_text').attr(
'opacity',
'1').classed(
'hidden_text',
false);
2396 JSROOT.CallBack(call_ready);
2398 return draw_g.property(
'max_text_width');
2401 JSROOT.TObjectPainter.prototype.DrawText =
function(align_arg, x, y, w, h, label, tcolor, latex_kind, draw_g) {
2403 if (!draw_g) draw_g = this.draw_g;
2406 if (typeof align_arg ==
'string') {
2407 align = align_arg.split(
";");
2408 if (align.length==1) align.push(
'middle');
2410 align = [
'start',
'middle'];
2411 if ((align_arg / 10) >= 3) align[0] =
'end';
else
2412 if ((align_arg / 10) >= 2) align[0] =
'middle';
2413 if ((align_arg % 10) == 0) align[1] =
'bottom';
else
2414 if ((align_arg % 10) == 1) align[1] =
'bottom';
else
2415 if ((align_arg % 10) == 3) align[1] =
'top';
2418 var scale = (w>0) && (h>0);
2420 if (latex_kind==null) latex_kind = 1;
2422 if (!JSROOT.Painter.isAnyLatex(label)) latex_kind = 0;
2424 var use_normal_text = ((JSROOT.gStyle.MathJax<1) && (latex_kind!==2)) || (latex_kind<1);
2429 if (use_normal_text) {
2430 if (latex_kind>0) label = JSROOT.Painter.translateLaTeX(label);
2432 var pos_x = x.toFixed(1), pos_y = y.toFixed(1), pos_dy = null, middleline =
false;
2436 if (align[0]==
"middle") pos_x = (x+w*0.5).toFixed(1);
else
2437 if (align[0]==
"end") pos_x = (x+w).toFixed(1);
2441 if (align[1] ==
'bottom') pos_y = (y + h).toFixed(1);
else
2442 if (align[1] ==
'top') pos_dy =
".8em";
else {
2443 pos_y = (y + h/2).toFixed(1);
2444 if (JSROOT.browser.isIE) pos_dy =
".4em";
else middleline =
true;
2447 if (align[1] ==
'top') pos_dy =
".8em";
else
2448 if (align[1] ==
'middle') {
2449 if (JSROOT.browser.isIE) pos_dy =
".4em";
else middleline =
true;
2454 var trans =
"translate("+pos_x+
","+pos_y+
")";
2455 if (!scale && (h<0)) trans +=
" rotate("+(-h)+
",0,0)";
2457 var txt = draw_g.append(
"text")
2458 .attr(
"text-anchor", align[0])
2461 .attr(
"fill", tcolor ? tcolor : null)
2462 .attr(
"transform", trans)
2464 if (pos_dy!=null) txt.attr(
"dy", pos_dy);
2465 if (middleline) txt.attr(
"dominant-baseline",
"middle");
2467 var box = this.GetBoundarySizes(txt.node());
2469 if (scale) txt.classed(
'hidden_text',
true).attr(
'opacity',
'0');
2471 if (box.width > draw_g.property(
'max_text_width')) draw_g.property(
'max_text_width', box.width);
2472 if ((w>0) && scale) this.TextScaleFactor(1.05*box.width / w, draw_g);
2473 if ((h>0) && scale) this.TextScaleFactor(1.*box.height / h, draw_g);
2478 w = Math.round(w); h = Math.round(h);
2479 x = Math.round(x); y = Math.round(y);
2483 if (!scale && h<0) { rotate = Math.abs(h); h = 0; }
2485 var fo_g = draw_g.append(
"svg:g")
2486 .attr(
'class',
'math_svg')
2487 .attr(
'visibility',
'hidden')
2490 .property(
'_width',w)
2491 .property(
'_height',h)
2492 .property(
'_scale', scale)
2493 .property(
'_rotate', rotate)
2494 .property(
'_align', align);
2496 var element = document.createElement(
"div");
2497 d3.select(element).style(
"visibility",
"hidden")
2498 .style(
"overflow",
"hidden")
2499 .style(
"position",
"absolute")
2500 .html(JSROOT.Painter.translateMath(label, latex_kind, tcolor));
2501 document.body.appendChild(element);
2503 draw_g.property(
'mathjax_use',
true);
2504 fo_g.property(
'_element', element);
2506 JSROOT.AssertPrerequisites(
'mathjax',
function() {
2507 if (typeof MathJax ==
'object')
2508 MathJax.Hub.Queue([
"Typeset", MathJax.Hub, element]);
2516 JSROOT.TFramePainter =
function(tframe) {
2517 JSROOT.TObjectPainter.call(
this, tframe);
2518 this.tooltip_enabled =
true;
2521 JSROOT.TFramePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2523 JSROOT.TFramePainter.prototype.Shrink =
function(shrink_left, shrink_right) {
2524 this.fX1NDC += shrink_left;
2525 this.fX2NDC -= shrink_right;
2528 JSROOT.TFramePainter.prototype.Redraw =
function() {
2530 var width = this.pad_width(),
2531 height = this.pad_height(),
2532 tframe = this.GetObject(),
2533 root_pad = this.root_pad(),
2534 framecolor = this.createAttFill(null, 1001, 0),
2535 lineatt = JSROOT.Painter.createAttLine(
'black'),
2536 bordermode = 0, bordersize = 0,
2537 has_ndc = (
'fX1NDC' in
this);
2540 if (root_pad === null)
2541 JSROOT.extend(
this, JSROOT.gStyle.FrameNDC);
2543 JSROOT.extend(
this, {
2544 fX1NDC: root_pad.fLeftMargin,
2545 fX2NDC: 1 - root_pad.fRightMargin,
2546 fY1NDC: root_pad.fTopMargin,
2547 fY2NDC: 1 - root_pad.fBottomMargin
2551 if (tframe !== null) {
2552 bordermode = tframe.fBorderMode;
2553 bordersize = tframe.fBorderSize;
2554 lineatt = JSROOT.Painter.createAttLine(tframe);
2555 framecolor = this.createAttFill(tframe);
2556 if (!has_ndc && (root_pad !== null)) {
2557 var xspan = width / Math.abs(root_pad.fX2 - root_pad.fX1),
2558 yspan = height / Math.abs(root_pad.fY2 - root_pad.fY1),
2559 px1 = (tframe.fX1 - root_pad.fX1) * xspan,
2560 py1 = (tframe.fY1 - root_pad.fY1) * yspan,
2561 px2 = (tframe.fX2 - root_pad.fX1) * xspan,
2562 py2 = (tframe.fY2 - root_pad.fY1) * yspan,
2564 if (px1 < px2) { pxl = px1; pxt = px2; }
2565 else { pxl = px2; pxt = px1; }
2566 if (py1 < py2) { pyl = py1; pyt = py2; }
2567 else { pyl = py2; pyt = py1; }
2568 this.fX1NDC = pxl / width;
2569 this.fY1NDC = pyl / height;
2570 this.fX2NDC = pxt / width;
2571 this.fY2NDC = pyt / height;
2575 framecolor = this.createAttFill(null, root_pad.fFrameFillStyle, root_pad.fFrameFillColor);
2579 if (framecolor.color ==
'none') framecolor.color =
'white';
2581 if (this.fillatt === undefined) this.fillatt = framecolor;
2582 if (this.lineatt === undefined) this.lineatt = lineatt;
2584 var lm = Math.round(width * this.fX1NDC),
2585 w = Math.round(width * (this.fX2NDC - this.fX1NDC)),
2586 tm = Math.round(height * (1 - this.fY2NDC)),
2587 h = Math.round(height * (this.fY2NDC - this.fY1NDC));
2591 this.draw_g = this.svg_frame();
2592 if (this.draw_g.empty())
2593 return console.error(
'did not found frame layer');
2595 var top_rect = this.draw_g.select(
"rect"),
2596 main_svg = this.draw_g.select(
".main_layer");
2598 if (main_svg.empty()) {
2599 this.draw_g.append(
"svg:title").text(
"");
2601 top_rect = this.draw_g.append(
"svg:rect");
2604 this.draw_g.append(
'svg:g').attr(
'class',
'grid_layer');
2606 main_svg = this.draw_g.append(
'svg:svg')
2607 .attr(
'class',
'main_layer')
2610 .attr(
'overflow',
'hidden');
2612 this.draw_g.append(
'svg:g').attr(
'class',
'axis_layer');
2613 this.draw_g.append(
'svg:g').attr(
'class',
'upper_layer');
2617 this.draw_g.property(
'frame_painter',
this);
2619 this.draw_g.attr(
"x", lm)
2623 .property(
'draw_x', lm)
2624 .property(
'draw_y', tm)
2625 .property(
'draw_width', w)
2626 .property(
'draw_height', h)
2627 .attr(
"transform",
"translate(" + lm +
"," + tm +
")");
2629 top_rect.attr(
"x", 0)
2633 .call(this.fillatt.func)
2634 .call(this.lineatt.func);
2636 main_svg.attr(
"width", w)
2638 .attr(
"viewBox",
"0 0 " + w +
" " + h);
2640 this.AddDrag({ obj:
this, only_resize:
true, redraw: this.RedrawPad.bind(
this) });
2642 var tooltip_rect = this.draw_g.select(
".interactive_rect");
2644 if (JSROOT.gStyle.Tooltip === 0)
2645 return tooltip_rect.remove();
2649 function MouseMoveEvent() {
2650 var pnt = d3.mouse(tooltip_rect.node());
2651 painter.ProcessTooltipEvent({ x: pnt[0], y: pnt[1], touch:
false });
2654 function MouseCloseEvent() {
2655 painter.ProcessTooltipEvent(null);
2658 function TouchMoveEvent() {
2659 var pnt = d3.touches(tooltip_rect.node());
2660 if (!pnt || pnt.length !== 1)
return painter.ProcessTooltipEvent(null);
2661 painter.ProcessTooltipEvent({ x: pnt[0][0], y: pnt[0][1], touch:
true });
2664 function TouchCloseEvent() {
2665 painter.ProcessTooltipEvent(null);
2668 if (tooltip_rect.empty()) {
2672 .attr(
"class",
"interactive_rect")
2673 .style(
"opacity",
"0")
2674 .style(
"fill",
"none")
2675 .style(
"pointer-events",
"visibleFill")
2676 .on(
'mouseenter', MouseMoveEvent)
2677 .on(
'mousemove', MouseMoveEvent)
2678 .on(
'mouseleave', MouseCloseEvent);
2681 tooltip_rect.on(
"touchstart", TouchMoveEvent)
2682 .on(
"touchmove", TouchMoveEvent)
2683 .on(
"touchend", TouchCloseEvent)
2684 .on(
"touchcancel", TouchCloseEvent);
2687 tooltip_rect.attr(
"x", 0)
2692 var hintsg = this.svg_layer(
"stat_layer").select(
".objects_hints");
2694 if (!hintsg.empty() && (JSROOT.gStyle.Tooltip > 0))
2695 setTimeout(this.ProcessTooltipEvent.bind(
this, hintsg.property(
'last_point')), 10);
2699 JSROOT.TFramePainter.prototype.FillContextMenu =
function(menu) {
2703 var main = this.main_painter(), alone = menu.size()==0;
2706 menu.add(
"header:Frame");
2708 menu.add(
"separator");
2711 if (main.zoom_xmin !== main.zoom_xmax)
2712 menu.add(
"Unzoom X", main.Unzoom.bind(main,
"x"));
2713 if (main.zoom_ymin !== main.zoom_ymax)
2714 menu.add(
"Unzoom Y", main.Unzoom.bind(main,
"y"));
2715 if (main.zoom_zmin !== main.zoom_zmax)
2716 menu.add(
"Unzoom Z", main.Unzoom.bind(main,
"z"));
2717 menu.add(
"Unzoom all", main.Unzoom.bind(main,
"xyz"));
2720 menu.addchk(main.options.Logx,
"SetLogx", main.ToggleLog.bind(main,
"x"));
2722 menu.addchk(main.options.Logy,
"SetLogy", main.ToggleLog.bind(main,
"y"));
2724 if (main.Dimension() == 2)
2725 menu.addchk(main.options.Logz,
"SetLogz", main.ToggleLog.bind(main,
"z"));
2727 menu.add(
"separator");
2730 menu.addchk(this.tooltip_enabled,
"Show tooltips",
function() {
2731 this.tooltip_enabled = !this.tooltip_enabled;
2733 this.FillAttContextMenu(menu,alone ?
"" :
"Frame ");
2734 menu.add(
"separator");
2735 menu.add(
"Save as frame.png",
function(arg) {
2736 var top = this.svg_frame();
2738 JSROOT.AssertPrerequisites(
"savepng",
function() {
2739 saveSvgAsPng(top.node(),
"frame.png");
2747 JSROOT.TFramePainter.prototype.IsTooltipShown =
function() {
2749 if (JSROOT.gStyle.Tooltip < 1)
return false;
2750 return ! (this.svg_layer(
"stat_layer").select(
".objects_hints").empty());
2753 JSROOT.TFramePainter.prototype.ProcessTooltipEvent =
function(pnt, enabled) {
2755 if (enabled !== undefined) this.tooltip_enabled = enabled;
2757 if ((pnt === undefined) || (JSROOT.gStyle.Tooltip < 1) || !this.tooltip_enabled) pnt = null;
2759 var hints = [], nhints = 0, maxlen = 0, lastcolor1 = 0, usecolor1 =
false,
2760 textheight = 11, hmargin = 3, wmargin = 3, hstep = 1.2,
2761 height = this.frame_height(),
2762 width = this.frame_width(),
2763 pp = this.pad_painter(
true);
2766 if (pp!==null) hints = pp.GetTooltips(pnt);
2768 if (pnt && pnt.touch) textheight = 15;
2770 hints.forEach(
function(hint) {
2771 if (hint === null)
return;
2775 for (var l=0;l<hint.lines.length;++l)
2776 maxlen = Math.max(maxlen, hint.lines[l].length);
2778 hint.height = hint.lines.length*textheight*hstep + 2*hmargin - textheight*(hstep-1);
2780 if ((hint.color1!== undefined) && (hint.color1!==
'none')) {
2781 if ((lastcolor1!==0) && (lastcolor1 !== hint.color1)) usecolor1 =
true;
2782 lastcolor1 = hint.color1;
2786 var layer = this.svg_layer(
"stat_layer"),
2787 hintsg = layer.select(
".objects_hints");
2790 if ((pnt === null) || (hints.length===0) || (maxlen===0)) {
2799 hintsg = layer.append(
"svg:g")
2800 .attr(
"class",
"objects_hints")
2801 .style(
"pointer-events",
"none");
2804 hintsg.attr(
"transform", this.draw_g.attr(
"transform"));
2806 hintsg.property(
"last_point", pnt);
2808 var viewmode = hintsg.property(
'viewmode');
2809 if (viewmode === undefined) viewmode =
"";
2811 var actualw = 0, posx = pnt.x + 15;
2816 var bleft = 0.5, bright = 0.5;
2818 if (viewmode==
"left") bright = 0.7;
else
2819 if (viewmode==
"right") bleft = 0.3;
2821 if (pnt.x <= bleft*width) {
2825 if (pnt.x >= bright*width) {
2829 posx = hintsg.property(
'startx');
2832 viewmode =
"single";
2835 if (viewmode !== hintsg.property(
'viewmode')) {
2836 hintsg.property(
'viewmode', viewmode);
2837 hintsg.selectAll(
"*").remove();
2840 var font = JSROOT.Painter.getFontDetails(160, textheight);
2844 for (var n=0; n < hints.length; ++n) {
2845 var hint = hints[n];
2846 var group = hintsg.select(
".painter_hint_"+n);
2852 var was_empty = group.empty();
2855 group = hintsg.append(
"svg:svg")
2856 .attr(
"class",
"painter_hint_"+n)
2857 .style(
'overflow',
'hidden')
2858 .attr(
"opacity",
"0")
2859 .style(
"pointer-events",
"none");
2861 if (viewmode ==
"single")
2862 curry = pnt.touch ? pnt.y - hints[n].height - 5 : pnt.y + 15;
2864 group.attr(
"x", posx)
2867 curry += hints[n].height + 5;
2870 group.selectAll(
"*").remove();
2872 group.attr(
"width", 100)
2873 .attr(
"height", hint.height);
2875 var r = group.append(
"rect")
2879 .attr(
"height", hint.height)
2880 .attr(
"fill",
"lightgrey")
2881 .style(
"pointer-events",
"none");
2884 var col = usecolor1 ? hint.color1 : hint.color2;
2885 if ((col !== undefined) && (col!==
'none'))
2886 r.attr(
"stroke", col).attr(
"stroke-width", hint.exact ? 3 : 1);
2889 if (hint.lines != null) {
2890 for (var l=0;l<hint.lines.length;l++)
2891 if (hint.lines[l]!==null) {
2892 var txt = group.append(
"svg:text")
2893 .attr(
"text-anchor",
"start")
2895 .attr(
"y", hmargin + l*textheight*hstep)
2897 .attr(
"fill",
"black")
2898 .style(
"pointer-events",
"none")
2900 .text(hint.lines[l]);
2902 var box = this.GetBoundarySizes(txt.node());
2904 actualw = Math.max(actualw, box.width);
2908 function translateFn() {
2911 return function(d, i, a) {
2912 return function(t) {
2913 return t < 0.8 ?
"0" : (t-0.8)*5;
2919 group.transition().duration(500).attrTween(
"opacity", translateFn());
2922 actualw += 2*wmargin;
2924 if ((viewmode ==
"right") && (posx + actualw > width)) {
2925 posx = width - actualw - 20;
2926 hintsg.selectAll(
"svg").attr(
"x", posx);
2930 hintsg.selectAll(
"svg").attr(
"width", actualw)
2931 .select(
'rect').attr(
"width", actualw);
2933 hintsg.property(
'startx', posx);
2936 JSROOT.Painter.drawFrame =
function(divid, obj) {
2937 var p =
new JSROOT.TFramePainter(obj);
2938 p.SetDivId(divid, 2);
2940 return p.DrawingReady();
2946 JSROOT.TPavePainter =
function(pave) {
2947 JSROOT.TObjectPainter.call(
this, pave);
2948 this.Enabled =
true;
2949 this.UseContextMenu =
true;
2950 this.UseTextColor =
false;
2953 JSROOT.TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2955 JSROOT.TPavePainter.prototype.DrawPave =
function(refill) {
2958 this.UseTextColor =
false;
2961 return this.RemoveDrawG();
2963 var pt = this.GetObject();
2967 var pad = this.root_pad();
2968 if (pt.fOption.indexOf(
"NDC")>=0) {
2969 pt.fX1NDC = pt.fX1; pt.fX2NDC = pt.fX2;
2970 pt.fY1NDC = pt.fY1; pt.fY2NDC = pt.fY2;
2974 if (pt.fX1 > 0) pt.fX1 = JSROOT.log10(pt.fX1);
2975 if (pt.fX2 > 0) pt.fX2 = JSROOT.log10(pt.fX2);
2978 if (pt.fY1 > 0) pt.fY1 = JSROOT.log10(pt.fY1);
2979 if (pt.fY2 > 0) pt.fY2 = JSROOT.log10(pt.fY2);
2981 pt.fX1NDC = (pt.fX1-pad.fX1) / (pad.fX2 - pad.fX1);
2982 pt.fY1NDC = (pt.fY1-pad.fY1) / (pad.fY2 - pad.fY1);
2983 pt.fX2NDC = (pt.fX2-pad.fX1) / (pad.fX2 - pad.fX1);
2984 pt.fY2NDC = (pt.fY2-pad.fY1) / (pad.fY2 - pad.fY1);
2986 pt.fX1NDC = pt.fY1NDC = 0.1;
2987 pt.fX2NDC = pt.fY2NDC = 0.9;
2991 var pos_x = Math.round(pt.fX1NDC *
this.pad_width()),
2992 pos_y = Math.round((1.0 - pt.fY2NDC) *
this.pad_height()),
2993 width = Math.round((pt.fX2NDC - pt.fX1NDC) *
this.pad_width()),
2994 height = Math.round((pt.fY2NDC - pt.fY1NDC) *
this.pad_height()),
2995 lwidth = pt.fBorderSize;
2998 this.RecreateDrawG(
true,
this.IsStats() ?
"stat_layer" :
"text_layer");
3004 .attr(
"width", width)
3005 .attr(
"height", height)
3006 .attr(
"transform",
"translate(" + pos_x +
"," + pos_y +
")");
3009 if ((lwidth > 1) && (pt.fShadowColor > 0))
3010 this.draw_g.append(
"svg:path")
3011 .attr(
"d",
"M" + width +
"," + height +
3012 " v" + (-height + lwidth) +
" h" + lwidth +
3013 " v" + height +
" h" + (-width) +
3014 " v" + (-lwidth) +
" Z")
3015 .style(
"fill", JSROOT.Painter.root_colors[pt.fShadowColor])
3016 .style(
"stroke", JSROOT.Painter.root_colors[pt.fShadowColor])
3017 .style(
"stroke-width",
"1px");
3019 if (this.lineatt === undefined)
3020 this.lineatt = JSROOT.Painter.createAttLine(pt, lwidth>0 ? 1 : 0);
3021 if (this.fillatt === undefined)
3022 this.fillatt = this.createAttFill(pt);
3024 this.draw_g.append(
"rect")
3027 .attr(
"width", width)
3028 .attr(
"height", height)
3029 .style(
"pointer-events",
"visibleFill")
3030 .call(this.fillatt.func)
3031 .call(this.lineatt.func);
3033 if (
'PaveDrawFunc' in
this)
3034 this.PaveDrawFunc(width, height, refill);
3036 this.AddDrag({ obj: pt, redraw: this.DrawPave.bind(
this), ctxmenu: JSROOT.touches && JSROOT.gStyle.ContextMenu && this.UseContextMenu });
3038 if (this.UseContextMenu && JSROOT.gStyle.ContextMenu)
3039 this.draw_g.on(
"contextmenu", this.ShowContextMenu.bind(
this) );
3042 JSROOT.TPavePainter.prototype.DrawPaveLabel =
function(width, height) {
3043 this.UseTextColor =
true;
3045 var pave = this.GetObject();
3047 this.StartTextDrawing(pave.fTextFont, height/1.2);
3049 this.DrawText(pave.fTextAlign, 0, 0, width, height, pave.fLabel, JSROOT.Painter.root_colors[pave.fTextColor]);
3051 this.FinishTextDrawing();
3054 JSROOT.TPavePainter.prototype.DrawPaveText =
function(width, height, refill) {
3056 if (refill && this.IsStats()) this.FillStatistic();
3058 var pt = this.GetObject(),
3059 tcolor = JSROOT.Painter.root_colors[pt.fTextColor],
3060 lwidth = pt.fBorderSize,
3063 nlines = pt.fLines.arr.length,
3068 for (var j = 0; j < nlines; ++j) {
3069 var line = pt.fLines.arr[j].fTitle;
3071 if (j>0) maxlen = Math.max(maxlen, line.length);
3072 if (!this.IsStats() || (j == 0) || (line.indexOf(
'|') < 0))
continue;
3073 if (first_stat === 0) first_stat = j;
3074 var parts = line.split(
"|");
3075 if (parts.length > num_cols)
3076 num_cols = parts.length;
3080 var stepy = height / nlines, has_head =
false, margin_x = pt.fMargin * width;
3082 this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2));
3085 this.DrawText(pt.fTextAlign, 0, 0, width, height, lines[0], tcolor);
3086 this.UseTextColor =
true;
3088 for (var j = 0; j < nlines; ++j) {
3090 jcolor = JSROOT.Painter.root_colors[pt.fLines.arr[j].fTextColor];
3091 if ((pt.fLines.arr[j].fTextColor == 0) || (jcolor===undefined)) {
3093 this.UseTextColor =
true;
3096 if (this.IsStats()) {
3097 if ((first_stat > 0) && (j >= first_stat)) {
3098 var parts = lines[j].split(
"|");
3099 for (var n = 0; n < parts.length; ++n)
3100 this.DrawText(
"middle",
3101 width * n / num_cols, posy,
3102 width/num_cols, stepy, parts[n], jcolor);
3103 }
else if (lines[j].indexOf(
'=') < 0) {
3106 if (lines[j].length > maxlen + 5)
3107 lines[j] = lines[j].substr(0,maxlen+2) +
"...";
3109 this.DrawText((j == 0) ?
"middle" :
"start",
3110 margin_x, posy, width-2*margin_x, stepy, lines[j], jcolor);
3112 var parts = lines[j].split(
"="), sumw = 0;
3113 for (var n = 0; n < 2; ++n)
3114 sumw += this.DrawText((n == 0) ?
"start" :
"end",
3115 margin_x, posy, width-2*margin_x, stepy, parts[n], jcolor);
3116 this.TextScaleFactor(1.05*sumw/(width-2*margin_x), this.draw_g);
3119 this.DrawText(pt.fTextAlign, margin_x, posy, width-2*margin_x, stepy, lines[j], jcolor);
3124 var maxtw = this.FinishTextDrawing();
3126 if ((lwidth > 0) && has_head) {
3127 this.draw_g.append(
"svg:line")
3129 .attr(
"y1", stepy.toFixed(1))
3131 .attr(
"y2", stepy.toFixed(1))
3132 .call(this.lineatt.func);
3135 if ((first_stat > 0) && (num_cols > 1)) {
3136 for (var nrow = first_stat; nrow < nlines; ++nrow)
3137 this.draw_g.append(
"svg:line")
3139 .attr(
"y1", (nrow * stepy).toFixed(1))
3141 .attr(
"y2", (nrow * stepy).toFixed(1))
3142 .call(this.lineatt.func);
3144 for (var ncol = 0; ncol < num_cols - 1; ++ncol)
3145 this.draw_g.append(
"svg:line")
3146 .attr(
"x1", (width / num_cols * (ncol + 1)).toFixed(1))
3147 .attr(
"y1", (first_stat * stepy).toFixed(1))
3148 .attr(
"x2", (width / num_cols * (ncol + 1)).toFixed(1))
3150 .call(this.lineatt.func);
3153 if ((pt.fLabel.length>0) && !
this.IsStats()) {
3154 var x = Math.round(width*0.25),
3155 y = Math.round(-height*0.02),
3156 w = Math.round(width*0.5),
3157 h = Math.round(height*0.04);
3159 var lbl_g = this.draw_g.append(
"svg:g");
3161 lbl_g.append(
"rect")
3166 .call(this.fillatt.func)
3167 .call(this.lineatt.func);
3169 this.StartTextDrawing(pt.fTextFont, h/1.5, lbl_g);
3171 this.DrawText(22, x, y, w, h, pt.fLabel, tcolor, 1, lbl_g);
3173 this.FinishTextDrawing(lbl_g);
3175 this.UseTextColor =
true;
3179 JSROOT.TPavePainter.prototype.Format =
function(value, fmt) {
3182 if (!fmt) fmt =
"stat";
3184 var pave = this.GetObject();
3187 fmt = pave.fStatFormat;
3188 if (!fmt) fmt = JSROOT.gStyle.StatFormat;
3191 fmt = pave.fFitFormat;
3192 if (!fmt) fmt = JSROOT.gStyle.FitFormat;
3194 if (fmt==
"entries") {
3195 if (value < 1e9)
return value.toFixed(0);
3199 fmt =
this[
'lastformat'];
3202 delete this[
'lastformat'];
3204 if (!fmt) fmt =
"6.4g";
3206 var res = JSROOT.FFormat(value, fmt);
3208 this[
'lastformat'] = JSROOT.lastFFormat;
3213 JSROOT.TPavePainter.prototype.ShowContextMenu =
function(evnt) {
3215 d3.event.stopPropagation();
3216 d3.event.preventDefault();
3222 var pthis =
this, pave = this.GetObject();
3224 JSROOT.Painter.createMenu(
function(menu) {
3225 menu.painter = pthis;
3226 menu.add(
"header: " + pave._typename +
"::" + pave.fName);
3227 if (pthis.IsStats()) {
3229 menu.add(
"SetStatFormat",
function() {
3230 var fmt = prompt(
"Enter StatFormat", pave.fStatFormat);
3232 pave.fStatFormat = fmt;
3236 menu.add(
"SetFitFormat",
function() {
3237 var fmt = prompt(
"Enter FitFormat", pave.fFitFormat);
3239 pave.fFitFormat = fmt;
3243 menu.add(
"separator");
3244 menu.add(
"sub:SetOptStat",
function() {
3246 var fmt = prompt(
"Enter OptStat", pave.fOptStat);
3247 if (fmt!=null) { pave.fOptStat = parseInt(fmt); pthis.Redraw(); }
3249 function AddStatOpt(pos, name) {
3250 var opt = (pos<10) ? pave.fOptStat : pave.fOptFit;
3251 opt = parseInt(parseInt(opt) / parseInt(Math.pow(10,pos % 10))) % 10;
3252 menu.addchk(opt, name, opt * 100 + pos,
function(arg) {
3253 var newopt = (arg % 100 < 10) ? pave.fOptStat : pave.fOptFit;
3254 var oldopt = parseInt(arg / 100);
3255 newopt -= (oldopt>0 ? oldopt : -1) * parseInt(Math.pow(10, arg % 10));
3256 if (arg % 100 < 10) pave.fOptStat = newopt;
3257 else pave.fOptFit = newopt;
3262 AddStatOpt(0,
"Histogram name");
3263 AddStatOpt(1,
"Entries");
3264 AddStatOpt(2,
"Mean");
3265 AddStatOpt(3,
"Std Dev");
3266 AddStatOpt(4,
"Underflow");
3267 AddStatOpt(5,
"Overflow");
3268 AddStatOpt(6,
"Integral");
3269 AddStatOpt(7,
"Skewness");
3270 AddStatOpt(8,
"Kurtosis");
3271 menu.add(
"endsub:");
3273 menu.add(
"sub:SetOptFit",
function() {
3275 var fmt = prompt(
"Enter OptStat", pave.fOptFit);
3276 if (fmt!=null) { pave.fOptFit = parseInt(fmt); pthis.Redraw(); }
3278 AddStatOpt(10,
"Fit parameters");
3279 AddStatOpt(11,
"Par errors");
3280 AddStatOpt(12,
"Chi square / NDF");
3281 AddStatOpt(13,
"Probability");
3282 menu.add(
"endsub:");
3284 menu.add(
"separator");
3287 if (pthis.UseTextColor)
3288 pthis.TextAttContextMenu(menu);
3290 pthis.FillAttContextMenu(menu);
3296 JSROOT.TPavePainter.prototype.IsStats =
function() {
3297 return this.MatchObjectType(
'TPaveStats');
3300 JSROOT.TPavePainter.prototype.FillStatistic =
function() {
3301 var pave = this.GetObject(), main = this.main_painter();
3303 if (pave.fName !==
"stats")
return false;
3304 if ((main===null) || !(
'FillStatistic' in main))
return false;
3307 if (main.IsDummyHisto())
return true;
3309 var dostat =
new Number(pave.fOptStat);
3310 var dofit =
new Number(pave.fOptFit);
3311 if (!dostat) dostat = JSROOT.gStyle.OptStat;
3312 if (!dofit) dofit = JSROOT.gStyle.OptFit;
3318 main.FillStatistic(
this, dostat, dofit);
3323 JSROOT.TPavePainter.prototype.UpdateObject =
function(obj) {
3324 if (!this.MatchObjectType(obj))
return false;
3326 var pave = this.GetObject();
3328 if (obj._typename ===
'TPaveText') {
3329 pave.fLines = JSROOT.clone(obj.fLines);
3332 if (obj._typename ===
'TPaveLabel') {
3333 pave.fLabel = obj.fLabel;
3340 JSROOT.TPavePainter.prototype.Redraw =
function() {
3343 this.DrawPave(
true);
3346 JSROOT.Painter.drawPaveText =
function(divid, pave, opt) {
3348 var painter =
new JSROOT.TPavePainter(pave);
3349 painter.SetDivId(divid, 2);
3351 if ((typeof opt ==
'string') && (opt.indexOf(
"onpad:")==0))
3352 painter.pad_name = opt.substr(6);
3354 switch (pave._typename) {
3356 painter.PaveDrawFunc = painter.DrawPaveLabel;
3360 painter.PaveDrawFunc = painter.DrawPaveText;
3366 return painter.DrawingReady();
3371 JSROOT.TPadPainter =
function(pad, iscan) {
3372 JSROOT.TObjectPainter.call(
this, pad);
3375 this.this_pad_name =
"";
3376 if (!this.iscan && (pad !== null) && (
'fName' in pad))
3377 this.this_pad_name = pad.fName.replace(
" ",
"_");
3378 this.painters =
new Array;
3379 this.has_canvas =
true;
3382 JSROOT.TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
3384 JSROOT.TPadPainter.prototype.ButtonSize =
function(fact) {
3385 return Math.round((!fact ? 1 : fact) * (this.iscan || !this.has_canvas ? 16 : 12));
3388 JSROOT.TPadPainter.prototype.CreateCanvasSvg =
function(check_resize, new_size) {
3390 var render_to = this.select_main();
3392 var rect = this.main_visible_rect();
3395 var w = rect.width, h = rect.height;
3397 if ((typeof new_size ==
'object') && (new_size!==null) && (
'width' in new_size) && (
'height' in new_size)) {
3399 h = new_size.height;
3402 var factor = null, svg = null;
3404 if (check_resize > 0) {
3406 svg = this.svg_canvas();
3408 var oldw = svg.property(
'draw_width'), oldh = svg.property(
'draw_height');
3410 if ((w<=0) && (h<=0)) {
3411 svg.attr(
"visibility",
"hidden");
3414 svg.attr(
"visibility",
"visible");
3415 svg.select(
".canvas_fillrect")
3416 .call(this.fillatt.func);
3419 if (check_resize == 1) {
3420 if ((oldw == w) && (oldh == h))
return false;
3423 factor = svg.property(
'height_factor');
3425 if (factor != null) {
3427 h = Math.round(w * factor);
3428 render_to.style(
'height', h+
'px');
3431 if ((check_resize==1) && (oldw>0) && (oldh>0) && !svg.property(
'redraw_by_resize'))
3432 if ((w/oldw>0.66) && (w/oldw<1.5) && (h/oldh>0.66) && (h/oldh<1.5)) {
3440 if ((h < 10) && (w > 0)) {
3446 if ((this.pad!==null) && (
'fCw' in this.pad) && (
'fCh' in this.pad) && (this.pad.fCw > 0)) {
3447 factor = this.pad.fCh / this.pad.fCw;
3448 if ((factor < 0.1) || (factor > 10))
3452 h = Math.round(w * factor);
3454 render_to.style(
'height', h+
'px');
3457 svg = this.select_main()
3459 .attr(
"class",
"jsroot root_canvas")
3460 .property(
'pad_painter',
this)
3461 .property(
'mainpainter', null)
3462 .property(
'current_pad',
"")
3463 .property(
'redraw_by_resize',
false);
3465 svg.append(
"svg:title").text(
"ROOT canvas");
3466 svg.append(
"svg:rect").attr(
"class",
"canvas_fillrect").attr(
"x",0).attr(
"y",0);
3467 svg.append(
"svg:g").attr(
"class",
"root_frame");
3468 svg.append(
"svg:g").attr(
"class",
"subpads_layer");
3469 svg.append(
"svg:g").attr(
"class",
"special_layer");
3470 svg.append(
"svg:g").attr(
"class",
"text_layer");
3471 svg.append(
"svg:g").attr(
"class",
"stat_layer");
3472 svg.append(
"svg:g").attr(
"class",
"btns_layer");
3474 this.fillatt = this.createAttFill(this.pad, 1001, 0);
3476 if (JSROOT.gStyle.ContextMenu)
3477 svg.select(
".canvas_fillrect").on(
"contextmenu", this.ShowContextMenu.bind(
this));
3480 if ((w<=0) || (h<=0)) {
3481 svg.attr(
"visibility",
"hidden");
3484 svg.attr(
"visibility",
"visible");
3489 .attr(
"width",
"100%")
3490 .attr(
"height",
"100%")
3491 .attr(
"viewBox",
"0 0 " + w +
" " + h)
3492 .attr(
"preserveAspectRatio",
"none")
3493 .property(
'height_factor', factor)
3494 .property(
'draw_x', 0)
3495 .property(
'draw_y', 0)
3496 .property(
'draw_width', w)
3497 .property(
'draw_height', h);
3499 svg.select(
".canvas_fillrect")
3502 .call(this.fillatt.func);
3504 this.svg_layer(
"btns_layer").attr(
"transform",
"translate(2," + (h-this.ButtonSize(1.25)) +
")");
3509 JSROOT.TPadPainter.prototype.CreatePadSvg =
function(only_resize) {
3510 if (!this.has_canvas)
3511 return this.CreateCanvasSvg(only_resize ? 2 : 0);
3513 var width = this.svg_canvas().property(
"draw_width"),
3514 height = this.svg_canvas().property(
"draw_height"),
3515 w = Math.round(this.pad.fAbsWNDC * width),
3516 h = Math.round(this.pad.fAbsHNDC * height),
3517 x = Math.round(this.pad.fAbsXlowNDC * width),
3518 y = Math.round(height - this.pad.fAbsYlowNDC * height) - h;
3520 var svg_pad = null, svg_rect = null, btns = null;
3523 svg_pad = this.svg_pad(this.this_pad_name);
3524 svg_rect = svg_pad.select(
".root_pad_border");
3525 btns = this.svg_layer(
"btns_layer", this.this_pad_name);
3527 svg_pad = this.svg_canvas().select(
".subpads_layer")
3529 .attr(
"class",
"root_pad")
3530 .attr(
"pad", this.this_pad_name)
3531 .property(
'pad_painter',
this)
3532 .property(
'mainpainter', null);
3533 svg_rect = svg_pad.append(
"svg:rect").attr(
"class",
"root_pad_border");
3534 svg_pad.append(
"svg:g").attr(
"class",
"root_frame");
3535 svg_pad.append(
"svg:g").attr(
"class",
"special_layer");
3536 svg_pad.append(
"svg:g").attr(
"class",
"text_layer");
3537 svg_pad.append(
"svg:g").attr(
"class",
"stat_layer");
3538 btns = svg_pad.append(
"svg:g").attr(
"class",
"btns_layer").property(
'nextx', 0);
3540 if (JSROOT.gStyle.ContextMenu)
3541 svg_pad.select(
".root_pad_border").on(
"contextmenu", this.ShowContextMenu.bind(
this));
3543 this.fillatt = this.createAttFill(this.pad, 1001, 0);
3544 this.lineatt = JSROOT.Painter.createAttLine(this.pad)
3545 if (this.pad.fBorderMode == 0) this.lineatt.color =
'none';
3548 svg_pad.attr(
"transform",
"translate(" + x +
"," + y +
")")
3549 .property(
'draw_x', x)
3550 .property(
'draw_y', y)
3551 .property(
'draw_width', w)
3552 .property(
'draw_height', h);
3554 svg_rect.attr(
"x", 0)
3558 .call(this.fillatt.func)
3559 .call(this.lineatt.func);
3561 btns.attr(
"transform",
"translate("+ (w- btns.property(
'nextx') - this.ButtonSize(0.25)) +
"," + (h-this.ButtonSize(1.25)) +
")");
3564 JSROOT.TPadPainter.prototype.CheckColors =
function(can) {
3565 if (can==null)
return;
3566 for (var i = 0; i < can.fPrimitives.arr.length; ++i) {
3567 var obj = can.fPrimitives.arr[i];
3568 if (obj==null)
continue;
3569 if ((obj._typename==
"TObjArray") && (obj.name ==
"ListOfColors")) {
3570 JSROOT.Painter.adoptRootColors(obj);
3571 can.fPrimitives.arr.splice(i,1);
3572 can.fPrimitives.opt.splice(i,1);
3578 JSROOT.TPadPainter.prototype.RemovePrimitive =
function(obj) {
3579 if ((this.pad===null) || (this.pad.fPrimitives === null))
return;
3580 var indx = this.pad.fPrimitives.arr.indexOf(obj);
3581 if (indx>=0) this.pad.fPrimitives.RemoveAt(indx);
3584 JSROOT.TPadPainter.prototype.FindPrimitive =
function(exact_obj, classname, name) {
3585 if ((this.pad===null) || (this.pad.fPrimitives === null))
return null;
3587 for (var i=0; i < this.pad.fPrimitives.arr.length; i++) {
3588 var obj = this.pad.fPrimitives.arr[i];
3590 if ((exact_obj!==null) && (obj !== exact_obj))
continue;
3592 if ((classname !== undefined) && (classname !== null))
3593 if (obj._typename !== classname)
continue;
3595 if ((name !== undefined) && (name !== null))
3596 if (obj.fName !== name)
continue;
3604 JSROOT.TPadPainter.prototype.HasObjectsToDraw =
function() {
3607 if ((this.pad===null) || !this.pad.fPrimitives || (this.pad.fPrimitives.arr.length==0))
return false;
3609 for (var n=0;n<this.pad.fPrimitives.arr.length;++n)
3610 if (this.pad.fPrimitives.arr[n] &&
this.pad.fPrimitives.arr[n]._typename !=
"TPad")
return true;
3615 JSROOT.TPadPainter.prototype.DrawPrimitive =
function(indx, callback) {
3616 if ((this.pad===null) || (indx >= this.pad.fPrimitives.arr.length))
3617 return JSROOT.CallBack(callback);
3619 var pp = JSROOT.draw(this.divid, this.pad.fPrimitives.arr[indx],
this.pad.fPrimitives.opt[indx]);
3621 if (pp === null)
return this.DrawPrimitive(indx+1, callback);
3623 pp._primitive =
true;
3624 pp.WhenReady(this.DrawPrimitive.bind(
this, indx+1, callback));
3628 JSROOT.TPadPainter.prototype.GetTooltips =
function(pnt) {
3629 var painters = [], hints = [];
3632 if (this.painters !== null)
3633 this.painters.forEach(
function(obj) {
3634 if (
'ProcessTooltip' in obj) painters.push(obj);
3637 if (pnt) pnt.nproc = painters.length;
3639 painters.forEach(
function(obj) {
3640 var hint = obj.ProcessTooltip(pnt);
3642 if (hint && pnt.painters) hint.painter = obj;
3648 JSROOT.TPadPainter.prototype.ShowContextMenu =
function(evnt) {
3652 var pos = d3.mouse(this.svg_pad(this.this_pad_name).node());
3653 if (pos && (pos.length==2) && (pos[0]>0) && (pos[0]<10) && (pos[1]>0) && pos[1]<10)
return;
3655 d3.event.stopPropagation();
3656 d3.event.preventDefault();
3664 JSROOT.Painter.createMenu(
function(menu) {
3665 menu.painter = pthis;
3667 menu.add(
"header: " + pthis.pad._typename +
"::" + pthis.pad.fName);
3669 menu.add(
"header: Canvas");
3672 menu.addchk((JSROOT.gStyle.Tooltip > 0),
"Show tooltips",
function() {
3673 JSROOT.gStyle.Tooltip = (JSROOT.gStyle.Tooltip === 0) ? 1 : -JSROOT.gStyle.Tooltip;
3676 pthis.FillAttContextMenu(menu);
3678 menu.add(
"separator");
3680 var file_name =
"canvas.png";
3681 if (!pthis.iscan) file_name = pthis.this_pad_name +
".png";
3683 menu.add(
"Save as "+file_name, file_name,
function(arg) {
3685 var top = this.svg_pad(this.this_pad_name);
3687 JSROOT.AssertPrerequisites(
"savepng",
function() {
3688 console.log(
'create', arg);
3689 top.selectAll(
".btns_layer").style(
"display",
"none");
3690 saveSvgAsPng(top.node(), arg);
3691 top.selectAll(
".btns_layer").style(
"display",
"");
3699 JSROOT.TPadPainter.prototype.Redraw =
function(resize) {
3701 this.CreateCanvasSvg(2);
3703 this.CreatePadSvg(
true);
3706 for (var i = 0; i < this.painters.length; ++i)
3707 this.painters[i].Redraw(resize);
3710 JSROOT.TPadPainter.prototype.NumDrawnSubpads =
function() {
3711 if (this.painters === undefined)
return 0;
3715 for (var i = 0; i < this.painters.length; ++i) {
3716 var obj = this.painters[i].GetObject();
3717 if ((obj!==null) && (obj._typename ===
"TPad")) num++;
3723 JSROOT.TPadPainter.prototype.CheckCanvasResize =
function(size, force) {
3724 if (!this.iscan)
return false;
3726 if ((size !== null) && (typeof size ===
'object') && size.force) force =
true;
3728 var changed = this.CreateCanvasSvg(force ? 2 : 1, size);
3732 for (var i = 0; i < this.painters.length; ++i)
3733 this.painters[i].Redraw(
true);
3738 JSROOT.TPadPainter.prototype.UpdateObject =
function(obj) {
3740 if ((obj == null) || !(
'fPrimitives' in obj))
return false;
3742 if (this.iscan) this.CheckColors(obj);
3744 if (obj.fPrimitives.arr.length !==
this.pad.fPrimitives.arr.length)
return false;
3746 var isany =
false, p = 0;
3747 for (var n = 0; n < obj.fPrimitives.arr.length; ++n) {
3748 while (p < this.painters.length) {
3749 var pp = this.painters[p++];
3750 if (!(
'_primitive' in pp))
continue;
3751 if (pp.UpdateObject(obj.fPrimitives.arr[n])) isany =
true;
3759 JSROOT.TPadPainter.prototype.ItemContextMenu =
function(name) {
3760 var rrr = this.svg_pad(this.this_pad_name).node().getBoundingClientRect();
3761 var evnt = { clientX: rrr.left+10, clientY: rrr.top + 10 };
3765 return setTimeout(this.ShowContextMenu.bind(
this, evnt), 50);
3767 var selp = null, selkind;
3770 case "xaxis": selp = this.main_painter(); selkind =
"x";
break;
3771 case "yaxis": selp = this.main_painter(); selkind =
"y";
break;
3772 case "frame": selp = this.frame_painter();
break;
3774 var indx = parseInt(name);
3775 if (!isNaN(indx)) selp = this.painters[indx];
3779 if (!selp || (typeof selp.FillContextMenu !==
'function'))
return;
3781 JSROOT.Painter.createMenu(
function(menu) {
3782 menu.painter = selp;
3783 if (selp.FillContextMenu(menu,selkind))
3784 setTimeout(menu.show.bind(menu, evnt), 50);
3789 JSROOT.TPadPainter.prototype.PadButtonClick =
function(funcname) {
3791 var elem = null, filename =
"";
3793 if (funcname ==
"CanvasSnapShot") {
3794 elem = this.svg_canvas();
3795 filename = (this.pad ? this.pad.fName :
"jsroot_canvas") +
".png";
3797 if (funcname ==
"PadSnapShot") {
3798 elem = this.svg_pad(this.this_pad_name);
3799 filename = this.this_pad_name +
".png";
3801 if ((elem!==null) && !elem.empty()) {
3802 var main = elem.property(
'mainpainter');
3804 if ((elem.property(
'can3d') === 1) && (main!==undefined) && (main.renderer!==undefined)) {
3805 var dataUrl = main.renderer.domElement.toDataURL(
"image/png");
3806 dataUrl.replace(
"image/png",
"image/octet-stream");
3807 var link = document.createElement(
'a');
3808 if (typeof link.download ===
'string') {
3809 document.body.appendChild(link);
3810 link.download = filename;
3811 link.href = dataUrl;
3813 document.body.removeChild(link);
3816 JSROOT.AssertPrerequisites(
"savepng",
function() {
3817 elem.selectAll(
".btns_layer").style(
"display",
"none");
3818 saveSvgAsPng(elem.node(), filename);
3819 elem.selectAll(
".btns_layer").style(
"display",
"");
3825 if (funcname ==
"PadContextMenus") {
3827 var pthis =
this, evnt = d3.event;
3829 d3.event.preventDefault();
3830 d3.event.stopPropagation();
3832 JSROOT.Painter.createMenu(
function(menu) {
3833 menu.painter = pthis;
3834 menu.add(
"header:Menus");
3837 menu.add(
"Canvas",
"pad", pthis.ItemContextMenu);
3839 menu.add(
"Pad",
"pad", pthis.ItemContextMenu);
3841 if (pthis.frame_painter())
3842 menu.add(
"Frame",
"frame", pthis.ItemContextMenu);
3844 if (pthis.main_painter()) {
3845 menu.add(
"X axis",
"xaxis", pthis.ItemContextMenu);
3846 menu.add(
"Y axis",
"yaxis", pthis.ItemContextMenu);
3849 if (pthis.painters && (pthis.painters.length>0)) {
3850 menu.add(
"separator");
3852 for (var n=0;n<pthis.painters.length;++n) {
3853 var pp = pthis.painters[n];
3854 var obj = pp ? pp.GetObject() : null;
3855 if (!obj || (shown.indexOf(obj)>=0))
continue;
3857 var name = (
'_typename' in obj) ? (obj._typename +
"::") :
"";
3858 if (
'fName' in obj) name += obj.fName;
3859 if (name.length==0) name =
"item" + n;
3860 menu.add(name, n, pthis.ItemContextMenu);
3874 for (var i = 0; i < this.painters.length; ++i) {
3875 var pp = this.painters[i];
3877 if (typeof pp.PadButtonClick ==
'function')
3878 pp.PadButtonClick(funcname);
3880 if (!done && (typeof pp.ButtonClick ==
'function'))
3881 done = pp.ButtonClick(funcname);
3885 JSROOT.TPadPainter.prototype.AddButton =
function(btn, tooltip, funcname) {
3888 if (!JSROOT.gStyle.ToolBar)
return;
3890 var group = this.svg_layer(
"btns_layer", this.this_pad_name);
3891 if (group.empty())
return;
3894 if (!group.select(
"[name=" + funcname +
']').empty())
return;
3896 var x = group.property(
"nextx");
3897 if (x===undefined) x = 0;
3899 var iscan = this.iscan || !this.has_canvas;
3901 var svg = group.append(
"svg:svg")
3902 .attr(
"class",
"svg_toolbar_btn")
3903 .attr(
"name", funcname)
3906 .attr(
"width",this.ButtonSize()+
"px")
3907 .attr(
"height",this.ButtonSize()+
"px")
3908 .attr(
"viewBox",
"0 0 512 512")
3909 .style(
"overflow",
"hidden");
3911 svg.append(
"svg:title").text(tooltip + (iscan ?
"" : (
" on pad " + this.this_pad_name)));
3913 if (
'recs' in btn) {
3915 for (var n=0;n<btn.recs.length;++n) {
3916 JSROOT.extend(rec, btn.recs[n]);
3917 svg.append(
'rect').attr(
"x", rec.x).attr(
"y", rec.y)
3918 .attr(
"width", rec.w).attr(
"height", rec.h)
3919 .attr(
"fill", rec.f);
3922 svg.append(
'svg:path').attr(
'd',btn.path);
3926 svg.append(
"svg:rect").attr(
"x",0).attr(
"y",0).attr(
"width",512).attr(
"height",512)
3927 .style(
"opacity",
"0").style(
"fill",
"none").style(
"pointer-events",
"visibleFill");
3929 svg.on(
"click", this.PadButtonClick.bind(
this, funcname));
3931 group.property(
"nextx", x+this.ButtonSize(1.25));
3934 group.attr(
"transform",
"translate("+ (this.pad_width(this.this_pad_name) - group.property(
'nextx')-this.ButtonSize(0.25)) +
"," + (this.pad_height(this.this_pad_name)-this.ButtonSize(1.25)) +
")");
3936 if (!iscan && (funcname.indexOf(
"Pad")!=0) && (this.pad_painter()!==
this))
3937 this.pad_painter().AddButton(btn, tooltip, funcname);
3940 JSROOT.Painter.drawCanvas =
function(divid, can, opt) {
3941 var painter =
new JSROOT.TPadPainter(can,
true);
3942 if (can && opt && (opt.indexOf(
"white")>=0)) can.fFillColor = 0;
3944 painter.SetDivId(divid, -1);
3945 painter.CheckColors(can);
3946 painter.CreateCanvasSvg(0);
3947 painter.SetDivId(divid);
3949 painter.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"CanvasSnapShot");
3950 painter.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
3953 if (opt.indexOf(
"noframe") < 0)
3954 JSROOT.Painter.drawFrame(divid, null);
3955 return painter.DrawingReady();
3958 painter.DrawPrimitive(0,
function() { painter.DrawingReady(); });
3962 JSROOT.Painter.drawPad =
function(divid, pad, opt) {
3963 var painter =
new JSROOT.TPadPainter(pad,
false);
3965 if (pad && opt && (opt.indexOf(
"white")>=0)) pad.fFillColor = 0;
3967 painter.SetDivId(divid);
3969 if (painter.svg_canvas().empty()) {
3970 painter.has_canvas =
false;
3971 painter.this_pad_name =
"";
3974 painter.CreatePadSvg();
3976 if (painter.MatchObjectType(
"TPad") && (!painter.has_canvas || painter.HasObjectsToDraw())) {
3977 painter.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"PadSnapShot");
3978 painter.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
3983 if (painter.has_canvas) {
3985 prev_name = painter.svg_canvas().property(
'current_pad');
3986 painter.svg_canvas().property(
'current_pad', pad.fName);
3989 painter.DrawPrimitive(0,
function() {
3991 painter.svg_canvas().property(
'current_pad', prev_name);
3992 painter.DrawingReady();
4000 JSROOT.TAxisPainter =
function(axis, embedded) {
4001 JSROOT.TObjectPainter.call(
this, axis);
4003 this.embedded = embedded;
4005 this.name =
"yaxis";
4006 this.kind =
"normal";
4017 JSROOT.TAxisPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
4019 JSROOT.TAxisPainter.prototype.SetAxisConfig =
function(name, kind, func, min, max, smin, smax) {
4024 this.full_min = min;
4025 this.full_max = max;
4026 this.scale_min = smin;
4027 this.scale_max = smax;
4030 JSROOT.TAxisPainter.prototype.CreateFormatFuncs =
function() {
4032 var axis = this.GetObject(),
4033 is_gaxis = (axis && axis._typename ===
'TGaxis');
4039 ndiv = Math.max(is_gaxis ? axis.fNdiv : axis.fNdivisions, 4) ;
4041 this.nticks = ndiv % 100;
4042 this.nticks2 = (ndiv % 10000 - this.nticks) / 100;
4043 this.nticks3 = Math.floor(ndiv/10000);
4045 if (axis && !is_gaxis && (this.nticks > 7)) this.nticks = 7;
4047 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
4048 if (gr_range<=0) gr_range = 100;
4050 if (this.kind ==
'time') {
4051 if (this.nticks > 8) this.nticks = 8;
4053 var scale_range = this.scale_max - this.scale_min;
4055 var tf1 = JSROOT.Painter.getTimeFormat(axis);
4056 if ((tf1.length == 0) || (scale_range < 0.1 * (
this.full_max -
this.full_min)))
4057 tf1 = JSROOT.Painter.chooseTimeFormat(scale_range / this.nticks,
true);
4058 var tf2 = JSROOT.Painter.chooseTimeFormat(scale_range / gr_range,
false);
4060 this.tfunc1 = this.tfunc2 = d3.time.format(tf1);
4062 this.tfunc2 = d3.time.format(tf2);
4064 this.format =
function(d, asticks) {
4065 return asticks ? this.tfunc1(d) : this.tfunc2(d);
4069 if (this.kind ==
'log') {
4071 this.noexp = axis ? axis.TestBit(JSROOT.EAxisBits.kNoExponent) :
false;
4072 if ((this.scale_max < 300) && (this.scale_min > 0.3)) this.noexp =
true;
4073 this.moreloglabels = axis ? axis.TestBit(JSROOT.EAxisBits.kMoreLogLabels) :
false;
4075 this.format =
function(d, asticks, notickexp) {
4077 var val = parseFloat(d);
4080 var rnd = Math.round(val);
4081 return ((rnd === val) && (Math.abs(rnd)<1e9)) ? rnd.toString() : val.toExponential(4);
4084 if (val <= 0)
return null;
4085 var vlog = JSROOT.log10(val);
4086 if (this.moreloglabels || (Math.abs(vlog - Math.round(vlog))<0.001)) {
4087 if (!this.noexp && !notickexp)
4088 return JSROOT.Painter.formatExp(val.toExponential(0));
4091 return val.toFixed(Math.round(-vlog+0.5));
4093 return val.toFixed(0);
4098 if (this.kind ==
'labels') {
4100 var scale_range = this.scale_max - this.scale_min;
4101 if (this.nticks > scale_range)
4102 this.nticks = Math.round(scale_range);
4107 this.format =
function(d) {
4108 var indx = Math.round(parseInt(d)) + 1;
4109 if ((indx<1) || (indx>this.axis.fNbins))
return null;
4110 for (var i = 0; i < this.axis.fLabels.arr.length; ++i) {
4111 var tstr = this.axis.fLabels.arr[i];
4112 if (tstr.fUniqueID == indx)
return tstr.fString;
4118 this.range = Math.abs(this.scale_max - this.scale_min);
4119 if (this.range <= 0)
4122 this.ndig = Math.round(JSROOT.log10(
this.nticks /
this.range) + 0.7);
4124 this.format =
function(d, asticks) {
4125 var val = parseFloat(d), rnd = Math.round(val);
4127 if (this.order===0) {
4128 if (val === rnd)
return rnd.toString();
4129 if (Math.abs(val) < 1e-10 * this.range)
return 0;
4130 val = val.toFixed(this.ndig > 0 ? this.ndig : 0);
4131 if ((typeof d ==
'string') && (d.length <= val.length+1))
return d;
4134 val = val / Math.pow(10, this.order);
4135 rnd = Math.round(val);
4136 if (val === rnd)
return rnd.toString();
4137 return val.toFixed(this.ndig + this.order > 0 ? this.ndig + this.order : 0 );
4141 return (Math.abs(rnd)<1e9) ? rnd.toString() : val.toExponential(4);
4142 return val.toFixed(this.ndig+2 > 0 ? this.ndig+2 : 0);
4147 JSROOT.TAxisPainter.prototype.CreateTicks =
function() {
4150 var handle = { nminor: 0, nmiddle: 0, nmajor: 0, func: this.func };
4152 handle.minor = handle.middle = handle.major = this.func.ticks(this.nticks);
4154 if (this.nticks2 > 1) {
4155 handle.minor = handle.middle = this.func.ticks(handle.major.length *
this.nticks2);
4157 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
4160 if ((handle.middle.length <= handle.major.length) || (handle.middle.length > gr_range/3.5)) {
4161 handle.minor = handle.middle = handle.major;
4163 if ((this.nticks3 > 1) && (this.kind !==
'log')) {
4164 handle.minor = this.func.ticks(handle.middle.length *
this.nticks3);
4165 if ((handle.minor.length <= handle.middle.length) || (handle.minor.length > gr_range/1.7)) handle.minor = handle.middle;
4169 handle.reset =
function() {
4170 this.nminor = this.nmiddle = this.nmajor = 0;
4173 handle.next =
function(doround) {
4174 if (this.nminor >= this.minor.length)
return false;
4176 this.tick = this.minor[this.nminor++];
4177 this.grpos = this.func(this.tick);
4178 if (doround) this.grpos = Math.round(this.grpos);
4181 if ((this.nmiddle < this.middle.length) && (Math.abs(
this.grpos -
this.func(
this.middle[
this.nmiddle])) < 1)) {
4186 if ((this.nmajor < this.major.length) && (Math.abs(this.grpos - this.func(this.major[this.nmajor])) < 1) ) {
4193 handle.last_major =
function() {
4194 return (this.kind !== 1) ?
false : this.nmajor == this.major.length;
4200 JSROOT.TAxisPainter.prototype.DrawAxis =
function(layer, w, h, transform, reverse) {
4204 var axis = this.GetObject(),
4205 is_gaxis = (axis && axis._typename ===
'TGaxis'),
4206 vertical = (this.name !==
"xaxis"),
4207 side = (this.name ===
"zaxis") ? -1 : 1, both_sides = 0,
4208 axis_g = layer, tickSize = 10, scaling_size = 100, text_scaling_size = 100;
4211 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(axis);
4212 scaling_size = (vertical ? this.pad_width() : this.pad_height());
4213 text_scaling_size = Math.min(this.pad_width(), this.pad_height());
4214 tickSize = Math.round(axis.fTickSize * scaling_size);
4216 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(axis.fAxisColor, 1);
4217 scaling_size = (vertical ? w : h);
4218 tickSize = Math.round(axis.fTickLength * scaling_size);
4219 text_scaling_size = Math.min(w,h);
4222 if (!is_gaxis || (this.name ===
"zaxis")) {
4223 axis_g = layer.select(
"." + this.name +
"_container");
4225 axis_g = layer.append(
"svg:g").attr(
"class",this.name+
"_container");
4227 axis_g.selectAll(
"*").remove();
4230 if ((axis.fChopt.indexOf(
"-")>=0) && (axis.fChopt.indexOf(
"+")<0)) side = -1;
else
4231 if (vertical && axis.fChopt==
"+L") side = -1;
else
4232 if ((axis.fChopt.indexOf(
"-")>=0) && (axis.fChopt.indexOf(
"+")>=0)) { side = 1; both_sides = 1; }
4234 axis_g.append(
"svg:line")
4235 .attr(
"x1",0).attr(
"y1",0)
4236 .attr(
"x1",vertical ? 0 : w)
4237 .attr(
"y1", vertical ? h : 0)
4238 .call(this.lineatt.func);
4241 if (transform!== undefined)
4242 axis_g.attr(
"transform", transform);
4244 this.CreateFormatFuncs();
4246 var center = (this.kind ==
'labels') ||
4247 (this.kind !==
'log' && axis.TestBit(JSROOT.EAxisBits.kCenterLabels));
4249 var res =
"", lastpos = 0, lasth = 0, textscale = 1;
4255 var handle = this.CreateTicks();
4257 while (handle.next(
true)) {
4258 var h1 = Math.round(tickSize/4), h2 = 0;
4260 if (handle.kind < 3)
4261 h1 = Math.round(tickSize/2);
4263 if (handle.kind == 1) {
4265 if (!(
'format' in
this) || (this.format(handle.tick,
true)!==null)) h1 = tickSize;
4266 this.ticks.push(handle.grpos);
4269 if (both_sides > 0) h2 = -h1;
else
4270 if (side < 0) { h2 = -h1; h1 = 0; }
else { h2 = 0; }
4272 if (res.length == 0) {
4273 res += vertical ? (
"M"+h1+
","+handle.grpos) : (
"M"+handle.grpos+
","+-h1);
4275 res += vertical ? (
"m"+(h1-lasth)+
","+(handle.grpos-lastpos)) : (
"m"+(handle.grpos-lastpos)+
","+(lasth-h1));
4278 res += vertical ? (
"h"+ (h2-h1)) : (
"v"+ (h1-h2));
4280 lastpos = handle.grpos;
4285 axis_g.append(
"svg:path").attr(
"d", res).call(this.lineatt.func);
4287 var last = vertical ? h : 0,
4288 labelfont = JSROOT.Painter.getFontDetails(axis.fLabelFont, Math.round(axis.fLabelSize * (is_gaxis ?
this.pad_height() : h))),
4289 label_color = JSROOT.Painter.root_colors[axis.fLabelColor],
4290 labeloffset = 3 + Math.round(axis.fLabelOffset * scaling_size),
4291 label_g = axis_g.append(
"svg:g")
4292 .attr(
"class",
"axis_labels")
4293 .call(labelfont.func);
4296 if ((this.kind==
"normal") && vertical && !axis.TestBit(JSROOT.EAxisBits.kNoExponent)) {
4297 var maxtick = Math.max(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1]));
4298 for(var order=18;order>-18;order-=3) {
4299 if (order===0)
continue;
4300 if ((order<0) && ((this.range>=0.1) || (maxtick>=1.)))
break;
4301 var mult = Math.pow(10, order);
4302 if ((this.range > mult * 9.99999) || ((maxtick > mult*50) && (this.range > mult * 0.05))) {
4309 for (var nmajor=0;nmajor<handle.major.length;++nmajor) {
4310 var pos = Math.round(this.func(handle.major[nmajor]));
4311 var lbl = this.format(handle.major[nmajor],
true);
4312 if (lbl === null)
continue;
4314 var t = label_g.append(
"svg:text").attr(
"fill", label_color).text(lbl);
4317 t.attr(
"x", -labeloffset*side)
4319 .style(
"text-anchor", (side > 0) ?
"end" :
"start")
4320 .style(
"dominant-baseline",
"middle");
4323 .attr(
"y", 2+labeloffset*side + both_sides*tickSize)
4324 .attr(
"dy", (side > 0) ?
".7em" :
"-.3em")
4325 .style(
"text-anchor",
"middle");
4327 var tsize = this.GetBoundarySizes(t.node());
4328 var space_before = (nmajor > 0) ? (pos - last) : (vertical ? h/2 : w/2);
4329 var space_after = (nmajor < handle.major.length-1) ? (Math.round(
this.func(handle.major[nmajor+1])) - pos) : space_before;
4330 var space = Math.min(Math.abs(space_before), Math.abs(space_after));
4334 if ((space > 0) && (tsize.height > 5) && (this.kind !==
'log'))
4335 textscale = Math.min(textscale, space / tsize.height);
4339 if (pos + space_after/2 - textscale*tsize.height/2 < -10)
4342 t.attr(
"y", Math.round(pos + space_after/2));
4348 if ((space > 0) && (tsize.width > 10) && (this.kind !==
'log'))
4349 textscale = Math.min(textscale, space / tsize.width);
4353 if (pos + space_after/2 - textscale*tsize.width/2 > w - 10)
4356 t.attr(
"x", Math.round(pos + space_after/2));
4363 if (this.order!==0) {
4364 var val = Math.pow(10,this.order).toExponential(0);
4366 var t = label_g.append(
"svg:text").attr(
"fill", label_color).text(
'\xD7' + JSROOT.Painter.formatExp(val));
4369 t.attr(
"x", labeloffset)
4371 .style(
"text-anchor",
"start")
4372 .style(
"dominant-baseline",
"middle")
4373 .attr(
"dy",
"-.5em");
4377 if ((textscale>0) && (textscale<1.)) {
4379 if ((textscale < 0.7) && !vertical && (side>0)) {
4380 label_g.selectAll(
"text").each(
function() {
4381 var txt = d3.select(
this), x = txt.attr(
"x"), y = txt.attr(
"y") - 5;
4383 txt.attr(
"transform",
"translate(" + x +
"," + y +
") rotate(25)")
4384 .style(
"text-anchor",
"start")
4385 .attr(
"x",null).attr(
"y",null);
4390 labelfont.size = Math.floor(labelfont.size * textscale + 0.7);
4391 label_g.call(labelfont.func);
4394 if (axis.fTitle.length > 0) {
4395 var title_g = axis_g.append(
"svg:g").attr(
"class",
"axis_title"),
4396 title_fontsize = Math.round(axis.fTitleSize * text_scaling_size),
4397 center = axis.TestBit(JSROOT.EAxisBits.kCenterTitle),
4398 rotate = axis.TestBit(JSROOT.EAxisBits.kRotateTitle) ? -1 : 1,
4399 title_color = JSROOT.Painter.root_colors[axis.fTitleColor];
4401 this.StartTextDrawing(axis.fTitleFont, title_fontsize, title_g);
4403 var myxor = ((rotate<0) && !reverse) || ((rotate>=0) && reverse);
4406 var xoffset = -side*Math.round(labeloffset + (2-side/10) * axis.fTitleOffset*title_fontsize);
4408 if ((this.name ==
"zaxis") && is_gaxis && (
'getBoundingClientRect' in axis_g.node())) {
4410 var rect = axis_g.node().getBoundingClientRect();
4411 if (xoffset < rect.width - tickSize) xoffset = Math.round(rect.width - tickSize);
4414 this.DrawText((center ?
"middle" : (myxor ?
"begin" :
"end" ))+
";middle",
4416 Math.round(center ? h/2 : (reverse ? h : 0)),
4417 0, (rotate<0 ? -90 : -270),
4418 axis.fTitle, title_color, 1, title_g);
4420 this.DrawText((center ?
'middle' : (myxor ?
'begin' :
'end')) +
";middle",
4421 Math.round(center ? w/2 : (reverse ? 0 : w)),
4422 Math.round(side*(labeloffset + 1.9*title_fontsize*axis.fTitleOffset)),
4423 0, (rotate<0 ? -180 : 0),
4424 axis.fTitle, title_color, 1, title_g);
4427 this.FinishTextDrawing(title_g);
4431 if (JSROOT.gStyle.Zooming) {
4432 var r = axis_g.append(
"svg:rect")
4433 .attr(
"class",
"axis_zoom")
4434 .style(
"opacity",
"0")
4435 .style(
"cursor",
"crosshair");
4438 r.attr(
"x", (side >0) ? (-2*labelfont.size - 3) : 3)
4440 .attr(
"width", 2*labelfont.size + 3)
4443 r.attr(
"x", 0).attr(
"y", 0)
4444 .attr(
"width", w).attr(
"height", labelfont.size + 3);
4449 if (
'getBoundingClientRect' in axis_g.node()) {
4450 var rect1 = axis_g.node().getBoundingClientRect(),
4451 rect2 = this.svg_pad().node().getBoundingClientRect();
4453 this.position = rect1.left - rect2.left;
4457 JSROOT.TAxisPainter.prototype.Redraw =
function() {
4459 var gaxis = this.GetObject(),
4460 x1 = Math.round(this.AxisToSvg(
"x", gaxis.fX1)),
4461 y1 = Math.round(this.AxisToSvg(
"y", gaxis.fY1)),
4462 x2 = Math.round(this.AxisToSvg(
"x", gaxis.fX2)),
4463 y2 = Math.round(this.AxisToSvg(
"y", gaxis.fY2)),
4464 w = x2 - x1, h = y1 - y2;
4466 var name = w<5 ?
"yaxis" :
"xaxis",
4473 if (gaxis.fChopt.indexOf(
"G")>=0) {
4474 func = d3.scale.log();
4477 func = d3.scale.linear();
4480 func.domain([min, max]);
4482 if (name ==
"yaxis") {
4486 var d = y1; y1 = y2; y2 = d;
4487 h = -h; reverse =
true;
4494 var d = x1; x1 = x2; x2 = d;
4495 w = -w; reverse =
true;
4500 this.SetAxisConfig(name, kind, func, min, max, min, max);
4502 this.RecreateDrawG(
true,
"text_layer");
4504 this.DrawAxis(this.draw_g, w, h,
"translate(" + x1 +
"," + y2 +
")", reverse);
4508 JSROOT.drawGaxis =
function(divid, obj, opt) {
4509 var painter =
new JSROOT.TAxisPainter(obj,
false);
4511 painter.SetDivId(divid);
4515 return painter.DrawingReady();
4521 JSROOT.THistPainter =
function(histo) {
4522 JSROOT.TObjectPainter.call(
this, histo);
4524 this.shrink_frame_left = 0.;
4525 this.draw_content =
true;
4528 this.x_kind =
'normal';
4529 this.y_kind =
'normal';
4532 JSROOT.THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
4534 JSROOT.THistPainter.prototype.IsDummyHisto =
function() {
4535 return (this.histo==null) || !this.draw_content || (this.options.Axis>0);
4538 JSROOT.THistPainter.prototype.IsTProfile =
function() {
4539 return this.MatchObjectType(
'TProfile');
4542 JSROOT.THistPainter.prototype.IsTH2Poly =
function() {
4543 return this.histo && this.histo._typename.match(/^TH2Poly/);
4546 JSROOT.THistPainter.prototype.Dimension =
function() {
4547 if (!this.histo)
return 0;
4548 if (this.histo._typename.indexOf(
"TH2")==0)
return 2;
4549 if (this.histo._typename.indexOf(
"TH3")==0)
return 3;
4553 JSROOT.THistPainter.prototype.DecodeOptions =
function(opt) {
4555 if ((opt == null) || (opt ==
"")) opt = this.histo[
'fOption'];
4558 var hdim = this.Dimension();
4560 Axis: 0, Bar: 0, Curve: 0, Error: 0, Hist: 0, Line: 0,
4561 Mark: 0, Fill: 0, Same: 0, Scat: 0, Func: 0, Star: 0,
4562 Arrow: 0, Box: 0, Text: 0, Char: 0, Color: 0, Contour: 0,
4563 Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0,
4564 Spec: 0, Pie: 0, List: 0, Zscale: 0, FrontBox: 1, BackBox: 1,
4565 System: JSROOT.Painter.Coord.kCARTESIAN,
4566 AutoColor : 0, NoStat : 0, AutoZoom :
false,
4567 HighRes: 0, Zero: 0, Logx: 0, Logy: 0, Logz: 0, Gridx: 0, Gridy: 0,
4568 Palette:0, Optimize:JSROOT.gStyle.OptimizeDraw
4571 var chopt = opt.toUpperCase();
4572 chopt = JSROOT.Painter.clearCuts(chopt);
4577 if ((hdim===1) && (this.histo.fSumw2.length > 0))
4578 for (var n=0;n<this.histo.fSumw2.length;++n)
4579 if (this.histo.fSumw2[n] > 0) { option.Error = 2;
break; }
4581 if (this.histo.fFunctions !== null) option.Func = 1;
4583 var i = chopt.indexOf(
'PAL');
4586 while ((i2<chopt.length) && (chopt.charCodeAt(i2)>=48) && (chopt.charCodeAt(i2)<58)) ++i2;
4588 option.Palette = parseInt(chopt.substring(i+3,i2));
4589 chopt = chopt.replace(chopt.substring(i,i2),
"");
4593 if (chopt.indexOf(
'NOOPTIMIZE') != -1) {
4594 option.Optimize = 0;
4595 chopt = chopt.replace(
'NOOPTIMIZE',
'');
4598 if (chopt.indexOf(
'OPTIMIZE') != -1) {
4599 option.Optimize = 2;
4600 chopt = chopt.replace(
'OPTIMIZE',
'');
4603 if (chopt.indexOf(
'AUTOCOL') != -1) {
4604 option.AutoColor = 1;
4606 chopt = chopt.replace(
'AUTOCOL',
'');
4608 if (chopt.indexOf(
'AUTOZOOM') != -1) {
4609 option.AutoZoom = 1;
4611 chopt = chopt.replace(
'AUTOZOOM',
'');
4613 if (chopt.indexOf(
'NOSTAT') != -1) {
4615 chopt = chopt.replace(
'NOSTAT',
'');
4617 if (chopt.indexOf(
'LOGX') != -1) {
4619 chopt = chopt.replace(
'LOGX',
'');
4621 if (chopt.indexOf(
'LOGY') != -1) {
4623 chopt = chopt.replace(
'LOGY',
'');
4625 if (chopt.indexOf(
'LOGZ') != -1) {
4627 chopt = chopt.replace(
'LOGZ',
'');
4630 chopt = chopt.trim();
4631 while ((chopt.length>0) && (chopt[0]==
',' || chopt[0]==
';')) chopt = chopt.substr(1);
4633 var nch = chopt.length;
4634 if (!nch) option.Hist = 1;
4636 var l = chopt.indexOf(
'SPEC');
4639 chopt = chopt.replace(
'SPEC',
' ');
4641 l = chopt.indexOf(
'BF(');
4642 if (l != -1) bs = parseInt(chopt)
4643 option.Spec = Math.max(1600, bs);
4646 if (chopt.indexOf('GL') != -1) chopt = chopt.replace('GL', ' ');
4647 if (chopt.indexOf('X+') != -1) {
4648 option.AxisPos = 10;
4649 chopt = chopt.replace(
'X+',
' ');
4651 if (chopt.indexOf(
'Y+') != -1) {
4652 option.AxisPos += 1;
4653 chopt = chopt.replace(
'Y+',
' ');
4655 if ((option.AxisPos == 10 || option.AxisPos == 1) && (nch == 2))
4657 if (option.AxisPos == 11 && nch == 4)
4659 if (chopt.indexOf(
'SAMES') != -1) {
4660 if (nch == 5) option.Hist = 1;
4662 chopt = chopt.replace(
'SAMES',
' ');
4664 if (chopt.indexOf(
'SAME') != -1) {
4665 if (nch == 4) option.Hist = 1;
4667 chopt = chopt.replace(
'SAME',
' ');
4669 if (chopt.indexOf(
'PIE') != -1) {
4671 chopt = chopt.replace(
'PIE',
' ');
4673 l = chopt.indexOf(
'LEGO');
4677 chopt = chopt.replace(
'LEGO',
' ');
4678 if (chopt[l + 4] ==
'1') {
4682 if (chopt[l + 4] ==
'2') {
4686 if (chopt[l + 4] ==
'3') {
4690 l = chopt.indexOf(
'FB');
4692 option.FrontBox = 0;
4693 chopt = chopt.replace(
'FB',
' ');
4695 l = chopt.indexOf(
'BB');
4698 chopt = chopt.replace(
'BB',
' ');
4700 l = chopt.indexOf(
'0');
4703 chopt = chopt.replace(
'0',
' ');
4706 l = chopt.indexOf(
'SURF');
4710 chopt = chopt.replace(
'SURF',
' ');
4711 if (chopt[l + 4] ==
'1') {
4715 if (chopt[l + 4] ==
'2') {
4719 if (chopt[l + 4] ==
'3') {
4723 if (chopt[l + 4] ==
'4') {
4727 if (chopt[l + 4] ==
'5') {
4731 if (chopt[l + 4] ==
'6') {
4735 if (chopt[l + 4] ==
'7') {
4739 l = chopt.indexOf(
'FB');
4741 option.FrontBox = 0;
4742 chopt = chopt.replace(
'FB',
' ');
4744 l = chopt.indexOf(
'BB');
4747 chopt = chopt.replace(
'BB',
' ');
4750 l = chopt.indexOf(
'TF3');
4752 l = chopt.indexOf(
'FB');
4754 option.FrontBox = 0;
4755 chopt = chopt.replace(
'FB',
' ');
4757 l = chopt.indexOf(
'BB');
4760 chopt = chopt.replace(
'BB',
' ');
4763 l = chopt.indexOf(
'ISO');
4765 l = chopt.indexOf(
'FB');
4767 option.FrontBox = 0;
4768 chopt = chopt.replace(
'FB',
' ');
4770 l = chopt.indexOf(
'BB');
4773 chopt = chopt.replace(
'BB',
' ');
4776 l = chopt.indexOf(
'LIST');
4779 chopt = chopt.replace(
'LIST',
' ');
4781 l = chopt.indexOf(
'CONT');
4783 chopt = chopt.replace(
'CONT',
' ');
4787 if (chopt[l + 4] ==
'1') {
4788 option.Contour = 11;
4791 if (chopt[l + 4] ==
'2') {
4792 option.Contour = 12;
4795 if (chopt[l + 4] ==
'3') {
4796 option.Contour = 13;
4799 if (chopt[l + 4] ==
'4') {
4800 option.Contour = 14;
4803 if (chopt[l + 4] ==
'5') {
4804 option.Contour = 15;
4811 l = chopt.indexOf(
'HBAR');
4815 chopt = chopt.replace(
'HBAR',
' ');
4816 if (chopt[l + 4] ==
'1') {
4820 if (chopt[l + 4] ==
'2') {
4824 if (chopt[l + 4] ==
'3') {
4828 if (chopt[l + 4] ==
'4') {
4833 l = chopt.indexOf(
'BAR');
4837 chopt = chopt.replace(
'BAR',
' ');
4838 if (chopt[l + 3] ==
'1') {
4842 if (chopt[l + 3] ==
'2') {
4846 if (chopt[l + 3] ==
'3') {
4850 if (chopt[l + 3] ==
'4') {
4855 l = chopt.indexOf(
'ARR');
4857 chopt = chopt.replace(
'ARR',
' ');
4865 l = chopt.indexOf(
'BOX');
4867 chopt = chopt.replace(
'BOX',
' ');
4871 if (chopt[l + 3] ==
'1') {
4880 l = chopt.indexOf(
'COL');
4884 if (chopt.charAt(l+3)==
'0') { option.Color = 111; name +=
"0"; ++l; }
else
4885 if (chopt.charAt(l+3)==
'1') { option.Color = 1; name +=
"1"; ++l; }
else
4886 if (chopt.charAt(l+3)==
'2') { option.Color = 2; name +=
"2"; ++l; }
else
4887 if (chopt.charAt(l+3)==
'3') { option.Color = 3; name +=
"3"; ++l; }
else
4890 if (chopt.charAt(l+4)==
'Z') { option.Zscale = 1; name +=
'Z'; }
4891 chopt = chopt.replace(name,
'');
4899 if (chopt.indexOf(
'CHAR') != -1) {
4901 chopt = chopt.replace(
'CHAR',
' ');
4904 l = chopt.indexOf(
'FUNC');
4907 chopt = chopt.replace(
'FUNC',
' ');
4910 l = chopt.indexOf(
'HIST');
4913 chopt = chopt.replace(
'HIST',
' ');
4917 if (chopt.indexOf(
'AXIS') != -1) {
4919 chopt = chopt.replace(
'AXIS',
' ');
4921 if (chopt.indexOf(
'AXIG') != -1) {
4923 chopt = chopt.replace(
'AXIG',
' ');
4925 if (chopt.indexOf(
'TEXT') != -1) {
4926 var angle = parseInt(chopt);
4927 if (!isNaN(angle)) {
4932 option.Text = 1000 + angle;
4936 chopt = chopt.replace(
'TEXT',
' ');
4937 l = chopt.indexOf(
'N');
4938 if (l != -1 && this.IsTH2Poly())
4939 option.Text += 3000;
4942 if (chopt.indexOf(
'SCAT') != -1) {
4944 chopt = chopt.replace(
'SCAT',
' ');
4946 if (chopt.indexOf(
'POL') != -1) {
4947 option.System = JSROOT.Painter.Coord.kPOLAR;
4948 chopt = chopt.replace(
'POL',
' ');
4950 if (chopt.indexOf(
'CYL') != -1) {
4951 option.System = JSROOT.Painter.Coord.kCYLINDRICAL;
4952 chopt = chopt.replace(
'CYL',
' ');
4954 if (chopt.indexOf(
'SPH') != -1) {
4955 option.System = JSROOT.Painter.Coord.kSPHERICAL;
4956 chopt = chopt.replace(
'SPH',
' ');
4958 l = chopt.indexOf(
'PSR');
4960 option.System = JSROOT.Painter.Coord.kRAPIDITY;
4961 chopt = chopt.replace(
'PSR',
' ');
4963 l = chopt.indexOf(
'TRI');
4968 chopt = chopt.replace(
'TRI',
' ');
4969 l = chopt.indexOf(
'FB');
4971 option.FrontBox = 0;
4972 chopt = chopt.replace(
'FB',
' ');
4974 l = chopt.indexOf(
'BB');
4977 chopt = chopt.replace(
'BB',
' ');
4979 l = chopt.indexOf(
'ERR');
4981 chopt = chopt.replace(
'ERR',
' ');
4983 l = chopt.indexOf(
'AITOFF');
4986 chopt = chopt.replace(
'AITOFF',
' ');
4988 l = chopt.indexOf(
'MERCATOR');
4991 chopt = chopt.replace(
'MERCATOR',
' ');
4993 l = chopt.indexOf(
'SINUSOIDAL');
4996 chopt = chopt.replace(
'SINUSOIDAL',
' ');
4998 l = chopt.indexOf(
'PARABOLIC');
5001 chopt = chopt.replace(
'PARABOLIC',
' ');
5003 if (option.Proj > 0) {
5005 option.Contour = 14;
5007 if (chopt.indexOf(
'A') != -1)
5009 if (chopt.indexOf(
'B') != -1)
5011 if (chopt.indexOf(
'C') != -1) {
5015 if (chopt.indexOf(
'F') != -1)
5017 if (chopt.indexOf(
'][') != -1) {
5021 if (chopt.indexOf(
'F2') != -1) option.Fill = 2;
5022 if (chopt.indexOf(
'L') != -1) {
5027 if (chopt.indexOf(
'P') != -1) {
5030 if (chopt.indexOf(
'P0') != -1) option.Mark = 10;
5032 if (chopt.indexOf(
'Z') != -1) option.Zscale = 1;
5033 if (chopt.indexOf(
'*') != -1) option.Star = 1;
5034 if (chopt.indexOf(
'H') != -1) option.Hist = 2;
5035 if (this.IsTH2Poly()) {
5036 if (option.Fill + option.Line + option.Mark != 0) option.Scat = 0;
5039 if (chopt.indexOf(
'E') != -1) {
5042 if (chopt.indexOf(
'E0') != -1) option.Error = 10;
5043 if (chopt.indexOf(
'E1') != -1) option.Error = 11;
5044 if (chopt.indexOf(
'E2') != -1) option.Error = 12;
5045 if (chopt.indexOf(
'E3') != -1) option.Error = 13;
5046 if (chopt.indexOf(
'E4') != -1) option.Error = 14;
5047 if (chopt.indexOf(
'E5') != -1) option.Error = 15;
5048 if (chopt.indexOf(
'E6') != -1) option.Error = 16;
5049 if (chopt.indexOf(
'X0') != -1) {
5050 if (option.Error == 1) option.Error += 20;
5053 if (option.Text &&
this.IsTProfile()) {
5054 option.Text += 2000;
5058 if (option.Error == 0) {
5063 option.Text += 2000;
5068 if (chopt.indexOf(
'9') != -1) option.HighRes = 1;
5069 if (option.Surf == 15) {
5070 if (option.System == JSROOT.Painter.Coord.kPOLAR
5071 || option.System == JSROOT.Painter.Coord.kCARTESIAN) {
5079 if (option.Bar == 1) option.Hist = -1;
5084 JSROOT.THistPainter.prototype.GetAutoColor =
function(col) {
5085 if (this.options.AutoColor<=0)
return col;
5087 var
id = this.options.AutoColor;
5088 this.options.AutoColor =
id % 8 + 1;
5089 return JSROOT.Painter.root_colors[id];
5092 JSROOT.THistPainter.prototype.ScanContent =
function() {
5097 alert(
"HistPainter.prototype.ScanContent not implemented");
5100 JSROOT.THistPainter.prototype.CheckPadOptions =
function() {
5102 this.fillatt = this.createAttFill(this.histo, undefined, undefined, 1);
5104 this.lineatt = JSROOT.Painter.createAttLine(this.histo);
5105 var main = this.main_painter();
5106 if (main!==null) this.lineatt.color = main.GetAutoColor(this.lineatt.color);
5108 var pad = this.root_pad();
5112 this.options.Logx = pad.fLogx;
5113 this.options.Logy = pad.fLogy;
5114 this.options.Logz = pad.fLogz;
5115 this.options.Gridx = pad.fGridx;
5116 this.options.Gridy = pad.fGridy;
5119 if (this.main_painter() !==
this)
return;
5121 this.zoom_xmin = this.zoom_xmax = 0;
5122 this.zoom_ymin = this.zoom_ymax = 0;
5123 this.zoom_zmin = this.zoom_zmax = 0;
5125 if ((pad==null) || !(
'fUxmin' in pad) || this.create_canvas)
return;
5127 var min = pad.fUxmin, max = pad.fUxmax;
5130 if ((this.Dimension() < 3) && ((min !== 0) || (max !== 1))) {
5131 if (pad.fLogx > 0) {
5132 min = Math.exp(min * Math.log(10));
5133 max = Math.exp(max * Math.log(10));
5136 if (min !== this.histo.fXaxis.fXmin || max !==
this.histo.fXaxis.fXmax)
5137 if (min >= this.histo.fXaxis.fXmin && max <=
this.histo.fXaxis.fXmax) {
5139 this.zoom_xmin = min;
5140 this.zoom_xmax = max;
5144 min = pad.fUymin; max = pad.fUymax;
5146 if ((this.Dimension() == 2) && ((min !== 0) || (max !== 1))) {
5147 if (pad.fLogy > 0) {
5148 min = Math.exp(min * Math.log(10));
5149 max = Math.exp(max * Math.log(10));
5152 if (min !== this.histo.fYaxis.fXmin || max !==
this.histo.fYaxis.fXmax)
5153 if (min >= this.histo.fYaxis.fXmin && max <=
this.histo.fYaxis.fXmax) {
5155 this.zoom_ymin = min;
5156 this.zoom_ymax = max;
5161 JSROOT.THistPainter.prototype.UpdateObject =
function(obj) {
5162 if (!this.MatchObjectType(obj)) {
5163 alert(
"JSROOT.THistPainter.UpdateObject - wrong class " + obj._typename +
" expected " +
this.histo._typename);
5174 var histo = this.GetObject();
5176 histo.fEntries = obj.fEntries;
5177 histo.fTsumw = obj.fTsumw;
5178 histo.fTsumwx = obj.fTsumwx;
5179 histo.fTsumwx2 = obj.fTsumwx2;
5180 if (this.Dimension() == 2) {
5181 histo.fTsumwy = obj.fTsumwy;
5182 histo.fTsumwy2 = obj.fTsumwy2;
5183 histo.fTsumwxy = obj.fTsumwxy;
5185 histo.fArray = obj.fArray;
5186 histo.fNcells = obj.fNcells;
5187 histo.fTitle = obj.fTitle;
5188 histo.fMinimum = obj.fMinimum;
5189 histo.fMaximum = obj.fMaximum;
5190 histo.fXaxis.fNbins = obj.fXaxis.fNbins;
5191 histo.fXaxis.fXmin = obj.fXaxis.fXmin;
5192 histo.fXaxis.fXmax = obj.fXaxis.fXmax;
5193 histo.fYaxis.fXmin = obj.fYaxis.fXmin;
5194 histo.fYaxis.fXmax = obj.fYaxis.fXmax;
5195 histo.fSumw2 = obj.fSumw2;
5197 if (this.IsTProfile()) {
5198 histo.fBinEntries = obj.fBinEntries;
5206 JSROOT.THistPainter.prototype.CreateAxisFuncs =
function(with_y_axis, with_z_axis) {
5210 this.xmin = this.histo.fXaxis.fXmin;
5211 this.xmax = this.histo.fXaxis.fXmax;
5213 if (this.histo.fXaxis.fXbins.length ==
this.nbinsx+1) {
5214 this.regularx =
false;
5215 this.GetBinX =
function(bin) {
5216 var indx = Math.round(bin);
5217 if (indx <= 0)
return this.xmin;
5218 if (indx > this.nbinsx) this.xmax;
5219 if (indx==bin)
return this.histo.fXaxis.fXbins[indx];
5220 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
5221 return this.histo.fXaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fXaxis.fXbins[indx2] * Math.abs(bin-indx);
5223 this.GetIndexX =
function(x,add) {
5224 for (var k = 1; k < this.histo.fXaxis.fXbins.length; ++k)
5225 if (x < this.histo.fXaxis.fXbins[k])
return Math.floor(k-1+add);
5229 this.regularx =
true;
5230 this.binwidthx = (this.xmax - this.xmin);
5231 if (this.nbinsx > 0)
5232 this.binwidthx = this.binwidthx / this.nbinsx;
5234 this.GetBinX =
function(bin) {
return this.xmin + bin*this.binwidthx; };
5235 this.GetIndexX =
function(x,add) {
return Math.floor((x - this.xmin) / this.binwidthx + add); };
5238 this.ymin = this.histo.fYaxis.fXmin;
5239 this.ymax = this.histo.fYaxis.fXmax;
5241 if (!with_y_axis || (this.nbinsy==0))
return;
5243 if (this.histo.fYaxis.fXbins.length ==
this.nbinsy+1) {
5244 this.regulary =
false;
5245 this.GetBinY =
function(bin) {
5246 var indx = Math.round(bin);
5247 if (indx <= 0)
return this.ymin;
5248 if (indx > this.nbinsy) this.ymax;
5249 if (indx==bin)
return this.histo.fYaxis.fXbins[indx];
5250 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
5251 return this.histo.fYaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fYaxis.fXbins[indx2] * Math.abs(bin-indx);
5253 this.GetIndexY =
function(y,add) {
5254 for (var k = 1; k < this.histo.fYaxis.fXbins.length; ++k)
5255 if (y < this.histo.fYaxis.fXbins[k])
return Math.floor(k-1+add);
5259 this.regulary =
true;
5260 this.binwidthy = (this.ymax - this.ymin);
5261 if (this.nbinsy > 0)
5262 this.binwidthy = this.binwidthy / this.nbinsy;
5264 this.GetBinY =
function(bin) {
return this.ymin+bin*this.binwidthy; };
5265 this.GetIndexY =
function(y,add) {
return Math.floor((y - this.ymin) / this.binwidthy + add); };
5268 if (!with_z_axis || (this.nbinsz==0))
return;
5270 if (this.histo.fZaxis.fXbins.length ==
this.nbinsz+1) {
5271 this.regularz =
false;
5272 this.GetBinZ =
function(bin) {
5273 var indx = Math.round(bin);
5274 if (indx <= 0)
return this.zmin;
5275 if (indx > this.nbinsz) this.zmax;
5276 if (indx==bin)
return this.histo.fZaxis.fXbins[indx];
5277 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
5278 return this.histo.fZaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fZaxis.fXbins[indx2] * Math.abs(bin-indx);
5280 this.GetIndexZ =
function(z,add) {
5281 for (var k = 1; k < this.histo.fZaxis.fXbins.length; ++k)
5282 if (z < this.histo.fZaxis.fXbins[k])
return Math.floor(k-1+add);
5286 this.regularz =
true;
5287 this.binwidthz = (this.zmax - this.zmin);
5288 if (this.nbinsz > 0)
5289 this.binwidthz = this.binwidthz / this.nbinsz;
5291 this.GetBinZ =
function(bin) {
return this.zmin+bin*this.binwidthz; };
5292 this.GetIndexZ =
function(z,add) {
return Math.floor((z - this.zmin) / this.binwidthz + add); };
5297 JSROOT.THistPainter.prototype.CreateXY =
function() {
5307 if (!this.is_main_painter()) {
5308 this.x = this.main_painter().x;
5309 this.y = this.main_painter().y;
5313 var w = this.frame_width(), h = this.frame_height();
5315 if (this.histo.fXaxis.fTimeDisplay) {
5316 this.x_kind =
'time';
5317 this.timeoffsetx = JSROOT.Painter.getTimeOffset(this.histo.fXaxis);
5318 this.ConvertX =
function(x) {
return new Date(this.timeoffsetx + x*1000); };
5319 this.RevertX =
function(grx) {
return (this.x.invert(grx) - this.timeoffsetx) / 1000; };
5321 this.x_kind = (this.histo.fXaxis.fLabels==null) ?
'normal' :
'labels';
5322 this.ConvertX =
function(x) {
return x; };
5323 this.RevertX =
function(grx) {
return this.x.invert(grx); };
5326 this.scale_xmin = this.xmin;
5327 this.scale_xmax = this.xmax;
5328 if (this.zoom_xmin != this.zoom_xmax) {
5329 this.scale_xmin = this.zoom_xmin;
5330 this.scale_xmax = this.zoom_xmax;
5332 if (this.x_kind ==
'time') {
5333 this.x = d3.time.scale();
5335 if (this.options.Logx) {
5336 if (this.scale_xmax <= 0) this.scale_xmax = 0;
5338 if ((this.scale_xmin <= 0) && (this.nbinsx>0))
5339 for (var i=0;i<this.nbinsx;++i) {
5340 this.scale_xmin = Math.max(this.scale_xmin, this.GetBinX(i));
5341 if (this.scale_xmin>0)
break;
5344 if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) {
5345 this.scale_xmin = this.scale_xmax * 0.0001;
5348 this.x = d3.scale.log();
5350 this.x = d3.scale.linear();
5353 this.x.domain([this.ConvertX(this.scale_xmin), this.ConvertX(this.scale_xmax)]).range([ 0, w ]);
5355 if (this.x_kind ==
'time') {
5357 this.grx =
function(val) {
return this.x(this.ConvertX(val)); }
5359 if (this.options.Logx) {
5360 this.grx =
function(val) {
return (val < this.scale_xmin) ? -5 : this.x(val); }
5365 this.scale_ymin = this.ymin;
5366 this.scale_ymax = this.ymax;
5367 if (this.zoom_ymin != this.zoom_ymax) {
5368 this.scale_ymin = this.zoom_ymin;
5369 this.scale_ymax = this.zoom_ymax;
5372 if (this.histo.fYaxis.fTimeDisplay) {
5373 this.y_kind =
'time';
5374 this.timeoffsety = JSROOT.Painter.getTimeOffset(this.histo.fYaxis);
5375 this.ConvertY =
function(y) {
return new Date(this.timeoffsety + y*1000); };
5376 this.RevertY =
function(gry) {
return (this.y.invert(gry) - this.timeoffsety) / 1000; };
5378 this.y_kind = ((this.Dimension()==2) && (this.histo.fYaxis.fLabels!=null)) ?
'labels' :
'normal';
5379 this.ConvertY =
function(y) {
return y; };
5380 this.RevertY =
function(gry) {
return this.y.invert(gry); };
5383 if (this.options.Logy) {
5384 if (this.scale_ymax <= 0)
5385 this.scale_ymax = 1;
5387 if ((this.zoom_ymin === this.zoom_ymax) && (this.Dimension()==1))
5388 this.scale_ymax*=1.8;
5390 if ((this.scale_ymin <= 0) && (this.nbinsy>0))
5391 for (var i=0;i<this.nbinsy;++i) {
5392 this.scale_ymin = Math.max(this.scale_ymin, this.GetBinY(i));
5393 if (this.scale_ymin>0)
break;
5396 if ((this.scale_ymin <= 0) && (
'ymin_nz' in
this) && (this.ymin_nz > 0))
5397 this.scale_ymin = 0.3*this.ymin_nz;
5399 if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax))
5400 this.scale_ymin = 0.000001 * this.scale_ymax;
5401 this.y = d3.scale.log();
5403 if (this.y_kind==
'time') {
5404 this.y = d3.time.scale();
5406 this.y = d3.scale.linear()
5409 this.y.domain([ this.ConvertY(this.scale_ymin), this.ConvertY(this.scale_ymax) ]).range([ h, 0 ]);
5411 if (this.y_kind==
'time') {
5413 this.gry =
function(val) {
return this.y(this.ConvertY(val)); }
5415 if (this.options.Logy) {
5417 this.gry =
function(val) {
return (val < this.scale_ymin) ? h+5 : this.y(val); }
5423 JSROOT.THistPainter.prototype.DrawGrids =
function() {
5425 if (!this.is_main_painter())
return;
5427 var layer = this.svg_frame().select(
".grid_layer");
5429 layer.selectAll(
".xgrid").remove();
5430 layer.selectAll(
".ygrid").remove();
5434 if (this.options.Gridx &&
this.x_handle) {
5436 var h = this.frame_height();
5438 layer.selectAll(
".xgrid")
5439 .data(this.x_handle.ticks).enter()
5441 .attr(
"class",
"xgrid")
5442 .attr(
"x1",
function(d) {
return d; })
5444 .attr(
"x2",
function(d) {
return d; })
5446 .style(
"stroke",
"black")
5447 .style(
"stroke-width", 1)
5448 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
5452 if (this.options.Gridy &&
this.y_handle) {
5453 var w = this.frame_width();
5455 layer.selectAll(
'.ygrid')
5456 .data(this.y_handle.ticks).enter()
5458 .attr(
"class",
"ygrid")
5460 .attr(
"y1",
function(d) {
return d; })
5462 .attr(
"y2",
function(d) {
return d; })
5463 .style(
"stroke",
"black")
5464 .style(
"stroke-width", 1)
5465 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
5469 JSROOT.THistPainter.prototype.DrawBins =
function() {
5470 alert(
"HistPainter.DrawBins not implemented");
5473 JSROOT.THistPainter.prototype.AxisAsText =
function(axis, value) {
5475 if (this.x_kind ==
'time')
5476 value = this.ConvertX(value);
5478 if (this.x_handle!==null)
5479 if (
'format' in this.x_handle)
5480 return this.x_handle.format(value);
5482 return value.toPrecision(4);
5486 if (this.y_kind ==
'time')
5487 value = this.ConvertY(value);
5489 if (this.y_handle!==null)
5490 if (
'format' in this.y_handle)
5491 return this.y_handle.format(value);
5493 return value.toPrecision(4);
5496 return value.toPrecision(4);
5499 JSROOT.THistPainter.prototype.DrawAxes =
function(shrink_forbidden) {
5502 if (!this.is_main_painter())
return;
5504 var layer = this.svg_frame().select(
".axis_layer"),
5505 w = this.frame_width(),
5506 h = this.frame_height();
5508 this.x_handle =
new JSROOT.TAxisPainter(this.histo.fXaxis,
true);
5509 this.x_handle.SetDivId(this.divid, -1);
5511 this.x_handle.SetAxisConfig(
"xaxis",
5512 (this.options.Logx &&
this.x_kind !==
"time") ?
"log" :
this.x_kind,
5513 this.x,
this.xmin,
this.xmax,
this.scale_xmin,
this.scale_xmax);
5515 this.x_handle.DrawAxis(layer, w, h,
"translate(0," + h +
")");
5517 this.y_handle =
new JSROOT.TAxisPainter(this.histo.fYaxis,
true);
5518 this.y_handle.SetDivId(this.divid, -1);
5520 this.y_handle.SetAxisConfig(
"yaxis",
5521 (this.options.Logy &&
this.y_kind !==
"time") ?
"log" :
this.y_kind,
5522 this.y,
this.ymin,
this.ymax,
this.scale_ymin,
this.scale_ymax);
5524 this.y_handle.DrawAxis(layer, w, h);
5526 if (shrink_forbidden)
return;
5528 var shrink = 0., ypos = this.y_handle.position;
5531 shrink = -ypos/w + 0.001;
5532 this.shrink_frame_left += shrink;
5534 if ((this.shrink_frame_left > 0) && (ypos/w > this.shrink_frame_left)) {
5535 shrink = -this.shrink_frame_left;
5536 this.shrink_frame_left = 0.;
5540 this.frame_painter().Shrink(shrink, 0);
5541 this.frame_painter().Redraw();
5543 this.DrawAxes(
true);
5547 JSROOT.THistPainter.prototype.DrawTitle =
function() {
5550 if (!this.is_main_painter())
return;
5552 var tpainter = this.FindPainterFor(null,
"title");
5553 var pavetext = (tpainter !== null) ? tpainter.GetObject() : null;
5554 if (pavetext === null) pavetext = this.FindInPrimitives(
"title");
5555 if ((pavetext !== null) && (pavetext._typename !==
"TPaveText")) pavetext = null;
5557 var draw_title = !this.histo.TestBit(JSROOT.TH1StatusBits.kNoTitle);
5559 if (pavetext !== null) {
5562 pavetext.AddText(this.histo.fTitle);
5564 if (draw_title && (tpainter === null)) {
5565 pavetext = JSROOT.Create(
"TPaveText");
5567 JSROOT.extend(pavetext, { fName:
"title", fX1NDC: 0.28, fY1NDC: 0.94, fX2NDC: 0.72, fY2NDC: 0.99 } );
5568 pavetext.AddText(this.histo.fTitle);
5570 JSROOT.Painter.drawPaveText(this.divid, pavetext);
5574 JSROOT.THistPainter.prototype.ToggleStat =
function(arg) {
5576 var stat = this.FindStat(), statpainter = null;
5579 if (arg==
'only-check')
return false;
5581 stat = this.CreateStat();
5583 statpainter = this.FindPainterFor(stat);
5586 if (arg==
'only-check')
return statpainter ? statpainter.Enabled :
false;
5589 statpainter.Enabled = !statpainter.Enabled;
5592 statpainter.Redraw();
5593 return statpainter.Enabled;
5596 JSROOT.draw(this.divid, stat,
"onpad:" + this.pad_name);
5601 JSROOT.THistPainter.prototype.IsAxisZoomed =
function(axis) {
5602 var obj = this.main_painter();
5603 if (obj == null) obj =
this;
5604 if (axis ===
"x")
return obj.zoom_xmin != obj.zoom_xmax;
5605 if (axis ===
"y")
return obj.zoom_ymin != obj.zoom_ymax;
5609 JSROOT.THistPainter.prototype.GetSelectIndex =
function(axis, size, add) {
5611 var indx = 0, obj = this.main_painter();
5612 if (obj == null) obj =
this;
5613 var nbin =
this[
'nbins'+axis];
5614 if (!nbin) nbin = 0;
5617 var func =
'GetIndex' + axis.toUpperCase(),
5618 min = obj[
'zoom_' + axis +
'min'],
5619 max = obj[
'zoom_' + axis +
'max'];
5621 if ((min != max) && (func in
this)) {
5622 if (size ==
"left") {
5623 indx =
this[func](min, add);
5625 indx =
this[func](max, add + 0.5);
5628 indx = (size ==
"left") ? 0 : nbin;
5632 if (this.histo) taxis = this.histo[
"f" + axis.toUpperCase() +
"axis"];
5634 if ((taxis.fFirst === taxis.fLast) || !taxis.TestBit(JSROOT.EAxisBits.kAxisRange) ||
5635 ((taxis.fFirst<=1) && (taxis.fLast>=nbin))) taxis = undefined;
5638 if (size ==
"left") {
5639 if (indx < 0) indx = 0;
5640 if (taxis && taxis.fFirst>1 && (indx<taxis.fFirst)) indx = taxis.fFirst-1;
5642 if (indx > nbin) indx = nbin;
5643 if (taxis && (taxis.fLast <= nbin) && (indx>taxis.fLast)) indx = taxis.fLast;
5649 JSROOT.THistPainter.prototype.FindStat =
function() {
5650 if (this.histo.fFunctions !== null)
5651 for (var i = 0; i < this.histo.fFunctions.arr.length; ++i) {
5652 var func = this.histo.fFunctions.arr[i];
5654 if ((func._typename ==
'TPaveStats') &&
5655 (func.fName ==
'stats'))
return func;
5661 JSROOT.THistPainter.prototype.CreateStat =
function() {
5663 if (!this.draw_content)
return null;
5665 var stats = this.FindStat();
5666 if (stats != null)
return stats;
5668 stats = JSROOT.Create(
'TPaveStats');
5669 JSROOT.extend(stats, { fName :
'stats',
5670 fOptStat: JSROOT.gStyle.OptStat,
5671 fOptFit: JSROOT.gStyle.OptFit,
5673 JSROOT.extend(stats, JSROOT.gStyle.StatNDC);
5674 JSROOT.extend(stats, JSROOT.gStyle.StatText);
5675 JSROOT.extend(stats, JSROOT.gStyle.StatFill);
5677 if (this.histo._typename.match(/^TProfile/) || this.histo._typename.match(/^TH2/))
5678 stats.fY1NDC = 0.67;
5680 stats.AddText(
this.histo.fName);
5682 if (this.histo.fFunctions === null)
5683 this.histo.fFunctions = JSROOT.Create(
"TList");
5685 this.histo.fFunctions.Add(stats,
"");
5690 JSROOT.THistPainter.prototype.FindF1 =
function() {
5692 if (this.histo.fFunctions == null)
return null;
5693 for (var i = 0; i < this.histo.fFunctions.arr.length; ++i) {
5694 var func = this.histo.fFunctions.arr[i];
5695 if (func._typename ==
'TF1')
return func;
5700 JSROOT.THistPainter.prototype.DrawNextFunction =
function(indx, callback) {
5703 if (this.options.Same || (
this.histo.fFunctions === null) || (indx >= this.histo.fFunctions.arr.length))
5704 return JSROOT.CallBack(callback);
5706 var func = this.histo.fFunctions.arr[indx],
5707 opt = this.histo.fFunctions.opt[indx],
5709 func_painter = this.FindPainterFor(func);
5713 if (func_painter === null) {
5714 if (func._typename ==
'TPaveText' || func._typename ==
'TPaveStats') {
5715 do_draw = !this.histo.TestBit(JSROOT.TH1StatusBits.kNoStats) && (this.options.NoStat!=1);
5717 if (func._typename ==
'TF1') {
5718 do_draw = !func.TestBit(JSROOT.BIT(9));
5722 if ((
'CompleteDraw' in func_painter) && (typeof func_painter.CompleteDraw ==
'function'))
5723 func_painter.CompleteDraw();
5726 var painter = JSROOT.draw(this.divid, func, opt);
5727 if (painter)
return painter.WhenReady(this.DrawNextFunction.bind(
this, indx+1, callback));
5730 this.DrawNextFunction(indx+1, callback);
5733 JSROOT.THistPainter.prototype.UnzoomUserRange =
function(dox, doy, doz) {
5735 if (!this.histo)
return false;
5737 function UnzoomTAxis(obj) {
5738 if (!obj)
return false;
5739 if (!obj.TestBit(JSROOT.EAxisBits.kAxisRange))
return false;
5740 if (obj.fFirst === obj.fLast)
return false;
5741 if ((obj.fFirst <= 1) && (obj.fLast >= obj.fNbins))
return false;
5742 obj.InvertBit(JSROOT.EAxisBits.kAxisRange);
5748 if (dox) res |= UnzoomTAxis(this.histo.fXaxis);
5749 if (doy) res |= UnzoomTAxis(this.histo.fYaxis);
5750 if (doz) res |= UnzoomTAxis(this.histo.fZaxis);
5755 JSROOT.THistPainter.prototype.ToggleLog =
function(axis) {
5756 var obj = this.main_painter();
5757 if (!obj) obj =
this;
5759 var curr = obj.options[
"Log" + axis];
5761 if (!curr && (
this[axis+
"_kind"] ==
"labels"))
return;
5762 obj.options[
"Log" + axis] = curr ? 0 : 1;
5766 JSROOT.THistPainter.prototype.Zoom =
function(xmin, xmax, ymin, ymax, zmin, zmax) {
5770 var main = this.main_painter(),
5771 zoom_x = (xmin !== xmax), zoom_y = (ymin !== ymax), zoom_z = (zmin !== zmax),
5772 unzoom_x =
false, unzoom_y =
false, unzoom_z =
false;
5776 if (xmin <= main.xmin) { xmin = main.xmin; cnt++; }
5777 if (xmax >= main.xmax) { xmax = main.xmax; cnt++; }
5778 if (cnt === 2) { zoom_x =
false; unzoom_x =
true; }
5780 unzoom_x = (xmin === xmax) && (xmin === 0);
5785 if (ymin <= main.ymin) { ymin = main.ymin; cnt++; }
5786 if (ymax >= main.ymax) { ymax = main.ymax; cnt++; }
5787 if (cnt === 2) { zoom_y =
false; unzoom_y =
true; }
5789 unzoom_y = (ymin === ymax) && (ymin === 0);
5794 if (zmin <= main.zmin) { zmin = main.zmin; cnt++; }
5795 if (zmax >= main.zmax) { zmax = main.zmax; cnt++; }
5796 if (cnt === 2) { zoom_z =
false; unzoom_z =
true; }
5798 unzoom_z = (zmin === zmax) && (zmin === 0);
5801 var changed =
false;
5804 if (zoom_x || zoom_y || zoom_z)
5805 main.ForEachPainter(
function(obj) {
5806 if (zoom_x && obj.CanZoomIn(
"x", xmin, xmax)) {
5807 main.zoom_xmin = xmin;
5808 main.zoom_xmax = xmax;
5812 if (zoom_y && obj.CanZoomIn(
"y", ymin, ymax)) {
5813 main.zoom_ymin = ymin;
5814 main.zoom_ymax = ymax;
5818 if (zoom_z && obj.CanZoomIn(
"z", zmin, zmax)) {
5819 main.zoom_zmin = zmin;
5820 main.zoom_zmax = zmax;
5827 if (unzoom_x || unzoom_y || unzoom_z) {
5829 if (main.zoom_xmin !== main.zoom_xmax) changed =
true;
5830 main.zoom_xmin = main.zoom_xmax = 0;
5833 if (main.zoom_ymin !== main.zoom_ymax) changed =
true;
5834 main.zoom_ymin = main.zoom_ymax = 0;
5837 if (main.zoom_zmin !== main.zoom_zmax) changed =
true;
5838 main.zoom_zmin = main.zoom_zmax = 0;
5843 changed = main.UnzoomUserRange(unzoom_x, unzoom_y, unzoom_z);
5846 var pp = this.pad_painter(
true);
5847 if (pp && pp.painters)
5848 pp.painters.forEach(
function(paint){
5849 if (paint && (paint!==main) && (typeof paint.UnzoomUserRange ==
'function'))
5850 if (paint.UnzoomUserRange(unzoom_x, unzoom_y, unzoom_z)) changed =
true;
5855 if (changed) this.RedrawPad();
5860 JSROOT.THistPainter.prototype.Unzoom =
function(dox, doy, doz) {
5861 if (typeof dox ===
'undefined') { dox =
true; doy =
true; doz =
true; }
else
5862 if (typeof dox ===
'string') { doz = dox.indexOf(
"z")>=0; doy = dox.indexOf(
"y")>=0; dox = dox.indexOf(
"x")>=0; }
5864 return this.Zoom(dox ? 0 : undefined, dox ? 0 : undefined,
5865 doy ? 0 : undefined, doy ? 0 : undefined,
5866 doz ? 0 : undefined, doz ? 0 : undefined);
5869 JSROOT.THistPainter.prototype.clearInteractiveElements =
function() {
5870 JSROOT.Painter.closeMenu();
5871 if (this.zoom_rect != null) { this.zoom_rect.remove(); this.zoom_rect = null; }
5875 this.SwitchTooltip(
true);
5878 JSROOT.THistPainter.prototype.mouseDoubleClick =
function() {
5879 d3.event.preventDefault();
5880 var m = d3.mouse(this.svg_frame().node());
5881 this.clearInteractiveElements();
5883 if (m[0] < 0) kind =
"y";
else
5884 if (m[1] > this.frame_height()) kind =
"x";
5888 JSROOT.THistPainter.prototype.startRectSel =
function() {
5891 if (this.zoom_kind > 100)
return;
5894 if ((d3.event.which || d3.event.button) !== 1)
return;
5896 d3.event.preventDefault();
5898 this.clearInteractiveElements();
5899 this.zoom_origin = d3.mouse(this.svg_frame().node());
5901 this.zoom_curr = [ Math.max(0, Math.min(
this.frame_width(), this.zoom_origin[0])),
5902 Math.max(0, Math.min(
this.frame_height(), this.zoom_origin[1])) ];
5904 if (this.zoom_origin[0] < 0) {
5906 this.zoom_origin[0] = 0;
5907 this.zoom_origin[1] = this.zoom_curr[1];
5908 this.zoom_curr[0] = this.frame_width();
5909 this.zoom_curr[1] += 1;
5910 }
else if (this.zoom_origin[1] > this.frame_height()) {
5912 this.zoom_origin[0] = this.zoom_curr[0];
5913 this.zoom_origin[1] = 0;
5914 this.zoom_curr[0] += 1;
5915 this.zoom_curr[1] = this.frame_height();
5918 this.zoom_origin[0] = this.zoom_curr[0];
5919 this.zoom_origin[1] = this.zoom_curr[1];
5922 d3.select(window).on(
"mousemove.zoomRect", this.moveRectSel.bind(
this))
5923 .on(
"mouseup.zoomRect", this.endRectSel.bind(
this),
true);
5925 this.zoom_rect = null;
5928 this.SwitchTooltip(
false);
5930 d3.event.stopPropagation();
5933 JSROOT.THistPainter.prototype.moveRectSel =
function() {
5935 if ((this.zoom_kind == 0) || (this.zoom_kind > 100))
return;
5937 d3.event.preventDefault();
5938 var m = d3.mouse(this.svg_frame().node());
5940 m[0] = Math.max(0, Math.min(
this.frame_width(), m[0]));
5941 m[1] = Math.max(0, Math.min(
this.frame_height(), m[1]));
5943 switch (this.zoom_kind) {
5944 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1];
break;
5945 case 2: this.zoom_curr[0] = m[0];
break;
5946 case 3: this.zoom_curr[1] = m[1];
break;
5949 if (this.zoom_rect===null)
5950 this.zoom_rect = this.svg_frame()
5952 .attr(
"class",
"zoom")
5953 .attr(
"pointer-events",
"none");
5955 this.zoom_rect.attr(
"x", Math.min(
this.zoom_origin[0],
this.zoom_curr[0]))
5956 .attr(
"y", Math.min(
this.zoom_origin[1],
this.zoom_curr[1]))
5957 .attr(
"width", Math.abs(
this.zoom_curr[0] -
this.zoom_origin[0]))
5958 .attr(
"height", Math.abs(
this.zoom_curr[1] -
this.zoom_origin[1]));
5961 JSROOT.THistPainter.prototype.endRectSel =
function() {
5962 if ((this.zoom_kind == 0) || (this.zoom_kind > 100))
return;
5964 d3.event.preventDefault();
5966 d3.select(window).on(
"mousemove.zoomRect", null)
5967 .on(
"mouseup.zoomRect", null);
5969 var m = d3.mouse(this.svg_frame().node());
5971 m[0] = Math.max(0, Math.min(
this.frame_width(), m[0]));
5972 m[1] = Math.max(0, Math.min(
this.frame_height(), m[1]));
5974 switch (this.zoom_kind) {
5975 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1];
break;
5976 case 2: this.zoom_curr[0] = m[0];
break;
5977 case 3: this.zoom_curr[1] = m[1];
break;
5980 var xmin, xmax, ymin, ymax, isany =
false;
5982 if ((this.zoom_kind != 3) && (Math.abs(this.zoom_curr[0] - this.zoom_origin[0]) > 10)) {
5983 xmin = Math.min(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
5984 xmax = Math.max(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
5988 if ((this.zoom_kind != 2) && (Math.abs(
this.zoom_curr[1] -
this.zoom_origin[1]) > 10)) {
5989 ymin = Math.min(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
5990 ymax = Math.max(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
5994 this.clearInteractiveElements();
5996 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
5999 JSROOT.THistPainter.prototype.startTouchZoom =
function() {
6001 if (this.zoom_kind != 0) {
6002 d3.event.preventDefault();
6003 d3.event.stopPropagation();
6007 var arr = d3.touches(this.svg_frame().node());
6012 if (arr.length == 1) {
6015 var now =
new Date();
6016 var diff = now.getTime() - this.last_touch.getTime();
6017 this.last_touch = now;
6019 if ((diff < 300) && (this.zoom_curr != null)
6020 && (Math.abs(
this.zoom_curr[0] - arr[0][0]) < 30)
6021 && (Math.abs(
this.zoom_curr[1] - arr[0][1]) < 30)) {
6023 d3.event.preventDefault();
6024 d3.event.stopPropagation();
6026 this.clearInteractiveElements();
6029 this.last_touch =
new Date(0);
6031 this.svg_frame().on(
"touchcancel", null)
6032 .on(
"touchend", null,
true);
6034 if (JSROOT.gStyle.ContextMenu) {
6035 this.zoom_curr = arr[0];
6036 this.svg_frame().on(
"touchcancel", this.endTouchSel.bind(
this))
6037 .on(
"touchend", this.endTouchSel.bind(
this));
6038 d3.event.preventDefault();
6039 d3.event.stopPropagation();
6043 if (arr.length != 2)
return;
6045 d3.event.preventDefault();
6046 d3.event.stopPropagation();
6048 this.clearInteractiveElements();
6050 this.svg_frame().on(
"touchcancel", null)
6051 .on(
"touchend", null);
6053 var pnt1 = arr[0], pnt2 = arr[1];
6055 this.zoom_curr = [ Math.min(pnt1[0], pnt2[0]), Math.min(pnt1[1], pnt2[1]) ];
6056 this.zoom_origin = [ Math.max(pnt1[0], pnt2[0]), Math.max(pnt1[1], pnt2[1]) ];
6058 if (this.zoom_curr[0] < 0) {
6059 this.zoom_kind = 103;
6060 this.zoom_curr[0] = 0;
6061 this.zoom_origin[0] = this.frame_width();
6062 }
else if (this.zoom_origin[1] > this.frame_height()) {
6063 this.zoom_kind = 102;
6064 this.zoom_curr[1] = 0;
6065 this.zoom_origin[1] = this.frame_height();
6067 this.zoom_kind = 101;
6070 this.SwitchTooltip(
false);
6072 this.zoom_rect = this.svg_frame().append(
"rect")
6073 .attr(
"class",
"zoom")
6074 .attr(
"id",
"zoomRect")
6075 .attr(
"x", this.zoom_curr[0])
6076 .attr(
"y", this.zoom_curr[1])
6077 .attr(
"width", this.zoom_origin[0] - this.zoom_curr[0])
6078 .attr(
"height", this.zoom_origin[1] - this.zoom_curr[1]);
6080 d3.select(window).on(
"touchmove.zoomRect", this.moveTouchSel.bind(
this))
6081 .on(
"touchcancel.zoomRect", this.endTouchSel.bind(
this))
6082 .on(
"touchend.zoomRect", this.endTouchSel.bind(
this));
6085 JSROOT.THistPainter.prototype.moveTouchSel =
function() {
6086 if (this.zoom_kind < 100)
return;
6088 d3.event.preventDefault();
6090 var arr = d3.touches(this.svg_frame().node());
6092 if (arr.length != 2)
6093 return this.clearInteractiveElements();
6095 var pnt1 = arr[0], pnt2 = arr[1];
6097 if (this.zoom_kind != 103) {
6098 this.zoom_curr[0] = Math.min(pnt1[0], pnt2[0]);
6099 this.zoom_origin[0] = Math.max(pnt1[0], pnt2[0]);
6101 if (this.zoom_kind != 102) {
6102 this.zoom_curr[1] = Math.min(pnt1[1], pnt2[1]);
6103 this.zoom_origin[1] = Math.max(pnt1[1], pnt2[1]);
6106 this.zoom_rect.attr(
"x", this.zoom_curr[0])
6107 .attr(
"y", this.zoom_curr[1])
6108 .attr(
"width", this.zoom_origin[0] - this.zoom_curr[0])
6109 .attr(
"height", this.zoom_origin[1] - this.zoom_curr[1]);
6111 if ((this.zoom_origin[0] - this.zoom_curr[0] > 10)
6112 || (this.zoom_origin[1] - this.zoom_curr[1] > 10))
6113 this.SwitchTooltip(
false);
6115 d3.event.stopPropagation();
6118 JSROOT.THistPainter.prototype.endTouchSel =
function() {
6120 this.svg_frame().on(
"touchcancel", null)
6121 .on(
"touchend", null);
6123 if (this.zoom_kind === 0) {
6126 d3.event.preventDefault();
6128 var now =
new Date();
6130 var diff = now.getTime() - this.last_touch.getTime();
6132 if ((diff > 500) && (diff<2000) && !this.frame_painter().IsTooltipShown()) {
6133 this.ShowContextMenu(
'main', { clientX: this.zoom_curr[0], clientY: this.zoom_curr[1] });
6134 this.last_touch =
new Date(0);
6136 this.clearInteractiveElements();
6140 if (this.zoom_kind < 100)
return;
6142 d3.event.preventDefault();
6143 d3.select(window).on(
"touchmove.zoomRect", null)
6144 .on(
"touchend.zoomRect", null)
6145 .on(
"touchcancel.zoomRect", null);
6147 var xmin, xmax, ymin, ymax, isany =
false;
6149 if ((this.zoom_kind != 103) && (Math.abs(
this.zoom_curr[0] -
this.zoom_origin[0]) > 10)) {
6150 xmin = Math.min(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
6151 xmax = Math.max(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
6155 if ((this.zoom_kind != 102) && (Math.abs(
this.zoom_curr[1] -
this.zoom_origin[1]) > 10)) {
6156 ymin = Math.min(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
6157 ymax = Math.max(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
6161 this.clearInteractiveElements();
6162 this.last_touch =
new Date(0);
6164 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
6166 d3.event.stopPropagation();
6169 JSROOT.THistPainter.prototype.mouseWheel =
function() {
6170 d3.event.stopPropagation();
6173 switch (d3.event.deltaMode) {
6174 case 0: delta = d3.event.deltaY / this.pad_height() * 2;
break;
6175 case 1: delta = d3.event.deltaY / this.pad_height() * 40;
break;
6176 case 2: delta = d3.event.deltaY / this.pad_height() * 200;
break;
6178 if (delta===0)
return;
6180 d3.event.preventDefault();
6182 this.clearInteractiveElements();
6184 if (delta < -0.2) delta = -0.2;
else if (delta>0.2) delta = 0.2;
6186 var xmin = this.scale_xmin, xmax = this.scale_xmax, ymin = undefined, ymax = undefined;
6188 if ((xmin === xmax) && (delta<0)) { xmin = this.xmin; xmax = this.xmax; }
6190 var cur = d3.mouse(this.svg_frame().node());
6193 var dmin = cur[0] / this.frame_width();
6194 if ((dmin>0) && (dmin<1)) {
6195 if (this.options.Logx) {
6196 var factor = (xmin>0) ? JSROOT.log10(xmax/xmin) : 2;
6197 if (factor>10) factor = 10;
else if (factor<1.5) factor = 1.5;
6198 xmin = xmin / Math.pow(factor, delta*dmin);
6199 xmax = xmax * Math.pow(factor, delta*(1-dmin));
6201 var rx = (xmax - xmin);
6202 if (delta>0) rx = 1.001 * rx / (1-delta);
6203 xmin += -delta*dmin*rx;
6204 xmax -= -delta*(1-dmin)*rx;
6206 if (xmin >= xmax) xmin = xmax = undefined;
6208 xmin = xmax = undefined;
6212 if ((this.Dimension() > 1) || (cur[0] < 0)) {
6213 ymin = this.scale_ymin; ymax = this.scale_ymax;
6215 if ((ymin === ymax) && (delta<0)) { ymin = this.ymin; ymax = this.ymax; }
6217 var dmin = 1 - cur[1] / this.frame_height();
6219 if ((ymin < ymax) && (dmin>0) && (dmin<1)) {
6220 if (this.options.Logy) {
6221 var factor = (ymin>0) ? JSROOT.log10(ymax/ymin) : 2;
6222 if (factor>10) factor = 10;
else if (factor<1.5) factor = 1.5;
6223 ymin = ymin / Math.pow(factor, delta*dmin);
6224 ymax = ymax * Math.pow(factor, delta*(1-dmin));
6226 var ry = (ymax - ymin);
6227 if (delta>0) ry = 1.001 * ry / (1-delta);
6228 ymin += -delta*dmin*ry;
6229 ymax -= -delta*(1-dmin)*ry;
6231 if (ymin >= ymax) ymin = ymax = undefined;
6233 ymin = ymax = undefined;
6237 this.Zoom(xmin,xmax,ymin,ymax);
6240 JSROOT.THistPainter.prototype.AddInteractive =
function() {
6243 if ((!JSROOT.gStyle.Zooming && !JSROOT.gStyle.ContextMenu) || !this.is_main_painter())
return;
6245 this.last_touch =
new Date(0);
6247 this.zoom_rect = null;
6248 this.zoom_origin = null;
6249 this.zoom_curr = null;
6252 if (JSROOT.gStyle.Zooming) {
6253 this.svg_frame().on(
"mousedown", this.startRectSel.bind(
this) );
6254 this.svg_frame().on(
"dblclick", this.mouseDoubleClick.bind(
this) );
6255 this.svg_frame().on(
"wheel", this.mouseWheel.bind(
this) );
6258 if (JSROOT.touches && (JSROOT.gStyle.Zooming || JSROOT.gStyle.ContextMenu))
6259 this.svg_frame().on(
"touchstart", this.startTouchZoom.bind(
this) );
6261 if (JSROOT.gStyle.ContextMenu) {
6262 if (JSROOT.touches) {
6263 this.svg_frame().selectAll(
".xaxis_container")
6264 .on(
"touchstart", this.startTouchMenu.bind(
this,
"x") );
6265 this.svg_frame().selectAll(
".yaxis_container")
6266 .on(
"touchstart", this.startTouchMenu.bind(
this,
"y") );
6268 this.svg_frame().on(
"contextmenu", this.ShowContextMenu.bind(
this) );
6269 this.svg_frame().selectAll(
".xaxis_container")
6270 .on(
"contextmenu", this.ShowContextMenu.bind(
this,
"x"));
6271 this.svg_frame().selectAll(
".yaxis_container")
6272 .on(
"contextmenu", this.ShowContextMenu.bind(
this,
"y"));
6276 JSROOT.THistPainter.prototype.ShowContextMenu =
function(kind, evnt, obj) {
6278 if ((
'zoom_kind' in
this) && (this.zoom_kind > 100))
return;
6287 var menu_painter =
this, frame_corner =
false;
6290 d3.event.preventDefault();
6291 d3.event.stopPropagation();
6294 if (kind === undefined) {
6295 var ms = d3.mouse(this.svg_frame().node());
6296 var tch = d3.touches(this.svg_frame().node());
6297 var pnt = null, pp = this.pad_painter(
true), fp = this.frame_painter(), sel = null;
6299 if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch:
true };
else
6300 if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch:
false };
6302 if ((pnt !== null) && (pp !== null)) {
6303 pnt.painters =
true;
6304 var hints = pp.GetTooltips(pnt);
6306 var bestdist = 1000;
6307 for (var n=0;n<hints.length;++n)
6308 if (hints[n] && hints[n].menu) {
6309 var dist = (
'menu_dist' in hints[n]) ? hints[n].menu_dist : 7;
6310 if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; }
6314 if (sel!==null) menu_painter = sel;
else
6315 if (fp!==null) kind =
"frame";
6317 if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20);
6322 menu_painter.ctx_menu_evnt = evnt;
6324 JSROOT.Painter.createMenu(
function(menu) {
6325 menu.painter =
this;
6326 var domenu = this.FillContextMenu(menu, kind, obj);
6329 if (fp && (!domenu || (frame_corner && (kind!==
"frame"))))
6330 domenu = fp.FillContextMenu(menu);
6334 this.SwitchTooltip(
false);
6335 menu.show(this.ctx_menu_evnt, this.SwitchTooltip.bind(
this,
true) );
6339 delete this.ctx_menu_evnt;
6340 }.bind(menu_painter) );
6344 JSROOT.THistPainter.prototype.ChangeUserRange =
function(arg) {
6345 var taxis = this.histo[
'f'+arg+
"axis"];
6348 var curr =
"[1," + taxis.fNbins+
"]";
6349 if (taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
6350 curr =
"[" +taxis.fFirst+
"," + taxis.fLast+
"]";
6352 var res = prompt(
"Enter user range for axis " + arg +
" like [1," + taxis.fNbins +
"]", curr);
6353 if (res==null)
return;
6354 res = JSON.parse(res);
6356 if (!res || (res.length!=2) || isNaN(res[0]) || isNaN(res[1]))
return;
6357 taxis.fFirst = parseInt(res[0]);
6358 taxis.fLast = parseInt(res[1]);
6360 var newflag = (taxis.fFirst < taxis.fLast) && (taxis.fFirst >= 1) && (taxis.fLast<=taxis.fNbins);
6361 if (newflag != taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
6362 taxis.InvertBit(JSROOT.EAxisBits.kAxisRange);
6367 JSROOT.THistPainter.prototype.FillContextMenu =
function(menu, kind, obj) {
6370 this.clearInteractiveElements();
6372 if ((kind==
"x") || (kind==
"y") || (kind==
"z")) {
6373 var faxis = this.histo.fXaxis;
6374 if (kind==
"y") faxis = this.histo.fYaxis;
else
6375 if (kind==
"z") faxis = obj ? obj : this.histo.fZaxis;
6376 menu.add(
"header: " + kind.toUpperCase() +
" axis");
6377 menu.add(
"Unzoom", this.Unzoom.bind(
this, kind));
6378 menu.addchk(this.options[
"Log" + kind],
"SetLog"+kind, this.ToggleLog.bind(
this, kind) );
6379 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kMoreLogLabels),
"More log",
6380 function() { faxis.InvertBit(JSROOT.EAxisBits.kMoreLogLabels); this.RedrawPad(); });
6381 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kNoExponent),
"No exponent",
6382 function() { faxis.InvertBit(JSROOT.EAxisBits.kNoExponent); this.RedrawPad(); });
6383 if (faxis != null) {
6384 menu.add(
"sub:Labels");
6385 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterLabels),
"Center",
6386 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterLabels); this.RedrawPad(); });
6387 this.AddColorMenuEntry(menu,
"Color", faxis.fLabelColor,
6388 function(arg) { faxis.fLabelColor = parseInt(arg); this.RedrawPad(); });
6389 this.AddSizeMenuEntry(menu,
"Offset", 0, 0.1, 0.01, faxis.fLabelOffset,
6390 function(arg) { faxis.fLabelOffset = parseFloat(arg); this.RedrawPad(); } );
6391 this.AddSizeMenuEntry(menu,
"Size", 0.02, 0.11, 0.01, faxis.fLabelSize,
6392 function(arg) { faxis.fLabelSize = parseFloat(arg); this.RedrawPad(); } );
6393 menu.add(
"endsub:");
6394 menu.add(
"sub:Title");
6395 menu.add(
"SetTitle",
function() {
6396 var t = prompt(
"Enter axis title", faxis.fTitle);
6397 if (t!==null) { faxis.fTitle = t; this.RedrawPad(); }
6399 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterTitle),
"Center",
6400 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); this.RedrawPad(); });
6401 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kRotateTitle),
"Rotate",
6402 function() { faxis.InvertBit(JSROOT.EAxisBits.kRotateTitle); this.RedrawPad(); });
6403 this.AddColorMenuEntry(menu,
"Color", faxis.fTitleColor,
6404 function(arg) { faxis.fTitleColor = parseInt(arg); this.RedrawPad(); });
6405 this.AddSizeMenuEntry(menu,
"Offset", 0, 3, 0.2, faxis.fTitleOffset,
6406 function(arg) { faxis.fTitleOffset = parseFloat(arg); this.RedrawPad(); } );
6407 this.AddSizeMenuEntry(menu,
"Size", 0.02, 0.11, 0.01, faxis.fTitleSize,
6408 function(arg) { faxis.fTitleSize = parseFloat(arg); this.RedrawPad(); } );
6409 menu.add(
"endsub:");
6411 menu.add(
"sub:Ticks");
6412 this.AddColorMenuEntry(menu,
"Color", faxis.fLineColor,
6413 function(arg) { faxis.fLineColor = parseInt(arg); this.RedrawPad(); });
6414 this.AddColorMenuEntry(menu,
"Color", faxis.fAxisColor,
6415 function(arg) { faxis.fAxisColor = parseInt(arg); this.RedrawPad(); });
6416 this.AddSizeMenuEntry(menu,
"Size", -0.05, 0.055, 0.01, faxis.fTickLength,
6417 function(arg) { faxis.fTickLength = parseFloat(arg); this.RedrawPad(); } );
6418 menu.add(
"endsub:");
6422 if (kind ==
"frame") {
6423 var fp = this.frame_painter();
6424 if (fp)
return fp.FillContextMenu(menu);
6427 menu.add(
"header:"+ this.histo._typename +
"::" +
this.histo.fName);
6429 if (this.draw_content) {
6430 menu.addchk(this.ToggleStat(
'only-check'),
"Show statbox",
function() { this.ToggleStat(); });
6431 if (this.Dimension() == 1) {
6432 menu.add(
"User range X",
"X", this.ChangeUserRange);
6434 menu.add(
"sub:User ranges");
6435 menu.add(
"X",
"X", this.ChangeUserRange);
6436 menu.add(
"Y",
"Y", this.ChangeUserRange);
6437 if (this.Dimension() > 2)
6438 menu.add(
"Z",
"Z", this.ChangeUserRange);
6443 if (
'FillHistContextMenu' in
this)
6444 this.FillHistContextMenu(menu);
6446 this.FillAttContextMenu(menu);
6451 JSROOT.THistPainter.prototype.ButtonClick =
function(funcname) {
6452 if (!this.is_main_painter())
return false;
6455 if ((this.zoom_xmin !== this.zoom_xmax) || (this.zoom_ymin !== this.zoom_ymax) || (this.zoom_zmin !== this.zoom_zmax)) {
6459 if (this.draw_content && (
'AutoZoom' in
this) && (this.Dimension() < 3)) {
6464 case "ToggleLogX": this.ToggleLog(
"x");
break;
6465 case "ToggleLogY": this.ToggleLog(
"y");
break;
6466 case "ToggleLogZ": this.ToggleLog(
"z");
break;
6467 case "ToggleStatBox": this.ToggleStat();
return true;
break;
6472 JSROOT.THistPainter.prototype.FillToolbar =
function() {
6473 var pp = this.pad_painter(
true);
6474 if (pp===null)
return;
6476 pp.AddButton(JSROOT.ToolbarIcons.auto_zoom,
'Toggle between unzoom and autozoom-in',
'ToggleZoom');
6477 pp.AddButton(JSROOT.ToolbarIcons.arrow_right,
"Toggle log x",
"ToggleLogX");
6478 pp.AddButton(JSROOT.ToolbarIcons.arrow_up,
"Toggle log y",
"ToggleLogY");
6479 if (this.Dimension() > 1)
6480 pp.AddButton(JSROOT.ToolbarIcons.arrow_diag,
"Toggle log z",
"ToggleLogZ");
6481 if (this.draw_content)
6482 pp.AddButton(JSROOT.ToolbarIcons.statbox,
'Toggle stat box',
"ToggleStatBox");
6487 JSROOT.TH1Painter =
function(histo) {
6488 JSROOT.THistPainter.call(
this, histo);
6491 JSROOT.TH1Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
6493 JSROOT.TH1Painter.prototype.ScanContent =
function() {
6497 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0;
6499 var profile = this.IsTProfile();
6501 this.nbinsx = this.histo.fXaxis.fNbins;
6504 for (var i = 0; i < this.nbinsx; ++i) {
6505 var value = this.histo.getBinContent(i + 1), err = 0;
6506 hsum += profile ? this.histo.fBinEntries[i + 1] : value;
6508 if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value;
6509 if (this.options.Error > 0) err = this.histo.getBinError(i + 1);
6511 hmin = value - err; hmax = value + err;
6513 hmin = Math.min(hmin, value - err);
6514 hmax = Math.max(hmax, value + err);
6520 hsum += this.histo.fBinEntries[0] + this.histo.fBinEntries[this.nbinsx + 1];
6522 hsum += this.histo.getBinContent(0) + this.histo.getBinContent(this.nbinsx + 1);
6524 this.stat_entries = hsum;
6525 if (this.histo.fEntries>1) this.stat_entries = this.histo.fEntries;
6527 this.CreateAxisFuncs(
false);
6532 this.ymin_nz = hmin_nz;
6534 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) {
6535 this.draw_content =
false;
6539 this.draw_content =
true;
6543 if (hmin == 0) { this.ymin = 0; this.ymax = 1; }
else
6544 if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
6545 else { this.ymin = 0; this.ymax = hmin * 2; }
6547 var dy = (hmax - hmin) * 0.05;
6548 this.ymin = hmin - dy;
6549 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
6550 this.ymax = hmax + dy;
6554 var set_zoom =
false;
6555 if (this.histo.fMinimum != -1111) {
6556 hmin = this.histo.fMinimum;
6557 if (hmin < this.ymin)
6562 if (this.histo.fMaximum != -1111) {
6563 hmax = this.histo.fMaximum;
6564 if (hmax > this.ymax)
6571 this.zoom_ymin = (hmin == null) ? this.ymin : hmin;
6572 this.zoom_ymax = (hmax == null) ? this.ymax : hmax;
6576 if (this.is_main_painter() && (this.zoom_xmin === this.zoom_xmax) &&
6577 this.histo.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
6578 (this.histo.fXaxis.fFirst !== this.histo.fXaxis.fLast) &&
6579 ((this.histo.fXaxis.fFirst>1) || (this.histo.fXaxis.fLast <= this.nbinsx))) {
6580 this.zoom_xmin = this.histo.fXaxis.fFirst > 1 ? this.GetBinX(this.histo.fXaxis.fFirst-1) : this.xmin;
6581 this.zoom_xmax = this.histo.fXaxis.fLast <= this.nbinsx ? this.GetBinX(this.histo.fXaxis.fLast) : this.xmax;
6585 if (this.options.Bar == 0 &&
this.options.Hist == 0
6586 &&
this.options.Error == 0 &&
this.options.Same == 0) {
6587 this.draw_content =
false;
6589 if (this.options.Axis > 0) {
6590 this.draw_content =
false;
6594 JSROOT.TH1Painter.prototype.CountStat =
function(cond) {
6595 var profile = this.IsTProfile();
6597 var stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0;
6599 var left = this.GetSelectIndex(
"x",
"left");
6600 var right = this.GetSelectIndex(
"x",
"right");
6602 var xx = 0, w = 0, xmax = null, wmax = null;
6604 for (var i = left; i < right; ++i) {
6605 xx = this.GetBinX(i+0.5);
6607 if ((cond!=null) && !cond(xx))
continue;
6610 w = this.histo.fBinEntries[i + 1];
6611 stat_sumwy += this.histo.fArray[i + 1];
6612 stat_sumwy2 += this.histo.fSumw2[i + 1];
6614 w = this.histo.getBinContent(i + 1);
6617 if ((xmax==null) || (w>wmax)) { xmax = xx; wmax = w; }
6620 stat_sumwx += w * xx;
6621 stat_sumwx2 += w * xx * xx;
6625 if (!this.IsAxisZoomed(
"x") && (this.histo.fTsumw>0)) {
6626 stat_sumw = this.histo.fTsumw;
6627 stat_sumwx = this.histo.fTsumwx;
6628 stat_sumwx2 = this.histo.fTsumwx2;
6631 var res = { meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: stat_sumw, entries: this.stat_entries, xmax:0, wmax:0 };
6633 if (stat_sumw > 0) {
6634 res.meanx = stat_sumwx / stat_sumw;
6635 res.meany = stat_sumwy / stat_sumw;
6636 res.rmsx = Math.sqrt(stat_sumwx2 / stat_sumw - res.meanx * res.meanx);
6637 res.rmsy = Math.sqrt(stat_sumwy2 / stat_sumw - res.meany * res.meany);
6648 JSROOT.TH1Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
6649 if (!this.histo)
return false;
6651 var pave = stat.GetObject(),
6652 data = this.CountStat(),
6653 print_name = dostat % 10,
6654 print_entries = Math.floor(dostat / 10) % 10,
6655 print_mean = Math.floor(dostat / 100) % 10,
6656 print_rms = Math.floor(dostat / 1000) % 10,
6657 print_under = Math.floor(dostat / 10000) % 10,
6658 print_over = Math.floor(dostat / 100000) % 10,
6659 print_integral = Math.floor(dostat / 1000000) % 10,
6660 print_skew = Math.floor(dostat / 10000000) % 10,
6661 print_kurt = Math.floor(dostat / 100000000) % 10;
6664 pave.AddText(this.histo.fName);
6666 if (this.IsTProfile()) {
6668 if (print_entries > 0)
6669 pave.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
6671 if (print_mean > 0) {
6672 pave.AddText(
"Mean = " + stat.Format(data.meanx));
6673 pave.AddText(
"Mean y = " + stat.Format(data.meany));
6676 if (print_rms > 0) {
6677 pave.AddText(
"Std Dev = " + stat.Format(data.rmsx));
6678 pave.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
6683 if (print_entries > 0)
6684 pave.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
6686 if (print_mean > 0) {
6687 pave.AddText(
"Mean = " + stat.Format(data.meanx));
6690 if (print_rms > 0) {
6691 pave.AddText(
"Std Dev = " + stat.Format(data.rmsx));
6694 if (print_under > 0) {
6695 var res = (this.histo.fArray.length > 0) ? this.histo.fArray[0] : 0;
6696 pave.AddText(
"Underflow = " + stat.Format(res));
6699 if (print_over > 0) {
6700 var res = (this.histo.fArray.length > 0) ? this.histo.fArray[
this.histo.fArray.length - 1] : 0;
6701 pave.AddText(
"Overflow = " + stat.Format(res));
6704 if (print_integral > 0) {
6705 pave.AddText(
"Integral = " + stat.Format(data.integral,
"entries"));
6709 pave.AddText(
"Skew = <not avail>");
6712 pave.AddText(
"Kurt = <not avail>");
6716 var f1 = this.FindF1();
6718 var print_fval = dofit%10;
6719 var print_ferrors = Math.floor(dofit/10) % 10;
6720 var print_fchi2 = Math.floor(dofit/100) % 10;
6721 var print_fprob = Math.floor(dofit/1000) % 10;
6723 if (print_fchi2 > 0)
6724 pave.AddText(
"#chi^2 / ndf = " + stat.Format(f1.fChisquare,
"fit") +
" / " + f1.fNDF);
6725 if (print_fprob > 0)
6726 pave.AddText(
"Prob = " + ((
'Math' in JSROOT) ? stat.Format(JSROOT.Math.Prob(f1.fChisquare, f1.fNDF)) :
"<not avail>"));
6727 if (print_fval > 0) {
6728 for(var n=0;n<f1.fNpar;++n) {
6729 var parname = f1.GetParName(n);
6730 var parvalue = f1.GetParValue(n);
6731 if (parvalue != null) parvalue = stat.Format(Number(parvalue),
"fit");
6732 else parvalue =
"<not avail>";
6734 if (f1.fParErrors!=null) {
6735 parerr = stat.Format(f1.fParErrors[n],
"last");
6736 if ((Number(parerr)==0.0) && (f1.fParErrors[n]!=0.0)) parerr = stat.Format(f1.fParErrors[n],
"4.2g");
6739 if ((print_ferrors > 0) && (parerr.length > 0))
6740 pave.AddText(parname +
" = " + parvalue +
" #pm " + parerr);
6742 pave.AddText(parname +
" = " + parvalue);
6749 var nlines = pave.fLines.arr.length,
6750 stath = nlines * JSROOT.gStyle.StatFontSize;
6751 if ((stath <= 0) || (JSROOT.gStyle.StatFont % 10 === 3)) {
6752 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
6753 pave.fY1NDC = 0.93 - stath;
6761 JSROOT.TH1Painter.prototype.DrawBins =
function() {
6765 var width = this.frame_width(), height = this.frame_height();
6767 if (!this.draw_content || (width<=0) || (height<=0))
6768 return this.RemoveDrawG();
6770 this.RecreateDrawG(
false,
"main_layer");
6772 var left = this.GetSelectIndex(
"x",
"left", -1),
6773 right = this.GetSelectIndex(
"x",
"right", 2),
6774 pmain = this.main_painter(),
6776 res =
"", lastbin =
false,
6777 startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, besti,
6778 exclude_zero = (this.options.Error!==10) && (this.options.Mark!==10),
6779 show_errors = (this.options.Error > 0),
6780 show_markers = (this.options.Mark > 0),
6781 path_fill = null, path_err = null, path_marker = null,
6782 endx =
"", endy =
"", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, mpath =
"";
6784 if (show_errors && !show_markers && (this.histo.fMarkerStyle > 1))
6785 show_markers =
true;
6787 if (this.options.Error == 12) {
6788 if (this.fillatt.color==
'none') show_markers =
true;
6789 else path_fill =
"";
6791 if (this.options.Error > 0) path_err =
"";
6795 if (!this.markeratt)
6796 this.markeratt = JSROOT.Painter.createAttMarker(this.histo);
6797 if (this.markeratt.size > 0) {
6800 this.markeratt.reset_pos();
6802 show_markers =
false;
6808 var use_minmax = ((right-left) > 3*width);
6810 if (this.options.Error == 11) {
6811 var lw = this.lineatt.width + JSROOT.gStyle.EndErrorSize;
6812 endx =
"m0," + lw +
"v-" + 2*lw +
"m0," + lw;
6813 endy =
"m" + lw +
",0h-" + 2*lw +
"m" + lw +
",0";
6814 dend = Math.floor((this.lineatt.width-1)/2);
6817 var draw_markers = show_errors || show_markers;
6819 if (draw_markers) use_minmax =
true;
6821 for (i = left; i <= right; ++i) {
6823 x = this.GetBinX(i);
6825 if (this.options.Logx && (x <= 0))
continue;
6827 grx = Math.round(pmain.grx(x));
6829 lastbin = (i === right);
6831 if (lastbin && (left<right)) {
6834 y = this.histo.getBinContent(i+1);
6835 if (this.options.Logy && (y <
this.scale_ymin))
6838 gry = Math.round(pmain.gry(y));
6841 if (res.length === 0) {
6843 prevx = startx = currx = grx;
6844 prevy = curry_min = curry_max = curry = gry;
6845 res =
"M"+currx+
","+curry;
6848 if ((grx === currx) && !lastbin) {
6849 if (gry < curry_min) besti = i;
6850 curry_min = Math.min(curry_min, gry);
6851 curry_max = Math.max(curry_max, gry);
6856 bincont = this.histo.getBinContent(besti+1);
6857 if (!exclude_zero || (bincont!==0)) {
6859 mx1 = Math.round(pmain.grx(
this.GetBinX(besti)));
6860 mx2 = Math.round(pmain.grx(
this.GetBinX(besti+1)));
6861 my = Math.round(pmain.gry(bincont));
6864 binerr = this.histo.getBinError(besti+1);
6865 yerr1 = Math.round(my - pmain.gry(bincont + binerr));
6866 yerr2 = Math.round(pmain.gry(bincont - binerr) - my);
6869 if ((my >= -yerr1) && (my <= height + yerr2)) {
6870 if (path_fill !== null)
6871 path_fill +=
"M" + mx1 +
","+(my-yerr1) +
6872 "h" + (mx2-mx1) +
"v" + (yerr1+yerr2+1) +
"h-" + (mx2-mx1) +
"z";
6873 if (path_err !== null)
6874 path_err +=
"M" + (mx1+dend) +
","+ my + endx +
"h" + (mx2-mx1-2*dend) + endx +
6875 "M" + Math.round((mx1+mx2)/2) +
"," + (my-yerr1+dend) + endy +
"v" + (yerr1+yerr2-2*dend) + endy;
6876 if (path_marker !== null)
6877 path_marker += this.markeratt.create((mx1+mx2)/2, my);
6883 if (!draw_markers && ((curry_min !== curry_max) || (prevy !== curry_min))) {
6885 if (prevx !== currx)
6886 res +=
"h"+(currx-prevx);
6888 if (curry === curry_min) {
6889 if (curry_max !== prevy)
6890 res +=
"v" + (curry_max - prevy);
6891 if (curry_min !== curry_max)
6892 res +=
"v" + (curry_min - curry_max);
6894 if (curry_min !== prevy)
6895 res +=
"v" + (curry_min - prevy);
6896 if (curry_max !== curry_min)
6897 res +=
"v" + (curry_max - curry_min);
6898 if (curry !== curry_max)
6899 res +=
"v" + (curry - curry_max);
6906 if (lastbin && (prevx !== grx))
6907 res +=
"h"+(grx-prevx);
6910 curry_min = curry_max = curry = gry;
6914 if ((gry !== curry) || lastbin) {
6915 if (grx !== currx) res +=
"h"+(grx-currx);
6916 if (gry !== curry) res +=
"v"+(gry-curry);
6922 if ((this.fillatt.color !==
'none') && (res.length>0)) {
6923 var h0 = (height+3);
6924 if ((this.hmin>=0) && (pmain.gry(0) < height)) h0 = Math.round(pmain.gry(0));
6925 res +=
"L"+currx+
","+h0 +
"L"+startx+
","+h0 +
"Z";
6930 if ((path_fill !== null) && (path_fill.length > 0))
6931 this.draw_g.append(
"svg:path")
6932 .attr(
"d", path_fill)
6933 .call(this.fillatt.func);
6935 if ((path_err !== null) && (path_err.length > 0))
6936 this.draw_g.append(
"svg:path")
6937 .attr(
"d", path_err)
6938 .call(this.lineatt.func)
6940 if ((path_marker !== null) && (path_marker.length > 0))
6941 this.draw_g.append(
"svg:path")
6942 .attr(
"d", path_marker)
6943 .call(this.markeratt.func);
6946 if (res.length > 0) {
6947 this.draw_g.append(
"svg:path")
6949 .style(
"stroke-linejoin",
"miter")
6950 .call(this.lineatt.func)
6951 .call(this.fillatt.func);
6955 JSROOT.TH1Painter.prototype.GetBinTips =
function(bin,asstr) {
6956 var tips = [], name = this.GetTipName(), pmain = this.main_painter();
6957 if (name.length>0) tips.push(name);
6959 var x1 = this.GetBinX(bin),
6960 x2 = this.GetBinX(bin+1),
6961 cont = this.histo.getBinContent(bin+1);
6963 if ((this.options.Error > 0) || (
this.options.Mark > 0)) {
6964 tips.push(
"x = " + pmain.AxisAsText(
"x", (x1+x2)/2));
6965 tips.push(
"y = " + pmain.AxisAsText(
"y", cont));
6966 if (this.options.Error > 0) {
6967 tips.push(
"error x = " + ((x2 - x1) / 2).toPrecision(4));
6968 tips.push(
"error y = " + this.histo.getBinError(bin + 1).toPrecision(4));
6971 tips.push(
"bin = " + (bin+1));
6973 if (pmain.x_kind ===
'labels')
6974 tips.push(
"x = " + pmain.AxisAsText(
"x", x1));
6976 if (pmain.x_kind ===
'time')
6977 tips.push(
"x = " + pmain.AxisAsText(
"x", (x1+x2)/2));
6979 tips.push(
"x = [" + pmain.AxisAsText(
"x", x1) +
", " + pmain.AxisAsText(
"x", x2) +
")");
6981 if (cont === Math.round(cont))
6982 tips.push(
"entries = " + cont);
6984 tips.push(
"entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.StatFormat));
6987 if (!asstr)
return tips;
6990 for (var n=0;n<tips.length;++n) res += (n>0 ?
"\n" :
"") + tips[n];
6994 JSROOT.TH1Painter.prototype.ProcessTooltip =
function(pnt) {
6995 if ((pnt === null) || !this.draw_content) {
6996 if (this.draw_g !== null)
6997 this.draw_g.select(
".tooltip_bin").remove();
6998 this.ProvideUserTooltip(null);
7002 var width = this.frame_width(),
7003 height = this.frame_height(),
7004 pmain = this.main_painter(),
7006 findbin = null, show_rect =
true,
7007 grx1, midx, grx2, gry1, midy, gry2,
7008 left = this.GetSelectIndex(
"x",
"left", -1),
7009 right = this.GetSelectIndex(
"x",
"right", 2),
7010 l = left, r = right;
7012 function GetBinGrX(i) {
7013 var x1 = painter.GetBinX(i);
7014 if ((x1<0) && painter.options.Logx)
return null;
7015 return pmain.grx(x1);
7018 function GetBinGrY(i) {
7019 var y = painter.histo.getBinContent(i + 1);
7020 if (painter.options.Logy && (y < painter.scale_ymin))
7022 return Math.round(pmain.gry(y));
7026 var m = Math.round((l+r)*0.5);
7028 var xx = GetBinGrX(m);
7029 if (xx === null) { l = m;
continue; }
7031 if (xx < pnt.x - 0.5) l = m;
else
7032 if (xx > pnt.x + 0.5) r = m;
else { l++; r--; }
7036 grx1 = GetBinGrX(findbin);
7038 while ((l>left) && (GetBinGrX(l-1) > grx1 - 1.0)) --l;
7039 while ((r<right) && (GetBinGrX(r+1) < grx1 + 1.0)) ++r;
7045 for (var m=l;m<=r;m++) {
7046 var dist = Math.abs(GetBinGrY(m) - pnt.y);
7047 if (dist < best) { best = dist; findbin = m; }
7051 if (best > height/10)
7052 findbin = Math.round(l + (r-l) / height * pnt.y);
7054 grx1 = GetBinGrX(findbin);
7057 grx1 = Math.round(grx1);
7058 grx2 = Math.round(GetBinGrX(findbin+1));
7060 midx = Math.round((grx1+grx2)/2);
7062 midy = gry1 = gry2 = GetBinGrY(findbin);
7065 if ((this.options.Error > 0) || (
this.options.Mark > 0)) {
7070 if (this.markeratt) msize = Math.max(msize, 2+Math.round(
this.markeratt.size * 4));
7073 if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; }
7075 if (this.options.Error > 0) {
7076 var cont = this.histo.getBinContent(findbin+1);
7077 var binerr = this.histo.getBinError(findbin+1);
7079 gry1 = Math.round(pmain.gry(cont + binerr));
7080 gry2 = Math.round(pmain.gry(cont - binerr));
7083 gry1 = Math.min(gry1, midy - msize);
7084 gry2 = Math.max(gry2, midy + msize);
7086 if (!pnt.touch && (pnt.nproc === 1))
7087 if ((pnt.y<gry1) || (pnt.y>gry2)) findbin = null;
7093 show_rect = (pnt.nproc === 1) && (right-left < width);
7097 if ((pnt.y < gry1) && !pnt.touch) findbin = null;
7101 if ((this.fillatt.color !==
'none') && (this.hmin>=0)) {
7102 gry2 = Math.round(pmain.gry(0));
7103 if ((gry2 > height) || (gry2 <= gry1)) gry2 = height;
7108 if (findbin!==null) {
7110 if ((findbin === left) && (grx1 > pnt.x + 2)) findbin = null;
else
7111 if ((findbin === right-1) && (grx2 < pnt.x - 2)) findbin = null;
7115 var ttrect = this.draw_g.select(
".tooltip_bin");
7117 if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) {
7119 this.ProvideUserTooltip(null);
7123 var res = { x: midx, y: midy,
7124 color1: this.lineatt.color, color2: this.fillatt.color,
7125 lines: this.GetBinTips(findbin) };
7130 ttrect = this.draw_g.append(
"svg:rect")
7131 .attr(
"class",
"tooltip_bin h1bin")
7132 .style(
"pointer-events",
"none");
7134 res.changed = ttrect.property(
"current_bin") !== findbin;
7137 ttrect.attr(
"x", grx1)
7138 .attr(
"width", grx2-grx1)
7140 .attr(
"height", gry2-gry1)
7141 .style(
"opacity",
"0.3")
7142 .property(
"current_bin", findbin);
7144 res.exact = (Math.abs(midy - pnt.y) <= 5) || ((pnt.y>=gry1) && (pnt.y<=gry2));
7148 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
7151 var radius = this.lineatt.width + 3;
7154 ttrect = this.draw_g.append(
"svg:circle")
7155 .attr(
"class",
"tooltip_bin")
7156 .style(
"pointer-events",
"none")
7158 .call(this.lineatt.func)
7159 .call(this.fillatt.func);
7161 res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius);
7163 res.menu = res.exact;
7164 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
7166 res.changed = ttrect.property(
"current_bin") !== findbin;
7169 ttrect.attr(
"cx", midx)
7171 .property(
"current_bin", findbin);
7174 if (this.IsUserTooltipCallback() && res.changed) {
7175 this.ProvideUserTooltip({ obj: this.histo, name: this.histo.fName,
7176 bin: findbin, cont: this.histo.getBinContent(findbin+1),
7177 grx: midx, gry: midy });
7184 JSROOT.TH1Painter.prototype.FillHistContextMenu =
function(menu) {
7185 if (!this.draw_content)
return;
7187 menu.add(
"Auto zoom-in", this.AutoZoom.bind(
this));
7188 menu.addDrawMenu(
"Draw with", [
"hist",
"p",
"e",
"e1",
"pe2"],
function(arg) {
7189 this.options = this.DecodeOptions(arg);
7194 JSROOT.TH1Painter.prototype.AutoZoom =
function() {
7195 var left = this.GetSelectIndex(
"x",
"left", -1),
7196 right = this.GetSelectIndex(
"x",
"right", 1),
7197 dist = right - left;
7199 if (dist == 0)
return;
7202 var min = this.histo.getBinContent(left + 1);
7203 for (var indx = left; indx < right; ++indx)
7204 if (this.histo.getBinContent(indx + 1) < min)
7205 min = this.histo.getBinContent(indx + 1);
7208 while ((left < right) && (this.histo.getBinContent(left + 1) <= min)) ++left;
7209 while ((left < right) && (this.histo.getBinContent(right) <= min)) --right;
7211 if ((right - left < dist) && (left < right))
7212 this.Zoom(this.GetBinX(left), this.GetBinX(right));
7215 JSROOT.TH1Painter.prototype.CanZoomIn =
function(axis,min,max) {
7216 if ((axis==
"x") && (this.GetIndexX(max,0.5) - this.GetIndexX(min,0) > 1))
return true;
7218 if ((axis==
"y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6))
return true;
7224 JSROOT.TH1Painter.prototype.Redraw =
function() {
7232 JSROOT.Painter.drawHistogram1D =
function(divid, histo, opt) {
7234 var painter =
new JSROOT.TH1Painter(histo);
7236 painter.SetDivId(divid, 1);
7239 painter.options = painter.DecodeOptions(opt);
7241 painter.CheckPadOptions();
7243 painter.ScanContent();
7249 painter.DrawGrids();
7253 painter.DrawTitle();
7255 if (JSROOT.gStyle.AutoStat && painter.create_canvas)
7256 painter.CreateStat();
7258 painter.DrawNextFunction(0,
function() {
7260 painter.AddInteractive();
7262 painter.FillToolbar();
7264 if (painter.options.AutoZoom) painter.AutoZoom();
7266 painter.DrawingReady();
7274 JSROOT.Painter.drawText =
function(divid, text) {
7275 var painter =
new JSROOT.TObjectPainter(text);
7276 painter.SetDivId(divid, 2);
7278 painter.Redraw =
function() {
7279 var text = this.GetObject(),
7280 w = this.pad_width(), h = this.pad_height(),
7281 pos_x = text.fX, pos_y = text.fY,
7282 tcolor = JSROOT.Painter.root_colors[text.fTextColor],
7283 use_pad =
true, latex_kind = 0, fact = 1.;
7285 if (text.TestBit(JSROOT.BIT(14))) {
7288 pos_y = (1 - pos_y) * h;
7290 if (this.main_painter() !== null) {
7291 w = this.frame_width(); h = this.frame_height(); use_pad =
false;
7292 pos_x = this.main_painter().grx(pos_x);
7293 pos_y = this.main_painter().gry(pos_y);
7295 if (this.root_pad() !== null) {
7296 pos_x = this.ConvertToNDC(
"x", pos_x) * w;
7297 pos_y = (1 - this.ConvertToNDC(
"y", pos_y)) * h;
7299 text.fTextAlign = 22;
7302 if (text.fTextSize === 0) text.fTextSize = 0.05;
7303 if (text.fTextColor === 0) text.fTextColor = 1;
7306 this.RecreateDrawG(use_pad, use_pad ?
"text_layer" :
"upper_layer");
7308 if (text._typename ==
'TLatex') { latex_kind = 1; fact = 0.9; }
else
7309 if (text._typename ==
'TMathText') { latex_kind = 2; fact = 0.8; }
7311 this.StartTextDrawing(text.fTextFont, Math.round(text.fTextSize*Math.min(w,h)*fact));
7313 this.DrawText(text.fTextAlign, Math.round(pos_x), Math.round(pos_y), 0, 0, text.fTitle, tcolor, latex_kind);
7315 this.FinishTextDrawing();
7318 return painter.DrawingReady();
7323 JSROOT.RawTextPainter =
function(txt) {
7324 JSROOT.TBasePainter.call(
this);
7329 JSROOT.RawTextPainter.prototype = Object.create( JSROOT.TBasePainter.prototype );
7331 JSROOT.RawTextPainter.prototype.RedrawObject =
function(obj) {
7337 JSROOT.RawTextPainter.prototype.Draw =
function() {
7338 var txt = this.txt.value;
7339 if (txt==null) txt =
"<undefined>";
7341 var mathjax =
'mathjax' in this.txt;
7343 if (!mathjax && !(
'as_is' in this.txt)) {
7344 var arr = txt.split(
"\n"); txt =
"";
7345 for (var i = 0; i < arr.length; ++i)
7346 txt +=
"<pre>" + arr[i] +
"</pre>";
7349 var frame = this.select_main();
7350 var main = frame.select(
"div");
7352 main = frame.append(
"div")
7353 .style(
'max-width',
'100%')
7354 .style(
'max-height',
'100%')
7355 .style(
'overflow',
'auto');
7360 this.SetDivId(this.divid);
7363 if (
this[
'loading_mathjax'])
return;
7364 this[
'loading_mathjax'] =
true;
7366 JSROOT.AssertPrerequisites(
'mathjax',
function() {
7367 painter[
'loading_mathjax'] =
false;
7368 if (typeof MathJax ==
'object') {
7369 MathJax.Hub.Queue([
"Typeset", MathJax.Hub, frame.node()]);
7375 JSROOT.Painter.drawRawText =
function(divid, txt, opt) {
7376 var painter =
new JSROOT.RawTextPainter(txt);
7377 painter.SetDivId(divid);
7379 return painter.DrawingReady();
7384 JSROOT.Painter.FolderHierarchy =
function(item, obj) {
7386 if ((obj==null) || !(
'fFolders' in obj) || (obj.fFolders==null))
return false;
7388 if (obj.fFolders.arr.length===0) { item._more =
false;
return true; }
7392 for ( var i = 0; i < obj.fFolders.arr.length; ++i) {
7393 var chld = obj.fFolders.arr[i];
7394 item._childs.push( {
7396 _kind :
"ROOT." + chld._typename,
7403 JSROOT.Painter.TaskHierarchy =
function(item, obj) {
7407 if ((obj==null) || !(
'fTasks' in obj) || (obj.fTasks==null))
return false;
7409 JSROOT.Painter.ObjectHierarchy(item, obj, { exclude: [
'fTasks',
'fName'] } );
7411 if ((obj.fTasks.arr.length===0) && (item._childs.length==0)) { item._more =
false;
return true; }
7415 for ( var i = 0; i < obj.fTasks.arr.length; ++i) {
7416 var chld = obj.fTasks.arr[i];
7417 item._childs.push( {
7419 _kind :
"ROOT." + chld._typename,
7427 JSROOT.Painter.ListHierarchy =
function(folder, lst) {
7428 if (lst._typename !=
'TList' && lst._typename !=
'TObjArray' && lst._typename !=
'TClonesArray')
return false;
7430 if ((lst.arr === undefined) || (lst.arr.length === 0)) {
7431 folder._more =
false;
7435 folder._childs = [];
7436 for ( var i = 0; i < lst.arr.length; ++i) {
7437 var obj = lst.arr[i];
7443 _name: i.toString(),
7451 _kind :
"ROOT." + obj._typename,
7452 _title : obj.fTitle,
7456 if ((item._name === undefined) ||
7457 (!isNaN(parseInt(item._name)) && (parseInt(item._name)!==i))
7458 || (lst.arr.indexOf(obj)<i))
7459 item._name = i.toString();
7461 if (item._title === undefined)
7462 item._title = obj._typename ? item._kind : item._name;
7465 folder._childs.push(item);
7470 JSROOT.Painter.TreeHierarchy =
function(node, obj) {
7471 if (obj._typename !=
'TTree' && obj._typename !=
'TNtuple')
return false;
7475 for ( var i = 0; i < obj.fBranches.arr.length; ++i) {
7476 var branch = obj.fBranches.arr[i];
7477 var nb_leaves = branch.fLeaves.arr.length;
7480 if (nb_leaves == 1 && branch.fLeaves.arr[0].fName == branch.fName) nb_leaves = 0;
7483 _name : branch.fName,
7484 _kind : nb_leaves > 0 ?
"ROOT.TBranch" :
"ROOT.TLeafF"
7487 node._childs.push(subitem);
7489 if (nb_leaves > 0) {
7490 subitem._childs = [];
7491 for (var j = 0; j < nb_leaves; ++j) {
7493 _name : branch.fLeaves.arr[j].fName,
7494 _kind :
"ROOT.TLeafF"
7496 subitem._childs.push(leafitem);
7504 JSROOT.Painter.KeysHierarchy =
function(folder, keys, file, dirname) {
7506 if (keys === undefined)
return false;
7508 folder._childs = [];
7510 for (var i = 0; i < keys.length; ++i) {
7514 _name : key.fName +
";" + key.fCycle,
7515 _cycle : key.fCycle,
7516 _kind :
"ROOT." + key.fClassName,
7517 _title : key.fTitle,
7518 _keyname : key.fName,
7523 if (
'fRealName' in key)
7524 item._realname = key.fRealName +
";" + key.fCycle;
7526 if (key.fClassName ==
'TDirectory' || key.fClassName ==
'TDirectoryFile') {
7528 if ((dirname!=null) && (file!=null)) dir = file.GetDir(dirname + key.fName);
7531 item._expand =
function(node, obj) {
7533 return JSROOT.Painter.KeysHierarchy(node, obj.fKeys);
7537 item._name = key.fName;
7538 JSROOT.Painter.KeysHierarchy(item, dir.fKeys, file, dirname + key.fName +
"/");
7541 if ((key.fClassName ==
'TList') && (key.fName ==
'StreamerInfo')) {
7542 item._name =
'StreamerInfo';
7543 item._kind =
"ROOT.TStreamerInfoList";
7544 item._title =
"List of streamer infos for binary I/O";
7545 item._readobj = file.fStreamerInfos;
7548 folder._childs.push(item);
7554 JSROOT.Painter.ObjectHierarchy =
function(top, obj, args) {
7555 if ((top==null) || (obj==null))
return false;
7558 var nosimple =
true, prnt = top;
7560 if (
'_nosimple' in prnt) { nosimple = prnt._nosimple;
break; }
7561 prnt = prnt._parent;
7565 if (!(
'_obj' in top))
7568 if (top._obj !== obj) alert(
'object missmatch');
7570 if (!(
'_title' in top) && (
'_typename' in obj))
7571 top._title =
"ROOT." + obj._typename;
7573 for (var key in obj) {
7574 if (key ==
'_typename')
continue;
7576 if (typeof fld ==
'function')
continue;
7577 if (args && args.exclude && (args.exclude.indexOf(key)>=0))
continue;
7585 item._value = item._title =
"null";
7586 if (!nosimple) top._childs.push(item);
7590 var proto = Object.prototype.toString.apply(fld);
7593 if ((proto.lastIndexOf(
'Array]') == proto.length-6) && (proto.indexOf(
'[object')==0)) {
7594 item._title = item._kind +
" len=" + fld.length;
7595 simple = (proto !=
'[object Array]');
7596 if (fld.length === 0) {
7597 item._value =
"[ ]";
7600 item._value =
"[...]";
7602 item._expand = JSROOT.Painter.ObjectHierarchy;
7606 if (typeof fld ==
'object') {
7607 if (
'_typename' in fld)
7608 item._kind = item._title =
"ROOT." + fld._typename;
7611 var curr = top, inparent =
false;
7612 while (curr && !inparent) {
7613 inparent = (curr._obj === fld);
7614 curr = curr._parent;
7618 item._value =
"{ prnt }";
7622 item._value =
"{ }";
7623 if (fld._typename ==
'TColor') item._value = JSROOT.Painter.MakeColorRGB(fld);
7626 if ((typeof fld ==
'number') || (typeof fld ==
'boolean')) {
7629 item._value =
"0x" + fld.toString(16);
7631 item._value = fld.toString();
7632 item._vclass =
'h_value_num';
7634 if (typeof fld ==
'string') {
7636 item._value =
'"' + fld +
'"';
7637 item._vclass =
'h_value_str';
7640 alert(
'miss ' + key +
' ' + typeof fld);
7643 if (!simple || !nosimple)
7644 top._childs.push(item);
7651 JSROOT.hpainter = null;
7653 JSROOT.HierarchyPainter =
function(name, frameid, backgr) {
7654 JSROOT.TBasePainter.call(
this);
7657 this.with_icons =
true;
7658 this.background = backgr;
7659 this.files_monitoring = (frameid == null);
7660 if (frameid != null) this.SetDivId(frameid);
7663 if (JSROOT.hpainter == null)
7664 JSROOT.hpainter =
this;
7667 JSROOT.HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
7669 JSROOT.HierarchyPainter.prototype.Cleanup =
function() {
7674 JSROOT.HierarchyPainter.prototype.FileHierarchy =
function(file) {
7678 _name : file.fFileName,
7679 _kind :
"ROOT.TFile",
7681 _fullurl : file.fFullURL,
7682 _had_direct_read :
false,
7684 _get :
function(item, itemname, callback) {
7688 if ((item!=null) && (item._readobj != null))
7689 return JSROOT.CallBack(callback, item, item._readobj);
7691 if (item!=null) itemname = painter.itemFullName(item, fff);
7695 function ReadFileObject(file) {
7696 if (fff._file==null) fff._file = file;
7698 if (file == null)
return JSROOT.CallBack(callback, item, null);
7700 file.ReadObject(itemname,
function(obj) {
7703 if ((item==null) && (obj!=null)) {
7705 var d = painter.Find({name:itemname, top:fff, last_exists:
true, check_keys:
true });
7706 if ((d!=null) && (
'last' in d) && (d.last!=fff)) {
7708 var dir = file.GetDir(painter.itemFullName(d.last, fff));
7710 d.last._name = d.last._keyname;
7711 var dirname = painter.itemFullName(d.last, fff);
7712 JSROOT.Painter.KeysHierarchy(d.last, dir.fKeys, file, dirname +
"/");
7716 JSROOT.Painter.KeysHierarchy(fff, file.fKeys, file,
"");
7718 item = painter.Find({name:itemname, top: fff});
7722 item._readobj = obj;
7724 if (
'_expand' in item) item._name = item._keyname;
7727 JSROOT.CallBack(callback, item, obj);
7731 if (fff._file != null) {
7732 ReadFileObject(fff._file);
7735 new JSROOT.TFile(fff._fullurl, ReadFileObject);
7740 JSROOT.Painter.KeysHierarchy(folder, file.fKeys, file,
"");
7745 JSROOT.HierarchyPainter.prototype.ForEach =
function(callback, top) {
7747 if (top==null) top = this.h;
7748 if ((top==null) || (typeof callback !=
'function'))
return;
7749 function each_item(item) {
7751 if (
'_childs' in item)
7752 for (var n = 0; n < item._childs.length; ++n) {
7753 item._childs[n]._parent = item;
7754 each_item(item._childs[n]);
7761 JSROOT.HierarchyPainter.prototype.Find =
function(arg) {
7769 function find_in_hierarchy(top, fullname) {
7771 if (!fullname || (fullname.length == 0) || (top==null))
return top;
7775 function process_child(child) {
7777 child._parent = top;
7778 if ((pos + 1 == fullname.length) || (pos < 0))
return child;
7780 return find_in_hierarchy(child, fullname.substr(pos + 1));
7785 pos = fullname.indexOf(
"/", pos + 1);
7787 var localname = (pos < 0) ? fullname : fullname.substr(0, pos);
7790 if (typeof top._childs !=
'undefined')
7791 for (var i = 0; i < top._childs.length; ++i)
7792 if (top._childs[i]._name == localname)
7793 return process_child(top._childs[i]);
7796 if ((
'check_keys' in arg) && (typeof top._childs !=
'undefined'))
7797 for (var i = 0; i < top._childs.length; ++i) {
7798 if (top._childs[i]._name.indexOf(localname +
";")==0)
7799 return process_child(top._childs[i]);
7802 if (
'force' in arg) {
7804 if (! (
'_childs' in top)) top._childs = [];
7805 var child = { _name: localname };
7806 top._childs.push(child);
7807 return process_child(child);
7811 if (arg.allow_index && (typeof top._childs !=
'undefined')) {
7812 var indx = parseInt(localname);
7813 if (!isNaN(indx) && (indx>=0) && (indx<top._childs.length))
7814 return process_child(top._childs[indx]);
7819 return (
'last_exists' in arg) && (top!=null) ? { last : top, rest : fullname } : null;
7825 if (typeof arg ==
'string') { itemname = arg; arg = {}; }
else
7826 if (typeof arg ==
'object') { itemname = arg.name;
if (
'top' in arg) top = arg.top; }
else
7829 return find_in_hierarchy(top, itemname);
7832 JSROOT.HierarchyPainter.prototype.itemFullName =
function(node, uptoparent) {
7835 while (node && (
'_parent' in node)) {
7836 if (res.length > 0) res =
"/" + res;
7837 res = node._name + res;
7838 node = node._parent;
7839 if (uptoparent && (node === uptoparent))
break;
7845 JSROOT.HierarchyPainter.prototype.ExecuteCommand =
function(itemname, callback) {
7850 var hitem = this.Find(itemname);
7851 var url = itemname +
"/cmd.json";
7853 var d3node = d3.select((typeof callback ==
'function') ? null : callback);
7855 if (
'_numargs' in hitem)
7856 for (var n = 0; n < hitem._numargs; ++n) {
7857 var argname =
"arg" + (n+1);
7858 var argvalue = null;
7859 if (n+2<arguments.length) argvalue = arguments[n+2];
7860 if ((argvalue==null) && (typeof callback ==
'object'))
7861 argvalue = prompt(
"Input argument " + argname +
" for command " + hitem._name,
"");
7862 if (argvalue==null)
return;
7863 url += ((n==0) ?
"?" :
"&") + argname +
"=" + argvalue;
7866 if (!d3node.empty()) {
7867 d3node.style(
'background',
'yellow');
7868 if (hitem && hitem._title) d3node.attr(
'title',
"Executing " + hitem._title);
7871 JSROOT.NewHttpRequest(url,
'text',
function(res) {
7872 if (typeof callback ==
'function')
return callback(res);
7873 if (d3node.empty())
return;
7874 var col = ((res!=null) && (res!=
'false')) ?
'green' :
'red';
7875 if (hitem && hitem._title) d3node.attr(
'title', hitem._title +
" lastres=" + res);
7876 d3node.style(
'background', col).transition().duration(2000).each(
"end",
function() { d3node.style(
'background',
''); });
7877 if ((col ==
'green') && (
'_hreload' in hitem)) pthis.reload();
7878 if ((col ==
'green') && (
'_update_item' in hitem)) pthis.updateItems(hitem._update_item.split(
";"));
7882 JSROOT.HierarchyPainter.prototype.RefreshHtml =
function(callback) {
7883 if (this.divid == null)
return JSROOT.CallBack(callback);
7884 var hpainter =
this;
7885 JSROOT.AssertPrerequisites(
'jq2d',
function() {
7886 hpainter.RefreshHtml(callback);
7890 JSROOT.HierarchyPainter.prototype.toggle =
function(status, h) {
7891 var hitem = (h==null) ? this.h : h;
7893 if (!(
'_childs' in hitem)) {
7894 if (!status || this.with_icons || ((typeof hitem._expand) !==
'function'))
return;
7895 this.expand(this.itemFullName(hitem));
7896 if (
'_childs' in hitem) hitem._isopen =
true;
7900 if (hitem != this.h)
7902 hitem._isopen =
true;
7904 delete hitem._isopen;
7906 for (var i=0; i < hitem._childs.length; ++i)
7907 this.toggle(status, hitem._childs[i]);
7909 if (h==null) this.RefreshHtml();
7912 JSROOT.HierarchyPainter.prototype.get =
function(arg, call_back, options) {
7916 var itemname = (typeof arg ==
'object') ? arg.arg : arg;
7918 var item =
this.Find( { name: itemname, allow_index:
true } );
7921 var d = (item!=null) ? null : this.Find({ name: itemname, last_exists:
true, check_keys:
true, allow_index:
true });
7926 if ((d !== null) && (
'last' in d) && (d.last !== null)) {
7927 var hpainter =
this;
7928 var parentname = this.itemFullName(d.last);
7931 if ((typeof arg ==
'object') && (
'rest' in arg))
7932 if ((arg.rest == d.rest) || (arg.rest.length <= d.rest.length))
7933 return JSROOT.CallBack(call_back);
7935 return this.expand(parentname,
function(res) {
7936 if (!res) JSROOT.CallBack(call_back);
7937 var newparentname = hpainter.itemFullName(d.last);
7938 hpainter.get( { arg: newparentname +
"/" + d.rest, rest: d.rest }, call_back, options);
7944 if ((item !== null) && (typeof item._obj ==
'object'))
7945 return JSROOT.CallBack(call_back, item, item._obj);
7949 while (curr != null) {
7950 if ((
'_get' in curr) && (typeof curr._get ==
'function'))
7951 return curr._get(item, null, call_back, options);
7952 curr = (
'_parent' in curr) ? curr._parent : null;
7955 JSROOT.CallBack(call_back, item, null);
7958 JSROOT.HierarchyPainter.prototype.draw =
function(divid, obj, drawopt) {
7960 return JSROOT.draw(divid, obj, drawopt);
7963 JSROOT.HierarchyPainter.prototype.redraw =
function(divid, obj, drawopt) {
7965 return JSROOT.redraw(divid, obj, drawopt);
7968 JSROOT.HierarchyPainter.prototype.player =
function(itemname, option, call_back) {
7969 var item = this.Find(itemname);
7971 if (!item || !(
'_player' in item))
return JSROOT.CallBack(call_back, null);
7973 var hpainter =
this;
7975 var prereq = (
'_prereq' in item) ? item[
'_prereq'] :
'';
7977 JSROOT.AssertPrerequisites(prereq,
function() {
7979 var player_func = JSROOT.findFunction(item._player);
7980 if (player_func == null)
return JSROOT.CallBack(call_back, null);
7982 hpainter.CreateDisplay(
function(mdi) {
7984 if (mdi) res = player_func(hpainter, itemname, option);
7985 JSROOT.CallBack(call_back, res);
7990 JSROOT.HierarchyPainter.prototype.canDisplay =
function(item, drawopt) {
7991 if (item == null)
return false;
7992 if (
'_player' in item)
return true;
7993 if (drawopt ==
'inspect')
return true;
7994 var handle = JSROOT.getDrawHandle(item._kind, drawopt);
7995 return (handle!=null) && (
'func' in handle);
7998 JSROOT.HierarchyPainter.prototype.display =
function(itemname, drawopt, call_back) {
7999 var h =
this, painter = null, updating =
false;
8001 function display_callback() {
8002 if (painter) painter.SetItemName(itemname, updating ? null : drawopt);
8003 JSROOT.CallBack(call_back, painter, itemname);
8006 h.CreateDisplay(
function(mdi) {
8008 if (!mdi)
return display_callback();
8010 var item = h.Find(itemname);
8012 if ((item!=null) && (
'_player' in item))
8013 return h.player(itemname, drawopt, display_callback);
8015 updating = (typeof(drawopt)==
'string') && (drawopt.indexOf(
"update:")==0);
8018 drawopt = drawopt.substr(7);
8019 if ((item==null) || (
'_doing_update' in item))
return display_callback();
8020 item._doing_update =
true;
8024 if (!h.canDisplay(item, drawopt))
return display_callback();
8028 if ((typeof(drawopt)==
'string') && (drawopt.indexOf(
"divid:")>=0)) {
8029 var pos = drawopt.indexOf(
"divid:");
8030 divid = drawopt.slice(pos+6);
8031 drawopt = drawopt.slice(0, pos);
8034 JSROOT.progress(
"Loading " + itemname);
8036 h.get(itemname,
function(item, obj) {
8040 if (updating && item)
delete item[
'_doing_update'];
8041 if (obj==null)
return display_callback();
8043 JSROOT.progress(
"Drawing " + itemname);
8045 if (divid.length > 0) {
8046 painter = updating ? h.redraw(divid, obj, drawopt) : h.draw(divid, obj, drawopt);
8048 mdi.ForEachPainter(
function(p, frame) {
8049 if (p.GetItemName() != itemname)
return;
8051 if (!updating && (drawopt!=null) && (p.GetItemDrawOpt()!=drawopt))
return;
8053 mdi.ActivateFrame(frame);
8054 painter.RedrawObject(obj);
8058 if (painter==null) {
8060 JSROOT.console(
"something went wrong - did not found painter when doing update of " + itemname);
8062 var frame = mdi.FindFrame(itemname,
true);
8063 d3.select(frame).html(
"");
8064 mdi.ActivateFrame(frame);
8065 painter = h.draw(d3.select(frame).attr(
"id"), obj, drawopt);
8066 if (JSROOT.gStyle.DragAndDrop)
8067 h.enable_dropping(frame, itemname);
8073 if (painter === null)
return display_callback();
8075 painter.WhenReady(display_callback);
8081 JSROOT.HierarchyPainter.prototype.enable_dragging =
function(element, itemname) {
8085 JSROOT.HierarchyPainter.prototype.enable_dropping =
function(frame, itemname) {
8089 JSROOT.HierarchyPainter.prototype.dropitem =
function(itemname, divid, call_back) {
8092 h.get(itemname,
function(item, obj) {
8094 var painter = h.draw(divid, obj,
"same");
8095 if (painter) painter.WhenReady(
function() { painter.SetItemName(itemname); });
8098 JSROOT.CallBack(call_back);
8104 JSROOT.HierarchyPainter.prototype.updateItems =
function(items) {
8108 if ((this.disp == null) || (items==null))
return;
8110 var draw_items = [], draw_options = [];
8112 this.disp.ForEachPainter(
function(p) {
8113 var itemname = p.GetItemName();
8114 if ((itemname==null) || (draw_items.indexOf(itemname)>=0))
return;
8115 if (typeof items ==
'array') {
8116 if (items.indexOf(itemname) < 0)
return;
8118 if (items != itemname)
return;
8120 draw_items.push(itemname);
8121 draw_options.push(
"update:" + p.GetItemDrawOpt());
8124 if (draw_items.length > 0)
8125 this.displayAll(draw_items, draw_options);
8129 JSROOT.HierarchyPainter.prototype.updateAll =
function(only_auto_items, only_items) {
8133 if (this.disp == null)
return;
8135 var allitems = [], options = [], hpainter =
this;
8138 this.disp.ForEachPainter(
function(p) {
8139 var itemname = p.GetItemName();
8140 var drawopt = p.GetItemDrawOpt();
8141 if ((itemname==null) || (allitems.indexOf(itemname)>=0))
return;
8143 var item = hpainter.Find(itemname);
8144 if ((item==null) || (
'_not_monitor' in item) || (
'_player' in item))
return;
8147 if (
'_always_monitor' in item) {
8150 var handle = JSROOT.getDrawHandle(item._kind);
8151 if (handle && (
'monitor' in handle)) {
8152 if ((handle.monitor===
false) || (handle.monitor==
'never'))
return;
8153 if (handle.monitor===
'always') forced =
true;
8157 if (forced || !only_auto_items) {
8158 allitems.push(itemname);
8159 options.push(
"update:" + drawopt);
8166 if (this.files_monitoring)
8167 this.ForEachRootFile(
function(item) {
8168 painter.ForEach(
function(fitem) {
delete fitem._readobj; }, item);
8172 this.displayAll(allitems, options);
8175 JSROOT.HierarchyPainter.prototype.displayAll =
function(items, options, call_back) {
8177 if ((items == null) || (items.length == 0))
return JSROOT.CallBack(call_back);
8181 if (options == null) options = [];
8182 while (options.length < items.length)
8185 if ((options.length == 1) &&( options[0] ==
"iotest")) {
8187 d3.select(
"#" + h[
'disp_frameid']).html(
"<h2>Start I/O test "+ (
'IO' in JSROOT ?
"Mode=" + JSROOT.IO.Mode :
"") +
"</h2>")
8189 var tm0 =
new Date();
8190 return h.get(items[0],
function(item, obj) {
8191 var tm1 =
new Date();
8192 d3.select(
"#" + h[
'disp_frameid']).append(
"h2").html(
"Item " + items[0] +
" reading time = " + (tm1.getTime() - tm0.getTime()) +
"ms");
8193 return JSROOT.CallBack(call_back);
8197 var dropitems =
new Array(items.length);
8200 for (var i = 0; i < items.length; ++i) {
8201 dropitems[i] = null;
8202 if (h.Find(items[i]))
continue;
8203 if (h.Find(items[i] +
";1")) { items[i] +=
";1";
continue; }
8205 var pos = items[i].indexOf(
"+");
8207 dropitems[i] = items[i].split(
"+");
8208 items[i] = dropitems[i].shift();
8210 for (var j = 0; j < dropitems[i].length; ++j) {
8211 var pos = dropitems[i][j].indexOf(
"_same_");
8212 if ((pos>0) && (h.Find(dropitems[i][j])==null))
8213 dropitems[i][j] = dropitems[i][j].substr(0,pos) + items[i].substr(pos);
8218 var pos = items[i].indexOf(
"_same_");
8219 if ((pos>0) && !h.Find(items[i]) && (i>0))
8220 items[i] = items[i].substr(0,pos) + items[0].substr(pos);
8224 for (var n = items.length-1; n>=0; n--) {
8225 var hitem = h.Find(items[n]);
8226 if ((hitem==null) || h.canDisplay(hitem, options[n]))
continue;
8230 options.splice(n, 1);
8231 dropitems.splice(n,1);
8234 if (items.length == 0)
return JSROOT.CallBack(call_back);
8236 h.CreateDisplay(
function(mdi) {
8237 if (!mdi)
return JSROOT.CallBack(call_back);
8240 for (var i = 0; i < items.length; ++i)
8241 if (options[i].indexOf(
'update:')!=0)
8242 mdi.CreateFrame(items[i]);
8245 for (var i = 0; i < items.length; ++i)
8246 h.display(items[i], options[i],
function(painter, itemname) {
8248 var indx = items.indexOf(itemname);
8249 if (indx<0)
return JSROOT.console(
'did not found item ' + itemname);
8251 items[indx] =
"---";
8253 function DropNextItem() {
8254 if ((painter!=null) && (dropitems[indx]!=null) && (dropitems[indx].length>0))
8255 return h.dropitem(dropitems[indx].shift(), painter.divid, DropNextItem);
8258 for (var cnt = 0; cnt < items.length; ++cnt)
8259 if (items[cnt]!=
'---') isany =
true;
8262 if (!isany) JSROOT.CallBack(call_back);
8270 JSROOT.HierarchyPainter.prototype.reload =
function() {
8271 var hpainter =
this;
8272 if (
'_online' in this.h)
8273 this.OpenOnline(this.h[
'_online'],
function() {
8274 hpainter.RefreshHtml();
8278 JSROOT.HierarchyPainter.prototype.expand =
function(itemname, call_back, d3cont) {
8279 var hpainter =
this;
8281 var hitem = this.Find(itemname);
8283 if (!hitem && d3cont)
return JSROOT.CallBack(call_back);
8285 function DoExpandItem(_item, _obj, _name) {
8286 if (!_name) _name = hpainter.itemFullName(_item);
8289 if (_obj && _item && typeof _item._expand ==
'function') {
8290 if (_item._expand(_item, _obj)) {
8291 _item._isopen =
true;
8292 if (typeof hpainter.UpdateTreeNode ==
'function')
8293 hpainter.UpdateTreeNode(_item, d3cont);
8294 JSROOT.CallBack(call_back, _item);
8299 if (!(
'_expand' in _item)) {
8300 var handle = JSROOT.getDrawHandle(_item._kind);
8301 if (handle && (
'expand' in handle)) {
8302 JSROOT.AssertPrerequisites(handle.prereq,
function() {
8303 _item._expand = JSROOT.findFunction(handle.expand);
8304 if (typeof _item._expand !=
'function') {
delete _item._expand;
return; }
8305 hpainter.expand(_name, call_back, d3cont);
8311 if (_obj && JSROOT.Painter.ObjectHierarchy(_item, _obj)) {
8312 _item._isopen =
true;
8313 if (typeof hpainter.UpdateTreeNode ==
'function')
8314 hpainter.UpdateTreeNode(_item, d3cont);
8315 JSROOT.CallBack(call_back, _item);
8324 if ((
'_more' in hitem) && !hitem._more)
return JSROOT.CallBack(call_back);
8326 if (DoExpandItem(hitem, hitem._obj, itemname))
return;
8329 JSROOT.progress(
"Loading " + itemname);
8331 this.
get(itemname,
function(item, obj) {
8335 if (obj && DoExpandItem(item, obj))
return;
8337 JSROOT.CallBack(call_back);
8338 },
"hierarchy_expand" );
8342 JSROOT.HierarchyPainter.prototype.GetTopOnlineItem =
function(item) {
8344 while ((item!=null) && (!(
'_online' in item))) item = item._parent;
8348 if (this.h==null)
return null;
8349 if (
'_online' in this.h)
return this.h;
8350 if ((this.h._childs!=null) && (
'_online' in this.h._childs[0]))
return this.h._childs[0];
8355 JSROOT.HierarchyPainter.prototype.ForEachJsonFile =
function(call_back) {
8356 if (this.h==null)
return;
8357 if (
'_jsonfile' in this.h)
8358 return JSROOT.CallBack(call_back, this.h);
8360 if (this.h._childs!=null)
8361 for (var n = 0; n < this.h._childs.length; ++n) {
8362 var item = this.h._childs[n];
8363 if (
'_jsonfile' in item) JSROOT.CallBack(call_back, item);
8367 JSROOT.HierarchyPainter.prototype.OpenJsonFile =
function(filepath, call_back) {
8368 var isfileopened =
false;
8369 this.ForEachJsonFile(
function(item) {
if (item._jsonfile==filepath) isfileopened =
true; });
8370 if (isfileopened)
return JSROOT.CallBack(call_back);
8373 JSROOT.NewHttpRequest(filepath,
'object',
function(res) {
8374 if (res == null)
return JSROOT.CallBack(call_back);
8375 var h1 = { _jsonfile : filepath, _kind :
"ROOT." + res._typename, _jsontmp : res, _name: filepath.split(
"/").pop() };
8376 if (
'fTitle' in res) h1._title = res.fTitle;
8377 h1._get =
function(item,itemname,callback) {
8378 if (
'_jsontmp' in item) {
8379 var res = item._jsontmp;
8380 delete item._jsontmp;
8381 return JSROOT.CallBack(callback, item, res);
8383 JSROOT.NewHttpRequest(item._jsonfile,
'object',
function(res) {
8384 return JSROOT.CallBack(callback, item, res);
8387 if (pthis.h == null) pthis.h = h1;
else
8388 if (pthis.h._kind ==
'TopFolder') pthis.h._childs.push(h1);
else {
8390 var topname = (
'_jsonfile' in h0) ?
"Files" :
"Items";
8391 pthis.h = { _name: topname, _kind:
'TopFolder', _childs : [h0, h1] };
8394 pthis.RefreshHtml(call_back);
8398 JSROOT.HierarchyPainter.prototype.ForEachRootFile =
function(call_back) {
8399 if (this.h==null)
return;
8400 if ((this.h._kind ==
"ROOT.TFile") && (this.h._file!=null))
8401 return JSROOT.CallBack(call_back, this.h);
8403 if (this.h._childs != null)
8404 for (var n = 0; n < this.h._childs.length; ++n) {
8405 var item = this.h._childs[n];
8406 if ((item._kind ==
'ROOT.TFile') && (
'_fullurl' in item))
8407 JSROOT.CallBack(call_back, item);
8411 JSROOT.HierarchyPainter.prototype.OpenRootFile =
function(filepath, call_back) {
8414 var isfileopened =
false;
8415 this.ForEachRootFile(
function(item) {
if (item._fullurl==filepath) isfileopened =
true; });
8416 if (isfileopened)
return JSROOT.CallBack(call_back);
8420 JSROOT.OpenFile(filepath,
function(file) {
8421 if (file == null)
return JSROOT.CallBack(call_back);
8422 var h1 = pthis.FileHierarchy(file);
8424 if (pthis.h == null) pthis.h = h1;
else
8425 if (pthis.h._kind ==
'TopFolder') pthis.h._childs.push(h1);
else {
8427 var topname = (h0._kind ==
"ROOT.TFile") ?
"Files" :
"Items";
8428 pthis.h = { _name: topname, _kind:
'TopFolder', _childs : [h0, h1] };
8431 pthis.RefreshHtml(call_back);
8435 JSROOT.HierarchyPainter.prototype.GetFileProp =
function(itemname) {
8436 var item = this.Find(itemname);
8437 if (item == null)
return null;
8439 var subname = item._name;
8440 while (item._parent != null) {
8441 item = item._parent;
8442 if (
'_file' in item) {
8444 fileurl : item._file.fURL,
8448 subname = item._name +
"/" + subname;
8454 JSROOT.MarkAsStreamerInfo =
function(h,item,obj) {
8457 if ((obj!=null) && (obj._typename==
'TList'))
8458 obj._typename =
'TStreamerInfoList';
8461 JSROOT.HierarchyPainter.prototype.GetOnlineItemUrl =
function(item) {
8463 if ((item!=null) && (typeof item ==
"string")) item = this.Find(item);
8464 var top = this.GetTopOnlineItem(item);
8465 if (item==null)
return null;
8467 var urlpath = this.itemFullName(item, top);
8468 if (top && (
'_online' in top) && (top._online!=
"")) urlpath = top._online + urlpath;
8472 JSROOT.HierarchyPainter.prototype.GetOnlineItem =
function(item, itemname, callback, option) {
8475 var url = itemname, h_get =
false, req =
"", req_kind =
"object", pthis =
this, draw_handle = null;
8477 if (option ===
'hierarchy_expand') { h_get =
true; option = undefined; }
8480 url = this.GetOnlineItemUrl(item);
8482 if (
'_kind' in item) draw_handle = JSROOT.getDrawHandle(item._kind);
8485 req =
'h.json?compact=3';
8486 item._expand = JSROOT.Painter.OnlineHierarchy;
8488 if (
'_make_request' in item) {
8489 func = JSROOT.findFunction(item._make_request);
8491 if ((draw_handle!=null) && (
'make_request' in draw_handle)) {
8492 func = draw_handle.make_request;
8495 if (typeof func ==
'function') {
8497 var dreq = func(pthis, item, url, option);
8500 if (typeof dreq ==
'string') req = dreq;
else {
8501 if (
'req' in dreq) req = dreq.req;
8502 if (
'kind' in dreq) req_kind = dreq.kind;
8506 if ((req.length==0) && (item._kind.indexOf(
"ROOT.")!=0))
8507 req =
'item.json.gz?compact=3';
8510 if ((itemname==null) && (item!=null) && (
'_cached_draw_object' in
this) && (req.length == 0)) {
8512 var obj = this._cached_draw_object;
8513 delete this._cached_draw_object;
8514 return JSROOT.CallBack(callback, item, obj);
8517 if (req.length == 0) req =
'root.json.gz?compact=3';
8519 if (url.length > 0) url +=
"/";
8522 var itemreq = JSROOT.NewHttpRequest(url, req_kind,
function(obj) {
8526 if (!h_get && (item!=null) && (
'_after_request' in item)) {
8527 func = JSROOT.findFunction(item._after_request);
8529 if ((draw_handle!=null) && (
'after_request' in draw_handle))
8530 func = draw_handle.after_request;
8532 if (typeof func ==
'function') {
8533 var res = func(pthis, item, obj, option, itemreq);
8534 if ((res!=null) && (typeof res ==
"object")) obj = res;
8537 JSROOT.CallBack(callback, item, obj);
8543 JSROOT.Painter.OnlineHierarchy =
function(node, obj) {
8546 if ((obj != null) && (node != null) && (
'_childs' in obj)) {
8548 for (var n=0;n<obj._childs.length;++n)
8549 if (obj._childs[n]._more || obj._childs[n]._childs)
8550 obj._childs[n]._expand = JSROOT.Painter.OnlineHierarchy;
8552 node._childs = obj._childs;
8560 JSROOT.HierarchyPainter.prototype.OpenOnline =
function(server_address, user_callback) {
8563 function AdoptHierarchy(result) {
8565 if (painter.h == null)
return;
8567 if ((
'_title' in painter.h) && (painter.h._title!=
'')) document.title = painter.h._title;
8569 result._isopen =
true;
8572 painter.h._online = server_address;
8574 painter.h._get =
function(item, itemname, callback, option) {
8575 painter.GetOnlineItem(item, itemname, callback, option);
8578 painter.h._expand = JSROOT.Painter.OnlineHierarchy;
8580 var scripts =
"", modules =
"";
8581 painter.ForEach(
function(item) {
8582 if (
'_childs' in item) item._expand = JSROOT.Painter.OnlineHierarchy;
8584 if (
'_autoload' in item) {
8585 var arr = item._autoload.split(
";");
8586 for (var n = 0; n < arr.length; ++n)
8587 if ((arr[n].length>3) &&
8588 ((arr[n].lastIndexOf(
".js")==arr[n].length-3) ||
8589 (arr[n].lastIndexOf(
".css")==arr[n].length-4))) {
8590 if (scripts.indexOf(arr[n])<0) scripts+=arr[n]+
";";
8592 if (modules.indexOf(arr[n])<0) modules+=arr[n]+
";";
8597 if (scripts.length > 0) scripts =
"user:" + scripts;
8600 JSROOT.AssertPrerequisites(modules + scripts,
function() {
8602 painter.ForEach(
function(item) {
8603 if (!(
'_drawfunc' in item) || !(
'_kind' in item))
return;
8604 var
typename =
"kind:" + item._kind;
8605 if (item._kind.indexOf(
'ROOT.')==0)
typename = item._kind.slice(5);
8606 var drawopt = item[
'_drawopt'];
8607 if (!JSROOT.canDraw(
typename) || (drawopt!=null))
8608 JSROOT.addDrawFunc({ name:
typename, func: item[
'_drawfunc'], script:item[
'_drawscript'], opt: drawopt});
8611 JSROOT.CallBack(user_callback, painter);
8615 if (!server_address) server_address =
"";
8617 if (typeof server_address ==
'object') {
8618 var h = server_address;
8619 server_address =
"";
8620 return AdoptHierarchy(h);
8623 JSROOT.NewHttpRequest(server_address +
"h.json?compact=3",
'object', AdoptHierarchy).send(null);
8626 JSROOT.HierarchyPainter.prototype.GetOnlineProp =
function(itemname) {
8627 var item = this.Find(itemname);
8628 if (item == null)
return null;
8630 var subname = item._name;
8631 while (item._parent != null) {
8632 item = item._parent;
8634 if (
'_online' in item) {
8636 server : item._online,
8640 subname = item._name +
"/" + subname;
8646 JSROOT.HierarchyPainter.prototype.FillOnlineMenu =
function(menu, onlineprop, itemname) {
8650 var node = this.Find(itemname);
8651 var opts = JSROOT.getDrawOptions(node._kind,
'nosame');
8652 var handle = JSROOT.getDrawHandle(node._kind);
8653 var root_type = (
'_kind' in node) ? node._kind.indexOf(
"ROOT.") == 0 :
false;
8656 menu.addDrawMenu(
"Draw", opts,
function(arg) { painter.display(itemname, arg); });
8658 if ((node[
'_childs'] == null) && (node[
'_more'] || root_type))
8659 menu.add(
"Expand",
function() { painter.expand(itemname); });
8661 if (handle && (
'execute' in handle))
8662 menu.add(
"Execute",
function() { painter.ExecuteCommand(itemname, menu.tree_node); });
8664 var drawurl = onlineprop.server + onlineprop.itemname +
"/draw.htm";
8666 if (this.IsMonitoring()) {
8667 drawurl += separ +
"monitoring=" + this.MonitoringInterval();
8672 menu.addDrawMenu(
"Draw in new window", opts,
function(arg) { window.open(drawurl+separ+
"opt=" +arg); });
8674 if ((opts!=null) && (opts.length > 0) && root_type)
8675 menu.addDrawMenu(
"Draw as png", opts,
function(arg) {
8676 window.open(onlineprop.server + onlineprop.itemname +
"/root.png?w=400&h=300&opt=" + arg);
8679 if (
'_player' in node)
8680 menu.add(
"Player",
function() { painter.player(itemname); });
8683 JSROOT.HierarchyPainter.prototype.Adopt =
function(h) {
8688 JSROOT.HierarchyPainter.prototype.SetMonitoring =
function(val) {
8689 this._monitoring_on =
false;
8690 this._monitoring_interval = 3000;
8692 val = (val === undefined) ? 0 : parseInt(val);
8694 if (!isNaN(val) && (val>0)) {
8695 this._monitoring_on =
true;
8696 this._monitoring_interval = Math.max(100,val);
8700 JSROOT.HierarchyPainter.prototype.MonitoringInterval =
function(val) {
8702 return (
'_monitoring_interval' in
this) ? this._monitoring_interval : 3000;
8705 JSROOT.HierarchyPainter.prototype.EnableMonitoring =
function(on) {
8706 this._monitoring_on = on;
8709 JSROOT.HierarchyPainter.prototype.IsMonitoring =
function() {
8710 return this._monitoring_on;
8713 JSROOT.HierarchyPainter.prototype.SetDisplay =
function(layout, frameid) {
8714 if ((frameid==null) && (typeof layout ==
'object')) {
8716 this.disp_kind =
'custom';
8717 this.disp_frameid = null;
8719 this.disp_kind = layout;
8720 this.disp_frameid = frameid;
8724 JSROOT.HierarchyPainter.prototype.GetLayout =
function() {
8725 return this.disp_kind;
8728 JSROOT.HierarchyPainter.prototype.clear =
function(withbrowser) {
8729 if (
'disp' in
this) {
8735 this.select_main().html(
"");
8739 this.ForEach(
function(item) {
8740 if ((
'clear' in item) && (typeof item.clear==
'function')) item.clear();
8745 JSROOT.HierarchyPainter.prototype.GetDisplay =
function() {
8746 return (
'disp' in
this) ? this.disp : null;
8749 JSROOT.HierarchyPainter.prototype.CreateDisplay =
function(callback) {
8753 if (
'disp' in
this) {
8754 if ((h.disp.NumDraw() > 0) || (h.disp_kind ==
"custom"))
return JSROOT.CallBack(callback, h.disp);
8760 if (document.getElementById(
this.disp_frameid) == null)
8761 return JSROOT.CallBack(callback, null);
8763 if (h.disp_kind ==
"simple")
8764 h.disp =
new JSROOT.SimpleDisplay(h.disp_frameid);
8766 if (h.disp_kind.search(
"grid") == 0)
8767 h.disp =
new JSROOT.GridDisplay(h.disp_frameid, h.disp_kind);
8769 return JSROOT.AssertPrerequisites(
'jq2d',
function() { h.CreateDisplay(callback); });
8771 JSROOT.CallBack(callback, h.disp);
8774 JSROOT.HierarchyPainter.prototype.updateOnOtherFrames =
function(painter, obj) {
8776 var mdi = this.disp;
8777 if (mdi==null)
return false;
8780 mdi.ForEachPainter(
function(p, frame) {
8781 if ((p===painter) || (p.GetItemName() != painter.GetItemName()))
return;
8782 mdi.ActivateFrame(frame);
8783 p.RedrawObject(obj);
8789 JSROOT.HierarchyPainter.prototype.CheckResize =
function(size) {
8791 this.disp.CheckMDIResize(null, size);
8794 JSROOT.HierarchyPainter.prototype.StartGUI =
function(h0, call_back) {
8795 var hpainter =
this;
8796 var filesarr = JSROOT.GetUrlOptionAsArray(
"file;files");
8797 var jsonarr = JSROOT.GetUrlOptionAsArray(
"json");
8798 var filesdir = JSROOT.GetUrlOption(
"path");
8799 var expanditems = JSROOT.GetUrlOptionAsArray(
"expand");
8800 if (expanditems.length==0 && (JSROOT.GetUrlOption(
"expand")==
"")) expanditems.push(
"");
8802 if (filesdir!=null) {
8803 for (var i=0;i<filesarr.length;++i) filesarr[i] = filesdir + filesarr[i];
8804 for (var i=0;i<jsonarr.length;++i) jsonarr[i] = filesdir + jsonarr[i];
8807 var itemsarr = JSROOT.GetUrlOptionAsArray(
"item;items");
8808 if ((itemsarr.length==0) && JSROOT.GetUrlOption(
"item")==
"") itemsarr.push(
"");
8810 var optionsarr = JSROOT.GetUrlOptionAsArray(
"opt;opts");
8812 var monitor = JSROOT.GetUrlOption(
"monitoring");
8814 if ((jsonarr.length==1) && (itemsarr.length==0) && (expanditems.length==0)) itemsarr.push(
"");
8816 if (!this.disp_kind) {
8817 var layout = JSROOT.GetUrlOption(
"layout");
8818 if ((typeof layout ==
"string") && (layout.length>0))
8819 this.disp_kind = layout;
8821 switch (itemsarr.length) {
8823 case 1: this.disp_kind =
'simple';
break;
8824 case 2: this.disp_kind =
'grid 1x2';
break;
8825 default: this.disp_kind =
'flex';
8829 if (JSROOT.GetUrlOption(
'files_monitoring')!=null) this.files_monitoring =
true;
8833 this.SetMonitoring(monitor);
8835 function OpenAllFiles() {
8836 if (jsonarr.length>0)
8837 hpainter.OpenJsonFile(jsonarr.shift(), OpenAllFiles);
8838 else if (filesarr.length>0)
8839 hpainter.OpenRootFile(filesarr.shift(), OpenAllFiles);
8840 else if (expanditems.length>0)
8841 hpainter.expand(expanditems.shift(), OpenAllFiles);
8843 hpainter.displayAll(itemsarr, optionsarr,
function() {
8844 hpainter.RefreshHtml();
8846 JSROOT.RegisterForResize(hpainter);
8848 setInterval(
function() { hpainter.updateAll(!hpainter.IsMonitoring()); }, hpainter.MonitoringInterval());
8850 JSROOT.CallBack(call_back);
8854 function AfterOnlineOpened() {
8856 if ((
'_monitoring' in hpainter.h) && (monitor==null)) {
8857 hpainter.SetMonitoring(hpainter.h._monitoring);
8860 if ((
'_layout' in hpainter.h) && (layout==null)) {
8861 hpainter.disp_kind = hpainter.h._layout;
8864 if ((
'_loadfile' in hpainter.h) && (filesarr.length==0)) {
8865 filesarr = JSROOT.ParseAsArray(hpainter.h._loadfile);
8868 if ((
'_drawitem' in hpainter.h) && (itemsarr.length==0)) {
8869 itemsarr = JSROOT.ParseAsArray(hpainter.h._drawitem);
8870 optionsarr = JSROOT.ParseAsArray(hpainter.h[
'_drawopt']);
8876 if (h0!=null) hpainter.OpenOnline(h0, AfterOnlineOpened);
8877 else OpenAllFiles();
8880 JSROOT.BuildNobrowserGUI =
function() {
8881 var myDiv = d3.select(
'#simpleGUI');
8882 var online =
false, drawing =
false;
8884 if (myDiv.empty()) {
8886 myDiv = d3.select(
'#onlineGUI');
8887 if (myDiv.empty()) { myDiv = d3.select(
'#drawGUI'); drawing =
true; }
8888 if (myDiv.empty())
return alert(
'no div for simple nobrowser gui found');
8891 JSROOT.Painter.readStyleFromURL();
8893 d3.select(
'html').style(
'height',
'100%');
8894 d3.select(
'body').style({
'min-height':
'100%',
'margin':
'0px',
"overflow":
"hidden"});
8896 myDiv.style({
"position":
"absolute",
"left":
"1px",
"top" :
"1px",
"bottom" :
"1px",
"right":
"1px"});
8898 var hpainter =
new JSROOT.HierarchyPainter(
'root', null);
8899 hpainter.SetDisplay(JSROOT.GetUrlOption(
"layout", null,
"simple"), myDiv.attr(
'id'));
8903 var func = JSROOT.findFunction(
'GetCachedHierarchy');
8904 if (typeof func ==
'function') h0 = func();
8905 if (typeof h0 !=
'object') h0 =
"";
8908 hpainter.StartGUI(h0,
function() {
8909 if (!drawing)
return;
8910 var func = JSROOT.findFunction(
'GetCachedObject');
8911 var obj = (typeof func ==
'function') ? JSROOT.JSONR_unref(func()) : null;
8912 if (obj!=null) hpainter[
'_cached_draw_object'] = obj;
8913 var opt = JSROOT.GetUrlOption(
"opt");
8914 hpainter.display(
"", opt);
8918 JSROOT.Painter.drawStreamerInfo =
function(divid, lst) {
8919 var painter =
new JSROOT.HierarchyPainter(
'sinfo', divid,
'white');
8921 painter.h = { _name :
"StreamerInfo", _childs : [] };
8923 for ( var i = 0; i < lst.arr.length; ++i) {
8924 var entry = lst.arr[i]
8926 if (entry._typename ==
"TList")
continue;
8928 if (typeof (entry.fName) ==
'undefined') {
8929 JSROOT.console(
"strange element in StreamerInfo with type " + entry._typename);
8934 _name : entry.fName +
";" + entry.fClassVersion,
8935 _kind :
"class " + entry.fName,
8936 _title :
"class:" + entry.fName +
' version:' + entry.fClassVersion +
' checksum:' + entry.fCheckSum,
8941 if (entry.fTitle !=
'') item._title +=
' ' + entry.fTitle;
8943 painter.h._childs.push(item);
8945 if (typeof entry.fElements ==
'undefined')
continue;
8946 for ( var l = 0; l < entry.fElements.arr.length; ++l) {
8947 var elem = entry.fElements.arr[l];
8948 if ((elem == null) || (typeof (elem.fName) ==
'undefined'))
continue;
8949 var info = elem.fTypeName +
" " + elem.fName +
";";
8950 if (elem.fTitle !=
'') info +=
" // " + elem.fTitle;
8951 item._childs.push({ _name : info, _title: elem.fTypeName, _kind:elem.fTypeName, _icon: (elem.fTypeName ==
'BASE') ?
"img_class" :
"img_member" });
8953 if (item._childs.length == 0)
delete item._childs;
8957 painter.RefreshHtml(
function() {
8958 painter.SetDivId(divid);
8959 painter.DrawingReady();
8965 JSROOT.Painter.drawInspector =
function(divid, obj) {
8966 var painter =
new JSROOT.HierarchyPainter(
'inspector', divid,
'white');
8967 painter.default_by_click =
"expand";
8968 painter.with_icons =
false;
8969 painter.h = { _name:
"Object", _title:
"ROOT." + obj._typename, _click_action:
"expand", _nosimple:
false };
8970 if ((typeof obj.fName ===
'string') && (obj.fName.length>0))
8971 painter.h._name = obj.fName;
8973 JSROOT.Painter.ObjectHierarchy(painter.h, obj);
8974 painter.RefreshHtml(
function() {
8975 painter.SetDivId(divid);
8976 painter.DrawingReady();
8986 JSROOT.MDIDisplay =
function(frameid) {
8987 this.frameid = frameid;
8988 d3.select(
"#"+this.frameid).property(
'mdi',
this);
8991 JSROOT.MDIDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
8995 console.warn(
"ForEachFrame not implemented in MDIDisplay");
8998 JSROOT.MDIDisplay.prototype.ForEachPainter =
function(userfunc, only_visible) {
9002 this.ForEachFrame(
function(frame) {
9003 var dummy =
new JSROOT.TObjectPainter();
9004 dummy.SetDivId(d3.select(frame).attr(
'id'), -1);
9005 dummy.ForEachPainter(
function(painter) { userfunc(painter, frame); });
9009 JSROOT.MDIDisplay.prototype.NumDraw =
function() {
9011 this.ForEachFrame(
function() { ++cnt; });
9015 JSROOT.MDIDisplay.prototype.FindFrame =
function(searchtitle, force) {
9016 var found_frame = null;
9018 this.ForEachFrame(
function(frame) {
9019 if (d3.select(frame).attr(
'frame_title') == searchtitle)
9020 found_frame = frame;
9023 if ((found_frame == null) && force)
9024 found_frame = this.CreateFrame(searchtitle);
9029 JSROOT.MDIDisplay.prototype.ActivateFrame =
function(frame) {
9033 JSROOT.MDIDisplay.prototype.CheckMDIResize =
function(only_frame_id, size) {
9035 var resized_frame = null;
9037 this.ForEachPainter(
function(painter, frame) {
9039 if ((only_frame_id !== null) && (d3.select(frame).attr(
'id') != only_frame_id))
return;
9041 if ((painter.GetItemName()!==null) && (typeof painter.CheckResize ==
'function')) {
9043 if (resized_frame === frame)
return;
9044 painter.CheckResize(size);
9045 resized_frame = frame;
9050 JSROOT.MDIDisplay.prototype.Reset =
function() {
9052 this.ForEachFrame(
function(frame) {
9053 JSROOT.cleanup(frame);
9056 d3.select(
"#"+this.frameid).html(
"").property(
'mdi', null);
9059 JSROOT.MDIDisplay.prototype.Draw =
function(title, obj, drawopt) {
9063 if (!JSROOT.canDraw(obj._typename, drawopt))
return;
9065 var frame = this.FindFrame(title,
true);
9067 this.ActivateFrame(frame);
9069 return JSROOT.redraw(d3.select(frame).attr(
"id"), obj, drawopt);
9075 JSROOT.CustomDisplay =
function() {
9076 JSROOT.MDIDisplay.call(
this,
"dummy");
9080 JSROOT.CustomDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
9082 JSROOT.CustomDisplay.prototype.AddFrame =
function(divid, itemname) {
9083 if (!(divid in this.frames)) this.frames[divid] =
"";
9085 this.frames[divid] += (itemname +
";");
9088 JSROOT.CustomDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
9089 var ks = Object.keys(this.frames);
9090 for (var k = 0; k < ks.length; ++k) {
9091 var node = d3.select(
"#"+ks[k]);
9093 JSROOT.CallBack(userfunc, node.node());
9097 JSROOT.CustomDisplay.prototype.CreateFrame =
function(title) {
9098 var ks = Object.keys(this.frames);
9099 for (var k = 0; k < ks.length; ++k) {
9100 var items = this.frames[ks[k]];
9101 if (items.indexOf(title+
";")>=0)
9102 return d3.select(
"#"+ks[k]).node();
9107 JSROOT.CustomDisplay.prototype.Reset =
function() {
9108 JSROOT.MDIDisplay.prototype.Reset.call(
this);
9109 this.ForEachFrame(
function(frame) {
9110 d3.select(frame).html(
"");
9116 JSROOT.SimpleDisplay =
function(frameid) {
9117 JSROOT.MDIDisplay.call(
this, frameid);
9120 JSROOT.SimpleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
9122 JSROOT.SimpleDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
9123 var node = d3.select(
"#"+this.frameid +
"_simple_display");
9125 JSROOT.CallBack(userfunc, node.node());
9128 JSROOT.SimpleDisplay.prototype.CreateFrame =
function(title) {
9130 JSROOT.cleanup(this.frameid+
"_simple_display");
9132 return d3.select(
"#"+this.frameid)
9135 .attr(
"id", this.frameid +
"_simple_display")
9136 .style(
"width",
"100%")
9137 .style(
"height",
"100%")
9138 .style(
"overflow" ,
"hidden")
9139 .attr(
"frame_title", title)
9143 JSROOT.SimpleDisplay.prototype.Reset =
function() {
9144 JSROOT.MDIDisplay.prototype.Reset.call(
this);
9146 d3.select(
"#"+this.frameid).html(
"");
9151 JSROOT.GridDisplay =
function(frameid, sizex, sizey) {
9158 JSROOT.MDIDisplay.call(
this, frameid);
9160 if (typeof sizex ==
"string") {
9161 if (sizex.search(
"grid") == 0)
9162 sizex = sizex.slice(4).trim();
9164 var separ = sizex.search(
"x");
9167 sizey = parseInt(sizex.slice(separ + 1));
9168 sizex = parseInt(sizex.slice(0, separ));
9170 sizex = parseInt(sizex);
9174 if (isNaN(sizex)) sizex = 3;
9175 if (isNaN(sizey)) sizey = 3;
9178 if (!sizex) sizex = 3;
9179 if (!sizey) sizey = sizex;
9184 JSROOT.GridDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
9186 JSROOT.GridDisplay.prototype.NumGridFrames =
function() {
9187 return this.sizex*this.sizey;
9190 JSROOT.GridDisplay.prototype.IsSingle =
function() {
9191 return (this.sizex == 1) && (this.sizey == 1);
9194 JSROOT.GridDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
9195 for (var cnt = 0; cnt < this.sizex * this.sizey; ++cnt) {
9196 var elem = this.IsSingle() ? d3.select(
"#"+this.frameid) : d3.select(
"#" + this.frameid +
"_grid_" + cnt);
9198 if (!elem.empty() && elem.attr(
'frame_title') !=
'')
9199 JSROOT.CallBack(userfunc, elem.node());
9203 JSROOT.GridDisplay.prototype.CreateFrame =
function(title) {
9205 var main = d3.select(
"#" + this.frameid);
9206 if (main.empty())
return null;
9208 var drawid = this.frameid;
9210 if (!this.IsSingle()) {
9211 var topid = this.frameid +
'_grid';
9212 if (d3.select(
"#" + topid).empty()) {
9213 var rect = main.node().getBoundingClientRect();
9214 var h = Math.floor(rect.height /
this.sizey) - 1;
9215 var w = Math.floor(rect.width /
this.sizex) - 1;
9217 var content =
"<div style='width:100%; height:100%; margin:0; padding:0; border:0; overflow:hidden'>"+
9218 "<table id='" + topid +
"' style='width:100%; height:100%; table-layout:fixed; border-collapse: collapse;'>";
9220 for (var i = 0; i < this.sizey; ++i) {
9222 for (var j = 0; j < this.sizex; ++j)
9223 content +=
"<td><div id='" + topid +
"_" + cnt++ +
"' class='grid_cell'></div></td>";
9226 content +=
"</table></div>";
9229 main.selectAll(
'.grid_cell').style({
'width': w +
'px',
'height': h +
'px',
'overflow' :
'hidden'});
9232 drawid = topid +
"_" + this.cnt;
9233 if (++this.cnt >= this.sizex * this.sizey) this.cnt = 0;
9236 JSROOT.cleanup(drawid);
9238 return d3.select(
"#" + drawid).html(
"").attr(
'frame_title', title).node();
9241 JSROOT.GridDisplay.prototype.Reset =
function() {
9242 JSROOT.MDIDisplay.prototype.Reset.call(
this);
9243 if (this.IsSingle())
9244 d3.select(
"#" + this.frameid).attr(
'frame_title', null);
9248 JSROOT.GridDisplay.prototype.CheckMDIResize =
function(frame_id, size) {
9250 if (!this.IsSingle()) {
9251 var main = d3.select(
"#" + this.frameid);
9252 var rect = main.node().getBoundingClientRect();
9253 var h = Math.floor(rect.height /
this.sizey) - 1;
9254 var w = Math.floor(rect.width /
this.sizex) - 1;
9255 main.selectAll(
'.grid_cell').style({
'width': w +
'px',
'height': h +
'px'});
9258 JSROOT.MDIDisplay.prototype.CheckMDIResize.call(
this, frame_id, size);
9263 JSROOT.RegisterForResize =
function(handle, delay) {
9270 if ((handle===null) || (handle === undefined))
return;
9272 var myInterval = null, myDelay = delay ? delay : 300;
9274 if (myDelay < 20) myDelay = 20;
9276 function ResizeTimer() {
9279 document.body.style.cursor =
'wait';
9280 if (typeof handle ==
'function') handle();
else
9281 if ((typeof handle ==
'object') && (typeof handle.CheckResize ==
'function')) handle.CheckResize();
else
9282 if (typeof handle ==
'string') {
9283 var node = d3.select(
'#'+handle);
9284 if (!node.empty()) {
9285 var mdi = node.property(
'mdi');
9287 mdi.CheckMDIResize();
9289 JSROOT.resize(node.node());
9293 document.body.style.cursor =
'auto';
9296 function ProcessResize() {
9297 if (myInterval !== null) clearTimeout(myInterval);
9298 myInterval = setTimeout(ResizeTimer, myDelay);
9301 window.addEventListener(
'resize', ProcessResize);
9304 JSROOT.addDrawFunc({ name:
"TCanvas", icon:
"img_canvas", func: JSROOT.Painter.drawCanvas });
9305 JSROOT.addDrawFunc({ name:
"TPad", icon:
"img_canvas", func: JSROOT.Painter.drawPad });
9306 JSROOT.addDrawFunc({ name:
"TSlider", icon:
"img_canvas", func: JSROOT.Painter.drawPad });
9307 JSROOT.addDrawFunc({ name:
"TFrame", icon:
"img_frame", func: JSROOT.Painter.drawFrame });
9308 JSROOT.addDrawFunc({ name:
"TPaveText", icon:
"img_pavetext", func: JSROOT.Painter.drawPaveText });
9309 JSROOT.addDrawFunc({ name:
"TPaveStats", icon:
"img_pavetext", func: JSROOT.Painter.drawPaveText });
9310 JSROOT.addDrawFunc({ name:
"TPaveLabel", icon:
"img_pavelabel", func: JSROOT.Painter.drawPaveText });
9311 JSROOT.addDrawFunc({ name:
"TLatex", icon:
"img_text", func: JSROOT.Painter.drawText });
9312 JSROOT.addDrawFunc({ name:
"TMathText", icon:
"img_text", func: JSROOT.Painter.drawText });
9313 JSROOT.addDrawFunc({ name:
"TText", icon:
"img_text", func: JSROOT.Painter.drawText });
9314 JSROOT.addDrawFunc({ name: /^TH1/, icon:
"img_histo1d", func: JSROOT.Painter.drawHistogram1D, opt:
";hist;P;P0;E;E1;E2;same"});
9315 JSROOT.addDrawFunc({ name:
"TProfile", icon:
"img_profile", func: JSROOT.Painter.drawHistogram1D, opt:
";E0;E1;E2;p;hist"});
9316 JSROOT.addDrawFunc({ name: /^TH2/, icon:
"img_histo2d", prereq:
"more2d", func:
"JSROOT.Painter.drawHistogram2D", opt:
";COL;COLZ;COL0Z;BOX;SCAT;TEXT;LEGO;same" });
9317 JSROOT.addDrawFunc({ name: /^TH3/, icon:
'img_histo3d', prereq:
"3d", func:
"JSROOT.Painter.drawHistogram3D" });
9318 JSROOT.addDrawFunc({ name:
"THStack", prereq:
"more2d", func:
"JSROOT.Painter.drawHStack" });
9319 JSROOT.addDrawFunc({ name:
"TPolyMarker3D", icon:
'img_histo3d', prereq:
"3d", func:
"JSROOT.Painter.drawPolyMarker3D" });
9320 JSROOT.addDrawFunc({ name:
"TGraphPolargram" });
9321 JSROOT.addDrawFunc({ name: /^TGraph/, icon:
"img_graph", prereq:
"more2d", func:
"JSROOT.Painter.drawGraph", opt:
";L;P"});
9322 JSROOT.addDrawFunc({ name:
"TCutG", icon:
"img_graph", prereq:
"more2d", func:
"JSROOT.Painter.drawGraph", opt:
";L;P"});
9323 JSROOT.addDrawFunc({ name: /^RooHist/, icon:
"img_graph", prereq:
"more2d", func:
"JSROOT.Painter.drawGraph", opt:
";L;P" });
9324 JSROOT.addDrawFunc({ name: /^RooCurve/, icon:
"img_graph", prereq:
"more2d", func:
"JSROOT.Painter.drawGraph", opt:
";L;P" });
9325 JSROOT.addDrawFunc({ name:
"TMultiGraph", icon:
"img_mgraph", prereq:
"more2d", func:
"JSROOT.Painter.drawMultiGraph" });
9326 JSROOT.addDrawFunc({ name:
"TStreamerInfoList", icon:
'img_question', func: JSROOT.Painter.drawStreamerInfo });
9327 JSROOT.addDrawFunc({ name:
"TPaletteAxis", icon:
"img_colz", prereq:
"more2d", func:
"JSROOT.Painter.drawPaletteAxis" });
9328 JSROOT.addDrawFunc({ name:
"kind:Text", icon:
"img_text", func: JSROOT.Painter.drawRawText });
9329 JSROOT.addDrawFunc({ name:
"TF1", icon:
"img_graph", prereq:
"math;more2d", func:
"JSROOT.Painter.drawFunction" });
9330 JSROOT.addDrawFunc({ name:
"TEllipse", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawEllipse" });
9331 JSROOT.addDrawFunc({ name:
"TLine", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawLine" });
9332 JSROOT.addDrawFunc({ name:
"TArrow", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawArrow" });
9333 JSROOT.addDrawFunc({ name:
"TGaxis", icon:
"img_graph", func: JSROOT.drawGaxis });
9334 JSROOT.addDrawFunc({ name:
"TLegend", icon:
"img_pavelabel", prereq:
"more2d", func:
"JSROOT.Painter.drawLegend" });
9335 JSROOT.addDrawFunc({ name:
"TBox", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawBox" });
9336 JSROOT.addDrawFunc({ name:
"TWbox", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawBox" });
9337 JSROOT.addDrawFunc({ name:
"TSliderBox", icon:
'img_graph', prereq:
"more2d", func:
"JSROOT.Painter.drawBox" });
9338 JSROOT.addDrawFunc({ name:
"TGeoVolume", icon:
'img_histo3d', prereq:
"geom", func:
"JSROOT.Painter.drawGeometry", expand:
"JSROOT.expandGeoVolume", opt:
"all;count;limit;maxlvl2;" });
9339 JSROOT.addDrawFunc({ name:
"TEveGeoShapeExtract", icon:
'img_histo3d', prereq:
"geom", func:
"JSROOT.Painter.drawGeometry", opt:
";count;limit;maxlvl2" });
9340 JSROOT.addDrawFunc({ name:
"TGeoManager", icon:
'img_histo3d', prereq:
"geom", expand:
"JSROOT.expandGeoManagerHierarchy" });
9341 JSROOT.addDrawFunc({ name: /^TGeo/, icon:
'img_histo3d', prereq:
"geom", func:
"JSROOT.Painter.drawGeoObject", opt:
"all" });
9343 JSROOT.addDrawFunc({ name:
"kind:Command", icon:
"img_execute", execute:
true });
9344 JSROOT.addDrawFunc({ name:
"TFolder", icon:
"img_folder", icon2:
"img_folderopen", noinspect:
true, expand: JSROOT.Painter.FolderHierarchy });
9345 JSROOT.addDrawFunc({ name:
"TTask", icon:
"img_task", expand: JSROOT.Painter.TaskHierarchy, for_derived:
true });
9346 JSROOT.addDrawFunc({ name:
"TTree", icon:
"img_tree", noinspect:
true, expand: JSROOT.Painter.TreeHierarchy });
9347 JSROOT.addDrawFunc({ name:
"TNtuple", icon:
"img_tree", noinspect:
true, expand: JSROOT.Painter.TreeHierarchy });
9348 JSROOT.addDrawFunc({ name:
"TBranch", icon:
"img_branch", noinspect:
true });
9349 JSROOT.addDrawFunc({ name: /^TLeaf/, icon:
"img_leaf" });
9350 JSROOT.addDrawFunc({ name:
"TList", icon:
"img_list", noinspect:
true, expand: JSROOT.Painter.ListHierarchy });
9351 JSROOT.addDrawFunc({ name:
"TObjArray", icon:
"img_list", noinspect:
true, expand: JSROOT.Painter.ListHierarchy });
9352 JSROOT.addDrawFunc({ name:
"TClonesArray", icon:
"img_list", noinspect:
true, expand: JSROOT.Painter.ListHierarchy });
9353 JSROOT.addDrawFunc({ name:
"TColor", icon:
"img_color" });
9354 JSROOT.addDrawFunc({ name:
"TFile", icon:
"img_file", noinspect:
true });
9355 JSROOT.addDrawFunc({ name:
"TMemFile", icon:
"img_file", noinspect:
true });
9356 JSROOT.addDrawFunc({ name:
"Session", icon:
"img_globe" });
9357 JSROOT.addDrawFunc({ name:
"kind:TopFolder", icon:
"img_base" });
9358 JSROOT.addDrawFunc({ name:
"kind:Folder", icon:
"img_folder", icon2:
"img_folderopen", noinspect:
true });
9360 JSROOT.getDrawHandle =
function(kind, selector) {
9367 if (typeof kind !=
'string')
return null;
9368 if (selector ===
"") selector = null;
9372 if ((selector === null) && (kind in JSROOT.DrawFuncs.cache))
9373 return JSROOT.DrawFuncs.cache[kind];
9375 var search = (kind.indexOf(
"ROOT.")==0) ? kind.substr(5) :
"kind:"+kind;
9378 for (var i=0; i < JSROOT.DrawFuncs.lst.length; ++i) {
9379 var h = JSROOT.DrawFuncs.lst[i];
9380 if (typeof h.name ==
"string") {
9381 if (h.name != search)
continue;
9383 if (!search.match(h.name))
continue;
9386 if (selector==null) {
9388 if (!(kind in JSROOT.DrawFuncs.cache)) JSROOT.DrawFuncs.cache[kind] = h;
9391 if (typeof selector==
'string') {
9392 if (first == null) first = h;
9395 var opts = h.opt.split(
';');
9396 for (var j=0; j < opts.length; ++j) opts[j] = opts[j].toLowerCase();
9397 if (opts.indexOf(selector.toLowerCase())>=0)
return h;
9400 if (selector === counter)
return h;
9408 JSROOT.addStreamerInfos =
function(lst) {
9409 if (lst === null)
return;
9411 function CheckBaseClasses(si, lvl) {
9412 if (si.fElements == null)
return null;
9413 if (lvl>10)
return null;
9415 for (var j=0; j<si.fElements.arr.length; ++j) {
9417 var element = si.fElements.arr[j];
9418 if (element.fTypeName !==
'BASE')
continue;
9420 var handle = JSROOT.getDrawHandle(
"ROOT." + element.fName);
9421 if (handle && !handle.for_derived) handle = null;
9424 if (handle === null)
9425 for (var k=0;k<lst.arr.length; ++k)
9426 if (lst.arr[k].fName === element.fName) {
9427 handle = CheckBaseClasses(lst.arr[k], lvl+1);
9431 if (handle && handle.for_derived)
return handle;
9436 for (var n=0;n<lst.arr.length;++n) {
9437 var si = lst.arr[n];
9438 if (JSROOT.getDrawHandle(
"ROOT." + si.fName) !== null)
continue;
9440 var handle = CheckBaseClasses(si, 0);
9442 if (!handle)
continue;
9446 var newhandle = JSROOT.extend({}, handle);
9448 newhandle.name = si.fName;
9449 JSROOT.DrawFuncs.lst.push(newhandle);
9454 JSROOT.getDrawOptions =
function(kind, selector) {
9455 if (typeof kind !=
'string')
return null;
9456 var allopts = null, isany =
false, noinspect =
false;
9457 for (var cnt=0;cnt<1000;++cnt) {
9458 var h = JSROOT.getDrawHandle(kind, cnt);
9460 if (h.noinspect) noinspect =
true;
9461 if (!(
'func' in h))
break;
9463 if (! (
'opt' in h))
continue;
9464 var opts = h.opt.split(
';');
9465 for (var i = 0; i < opts.length; ++i) {
9466 opts[i] = opts[i].toLowerCase();
9467 if ((selector==
'nosame') && (opts[i].indexOf(
'same')==0))
continue;
9469 if (allopts===null) allopts = [];
9470 if (allopts.indexOf(opts[i])<0) allopts.push(opts[i]);
9474 if (isany && (allopts===null)) allopts = [
""];
9477 if (!isany && kind.indexOf(
"ROOT.")==0) allopts = [];
9479 if (!noinspect && allopts)
9480 allopts.push(
"inspect");
9485 JSROOT.canDraw =
function(classname) {
9486 return JSROOT.getDrawOptions(
"ROOT." + classname) !== null;
9492 JSROOT.draw =
function(divid, obj, opt) {
9493 if ((obj===null) || (typeof obj !==
'object'))
return null;
9495 if (opt ==
'inspect')
9496 return JSROOT.Painter.drawInspector(divid, obj);
9498 var handle = null, painter = null;
9499 if (
'_typename' in obj) handle = JSROOT.getDrawHandle(
"ROOT." + obj._typename, opt);
9500 else if (
'_kind' in obj) handle = JSROOT.getDrawHandle(obj._kind, opt);
9502 if ((handle==null) || !(
'func' in handle))
return null;
9504 function performDraw() {
9505 if ((painter===null) && (
'painter_kind' in handle))
9506 painter = (handle.painter_kind ==
"base") ?
new JSROOT.TBasePainter() :
new JSROOT.TObjectPainter(obj);
9508 if (painter==null)
return handle.func(divid, obj, opt);
9510 return handle.func.bind(painter)(divid, obj, opt, painter);
9513 if (typeof handle.func ==
'function')
return performDraw();
9515 var funcname =
"", prereq =
"";
9516 if (typeof handle.func ==
'object') {
9517 if (
'func' in handle.func) funcname = handle.func.func;
9518 if (
'script' in handle.func) prereq =
"user:" + handle.func.script;
9520 if (typeof handle.func ==
'string') {
9521 funcname = handle.func;
9522 if ((
'prereq' in handle) && (typeof handle.prereq ==
'string')) prereq = handle.prereq;
9523 if ((
'script' in handle) && (typeof handle.script ==
'string')) prereq +=
";user:" + handle.script;
9526 if (funcname.length==0)
return null;
9528 if (prereq.length > 0) {
9532 if (!(
'painter_kind' in handle))
9533 handle.painter_kind = (funcname.indexOf(
"JSROOT.Painter")==0) ?
"object" :
"base";
9535 painter = (handle.painter_kind ==
"base") ?
new JSROOT.TBasePainter() :
new JSROOT.TObjectPainter(obj);
9537 JSROOT.AssertPrerequisites(prereq,
function() {
9538 var func = JSROOT.findFunction(funcname);
9540 alert(
'Fail to find function ' + funcname +
' after loading ' + prereq);
9545 var ppp = performDraw();
9547 if (ppp !== painter)
9548 alert(
'Painter function ' + funcname +
' do not follow rules of dynamicaly loaded painters');
9554 var func = JSROOT.findFunction(funcname);
9555 if (func == null)
return null;
9558 return performDraw();
9566 JSROOT.redraw =
function(divid, obj, opt) {
9567 if (obj==null)
return;
9569 var dummy =
new JSROOT.TObjectPainter();
9570 dummy.SetDivId(divid, -1);
9571 var can_painter = dummy.pad_painter();
9573 if (can_painter !== null) {
9574 if (obj._typename ===
"TCanvas") {
9575 can_painter.RedrawObject(obj);
9579 for (var i = 0; i < can_painter.painters.length; ++i) {
9580 var painter = can_painter.painters[i];
9581 if (painter.MatchObjectType(obj._typename))
9582 if (painter.UpdateObject(obj)) {
9583 can_painter.RedrawPad();
9590 JSROOT.console(
"Cannot find painter to update object of type " + obj._typename);
9592 JSROOT.cleanup(divid);
9594 return JSROOT.draw(divid, obj, opt);
9603 JSROOT.resize =
function(divid, arg) {
9604 if (arg ===
true) arg = { force:
true };
else
9605 if (typeof arg !==
'object') arg = null;
9607 var dummy =
new JSROOT.TObjectPainter(), done =
false;
9608 dummy.SetDivId(divid, -1);
9609 dummy.ForEachPainter(
function(painter) {
9610 if (!done && typeof painter[
'CheckResize'] ==
'function')
9611 done = painter.CheckResize(arg);
9616 JSROOT.CheckElementResize = JSROOT.resize;
9619 JSROOT.cleanup =
function(divid) {
9620 var dummy =
new JSROOT.TObjectPainter();
9621 dummy.SetDivId(divid, -1);
9622 dummy.ForEachPainter(
function(painter) {
9623 if (typeof painter[
'Cleanup'] ===
'function')
9626 dummy.select_main().html(
"");
9632 JSROOT.progress =
function(msg) {
9633 var
id =
"jsroot_progressbox";
9634 var box = d3.select(
"#"+
id);
9636 if (!JSROOT.gStyle.ProgressBox)
return box.remove();
9638 if ((arguments.length == 0) || (msg === undefined) || (msg === null))
9639 return box.remove();
9642 box = d3.select(document.body)
9648 box.select(
"p").html(msg);