6 if (typeof JSROOT !=
'object') {
7 var e1 =
new Error(
'JSROOT is not defined');
8 e1.source =
'JSRootPainter.js';
12 if (typeof d3 !=
'object') {
13 var e1 =
new Error(
'This extension requires d3.v3.js');
14 e1.source =
'JSRootPainter.js';
18 if (typeof JSROOT.Painter ==
'object') {
19 var e1 =
new Error(
'JSROOT.Painter already defined');
20 e1.source =
'JSRootPainter.js';
25 JSROOT.fDrawFunc =
new Array;
27 JSROOT.addDrawFunc =
function(_name, _func) {
28 JSROOT.fDrawFunc.push({ name:_name, func:_func });
41 StatNDC : { fX1NDC : 0.78, fY1NDC: 0.75, fX2NDC: 0.98, fY2NDC: 0.91 },
42 StatText : { fTextAngle: 0, fTextSize: 9, fTextAlign: 12, fTextColor: 1, fTextFont: 42 },
43 StatFill : { fFillColor: 0, fFillStyle: 1001 },
44 TimeOffset : 788918400000,
45 StatFormat :
function(v) {
return (Math.abs(v) < 1e5) ? v.toFixed(5) : v.toExponential(7); },
46 StatEntriesFormat :
function(v) {
return (Math.abs(v) < 1e7) ? v.toFixed(0) : v.toExponential(7); }
54 JSROOT.Painter.readStyleFromURL =
function(url) {
55 var optimize = JSROOT.GetUrlOption(
"optimize", url);
56 if (optimize==
"") JSROOT.gStyle.OptimizeDraw = 2;
else
58 JSROOT.gStyle.OptimizeDraw = parseInt(optimize);
59 if (JSROOT.gStyle.OptimizeDraw==NaN) JSROOT.gStyle.OptimizeDraw = 2;
62 var inter = JSROOT.GetUrlOption(
"interactive", url);
63 if ((inter==
"") || (inter==
"1")) inter =
"11111";
else
64 if (inter==
"0") inter =
"00000";
65 if ((inter!=null) && (inter.length==5)) {
66 JSROOT.gStyle.Tooltip = (inter.charAt(0) !=
'0');
67 JSROOT.gStyle.ContextMenu = (inter.charAt(1) !=
'0');
68 JSROOT.gStyle.Zooming = (inter.charAt(2) !=
'0');
69 JSROOT.gStyle.MoveResize = (inter.charAt(3) !=
'0');
70 JSROOT.gStyle.DragAndDrop = (inter.charAt(4) !=
'0');
73 var col = JSROOT.GetUrlOption(
"col", url);
76 if ((col!=NaN) && (col>0) && (col<4)) JSROOT.gStyle.DefaultCol = col;
83 JSROOT.Painter.createmenu =
function(event, menuname) {
85 if (!menuname) menuname =
"root_ctx_menu";
87 var xMousePosition =
event.clientX + window.pageXOffset;
88 var yMousePosition =
event.clientY + window.pageYOffset;
90 var x = document.getElementById(menuname);
91 if (x) x.parentNode.removeChild(x);
93 var d = document.createElement(
'div');
94 d.setAttribute(
'class',
'ctxmenu');
95 d.setAttribute(
'id', menuname);
96 document.body.appendChild(d);
97 d.style.left = xMousePosition +
"px";
98 d.style.top = yMousePosition +
"px";
99 d.onmouseover =
function(e) {
100 this.style.cursor =
'pointer';
102 d.onclick =
function(e) {
103 var x = document.getElementById(menuname);
104 if (x) x.parentNode.removeChild(x);
107 document.body.onclick =
function(e) {
108 var x = document.getElementById(menuname);
110 x.parentNode.removeChild(x);
119 JSROOT.Painter.menuitem =
function(menu, txt, func) {
120 var p = document.createElement(
'p');
123 p.setAttribute(
'class',
'ctxline');
127 JSROOT.Painter.Coord = {
136 JSROOT.Painter.root_colors =
function() {
137 var colorMap =
new Array(
'white',
'black',
'red',
'green',
'blue',
138 'rgb(255,255,0)',
'rgb(255,0,255)',
'rgb(0,255,255)',
139 'rgb(89, 211,84)',
'rgb(89,84,216)',
'rgb(254,254,254)',
140 'rgb(191,181,173)',
'rgb(76,76,76)',
'rgb(102,102,102)',
141 'rgb(127,127,127)',
'rgb(153,153,153)',
'rgb(178,178,178)',
142 'rgb(204,204,204)',
'rgb(229,229,229)',
'rgb(242,242,242)',
143 'rgb(204,198,170)',
'rgb(204,198,170)',
'rgb(193,191,168)',
144 'rgb(186,181,163)',
'rgb(178,165,150)',
'rgb(183,163,155)',
145 'rgb(173,153,140)',
'rgb(155,142,130)',
'rgb(135,102,86)',
146 'rgb(175,206,198)',
'rgb(132,193,163)',
'rgb(137,168,160)',
147 'rgb(130,158,140)',
'rgb(173,188,198)',
'rgb(122,142,153)',
148 'rgb(117,137,145)',
'rgb(104,130,150)',
'rgb(109,122,132)',
149 'rgb(124,153,209)',
'rgb(127,127,155)',
'rgb(170,165,191)',
150 'rgb(211,206,135)',
'rgb(221,186,135)',
'rgb(188,158,130)',
151 'rgb(198,153,124)',
'rgb(191,130,119)',
'rgb(206,94,96)',
152 'rgb(170,142,147)',
'rgb(165,119,122)',
'rgb(147,104,112)',
155 var circleColors = [ 632, 416, 600, 400, 616, 432 ];
157 var rectangleColors = [ 800, 820, 840, 860, 880, 900 ];
159 var set1 = [ 255, 204, 204, 255, 153, 153, 204, 153, 153, 255, 102, 102,
160 204, 102, 102, 153, 102, 102, 255, 51, 51, 204, 51, 51, 153, 51,
161 51, 102, 51, 51, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51, 0, 0 ];
162 var set2 = [ 204, 255, 204, 153, 255, 153, 153, 204, 153, 102, 255, 102,
163 102, 204, 102, 102, 153, 102, 51, 255, 51, 51, 204, 51, 51, 153,
164 51, 51, 102, 51, 0, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51, 0 ];
165 var set3 = [ 204, 204, 255, 153, 153, 255, 153, 153, 204, 102, 102, 255,
166 102, 102, 204, 102, 102, 153, 51, 51, 255, 51, 51, 204, 51, 51,
167 153, 51, 51, 102, 0, 0, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51 ];
168 var set4 = [ 255, 255, 204, 255, 255, 153, 204, 204, 153, 255, 255, 102,
169 204, 204, 102, 153, 153, 102, 255, 255, 51, 204, 204, 51, 153, 153,
170 51, 102, 102, 51, 255, 255, 0, 204, 204, 0, 153, 153, 0, 102, 102, 0, 51, 51, 0 ];
171 var set5 = [ 255, 204, 255, 255, 153, 255, 204, 153, 204, 255, 102, 255,
172 204, 102, 204, 153, 102, 153, 255, 51, 255, 204, 51, 204, 153, 51,
173 153, 102, 51, 102, 255, 0, 255, 204, 0, 204, 153, 0, 153, 102, 0, 102, 51, 0, 51 ];
174 var set6 = [ 204, 255, 255, 153, 255, 255, 153, 204, 204, 102, 255, 255,
175 102, 204, 204, 102, 153, 153, 51, 255, 255, 51, 204, 204, 51, 153,
176 153, 51, 102, 102, 0, 255, 255, 0, 204, 204, 0, 153, 153, 0, 102, 102, 0, 51, 51 ];
178 var circleSets =
new Array(set1, set2, set3, set4, set5, set6);
180 var set7 = [ 255, 204, 153, 204, 153, 102, 153, 102, 51, 153, 102, 0,
181 204, 153, 51, 255, 204, 102, 255, 153, 0, 255, 204, 51, 204, 153,
182 0, 255, 204, 0, 255, 153, 51, 204, 102, 0, 102, 51, 0, 153, 51, 0,
183 204, 102, 51, 255, 153, 102, 255, 102, 0, 255, 102, 51, 204, 51, 0,
185 var set8 = [ 153, 255, 51, 102, 204, 0, 51, 102, 0, 51, 153, 0, 102, 204,
186 51, 153, 255, 102, 102, 255, 0, 102, 255, 51, 51, 204, 0, 51, 255,
187 0, 204, 255, 153, 153, 204, 102, 102, 153, 51, 102, 153, 0, 153,
188 204, 51, 204, 255, 102, 153, 255, 0, 204, 255, 51, 153, 204, 0,
190 var set9 = [ 153, 255, 204, 102, 204, 153, 51, 153, 102, 0, 153, 102, 51,
191 204, 153, 102, 255, 204, 0, 255, 102, 51, 255, 204, 0, 204, 153, 0,
192 255, 204, 51, 255, 153, 0, 204, 102, 0, 102, 51, 0, 153, 51, 51,
193 204, 102, 102, 255, 153, 0, 255, 153, 51, 255, 102, 0, 204, 51, 0,
195 var set10 = [ 153, 204, 255, 102, 153, 204, 51, 102, 153, 0, 51, 153, 51,
196 102, 204, 102, 153, 255, 0, 102, 255, 51, 102, 255, 0, 51, 204, 0,
197 51, 255, 51, 153, 255, 0, 102, 204, 0, 51, 102, 0, 102, 153, 51,
198 153, 204, 102, 204, 255, 0, 153, 255, 51, 204, 255, 0, 153, 204, 0,
200 var set11 = [ 204, 153, 255, 153, 102, 204, 102, 51, 153, 102, 0, 153,
201 153, 51, 204, 204, 102, 255, 153, 0, 255, 204, 51, 255, 153, 0,
202 204, 204, 0, 255, 153, 51, 255, 102, 0, 204, 51, 0, 102, 51, 0,
203 153, 102, 51, 204, 153, 102, 255, 102, 0, 255, 102, 51, 255, 51, 0,
205 var set12 = [ 255, 51, 153, 204, 0, 102, 102, 0, 51, 153, 0, 51, 204, 51,
206 102, 255, 102, 153, 255, 0, 102, 255, 51, 102, 204, 0, 51, 255, 0,
207 51, 255, 153, 204, 204, 102, 153, 153, 51, 102, 153, 0, 102, 204,
208 51, 153, 255, 102, 204, 255, 0, 153, 204, 0, 153, 255, 51, 204,
211 var rectSets =
new Array(set7, set8, set9, set10, set11, set12);
213 for (var i = 0; i < 6; i++) {
214 for (var j = 0; j < 15; j++) {
215 var colorn = circleColors[i] + j - 10;
216 colorMap[colorn] =
'rgb(' + circleSets[i][3 * j] +
',' + circleSets[i][3 * j + 1] +
',' + circleSets[i][3 * j + 2] +
')';
217 colorn = rectangleColors[i] + j - 9;
218 colorMap[colorn] =
'rgb(' + rectSets[i][3 * j] +
',' + rectSets[i][3 * j + 1] +
',' + rectSets[i][3 * j + 2] +
')';
224 JSROOT.Painter.adoptRootColors =
function(objarr) {
225 if (!objarr || !objarr.arr)
return;
227 for (var n in objarr.arr) {
228 var col = objarr.arr[n];
229 if ((col==null) || (col[
'_typename'] !=
'TColor'))
continue;
231 var num = col.fNumber;
232 if ((num<0) || (num>4096))
continue;
234 var rgb =
"rgb(" + (col.fRed*255).toFixed(0) +
"," + (col.fGreen*255).toFixed(0) +
"," + (col.fBlue*255).toFixed(0) +
")";
236 if (rgb ==
'rgb(255,255,255)') rgb =
'white';
238 while (num>JSROOT.Painter.root_colors.length)
239 JSROOT.Painter.root_colors.push(rgb);
241 if (JSROOT.Painter.root_colors[num] != rgb) {
242 JSROOT.Painter.root_colors[num] = rgb;
247 JSROOT.Painter.root_line_styles =
new Array(
"",
"",
"3, 3",
"1, 2",
248 "3, 4, 1, 4",
"5, 3, 1, 3",
"5, 3, 1, 3, 1, 3, 1, 3",
"5, 5",
249 "5, 3, 1, 3, 1, 3",
"20, 5",
"20, 10, 1, 10",
"1, 2");
252 JSROOT.Painter.root_markers =
new Array(
'fcircle',
'fcircle',
'fcross',
253 'dcross',
'ocircle',
'gcross',
'fcircle',
'fcircle',
'fcircle',
254 'fcircle',
'fcircle',
'fcircle',
'fcircle',
'fcircle',
'fcircle',
255 'fcircle',
'fcircle',
'fcircle',
'fcircle',
'fcircle',
'fcircle',
256 'fsquare',
'ftriangle-up',
'ftriangle-down',
'ocircle',
'osquare',
257 'otriangle-up',
'odiamond',
'ocross',
'fstar',
'ostar',
'dcross',
258 'otriangle-down',
'fdiamond',
'fcross');
261 JSROOT.Painter.createAttMarker =
function(attmarker) {
263 var marker_name = JSROOT.Painter.root_markers[attmarker[
'fMarkerStyle']];
265 var info = { shape: 0, toFill:
true, toRotate:
false };
267 if (typeof (marker_name) !=
'undefined') {
268 switch (marker_name.charAt(0)) {
269 case 'd': info.shape = 7;
break;
270 case 'o': info.toFill =
false;
break;
271 case 'g': info.toRotate =
true;
break;
274 switch (marker_name.substr(1)) {
275 case "circle": info.shape = 0;
break;
276 case "cross": info.shape = 1;
break;
277 case "diamond": info.shape = 2;
break;
278 case "square": info.shape = 3;
break;
279 case "triangle-up": info.shape = 4;
break;
280 case "triangle-down": info.shape = 5;
break;
281 case "star": info.shape = 6;
break;
285 var markerSize = attmarker[
'fMarkerSize'];
287 var markerScale = (info.shape == 0) ? 32 : 64;
288 if (attmarker[
'fMarkerStyle'] == 1) markerScale = 1;
290 var marker_color = JSROOT.Painter.root_colors[attmarker[
'fMarkerColor']];
292 var res = { stroke: marker_color, fill: marker_color, marker:
"" };
293 if (!info.toFill) res[
'fill'] =
'none';
296 res[
'marker'] =
"M " + (-4*markerSize) +
" " + (-1*markerSize) +
297 " L " + 4*markerSize +
" " + (-1*markerSize) +
298 " L " + (-2.4*markerSize) +
" " + 4*markerSize +
299 " L 0 " + (-4*markerSize) +
300 " L " + 2.8*markerSize +
" " + 4*markerSize +
" z";
303 res[
'marker'] =
"M " + (-4*markerSize) +
" " + (-4*markerSize) +
304 " L " + 4*markerSize +
" " + 4*markerSize +
305 " M 0 " + (-4*markerSize) +
" 0 " + 4*markerSize +
306 " M " + 4*markerSize +
" " + (-4*markerSize) +
307 " L " + (-4*markerSize) +
" " + 4*markerSize +
308 " M " + (-4*markerSize) +
" 0 L " + 4*markerSize +
" 0";
310 res[
'marker'] = d3.svg.symbol().type(d3.svg.symbolTypes[info.shape]).size(markerSize * markerScale);
312 res.SetMarker =
function(selection) {
313 selection.style(
"fill", this.fill)
314 selection.style(
"stroke", this.stroke)
315 selection.attr(
"d", this.marker);
318 res.func = res.SetMarker.bind(res);
323 JSROOT.Painter.createAttLine =
function(attline, borderw) {
325 var color = 0, _width = 0, style = 0;
327 if (attline==
'black') { color = 1; _width = 1; }
else
328 if (attline==
'none') { _width = 0; }
else
329 if (typeof attline ==
'object') {
330 if (
'fLineColor' in attline) color = attline[
'fLineColor'];
331 if (
'fLineWidth' in attline) _width = attline[
'fLineWidth'];
332 if (
'fLineStyle' in attline) style = attline[
'fLineStyle'];
334 if (borderw!=null) _width = borderw;
337 color: JSROOT.Painter.root_colors[color],
339 dash: JSROOT.Painter.root_line_styles[style]
342 if ((_width==0) || (color==0)) line.color =
'none';
344 line.SetLine =
function(selection) {
345 selection.style(
'stroke', this.color);
346 if (this.color!=
'none') {
347 selection.style(
'stroke-width', this.width);
348 selection.style(
'stroke-dasharray', this.dash);
351 line.func = line.SetLine.bind(line);
357 JSROOT.Painter.clearCuts =
function(chopt) {
359 var left = chopt.indexOf(
'[');
360 var right = chopt.indexOf(
']');
361 if ((left>=0) && (right>=0) && (left<right))
362 for (var i = left; i <= right; i++) chopt[i] =
' ';
366 JSROOT.Painter.root_fonts =
new Array(
'Arial',
'Times New Roman',
367 'bold Times New Roman',
'bold italic Times New Roman',
'Arial',
368 'oblique Arial',
'bold Arial',
'bold oblique Arial',
'Courier New',
369 'oblique Courier New',
'bold Courier New',
'bold oblique Courier New',
370 'Symbol',
'Times New Roman',
'Wingdings',
'Symbol');
372 JSROOT.Painter.getFontDetails =
function(fontIndex, size) {
374 var fontName = JSROOT.Painter.root_fonts[Math.floor(fontIndex / 10)];
376 var res = { name:
"Arial", size: 11, weight: null, style: null };
378 if (size != null) res.size = Math.round(size);
380 if (fontName == null)
383 if (fontName.indexOf(
"bold") != -1) {
387 fontName = fontName.substring(5, fontName.length);
389 if (fontName.charAt(0) ==
'i') {
390 res.style =
"italic";
391 fontName = fontName.substring(7, fontName.length);
392 }
else if (fontName.charAt(0) ==
'o') {
393 res.style =
"oblique";
394 fontName = fontName.substring(8, fontName.length);
396 if (name ==
'Symbol') {
403 res.SetFont =
function(selection) {
404 selection.attr(
"font-family", this.name)
405 .attr(
"font-size", this.size)
406 .attr(
"xml:space",
"preserve");
407 if (this.weight!=null)
408 selection.attr(
"font-weight", this.weight);
409 if (this.style!=null)
410 selection.attr(
"font-style", this.style);
413 res.stringWidth =
function(svg, line) {
415 var text = svg.append(
"svg:text")
416 .attr(
"class",
"temp_text")
417 .attr(
"xml:space",
"preserve")
421 var w = text.node().getBBox().width;
426 res.func = res.SetFont.bind(res);
432 JSROOT.Painter.padtoX =
function(pad, x) {
434 if (pad[
'fLogx'] && x < 50)
435 return Math.exp(2.302585092994 * x);
439 JSROOT.Painter.moveChildToEnd =
function(child) {
441 var prnt = child.node().parentNode;
442 prnt.removeChild(child.node());
443 prnt.appendChild(child.node());
446 JSROOT.Painter.ytoPad =
function(y, pad) {
449 y = JSROOT.Math.log10(y);
469 JSROOT.Painter.HLStoRGB =
function(h, l, s) {
474 function hue2rgb(p, q, t) {
477 if (t < 1 / 6)
return p + (q - p) * 6 * t;
478 if (t < 1 / 2)
return q;
479 if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
482 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
484 r = hue2rgb(p, q, h + 1 / 3);
485 g = hue2rgb(p, q, h);
486 b = hue2rgb(p, q, h - 1 / 3);
488 return 'rgb(' + Math.round(r * 255) +
', ' + Math.round(g * 255) +
', ' + Math.round(b * 255) +
')';
491 JSROOT.Painter.chooseTimeFormat =
function(range, nticks) {
492 if (nticks < 1) nticks = 1;
493 var awidth = range / nticks;
502 awidth /= 60; reasformat = 2;
505 awidth /= 60; reasformat = 3;
508 awidth /= 24; reasformat = 4;
510 if (awidth >= 15.218425) {
511 awidth /= 30.43685; reasformat = 5;
514 awidth /= 12; reasformat = 6;
516 awidth /= 12; reasformat = 7;
525 switch (reasformat) {
527 case 1:
return "%Mm%S";
528 case 2:
return "%Hh%M";
529 case 3:
return "%d-%Hh";
530 case 4:
return "%d/%m";
531 case 5:
return "%d/%m/%y";
532 case 6:
return "%d/%m/%y";
533 case 7:
return "%m/%y";
539 JSROOT.Painter.getTimeFormat =
function(axis) {
540 var timeFormat = axis[
'fTimeFormat'];
541 var idF = timeFormat.indexOf(
'%F');
543 return timeFormat.substr(0, idF);
547 JSROOT.Painter.getTimeOffset =
function(axis) {
548 var timeFormat = axis[
'fTimeFormat'];
550 var idF = timeFormat.indexOf(
'%F');
553 var lnF = timeFormat.length;
554 var stringtimeoffset = timeFormat.substr(idF + 2, lnF);
555 for (var i = 0; i < 3; ++i)
556 stringtimeoffset = stringtimeoffset.replace(
'-',
'/');
558 if ((stringtimeoffset ==
"0") || (stringtimeoffset ==
""))
return 0;
560 var stimeoffset =
new Date(stringtimeoffset);
561 var timeoffset = stimeoffset.getTime();
562 var ids = stringtimeoffset.indexOf(
's');
564 var lns = stringtimeoffset.length;
565 var sdp = stringtimeoffset.substr(ids + 1, lns);
566 var dp = parseFloat(sdp);
572 return JSROOT.gStyle[
'TimeOffset'];
575 JSROOT.Painter.formatExp =
function(label) {
577 if (parseFloat(str) == 1.0)
return '1';
578 if (parseFloat(str) == 10.0)
return '10';
579 var str = str.replace(
'e+',
'x10@');
580 var str = str.replace(
'e-',
'x10@-');
581 var _val = str.substring(0, str.indexOf(
'@'));
582 var _exp = str.substr(str.indexOf(
'@'));
583 _val = _val.replace(
'@',
'');
584 _exp = _exp.replace(
'@',
'');
585 var u, size = _exp.length;
586 for (var j = 0; j < size; ++j) {
587 var u, c = _exp.charAt(j);
588 if (c ==
'+') u =
'\u207A';
else
589 if (c ==
'-') u =
'\u207B';
else {
591 if (e == 1) u = String.fromCharCode(0xB9);
else
592 if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
else
593 u = String.fromCharCode(0x2070 + e);
595 _exp = _exp.replace(c, u);
597 _val = _val.replace(
'1x',
'');
601 JSROOT.Painter.translateExp =
function(str) {
602 var lstr = str.match(/\^{[0-9]*}/gi);
605 for (var i = 0; i < lstr.length; ++i) {
606 symbol = lstr[i].replace(
' ',
'');
607 symbol = symbol.replace(
'^{',
'');
608 symbol = symbol.replace(
'}',
'');
609 var size = symbol.length;
610 for (var j = 0; j < size; ++j) {
611 var c = symbol.charAt(j);
612 var u, e = parseInt(c);
613 if (e == 1) u = String.fromCharCode(0xB9);
614 else if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
615 else u = String.fromCharCode(0x2070 + e);
616 symbol = symbol.replace(c, u);
618 str = str.replace(lstr[i], symbol);
624 JSROOT.Painter.symbols_map = {
630 '#varepsilon' :
'\u03B5',
635 '#varphi' :
'\u03C6',
637 '#lambda' :
'\u03BB',
640 '#omicron' :
'\u03BF',
646 '#upsilon' :
'\u03C5',
647 '#varomega' :
'\u03D6',
656 '#Epsilon' :
'\u0395',
661 '#vartheta' :
'\u03D1',
663 '#Lambda' :
'\u039B',
666 '#Omicron' :
'\u039F',
672 '#Upsilon' :
'\u03A5',
673 '#varsigma' :
'\u03C2',
678 '#varUpsilon' :
'\u03D2',
679 '#epsilon' :
'\u03B5',
690 '#diamond' :
'\u2666',
693 '#leftrightarrow' :
'\u2194',
694 '#leftarrow' :
'\u2190',
695 '#uparrow' :
'\u2191',
696 '#rightarrow' :
'\u2192',
697 '#downarrow' :
'\u2193',
700 '#doublequote' :
'\u2033',
703 '#propto' :
'\u221D',
704 '#partial' :
'\u2202',
705 '#bullet' :
'\u2022',
709 '#approx' :
'\u2248',
713 '#downleftarrow' :
'\u21B5',
715 '#Jgothic' :
'\u2111',
716 '#Rgothic' :
'\u211C',
718 '#otimes' :
'\u2297',
720 '#oslash' :
'\u2205',
723 '#supseteq' :
'\u2287',
724 '#supset' :
'\u2283',
725 '#notsubset' :
'\u2284',
726 '#subseteq' :
'\u2286',
727 '#subset' :
'\u2282',
734 '#ocopyright' :
'\xA9',
735 '#trademark' :
'\u2122',
738 '#upoint' :
'\u22C5',
742 '#Leftrightarrow' :
'\u21D4',
743 '#Leftarrow' :
'\u21D0',
744 '#Uparrow' :
'\u21D1',
745 '#Rightarrow' :
'\u21D2',
746 '#Downarrow' :
'\u21D3',
749 '#copyright' :
'\xA9',
756 '#bottombar' :
'\u230A',
763 '#forall' :
'\u2200',
764 '#exists' :
'\u2203',
783 JSROOT.Painter.translateLaTeX =
function(string) {
785 str = this.translateExp(str);
786 while (str.indexOf(
'^{o}') != -1)
787 str = str.replace(
'^{o}',
'\xBA');
788 var lstr = str.match(/\#sqrt{(.*?)}/gi);
790 for (var i = 0; i < lstr.length; ++i) {
791 var symbol = lstr[i].replace(
' ',
'');
792 symbol = symbol.replace(
'#sqrt{',
'#sqrt');
793 symbol = symbol.replace(
'}',
'');
794 str = str.replace(lstr[i], symbol);
796 lstr = str.match(/\_{(.*?)}/gi);
798 for (var i = 0; i < lstr.length; ++i) {
799 var symbol = lstr[i].replace(
' ',
'');
800 symbol = symbol.replace(
'_{',
'');
801 symbol = symbol.replace(
'}',
'');
802 str = str.replace(lstr[i], symbol);
804 lstr = str.match(/\^{(.*?)}/gi);
806 for (i = 0; i < lstr.length; ++i) {
807 var symbol = lstr[i].replace(
' ',
'');
808 symbol = symbol.replace(
'^{',
'');
809 symbol = symbol.replace(
'}',
'');
810 str = str.replace(lstr[i], symbol);
812 while (str.indexOf(
'#/') != -1)
813 str = str.replace(
'#/', JSROOT.Painter.symbols_map[
'#/']);
814 for ( var x in JSROOT.Painter.symbols_map) {
815 while (str.indexOf(x) != -1)
816 str = str.replace(x, JSROOT.Painter.symbols_map[x]);
823 JSROOT.TBasePainter =
function() {
826 JSROOT.TBasePainter.prototype.Cleanup =
function() {
830 JSROOT.TBasePainter.prototype.GetObject =
function() {
834 JSROOT.TBasePainter.prototype.UpdateObject =
function(obj) {
838 JSROOT.TBasePainter.prototype.RedrawPad =
function(resize) {
841 JSROOT.TBasePainter.prototype.RedrawObject =
function(obj) {
842 if (this.UpdateObject(obj)) {
843 var current = document.body.style.cursor;
844 document.body.style.cursor =
'wait';
846 document.body.style.cursor = current;
850 JSROOT.TBasePainter.prototype.CheckResize =
function(force) {
853 JSROOT.TBasePainter.prototype.SetDivId =
function(divid) {
857 this[
'divid'] = divid;
859 $(
"#" + divid).children().eq(0).prop(
'painter',
this);
864 JSROOT.TObjectPainter =
function(obj) {
865 JSROOT.TBasePainter.call(
this);
866 this.obj_typename = (obj!=null) && (
'_typename' in obj) ? obj[
'_typename'] :
"";
872 JSROOT.TObjectPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
874 JSROOT.TObjectPainter.prototype.CheckResize =
function(force) {
876 var can = this.svg_canvas();
878 var pad_painter = can ? can[
'pad_painter'] : null;
880 if (pad_painter) pad_painter.CheckCanvasResize();
883 JSROOT.TObjectPainter.prototype.RemoveDrawG =
function() {
887 if (this.draw_g != null) {
888 this.draw_g.remove();
893 JSROOT.TObjectPainter.prototype.RecreateDrawG =
function(take_pad, layer) {
897 this.draw_g.selectAll(
"*").remove();
900 if (layer==null) layer =
".text_layer"
902 this.draw_g = this.svg_pad(
true).select(layer).append(
"svg:g");
904 var frame = this.svg_frame(
true);
906 var w = frame.attr(
"width");
907 var h = frame.attr(
"height");
910 if (layer==null) layer =
".main_layer";
911 this.draw_g = frame.select(layer).append(
"svg");
914 this.draw_g.attr(
"x", 0)
918 .attr(
"viewBox",
"0 0 " + w +
" " + h)
919 .attr(
'overflow',
'hidden');
924 JSROOT.TObjectPainter.prototype.svg_canvas =
function(asselect) {
925 var res = d3.select(
"#" + this.divid +
" .root_canvas");
926 return asselect ? res : res.node();
930 JSROOT.TObjectPainter.prototype.svg_pad =
function(asselect) {
931 var c = this.svg_canvas(
true);
932 if (this.pad_name !=
'')
933 c = c.select(
"[pad=" + this.pad_name +
']');
934 return asselect ? c : c.node();
937 JSROOT.TObjectPainter.prototype.root_pad =
function() {
938 var p = this.svg_pad();
939 var pad_painter = p ? p[
'pad_painter'] : null;
940 return pad_painter ? pad_painter.pad : null;
944 JSROOT.TObjectPainter.prototype.svg_frame =
function(asselect) {
945 var f = this.svg_pad(
true).select(
".root_frame");
946 return asselect ? f : f.node();
950 JSROOT.TObjectPainter.prototype.main_painter =
function() {
952 var svg_p = this.svg_pad();
953 if (svg_p) this.main = svg_p[
'mainpainter'];
958 JSROOT.TObjectPainter.prototype.is_main_painter =
function() {
959 return this == this.main_painter();
962 JSROOT.TObjectPainter.prototype.SetDivId =
function(divid, is_main) {
970 this[
'divid'] = divid;
972 if (is_main == null) is_main = 0;
974 this[
'create_canvas'] =
false;
977 var svg_c = this.svg_canvas();
979 if ((svg_c==null) && (is_main>0)) {
980 JSROOT.Painter.drawCanvas(divid, null);
981 svg_c = this.svg_canvas();
982 this[
'create_canvas'] =
true;
986 if ((is_main < 0) || (this.obj_typename==
"TCanvas"))
return;
988 console.log(
"Special case for " + this.obj_typename +
" assign painter to first DOM element");
989 $(
"#" + divid).children().eq(0).prop(
'painter',
this);
994 this.pad_name = svg_c[
'current_pad'];
996 if (is_main < 0)
return;
999 if ((is_main > 0) && (this.svg_frame()==null)) {
1000 JSROOT.Painter.drawFrame(divid, null);
1001 if (this.svg_frame()==null)
return alert(
"Fail to draw dummy TFrame");
1002 this[
'create_canvas'] =
true;
1005 var svg_p = this.svg_pad();
1006 if (svg_p[
'pad_painter'] !=
this)
1007 svg_p[
'pad_painter'].painters.push(
this);
1009 if ((is_main > 0) && (svg_p[
'mainpainter']==null))
1011 svg_p[
'mainpainter'] =
this;
1014 JSROOT.TObjectPainter.prototype.createAttFill =
function(attfill, pattern, color) {
1016 if ((pattern==null) && attfill) pattern = attfill[
'fFillStyle'];
1017 if ((color==null) && attfill) color = attfill[
'fFillColor'];
1019 var fill = { color:
"none" };
1020 fill.SetFill =
function(selection) {
1021 selection.style(
'fill', this.color);
1022 if (
'antialias' in
this)
1023 selection.style(
'antialias', this.antialias);
1025 fill.func = fill.SetFill.bind(fill);
1027 if (typeof attfill ==
'string') {
1028 fill.color = attfill;
1032 if ((pattern < 1001) || ((pattern >= 4000) && (pattern <= 4100)))
return fill;
1034 fill.color = JSROOT.Painter.root_colors[color];
1035 if (typeof fill.color !=
'string') fill.color =
"none";
1037 var svg = this.svg_canvas(
true);
1039 if ((pattern < 3000) || (pattern>3025) || svg.empty())
return fill;
1041 var
id =
"pat_" + pattern +
"_" + color;
1043 fill.color =
"url(#" +
id +
")";
1044 fill.antialias =
false;
1046 if (document.getElementById(
id) != null)
return fill;
1048 var line_color = JSROOT.Painter.root_colors[color];
1052 svg.append(
'svg:pattern')
1053 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1054 .attr(
"width",
"3px").attr(
"height",
"2px").style(
"stroke", line_color)
1056 .attr(
"x", 0).attr(
"y", 0).attr(
"width", 1).attr(
"height", 1).style(
"stroke",line_color)
1058 .attr(
"x", 2).attr(
"y", 0).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color)
1060 .attr(
"x", 1).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color);
1063 svg.append(
'svg:pattern')
1064 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1065 .attr(
"width",
"4px").attr(
"height",
"2px").style(
"stroke", line_color)
1067 .attr(
"x", 1).attr(
"y", 0).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color)
1069 .attr(
"x", 3).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color);
1072 svg.append(
'svg:pattern')
1073 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1074 .attr(
"width",
"4px").attr(
"height",
"4px").style(
"stroke", line_color)
1076 .attr(
"x", 2).attr(
"y", 1).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color)
1078 .attr(
"x", 0).attr(
"y", 3).attr(
"width", 1).attr(
"height", 1).style(
"stroke", line_color);
1081 svg.append(
'svg:pattern')
1082 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1083 .attr(
"width",
"8px").attr(
"height",
"8px").style(
"stroke", line_color)
1085 .attr(
"x1", 8).attr(
"y1", 0).attr(
"x2", 0).attr(
"y2", 8)
1086 .style(
"stroke",line_color).style(
"stroke-width", 1);
1089 svg.append(
'svg:pattern')
1090 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1091 .attr(
"width",
"8px").attr(
"height",
"8px").style(
"stroke", line_color)
1093 .attr(
"x1", 0).attr(
"y1", 0).attr(
"x2", 8).attr(
"y2", 8)
1094 .style(
"stroke",line_color).style(
"stroke-width", 1);
1097 svg.append(
'svg:pattern')
1098 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1099 .attr(
"width",
"4px").attr(
"height",
"4px").style(
"stroke", line_color)
1101 .attr(
"x1", 1).attr(
"y1", 0).attr(
"x2", 1).attr(
"y2", 3)
1102 .style(
"stroke",line_color).style(
"stroke-width", 1);
1105 svg.append(
'svg:pattern')
1106 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1107 .attr(
"width",
"4px").attr(
"height",
"4px").style(
"stroke", line_color)
1109 .attr(
"x1", 0).attr(
"y1", 1).attr(
"x2", 3).attr(
"y2", 1)
1110 .style(
"stroke",line_color).style(
"stroke-width", 1);
1113 svg.append(
'svg:pattern')
1114 .attr(
"id",
id).attr(
"patternUnits",
"userSpaceOnUse")
1115 .attr(
"width",
"8px").attr(
"height",
"8px").style(
"stroke", line_color)
1117 .attr(
"x1", 8).attr(
"y1", 0).attr(
"x2", 0).attr(
"y2", 8)
1118 .style(
"stroke",line_color).style(
"stroke-width", 1);
1126 JSROOT.TObjectPainter.prototype.ForEachPainter =
function(userfunc) {
1128 var svg_c = this.svg_canvas();
1130 userfunc(svg_c[
'pad_painter']);
1131 var painters = svg_c[
'pad_painter'].painters;
1132 for (var k in painters) userfunc(painters[k]);
1134 var painter = $(
"#" + this.divid).children().eq(0).prop(
'painter');
1135 if (painter!=null) userfunc(painter);
1139 JSROOT.TObjectPainter.prototype.Cleanup =
function() {
1141 $(
"#" + this.divid).empty();
1144 JSROOT.TObjectPainter.prototype.RedrawPad =
function(resize) {
1148 var pad = this.svg_pad();
1150 var pad_painter = pad ? pad[
'pad_painter'] : null;
1152 if (pad_painter) pad_painter.Redraw(
true);
1155 JSROOT.TObjectPainter.prototype.RemoveDrag =
function(id) {
1156 var drag_rect_name =
id +
"_drag_rect";
1157 var resize_rect_name =
id +
"_resize_rect";
1158 if (
this[drag_rect_name]) {
1159 this[drag_rect_name].remove();
1160 this[drag_rect_name] = null;
1162 if (
this[resize_rect_name]) {
1163 this[resize_rect_name].remove();
1164 this[resize_rect_name] = null;
1168 JSROOT.TObjectPainter.prototype.AddDrag =
function(id, draw_g, callback) {
1169 if (!JSROOT.gStyle.MoveResize)
return;
1173 var drag_rect_name =
id +
"_drag_rect";
1174 var resize_rect_name =
id +
"_resize_rect";
1176 var rect_width =
function() {
return Number(draw_g.attr(
"width")); }
1177 var rect_height =
function() {
return Number(draw_g.attr(
"height")); }
1179 var acc_x = 0, acc_y = 0, pad_w = 1, pad_h = 1;
1181 var drag_move = d3.behavior.drag().origin(Object)
1182 .on(
"dragstart",
function() {
1183 d3.event.sourceEvent.preventDefault();
1185 acc_x = 0; acc_y = 0;
1186 pad_w = Number(pthis.svg_pad(
true).attr(
"width")) - rect_width();
1187 pad_h = Number(pthis.svg_pad(
true).attr(
"height")) - rect_height();
1189 pthis[drag_rect_name] =
1192 .attr(
"class",
"zoom")
1193 .attr(
"id", drag_rect_name)
1194 .attr(
"x", draw_g.attr(
"x"))
1195 .attr(
"y", draw_g.attr(
"y"))
1196 .attr(
"width", rect_width())
1197 .attr(
"height", rect_height())
1198 .style(
"cursor",
"move");
1199 }).on(
"drag",
function() {
1200 d3.event.sourceEvent.preventDefault();
1202 var x = Number(pthis[drag_rect_name].attr(
"x"));
1203 var y = Number(pthis[drag_rect_name].attr(
"y"));
1204 var dx = d3.event.dx, dy = d3.event.dy;
1206 if (((acc_x<0) && (dx>0)) || ((acc_x>0) && (dx<0))) { acc_x += dx; dx = 0; }
1207 if (((acc_y<0) && (dy>0)) || ((acc_y>0) && (dy<0))) { acc_y += dy; dy = 0; }
1209 if ((x + dx < 0) || (x +dx > pad_w)) acc_x += dx;
else x+=dx;
1210 if ((y+dy < 0) || (y+dy > pad_h)) acc_y += dy;
else y += dy;
1212 pthis[drag_rect_name].attr(
"x", x);
1213 pthis[drag_rect_name].attr(
"y", y);
1215 JSROOT.Painter.moveChildToEnd(pthis[drag_rect_name]);
1217 d3.event.sourceEvent.stopPropagation();
1218 }).on(
"dragend",
function() {
1219 d3.event.sourceEvent.preventDefault();
1221 pthis[drag_rect_name].style(
"cursor",
"auto");
1223 var x = Number(pthis[drag_rect_name].attr(
"x"));
1224 var y = Number(pthis[drag_rect_name].attr(
"y"));
1226 var dx = x - Number(draw_g.attr(
"x"));
1227 var dy = y - Number(draw_g.attr(
"y"));
1229 pthis[drag_rect_name].remove();
1230 pthis[drag_rect_name] = null;
1232 draw_g.attr(
"x", x).attr(
"y", y);
1234 callback.move(x, y, dx, dy);
1236 pthis[resize_rect_name]
1237 .attr(
"x", rect_width() - 20)
1238 .attr(
"y", rect_height() - 20);
1241 var drag_resize = d3.behavior.drag().origin(Object)
1242 .on(
"dragstart",
function() {
1243 d3.event.sourceEvent.stopPropagation();
1244 d3.event.sourceEvent.preventDefault();
1246 acc_x = 0; acc_y = 0;
1247 pad_w = Number(pthis.svg_pad(
true).attr(
"width")) - Number(draw_g.attr(
"x"));
1248 pad_h = Number(pthis.svg_pad(
true).attr(
"height")) - Number(draw_g.attr(
"y"));
1249 pthis[drag_rect_name] =
1252 .attr(
"class",
"zoom")
1253 .attr(
"id", drag_rect_name)
1254 .attr(
"x", draw_g.attr(
"x"))
1255 .attr(
"y", draw_g.attr(
"y"))
1256 .attr(
"width", rect_width())
1257 .attr(
"height", rect_height())
1258 .style(
"cursor",
"se-resize");
1259 }).on(
"drag",
function() {
1260 d3.event.sourceEvent.preventDefault();
1262 var w = Number(pthis[drag_rect_name].attr(
"width"));
1263 var h = Number(pthis[drag_rect_name].attr(
"height"));
1264 var dx = d3.event.dx, dy = d3.event.dy;
1265 if ((acc_x>0) && (dx<0)) { acc_x += dx; dx = 0; }
1266 if ((acc_y>0) && (dy<0)) { acc_y += dy; dy = 0; }
1267 if (w+dx > pad_w) acc_x += dx;
else w+=dx;
1268 if (h+dy > pad_h) acc_y += dy;
else h+=dy;
1269 pthis[drag_rect_name].attr(
"width", w);
1270 pthis[drag_rect_name].attr(
"height", h);
1272 JSROOT.Painter.moveChildToEnd(pthis[drag_rect_name]);
1274 d3.event.sourceEvent.stopPropagation();
1275 }).on(
"dragend",
function() {
1276 d3.event.sourceEvent.preventDefault();
1277 pthis[drag_rect_name].style(
"cursor",
"auto");
1279 var newwidth = Number(pthis[drag_rect_name].attr(
"width"));
1280 var newheight = Number(pthis[drag_rect_name].attr(
"height"));
1282 draw_g.attr(
'width', newwidth).attr(
'height', newheight);
1284 pthis[drag_rect_name].remove();
1285 pthis[drag_rect_name] = null;
1287 callback.resize(newwidth, newheight);
1290 pthis[resize_rect_name]
1291 .attr(
"x", newwidth - 20)
1292 .attr(
"y", newheight - 20);
1295 draw_g.call(drag_move);
1297 this[resize_rect_name] =
1298 draw_g.append(
"rect")
1299 .attr(
"class", resize_rect_name)
1300 .style(
"opacity",
"0")
1301 .style(
"cursor",
"se-resize")
1302 .attr(
"x", rect_width() - 20)
1303 .attr(
"y", rect_height() - 20)
1309 JSROOT.TObjectPainter.prototype.FindPainterFor =
function(selobj,selname) {
1314 var painters = this.svg_pad() ? this.svg_pad().pad_painter.painters : null;
1315 if (painters == null)
return null;
1317 for (var n in painters) {
1318 var pobj = painters[n].GetObject();
1319 if (pobj==null)
continue;
1321 if (selobj && (pobj === selobj))
return painters[n];
1323 if (selname && (
'fName' in pobj) && (pobj[
'fName']==selname))
return painters[n];
1329 JSROOT.TObjectPainter.prototype.Redraw =
function() {
1337 JSROOT.TFramePainter =
function(tframe) {
1338 JSROOT.TObjectPainter.call(
this, tframe);
1339 this.tframe = tframe;
1342 JSROOT.TFramePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
1344 JSROOT.TFramePainter.prototype.GetObject =
function() {
1348 JSROOT.TFramePainter.prototype.Shrink =
function(shrink_left, shrink_right) {
1349 var ndc = this.svg_frame() ? this.svg_frame()[
'NDC'] : null;
1351 ndc.x1 += shrink_left;
1352 ndc.x2 -= shrink_right;
1356 JSROOT.TFramePainter.prototype.DrawFrameSvg =
function() {
1357 var width = Number(this.svg_pad(
true).attr(
"width")),
1358 height = Number(this.svg_pad(
true).attr(
"height"));
1359 var w = width, h = height;
1361 var ndc = this.svg_frame() ? this.svg_frame()[
'NDC'] : null;
1362 if (ndc == null) ndc = { x1 : 0.07, y1 : 0.12, x2 : 0.95, y2 : 0.88 };
1364 var root_pad = this.root_pad();
1366 var lm = width * ndc.x1;
1367 var rm = width * (1 - ndc.x2);
1368 var tm = height * ndc.y1;
1369 var bm = height * (1 - ndc.y2);
1371 var framecolor = this.createAttFill(
'white'),
1372 lineatt = JSROOT.Painter.createAttLine(
'black'),
1373 bordermode = 0, bordersize = 0;
1376 bordermode = this.tframe[
'fBorderMode'];
1377 bordersize = this.tframe[
'fBorderSize'];
1378 lineatt = JSROOT.Painter.createAttLine(this.tframe);
1380 var xspan = width / Math.abs(root_pad[
'fX2'] - root_pad[
'fX1']);
1381 var yspan = height / Math.abs(root_pad[
'fY2'] - root_pad[
'fY1']);
1382 var px1 = (this.tframe[
'fX1'] - root_pad[
'fX1']) * xspan;
1383 var py1 = (this.tframe[
'fY1'] - root_pad[
'fY1']) * yspan;
1384 var px2 = (this.tframe[
'fX2'] - root_pad[
'fX1']) * xspan;
1385 var py2 = (this.tframe[
'fY2'] - root_pad[
'fY1']) * yspan;
1386 var pxl, pxt, pyl, pyt;
1387 if (px1 < px2) { pxl = px1; pxt = px2; }
1388 else { pxl = px2; pxt = px1; }
1389 if (py1 < py2) { pyl = py1; pyt = py2; }
1390 else { pyl = py2; pyt = py1; }
1398 lm = this.tframe[
'fX1'] * width;
1399 tm = this.tframe[
'fY1'] * height;
1400 bm = (1.0 - this.tframe[
'fY2']) * height;
1401 rm = (1.0 - this.tframe[
'fX2'] + shrink_right) * width;
1405 framecolor = this.createAttFill(this.tframe);
1408 framecolor = this.createAttFill(null, root_pad[
'fFrameFillStyle'], root_pad[
'fFrameFillColor']);
1415 if (framecolor.color ==
'none') framecolor.color =
'white';
1418 var frame_g = this.svg_pad(
true).select(
".root_frame");
1420 var top_rect = null;
1422 if (frame_g.empty()) {
1423 frame_g = this.svg_pad(
true).select(
".frame_layer").append(
"svg:g").attr(
"class",
"root_frame");
1425 top_rect = frame_g.append(
"svg:rect");
1428 frame_g.append(
'svg:g').attr(
'class',
'grid_layer');
1429 frame_g.append(
'svg:g').attr(
'class',
'main_layer');
1430 frame_g.append(
'svg:g').attr(
'class',
'axis_layer');
1432 top_rect = frame_g.select(
"rect");
1436 frame_g.node()[
'NDC'] = {
1438 x2 : (lm + w) / width,
1440 y2 : (tm + h) / height
1444 frame_g.node()[
'frame_painter'] =
this;
1446 lm = Math.round(lm); tm = Math.round(tm);
1447 w = Math.round(w); h = Math.round(h);
1449 frame_g.attr(
"x", lm)
1453 .attr(
"transform",
"translate(" + lm +
"," + tm +
")");
1455 top_rect.attr(
"x", 0)
1459 .call(framecolor.func)
1460 .call(lineatt.func);
1463 JSROOT.TFramePainter.prototype.Redraw =
function() {
1464 this.DrawFrameSvg();
1467 JSROOT.Painter.drawFrame =
function(divid, obj) {
1468 var p =
new JSROOT.TFramePainter(obj);
1476 JSROOT.TF1Painter =
function(tf1) {
1477 JSROOT.TObjectPainter.call(
this, tf1);
1481 JSROOT.TF1Painter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
1483 JSROOT.TF1Painter.prototype.GetObject =
function() {
1487 JSROOT.TF1Painter.prototype.Redraw =
function() {
1491 JSROOT.TF1Painter.prototype.Eval =
function(x) {
1492 return this.tf1.evalPar(x);
1495 JSROOT.TF1Painter.prototype.CreateDummyHisto =
function() {
1496 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
1497 if (this.tf1[
'fNsave'] > 0) {
1500 var nb_points = this.tf1[
'fNpx'];
1501 for (var i = 0; i < nb_points; ++i) {
1502 var h = this.tf1[
'fSave'][i];
1503 if ((i == 0) || (h > ymax))
1505 if ((i == 0) || (h < ymin))
1508 xmin = this.tf1[
'fSave'][nb_points + 1];
1509 xmax = this.tf1[
'fSave'][nb_points + 2];
1513 if (this.tf1[
'fNpfits'] <= 103)
1514 this.tf1[
'fNpfits'] = 103;
1515 xmin = this.tf1[
'fXmin'];
1516 xmax = this.tf1[
'fXmax'];
1518 var nb_points = Math.max(this.tf1[
'fNpx'], this.tf1[
'fNpfits']);
1520 var binwidthx = (xmax - xmin) / nb_points;
1521 var left = -1, right = -1;
1522 for (var i = 0; i < nb_points; ++i) {
1523 var h = this.Eval(xmin + (i * binwidthx));
1524 if (isNaN(h))
continue;
1531 if ((right < 0) || (right == i - 1))
1541 xmax = xmin + right * binwidthx;
1542 xmin = xmin + left * binwidthx;
1546 if (ymax > 0.0) ymax *= 1.05;
1547 if (ymin < 0.0) ymin *= 1.05;
1549 var histo = JSROOT.Create(
"TH1I");
1551 histo[
'fName'] = this.tf1[
'fName'] +
"_hist";
1552 histo[
'fTitle'] = this.tf1[
'fTitle'];
1554 histo[
'fXaxis'][
'fXmin'] = xmin;
1555 histo[
'fXaxis'][
'fXmax'] = xmax;
1556 histo[
'fYaxis'][
'fXmin'] = ymin;
1557 histo[
'fYaxis'][
'fXmax'] = ymax;
1562 JSROOT.TF1Painter.prototype.CreateBins =
function() {
1566 if (this.tf1[
'fNsave'] > 0) {
1569 var nb_points = this.tf1[
'fNpx'];
1571 var xmin = this.tf1[
'fSave'][nb_points + 1];
1572 var xmax = this.tf1[
'fSave'][nb_points + 2];
1573 var binwidthx = (xmax - xmin) / nb_points;
1575 this[
'bins'] = d3.range(nb_points).map(
function(p) {
1577 x : xmin + (p * binwidthx),
1578 y : pthis.tf1[
'fSave'][p]
1581 this[
'interpolate_method'] =
'monotone';
1583 if (this.tf1[
'fNpfits'] <= 103)
1584 this.tf1[
'fNpfits'] = 333;
1585 var xmin = this.tf1[
'fXmin'];
1586 var xmax = this.tf1[
'fXmax'];
1587 var nb_points = Math.max(this.tf1[
'fNpx'], this.tf1[
'fNpfits']);
1588 var binwidthx = (xmax - xmin) / nb_points;
1589 this[
'bins'] = d3.range(nb_points).map(
function(p) {
1590 var xx = xmin + (p * binwidthx);
1591 var yy = pthis.Eval(xx);
1592 if (isNaN(yy)) yy = 0;
1598 this[
'interpolate_method'] =
'cardinal-open';
1602 JSROOT.TF1Painter.prototype.DrawBins =
function() {
1603 var w = Number(this.svg_frame(
true).attr(
"width")),
1604 h = Number(this.svg_frame(
true).attr(
"height"));
1606 this.RecreateDrawG();
1609 var x = this.main_painter().x;
1610 var y = this.main_painter().y;
1612 var attline = JSROOT.Painter.createAttLine(this.tf1);
1613 var fill = this.createAttFill(this.tf1);
1614 if (fill.color ==
'white') fill.color =
'none';
1616 var line = d3.svg.line()
1617 .x(
function(d) {
return x(d.x).toFixed(1); })
1618 .y(
function(d) {
return y(d.y).toFixed(1); })
1619 .interpolate(this.interpolate_method);
1621 var area = d3.svg.area()
1622 .x(
function(d) {
return x(d.x).toFixed(1); })
1624 .y0(
function(d) {
return y(d.y).toFixed(1); });
1626 if (attline.color !=
"none")
1627 this.draw_g.append(
"svg:path")
1628 .attr(
"class",
"line")
1629 .attr(
"d",line(pthis.bins))
1630 .style(
"fill",
"none")
1631 .call(attline.func);
1633 if (fill.color !=
"none")
1634 this.draw_g.append(
"svg:path")
1635 .attr(
"class",
"area")
1636 .attr(
"d",area(pthis.bins))
1637 .style(
"stroke",
"none")
1641 if (JSROOT.gStyle.Tooltip)
1642 this.draw_g.selectAll()
1643 .data(this.bins).enter()
1644 .append(
"svg:circle")
1645 .attr(
"cx",
function(d) {
return x(d.x).toFixed(1); })
1646 .attr(
"cy",
function(d) {
return y(d.y).toFixed(1); })
1648 .style(
"opacity", 0)
1649 .append(
"svg:title")
1650 .text(
function(d) {
return "x = " + d.x.toPrecision(4) +
" \ny = " + d.y.toPrecision(4); });
1653 JSROOT.TF1Painter.prototype.UpdateObject =
function(obj) {
1654 if (obj[
'_typename'] != this.tf1[
'_typename'])
return false;
1661 JSROOT.Painter.drawFunction =
function(divid, tf1) {
1662 var painter =
new JSROOT.TF1Painter(tf1);
1664 painter.SetDivId(divid, -1);
1666 if (painter.main_painter() == null) {
1667 var histo = painter.CreateDummyHisto();
1668 JSROOT.Painter.drawHistogram1D(divid, histo);
1671 painter.SetDivId(divid);
1673 painter.CreateBins();
1682 JSROOT.TGraphPainter =
function(graph) {
1683 JSROOT.TObjectPainter.call(
this, graph);
1685 this.ownhisto =
false;
1688 JSROOT.TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
1690 JSROOT.TGraphPainter.prototype.GetObject =
function() {
1694 JSROOT.TGraphPainter.prototype.Redraw =
function() {
1698 JSROOT.TGraphPainter.prototype.DecodeOptions =
function(opt) {
1704 this.draw_all =
true;
1705 this.optionLine = 0;
1706 this.optionAxis = 0;
1707 this.optionCurve = 0;
1708 this.optionStar = 0;
1709 this.optionMark = 0;
1714 this.optionFill = 0;
1716 this.optionCurveFill = 0;
1717 this.draw_errors =
true;
1718 this.optionNone = 0;
1721 if ((opt != null) && (opt !=
"")) {
1722 this.opt = opt.toUpperCase();
1723 this.opt.replace(
'SAME',
'');
1726 if (this.opt.indexOf(
'L') != -1)
1727 this.optionLine = 1;
1728 if (this.opt.indexOf(
'A') != -1)
1729 this.optionAxis = 1;
1730 if (this.opt.indexOf(
'C') != -1)
1731 this.optionCurve = 1;
1732 if (this.opt.indexOf(
'*') != -1)
1733 this.optionStar = 1;
1734 if (this.opt.indexOf(
'P') != -1)
1735 this.optionMark = 1;
1736 if (this.opt.indexOf(
'B') != -1)
1738 if (this.opt.indexOf(
'R') != -1)
1740 if (this.opt.indexOf(
'1') != -1)
1742 if (this.opt.indexOf(
'F') != -1)
1743 this.optionFill = 1;
1744 if (this.opt.indexOf(
'2') != -1 || this.opt.indexOf(
'3') != -1
1745 || this.opt.indexOf(
'4') != -1 || this.opt.indexOf(
'5') != -1)
1749 if (this.optionLine + this.optionFill + this.optionCurve + this.optionStar + this.optionMark + this.optionBar + this.optionE == 0) {
1750 if (this.opt.length == 0)
1751 this.optionLine = 1;
1753 this.optionNone = 1;
1757 if (this.optionStar)
1758 this.graph[
'fMarkerStyle'] = 3;
1760 if (this.optionCurve && this.optionFill) {
1761 this.optionCurveFill = 1;
1762 this.optionFill = 0;
1765 var pad = this.root_pad();
1767 this.logx = pad[
'fLogx'];
1768 this.logy = pad[
'fLogy'];
1769 this.logz = pad[
'fLogz'];
1770 this.gridx = pad[
'fGridx'];
1771 this.gridy = pad[
'fGridy'];
1774 this.xaxis_type = this.logx ?
'logarithmic' :
'linear';
1775 this.yaxis_type = this.logy ?
'logarithmic' :
'linear';
1777 if (this.graph[
'_typename'] ==
'TGraph') {
1779 if (this.graph[
'fHistogram'][
'fXaxis'][
'fTimeDisplay']) {
1780 this.xaxis_type =
'datetime';
1783 if (this.graph[
'fHistogram'][
'fYaxis'][
'fTimeDisplay']) {
1784 this.yaxis_type =
'datetime';
1786 }
else if (this.graph[
'_typename'] ==
'TGraphErrors') {
1787 this.maxEX = d3.max(this.graph[
'fEX']);
1788 this.maxEY = d3.max(this.graph[
'fEY']);
1789 if (this.maxEX < 1.0e-300 && this.maxEY < 1.0e-300)
1790 this.draw_errors =
false;
1792 this.seriesType =
'scatter';
1793 if (this.optionBar == 1) this.seriesType =
'bar';
1794 this.showMarker =
false;
1795 if (this.optionMark == 1 || this.optionStar == 1) this.showMarker =
true;
1797 if (this.optionLine == 1 || this.optionCurve == 1 || this.optionFill == 1)
1798 this.seriesType =
'line';
1800 if (this.optionBar == 1) {
1801 this.binwidthx = (this.graph[
'fHistogram'][
'fXaxis'][
'fXmax'] -
1802 this.graph[
'fHistogram'][
'fXaxis'][
'fXmin'])
1803 / (this.graph[
'fNpoints'] - 1);
1807 JSROOT.TGraphPainter.prototype.CreateBins =
function() {
1810 var npoints = this.graph[
'fNpoints'];
1811 if ((this.graph._typename==
"TCutG") && (npoints>3)) npoints--;
1813 this.lineatt = JSROOT.Painter.createAttLine(this.graph);
1815 this.bins = d3.range(npoints).map(
1817 if (pthis.optionBar == 1) {
1819 x : pthis.graph[
'fX'][p] - (pthis.binwidthx / 2),
1820 y : pthis.graph[
'fY'][p],
1821 bw : pthis.binwidthx,
1822 bh : pthis.graph[
'fY'][p]
1824 }
else if (pthis.graph[
'_typename'] ==
'TGraphErrors') {
1826 x : pthis.graph[
'fX'][p],
1827 y : pthis.graph[
'fY'][p],
1828 exlow : pthis.graph[
'fEX'][p],
1829 exhigh : pthis.graph[
'fEX'][p],
1830 eylow : pthis.graph[
'fEY'][p],
1831 eyhigh : pthis.graph[
'fEY'][p]
1833 }
else if (pthis.graph[
'_typename'] ==
'TGraphAsymmErrors'
1834 || pthis.graph[
'_typename'].match(/^RooHist/)) {
1836 x : pthis.graph[
'fX'][p],
1837 y : pthis.graph[
'fY'][p],
1838 exlow : pthis.graph[
'fEXlow'][p],
1839 exhigh : pthis.graph[
'fEXhigh'][p],
1840 eylow : pthis.graph[
'fEYlow'][p],
1841 eyhigh : pthis.graph[
'fEYhigh'][p]
1845 x : pthis.graph[
'fX'][p],
1846 y : pthis.graph[
'fY'][p]
1851 this.exclusionGraph =
false;
1852 if (this.lineatt.width <= 99)
return;
1856 this.exclusionGraph =
true;
1859 var n = this.graph[
'fNpoints'];
1860 var xo =
new Array(n + 2),
1861 yo =
new Array(n + 2),
1862 xt =
new Array(n + 2),
1863 yt =
new Array(n + 2),
1864 xf =
new Array(2 * n + 2),
1865 yf =
new Array(2 * n + 2);
1870 var a, i, j, nf, wk = 1;
1871 if (this.lineatt.width > 32767) {
1872 this.lineatt.width = 65536 - this.lineatt.width;
1875 wk *= (this.lineatt.width / 100) * 0.005;
1876 this.lineatt.width = this.lineatt.width % 100;
1877 if (this.lineatt.width > 0) this.optionLine = 1;
1879 var w = Number(this.svg_frame(
true).attr(
"width")),
1880 h = Number(this.svg_frame(
true).attr(
"height"));
1884 var xmin = this.main_painter().xmin, xmax = this.main_painter().xmax,
1885 ymin = this.main_painter().ymin, ymax = this.main_painter().ymax;
1886 for (i = 0; i < n; i++) {
1887 xo[i] = (this.graph[
'fX'][i] - xmin) / (xmax - xmin);
1888 yo[i] = (this.graph[
'fY'][i] - ymin) / (ymax - ymin);
1890 yo[i] = yo[i] / ratio;
1892 xo[i] = xo[i] / ratio;
1899 for (i = 1; i < n; i++) {
1900 if (xo[i] == xo[i - 1] && yo[i] == yo[i - 1])
continue;
1903 if (xf[i] == xf[i - 1])
1911 if (xf[1] == xf[0]) {
1914 a = Math.atan((yf[1] - yf[0]) / (xf[1] - xf[0]));
1916 if (xf[0] <= xf[1]) {
1917 xt[0] = xf[0] - wk * Math.sin(a);
1918 yt[0] = yf[0] + wk * Math.cos(a);
1920 xt[0] = xf[0] + wk * Math.sin(a);
1921 yt[0] = yf[0] - wk * Math.cos(a);
1923 if (xf[nf] == xf[nf - 1]) {
1926 a = Math.atan((yf[nf] - yf[nf - 1]) / (xf[nf] - xf[nf - 1]));
1928 if (xf[nf] >= xf[nf - 1]) {
1929 xt[nf] = xf[nf] - wk * Math.sin(a);
1930 yt[nf] = yf[nf] + wk * Math.cos(a);
1932 xt[nf] = xf[nf] + wk * Math.sin(a);
1933 yt[nf] = yf[nf] - wk * Math.cos(a);
1936 var a1, a2, a3, xi0, yi0, xi1, yi1, xi2, yi2;
1937 for (i = 1; i < nf; i++) {
1947 a1 = Math.atan((yi1 - yi0) / (xi1 - xi0));
1954 a2 = Math.atan((yi0 - yi2) / (xi0 - xi2));
1958 x1 = xi0 - wk * Math.sin(a1);
1959 y1 = yi0 + wk * Math.cos(a1);
1960 x2 = xi0 - wk * Math.sin(a2);
1961 y2 = yi0 + wk * Math.cos(a2);
1962 xm = (x1 + x2) * 0.5;
1963 ym = (y1 + y2) * 0.5;
1967 a3 = Math.atan((ym - yi0) / (xm - xi0));
1969 x3 = xi0 - wk * Math.sin(a3 + (Math.PI / 2.0));
1970 y3 = yi0 + wk * Math.cos(a3 + (Math.PI / 2.0));
1973 if ((xm - xi0) * (x3 - xi0) < 0 && (ym - yi0) * (y3 - yi0) < 0) {
1977 if ((xm == x1) && (ym == y1)) {
1985 if (xf[nf] == xf[0] && yf[nf] == yf[0]) {
1986 xm = (xt[nf] + xt[0]) * 0.5;
1987 ym = (yt[nf] + yt[0]) * 0.5;
1991 a3 = Math.atan((ym - yf[0]) / (xm - xf[0]));
1993 x3 = xf[0] + wk * Math.sin(a3 + (Math.PI / 2.0));
1994 y3 = yf[0] - wk * Math.cos(a3 + (Math.PI / 2.0));
1995 if ((xm - xf[0]) * (x3 - xf[0]) < 0 && (ym - yf[0]) * (y3 - yf[0]) < 0) {
1996 x3 = 2 * xf[0] - x3;
1997 y3 = 2 * yf[0] - y3;
2005 var xc, yc, c1, b1, c2, b2;
2008 for (i = nf2; i > 0; i--) {
2009 for (j = i - 1; j > 0; j--) {
2010 if (xt[i - 1] == xt[i] || xt[j - 1] == xt[j])
2012 c1 = (yt[i - 1] - yt[i]) / (xt[i - 1] - xt[i]);
2013 b1 = yt[i] - c1 * xt[i];
2014 c2 = (yt[j - 1] - yt[j]) / (xt[j - 1] - xt[j]);
2015 b2 = yt[j] - c2 * xt[j];
2017 xc = (b2 - b1) / (c1 - c2);
2019 if (xc > Math.min(xt[i], xt[i - 1])
2020 && xc < Math.max(xt[i], xt[i - 1])
2021 && xc > Math.min(xt[j], xt[j - 1])
2022 && xc < Math.max(xt[j], xt[j - 1])
2023 && yc > Math.min(yt[i], yt[i - 1])
2024 && yc < Math.max(yt[i], yt[i - 1])
2025 && yc > Math.min(yt[j], yt[j - 1])
2026 && yc < Math.max(yt[j], yt[j - 1])) {
2054 for (i = 0; i < nf; i++) {
2056 xf[i] = xmin + (xf[i] * (xmax - xmin));
2057 yf[i] = ymin + (yf[i] * (ymax - ymin)) * ratio;
2059 xf[i] = xmin + (xf[i] * (xmax - xmin)) * ratio;
2060 yf[i] = ymin + (yf[i] * (ymax - ymin));
2062 xf[i] = xmin + (xf[i] * (xmax - xmin));
2063 yf[i] = ymin + (yf[i] * (ymax - ymin));
2065 if (this.logx && xf[i] <= 0.0)
2067 if (this.logy && yf[i] <= 0.0)
2071 this.excl = d3.range(nf).map(
function(p) {
return { x : xf[p], y : yf[p] }; });
2076 xo.splice(0, xo.length);
2077 yo.splice(0, yo.length);
2080 xt.splice(0, xt.length);
2081 yt.splice(0, yt.length);
2084 xf.splice(0, xf.length);
2085 yf.splice(0, yf.length);
2090 JSROOT.TGraphPainter.prototype.DrawBins =
function() {
2092 var w = Number(this.svg_frame(
true).attr(
"width")),
2093 h = Number(this.svg_frame(
true).attr(
"height"));
2095 this.RecreateDrawG();
2099 var fill = this.createAttFill(this.graph);
2101 function TooltipText(d) {
2103 var res =
"x = " + pthis.main_painter().AxisAsText(
"x", d.x) +
"\n" +
2104 "y = " + pthis.main_painter().AxisAsText(
"y", d.y);
2106 if (pthis.draw_errors && (
'exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0)))
2107 res +=
"\nerror x = -" + pthis.main_painter().AxisAsText(
"x", d.exlow) +
2108 "/+" + pthis.main_painter().AxisAsText(
"x", d.exhigh);
2110 if (pthis.draw_errors && (
'eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0)) )
2111 res +=
"\nerror y = -" + pthis.main_painter().AxisAsText(
"y", d.eylow) +
2112 "/+" + pthis.main_painter().AxisAsText(
"y", d.eyhigh);
2117 var x = this.main_painter().x;
2118 var y = this.main_painter().y;
2119 var line = d3.svg.line()
2120 .x(
function(d) {
return Math.round(x(d.x)); })
2121 .y(
function(d) {
return Math.round(y(d.y)); });
2123 if (this.seriesType ==
'bar') {
2124 var fillcolor = JSROOT.Painter.root_colors[this.graph[
'fFillColor']];
2125 if (typeof (fillcolor) ==
'undefined') fillcolor =
"rgb(204,204,204)";
2127 var xdom = this.main_painter().x.domain();
2128 var xfactor = xdom[1] - xdom[0];
2129 this.draw_errors =
false;
2131 var nodes = this.draw_g.selectAll(
"bar_graph")
2132 .data(pthis.bins).enter()
2134 .attr(
"x",
function(d) {
return x(d.x) })
2135 .attr(
"y",
function(d) {
return y(d.y) })
2136 .attr(
"width",
function(d) {
return (w / (xdom[1] - xdom[0])) - 1 })
2137 .attr(
"height",
function(d) {
return y(d.y) - y(d.y + d.bh); })
2138 .style(
"fill", fillcolor);
2140 if (JSROOT.gStyle.Tooltip)
2141 nodes.append(
"svg:title").text(
function(d) {
return "x = " + d.x.toPrecision(4) +
" \nentries = " + d.y.toPrecision(4); });
2143 if (this.exclusionGraph) {
2145 this.showMarker =
false;
2147 this.draw_g.append(
"svg:path")
2148 .attr(
"d", line(pthis.excl))
2149 .style(
"stroke",
"none")
2150 .style(
"stroke-width", pthis.excl_ff)
2152 .style(
'opacity', 0.75);
2155 if (this.seriesType ==
'line') {
2157 var close_symbol =
"";
2158 if (this.graph._typename==
"TCutG") close_symbol =
" Z";
2160 var lineatt = this.lineatt;
2161 if (this.optionLine == 0) lineatt = JSROOT.Painter.createAttLine(
'none');
2163 if (this.optionFill == 1) {
2166 fill.color =
'none';
2169 this.draw_g.append(
"svg:path")
2170 .attr(
"d", line(pthis.bins) + close_symbol)
2171 .attr(
"class",
"draw_line")
2176 if (JSROOT.gStyle.Tooltip && !
this.showMarker)
2177 this.draw_g.selectAll(
"draw_line")
2178 .data(pthis.bins).enter()
2179 .append(
"svg:circle")
2180 .attr(
"cx",
function(d) {
return Math.round(x(d.x)); })
2181 .attr(
"cy",
function(d) {
return Math.round(y(d.y)); })
2183 .style(
"opacity", 0)
2184 .append(
"svg:title")
2188 if (this.draw_errors)
2189 this.draw_errors = (this.graph[
'_typename'] ==
'TGraphErrors' ||
2190 this.graph[
'_typename'] ==
'TGraphAsymmErrors' ||
2191 this.graph[
'_typename'].match(/^RooHist/)) && !this.optionBar;
2195 if (this.draw_errors || this.showMarker) {
2196 var draw_bins =
new Array;
2197 for (var i in this.bins) {
2198 var pnt = this.bins[i];
2201 if ((grx<0) || (grx>w) || (gry<0) || (gry>h))
continue;
2204 pnt[
'grx1'] = grx.toFixed(1);
2205 pnt[
'gry1'] = gry.toFixed(1);
2206 if (pnt.exlow > 0) pnt[
'grx0'] = (x(pnt.x - pnt.exlow) - grx).toFixed(1);
2207 if (pnt.exhigh > 0) pnt[
'grx2'] = (x(pnt.x + pnt.exhigh) - grx).toFixed(1);
2208 if (pnt.eylow > 0) pnt[
'gry0'] = (y(pnt.y - pnt.eylow) - gry).toFixed(1);
2209 if (pnt.eyhigh > 0) pnt[
'gry2'] = (y(pnt.y + pnt.eyhigh) - gry).toFixed(1);
2211 draw_bins.push(pnt);
2214 nodes = this.draw_g.selectAll(
"g.node")
2218 .attr(
"transform",
function(d) {
return "translate(" + d.grx1 +
"," + d.gry1 +
")"; })
2221 if (JSROOT.gStyle.Tooltip && nodes)
2222 nodes.append(
"svg:title").text(TooltipText);
2224 if (this.draw_errors) {
2226 nodes.filter(
function(d) {
return (d.exlow > 0) || (d.exhigh > 0); })
2228 .attr(
"x1",
function(d) {
return d.grx0; })
2230 .attr(
"x2",
function(d) {
return d.grx2; })
2232 .style(
"stroke", this.lineatt.color)
2233 .style(
"stroke-width", this.lineatt.width);
2235 nodes.filter(
function(d) {
return (d.exlow > 0); })
2238 .attr(
"x1",
function(d) {
return d.grx0; })
2240 .attr(
"x2",
function(d) {
return d.grx0; })
2241 .style(
"stroke", this.lineatt.color)
2242 .style(
"stroke-width", this.lineatt.width);
2244 nodes.filter(
function(d) {
return (d.exhigh > 0); })
2247 .attr(
"x1",
function(d) {
return d.grx2; })
2249 .attr(
"x2",
function(d) {
return d.grx2; })
2250 .style(
"stroke", this.lineatt.color)
2251 .style(
"stroke-width", this.lineatt.width);
2255 nodes.filter(
function(d) {
return (d.eylow > 0) || (d.eyhigh > 0); })
2258 .attr(
"y1",
function(d) {
return d.gry0; })
2260 .attr(
"y2",
function(d) {
return d.gry2; })
2261 .style(
"stroke", this.lineatt.color)
2262 .style(
"stroke-width", this.lineatt.width);
2264 nodes.filter(
function(d) {
return (d.eylow > 0); })
2267 .attr(
"y1",
function(d) {
return d.gry0; })
2269 .attr(
"y2",
function(d) {
return d.gry0; })
2270 .style(
"stroke", this.lineatt.color)
2271 .style(
"stroke-width", this.lineatt.width);
2273 nodes.filter(
function(d) {
return (d.eyhigh > 0); })
2276 .attr(
"y1",
function(d) {
return d.gry2; })
2278 .attr(
"y2",
function(d) {
return d.gry2; })
2279 .style(
"stroke", this.lineatt.color)
2280 .style(
"stroke-width", this.lineatt.width);
2283 if (this.showMarker) {
2285 var marker = JSROOT.Painter.createAttMarker(this.graph);
2287 nodes.append(
"svg:path").call(marker.func);
2291 JSROOT.TGraphPainter.prototype.UpdateObject =
function(obj) {
2292 if (obj[
'_typename'] != this.graph[
'_typename'])
2297 this.main_painter().UpdateObject(obj[
'fHistogram']);
2300 this.graph[
'fX'] = obj[
'fX'];
2301 this.graph[
'fY'] = obj[
'fY'];
2302 this.graph[
'fNpoints'] = obj[
'fNpoints'];
2307 JSROOT.Painter.drawGraph =
function(divid, graph, opt) {
2309 var painter =
new JSROOT.TGraphPainter(graph);
2310 painter.SetDivId(divid, -1);
2312 if (painter.main_painter() == null) {
2313 if (graph[
'fHistogram']==null) {
2314 alert(
"drawing first graph without fHistogram field, not (yet) supported");
2317 JSROOT.Painter.drawHistogram1D(divid, graph[
'fHistogram']);
2318 painter.ownhisto =
true;
2321 painter.SetDivId(divid);
2323 painter.DecodeOptions(opt);
2325 painter.CreateBins();
2334 JSROOT.TPavePainter =
function(pave) {
2335 JSROOT.TObjectPainter.call(
this, pave);
2336 this.pavetext = pave;
2337 this.Enabled =
true;
2340 JSROOT.TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2342 JSROOT.TPavePainter.prototype.GetObject =
function() {
2343 return this.pavetext;
2346 JSROOT.TPavePainter.prototype.DrawPaveText =
function() {
2347 var pavetext = this.pavetext;
2349 var w = Number(this.svg_pad(
true).attr(
"width")),
2350 h = Number(this.svg_pad(
true).attr(
"height"));
2352 var pos_x = Math.round(pavetext[
'fX1NDC'] * w);
2354 var pos_y = Math.round((1.0 - pavetext[
'fY1NDC']) * h);
2355 var width = Math.round(Math.abs(pavetext[
'fX2NDC'] - pavetext[
'fX1NDC']) * w);
2356 var height = Math.round(Math.abs(pavetext[
'fY2NDC'] - pavetext[
'fY1NDC']) * h);
2358 var nlines = pavetext[
'fLines'].arr.length;
2359 var tcolor = JSROOT.Painter.root_colors[pavetext[
'fTextColor']];
2360 var scolor = JSROOT.Painter.root_colors[pavetext[
'fShadowColor']];
2361 var fcolor = this.createAttFill(pavetext);
2367 var align =
'start', halign = Math.round(pavetext[
'fTextAlign'] / 10);
2368 var baseline =
'bottom', valign = pavetext[
'fTextAlign'] % 10;
2369 if (halign == 1) align =
'start';
2370 else if (halign == 2) align =
'middle';
2371 else if (halign == 3) align =
'end';
2372 if (valign == 1) baseline =
'bottom';
2373 else if (valign == 2) baseline =
'middle';
2374 else if (valign == 3) baseline =
'top';
2376 var h_margin = Math.round(pavetext[
'fMargin'] * width);
2378 var font = JSROOT.Painter.getFontDetails(pavetext[
'fTextFont'], height / (nlines * 1.2));
2380 var lwidth = pavetext[
'fBorderSize'] ? pavetext[
'fBorderSize'] : 0;
2381 var attline = JSROOT.Painter.createAttLine(pavetext, lwidth>0 ? 1 : 0);
2383 var first_stat = 0, num_cols = 0, maxlw = 0;
2384 var lines =
new Array;
2387 for (var j = 0; j < nlines; ++j) {
2388 var line = JSROOT.Painter.translateLaTeX(pavetext[
'fLines'].arr[j][
'fTitle']);
2390 var lw = h_margin + font.stringWidth(this.svg_pad(
true), line) + h_margin;
2391 if (lw > maxlw) maxlw = lw;
2392 if ((j == 0) || (line.indexOf(
'|') < 0))
continue;
2393 if (first_stat === 0) first_stat = j;
2394 var parts = line.split(
"|");
2395 if (parts.length > num_cols)
2396 num_cols = parts.length;
2400 font.size = Math.floor(font.size * (width / maxlw));
2402 if ((nlines==1) && (lwidth==0) && (maxlw < width - 40)) {
2404 var diff = width - maxlw;
2407 pavetext[
'fX1NDC'] = pos_x / w;
2408 pavetext[
'fX2NDC'] = (pos_x + width) / w;
2411 var h_margin = Math.round(pavetext[
'fMargin'] * width);
2412 var text_pos_x = h_margin / 2;
2415 case 1: text_pos_x = h_margin;
break;
2416 case 2: text_pos_x = width / 2;
break;
2417 case 3: text_pos_x = width - h_margin;
break;
2423 this.RecreateDrawG(
true,
".stat_layer");
2429 .attr(
"width", width)
2430 .attr(
"height", height)
2431 .attr(
"transform",
"translate(" + pos_x +
"," + pos_y +
")");
2433 this.draw_g.append(
"rect")
2436 .attr(
"width", width)
2437 .attr(
"height", height)
2439 .call(attline.func);
2442 var stepy = (height - 0.2*font.size) / nlines;
2445 this.draw_g.append(
"text")
2446 .attr(
"text-anchor", align)
2447 .attr(
"x", text_pos_x)
2448 .attr(
"y", ((height / 2) + (font.size / 3)).toFixed(1))
2450 .attr(
"fill", tcolor)
2454 for (var j = 0; j < nlines; ++j) {
2455 var jcolor = JSROOT.Painter.root_colors[pavetext[
'fLines'].arr[j][
'fTextColor']];
2456 if (pavetext[
'fLines'].arr[j][
'fTextColor'] == 0) jcolor = tcolor;
2457 var posy = (j+0.5)*stepy + font.size*0.5 - 1;
2459 if (pavetext[
'_typename'] ==
'TPaveStats') {
2460 if ((first_stat > 0) && (j >= first_stat)) {
2461 var parts = lines[j].split(
"|");
2462 for (var n = 0; n < parts.length; n++)
2463 this.draw_g.append(
"text")
2464 .attr(
"text-anchor",
"middle")
2465 .attr(
"x", (width * (n + 0.5) / num_cols).toFixed(1))
2466 .attr(
"y", posy.toFixed(1))
2468 .attr(
"fill", jcolor)
2470 }
else if ((j == 0) || (lines[j].indexOf(
'=') < 0)) {
2471 this.draw_g.append(
"text")
2472 .attr(
"text-anchor", (j == 0) ?
"middle" :
"start")
2473 .attr(
"x", ((j == 0) ? width / 2 : pavetext[
'fMargin'] * width).toFixed(1))
2474 .attr(
"y", posy.toFixed(1))
2476 .attr(
"fill", jcolor)
2479 var parts = lines[j].split(
"=");
2480 for (var n = 0; n < 2; n++)
2481 this.draw_g.append(
"text")
2482 .attr(
"text-anchor", (n == 0) ?
"start" :
"end")
2483 .attr(
"x", ((n == 0) ? pavetext[
'fMargin'] * width : (1 - pavetext[
'fMargin']) * width).toFixed(1))
2484 .attr(
"y", posy.toFixed(1))
2486 .attr(
"fill", jcolor)
2490 this.draw_g.append(
"text")
2491 .attr(
"text-anchor",
"start")
2492 .attr(
"x", text_pos_x.toFixed(1))
2493 .attr(
"y", posy.toFixed(1))
2495 .attr(
"fill", jcolor)
2501 if (pavetext[
'fBorderSize'] && (pavetext[
'_typename'] ==
'TPaveStats')) {
2502 this.draw_g.append(
"svg:line")
2503 .attr(
"class",
"pavedraw")
2508 .call(attline.func);
2511 if ((first_stat > 0) && (num_cols > 1)) {
2512 for (var nrow = first_stat; nrow < nlines; nrow++)
2513 this.draw_g.append(
"svg:line")
2515 .attr(
"y1", nrow * stepy)
2517 .attr(
"y2", nrow * stepy)
2518 .call(attline.func);
2520 for (var ncol = 0; ncol < num_cols - 1; ncol++)
2521 this.draw_g.append(
"svg:line")
2522 .attr(
"x1", width / num_cols * (ncol + 1))
2523 .attr(
"y1", first_stat * stepy)
2524 .attr(
"x2", width / num_cols * (ncol + 1))
2526 .call(attline.func);
2529 if (lwidth && lwidth > 1) {
2530 this.draw_g.append(
"svg:line")
2531 .attr(
"x1", width + (lwidth / 2))
2532 .attr(
"y1", lwidth + 1)
2533 .attr(
"x2", width + (lwidth / 2))
2534 .attr(
"y2", height + lwidth - 1)
2535 .style(
"stroke", attline.color)
2536 .style(
"stroke-width", lwidth);
2537 this.draw_g.append(
"svg:line")
2538 .attr(
"x1", lwidth + 1)
2539 .attr(
"y1", height + (lwidth / 2))
2540 .attr(
"x2", width + lwidth - 1)
2541 .attr(
"y2", height + (lwidth / 2))
2542 .style(
"stroke", attline.color)
2543 .style(
"stroke-width", lwidth);
2546 this.AddDrag(
"stat", this.draw_g, {
2547 move :
function(x, y, dx, dy) {
2548 pthis.draw_g.attr(
"transform",
"translate(" + x +
"," + y +
")");
2550 pthis.pavetext[
'fX1NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
2551 pthis.pavetext[
'fX2NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
2552 pthis.pavetext[
'fY1NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
2553 pthis.pavetext[
'fY2NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
2555 resize :
function(width, height) {
2556 pthis.pavetext[
'fX2NDC'] = pthis.pavetext[
'fX1NDC'] + width / Number(pthis.svg_pad(
true).attr(
"width"));
2557 pthis.pavetext[
'fY1NDC'] = pthis.pavetext[
'fY2NDC'] - height / Number(pthis.svg_pad(
true).attr(
"height"));
2559 pthis.DrawPaveText();
2564 JSROOT.TPavePainter.prototype.AddLine =
function(txt) {
2565 this.pavetext.AddText(txt);
2569 JSROOT.TPavePainter.prototype.IsStats =
function() {
2570 if (!this.pavetext)
return false;
2571 return this.pavetext[
'fName'] ==
"stats";
2574 JSROOT.TPavePainter.prototype.FillStatistic =
function() {
2575 if (!this.IsStats())
return;
2577 var dostat =
new Number(this.pavetext[
'fOptStat']);
2578 if (!dostat) dostat =
new Number(JSROOT.gStyle.OptStat);
2581 if (
'FillStatistic' in this.main_painter()) {
2584 this.pavetext[
'fLines'].arr.length = 0;
2586 this.main_painter().FillStatistic(
this, dostat);
2590 JSROOT.TPavePainter.prototype.UpdateObject =
function(obj) {
2591 if (obj._typename !=
'TPaveText')
return false;
2592 this.pavetext[
'fLines'] = JSROOT.clone(obj[
'fLines']);
2596 JSROOT.TPavePainter.prototype.Redraw =
function() {
2601 if (!this.Enabled) {
2602 this.RemoveDrag(
"stat");
2606 this.FillStatistic();
2608 this.DrawPaveText();
2611 JSROOT.Painter.drawPaveText =
function(divid, pavetext) {
2612 if (pavetext[
'fX1NDC'] < 0.0 || pavetext[
'fY1NDC'] < 0.0 ||
2613 pavetext[
'fX1NDC'] > 1.0 || pavetext[
'fY1NDC'] > 1.0)
2616 var painter =
new JSROOT.TPavePainter(pavetext);
2618 painter.SetDivId(divid);
2622 painter.FillStatistic();
2624 painter.DrawPaveText();
2631 JSROOT.TPadPainter =
function(pad, iscan) {
2632 JSROOT.TObjectPainter.call(
this, pad);
2633 if (this.obj_typename==
"") this.obj_typename = iscan ?
"TCanvas" :
"TPad";
2636 this.painters =
new Array;
2639 JSROOT.TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2641 JSROOT.TPadPainter.prototype.CreateCanvasSvg =
function(only_resize) {
2643 var render_to = $(
"#" + this.divid);
2645 var w = render_to.width(), h = render_to.height();
2650 svg = this.svg_canvas(
true);
2651 if ((svg.property(
'last_width') == w) && (svg.property(
'last_height') == h))
return false;
2660 if ((this.pad!=null) && (
'fCw' in this.pad) && (
'fCh' in this.pad) && (this.pad[
'fCw'] > 0)) {
2661 factor = this.pad[
'fCh'] / this.pad[
'fCw'];
2662 if ((factor < 0.1) || (factor > 10))
2668 render_to.height(h);
2673 if (this.pad &&
'fFillColor' in this.pad)
2674 fill = this.createAttFill(this.pad);
2676 fill = this.createAttFill(
'white');
2678 render_to.css(
"background-color", fill.color);
2680 svg = d3.select(
"#" + this.divid)
2682 .attr(
"class",
"root_canvas")
2683 .style(
"background-color", fill.color)
2684 .property(
'pad_painter',
this)
2685 .property(
'mainpainter', null)
2686 .property(
'current_pad',
"")
2688 svg.append(
"svg:g").attr(
"class",
"frame_layer");
2689 svg.append(
"svg:g").attr(
"class",
"text_layer");
2690 svg.append(
"svg:g").attr(
"class",
"stat_layer");
2694 svg.attr(
"width", w)
2696 .attr(
"viewBox",
"0 0 " + w +
" " + h)
2697 .property(
'last_width', w)
2698 .property(
'last_height', h);
2704 JSROOT.TPadPainter.prototype.CreatePadSvg =
function(only_resize) {
2705 var width = Number(this.svg_canvas(
true).attr(
"width")),
2706 height = Number(this.svg_canvas(
true).attr(
"height"));
2707 var x = Math.round(this.pad[
'fAbsXlowNDC'] * width);
2708 var y = Math.round(height - this.pad[
'fAbsYlowNDC'] * height);
2709 var w = Math.round(this.pad[
'fAbsWNDC'] * width);
2710 var h = Math.round(this.pad[
'fAbsHNDC'] * height);
2713 var fill = this.createAttFill(this.pad);
2714 var attline = JSROOT.Painter.createAttLine(this.pad)
2715 if (this.pad[
'fBorderMode'] == 0) attline.color =
'none';
2717 var svg_pad = null, svg_rect = null;
2720 svg_pad = this.svg_pad(
true);
2721 svg_rect = svg_pad.select(
".root_pad_border");
2723 svg_pad = this.svg_canvas(
true).append(
"g")
2724 .attr(
"class",
"root_pad")
2725 .attr(
"pad", this.pad[
'fName'])
2726 .property(
'pad_painter',
this)
2727 .property(
'mainpainter', null);
2728 svg_rect = svg_pad.append(
"svg:rect").attr(
"class",
"root_pad_border");
2729 svg_pad.append(
"svg:g").attr(
"class",
"frame_layer");
2730 svg_pad.append(
"svg:g").attr(
"class",
"text_layer");
2731 svg_pad.append(
"svg:g").attr(
"class",
"stat_layer");
2734 svg_pad.attr(
"width", w)
2736 .attr(
"viewBox", x +
" " + y +
" " + (x+w) +
" " + (y+h))
2737 .attr(
"transform",
"translate(" + x +
"," + y +
")");
2739 svg_rect.attr(
"x", 0)
2744 .call(attline.func);
2747 JSROOT.TPadPainter.prototype.CheckColors =
function(can) {
2748 if (can==null)
return;
2749 for (var i in can.fPrimitives.arr) {
2750 var obj = can.fPrimitives.arr[i];
2751 if (obj==null)
continue;
2752 if ((obj._typename==
"TObjArray") && (obj.name ==
"ListOfColors")) {
2753 JSROOT.Painter.adoptRootColors(obj);
2754 can.fPrimitives.arr.splice(i,1);
2755 can.fPrimitives.opt.splice(i,1);
2761 JSROOT.TPadPainter.prototype.DrawPrimitives =
function() {
2762 if (this.pad==null)
return;
2764 for (var i in this.pad.fPrimitives.arr) {
2765 var pp = JSROOT.draw(this.divid, this.pad.fPrimitives.arr[i],
this.pad.fPrimitives.opt[i]);
2766 if (pp) pp[
'_primitive'] =
true;
2770 JSROOT.TPadPainter.prototype.Redraw =
function(resize) {
2771 if (resize && !this.iscan) this.CreatePadSvg(
true);
2774 for (var i in this.painters)
2775 this.painters[i].Redraw(resize);
2779 JSROOT.TPadPainter.prototype.CheckCanvasResize =
function() {
2780 if (!this.iscan)
return;
2782 var changed = this.CreateCanvasSvg(
true);
2783 if (changed) this.Redraw(
true);
2787 JSROOT.TPadPainter.prototype.UpdateObject =
function(obj) {
2789 if ((obj == null) || !(
'fPrimitives' in obj))
return false;
2791 if (this.iscan) this.CheckColors(obj);
2793 if (obj.fPrimitives.arr.length !=
this.pad.fPrimitives.arr.length)
return false;
2795 var isany =
false, p = 0;
2797 for (var n in obj.fPrimitives.arr) {
2798 var sub = obj.fPrimitives.arr[n];
2800 while (p<this.painters.length) {
2801 var pp = this.painters[p++];
2802 if (!(
'_primitive' in pp))
continue;
2803 if (pp.UpdateObject(sub)) isany =
true;
2811 JSROOT.Painter.drawCanvas =
function(divid, can) {
2812 var painter =
new JSROOT.TPadPainter(can,
true);
2813 painter.SetDivId(divid, -1);
2814 painter.CreateCanvasSvg();
2815 painter.SetDivId(divid);
2818 JSROOT.Painter.drawFrame(divid, null);
2820 painter.CheckColors(can);
2821 painter.DrawPrimitives();
2827 JSROOT.Painter.drawPad =
function(divid, pad) {
2829 var painter =
new JSROOT.TPadPainter(pad,
false);
2830 painter.SetDivId(divid);
2832 painter.CreatePadSvg();
2834 painter.pad_name = pad[
'fName'];
2837 var prev_name = painter.svg_canvas()[
'current_pad'];
2838 painter.svg_canvas()[
'current_pad'] = pad[
'fName'];
2840 painter.DrawPrimitives();
2843 painter.svg_canvas()[
'current_pad'] = prev_name;
2850 JSROOT.TColzPalettePainter =
function(palette) {
2851 JSROOT.TObjectPainter.call(
this, palette);
2852 this.palette = palette;
2855 JSROOT.TColzPalettePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2857 JSROOT.TColzPalettePainter.prototype.GetObject =
function() {
2858 return this.palette;
2861 JSROOT.TColzPalettePainter.prototype.DrawPalette =
function() {
2862 var palette = this.palette;
2863 var axis = palette[
'fAxis'];
2865 var minbin = this.main_painter().minbin;
2866 var maxbin = this.main_painter().maxbin;
2867 var nbr1 = axis[
'fNdiv'] % 100;
2868 if (nbr1<=0) nbr1 = 8;
2870 var width = Number(this.svg_pad(
true).attr(
"width")),
2871 height = Number(this.svg_pad(
true).attr(
"height"));
2873 var s_height = Math.round(Math.abs(palette[
'fY2NDC'] - palette[
'fY1NDC']) * height);
2875 var axisOffset = axis[
'fLabelOffset'] * width;
2876 var tickSize = axis[
'fTickSize'] * width;
2878 var z = d3.scale.linear().clamp(
true).domain([ minbin, maxbin ]).range( [ s_height, 0 ]).nice();
2880 var labelfont = JSROOT.Painter.getFontDetails(axis[
'fLabelFont'], axis[
'fLabelSize'] * height);
2882 var pos_x = Math.round(palette[
'fX1NDC'] * width);
2883 var pos_y = Math.round(height*(1 - palette[
'fY1NDC']));
2885 var s_width = Math.round(Math.abs(palette[
'fX2NDC'] - palette[
'fX1NDC']) * width);
2889 this.RecreateDrawG(
true,
".text_layer");
2892 .attr(
"x", pos_x).attr(
"y", pos_y)
2893 .attr(
"width", s_width).attr(
"height", s_height)
2894 .attr(
"transform",
"translate(" + pos_x +
", " + pos_y +
")");
2896 var paletteColors = this.main_painter().paletteColors;
2899 var rectHeight = 1. * s_height / paletteColors.length;
2901 this.draw_g.selectAll(
"colorRect")
2902 .data(paletteColors)
2905 .attr(
"class",
"colorRect")
2907 .attr(
"y",
function(d, i) {
return (s_height - (i + 1) * rectHeight).toFixed(1); })
2908 .attr(
"width", s_width)
2909 .attr(
"height", rectHeight.toFixed(1))
2910 .attr(
"fill",
function(d) {
return d; })
2911 .attr(
"stroke",
function(d) {
return d; });
2917 var z_axis = d3.svg.axis().scale(z)
2919 .tickPadding(axisOffset)
2920 .tickSize(-tickSize, -tickSize / 2, 0)
2923 var zax = this.draw_g.append(
"svg:g")
2924 .attr(
"class",
"zaxis")
2925 .attr(
"transform",
"translate(" + s_width +
", 0)")
2928 zax.selectAll(
"text")
2929 .call(labelfont.func)
2930 .attr(
"fill", JSROOT.Painter.root_colors[axis[
'fLabelColor']]);
2935 var title = axis[
'fTitle'];
2936 if (title !=
"" && typeof (axis[
'fTitleFont']) !=
'undefined') {
2937 var titlefont = JSROOT.Painter.getFontDetails(axis[
'fTitleFont'], axis[
'fTitleSize'] * height);
2938 this.draw_g.append(
"text")
2939 .attr(
"class",
"Z axis label")
2940 .attr(
"x", s_width + labelfont.size)
2941 .attr(
"y", s_height)
2942 .attr(
"text-anchor",
"end")
2943 .call(titlefont.func);
2948 this.AddDrag(
"colz", this.draw_g, {
2949 move :
function(x, y, dx, dy) {
2951 pthis.draw_g.attr(
"transform",
"translate(" + x +
"," + y +
")");
2953 pthis.palette[
'fX1NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
2954 pthis.palette[
'fX2NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
2955 pthis.palette[
'fY1NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
2956 pthis.palette[
'fY2NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
2958 resize :
function(width, height) {
2959 pthis.palette[
'fX2NDC'] = pthis.palette[
'fX1NDC'] + width / Number(pthis.svg_pad(
true).attr(
"width"));
2960 pthis.palette[
'fY1NDC'] = pthis.palette[
'fY2NDC'] - height / Number(pthis.svg_pad(
true).attr(
"height"));
2962 pthis.RemoveDrawG();
2963 pthis.DrawPalette();
2968 JSROOT.TColzPalettePainter.prototype.Redraw =
function() {
2972 if (
'options' in this.main_painter())
2973 enabled = (this.main_painter().options.Zscale > 0) && (this.main_painter().options.Color > 0);
2980 this.RemoveDrag(
"colz");
2984 JSROOT.Painter.drawPaletteAxis =
function(divid, palette) {
2985 var painter =
new JSROOT.TColzPalettePainter(palette);
2987 painter.SetDivId(divid);
2989 painter.DrawPalette();
2996 JSROOT.THistPainter =
function(histo) {
2997 JSROOT.TObjectPainter.call(
this, histo);
2999 this.shrink_frame_left = 0.;
3000 this.draw_content =
true;
3005 JSROOT.THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
3007 JSROOT.THistPainter.prototype.GetObject =
function() {
3011 JSROOT.THistPainter.prototype.IsTProfile =
function() {
3012 return this.histo && this.histo[
'_typename'] ==
'TProfile';
3015 JSROOT.THistPainter.prototype.IsTH2Poly =
function() {
3016 return this.histo && this.histo[
'_typename'].match(/^TH2Poly/);
3019 JSROOT.THistPainter.prototype.Dimension =
function() {
3020 if (!this.histo)
return 0;
3021 if (
'fDimension' in this.histo)
return this.histo[
'fDimension'];
3022 if (this.histo[
'_typename'].match(/^TH2/))
return 2;
3023 if (this.histo[
'_typename'].match(/^TH3/))
return 3;
3027 JSROOT.THistPainter.prototype.DecodeOptions =
function(opt) {
3028 if ((opt == null) || (opt ==
"")) opt = this.histo[
'fOption'];
3031 var hdim = this.Dimension();
3032 var nch = opt.length;
3034 Axis: 0, Bar: 0, Curve: 0, Error: 0, Hist: 0, Line: 0,
3035 Mark: 0, Fill: 0, Same: 0, Scat: 0, Func: 0, Star: 0,
3036 Arrow: 0, Box: 0, Text: 0, Char: 0, Color: 0, Contour: 0,
3037 Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0,
3038 Spec: 0, Pie: 0, List: 0, Zscale: 0, FrontBox: 1, BackBox: 1,
3039 System: JSROOT.Painter.Coord.kCARTESIAN,
3040 HighRes: 0, Zero: 0, Logx: 0, Logy: 0, Logz: 0, Gridx: 0, Gridy: 0
3043 var chopt = opt.toUpperCase();
3044 chopt = JSROOT.Painter.clearCuts(chopt);
3045 if (hdim > 1) option.Scat = 1;
3046 if (!nch) option.Hist = 1;
3047 if (this.IsTProfile()) option.Error = 2;
3048 if (
'fFunctions' in this.histo) option.Func = 1;
3050 if (chopt.indexOf(
'LOGX') != -1) {
3052 chopt = chopt.replace(
'LOGX',
'');
3054 if (chopt.indexOf(
'LOGY') != -1) {
3056 chopt = chopt.replace(
'LOGY',
'');
3059 var l = chopt.indexOf(
'SPEC');
3062 chopt = chopt.replace(
'SPEC',
' ');
3064 l = chopt.indexOf(
'BF(');
3065 if (l != -1) bs = parseInt(chopt)
3066 option.Spec = Math.max(1600, bs);
3069 if (chopt.indexOf('GL') != -1) chopt = chopt.replace('GL', ' ');
3070 if (chopt.indexOf('X+') != -1) {
3071 option.AxisPos = 10;
3072 chopt = chopt.replace(
'X+',
' ');
3074 if (chopt.indexOf(
'Y+') != -1) {
3075 option.AxisPos += 1;
3076 chopt = chopt.replace(
'Y+',
' ');
3078 if ((option.AxisPos == 10 || option.AxisPos == 1) && (nch == 2))
3080 if (option.AxisPos == 11 && nch == 4)
3082 if (chopt.indexOf(
'SAMES') != -1) {
3083 if (nch == 5) option.Hist = 1;
3085 chopt = chopt.replace(
'SAMES',
' ');
3087 if (chopt.indexOf(
'SAME') != -1) {
3088 if (nch == 4) option.Hist = 1;
3090 chopt = chopt.replace(
'SAME',
' ');
3092 if (chopt.indexOf(
'PIE') != -1) {
3094 chopt = chopt.replace(
'PIE',
' ');
3096 l = chopt.indexOf(
'LEGO');
3100 chopt = chopt.replace(
'LEGO',
' ');
3101 if (chopt[l + 4] ==
'1') {
3105 if (chopt[l + 4] ==
'2') {
3109 if (chopt[l + 4] ==
'3') {
3113 l = chopt.indexOf(
'FB');
3115 option.FrontBox = 0;
3116 chopt = chopt.replace(
'FB',
' ');
3118 l = chopt.indexOf(
'BB');
3121 chopt = chopt.replace(
'BB',
' ');
3123 l = chopt.indexOf(
'0');
3126 chopt = chopt.replace(
'0',
' ');
3129 l = chopt.indexOf(
'SURF');
3133 chopt = chopt.replace(
'SURF',
' ');
3134 if (chopt[l + 4] ==
'1') {
3138 if (chopt[l + 4] ==
'2') {
3142 if (chopt[l + 4] ==
'3') {
3146 if (chopt[l + 4] ==
'4') {
3150 if (chopt[l + 4] ==
'5') {
3154 if (chopt[l + 4] ==
'6') {
3158 if (chopt[l + 4] ==
'7') {
3162 l = chopt.indexOf(
'FB');
3164 option.FrontBox = 0;
3165 chopt = chopt.replace(
'FB',
' ');
3167 l = chopt.indexOf(
'BB');
3170 chopt = chopt.replace(
'BB',
' ');
3173 l = chopt.indexOf(
'TF3');
3175 l = chopt.indexOf(
'FB');
3177 option.FrontBox = 0;
3178 chopt = chopt.replace(
'FB',
' ');
3180 l = chopt.indexOf(
'BB');
3183 chopt = chopt.replace(
'BB',
' ');
3186 l = chopt.indexOf(
'ISO');
3188 l = chopt.indexOf(
'FB');
3190 option.FrontBox = 0;
3191 chopt = chopt.replace(
'FB',
' ');
3193 l = chopt.indexOf(
'BB');
3196 chopt = chopt.replace(
'BB',
' ');
3199 l = chopt.indexOf(
'LIST');
3202 chopt = chopt.replace(
'LIST',
' ');
3204 l = chopt.indexOf(
'CONT');
3206 chopt = chopt.replace(
'CONT',
' ');
3210 if (chopt[l + 4] ==
'1') {
3211 option.Contour = 11;
3214 if (chopt[l + 4] ==
'2') {
3215 option.Contour = 12;
3218 if (chopt[l + 4] ==
'3') {
3219 option.Contour = 13;
3222 if (chopt[l + 4] ==
'4') {
3223 option.Contour = 14;
3226 if (chopt[l + 4] ==
'5') {
3227 option.Contour = 15;
3234 l = chopt.indexOf(
'HBAR');
3238 chopt = chopt.replace(
'HBAR',
' ');
3239 if (chopt[l + 4] ==
'1') {
3243 if (chopt[l + 4] ==
'2') {
3247 if (chopt[l + 4] ==
'3') {
3251 if (chopt[l + 4] ==
'4') {
3256 l = chopt.indexOf(
'BAR');
3260 chopt = chopt.replace(
'BAR',
' ');
3261 if (chopt[l + 3] ==
'1') {
3265 if (chopt[l + 3] ==
'2') {
3269 if (chopt[l + 3] ==
'3') {
3273 if (chopt[l + 3] ==
'4') {
3278 l = chopt.indexOf(
'ARR');
3280 chopt = chopt.replace(
'ARR',
' ');
3288 l = chopt.indexOf(
'BOX');
3290 chopt = chopt.replace(
'BOX',
' ');
3294 if (chopt[l + 3] ==
'1') {
3303 l = chopt.indexOf(
'COL');
3307 if (chopt.charAt(l+3)==
'1') { option.Color = 1; name +=
"1"; l++; }
else
3308 if (chopt.charAt(l+3)==
'2') { option.Color = 2; name +=
"2"; l++; }
else
3309 if (chopt.charAt(l+3)==
'3') { option.Color = 3; name +=
"3"; l++; }
else
3310 option.Color = JSROOT.gStyle.DefaultCol;
3312 if (chopt.charAt(l+4)==
'Z') { option.Zscale = 1; name +=
'Z'; }
3313 chopt = chopt.replace(name,
'');
3321 if (chopt.indexOf(
'CHAR') != -1) {
3323 chopt = chopt.replace(
'CHAR',
' ');
3326 l = chopt.indexOf(
'FUNC');
3329 chopt = chopt.replace(
'FUNC',
' ');
3332 l = chopt.indexOf(
'HIST');
3335 chopt = chopt.replace(
'HIST',
' ');
3339 if (chopt.indexOf(
'AXIS') != -1) {
3341 chopt = chopt.replace(
'AXIS',
' ');
3343 if (chopt.indexOf(
'AXIG') != -1) {
3345 chopt = chopt.replace(
'AXIG',
' ');
3347 if (chopt.indexOf(
'SCAT') != -1) {
3349 chopt = chopt.replace(
'SCAT',
' ');
3351 l = chopt.indexOf(
'TEXT');
3353 var angle = parseInt(chopt);
3354 if (!isNaN(angle)) {
3359 option.Text = 1000 + angle;
3363 chopt = chopt.replace(
'TEXT',
' ');
3364 l = chopt.indexOf(
'N');
3365 if (l != -1 && this.IsTH2Poly())
3366 option.Text += 3000;
3369 if (chopt.indexOf(
'POL') != -1) {
3370 option.System = JSROOT.Painter.Coord.kPOLAR;
3371 chopt = chopt.replace(
'POL',
' ');
3373 if (chopt.indexOf(
'CYL') != -1) {
3374 option.System = JSROOT.Painter.Coord.kCYLINDRICAL;
3375 chopt = chopt.replace(
'CYL',
' ');
3377 if (chopt.indexOf(
'SPH') != -1) {
3378 option.System = JSROOT.Painter.Coord.kSPHERICAL;
3379 chopt = chopt.replace(
'SPH',
' ');
3381 l = chopt.indexOf(
'PSR');
3383 option.System = JSROOT.Painter.Coord.kRAPIDITY;
3384 chopt = chopt.replace(
'PSR',
' ');
3386 l = chopt.indexOf(
'TRI');
3391 chopt = chopt.replace(
'TRI',
' ');
3392 l = chopt.indexOf(
'FB');
3394 option.FrontBox = 0;
3395 chopt = chopt.replace(
'FB',
' ');
3397 l = chopt.indexOf(
'BB');
3400 chopt = chopt.replace(
'BB',
' ');
3402 l = chopt.indexOf(
'ERR');
3404 chopt = chopt.replace(
'ERR',
' ');
3406 l = chopt.indexOf(
'AITOFF');
3409 chopt = chopt.replace(
'AITOFF',
' ');
3411 l = chopt.indexOf(
'MERCATOR');
3414 chopt = chopt.replace(
'MERCATOR',
' ');
3416 l = chopt.indexOf(
'SINUSOIDAL');
3419 chopt = chopt.replace(
'SINUSOIDAL',
' ');
3422 l = chopt.indexOf(
'PARABOLIC');
3425 chopt = chopt.replace(
'PARABOLIC',
' ');
3428 if (option.Proj > 0) {
3430 option.Contour = 14;
3432 if (chopt.indexOf(
'A') != -1)
3434 if (chopt.indexOf(
'B') != -1)
3436 if (chopt.indexOf(
'C') != -1) {
3440 if (chopt.indexOf(
'F') != -1)
3442 if (chopt.indexOf(
'][') != -1) {
3446 if (chopt.indexOf(
'F2') != -1) option.Fill = 2;
3447 if (chopt.indexOf(
'L') != -1) {
3451 if (chopt.indexOf(
'P') != -1) {
3455 if (chopt.indexOf(
'Z') != -1) option.Zscale = 1;
3456 if (chopt.indexOf(
'*') != -1) option.Star = 1;
3457 if (chopt.indexOf(
'H') != -1) option.Hist = 2;
3458 if (chopt.indexOf(
'P0') != -1) option.Mark = 10;
3459 if (this.IsTH2Poly()) {
3460 if (option.Fill + option.Line + option.Mark != 0) option.Scat = 0;
3463 if (chopt.indexOf(
'E') != -1) {
3466 if (chopt.indexOf(
'E0') != -1) option.Error = 10;
3467 if (chopt.indexOf(
'E1') != -1) option.Error = 11;
3468 if (chopt.indexOf(
'E2') != -1) option.Error = 12;
3469 if (chopt.indexOf(
'E3') != -1) option.Error = 13;
3470 if (chopt.indexOf(
'E4') != -1) option.Error = 14;
3471 if (chopt.indexOf(
'E5') != -1) option.Error = 15;
3472 if (chopt.indexOf(
'E6') != -1) option.Error = 16;
3473 if (chopt.indexOf(
'X0') != -1) {
3474 if (option.Error == 1) option.Error += 20;
3477 if (option.Text &&
this.IsTProfile()) {
3478 option.Text += 2000;
3482 if (option.Error == 0) {
3487 option.Text += 2000;
3492 if (chopt.indexOf(
'9') != -1) option.HighRes = 1;
3493 if (option.Surf == 15) {
3494 if (option.System == JSROOT.Painter.Coord.kPOLAR
3495 || option.System == JSROOT.Painter.Coord.kCARTESIAN) {
3503 if (option.Bar == 1) option.Hist = -1;
3508 JSROOT.THistPainter.prototype.ScanContent =
function() {
3513 alert(
"HistPainter.prototype.ScanContent not implemented");
3516 JSROOT.THistPainter.prototype.CheckPadOptions =
function() {
3518 var pad = this.root_pad();
3522 this.options.Logx = pad[
'fLogx'];
3523 this.options.Logy = pad[
'fLogy'];
3524 this.options.Logz = pad[
'fLogz'];
3525 this.options.Gridx = pad[
'fGridx'];
3526 this.options.Gridy = pad[
'fGridy'];
3529 if (this.main_painter() !==
this)
return;
3531 this[
'zoom_xmin'] = 0;
3532 this[
'zoom_xmax'] = 0;
3533 this[
'zoom_xpad'] =
true;
3535 this[
'zoom_ymin'] = 0;
3536 this[
'zoom_ymax'] = 0;
3537 this[
'zoom_ypad'] =
true;
3539 if ((pad!=null) && (
'fUxmin' in pad) && !this.create_canvas) {
3540 this[
'zoom_xmin'] = pad.fUxmin;
3541 this[
'zoom_xmax'] = pad.fUxmax;
3542 this[
'zoom_ymin'] = pad.fUymin;
3543 this[
'zoom_ymax'] = pad.fUymax;
3545 if (pad.fLogx > 0) {
3546 this[
'zoom_xmin'] = Math.exp(
this[
'zoom_xmin'] * Math.log(10));
3547 this[
'zoom_xmax'] = Math.exp(
this[
'zoom_xmax'] * Math.log(10));
3550 if (pad.fLogy > 0) {
3551 this[
'zoom_ymin'] = Math.exp(
this[
'zoom_ymin'] * Math.log(10));
3552 this[
'zoom_ymax'] = Math.exp(
this[
'zoom_ymax'] * Math.log(10));
3558 JSROOT.THistPainter.prototype.UpdateObject =
function(obj) {
3559 if (obj[
'_typename'] != this.histo[
'_typename']) {
3560 alert(
"JSROOT.THistPainter.UpdateObject - wrong class " + obj[
'_typename'] +
" expected " + this.histo[
'_typename']);
3571 this.histo[
'fArray'] = obj[
'fArray'];
3572 this.histo[
'fN'] = obj[
'fN'];
3573 this.histo[
'fTitle'] = obj[
'fTitle'];
3574 this.histo[
'fXaxis'][
'fNbins'] = obj[
'fXaxis'][
'fNbins'];
3575 this.histo[
'fXaxis'][
'fXmin'] = obj[
'fXaxis'][
'fXmin'];
3576 this.histo[
'fXaxis'][
'fXmax'] = obj[
'fXaxis'][
'fXmax'];
3577 this.histo[
'fYaxis'][
'fXmin'] = obj[
'fYaxis'][
'fXmin'];
3578 this.histo[
'fYaxis'][
'fXmax'] = obj[
'fYaxis'][
'fXmax'];
3580 if (this.IsTProfile()) {
3581 this.histo[
'fBinEntries'] = obj[
'fBinEntries'];
3582 this.histo[
'fSumw2'] = obj[
'fSumw2'];
3590 JSROOT.THistPainter.prototype.CreateXY =
function() {
3594 if (!this.is_main_painter()) {
3595 this[
'x'] = this.main_painter()[
'x'];
3596 this[
'y'] = this.main_painter()[
'y'];
3600 var w = Number(this.svg_frame(
true).attr(
"width")),
3601 h = Number(this.svg_frame(
true).attr(
"height"));
3603 this[
'scale_xmin'] = this.xmin;
3604 this[
'scale_xmax'] = this.xmax;
3605 if (this.zoom_xmin != this.zoom_xmax) {
3606 this[
'scale_xmin'] = this.zoom_xmin;
3607 this[
'scale_xmax'] = this.zoom_xmax;
3610 if (this.options.Logx) {
3611 if (this.scale_xmax <= 0) this.scale_xmax = 0;
3613 if ((this.scale_xmin <= 0) && (this.nbinsx>0))
3614 for (var i=0;i<this.nbinsx;i++) {
3615 var left = this.xmin + i*this.binwidthx;
3616 if (left>0) { this.scale_xmin = left;
break; }
3619 if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) {
3620 this.scale_xmin = this.scale_xmax * 0.0001;
3623 this[
'x'] = d3.scale.log().domain([ this.scale_xmin, this.scale_xmax ]).range([ 0, w ]);
3625 this[
'x'] = d3.scale.linear().domain([ this.scale_xmin, this.scale_xmax ]).range([ 0, w ]);
3628 this[
'scale_ymin'] = this.ymin;
3629 this[
'scale_ymax'] = this.ymax;
3631 if (this.zoom_ypad) {
3632 if (this.histo.fMinimum != -1111) this.zoom_ymin = this.histo.fMinimum;
3633 if (this.histo.fMaximum != -1111) this.zoom_ymax = this.histo.fMaximum;
3634 this[
'zoom_ypad'] =
false;
3637 if (this.zoom_ymin != this.zoom_ymax) {
3638 this[
'scale_ymin'] = this.zoom_ymin;
3639 this[
'scale_ymax'] = this.zoom_ymax;
3642 if (this.options.Logy) {
3643 if (this.scale_ymax <= 0) this.scale_ymax = 1;
3645 if ((this.scale_ymin <= 0) && (this.nbinsy>0))
3646 for (var i=0;i<this.nbinsy;i++) {
3647 var down = this.ymin + i*this.binwidthy;
3648 if (down>0) { this.scale_ymin = down;
break; }
3651 if ((this.scale_ymin <= 0) && (
'ymin_nz' in
this) && (this.ymin_nz > 0))
3652 this.scale_ymin = 0.3*this.ymin_nz;
3654 if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax))
3655 this.scale_ymin = 0.000001 * this.scale_ymax;
3656 this[
'y'] = d3.scale.log().domain([ this.scale_ymin, this.scale_ymax ]).range([ h, 0 ]);
3658 this[
'y'] = d3.scale.linear().domain([ this.scale_ymin, this.scale_ymax ]).range([ h, 0 ]);
3662 JSROOT.THistPainter.prototype.DrawGrids =
function() {
3664 if (!this.is_main_painter())
return;
3666 var layer = this.svg_frame(
true).select(
".grid_layer");
3668 layer.selectAll(
".xgrid").remove();
3669 layer.selectAll(
".ygrid").remove();
3673 if (this.options.Gridx) {
3675 var h = Number(this.svg_frame(
true).attr(
"height"));
3677 var xticks = this.x.ticks(this.x_nticks);
3679 layer.selectAll(
".xgrid")
3680 .data(xticks).enter()
3682 .attr(
"class",
"xgrid")
3687 .style(
"stroke",
"black")
3688 .style(
"stroke-width", 1)
3689 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
3693 if (this.options.Gridy) {
3694 var w = Number(this.svg_frame(
true).attr(
"width"));
3696 var yticks = this.y.ticks(this.y_nticks);
3698 layer.selectAll(
'.ygrid')
3699 .data(yticks).enter()
3701 .attr(
"class",
"ygrid")
3706 .style(
"stroke",
"black")
3707 .style(
"stroke-width", 1)
3708 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
3712 JSROOT.THistPainter.prototype.DrawBins =
function() {
3713 alert(
"HistPainter.DrawBins not implemented");
3716 JSROOT.THistPainter.prototype.AxisAsText =
function(axis, value) {
3719 if (
'dfx' in
this) {
3720 return this.dfx(
new Date(this.timeoffsetx + value * 1000));
3723 if (Math.abs(value) < 1e-14)
3724 if (Math.abs(
this.xmax -
this.xmin) > 1e-5)
3726 return value.toPrecision(4);
3730 if (
'dfy' in
this) {
3731 return this.dfy(
new Date(this.timeoffsety + value * 1000));
3733 if (Math.abs(value) < 1e-14)
3734 if (Math.abs(
this.ymax -
this.ymin) > 1e-5)
3736 return value.toPrecision(4);
3739 return value.toPrecision(4);
3742 JSROOT.THistPainter.prototype.DrawAxes =
function(shrink_forbidden) {
3745 if (!this.is_main_painter())
return;
3747 var w = Number(this.svg_frame(
true).attr(
"width")),
3748 h = Number(this.svg_frame(
true).attr(
"height"));
3749 var noexpx = this.histo[
'fXaxis'].TestBit(JSROOT.EAxisBits.kNoExponent);
3750 var noexpy = this.histo[
'fYaxis'].TestBit(JSROOT.EAxisBits.kNoExponent);
3751 var moreloglabelsx = this.histo[
'fXaxis'].TestBit(JSROOT.EAxisBits.kMoreLogLabels);
3752 var moreloglabelsy = this.histo[
'fYaxis'].TestBit(JSROOT.EAxisBits.kMoreLogLabels);
3753 if (this.histo[
'fXaxis'][
'fXmax'] < 100 && this.histo[
'fXaxis'][
'fXmax'] / this.histo[
'fXaxis'][
'fXmin'] < 100) noexpx =
true;
3754 if (this.histo[
'fYaxis'][
'fXmax'] < 100 && this.histo[
'fYaxis'][
'fXmax'] / this.histo[
'fYaxis'][
'fXmin'] < 100) noexpy =
true;
3756 var xax_g = this.svg_frame(
true).selectAll(
".xaxis_container");
3758 xax_g = this.svg_frame(
true).select(
".axis_layer").append(
"svg:g").attr(
"class",
"xaxis_container");
3760 xax_g.selectAll(
"*").remove();
3761 xax_g.attr(
"transform",
"translate(0," + h +
")");
3763 var yax_g = this.svg_frame(
true).selectAll(
".yaxis_container");
3764 if (yax_g.empty()) yax_g = this.svg_frame(
true).select(
".axis_layer").append(
"svg:g").attr(
"class",
"yaxis_container");
3765 yax_g.selectAll(
"*").remove();
3767 var x_axis = null, y_axis = null;
3769 var ndivx = this.histo[
'fXaxis'][
'fNdivisions'];
3770 this[
'x_nticks'] = ndivx % 100;
3771 var n2ax = (ndivx % 10000 - this.x_nticks) / 100;
3772 var n3ax = ndivx / 10000;
3774 var ndivy = this.histo[
'fYaxis'][
'fNdivisions'];
3775 this[
'y_nticks'] = ndivy % 100;
3776 var n2ay = (ndivy % 10000 - this.y_nticks) / 100;
3777 var n3ay = ndivy / 10000;
3780 var label = JSROOT.Painter.translateLaTeX(this.histo[
'fXaxis'][
'fTitle']);
3781 var xAxisLabelOffset = 3 + (this.histo[
'fXaxis'][
'fLabelOffset'] * h);
3783 var xlabelfont = JSROOT.Painter.getFontDetails(this.histo[
'fXaxis'][
'fLabelFont'], this.histo[
'fXaxis'][
'fLabelSize'] * h);
3785 var ylabelfont = JSROOT.Painter.getFontDetails(this.histo[
'fYaxis'][
'fLabelFont'], this.histo[
'fYaxis'][
'fLabelSize'] * h);
3787 if (label.length > 0) {
3788 var xtitlefont = JSROOT.Painter.getFontDetails(this.histo[
'fXaxis'][
'fTitleFont'], this.histo[
'fXaxis'][
'fTitleSize'] * h);
3789 xax_g.append(
"text")
3790 .attr(
"class",
"x_axis_label")
3792 .attr(
"y", xlabelfont.size + xAxisLabelOffset *
this.histo[
'fXaxis'][
'fTitleOffset'] + xtitlefont.size)
3793 .attr(
"text-anchor",
"end")
3794 .call(xtitlefont.func)
3799 label = JSROOT.Painter.translateLaTeX(this.histo[
'fYaxis'][
'fTitle']);
3801 var yAxisLabelOffset = 3 + (this.histo[
'fYaxis'][
'fLabelOffset'] * w);
3803 if (label.length > 0) {
3804 var ytitlefont = JSROOT.Painter.getFontDetails(this.histo[
'fYaxis'][
'fTitleFont'], this.histo[
'fYaxis'][
'fTitleSize'] * h);
3805 yax_g.append(
"text")
3806 .attr(
"class",
"y_axis_label")
3808 .attr(
"y", - ylabelfont.size - ytitlefont.size - yAxisLabelOffset *
this.histo[
'fYaxis'][
'fTitleOffset'])
3809 .call(ytitlefont.func)
3810 .attr(
"text-anchor",
"end")
3812 .attr(
"transform",
"rotate(270, 0, 0)");
3815 var xAxisColor = this.histo[
'fXaxis'][
'fAxisColor'];
3816 var xDivLength = this.histo[
'fXaxis'][
'fTickLength'] * h;
3817 var yAxisColor = this.histo[
'fYaxis'][
'fAxisColor'];
3818 var yDivLength = this.histo[
'fYaxis'][
'fTickLength'] * w;
3825 var xrange = this.xmax - this.xmin;
3826 if (this.histo[
'fXaxis'][
'fTimeDisplay']) {
3827 if (this.x_nticks > 8) this.x_nticks = 8;
3829 var timeformatx = JSROOT.Painter.getTimeFormat(this.histo[
'fXaxis']);
3831 this[
'timeoffsetx'] = JSROOT.Painter.getTimeOffset(this.histo[
'fXaxis']);
3833 var scale_xrange = this.scale_xmax - this.scale_xmin;
3835 if ((timeformatx.length == 0) || (scale_xrange < 0.1 * xrange)) {
3836 timeformatx = JSROOT.Painter.chooseTimeFormat(scale_xrange, this.x_nticks);
3839 this[
'dfx'] = d3.time.format(timeformatx);
3841 x_axis = d3.svg.axis().scale(this.x).orient(
"bottom")
3842 .tickPadding(xAxisLabelOffset)
3843 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
3844 .tickFormat(
function(d) {
return pthis.dfx(
new Date(pthis.timeoffsetx + d * 1000)); })
3845 .ticks(this.x_nticks);
3846 }
else if (this.options.Logx) {
3847 x_axis = d3.svg.axis().scale(this.x).orient(
"bottom")
3848 .tickPadding(xAxisLabelOffset)
3849 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
3850 .tickFormat(
function(d) {
3851 var val = parseFloat(d);
3852 var vlog = Math.abs(JSROOT.Math.log10(val));
3853 if (moreloglabelsx) {
3854 if (vlog % 1 < 0.7 || vlog % 1 > 0.9999) {
3856 return val.toFixed();
3858 return JSROOT.Painter.formatExp(val.toExponential(0));
3862 if (vlog % 1 < 0.0001 || vlog % 1 > 0.9999) {
3864 return val.toFixed();
3866 return JSROOT.Painter.formatExp(val.toExponential(0));
3872 x_axis = d3.svg.axis()
3875 .tickPadding(xAxisLabelOffset)
3876 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
3877 .tickFormat(
function(d) {
3879 if ((Math.abs(d) < 1e-14) && (Math.abs(xrange) > 1e-5)) d = 0;
3880 return parseFloat(d.toPrecision(12)); })
3881 .ticks(this.x_nticks);
3884 var yrange = this.ymax - this.ymin;
3885 if (this.histo[
'fYaxis'][
'fTimeDisplay']) {
3886 if (this.y_nticks > 8) this.y_nticks = 8;
3887 var timeformaty = JSROOT.Painter.getTimeFormat(this.histo[
'fYaxis']);
3889 this[
'timeoffsety'] = JSROOT.Painter
3890 .getTimeOffset(this.histo[
'fYaxis']);
3892 var scale_yrange = this.scale_ymax - this.scale_ymin;
3894 if ((timeformaty.length == 0) || (scale_yrange < 0.1 * yrange))
3895 timeformaty = JSROOT.Painter.chooseTimeFormat(scale_yrange, this.y_nticks);
3897 this[
'dfy'] = d3.time.format(timeformaty);
3899 y_axis = d3.svg.axis()
3902 .tickPadding(yAxisLabelOffset)
3903 .tickSize(-yDivLength, -yDivLength / 2,-yDivLength / 4)
3904 .tickFormat(
function(d) {
return pthis.dfy(
new Date(pthis.timeoffsety + d * 1000)); })
3905 .ticks(this.y_nticks);
3906 }
else if (this.options.Logy) {
3907 y_axis = d3.svg.axis()
3910 .tickPadding(yAxisLabelOffset)
3911 .tickSize(-yDivLength, -yDivLength / 2, -yDivLength / 4)
3912 .tickFormat(
function(d) {
3913 var val = parseFloat(d);
3914 var vlog = Math.abs(JSROOT.Math.log10(val));
3915 if (moreloglabelsy) {
3916 if (vlog % 1 < 0.7 || vlog % 1 > 0.9999) {
3918 return val.toFixed();
3920 return JSROOT.Painter.formatExp(val.toExponential(0));
3924 if (vlog % 1 < 0.0001 || vlog % 1 > 0.9999) {
3926 return val.toFixed();
3928 return JSROOT.Painter.formatExp(val.toExponential(0));
3934 if (this.y_nticks >= 10) this.y_nticks -= 2;
3935 y_axis = d3.svg.axis()
3938 .tickPadding(yAxisLabelOffset)
3939 .tickSize(-yDivLength, -yDivLength / 2,-yDivLength / 4)
3940 .tickFormat(
function(d) {
3941 if ((Math.abs(d) < 1e-14) && (Math.abs(yrange) > 1e-5)) d = 0;
3942 return parseFloat(d.toPrecision(12)); })
3943 .ticks(this.y_nticks);
3946 xax_g.append(
"svg:g").attr(
"class",
"xaxis").call(x_axis);
3949 if ((n2ax > 0) && !this.options.Logx) {
3951 d3.svg.axis().scale(this.x).orient(
"bottom")
3952 .tickPadding(xAxisLabelOffset).innerTickSize(-xDivLength / 2)
3953 .tickFormat(
function(d) {
return; })
3954 .ticks(this.x.ticks(
this.x_nticks).length * n2ax);
3956 xax_g.append(
"svg:g").attr(
"class",
"xaxis").call(x_axis_sub);
3959 yax_g.append(
"svg:g").attr(
"class",
"yaxis").call(y_axis);
3962 if ((n2ay > 0) && !this.options.Logy) {
3963 var y_axis_sub = d3.svg.axis().scale(this.y).orient(
"left")
3964 .tickPadding(yAxisLabelOffset).innerTickSize(-yDivLength / 2)
3965 .tickFormat(
function(d) {
return; })
3966 .ticks(this.y.ticks(
this.y_nticks).length * n2ay);
3968 yax_g.append(
"svg:g").attr(
"class",
"yaxis").call(y_axis_sub);
3971 xax_g.selectAll(
"text").call(xlabelfont.func);
3973 yax_g.selectAll(
"text").call(ylabelfont.func);
3976 if (JSROOT.gStyle.Zooming) {
3977 xax_g.append(
"svg:rect")
3978 .attr(
"class",
"xaxis_zoom")
3982 .attr(
"height", xlabelfont.size + 3)
3983 .style(
'opacity',
"0");
3986 yax_g.append(
"svg:rect")
3987 .attr(
"class",
"yaxis_zoom")
3988 .attr(
"x",-2 * ylabelfont.size - 3)
3990 .attr(
"width", 2 * ylabelfont.size + 3)
3992 .style(
'opacity',
"0");
3995 if ((shrink_forbidden==null) && typeof yax_g.node()[
'getBoundingClientRect'] ==
'function') {
3997 var rect1 = yax_g.node().getBoundingClientRect();
3998 var rect2 = this.svg_pad().getBoundingClientRect();
3999 var position = rect1.left - rect2.left;
4004 shrink = -position/w + 0.001;
4005 this.shrink_frame_left += shrink;
4007 if ((this.shrink_frame_left > 0) && (position/w > this.shrink_frame_left)) {
4008 shrink = -this.shrink_frame_left;
4009 this.shrink_frame_left = 0.;
4013 this.svg_frame()[
'frame_painter'].Shrink(shrink, 0);
4014 this.svg_frame()[
'frame_painter'].Redraw();
4016 this.DrawAxes(
true);
4021 JSROOT.THistPainter.prototype.DrawTitle =
function() {
4023 var painter = this.FindPainterFor(null,
"title");
4025 if (painter!=null) {
4026 painter.pavetext.Clear();
4027 painter.pavetext.AddText(this.histo[
'fTitle']);
4030 var pavetext = JSROOT.Create(
"TPaveText");
4032 jQuery.extend(pavetext, { fName:
"title",
4033 fX1NDC: 0.2809483, fY1NDC: 0.9339831,
4034 fX2NDC: 0.7190517, fY2NDC: 0.995});
4035 pavetext.AddText(this.histo[
'fTitle']);
4037 painter = JSROOT.Painter.drawPaveText(this.divid, pavetext);
4041 JSROOT.THistPainter.prototype.ToggleStat =
function() {
4043 var stat = this.FindStat();
4048 stat = this.CreateStat();
4055 var statpainter = this.FindPainterFor(stat);
4056 if (statpainter == null) {
4057 alert(
"Did not found painter for existing stat??");
4061 statpainter.Enabled = !statpainter.Enabled;
4065 statpainter.Redraw();
4068 JSROOT.THistPainter.prototype.GetSelectIndex =
function(axis, size, add) {
4071 var obj = this.main_painter();
4072 if (obj == null) obj =
this;
4078 if (obj.zoom_xmin != obj.zoom_xmax) {
4080 indx = Math.floor((obj.zoom_xmin -
this.xmin) /
this.binwidthx + add);
4082 indx = Math.round((obj.zoom_xmax -
this.xmin) /
this.binwidthx + 0.5 + add);
4084 indx = (size ==
"left") ? 0 : nbin;
4090 if (obj.zoom_ymin != obj.zoom_ymax) {
4092 indx = Math.floor((obj.zoom_ymin -
this.ymin) /
this.binwidthy + add);
4094 indx = Math.round((obj.zoom_ymax -
this.ymin) /
this.binwidthy + 0.5 + add);
4096 indx = (size ==
"left") ? 0 : nbin;
4100 if (size ==
"left") {
4101 if (indx < 0) indx = 0;
4103 if (indx > nbin) indx = nbin;
4109 JSROOT.THistPainter.prototype.FindStat =
function() {
4111 if (
'fFunctions' in this.histo)
4112 for ( var i in this.histo.fFunctions.arr) {
4114 var func = this.histo.fFunctions.arr[i];
4116 if (func[
'_typename'] ==
'TPaveText' || func[
'_typename'] ==
'TPaveStats') {
4124 JSROOT.THistPainter.prototype.CreateStat =
function() {
4126 if (!this.draw_content)
return null;
4127 if (this.FindStat() != null)
return null;
4129 var stats = JSROOT.Create(
'TPaveStats');
4130 jQuery.extend(stats, { _AutoCreated:
true,
4132 fOptStat: JSROOT.gStyle.OptStat,
4134 jQuery.extend(stats, JSROOT.gStyle.StatNDC);
4135 jQuery.extend(stats, JSROOT.gStyle.StatText);
4136 jQuery.extend(stats, JSROOT.gStyle.StatFill);
4138 if (this.histo[
'_typename'] && (this.histo[
'_typename'].match(/^TProfile/) || this.histo[
'_typename'].match(/^TH2/)))
4139 stats[
'fY1NDC'] = 0.67;
4141 stats.AddText(this.histo[
'fName']);
4143 if (!
'fFunctions' in this.histo)
4144 this.histo[
'fFunctions'] = JSROOT.Create(
"TList");
4146 this.histo.fFunctions.arr.push(stats);
4151 JSROOT.THistPainter.prototype.DrawFunctions =
function() {
4156 if (!(
'fFunctions' in this.histo))
return;
4160 var lastpainter =
this;
4162 var kNotDraw = JSROOT.BIT(9);
4165 kCanDelete : JSROOT.BIT(0),
4166 kMustCleanup : JSROOT.BIT(3),
4167 kObjInCanvas : JSROOT.BIT(3),
4168 kIsReferenced : JSROOT.BIT(4),
4169 kHasUUID : JSROOT.BIT(5),
4170 kCannotPick : JSROOT.BIT(6),
4171 kNoContextMenu : JSROOT.BIT(8),
4172 kInvalidObject : JSROOT.BIT(13)
4175 for ( var i in this.histo.fFunctions.arr) {
4177 var func = this.histo.fFunctions.arr[i];
4179 var funcpainter = this.FindPainterFor(func);
4183 if (funcpainter != null)
continue;
4185 if (func[
'_typename'] ==
'TPaveText' || func[
'_typename'] ==
'TPaveStats') {
4186 funcpainter = JSROOT.Painter.drawPaveText(this.divid, func);
4189 if (func[
'_typename'] ==
'TF1') {
4190 var is_pad = this.root_pad() != null;
4191 if ((!is_pad && !func.TestBit(kNotDraw))
4192 || (is_pad && func.TestBit(EStatusBits.kObjInCanvas)))
4193 funcpainter = JSROOT.Painter.drawFunction(this.divid, func);
4196 if (func[
'_typename'] ==
'TPaletteAxis') {
4197 funcpainter = JSROOT.Painter.drawPaletteAxis(this.divid, func);
4202 JSROOT.THistPainter.prototype.Redraw =
function() {
4207 if (this.create_canvas) this.DrawTitle();
4210 JSROOT.THistPainter.prototype.Unzoom =
function(dox, doy) {
4211 var obj = this.main_painter();
4212 if (!obj) obj =
this;
4214 var changed =
false;
4217 if (obj[
'zoom_xmin'] != obj[
'zoom_xmax']) changed =
true;
4218 obj[
'zoom_xmin'] = 0;
4219 obj[
'zoom_xmax'] = 0;
4222 if (obj[
'zoom_ymin'] != obj[
'zoom_ymax']) changed =
true;
4223 obj[
'zoom_ymin'] = 0;
4224 obj[
'zoom_ymax'] = 0;
4227 if (changed) this.RedrawPad();
4230 JSROOT.THistPainter.prototype.Zoom =
function(xmin, xmax, ymin, ymax) {
4231 var obj = this.main_painter();
4232 if (!obj) obj =
this;
4236 if ((xmin != xmax) && (Math.abs(xmax-xmin) > obj.binwidthx*2.0)) {
4237 obj[
'zoom_xmin'] = xmin;
4238 obj[
'zoom_xmax'] = xmax;
4241 if ((ymin != ymax) && (Math.abs(ymax-ymin) > ((
'binwidthy' in obj) ? (obj.binwidthy*2.0) : Math.abs(obj.ymax-obj.ymin)*1e-6))) {
4242 obj[
'zoom_ymin'] = ymin;
4243 obj[
'zoom_ymax'] = ymax;
4247 if (isany) this.RedrawPad();
4250 JSROOT.THistPainter.prototype.AddInteractive =
function() {
4253 if (!JSROOT.gStyle.Zooming || !
this.is_main_painter())
return;
4257 var width = Number(this.svg_frame(
true).attr(
"width")),
4258 height = Number(this.svg_frame(
true).attr(
"height"));
4259 var e, origin, curr = null, rect = null;
4260 var lasttouch =
new Date(0);
4264 var disable_tooltip =
false;
4270 function closeAllExtras() {
4271 var x = document.getElementById(
'root_ctx_menu');
4272 if (x) x.parentNode.removeChild(x);
4273 if (rect != null) { rect.remove(); rect = null; }
4275 if (disable_tooltip) {
4276 JSROOT.gStyle.Tooltip =
true;
4277 disable_tooltip =
false;
4281 function showContextMenu() {
4283 d3.event.preventDefault();
4286 if (zoom_kind > 100)
return;
4291 var menu = JSROOT.Painter.createmenu(d3.event,
'root_ctx_menu');
4293 menu[
'painter'] = pthis;
4295 JSROOT.Painter.menuitem(menu, pthis.histo[
'fName']);
4296 JSROOT.Painter.menuitem(menu,
"----------------");
4298 pthis.FillContextMenu(menu);
4301 function startTouchSel() {
4304 if (zoom_kind != 0) {
4305 d3.event.preventDefault();
4306 d3.event.stopPropagation();
4311 width = Number(pthis.svg_frame(
true).attr(
"width"));
4312 height = Number(pthis.svg_frame(
true).attr(
"height"));
4316 var arr = d3.touches(e);
4319 if (arr.length == 1) {
4321 var now =
new Date();
4322 var diff = now.getTime() - lasttouch.getTime();
4324 if ((diff < 300) && (curr != null)
4325 && (Math.abs(curr[0] - arr[0][0]) < 30)
4326 && (Math.abs(curr[1] - arr[0][1]) < 30)) {
4328 d3.event.preventDefault();
4329 d3.event.stopPropagation();
4332 pthis.Unzoom(
true,
true);
4339 if (arr.length != 2)
return;
4341 d3.event.preventDefault();
4351 curr.push(Math.min(pnt1[0], pnt2[0]));
4352 curr.push(Math.min(pnt1[1], pnt2[1]));
4353 origin.push(Math.max(pnt1[0], pnt2[0]));
4354 origin.push(Math.max(pnt1[1], pnt2[1]));
4360 }
else if (origin[1] > height) {
4371 rect = pthis.svg_frame(
true).append(
"rect")
4372 .attr(
"class",
"zoom")
4373 .attr(
"id",
"zoomRect")
4376 .attr(
"width", origin[0] - curr[0])
4377 .attr(
"height", origin[1] - curr[1]);
4381 d3.select(window).on(
"touchmove.zoomRect", moveTouchSel)
4382 .on(
"touchcancel.zoomRect", endTouchSel)
4383 .on(
"touchend.zoomRect", endTouchSel,
true);
4384 d3.event.stopPropagation();
4387 function moveTouchSel() {
4388 if (zoom_kind < 100)
return;
4390 d3.event.preventDefault();
4393 var arr = d3.touches(e);
4395 if (arr.length != 2) {
4404 if (zoom_kind != 103) {
4405 curr[0] = Math.min(pnt1[0], pnt2[0]);
4406 origin[0] = Math.max(pnt1[0], pnt2[0]);
4408 if (zoom_kind != 102) {
4409 curr[1] = Math.min(pnt1[1], pnt2[1]);
4410 origin[1] = Math.max(pnt1[1], pnt2[1]);
4413 rect.attr(
"x", curr[0])
4415 .attr(
"width", origin[0] - curr[0])
4416 .attr(
"height", origin[1] - curr[1]);
4418 if (JSROOT.gStyle.Tooltip && ((origin[0] - curr[0]>10) || (origin[1] - curr[1]>10))) {
4419 JSROOT.gStyle.Tooltip =
false;
4420 disable_tooltip =
true;
4423 d3.event.stopPropagation();
4426 function endTouchSel() {
4428 if (zoom_kind < 100)
return;
4430 d3.event.preventDefault();
4431 d3.select(window).on(
"touchmove.zoomRect", null)
4432 .on(
"touchend.zoomRect", null)
4433 .on(
"touchcancel.zoomRect", null);
4434 d3.select(
"body").classed(
"noselect",
false);
4436 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
4440 if ((zoom_kind != 103) && (Math.abs(curr[0] - origin[0]) > 10)) {
4441 xmin = Math.min(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
4442 xmax = Math.max(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
4446 if ((zoom_kind != 102) && (Math.abs(curr[1] - origin[1]) > 10)) {
4447 ymin = Math.min(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
4448 ymax = Math.max(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
4452 d3.select(
"body").style(
"-webkit-user-select",
"auto");
4454 if (disable_tooltip)
4455 JSROOT.gStyle.Tooltip =
true;
4461 if (isany) pthis.Zoom(xmin, xmax, ymin, ymax);
4463 d3.event.stopPropagation();
4466 function detectLeftButton(event) {
4467 if (
'buttons' in event)
return event.buttons === 1;
4468 else if (
'which' in event)
return event.which === 1;
4469 else return event.button === 1;
4472 function startRectSel() {
4478 if (zoom_kind > 100)
return;
4480 d3.event.preventDefault();
4483 width = Number(pthis.svg_frame(
true).attr(
"width"));
4484 height = Number(pthis.svg_frame(
true).attr(
"height"));
4489 origin = d3.mouse(e);
4492 curr.push(Math.max(0, Math.min(width, origin[0])));
4493 curr.push(Math.max(0, Math.min(height, origin[1])));
4495 if (origin[0] < 0) {
4498 origin[1] = curr[1];
4501 }
else if (origin[1] > height) {
4503 origin[0] = curr[0];
4509 origin[0] = curr[0];
4510 origin[1] = curr[1];
4516 rect = pthis.svg_frame(
true)
4518 .attr(
"class",
"zoom")
4519 .attr(
"id",
"zoomRect");
4521 pthis.svg_frame(
true).on(
"dblclick", unZoom);
4523 d3.select(window).on(
"mousemove.zoomRect", moveRectSel)
4524 .on(
"mouseup.zoomRect", endRectSel,
true);
4526 d3.event.stopPropagation();
4530 d3.event.preventDefault();
4531 var m = d3.mouse(e);
4533 if (m[0] < 0) pthis.Unzoom(
false,
true);
else
4534 if (m[1] > height) pthis.Unzoom(
true,
false);
else {
4535 pthis.Unzoom(
true,
true);
4536 pthis.svg_frame(
true).on(
"dblclick", null);
4540 function moveRectSel() {
4542 if ((zoom_kind == 0) || (zoom_kind > 100))
return;
4544 d3.event.preventDefault();
4545 var m = d3.mouse(e);
4547 m[0] = Math.max(0, Math.min(width, m[0]));
4548 m[1] = Math.max(0, Math.min(height, m[1]));
4550 switch (zoom_kind) {
4551 case 1: curr[0] = m[0]; curr[1] = m[1];
break;
4552 case 2: curr[0] = m[0];
break;
4553 case 3: curr[1] = m[1];
break;
4556 rect.attr(
"x", Math.min(origin[0], curr[0]))
4557 .attr(
"y", Math.min(origin[1], curr[1]))
4558 .attr(
"width", Math.abs(curr[0] - origin[0]))
4559 .attr(
"height", Math.abs(curr[1] - origin[1]));
4561 if (JSROOT.gStyle.Tooltip && ((Math.abs(curr[0] - origin[0])>10) || (Math.abs(curr[1] - origin[1])>10))) {
4562 JSROOT.gStyle.Tooltip =
false;
4563 disable_tooltip =
true;
4567 function endRectSel() {
4568 if ((zoom_kind == 0) || (zoom_kind > 100))
return;
4570 d3.event.preventDefault();
4573 d3.select(window).on(
"mousemove.zoomRect", null)
4574 .on(
"mouseup.zoomRect", null);
4575 d3.select(
"body").classed(
"noselect",
false);
4577 var m = d3.mouse(e);
4579 m[0] = Math.max(0, Math.min(width, m[0]));
4580 m[1] = Math.max(0, Math.min(height, m[1]));
4582 switch (zoom_kind) {
4583 case 1: curr[0] = m[0]; curr[1] = m[1];
break;
4584 case 2: curr[0] = m[0];
break;
4585 case 3: curr[1] = m[1];
break;
4588 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
4592 if ((zoom_kind != 3) && (Math.abs(curr[0] - origin[0]) > 10)) {
4593 xmin = Math.min(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
4594 xmax = Math.max(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
4598 if ((zoom_kind != 2) && (Math.abs(curr[1] - origin[1]) > 10)) {
4599 ymin = Math.min(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
4600 ymax = Math.max(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
4604 d3.select(
"body").style(
"-webkit-user-select",
"auto");
4606 if (disable_tooltip) {
4607 JSROOT.gStyle.Tooltip =
true;
4608 disable_tooltip =
false;
4615 if (isany) pthis.Zoom(xmin, xmax, ymin, ymax);
4618 this.svg_frame(
true).on(
"mousedown", startRectSel);
4619 this.svg_frame(
true).on(
"touchstart", startTouchSel);
4620 this.svg_frame(
true).on(
"contextmenu", showContextMenu);
4624 JSROOT.THistPainter.prototype.FillContextMenu =
function(menu) {
4625 JSROOT.Painter.menuitem(menu,
"Unzoom X",
function() {
4626 menu[
'painter'].Unzoom(
true,
false);
4628 JSROOT.Painter.menuitem(menu,
"Unzoom Y",
function() {
4629 menu[
'painter'].Unzoom(
false,
true);
4631 JSROOT.Painter.menuitem(menu,
"Unzoom",
function() {
4632 menu[
'painter'].Unzoom(
true,
true);
4635 JSROOT.Painter.menuitem(menu, JSROOT.gStyle.Tooltip ?
"Disable tooltip" :
"Enable tooltip",
function() {
4636 JSROOT.gStyle.Tooltip = !JSROOT.gStyle.Tooltip;
4637 menu[
'painter'].RedrawPad();
4642 var item = this.options.Logx > 0 ?
"Linear X" :
"Log X";
4644 JSROOT.Painter.menuitem(menu, item,
function() {
4645 menu[
'painter'].options.Logx = 1 - menu[
'painter'].options.Logx;
4646 menu[
'painter'].RedrawPad();
4649 var item = this.options.Logy > 0 ?
"Linear Y" :
"Log Y";
4650 JSROOT.Painter.menuitem(menu, item,
function() {
4651 menu[
'painter'].options.Logy = 1 - menu[
'painter'].options.Logy;
4652 menu[
'painter'].RedrawPad();
4655 if (this.draw_content)
4656 JSROOT.Painter.menuitem(menu,
"Toggle stat",
function() {
4657 menu[
'painter'].ToggleStat();
4663 JSROOT.TH1Painter =
function(histo) {
4664 JSROOT.THistPainter.call(
this, histo);
4667 JSROOT.TH1Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
4669 JSROOT.TH1Painter.prototype.ScanContent =
function() {
4673 this.fill = this.createAttFill(this.histo);
4674 if (this.fill.color ==
'white') this.fill.color =
'none';
4676 this.attline = JSROOT.Painter.createAttLine(this.histo);
4678 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0;
4680 var profile = this.IsTProfile();
4682 this.nbinsx = this.histo[
'fXaxis'][
'fNbins'];
4684 for (var i = 0; i < this.nbinsx; ++i) {
4685 var value = this.histo.getBinContent(i + 1);
4686 hsum += profile ? this.histo.fBinEntries[i + 1] : value;
4687 if (i == 0) hmin = hmax = value;
4688 if (value < hmin) hmin = value;
else
4689 if (value > hmax) hmax = value;
4691 if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value;
4696 hsum += this.histo.fBinEntries[0] + this.histo.fBinEntries[this.nbinsx + 1];
4698 hsum += this.histo.getBinContent(0) + this.histo.getBinContent(this.nbinsx + 1);
4700 this.stat_entries = hsum;
4703 this.xmin = this.histo[
'fXaxis'][
'fXmin'];
4704 this.xmax = this.histo[
'fXaxis'][
'fXmax'];
4706 this.binwidthx = (this.xmax - this.xmin);
4707 if (this.nbinsx > 0)
4708 this.binwidthx = this.binwidthx / this.nbinsx;
4710 this.ymin = this.histo[
'fYaxis'][
'fXmin'];
4711 this.ymax = this.histo[
'fYaxis'][
'fXmax'];
4712 this.ymin_nz = hmin_nz;
4714 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) {
4715 if (this.histo[
'fMinimum'] != -1111) this.ymin = this.histo[
'fMinimum'];
4716 if (this.histo[
'fMaximum'] != -1111) this.ymax = this.histo[
'fMaximum'];
4717 this.draw_content =
false;
4719 if (this.histo[
'fMinimum'] != -1111) hmin = this.histo[
'fMinimum'];
4720 if (this.histo[
'fMaximum'] != -1111) hmax = this.histo[
'fMaximum'];
4722 if (hmin == 0) { this.ymax = 0; this.ymax = 1; }
else
4723 if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
4724 else { this.ymin = 0; this.ymax = hmin * 2; }
4726 var dy = (hmax - hmin) * 0.1;
4727 this.ymin = hmin - dy;
4728 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
4729 this.ymax = hmax + dy;
4731 this.draw_content =
true;
4735 if (this.options.Bar == 0 &&
this.options.Hist == 0
4736 &&
this.options.Error == 0 &&
this.options.Same == 0) {
4737 this.draw_content =
false;
4739 if (this.options.Axis > 0) {
4740 this.draw_content =
false;
4744 JSROOT.TH1Painter.prototype.CountStat =
function(cond) {
4745 var profile = this.IsTProfile();
4747 var stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0;
4749 var left = this.GetSelectIndex(
"x",
"left");
4750 var right = this.GetSelectIndex(
"x",
"right");
4752 var xx = 0, w = 0, xmax = null, wmax = null;
4754 for (var i = left; i < right; i++) {
4755 xx = this.xmin + (i + 0.5) * this.binwidthx;
4757 if ((cond!=null) && !cond(xx))
continue;
4760 w = this.histo.fBinEntries[i + 1];
4761 stat_sumwy += this.histo.fArray[i + 1];
4762 stat_sumwy2 += this.histo.fSumw2[i + 1];
4764 w = this.histo.getBinContent(i + 1);
4767 if ((xmax==null) || (w>wmax)) { xmax = xx; wmax = w; }
4770 stat_sumwx += w * xx;
4771 stat_sumwx2 += w * xx * xx;
4774 var res = { meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: stat_sumw, entries: this.stat_entries, xmax:0, wmax:0 };
4776 if (stat_sumw > 0) {
4777 res.meanx = stat_sumwx / stat_sumw;
4778 res.meany = stat_sumwy / stat_sumw;
4779 res.rmsx = Math.sqrt(stat_sumwx2 / stat_sumw - res.meanx * res.meanx);
4780 res.rmsy = Math.sqrt(stat_sumwy2 / stat_sumw - res.meany * res.meany);
4791 JSROOT.TH1Painter.prototype.FillStatistic =
function(stat, dostat) {
4792 if (!this.histo)
return false;
4794 var data = this.CountStat();
4796 var print_name = Math.floor(dostat % 10);
4797 var print_entries = Math.floor(dostat / 10) % 10;
4798 var print_mean = Math.floor(dostat / 100) % 10;
4799 var print_rms = Math.floor(dostat / 1000) % 10;
4800 var print_under = Math.floor(dostat / 10000) % 10;
4801 var print_over = Math.floor(dostat / 100000) % 10;
4802 var print_integral = Math.floor(dostat / 1000000) % 10;
4803 var print_skew = Math.floor(dostat / 10000000) % 10;
4804 var print_kurt = Math.floor(dostat / 100000000) % 10;
4807 stat.AddLine(this.histo[
'fName']);
4809 if (this.IsTProfile()) {
4811 if (print_entries > 0)
4812 stat.AddLine(
"Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
4814 if (print_mean > 0) {
4815 stat.AddLine(
"Mean = " + JSROOT.gStyle.StatFormat(data.meanx));
4816 stat.AddLine(
"Mean y = " + JSROOT.gStyle.StatFormat(data.meany));
4819 if (print_rms > 0) {
4820 stat.AddLine(
"RMS = " + JSROOT.gStyle.StatFormat(data.rmsx));
4821 stat.AddLine(
"RMS y = " + JSROOT.gStyle.StatFormat(data.rmsy));
4826 if (print_entries > 0)
4827 stat.AddLine(
"Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
4829 if (print_mean > 0) {
4830 stat.AddLine(
"Mean = " + JSROOT.gStyle.StatFormat(data.meanx));
4833 if (print_rms > 0) {
4834 stat.AddLine(
"RMS = " + JSROOT.gStyle.StatFormat(data.rmsx));
4837 if (print_under > 0) {
4839 if (this.histo[
'fArray'].length > 0)
4840 res = this.histo[
'fArray'][0];
4841 stat.AddLine(
"Underflow = " + JSROOT.gStyle.StatFormat(res));
4844 if (print_over > 0) {
4846 if (this.histo[
'fArray'].length > 0)
4847 res = this.histo[
'fArray'][this.histo[
'fArray'].length - 1];
4848 stat.AddLine(
"Overflow = " + JSROOT.gStyle.StatFormat(res));
4851 if (print_integral > 0) {
4852 stat.AddLine(
"Integral = " + JSROOT.gStyle.StatEntriesFormat(data.integral));
4856 stat.AddLine(
"Skew = not avail");
4859 stat.AddLine(
"Kurt = not avail");
4863 var nlines = stat.pavetext[
'fLines'].arr.length;
4864 var stath = nlines * JSROOT.gStyle.StatFontSize;
4865 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
4866 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
4867 stat.pavetext[
'fY1NDC'] = 0.93 - stath;
4868 stat.pavetext[
'fY2NDC'] = 0.93;
4874 JSROOT.TH1Painter.prototype.CreateDrawBins =
function(width, height, exclude_zeros) {
4877 var left = this.GetSelectIndex(
"x",
"left", -1);
4878 var right = this.GetSelectIndex(
"x",
"right", 2);
4880 var draw_bins =
new Array;
4882 var can_optimize = ((JSROOT.gStyle.OptimizeDraw > 0) && (right-left > 5000)) ||
4883 ((JSROOT.gStyle.OptimizeDraw > 1) && (right-left > 2*width));
4885 var x1, x2 = this.xmin + left * this.binwidthx;
4886 var grx1 = -1111, grx2 = -1111, gry;
4889 var searchmax =
false;
4891 for (var i = left; i < right; i++) {
4894 x2 += this.binwidthx;
4896 if (this.options.Logx && (x1 <= 0))
continue;
4900 if (grx1 < 0) grx1 = this.x(x1);
4902 var pmax = i, cont = this.histo.getBinContent(i + 1);
4905 searchmax = !searchmax;
4908 while ((i+1<right) && (this.x(x2 + this.binwidthx) < grx2 + 0.5)) {
4909 i++; x2 += this.binwidthx;
4910 var ccc = this.histo.getBinContent(i + 1);
4911 if (searchmax ? ccc>cont : ccc<cont) {
4920 if (exclude_zeros && (cont==0))
continue;
4922 if (this.options.Logy && (cont <
this.scale_ymin))
4927 point = { x : grx1, y : gry };
4929 if (this.options.Error > 0) {
4930 point[
'xerr'] = (grx2 - grx1) / 2;
4931 point[
'yerr'] = gry - this.y(cont + this.histo.getBinError(pmax + 1));
4934 if (this.options.Error > 0) {
4935 point[
'x'] = (grx1 + grx2) / 2;
4936 point[
'tip'] =
"x = " + this.AxisAsText(
"x", (x1 + x2)/2 ) +
"\n" +
4937 "y = " + this.AxisAsText(
"y", cont) +
"\n" +
4938 "error x = " + ((x2 - x1) / 2).toPrecision(4) +
"\n" +
4939 "error y = " + this.histo.getBinError(pmax + 1).toPrecision(4);
4941 point[
'width'] = grx2 - grx1;
4943 point[
'tip'] =
"bin = " + (pmax + 1) +
"\n" +
4944 "x = [" + this.AxisAsText(
"x", x1) +
", " + this.AxisAsText(
"x", x2) +
"]\n" +
4945 "entries = " + cont;
4948 draw_bins.push(point);
4952 if ((right == this.nbinsx) && (this.options.Error == 0) && (point!=null)) {
4953 var extrapoint = jQuery.extend(
true, {}, point);
4954 extrapoint.x = grx2;
4955 draw_bins.push(extrapoint);
4961 JSROOT.TH1Painter.prototype.DrawAsMarkers =
function(draw_bins, w, h) {
4964 var draw_bins = this.CreateDrawBins(w, h, this.IsTProfile() || (this.Mark==10));
4967 var nodes = this.draw_g.selectAll(
"g")
4971 .attr(
"transform",
function(d) {
return "translate(" + d.x.toFixed(1) +
"," + d.y.toFixed(1) +
")";});
4973 if (JSROOT.gStyle.Tooltip)
4974 nodes.append(
"svg:title").text(
function(d) {
return d.tip; });
4976 var xerr = null, yerr = null;
4979 if (this.options.Error > 0)
4980 nodes.append(
"svg:line")
4981 .attr(
"x1",
function(d) {
return (-d.xerr).toFixed(1); })
4983 .attr(
"x2",
function(d) {
return d.xerr.toFixed(1); })
4985 .call(this.attline.func);
4987 if (this.options.Error == 11) {
4988 nodes.append(
"svg:line")
4990 .attr(
"x1",
function(d) {
return (-d.xerr).toFixed(1); })
4992 .attr(
"x2",
function(d) {
return (-d.xerr).toFixed(1); })
4993 .call(this.attline.func);
4994 nodes.append(
"svg:line")
4996 .attr(
"x1",
function(d) {
return d.xerr.toFixed(1); })
4998 .attr(
"x2",
function(d) {
return d.xerr.toFixed(1); })
4999 .call(this.attline.func);
5003 if (this.options.Error > 0)
5004 nodes.append(
"svg:line")
5006 .attr(
"y1",
function(d) {
return (-d.yerr).toFixed(1); })
5008 .attr(
"y2",
function(d) {
return d.yerr.toFixed(1); })
5009 .call(this.attline.func);
5011 if (this.options.Error == 11) {
5012 nodes.append(
"svg:line")
5014 .attr(
"y1",
function(d) {
return (-d.yerr).toFixed(1); })
5016 .attr(
"y2",
function(d) {
return (-d.yerr).toFixed(1); })
5017 .call(this.attline.func);
5018 nodes.append(
"svg:line")
5020 .attr(
"y1",
function(d) {
return d.yerr.toFixed(1); })
5022 .attr(
"y2",
function(d) {
return d.yerr.toFixed(1); })
5023 .call(this.attline.func);
5027 if ((this.histo[
'fMarkerStyle'] == 1) && (this.options.Error > 0))
return;
5029 var marker = JSROOT.Painter.createAttMarker(this.histo);
5031 nodes.append(
"svg:path").call(marker.func);
5034 JSROOT.TH1Painter.prototype.DrawBins =
function() {
5036 var width = Number(this.svg_frame(
true).attr(
"width")),
5037 height = Number(this.svg_frame(
true).attr(
"height"));
5039 if (!this.draw_content || (width<=0) || (height<=0)) {
5044 this.RecreateDrawG();
5046 if (this.IsTProfile() || (this.options.Error > 0) || (
this.options.Mark > 0))
5047 return this.DrawAsMarkers(width, height);
5049 var draw_bins = this.CreateDrawBins(width, height);
5051 if (this.fill.color !=
'none') {
5054 var area = d3.svg.area()
5055 .x(
function(d) {
return d.x.toFixed(1); })
5056 .y0(
function(d) {
return d.y.toFixed(1); })
5057 .y1(
function(d) {
return height; })
5058 .interpolate(
"step-after");
5060 this.draw_g.append(
"svg:path")
5061 .attr(
"d", area(draw_bins))
5062 .call(this.attline.func)
5063 .call(this.fill.func);
5066 var line = d3.svg.line()
5067 .x(
function(d) {
return d.x.toFixed(1); })
5068 .y(
function(d) {
return d.y.toFixed(1); })
5069 .interpolate(
"step-after");
5073 .attr(
"d", line(draw_bins))
5074 .call(this.attline.func)
5075 .style(
"fill",
"none");
5078 if (JSROOT.gStyle.Tooltip) {
5080 this.draw_g.selectAll(
"selections")
5081 .data(draw_bins).enter()
5083 .attr(
"x1",
function(d) {
return d.x + d.width / 2; })
5084 .attr(
"y1",
function(d) {
return Math.max(0, d.y); })
5085 .attr(
"x2",
function(d) {
return d.x + d.width / 2; })
5086 .attr(
"y2",
function(d) {
return height; })
5087 .style(
"opacity", 0)
5088 .style(
"stroke",
"#4572A7")
5089 .style(
"stroke-width",
function(d) {
return d.width; })
5090 .on(
'mouseover',
function() {
5091 if (JSROOT.gStyle.Tooltip && (d3.select(
this).style(
"opacity")==
"0"))
5092 d3.select(
this).transition().duration(100).style(
"opacity",
"0.3");
5094 .on(
'mouseout',
function() {
5095 d3.select(
this).transition().duration(100).style(
"opacity",
"0");
5097 .append(
"svg:title").text(
function(d) {
return d.tip; });
5101 JSROOT.TH1Painter.prototype.FillContextMenu =
function(menu) {
5102 JSROOT.THistPainter.prototype.FillContextMenu.call(
this, menu);
5103 if (this.draw_content)
5104 JSROOT.Painter.menuitem(menu,
"Auto zoom-in",
function() { menu[
'painter'].AutoZoom(); });
5107 JSROOT.TH1Painter.prototype.AutoZoom =
function() {
5108 var left = this.GetSelectIndex(
"x",
"left", -1);
5109 var right = this.GetSelectIndex(
"x",
"right", 1);
5111 var dist = (right - left);
5116 var min = this.histo.getBinContent(left + 1);
5119 for (var indx = left; indx < right; indx++)
5120 if (this.histo.getBinContent(indx + 1) < min)
5121 min = this.histo.getBinContent(indx + 1);
5123 while ((left < right) && (this.histo.getBinContent(left + 1) <= min)) left++;
5124 while ((left < right) && (this.histo.getBinContent(right) <= min)) right--;
5126 if ((right - left < dist) && (left < right))
5127 this.Zoom(this.xmin + left * this.binwidthx, this.xmin + right * this.binwidthx, 0, 0);
5130 JSROOT.Painter.drawHistogram1D =
function(divid, histo, opt) {
5133 var painter =
new JSROOT.TH1Painter(histo);
5134 painter.SetDivId(divid, 1);
5137 painter.options = painter.DecodeOptions(opt);
5139 painter.CheckPadOptions();
5141 painter.ScanContent();
5147 painter.DrawGrids();
5151 if (painter.create_canvas) painter.DrawTitle();
5153 if (JSROOT.gStyle.AutoStat && painter.create_canvas) painter.CreateStat();
5155 painter.DrawFunctions();
5157 painter.AddInteractive();
5164 JSROOT.TH2Painter =
function(histo) {
5165 JSROOT.THistPainter.call(
this, histo);
5166 this.paletteColors = [];
5169 JSROOT.TH2Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
5171 JSROOT.TH2Painter.prototype.FillContextMenu =
function(menu) {
5172 JSROOT.THistPainter.prototype.FillContextMenu.call(
this, menu);
5173 JSROOT.Painter.menuitem(menu,
"Auto zoom-in",
function() { menu[
'painter'].AutoZoom(); });
5174 JSROOT.Painter.menuitem(menu,
"Draw in 3D",
function() { menu[
'painter'].Draw3D(); });
5175 JSROOT.Painter.menuitem(menu,
"Toggle col",
function() {
5176 if (menu[
'painter'].options.Color == 0)
5177 menu[
'painter'].options.Color = JSROOT.gStyle.DefaultCol;
5179 menu[
'painter'].options.Color = -1 * menu[
'painter'].options.Color;
5180 menu[
'painter'].RedrawPad();
5183 if (this.options.Color > 0)
5184 JSROOT.Painter.menuitem(menu,
"Toggle colz",
function() { menu[
'painter'].ToggleColz(); });
5187 JSROOT.TH2Painter.prototype.FindPalette =
function(
remove) {
5188 if (
'fFunctions' in this.histo)
5189 for ( var i in this.histo.fFunctions.arr) {
5190 var func = this.histo.fFunctions.arr[i];
5191 if (func[
'_typename'] !=
'TPaletteAxis')
5194 this.histo.fFunctions.arr.splice(i, 1);
5204 JSROOT.TH2Painter.prototype.ToggleColz =
function() {
5205 if (this.FindPalette() == null) {
5206 var shrink = this.CreatePalette(0.04);
5207 this.svg_frame()[
'frame_painter'].Shrink(0, shrink);
5208 this.options.Zscale = 1;
5210 JSROOT.Painter.drawPaletteAxis(this.divid, this.FindPalette());
5212 if (this.options.Zscale > 0)
5213 this.options.Zscale = 0;
5215 this.options.Zscale = 1;
5221 JSROOT.TH2Painter.prototype.AutoZoom =
function() {
5222 var i1 = this.GetSelectIndex(
"x",
"left", -1);
5223 var i2 = this.GetSelectIndex(
"x",
"right", 1);
5224 var j1 = this.GetSelectIndex(
"y",
"left", -1);
5225 var j2 = this.GetSelectIndex(
"y",
"right", 1);
5227 if ((i1 == i2) || (j1 == j2))
return;
5229 var min = this.histo.getBinContent(i1 + 1, j1 + 1);
5232 for (var i = i1; i < i2; i++)
5233 for (var j = j1; j < j2; j++)
5234 if (this.histo.getBinContent(i + 1, j + 1) < min)
5235 min = this.histo.getBinContent(i + 1, j + 1);
5237 var ileft = i2, iright = i1, jleft = j2, jright = j1;
5239 for (var i = i1; i < i2; i++)
5240 for (var j = j1; j < j2; j++)
5241 if (this.histo.getBinContent(i + 1, j + 1) > min) {
5242 if (i < ileft) ileft = i;
5243 if (i >= iright) iright = i + 1;
5244 if (j < jleft) jleft = j;
5245 if (j >= jright) jright = j + 1;
5248 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
5250 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
5251 xmin = this.xmin + ileft * this.binwidthx;
5252 xmax = this.xmin + iright * this.binwidthx;
5255 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
5256 ymin = this.ymin + jleft * this.binwidthy;
5257 ymax = this.ymin + jright * this.binwidthy;
5260 this.Zoom(xmin, xmax, ymin, ymax);
5263 JSROOT.TH2Painter.prototype.CreatePalette =
function(rel_width) {
5264 if (this.FindPalette() != null)
return 0.;
5266 if (!rel_width || rel_width <= 0) rel_width = 0.04;
5269 pal[
'_typename'] =
'TPaletteAxis';
5270 pal[
'fName'] =
'palette';
5272 pal[
'_AutoCreated'] =
true;
5274 pal[
'fX1NDC'] = this.svg_frame()[
'NDC'].x2 - rel_width;
5275 pal[
'fY1NDC'] = this.svg_frame()[
'NDC'].y1;
5276 pal[
'fX2NDC'] = this.svg_frame()[
'NDC'].x2;
5277 pal[
'fY2NDC'] = this.svg_frame()[
'NDC'].y2;
5279 pal[
'fShadowColor'] = 1;
5280 pal[
'fCorenerRadius'] = 0;
5281 pal[
'fResizing'] =
false;
5282 pal[
'fBorderSize'] = 4;
5283 pal[
'fName'] =
"TPave";
5284 pal[
'fOption'] =
"br";
5285 pal[
'fLineColor'] = 1;
5286 pal[
'fLineSyle'] = 1;
5287 pal[
'fLineWidth'] = 1;
5288 pal[
'fFillColor'] = 1;
5289 pal[
'fFillSyle'] = 1;
5293 axis[
'_typename'] =
'TGaxis';
5294 axis[
'fTickSize'] = 0.03;
5295 axis[
'fLabelOffset'] = 0.005;
5296 axis[
'fLabelSize'] = 0.035;
5297 axis[
'fTitleOffset'] = 1;
5298 axis[
'fTitleSize'] = 0.035;
5300 axis[
'fLabelColor'] = 1;
5301 axis[
'fLabelFont'] = 42;
5302 axis[
'fChopt'] =
"";
5304 axis[
'fTitle'] =
"";
5305 axis[
'fTimeFormat'] =
"";
5306 axis[
'fFunctionName'] =
"";
5308 axis[
'fWmax'] = 100;
5309 axis[
'fLineColor'] = 1;
5310 axis[
'fLineSyle'] = 1;
5311 axis[
'fLineWidth'] = 1;
5312 axis[
'fTextAngle'] = 0;
5313 axis[
'fTextSize'] = 0.04;
5314 axis[
'fTextAlign'] = 11;
5315 axis[
'fTextColor'] = 1;
5316 axis[
'fTextFont'] = 42;
5318 pal[
'fAxis'] = axis;
5320 if (!
'fFunctions' in this.histo)
5321 this.histo[
'fFunctions'] = JSROOT.Create(
"TList");
5324 this.histo.fFunctions.arr.unshift(pal);
5329 var width = Number(this.svg_frame(
true).attr(
"width")),
5330 height = Number(this.svg_frame(
true).attr(
"height"));
5332 var axisOffset = Math.round(axis[
'fLabelOffset'] * width);
5333 var tickSize = Math.round(axis[
'fTickSize'] * width);
5334 var axisfont = JSROOT.Painter.getFontDetails(axis[
'fLabelFont'], axis[
'fLabelSize'] * height);
5336 var ticks = d3.scale.linear().clamp(
true)
5337 .domain([ this.minbin, this.maxbin ])
5338 .range([ height, 0 ]).nice().ticks(axis[
'fNdiv'] % 100);
5341 for (var i in ticks) {
5342 var len = axisfont.stringWidth(this.svg_frame(
true), ticks[i]);
5343 if (len > maxlen) maxlen = len;
5346 var rel = (maxlen + axisOffset) / width;
5348 if (pal[
'fX2NDC'] + rel > 0.98) {
5349 var shift = pal[
'fX2NDC'] + rel - 0.98;
5351 pal[
'fX1NDC'] -= shift;
5352 pal[
'fX2NDC'] -= shift;
5356 return rel_width + 0.01;
5359 JSROOT.TH2Painter.prototype.ScanContent =
function() {
5360 this.fillcolor = JSROOT.Painter.root_colors[this.histo[
'fFillColor']];
5363 this.attline = JSROOT.Painter.createAttLine(this.histo);
5364 if (this.attline.color ==
'none') this.attline.color =
'#4572A7';
5366 this.nbinsx = this.histo[
'fXaxis'][
'fNbins'];
5367 this.nbinsy = this.histo[
'fYaxis'][
'fNbins'];
5370 this.xmin = this.histo[
'fXaxis'][
'fXmin'];
5371 this.xmax = this.histo[
'fXaxis'][
'fXmax'];
5372 this.ymin = this.histo[
'fYaxis'][
'fXmin'];
5373 this.ymax = this.histo[
'fYaxis'][
'fXmax'];
5375 this.binwidthx = (this.xmax - this.xmin);
5376 if (this.nbinsx > 0)
5377 this.binwidthx = this.binwidthx / this.nbinsx;
5379 this.binwidthy = (this.ymax - this.ymin);
5380 if (this.nbinsy > 0)
5381 this.binwidthy = this.binwidthy / this.nbinsy
5383 this.gmaxbin = this.histo.getBinContent(1, 1);
5384 this.gminbin = this.gmaxbin;
5385 for (var i = 0; i < this.nbinsx; ++i) {
5386 for (var j = 0; j < this.nbinsy; ++j) {
5387 var bin_content = this.histo.getBinContent(i + 1, j + 1);
5388 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
5389 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
5394 this.draw_content = this.gmaxbin > 0;
5397 JSROOT.TH2Painter.prototype.CountStat =
function(cond) {
5398 var stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0, stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy2 = 0;
5400 var res = { entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix : [], xmax: 0, ymax:0, wmax: null };
5401 for (var n = 0; n < 9; n++) res.matrix.push(0);
5403 var xleft = this.GetSelectIndex(
"x",
"left");
5404 var xright = this.GetSelectIndex(
"x",
"right");
5406 var yleft = this.GetSelectIndex(
"y",
"left");
5407 var yright = this.GetSelectIndex(
"y",
"right");
5409 for (var xi = 0; xi <= this.nbinsx + 1; xi++) {
5410 var xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
5411 var xx = this.xmin + (xi - 0.5) * this.binwidthx;
5413 for (var yi = 0; yi <= this.nbinsx + 1; yi++) {
5414 var yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
5415 var yy = this.ymin + (yi - 0.5) * this.binwidthy;
5417 var zz = this.histo.getBinContent(xi, yi);
5421 res.matrix[yside * 3 + xside] += zz;
5423 if ((xside != 1) || (yside != 1))
continue;
5425 if ((cond!=null) && !cond(xx,yy))
continue;
5427 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
5430 stat_sumx1 += xx * zz;
5431 stat_sumy1 += yy * zz;
5432 stat_sumx2 += xx * xx * zz;
5433 stat_sumy2 += yy * yy * zz;
5434 stat_sumxy2 += xx * yy * zz;
5438 if (stat_sum0 > 0) {
5439 res.meanx = stat_sumx1 / stat_sum0;
5440 res.meany = stat_sumy1 / stat_sum0;
5441 res.rmsx = Math.sqrt(stat_sumx2 / stat_sum0 - res.meanx * res.meanx);
5442 res.rmsy = Math.sqrt(stat_sumy2 / stat_sum0 - res.meany * res.meany);
5445 if (res.wmax==null) res.wmax = 0;
5446 res.integral = stat_sum0;
5451 JSROOT.TH2Painter.prototype.FillStatistic =
function(stat, dostat) {
5452 if (!this.histo)
return false;
5454 var data = this.CountStat();
5456 var print_name = Math.floor(dostat % 10);
5457 var print_entries = Math.floor(dostat / 10) % 10;
5458 var print_mean = Math.floor(dostat / 100) % 10;
5459 var print_rms = Math.floor(dostat / 1000) % 10;
5460 var print_under = Math.floor(dostat / 10000) % 10;
5461 var print_over = Math.floor(dostat / 100000) % 10;
5462 var print_integral = Math.floor(dostat / 1000000) % 10;
5463 var print_skew = Math.floor(dostat / 10000000) % 10;
5464 var print_kurt = Math.floor(dostat / 100000000) % 10;
5467 stat.AddLine(this.histo[
'fName']);
5469 if (print_entries > 0)
5470 stat.AddLine(
"Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
5472 if (print_mean > 0) {
5473 stat.AddLine(
"Mean x = " + JSROOT.gStyle.StatFormat(data.meanx));
5474 stat.AddLine(
"Mean y = " + JSROOT.gStyle.StatFormat(data.meany));
5477 if (print_rms > 0) {
5478 stat.AddLine(
"RMS x = " + JSROOT.gStyle.StatFormat(data.rmsx));
5479 stat.AddLine(
"RMS y = " + JSROOT.gStyle.StatFormat(data.rmsy));
5482 if (print_integral > 0) {
5483 stat.AddLine(
"Integral = " + JSROOT.gStyle.StatEntriesFormat(data.matrix[4]));
5486 if (print_skew > 0) {
5487 stat.AddLine(
"Skewness x = <undef>");
5488 stat.AddLine(
"Skewness y = <undef>");
5492 stat.AddLine(
"Kurt = <undef>");
5494 if ((print_under > 0) || (print_over > 0)) {
5495 var m = data.matrix;
5497 stat.AddLine(
"" + m[6].toFixed(0) +
" | " + m[7].toFixed(0) +
" | " + m[7].toFixed(0));
5498 stat.AddLine(
"" + m[3].toFixed(0) +
" | " + m[4].toFixed(0) +
" | " + m[5].toFixed(0));
5499 stat.AddLine(
"" + m[0].toFixed(0) +
" | " + m[1].toFixed(0) +
" | " + m[2].toFixed(0));
5503 var nlines = stat.pavetext[
'fLines'].arr.length;
5504 var stath = nlines * JSROOT.gStyle.StatFontSize;
5505 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
5506 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
5507 stat.pavetext[
'fY1NDC'] = 0.93 - stath;
5508 stat.pavetext[
'fY2NDC'] = 0.93;
5513 JSROOT.TH2Painter.prototype.getValueColor =
function(zc) {
5514 var wmin = this.minbin, wmax = this.maxbin;
5515 var wlmin = wmin, wlmax = wmax;
5516 var ndivz = this.histo[
'fContour'].length;
5517 if (ndivz < 16) ndivz = 16;
5518 var scale = ndivz / (wlmax - wlmin);
5519 if (this.options.Logz) {
5520 if (wmin <= 0 && wmax > 0)
5521 wmin = Math.min(1.0, 0.001 * wmax);
5522 wlmin = Math.log(wmin) / Math.log(10);
5523 wlmax = Math.log(wmax) / Math.log(10);
5526 if (this.paletteColors.length == 0) {
5527 var saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50;
5528 for (var i = 0; i < maxPretty; i++) {
5529 var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360.0;
5530 var rgbval = JSROOT.Painter.HLStoRGB(hue, lightness, saturation);
5531 this.paletteColors.push(rgbval);
5534 if (this.options.Logz) zc = Math.log(zc) / Math.log(10);
5535 if (zc < wlmin) zc = wlmin;
5536 var ncolors = this.paletteColors.length;
5537 var color = Math.round(0.01 + (zc - wlmin) * scale);
5538 var theColor = Math.round((color + 0.99) * ncolors / ndivz) - 1;
5539 var icol = theColor % ncolors;
5540 if (icol < 0) icol = 0;
5542 return this.paletteColors[icol];
5545 JSROOT.TH2Painter.prototype.CreateDrawBins =
function(w, h, coordinates_kind, tipkind) {
5546 var i1 = this.GetSelectIndex(
"x",
"left", 0);
5547 var i2 = this.GetSelectIndex(
"x",
"right", 0);
5548 var j1 = this.GetSelectIndex(
"y",
"left", 0);
5549 var j2 = this.GetSelectIndex(
"y",
"right", 0);
5551 var x1, y1, x2, y2, grx1, gry1, grx2, gry2, fillcol, shrx, shry, binz, point, wx ,wy;
5554 this.maxbin = this.minbin = this.histo.getBinContent(i1 + 1, j1 + 1);
5555 for (var i = i1; i < i2; i++) {
5556 for (var j = j1; j < j2; j++) {
5557 binz = this.histo.getBinContent(i + 1, j + 1);
5558 if (binz>this.maxbin) this.maxbin = binz;
else
5559 if (binz<this.minbin) this.minbin = binz;
5563 var xfactor = 1, yfactor = 1;
5564 if (coordinates_kind == 1) {
5565 xfactor = 0.5 * w / (i2 - i1) / (this.maxbin - this.minbin);
5566 yfactor = 0.5 * h / (j2 - j1) / (this.maxbin - this.minbin);
5569 var local_bins =
new Array;
5571 x2 = this.xmin + i1 * this.binwidthx;
5573 for (var i = i1; i < i2; i++) {
5575 x2 += this.binwidthx;
5577 if (this.options.Logx && (x1 <= 0))
continue;
5580 if (grx1 < 0) grx1 = this.x(x1);
5583 y2 = this.ymin + j1 * this.binwidthy;
5585 for (var j = j1; j < j2; j++) {
5587 y2 += this.binwidthy;
5588 if (this.options.Logy && (y1 <= 0))
continue;
5590 if (gry1 < 0) gry1 = this.y(y1);
5592 binz = this.histo.getBinContent(i + 1, j + 1);
5593 if ((binz == 0) || (binz < this.minbin))
continue;
5595 switch (coordinates_kind) {
5600 width : grx2 - grx1 + 1,
5601 height : gry1 - gry2 + 1,
5603 fill : this.getValueColor(binz)
5605 point[
'tipcolor'] = (point[
'fill'] ==
"black") ?
"grey" :
"black";
5609 shrx = xfactor * (this.maxbin - binz);
5610 shry = yfactor * (this.maxbin - binz);
5614 width : grx2 - grx1 - 2 * shrx,
5615 height : gry1 - gry2 - 2 * shry,
5616 stroke : this.attline.color,
5617 fill : this.fillcolor
5619 point[
'tipcolor'] = (point[
'fill'] ==
"black") ?
"grey" :
"black";
5632 point[
'tip'] =
"x = [" + this.AxisAsText(
"x", x1) +
", " + this.AxisAsText(
"x", x2) +
"]\n" +
5633 "y = [" + this.AxisAsText(
"y", y1) +
", " + this.AxisAsText(
"y", y2) +
"]\n" +
5634 "entries = " + binz;
5635 else if (tipkind == 2)
5636 point[
'tip'] =
"x = " + this.AxisAsText(
"x", x1) +
"\n" +
5637 "y = " + this.AxisAsText(
"y", y1) +
"\n" +
5638 "entries = " + binz;
5640 local_bins.push(point);
5647 JSROOT.TH2Painter.prototype.DrawSimpleCanvas =
function(w,h) {
5649 var i1 = this.GetSelectIndex(
"x",
"left", 0);
5650 var i2 = this.GetSelectIndex(
"x",
"right", 0);
5651 var j1 = this.GetSelectIndex(
"y",
"left", 0);
5652 var j2 = this.GetSelectIndex(
"y",
"right", 0);
5654 this.maxbin = this.minbin = this.histo.getBinContent(i1 + 1, j1 + 1);
5655 for (var i = i1; i < i2; i++) {
5656 for (var j = j1; j < j2; j++) {
5657 binz = this.histo.getBinContent(i + 1, j + 1);
5658 if (binz>this.maxbin) this.maxbin = binz;
else
5659 if (binz<this.minbin) this.minbin = binz;
5663 var dx = i2-i1, dy = j2-j1;
5666 this.draw_g.append(
"foreignObject")
5669 .append(
"xhtml:canvas")
5672 .attr(
"style",
"width: " + w +
"px; height: "+ h +
"px");
5674 var context = canvas.node().getContext(
"2d");
5675 var image = context.createImageData(dx, dy);
5679 for (var j = j2-1; j >= j1; j--) {
5680 for (var i = i1; i < i2; i++) {
5681 var bin = this.histo.getBinContent(i + 1, j + 1);
5682 var col = bin>this.minbin ? this.getValueColor(bin) :
'white';
5683 var c = d3.rgb(col);
5684 image.data[++p] = c.r;
5685 image.data[++p] = c.g;
5686 image.data[++p] = c.b;
5687 image.data[++p] = 255;
5691 context.putImageData(image, 0, 0);
5694 JSROOT.TH2Painter.prototype.DrawNormalCanvas =
function(w,h) {
5696 var local_bins = this.CreateDrawBins(w, h, 0, 0);
5698 var foreignObject = document.createElementNS(
'http://www.w3.org/2000/svg',
'foreignObject' );
5701 var canvas = document.createElementNS(
"http://www.w3.org/1999/xhtml",
"canvas");
5703 $(canvas).attr(
'width', w).attr(
'height',h)
5707 $(foreignObject).attr(
"width", w).attr(
"height", h).append(canvas);
5709 $(this.draw_g.node()).append(foreignObject);
5711 var ctx = canvas.getContext(
"2d");
5724 for (var i in local_bins) {
5725 var bin = local_bins[i];
5726 ctx.fillStyle = bin.fill;
5727 ctx.fillRect(bin.x,bin.y,bin.width,bin.height);
5734 JSROOT.TH2Painter.prototype.DrawBins =
function() {
5736 this.RecreateDrawG();
5738 var w = Number(this.svg_frame(
true).attr(
"width")),
5739 h = Number(this.svg_frame(
true).attr(
"height"));
5741 if (this.options.Color==2)
5742 return this.DrawSimpleCanvas(w,h);
5744 if (this.options.Color==3)
5745 return this.DrawNormalCanvas(w,h);
5751 var draw_markers = (this.options.Scat > 0 && this.histo[
'fMarkerStyle'] > 1);
5752 var normal_coordinates = (this.options.Color > 0) || draw_markers;
5755 if (JSROOT.gStyle.Tooltip) tipkind = draw_markers ? 2 : 1;
5757 var local_bins = this.CreateDrawBins(w, h, normal_coordinates ? 0 : 1, tipkind);
5761 var marker = JSROOT.Painter.createAttMarker(this.histo);
5764 this.draw_g.selectAll(
".marker")
5766 .enter().append(
"svg:path")
5767 .attr(
"class",
"marker")
5768 .attr(
"transform",
function(d) {
return "translate(" + d.x.toFixed(1) +
"," + d.y.toFixed(1) +
")" })
5771 if (JSROOT.gStyle.Tooltip)
5772 markers.append(
"svg:title").text(
function(d) {
return d.tip; });
5774 var drawn_bins = this.draw_g.selectAll(
".bins")
5775 .data(local_bins).enter()
5777 .attr(
"class",
"bins")
5778 .attr(
"x",
function(d) {
return d.x.toFixed(1); })
5779 .attr(
"y",
function(d) {
return d.y.toFixed(1); })
5780 .attr(
"width",
function(d) {
return d.width.toFixed(1); })
5781 .attr(
"height",
function(d) {
return d.height.toFixed(1); })
5782 .style(
"stroke",
function(d) {
return d.stroke; })
5783 .style(
"fill",
function(d) {
5784 this[
'f0'] = d.fill;
5785 this[
'f1'] = d.tipcolor;
5789 if (JSROOT.gStyle.Tooltip)
5791 .on(
'mouseover',
function() {
5792 if (JSROOT.gStyle.Tooltip)
5793 d3.select(
this).transition().duration(100).style(
"fill",
this[
'f1']);
5795 .on(
'mouseout',
function() {
5796 d3.select(
this).transition().duration(100).style(
"fill",
this[
'f0']);
5798 .append(
"svg:title").text(
function(d) {
return d.tip; });
5804 JSROOT.TH2Painter.prototype.Draw2D =
function() {
5806 if (this.options.Lego>0) this.options.Lego = 0;
5808 if (
this[
'done2d'])
return;
5811 if ((this.FindPalette() == null) && this.create_canvas && (this.options.Zscale > 0)) {
5813 var shrink = this.CreatePalette(0.04);
5814 this.svg_frame()[
'frame_painter'].Shrink(0, shrink);
5815 this.svg_frame()[
'frame_painter'].Redraw();
5817 }
else if (this.options.Zscale == 0) {
5819 this.FindPalette(
true);
5823 if (JSROOT.gStyle.AutoStat &&
this.create_canvas)
5832 if (this.create_canvas) this.DrawTitle();
5834 this.DrawFunctions();
5836 this.AddInteractive();
5838 this[
'done2d'] =
true;
5841 JSROOT.TH2Painter.prototype.Draw3D =
function() {
5843 if (this.options.Lego<=0) this.options.Lego = 1;
5846 JSROOT.AssertPrerequisites(
'3d',
function() {
5847 JSROOT.Painter.real_drawHistogram2D(painter);
5851 JSROOT.Painter.drawHistogram2D =
function(divid, histo, opt) {
5854 var painter =
new JSROOT.TH2Painter(histo);
5856 painter.SetDivId(divid, 1);
5859 painter.options = painter.DecodeOptions(opt);
5861 painter.CheckPadOptions();
5863 painter.ScanContent();
5867 if (painter.options.Lego > 0)
5875 JSROOT.Painter.drawHistogram3D =
function(divid, obj, opt) {
5876 JSROOT.AssertPrerequisites(
'3d',
function() {
5877 JSROOT.Painter.real_drawHistogram3D(divid, obj, opt);
5883 JSROOT.THStackPainter =
function(stack) {
5884 JSROOT.TObjectPainter.call(
this, stack);
5886 this.nostack =
false;
5887 this.firstpainter = null;
5888 this.painters =
new Array;
5891 JSROOT.THStackPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
5893 JSROOT.THStackPainter.prototype.GetObject =
function() {
5897 JSROOT.THStackPainter.prototype.drawStack =
function(opt) {
5899 var pad = this.root_pad();
5900 var histos = this.stack[
'fHists'];
5901 var nhists = histos.arr.length;
5903 if (opt == null) opt =
"";
5904 else opt = opt.toLowerCase();
5906 if (opt.indexOf(
"same") != -1) {
5908 opt.replace(
"same",
"");
5912 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
5913 for (var i = 0; i < nhists; ++i) {
5915 if (i == 0 || h[
'fXaxis'][
'fXmin'] < xmin)
5916 xmin = h[
'fXaxis'][
'fXmin'];
5917 if (i == 0 || h[
'fXaxis'][
'fXmax'] > xmax)
5918 xmax = h[
'fXaxis'][
'fXmax'];
5919 if (i == 0 || h[
'fYaxis'][
'fXmin'] < ymin)
5920 ymin = h[
'fYaxis'][
'fXmin'];
5921 if (i == 0 || h[
'fYaxis'][
'fXmax'] > ymax)
5922 ymax = h[
'fYaxis'][
'fXmax'];
5924 this.nostack = opt.indexOf(
"nostack") == -1 ?
false :
true;
5926 this.stack.buildStack();
5929 if (this.stack[
'fMaximum'] == -1111) themax = this.stack.getMaximum(opt);
5930 else themax = this.stack[
'fMaximum'];
5931 if (this.stack[
'fMinimum'] == -1111) {
5932 themin = this.stack.getMinimum(opt);
5933 if (pad && pad[
'fLogy']) {
5937 themin = themax * 1.e-3;
5938 }
else if (themin > 0)
5941 themin = this.stack[
'fMinimum'];
5942 if (!(
'fHistogram' in this.stack)) {
5943 h = this.stack[
'fHists'].arr[0];
5944 this.stack[
'fHistogram'] = JSROOT.Create(
"TH1I");
5945 this.stack[
'fHistogram'][
'fName'] =
"unnamed";
5946 this.stack[
'fHistogram'][
'fXaxis'] = JSROOT.clone(h[
'fXaxis']);
5947 this.stack[
'fHistogram'][
'fYaxis'] = JSROOT.clone(h[
'fYaxis']);
5948 this.stack[
'fHistogram'][
'fXaxis'][
'fXmin'] = xmin;
5949 this.stack[
'fHistogram'][
'fXaxis'][
'fXmax'] = xmax;
5950 this.stack[
'fHistogram'][
'fYaxis'][
'fXmin'] = ymin;
5951 this.stack[
'fHistogram'][
'fYaxis'][
'fXmax'] = ymax;
5953 this.stack[
'fHistogram'][
'fTitle'] = this.stack[
'fTitle'];
5955 var histo = this.stack[
'fHistogram'];
5956 if (!histo.TestBit(JSROOT.TH1StatusBits.kIsZoomed)) {
5957 if (this.nostack && this.stack[
'fMaximum'] != -1111)
5958 histo[
'fMaximum'] = this.stack[
'fMaximum'];
5960 if (pad && pad[
'fLogy'])
5961 histo[
'fMaximum'] = themax * (1 + 0.2 * JSROOT.Math.log10(themax / themin));
5963 histo[
'fMaximum'] = 1.05 * themax;
5965 if (this.nostack && this.stack[
'fMinimum'] != -1111)
5966 histo[
'fMinimum'] = this.stack[
'fMinimum'];
5968 if (pad && pad[
'fLogy'])
5969 histo[
'fMinimum'] = themin / (1 + 0.5 * JSROOT.Math.log10(themax / themin));
5971 histo[
'fMinimum'] = themin;
5976 var hopt = histo[
'fOption'];
5977 if ((opt !=
"") && (hopt.indexOf(opt) == -1))
5980 if (histo[
'_typename'].match(/^TH1/))
5981 this.firstpainter = JSROOT.Painter.drawHistogram1D(
this.divid, histo, hopt);
5983 if (histo[
'_typename'].match(/^TH2/))
5984 this.firstpainter = JSROOT.Painter.drawHistogram2D(this.divid, histo, hopt);
5987 for (var i = 0; i < nhists; ++i) {
5991 h = this.stack[
'fStack'].arr[nhists - i - 1];
5993 var hopt = h[
'fOption'];
5994 if ((opt !=
"") && (hopt.indexOf(opt) == -1)) hopt += opt;
5997 if (h[
'_typename'].match(/^TH1/)) {
5998 var subpainter = JSROOT.Painter.drawHistogram1D(this.divid, h, hopt);
5999 this.painters.push(subpainter);
6004 JSROOT.THStackPainter.prototype.UpdateObject =
function(obj) {
6006 if (this.firstpainter)
6007 if (this.firstpainter.UpdateObject(obj[
'fHistogram'])) isany =
true;
6009 var histos = obj[
'fHists'];
6010 var nhists = histos.arr.length;
6012 for (var i = 0; i < nhists; ++i) {
6018 h = obj[
'fStack'].arr[nhists - i - 1];
6020 if (this.painters[i].UpdateObject(h)) isany =
true;
6027 JSROOT.Painter.drawHStack =
function(divid, stack, opt) {
6033 if (!
'fHists' in stack)
return;
6034 if (stack[
'fHists'].arr.length == 0)
return;
6036 var painter =
new JSROOT.THStackPainter(stack);
6037 painter.SetDivId(divid);
6039 painter.drawStack(opt);
6046 JSROOT.TLegendPainter =
function(legend) {
6047 JSROOT.TObjectPainter.call(
this, legend);
6048 this.legend = legend;
6051 JSROOT.TLegendPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
6053 JSROOT.TLegendPainter.prototype.GetObject =
function() {
6057 JSROOT.TLegendPainter.prototype.drawLegend =
function() {
6058 this.RecreateDrawG(
true,
".text_layer");
6060 var svg = this.svg_pad(
true);
6061 var pave = this.legend;
6063 var x = 0, y = 0, w = 0, h = 0;
6064 if (pave[
'fInit'] == 0) {
6065 x = pave[
'fX1'] * Number(svg.attr(
"width"));
6066 y = Number(svg.attr(
"height")) - pave[
'fY1']
6067 * Number(svg.attr(
"height"));
6068 w = (pave[
'fX2'] - pave[
'fX1']) * Number(svg.attr(
"width"));
6069 h = (pave[
'fY2'] - pave[
'fY1']) * Number(svg.attr(
"height"));
6071 x = pave[
'fX1NDC'] * Number(svg.attr(
"width"));
6072 y = Number(svg.attr(
"height")) - pave[
'fY1NDC']
6073 * Number(svg.attr(
"height"));
6074 w = (pave[
'fX2NDC'] - pave[
'fX1NDC']) * Number(svg.attr(
"width"));
6075 h = (pave[
'fY2NDC'] - pave[
'fY1NDC']) * Number(svg.attr(
"height"));
6078 var lwidth = pave[
'fBorderSize'] ? pave[
'fBorderSize'] : 0;
6079 var fill = this.createAttFill(pave);
6080 var lcolor = JSROOT.Painter.createAttLine(pave, lwidth);
6087 .attr(
"transform",
"translate(" + x +
"," + y +
")");
6089 p.append(
"svg:rect")
6095 .style(
"stroke-width", lwidth ? 1 : 0)
6096 .style(
"stroke", lcolor.color);
6098 var tcolor = JSROOT.Painter.root_colors[pave[
'fTextColor']];
6099 var tpos_x = pave[
'fMargin'] * w;
6100 var nlines = pave.fPrimitives.arr.length;
6101 var font = JSROOT.Painter.getFontDetails(pave[
'fTextFont'], h / (nlines * 1.5));
6103 var max_len = 0, mul = 1.4;
6104 for (var j = 0; j < nlines; ++j) {
6105 var line = JSROOT.Painter.translateLaTeX(pave.fPrimitives.arr[j][
'fLabel']);
6106 var lw = tpos_x + font.stringWidth(svg, line);
6107 if (lw > max_len) max_len = lw;
6110 font.size = Math.floor(font.size * 0.95 * (w / max_len));
6111 mul *= 0.95 * (max_len / w);
6113 var x1 = pave[
'fX1NDC'];
6114 var x2 = pave[
'fX2NDC'];
6115 var y1 = pave[
'fY1NDC'];
6116 var y2 = pave[
'fY2NDC'];
6117 var margin = pave[
'fMargin'] * (x2 - x1) / pave[
'fNColumns'];
6118 var yspace = (y2 - y1) / nlines;
6119 var ytext = y2 + 0.5 * yspace;
6120 var boxw = margin * 0.35;
6122 for (var i = 0; i < nlines; ++i) {
6123 var leg = pave.fPrimitives.arr[i];
6124 var lopt = leg[
'fOption'].toLowerCase();
6126 var
string = leg[
'fLabel'];
6128 var pos_y = ((i + 1) * (font.size * mul)) - (font.size / 3);
6129 var tpos_y = (i + 1) * (font.size * mul);
6131 var pos_y = (h * 0.75) - (font.size / 3);
6132 var tpos_y = h * 0.75;
6136 var attmarker = leg;
6139 var mo = leg[
'fObject'];
6141 if ((mo != null) && (typeof mo ==
'object')) {
6142 if (
'fLineColor' in mo) attline = mo;
6143 if (
'fFillColor' in mo) attfill = mo;
6144 if (
'fMarkerColor' in mo) attmarker = mo;
6147 var fill = this.createAttFill(attfill);
6148 var llll = JSROOT.Painter.createAttLine(attline);
6151 .attr(
"class",
"text")
6152 .attr(
"text-anchor",
"start")
6156 .attr(
"fill", tcolor)
6160 if (lopt.indexOf(
'f') != -1) {
6163 var xsym = margin / 2;
6165 var xf =
new Array(4), yf =
new Array(4);
6166 xf[0] = xsym - boxw;
6167 yf[0] = ysym - yspace * 0.35;
6168 xf[1] = xsym + boxw;
6171 yf[2] = ysym + yspace * 0.35;
6174 for (var j = 0; j < 4; j++) {
6175 xf[j] = xf[j] * Number(svg.attr(
"width"));
6176 yf[j] = yf[j] * Number(svg.attr(
"height"));
6178 var ww = xf[1] - xf[0];
6179 var hh = yf[2] - yf[0];
6180 pos_y = pos_y - (hh / 2);
6181 var pos_x = (tpos_x / 2) - (ww / 2);
6183 p.append(
"svg:rect")
6192 if (lopt.indexOf(
'l') != -1) {
6195 var line_length = (0.7 * pave[
'fMargin']) * w;
6196 var pos_x = (tpos_x - line_length) / 2;
6197 p.append(
"svg:line")
6200 .attr(
"x2", pos_x + line_length)
6205 if (lopt.indexOf(
'e') != -1 && (lopt.indexOf(
'l') == -1 || lopt.indexOf(
'f') != -1)) {
6208 if (lopt.indexOf(
'p') != -1) {
6210 var line_length = (0.7 * pave[
'fMargin']) * w;
6211 var pos_x = tpos_x / 2;
6213 var marker = JSROOT.Painter.createAttMarker(attmarker);
6214 p.append(
"svg:path")
6215 .attr(
"transform",
function(d) {
return "translate(" + pos_x +
"," + pos_y +
")"; })
6219 if (lwidth && lwidth > 1) {
6220 p.append(
"svg:line")
6221 .attr(
"x1", w + (lwidth / 2))
6222 .attr(
"y1", lwidth + 1)
6223 .attr(
"x2", w + (lwidth / 2))
6224 .attr(
"y2", h + lwidth - 1)
6226 p.append(
"svg:line")
6227 .attr(
"x1", lwidth + 1)
6228 .attr(
"y1", h + (lwidth / 2))
6229 .attr(
"x2", w + lwidth - 1)
6230 .attr(
"y2", h + (lwidth / 2))
6231 .style(
"stroke", lcolor)
6237 this.AddDrag(
'leg', this.draw_g, {
6238 move :
function(x, y, dx, dy) {
6239 pthis.draw_g.attr(
"transform",
"translate(" + x +
"," + y +
")");
6241 pave[
'fX1NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
6242 pave[
'fX2NDC'] += dx / Number(pthis.svg_pad(
true).attr(
"width"));
6243 pave[
'fY1NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
6244 pave[
'fY2NDC'] -= dy / Number(pthis.svg_pad(
true).attr(
"height"));
6246 resize :
function(width, height) {
6247 pave[
'fX2NDC'] = pave[
'fX1NDC'] + width / Number(pthis.svg_pad(
true).attr(
"width"));
6248 pave[
'fY1NDC'] = pave[
'fY2NDC'] - height / Number(pthis.svg_pad(
true).attr(
"height"));
6255 JSROOT.TLegendPainter.prototype.Redraw =
function() {
6259 JSROOT.Painter.drawLegend =
function(divid, obj, opt) {
6260 var painter =
new JSROOT.TLegendPainter(obj);
6261 painter.SetDivId(divid);
6268 JSROOT.TMultiGraphPainter =
function(mgraph) {
6269 JSROOT.TObjectPainter.call(
this, mgraph);
6270 this.mgraph = mgraph;
6271 this.firstpainter = null;
6272 this.painters =
new Array;
6275 JSROOT.TMultiGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
6277 JSROOT.TMultiGraphPainter.prototype.GetObject =
function() {
6281 JSROOT.TMultiGraphPainter.prototype.UpdateObject =
function(obj) {
6283 if ((obj==null) || (obj[
'_typename'] !=
'TMultiGraph'))
return false;
6285 var histo = obj[
'fHistogram'];
6286 var graphs = obj[
'fGraphs'];
6289 if (this.firstpainter && histo)
6290 if (this.firstpainter.UpdateObject(histo)) isany =
true;
6292 for (var i in graphs.arr) {
6293 if (i>=this.painters.length)
break;
6294 if (this.painters[i].UpdateObject(graphs.arr[i])) isany =
true;
6300 JSROOT.TMultiGraphPainter.prototype.drawMultiGraph =
function(opt) {
6301 var maximum, minimum, rwxmin = 0, rwxmax = 0, rwymin = 0, rwymax = 0, uxmin = 0, uxmax = 0, dx, dy;
6302 var histo = this.mgraph[
'fHistogram'];
6303 var graphs = this.mgraph[
'fGraphs'];
6304 var scalex = 1, scaley = 1;
6305 var logx =
false, logy =
false, logz =
false, gridx =
false, gridy =
false;
6306 var draw_all =
true;
6308 var pad = this.root_pad();
6311 rwxmin = pad.fUxmin;
6312 rwxmax = pad.fUxmax;
6313 rwymin = pad.fUymin;
6314 rwymax = pad.fUymax;
6315 logx = pad[
'fLogx'];
6316 logy = pad[
'fLogy'];
6317 logz = pad[
'fLogz'];
6318 gridx = pad[
'fGridx'];
6319 gridy = pad[
'fGridy'];
6322 minimum = histo[
'fYaxis'][
'fXmin'];
6323 maximum = histo[
'fYaxis'][
'fXmax'];
6325 uxmin = JSROOT.Painter.padtoX(pad, rwxmin);
6326 uxmax = JSROOT.Painter.padtoX(pad, rwxmax);
6329 for (var i = 0; i < graphs.arr.length; ++i) {
6330 var r = graphs.arr[i].ComputeRange();
6331 if ((i==0) || (r.xmin < rwxmin)) rwxmin = r.xmin;
6332 if ((i==0) || (r.ymin < rwymin)) rwymin = r.ymin;
6333 if ((i==0) || (r.xmax > rwxmax)) rwxmax = r.xmax;
6334 if ((i==0) || (r.ymax > rwymax)) rwymax = r.ymax;
6336 if (rwxmin == rwxmax)
6338 if (rwymin == rwymax)
6340 dx = 0.05 * (rwxmax - rwxmin);
6341 dy = 0.05 * (rwymax - rwymin);
6342 uxmin = rwxmin - dx;
6343 uxmax = rwxmax + dx;
6346 rwymin = 0.001 * rwymax;
6347 minimum = rwymin / (1 + 0.5 * JSROOT.Math.log10(rwymax / rwymin));
6348 maximum = rwymax * (1 + 0.2 * JSROOT.Math.log10(rwymax / rwymin));
6350 minimum = rwymin - dy;
6351 maximum = rwymax + dy;
6353 if (minimum < 0 && rwymin >= 0)
6355 if (maximum > 0 && rwymax <= 0)
6358 if (this.mgraph[
'fMinimum'] != -1111)
6359 rwymin = minimum = this.mgraph[
'fMinimum'];
6360 if (this.mgraph[
'fMaximum'] != -1111)
6361 rwymax = maximum = this.mgraph[
'fMaximum'];
6362 if (uxmin < 0 && rwxmin >= 0) {
6363 if (logx) uxmin = 0.9 * rwxmin;
6366 if (uxmax > 0 && rwxmax <= 0) {
6367 if (logx) uxmax = 1.1 * rwxmax;
6369 if (minimum < 0 && rwymin >= 0) {
6370 if (logy) minimum = 0.9 * rwymin;
6372 if (maximum > 0 && rwymax <= 0) {
6373 if (logy) maximum = 1.1 * rwymax;
6375 if (minimum <= 0 && logy)
6376 minimum = 0.001 * maximum;
6377 if (uxmin <= 0 && logx) {
6381 uxmin = 0.001 * uxmax;
6386 histo[
'fYaxis'][
'fXmin'] = rwymin;
6387 histo[
'fYaxis'][
'fXmax'] = rwymax;
6392 histo = JSROOT.Create(
"TH1I");
6393 histo[
'fXaxis'][
'fXmin'] = rwxmin;
6394 histo[
'fXaxis'][
'fXmax'] = rwxmax;
6395 histo[
'fYaxis'][
'fXmin'] = rwymin;
6396 histo[
'fYaxis'][
'fXmax'] = rwymax;
6401 this.firstpainter = JSROOT.Painter.drawHistogram1D(this.divid, histo);
6403 for ( var i in graphs.arr) {
6404 var subpainter = JSROOT.Painter.drawGraph(this.divid, graphs.arr[i]);
6405 this.painters.push(subpainter);
6409 JSROOT.Painter.drawMultiGraph =
function(divid, mgraph, opt) {
6410 var painter =
new JSROOT.TMultiGraphPainter(mgraph);
6411 painter.SetDivId(divid);
6412 painter.drawMultiGraph(opt);
6418 JSROOT.TTextPainter =
function(text) {
6419 JSROOT.TObjectPainter.call(
this, text);
6423 JSROOT.TTextPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
6425 JSROOT.TTextPainter.prototype.GetObject =
function() {
6429 JSROOT.TTextPainter.prototype.drawPaveLabel =
function() {
6431 this.RecreateDrawG(
true,
".text_layer");
6433 var pavelabel = this.text;
6435 var w = Number(this.svg_pad(
true).attr(
"width")),
6436 h = Number(this.svg_pad(
true).attr(
"height"));
6438 var pos_x = pavelabel[
'fX1NDC'] * w;
6439 var pos_y = (1.0 - pavelabel[
'fY1NDC']) * h;
6440 var width = Math.abs(pavelabel[
'fX2NDC'] - pavelabel[
'fX1NDC']) * w;
6441 var height = Math.abs(pavelabel[
'fY2NDC'] - pavelabel[
'fY1NDC']) * h;
6443 var fcolor = this.createAttFill(pavelabel);
6444 var tcolor = JSROOT.Painter.root_colors[pavelabel[
'fTextColor']];
6445 var scolor = JSROOT.Painter.root_colors[pavelabel[
'fShadowColor']];
6450 var align =
'start', halign = Math.round(pavelabel[
'fTextAlign'] / 10);
6451 var baseline =
'bottom', valign = pavelabel[
'fTextAlign'] % 10;
6452 if (halign == 1) align =
'start';
6453 else if (halign == 2) align =
'middle';
6454 else if (halign == 3) align =
'end';
6455 if (valign == 1) baseline =
'bottom';
6456 else if (valign == 2) baseline =
'middle';
6457 else if (valign == 3) baseline =
'top';
6460 case 1: lmargin = pavelabel[
'fMargin'] * width;
break;
6461 case 2: lmargin = width / 2;
break;
6462 case 3: lmargin = width - (pavelabel[
'fMargin'] * width);
break;
6464 var lwidth = pavelabel[
'fBorderSize'] ? pavelabel[
'fBorderSize'] : 0;
6465 var font = JSROOT.Painter.getFontDetails(pavelabel[
'fTextFont'], height / 1.9);
6467 var lcolor = JSROOT.Painter.createAttLine(pavelabel, lwidth);
6469 var pave = this.draw_g
6470 .attr(
"width", width)
6471 .attr(
"height", height)
6472 .attr(
"transform",
"translate(" + pos_x +
"," + pos_y +
")");
6474 pave.append(
"svg:rect")
6477 .attr(
"width", width)
6478 .attr(
"height", height)
6480 .style(
"stroke-width", lwidth ? 1 : 0)
6481 .style(
"stroke", lcolor.color);
6483 var line = JSROOT.Painter.translateLaTeX(pavelabel[
'fLabel']);
6485 var lw = font.stringWidth(this.svg_pad(
true), line);
6486 if (lw > width) font.size = Math.floor(font.size * (width / lw));
6489 .attr(
"class",
"text")
6490 .attr(
"text-anchor", align)
6492 .attr(
"y", (height / 2) + (font.size / 3))
6494 .attr(
"fill", tcolor)
6497 if (lwidth && lwidth > 1) {
6498 pave.append(
"svg:line")
6499 .attr(
"x1", width + (lwidth / 2))
6500 .attr(
"y1", lwidth + 1)
6501 .attr(
"x2", width + (lwidth / 2))
6502 .attr(
"y2", height + lwidth - 1)
6504 pave.append(
"svg:line")
6505 .attr(
"x1", lwidth + 1)
6506 .attr(
"y1", height + (lwidth / 2))
6507 .attr(
"x2", width + lwidth - 1)
6508 .attr(
"y2", height + (lwidth / 2))
6509 .style(
"stroke", lcolor)
6514 JSROOT.TTextPainter.prototype.drawText =
function() {
6515 this.RecreateDrawG(
true,
".text_layer");
6517 var kTextNDC = JSROOT.BIT(14);
6519 var w = Number(this.svg_pad(
true).attr(
"width")),
6520 h = Number(this.svg_pad(
true).attr(
"height"));
6521 var align =
'start', halign = Math.round(this.text[
'fTextAlign'] / 10);
6522 var baseline =
'bottom', valign = this.text[
'fTextAlign'] % 10;
6523 if (halign == 1) align =
'start';
6524 else if (halign == 2) align =
'middle';
6525 else if (halign == 3) align =
'end';
6526 if (valign == 1) baseline =
'bottom';
6527 else if (valign == 2) baseline =
'middle';
6528 else if (valign == 3) baseline =
'top';
6531 case 1: lmargin = this.text[
'fMargin'] * w;
break;
6532 case 2: lmargin = w / 2;
break;
6533 case 3: lmargin = w - (this.text[
'fMargin'] * w);
break;
6535 var pos_x = this.text[
'fX'], pos_y = this.text[
'fY'];
6536 if (this.text.TestBit(kTextNDC)) {
6538 pos_y = (1 - pos_y) * h;
6540 if (this.main_painter()!=null) {
6541 pos_x = this.main_painter().x(pos_x);
6542 pos_y = this.main_painter().y(pos_y);
6544 if (this.root_pad()!=null) {
6545 var pad = this.root_pad();
6547 pos_x = (pos_x > 0) ? JSROOT.Math.log10(pos_x) : pad[
'fUxmin'];
6549 pos_y = (pos_y > 0) ? JSROOT.Math.log10(pos_y) : pad[
'fUymin'];
6551 pos_x = ((Math.abs(pad[
'fX1']) + pos_x) / (pad[
'fX2'] - pad[
'fX1'])) * w;
6552 pos_y = (1 - ((Math.abs(pad[
'fY1']) + pos_y) / (pad[
'fY2'] - pad[
'fY1']))) * h;
6554 alert(
"Cannot draw text at x/y coordinates without real TPad object");
6559 var tcolor = JSROOT.Painter.root_colors[this.text[
'fTextColor']];
6560 var font = JSROOT.Painter.getFontDetails(this.text[
'fTextFont'], this.text[
'fTextSize'] * Math.min(w,h));
6562 var
string = this.text[
'fTitle'];
6564 if (this.text[
'_typename'] ==
'TLatex')
6565 string = JSROOT.Painter.translateLaTeX(
string);
6567 this.draw_g.append(
"text")
6568 .attr(
"class",
"text")
6569 .attr(
"x", pos_x.toFixed(1))
6570 .attr(
"y", pos_y.toFixed(1))
6572 .attr(
"text-anchor", align)
6573 .attr(
"fill", tcolor)
6577 JSROOT.TTextPainter.prototype.UpdateObject =
function(obj) {
6578 if (this.text[
'_typename'] != obj[
'_typename'])
return false;
6579 if (this.text[
'_typename'] ==
'TPaveLabel') {
6580 this.text[
'fLabel'] = obj[
'fLabel'];
6582 this.text[
'fTitle'] = obj[
'fTitle'];
6589 JSROOT.TTextPainter.prototype.Redraw =
function() {
6590 if (this.text[
'_typename'] ==
'TPaveLabel')
6591 this.drawPaveLabel();
6596 JSROOT.Painter.drawText =
function(divid, text) {
6597 var painter =
new JSROOT.TTextPainter(text);
6598 painter.SetDivId(divid);
6603 JSROOT.Painter.drawStreamerInfo =
function(divid, obj) {
6604 $(
"#" + divid).css({ overflow :
'auto' });
6605 var painter =
new JSROOT.HierarchyPainter(
'sinfo', divid,
true);
6606 painter.ShowStreamerInfo(obj);
6614 JSROOT.DelHList =
function(_name) {
6615 for ( var i in JSROOT.HList)
6616 if (JSROOT.HList[i].name == _name) {
6617 var old = JSROOT.HList[i];
6618 JSROOT.HList.splice(i, 1);
6624 JSROOT.AddHList =
function(_name, _h) {
6625 JSROOT.DelHList(_name);
6632 JSROOT.H =
function(name) {
6633 for ( var i in JSROOT.HList)
6634 if (JSROOT.HList[i].name == name)
6635 return JSROOT.HList[i].h;
6639 JSROOT.HierarchyPainter =
function(name, frameid, local) {
6640 JSROOT.TBasePainter.call(
this);
6642 this.frameid = frameid;
6645 if (!this.local) JSROOT.AddHList(name,
this);
6648 JSROOT.HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
6650 JSROOT.HierarchyPainter.prototype.Cleanup =
function() {
6651 if (!this.local) JSROOT.DelHList(this.name);
6654 JSROOT.HierarchyPainter.prototype.GlobalName =
function(suffix) {
6655 var res =
"JSROOT.H(\'" + this.name +
"\')";
6656 if (suffix != null) res += suffix;
6660 JSROOT.HierarchyPainter.prototype.ListHierarchy =
function(folder, lst) {
6661 folder[
'_childs'] = [];
6662 for ( var i in lst.arr) {
6663 var obj = lst.arr[i];
6665 _name : obj[
'fName'],
6666 _kind :
"ROOT." + obj[
'_typename'],
6669 folder._childs.push(item);
6673 JSROOT.HierarchyPainter.prototype.StreamerInfoHierarchy =
function(folder, lst) {
6674 folder[
'_childs'] = [];
6676 for ( var i in lst.arr) {
6677 var entry = lst.arr[i]
6679 if (typeof (entry[
'fName']) ==
'undefined') {
6680 console.log(
"strange element in StreamerInfo with name " + entry[
'fName']);
6685 _name : entry[
'fName'],
6690 folder._childs.push(item);
6692 item._childs.push({ _name :
'Checksum: ' + entry[
'fCheckSum'] });
6693 item._childs.push({ _name :
'Class version: ' + entry[
'fClassVersion'] });
6694 if (entry[
'fTitle'] !=
'') item._childs.push({ _name :
'Title: ' + entry[
'fTitle'] });
6695 if (typeof entry[
'fElements'] ==
'undefined')
continue;
6696 for ( var l in entry[
'fElements'][
'arr']) {
6697 var elem = entry[
'fElements'][
'arr'][l];
6698 if ((elem == null) || (typeof (elem[
'fName']) ==
'undefined'))
continue;
6699 var info = elem[
'fTypeName'] +
" " + elem[
'fName'] +
";";
6700 if (elem[
'fTitle'] !=
'') info +=
" // " + elem[
'fTitle'];
6701 item._childs.push({ _name : info });
6706 JSROOT.HierarchyPainter.prototype.TreeHierarchy =
function(node, obj) {
6709 for ( var i in obj[
'fBranches'].arr) {
6710 var branch = obj[
'fBranches'].arr[i];
6711 var nb_leaves = branch[
'fLeaves'].arr.length;
6714 if (nb_leaves == 1 && branch[
'fLeaves'].arr[0][
'fName'] == branch[
'fName']) nb_leaves = 0;
6717 _name : branch[
'fName'],
6718 _kind : nb_leaves > 0 ?
"ROOT.TBranch" :
"ROOT.TLeafF"
6721 node._childs.push(subitem);
6723 if (nb_leaves > 0) {
6724 subitem._childs = [];
6725 for (var j = 0; j < nb_leaves; ++j) {
6727 _name : branch[
'fLeaves'].arr[j][
'fName'],
6728 _kind :
"ROOT.TLeafF"
6730 subitem._childs.push(leafitem);
6736 JSROOT.HierarchyPainter.prototype.KeysHierarchy =
function(folder, keys, file) {
6737 folder[
'_childs'] = [];
6740 for (var i in keys) {
6744 _name : key[
'fName'] +
";" + key[
'fCycle'],
6745 _kind :
"ROOT." + key[
'fClassName'],
6746 _title : key[
'fTitle'],
6747 _keyname : key[
'fName'],
6751 if (
'fRealName' in key)
6752 item[
'_realname'] = key[
'fRealName'] +
";" + key[
'fCycle'];
6754 if ((key[
'fClassName'] ==
'TTree' || key[
'fClassName'] ==
'TNtuple')) {
6755 item[
"_more"] =
true;
6757 item[
'_expand'] =
function(node, obj) {
6758 painter.TreeHierarchy(node, obj);
6761 }
else if (key[
'fClassName'] ==
'TDirectory' || key[
'fClassName'] ==
'TDirectoryFile') {
6762 item[
"_more"] =
true;
6763 item[
"_isdir"] =
true;
6764 item[
'_expand'] =
function(node, obj) {
6765 painter.KeysHierarchy(node, obj.fKeys);
6768 }
else if ((key[
'fClassName'] ==
'TList') && (key[
'fName'] ==
'StreamerInfo') && (file != null)) {
6769 item[
'_name'] =
'StreamerInfo';
6770 item[
'_kind'] =
"ROOT.TStreamerInfoList";
6771 item[
'_title'] =
"List of streamer infos for binary I/O";
6772 item[
'_readobj'] = file.fStreamerInfos;
6773 item[
'_expand'] =
function(node, obj) {
6774 painter.StreamerInfoHierarchy(node, obj);
6778 }
else if (key[
'fClassName'] ==
'TList'
6779 || key[
'fClassName'] ==
'TObjArray'
6780 || key[
'fClassName'] ==
'TClonesArray') {
6781 item[
"_more"] =
true;
6782 item[
'_expand'] =
function(node, obj) {
6783 painter.ListHierarchy(node, obj);
6788 folder._childs.push(item);
6792 JSROOT.HierarchyPainter.prototype.FileHierarchy =
function(file) {
6796 _name : file.fFileName,
6797 _kind :
"ROOT.TFile",
6800 _get :
function(item, callback) {
6801 if ((this._file == null) || (item._readobj != null)) {
6802 if (typeof callback ==
'function')
6803 callback(item, item._readobj);
6807 var fullname = painter.itemFullName(item,
this);
6811 this._file.ReadObject(fullname,
function(obj) {
6812 item._readobj = obj;
6813 if (
'_expand' in item)
6814 item._name = item._keyname;
6816 if (typeof callback ==
'function')
6817 callback(item, obj);
6822 _getdirect :
function(itemname, callback) {
6823 this._file.ReadObject(itemname,
function(obj) {
6824 if (typeof callback ==
'function')
6825 callback(itemname, obj);
6830 this.KeysHierarchy(folder, file.fKeys, file);
6835 JSROOT.HierarchyPainter.prototype.Find =
function(itemname, force) {
6837 function find_in_hierarchy(top, fullname) {
6839 if (!fullname || fullname.length == 0)
return top;
6843 function process_child(child) {
6845 child[
'_parent'] = top;
6846 if ((pos + 1 == fullname.length) || (pos < 0))
return child;
6848 return find_in_hierarchy(child, fullname.substr(pos + 1));
6853 pos = fullname.indexOf(
"/", pos + 1);
6855 var localname = (pos < 0) ? fullname : fullname.substr(0, pos);
6857 for (var i in top._childs)
6858 if (top._childs[i]._name == localname)
6859 return process_child(top._childs[i]);
6863 if (! (
'_childs' in top)) top[
'_childs'] = [];
6864 var child = { _name: localname };
6865 top[
'_childs'].push(child);
6866 return process_child(child);
6873 return find_in_hierarchy(this.h, itemname);
6876 JSROOT.HierarchyPainter.prototype.itemFullName =
function(node, uptoparent) {
6879 while (
'_parent' in node) {
6880 if (res.length > 0) res =
"/" + res;
6881 res = node._name + res;
6882 node = node._parent;
6883 if ((uptoparent != null) && (node == uptoparent))
break;
6889 JSROOT.HierarchyPainter.prototype.CheckCanDo =
function(node) {
6890 var cando = { expand :
false, display :
false, scan :
true, open :
false,
6891 img1 :
"", img2 :
"", html :
"", ctxt :
false };
6893 var kind = node[
"_kind"];
6894 if (kind == null) kind =
"";
6896 cando.expand = (
'_more' in node);
6898 if (node == this.h) {
6900 }
else if (kind ==
"ROOT.Session") {
6901 cando.img1 =
"img_globe";
6902 }
else if (kind.match(/^ROOT.TH1/)) {
6903 cando.img1 =
"img_histo1d";
6905 cando.display =
true;
6906 }
else if (kind.match(/^ROOT.TH2/)) {
6907 cando.img1 =
"img_histo2d";
6909 cando.display =
true;
6910 }
else if (kind.match(/^ROOT.TH3/)) {
6911 cando.img1 =
"img_histo3d";
6913 cando.display =
true;
6914 }
else if (kind ==
"ROOT.TCanvas") {
6915 cando.img1 =
"img_canvas";
6916 cando.display =
true;
6917 }
else if (kind ==
"ROOT.TProfile") {
6918 cando.img1 =
"img_profile";
6919 cando.display =
true;
6920 }
else if (kind.match(/^ROOT.TGraph/) || (kind==
"TCutG")) {
6921 cando.img1 =
"img_graph";
6922 cando.display =
true;
6923 }
else if (kind ==
"ROOT.TF1") {
6924 cando.img1 =
"img_graph";
6925 cando.display =
true;
6926 }
else if (kind ==
"ROOT.TTree") {
6927 cando.img1 =
"img_tree";
6928 }
else if (kind ==
"ROOT.TFolder") {
6929 cando.img1 =
"img_folder";
6930 cando.img2 =
"img_folderopen";
6931 }
else if (kind ==
"ROOT.TNtuple")
6932 cando.img1 =
"img_tree";
6933 else if (kind ==
"ROOT.TBranch")
6934 cando.img1 =
"img_branch";
6935 else if (kind.match(/^ROOT.TLeaf/))
6936 cando.img1 =
"img_leaf";
6937 else if (kind ==
"ROOT.TStreamerInfoList") {
6938 cando.img1 =
'img_question';
6939 cando.expand =
false;
6940 cando.display =
true;
6941 }
else if ((kind.indexOf(
"ROOT.") == 0) && JSROOT.canDraw(kind.slice(5))) {
6942 cando.img1 =
"img_histo1d";
6944 cando.display =
true;
6950 JSROOT.HierarchyPainter.prototype.RefreshHtml =
function(force) {
6951 if (this.frameid == null)
return;
6952 var elem = $(
"#" + this.frameid);
6953 if (elem.length == 0)
return;
6955 if (this.h == null)
return elem.html(
"<h2>null</h2>");
6957 this[
'html'] =
"<p>";
6959 this[
'html'] +=
"<a href='#open_all'>open all</a>";
6960 this[
'html'] +=
"| <a href='#close_all'>close all</a>";
6961 if (
'_online' in this.h)
6962 this[
'html'] +=
"| <a href='#reload'>reload</a>";
6964 this[
'html'] +=
"<a/>"
6966 if (
'disp_kind' in
this)
6967 this[
'html'] +=
"| <a href='#clear'>clear</a>";
6969 this[
'html'] +=
"<a/>"
6971 this[
'html'] +=
"</p>";
6973 this[
'html'] +=
'<div class="h_tree">'
6974 this.addItemHtml(this.h, null);
6975 this[
'html'] +=
'</div>';
6979 var items = elem.html(
this[
'html'])
6981 .click(
function() { h.tree_click($(
this)); });
6983 if (
'disp_kind' in h) {
6984 if (JSROOT.gStyle.DragAndDrop)
6985 items.draggable({ revert:
"invalid", appendTo:
"body", helper:
"clone" });
6987 if (JSROOT.gStyle.ContextMenu)
6988 items.on(
'contextmenu',
function(e) { h.tree_contextmenu($(
this), e); })
6991 elem.find(
".plus_minus").click(
function() { h.tree_click($(
this),
true); });
6993 elem.find(
"a").first().click(
function() { h.toggle(
true);
return false; })
6994 .next().click(
function() { h.toggle(
false);
return false; })
6995 .next().click(
function() { h.reload();
return false; })
6996 .next().click(
function() { h.clear();
return false; });
6999 JSROOT.HierarchyPainter.prototype.isLastSibling =
function(hitem) {
7000 return hitem && hitem._parent && hitem._parent._childs &&
7001 (hitem._parent._childs.indexOf(hitem) == hitem._parent._childs.length-1);
7004 JSROOT.HierarchyPainter.prototype.addItemHtml =
function(hitem, parent) {
7005 var isroot = (parent == null);
7006 var has_childs =
'_childs' in hitem;
7007 var cando = this.CheckCanDo(hitem);
7009 if (!isroot) hitem._parent = parent;
7011 var can_click =
false;
7013 if (!has_childs || !cando.scan) {
7016 if (cando.img1.length == 0) {
7017 cando.img1 =
'img_folder';
7018 cando.img2 =
'img_folderopen';
7021 if (cando.display) {
7024 if (cando.html.length > 0) can_click =
true;
7027 if (!(
'_icon' in hitem)) hitem[
'_icon'] = cando.img1;
7028 if (!(
'_icon2' in hitem)) hitem[
'_icon2'] = cando.img2;
7029 if (hitem[
'_icon2']==
"") hitem[
'_icon2'] = hitem[
'_icon'];
7033 if (!hitem[
'_icon'])
7034 hitem[
'_icon'] = has_childs ?
"img_folder" :
"img_page";
7036 if (!hitem[
'_icon2'])
7037 hitem[
'_icon2'] = has_childs ?
"img_folderopen" :
"img_page";
7040 hitem[
'_icon'] = hitem[
'_icon2'] =
"img_base";
7042 var itemname = this.itemFullName(hitem);
7044 this[
'html'] +=
'<div item="' + itemname +
'">';
7048 var prnt = isroot ? null : hitem._parent;
7049 while ((prnt != null) && (prnt != this.h)) {
7050 sindent =
'<div class="' + (this.isLastSibling(prnt) ?
"img_empty" :
"img_line") +
'"/>' + sindent;
7051 prnt = prnt._parent;
7053 this[
'html'] += sindent;
7055 var icon_class =
"", plusminus =
false;
7061 icon_class = hitem._isopen ?
"img_minus" :
"img_plus";
7064 icon_class =
"img_join";
7067 if (icon_class.length > 0) {
7068 this[
'html'] +=
'<div class="' + icon_class;
7069 if (this.isLastSibling(hitem))
this[
'html'] +=
"bottom";
7070 if (plusminus)
this[
'html'] +=
' plus_minus" style="cursor:pointer';
7071 this[
'html'] +=
'"/>';
7076 var icon_name = hitem._isopen ? hitem._icon2 : hitem._icon;
7078 if (icon_name.indexOf(
"img_")==0)
7079 this[
'html'] +=
'<div class="' + icon_name +
'"/>';
7081 this[
'html'] +=
'<img src="' + icon_name +
'" alt=""/>';
7083 this[
'html'] +=
'<a';
7084 if (can_click || has_childs)
this[
'html'] +=
' class="h_item"';
7086 var element_name = hitem._name;
7088 if (
'_realname' in hitem)
7089 element_name = hitem._realname;
7091 var element_title =
"";
7092 if (
'_title' in hitem) element_title = hitem._title;
7094 if (
'_fullname' in hitem)
7095 element_title +=
" fullname: " + hitem[
'_fullname'];
7097 if (element_title.length == 0) element_title = element_name;
7099 this[
'html'] +=
' title="' + element_title +
'"';
7100 this[
'html'] +=
'>' + element_name +
'</a>';
7102 if (has_childs && (isroot || hitem._isopen)) {
7103 this[
'html'] +=
'<div class="h_childs">';
7104 for (var i in hitem._childs)
7105 this.addItemHtml(hitem._childs[i], hitem);
7106 this[
'html'] +=
'</div>';
7109 this[
'html'] +=
'</div>';
7112 JSROOT.HierarchyPainter.prototype.tree_click =
function(node, plusminus) {
7114 var itemname = node.parent().attr(
'item');
7116 if (itemname==null)
return;
7118 var hitem = this.Find(itemname);
7119 if (hitem==null)
return;
7122 var cando = this.CheckCanDo(hitem);
7124 if (cando.open && (cando.html.length>0))
7125 return window.open(cando.html);
7127 if (cando.expand && (hitem[
'_childs'] == null))
7128 return this.expand(itemname, hitem, node.parent());
7131 return this.display(itemname);
7133 if (!(
'_childs' in hitem) || (hitem === this.h))
return;
7137 delete hitem._isopen;
7139 hitem._isopen =
true;
7141 this.UpdateTreeNode(node.parent(), hitem);
7144 JSROOT.HierarchyPainter.prototype.open =
function(itemname) {
7145 console.log(
"open() no longer available");
7148 JSROOT.HierarchyPainter.prototype.UpdateTreeNode =
function(node, hitem) {
7149 var has_childs =
'_childs' in hitem;
7151 var newname = hitem._isopen ? hitem._icon2 : hitem._icon;
7152 var oldname = hitem._isopen ? hitem._icon : hitem._icon2;
7154 var img = node.find(
"a").first().prev();
7156 if (newname.indexOf(
"img_")<0) {
7157 img.attr(
"src", newname);
7159 if (newname!=oldname)
7160 img.switchClass(oldname, newname);
7167 var new_class = hitem._isopen ?
"img_minus" :
"img_plus";
7168 if (this.isLastSibling(hitem)) new_class +=
"bottom";
7170 if (img.hasClass(
"plus_minus")) {
7171 img.attr(
'class', new_class +
" plus_minus");
7174 img.attr(
'class', new_class +
" plus_minus");
7175 img.css(
'cursor',
'pointer');
7176 img.click(
function() { h.tree_click($(
this),
true); });
7179 var childs = node.children().last();
7180 if (childs.hasClass(
"h_childs")) childs.remove();
7182 var display_childs = has_childs && hitem._isopen;
7183 if (!display_childs)
return;
7185 this[
'html'] =
'<div class="h_childs">';
7186 for (var i in hitem._childs)
7187 this.addItemHtml(hitem._childs[i], hitem);
7188 this[
'html'] +=
'</div>';
7189 node.append(
this[
'html']);
7190 childs = node.children().last();
7192 var items = childs.find(
".h_item")
7193 .click(
function() { h.tree_click($(
this)); });
7195 if (
'disp_kind' in h) {
7196 if (JSROOT.gStyle.DragAndDrop)
7197 items.draggable({ revert:
"invalid", appendTo:
"body", helper:
"clone" });
7199 if (JSROOT.gStyle.ContextMenu)
7200 items.on(
'contextmenu',
function(e) { h.tree_contextmenu($(
this), e); })
7203 childs.find(
".plus_minus").click(
function() { h.tree_click($(
this),
true); });
7206 JSROOT.HierarchyPainter.prototype.toggle =
function(status) {
7209 var toggleItem =
function(hitem) {
7211 if (hitem != painter.h)
7213 hitem._isopen =
true;
7215 delete hitem._isopen;
7217 if (
'_childs' in hitem)
7218 for ( var i in hitem._childs)
7219 toggleItem(hitem._childs[i]);
7227 JSROOT.HierarchyPainter.prototype.get =
function(itemname, callback, options) {
7228 var item = this.Find(itemname);
7231 if ((item == null) && (
'_getdirect' in this.h))
7232 return this.h._getdirect(itemname, callback);
7236 while (curr != null) {
7237 if ((
'_get' in curr) && (typeof (curr._get) ==
'function'))
7238 return curr._get(item, callback);
7239 curr = (
'_parent' in curr) ? curr[
'_parent'] : null;
7242 if (typeof callback ==
'function')
7243 callback(item, null);
7246 JSROOT.HierarchyPainter.prototype.draw =
function(divid, obj, drawopt) {
7248 return JSROOT.draw(divid, obj, drawopt);
7251 JSROOT.HierarchyPainter.prototype.display =
function(itemname, drawopt, call_back) {
7253 function do_call_back(res) {
7254 if (typeof call_back==
'function') call_back(res);
7257 if (!this.CreateDisplay())
return do_call_back(null);
7261 var mdi = h[
'disp'];
7263 var updating = drawopt==
"update";
7266 var item = h.Find(itemname);
7267 if ((item==null) || (
'_doing_update' in item))
return do_call_back(null);
7268 item[
'_doing_update'] =
true;
7271 h.get(itemname,
function(item, obj) {
7273 if (updating)
delete item[
'_doing_update'];
7274 if (obj==null)
return do_call_back(null);
7278 var pos = drawopt ? drawopt.indexOf(
"divid:") : -1;
7280 var divid = drawopt.slice(pos+6);
7281 drawopt = drawopt.slice(0, pos);
7282 painter = h.draw(divid, obj, drawopt);
7284 mdi.ForEachPainter(
function(p, frame) {
7285 if (p[
'_hitemname'] != itemname)
return;
7287 mdi.ActivateFrame(frame);
7288 painter.RedrawObject(obj);
7291 if (painter==null) {
7293 console.log(
"something went wrong - did not found painter when doing update of " + itemname);
7295 var frame = mdi.FindFrame(itemname,
true);
7296 if (JSROOT.gStyle.DragAndDrop)
7297 frame.addClass(
"ui-state-default");
7298 painter = h.draw(frame.attr(
"id"), obj, drawopt);
7300 mdi.ActivateFrame(frame);
7302 if (JSROOT.gStyle.DragAndDrop)
7304 hoverClass :
"ui-state-active",
7305 accept:
function(ui) {
7306 var dropname = ui.parent().attr(
'item');
7307 if (dropname == itemname)
return false;
7309 var ditem = h.Find(dropname);
7310 if (ditem==null)
return false;
7312 return ditem._kind.indexOf(
"ROOT.")==0;
7314 drop:
function(event, ui) {
7315 var dropname = ui.draggable.parent().attr(
'item');
7316 return h.dropitem(dropname, frame.attr(
"id"));
7322 if (painter) painter[
'_hitemname'] = itemname;
7324 do_call_back(painter);
7328 JSROOT.HierarchyPainter.prototype.dropitem =
function(itemname, divid) {
7330 var mdi = h[
'disp'];
7332 h.get(itemname,
function(item, obj) {
7333 if (obj==null)
return;
7334 var painter = h.draw(divid, obj,
"same");
7335 if (painter) painter[
'_hitemname'] = itemname;
7342 JSROOT.HierarchyPainter.prototype.updateAll =
function() {
7345 var mdi =
this[
'disp'];
7346 if (mdi == null)
return;
7351 mdi.ForEachPainter(
function(p) {
7352 if ((
'_hitemname' in p) && (allitems.indexOf(p[
'_hitemname'])<0)) allitems.push(p[
'_hitemname']);
7356 for (var cnt in allitems)
7357 this.display(allitems[cnt],
"update");
7360 JSROOT.HierarchyPainter.prototype.displayAll =
function(items, options) {
7361 if ((items == null) || (items.length == 0))
return;
7362 if (!this.CreateDisplay())
return;
7363 if (options == null) options = [];
7364 while (options.length < items.length)
7367 var mdi =
this[
'disp'];
7369 var dropitems =
new Array(items.length);
7372 for (var i in items) {
7373 if (this.Find(items[i]))
continue;
7374 if (this.Find(items[i] +
";1")) { items[i] +=
";1";
continue; }
7376 var pos = items[i].indexOf(
"+");
7377 if ((pos>0) && this.Find(items[i].slice(0,pos))) {
7378 dropitems[i] = items[i].slice(pos+1);
7379 items[i] = items[i].slice(0,pos);
7384 for (var i in items)
7385 mdi.CreateFrame(items[i]);
7390 for (var i in items)
7391 this.display(items[i], options[i],
function(painter) {
7392 if ((painter==0) || (dropitems[i]==null))
return;
7393 h.dropitem(dropitems[i], painter.divid);
7397 JSROOT.HierarchyPainter.prototype.reload =
function() {
7398 if (
'_online' in this.h)
7399 this.OpenOnline(this.h[
'_online']);
7402 JSROOT.HierarchyPainter.prototype.expand =
function(itemname, item0, node) {
7406 node = $(
"#" + this.frameid).find(
"[item='" + itemname +
"']");
7409 return console.log(
"Did not found node with item = " + itemname);
7411 if (item0==null) item0 = this.Find(itemname);
7412 if (item0==null)
return;
7413 item0[
'_doing_expand'] =
true;
7415 this.
get(itemname,
function(item, obj) {
7416 delete item0[
'_doing_expand'];
7417 if ((item == null) || (obj == null))
return;
7420 while (curr != null) {
7421 if ((
'_expand' in curr) && (typeof (curr[
'_expand']) ==
'function')) {
7422 if (curr[
'_expand'](item, obj)) {
7423 var itemname = painter.itemFullName(item);
7424 node.attr(
'item', itemname);
7425 node.find(
"a").text(item._name);
7426 item._isopen =
true;
7427 painter.UpdateTreeNode(node, item);
7431 curr = (
'_parent' in curr) ? curr[
'_parent'] : null;
7436 JSROOT.HierarchyPainter.prototype.OpenRootFile =
function(filepath, andThan) {
7439 var f =
new JSROOT.TFile(filepath,
function(file) {
7440 if (file == null)
return;
7442 pthis.h = pthis.FileHierarchy(file);
7444 pthis.RefreshHtml();
7446 if (typeof andThan ==
'function') andThan();
7450 JSROOT.HierarchyPainter.prototype.GetFileProp =
function(itemname) {
7451 var item = this.Find(itemname);
7452 if (item == null)
return null;
7454 var subname = item._name;
7455 while (item._parent != null) {
7456 item = item._parent;
7457 if (
'_file' in item) {
7459 fileurl : item._file.fURL,
7463 subname = item._name +
"/" + subname;
7469 JSROOT.HierarchyPainter.prototype.CompleteOnline =
function(ready_callback) {
7476 JSROOT.HierarchyPainter.prototype.OpenOnline =
function(server_address, user_callback) {
7477 if (!server_address) server_address =
"";
7481 var req = JSROOT.NewHttpRequest(server_address +
"h.json?compact=3",
'object',
function(result) {
7483 if (painter.h == null)
return;
7486 painter.h[
'_online'] = server_address;
7488 painter.h[
'_get'] =
function(item, callback) {
7490 var url = painter.itemFullName(item);
7491 if (url.length > 0) url +=
"/";
7492 var h_get = (
'_more' in item) || (
'_doing_expand' in item);
7493 url += h_get ?
'h.json?compact=3' :
'root.json.gz?compact=3';
7495 var itemreq = JSROOT.NewHttpRequest(url,
'object',
function(obj) {
7496 if ((obj != null) && !h_get && (item._name ===
"StreamerInfo")
7497 && (obj[
'_typename'] ===
'TList'))
7498 obj[
'_typename'] =
'TStreamerInfoList';
7500 if (typeof callback ==
'function')
7501 callback(item, obj);
7507 painter.h[
'_expand'] =
function(node, obj) {
7510 if ((obj != null) && (node != null) && (
'_childs' in obj)) {
7511 node._childs = obj._childs;
7518 painter.CompleteOnline(
function() {
7519 if (painter.h != null)
7520 painter.RefreshHtml(
true);
7522 if (typeof user_callback ==
'function')
7523 user_callback(painter);
7530 JSROOT.HierarchyPainter.prototype.GetOnlineProp =
function(itemname) {
7531 var item = this.Find(itemname);
7532 if (item == null)
return null;
7534 var subname = item._name;
7535 while (item._parent != null) {
7536 item = item._parent;
7538 if (
'_online' in item) {
7540 server : item[
'_online'],
7544 subname = item._name +
"/" + subname;
7550 JSROOT.HierarchyPainter.prototype.FillOnlineMenu =
function(menu, onlineprop, itemname) {
7554 var node = this.Find(itemname);
7555 var cando = this.CheckCanDo(node);
7558 JSROOT.Painter.menuitem(menu,
"Draw",
function() { painter.display(itemname); });
7560 if (cando.expand || cando.display)
7561 JSROOT.Painter.menuitem(menu,
"Expand",
function() { painter.expand(itemname); });
7563 var drawurl = onlineprop.server + onlineprop.itemname +
"/draw.htm";
7564 if (this.IsMonitoring())
7565 drawurl +=
"?monitoring=" + this.MonitoringInterval();
7568 JSROOT.Painter.menuitem(menu,
"Draw in new window",
function() { window.open(drawurl); });
7571 JSROOT.Painter.menuitem(menu,
"Draw as png",
function() {
7572 window.open(onlineprop.server + onlineprop.itemname +
"/root.png?w=400&h=300&opt=");
7576 JSROOT.HierarchyPainter.prototype.ShowStreamerInfo =
function(sinfo) {
7577 this.h = { _name :
"StreamerInfo" };
7578 this.StreamerInfoHierarchy(this.h, sinfo);
7582 JSROOT.HierarchyPainter.prototype.Adopt =
function(h) {
7587 JSROOT.HierarchyPainter.prototype.MonitoringInterval =
function() {
7589 var monitor =
this[
'_monitoring_interval'];
7590 if (monitor == null) {
7591 monitor = JSROOT.GetUrlOption(
"monitoring");
7592 if ((monitor ==
"") || (monitor==null)) monitor = 3000;
7593 else monitor = parseInt(monitor);
7594 if ((monitor == NaN) || (monitor<=0)) monitor = 3000;
7595 this[
'_monitoring_interval'] = monitor;
7600 JSROOT.HierarchyPainter.prototype.EnableMonitoring =
function(on) {
7601 this[
'_monitoring_on'] = on;
7604 JSROOT.HierarchyPainter.prototype.IsMonitoring =
function() {
7605 return this[
'_monitoring_on'];
7608 JSROOT.HierarchyPainter.prototype.tree_contextmenu =
function(node, event) {
7609 event.preventDefault();
7611 var itemname = node.parent().attr(
'item');
7613 var hitem = this.Find(itemname);
7614 if (hitem==null)
return;
7616 var cando = this.CheckCanDo(hitem);
7618 if (!cando.display && !cando.ctxt && (itemname!=
""))
return;
7620 var onlineprop = this.GetOnlineProp(itemname);
7621 var fileprop = this.GetFileProp(itemname);
7623 var menu = JSROOT.Painter.createmenu(event);
7625 function qualifyURL(url) {
7626 function escapeHTML(s) {
7627 return s.split(
'&').join(
'&').split(
'<').join(
'<').split(
'"').join(
'"');
7629 var el = document.createElement(
'div');
7630 el.innerHTML =
'<a href="' + escapeHTML(url) +
'">x</a>';
7631 return el.firstChild.href;
7636 if (itemname ==
"") {
7638 if (
'_online' in this.h) {
7640 if (this.IsMonitoring())
7641 addr +=
"monitoring=" + this.MonitoringInterval();
7642 }
else if (
'_file' in this.h) {
7643 addr = JSROOT.source_dir +
"index.htm?";
7644 addr +=
"file=" + this.h[
'_file'].fURL;
7647 if (
this[
'disp_kind']) {
7648 if (addr.length > 2) addr +=
"&";
7649 addr +=
"layout=" +
this[
'disp_kind'].replace(/ /g,
"");
7654 if (
this[
'disp'] != null)
7655 this[
'disp'].ForEachPainter(
function(painter) {
7656 if (
'_hitemname' in painter)
7657 items.push(painter[
'_hitemname']);
7660 if (items.length == 1) {
7661 if (addr.length > 2) addr +=
"&";
7662 addr +=
"item=" + items[0];
7663 }
else if (items.length > 1) {
7664 if (addr.length > 2) addr +=
"&";
7665 addr +=
"items=" + JSON.stringify(items);
7668 JSROOT.Painter.menuitem(menu,
"Direct link",
function() { window.open(addr); });
7669 JSROOT.Painter.menuitem(menu,
"Only items",
function() { window.open(addr +
"&nobrowser"); });
7671 if (onlineprop != null) {
7672 this.FillOnlineMenu(menu, onlineprop, itemname);
7674 if (fileprop != null) {
7675 JSROOT.Painter.menuitem(menu,
"Draw",
function() { painter.display(itemname); });
7676 var filepath = qualifyURL(fileprop.fileurl);
7677 if (filepath.indexOf(JSROOT.source_dir) == 0)
7678 filepath = filepath.slice(JSROOT.source_dir.length);
7679 JSROOT.Painter.menuitem(menu,
"Draw in new window",
function() {
7680 window.open(JSROOT.source_dir +
"index.htm?nobrowser&file=" + filepath +
"&item=" + fileprop.itemname);
7684 JSROOT.Painter.menuitem(menu,
"Close",
function() {});
7689 JSROOT.HierarchyPainter.prototype.SetDisplay =
function(kind, frameid) {
7690 this[
'disp_kind'] = kind;
7691 this[
'disp_frameid'] = frameid;
7694 JSROOT.HierarchyPainter.prototype.clear =
function() {
7696 this[
'disp'].Reset();
7699 JSROOT.HierarchyPainter.prototype.CreateDisplay =
function(force) {
7700 if (
'disp' in
this) {
7701 if (!force &&
this[
'disp'].NumDraw() > 0)
return true;
7702 this[
'disp'].Reset();
7703 delete this[
'disp'];
7707 if (document.getElementById(
this[
'disp_frameid']) == null)
return false;
7709 if (
this[
'disp_kind'] ==
"tabs")
7710 this[
'disp'] =
new JSROOT.TabsDisplay(
this[
'disp_frameid']);
7712 if (
this[
'disp_kind'].search(
"grid") == 0)
7713 this[
'disp'] =
new JSROOT.GridDisplay(
this[
'disp_frameid'],
this[
'disp_kind']);
7715 this[
'disp'] =
new JSROOT.CollapsibleDisplay(
this[
'disp_frameid']);
7720 JSROOT.HierarchyPainter.prototype.CheckResize =
function(force) {
7722 this[
'disp'].CheckResize();
7729 JSROOT.MDIDisplay =
function(frameid) {
7730 this.frameid = frameid;
7733 JSROOT.MDIDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
7737 alert(
"ForEachFrame not implemented");
7740 JSROOT.MDIDisplay.prototype.ForEachPainter =
function(userfunc, only_visible) {
7744 this.ForEachFrame(
function(frame) {
7745 var dummy =
new JSROOT.TObjectPainter();
7746 dummy.SetDivId($(frame).attr(
'id'), -1);
7747 dummy.ForEachPainter(
function(painter) { userfunc(painter, frame); });
7751 JSROOT.MDIDisplay.prototype.NumDraw =
function() {
7753 this.ForEachFrame(
function() { cnt++; });
7757 JSROOT.MDIDisplay.prototype.FindFrame =
function(searchtitle, force) {
7758 var found_frame = null;
7760 this.ForEachFrame(
function(frame) {
7761 if (frame.prop(
'title') == searchtitle)
7762 found_frame = frame;
7765 if ((found_frame == null) && force)
7766 found_frame = this.CreateFrame(searchtitle);
7771 JSROOT.MDIDisplay.prototype.FindPainter =
function(title) {
7773 this.ForEachPainter(
function(p,f) {
7774 if ((res==null) && (f.prop(
'title')==title)) res = p;
7779 JSROOT.MDIDisplay.prototype.ActivateFrame =
function(frame) {
7783 JSROOT.MDIDisplay.prototype.CheckResize =
function() {
7784 this.ForEachPainter(
function(painter) {
7785 if ((
'_hitemname' in painter) && (typeof painter[
'CheckResize'] ==
'function'))
7786 painter.CheckResize();
7790 JSROOT.MDIDisplay.prototype.Reset =
function() {
7791 this.ForEachPainter(
function(painter) {
7792 if ((
'_hitemname' in painter) && (typeof painter[
'Clenaup'] ==
'function'))
7796 document.getElementById(this.frameid).innerHTML =
'';
7799 JSROOT.MDIDisplay.prototype.Draw =
function(title, obj, drawopt) {
7803 var painter = this.FindPainter(title);
7804 var frame = this.FindFrame(title);
7806 if (painter!=null) {
7807 this.ActivateFrame(frame);
7808 painter.RedrawObject(obj);
7812 if (!JSROOT.canDraw(obj[
'_typename'], drawopt))
return;
7815 frame = this.CreateFrame(title);
7817 this.ActivateFrame(frame);
7819 return JSROOT.draw($(frame).attr(
"id"), obj, drawopt);
7824 JSROOT.CloseCollapsible =
function(e, el) {
7825 var sel = $(el)[0].textContent;
7826 if (typeof (sel) ==
'undefined')
7828 sel.replace(
' x',
'');
7829 sel.replace(
';',
'');
7830 sel.replace(
' ',
'');
7831 $(el).next().andSelf().remove();
7832 e.stopPropagation();
7835 JSROOT.CollapsibleDisplay =
function(frameid) {
7836 JSROOT.MDIDisplay.call(
this, frameid);
7840 JSROOT.CollapsibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
7842 JSROOT.CollapsibleDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
7843 var topid = this.frameid +
'_collapsible';
7845 if (document.getElementById(topid) == null)
return;
7847 if (typeof userfunc !=
'function')
return;
7849 $(
'#' + topid +
' .collapsible_draw').each(
function() {
7852 if (only_visible && $(
this).is(
":hidden"))
return;
7858 JSROOT.CollapsibleDisplay.prototype.ActivateFrame =
function(frame) {
7859 if ($(frame).is(
":hidden")) {
7860 $(frame).prev().toggleClass(
"ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
7861 .find(
"> .ui-icon").toggleClass(
"ui-icon-triangle-1-e ui-icon-triangle-1-s").end()
7862 .next().toggleClass(
"ui-accordion-content-active").slideDown(0);
7864 $(frame).prev()[0].scrollIntoView();
7867 JSROOT.CollapsibleDisplay.prototype.CreateFrame =
function(title) {
7869 var topid = this.frameid +
'_collapsible';
7871 if (document.getElementById(topid) == null)
7872 $(
"#right-div").append(
'<div id="'+ topid +
'" class="ui-accordion ui-accordion-icons ui-widget ui-helper-reset" style="overflow:auto; overflow-y:scroll; height:100%"></div>');
7874 var hid = topid +
"_sub" + this.cnt++;
7875 var uid = hid +
"h";
7877 var entryInfo =
"<h5 id=\"" + uid +
"\"><a> " + title +
"</a> </h5>\n";
7878 entryInfo +=
"<div class='collapsible_draw' id='" + hid +
"'></div>\n";
7879 $(
"#" + topid).append(entryInfo);
7882 .addClass(
"ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom")
7883 .hover(
function() { $(
this).toggleClass(
"ui-state-hover"); })
7884 .prepend(
'<span class="ui-icon ui-icon-triangle-1-e"></span>')
7885 .append(
'<button type="button" class="closeButton" title="close canvas" onclick="JSROOT.CloseCollapsible(event, \'#'
7886 + uid +
'\')
"><img class="img_remove
" src="" alt=""/></button>')
7887 .click( function() {
7888 $(this).toggleClass("ui-accordion-header-active ui-state-active ui-state-
default ui-corner-bottom
")
7889 .find("> .ui-icon
").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s
")
7890 .end().next().toggleClass("ui-accordion-content-active
").slideToggle(0);
7894 .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom
")
7898 .toggleClass("ui-accordion-header-active ui-state-active ui-state-
default ui-corner-bottom
")
7899 .find("> .ui-icon
").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s
").end().next()
7900 .toggleClass("ui-accordion-content-active
").slideToggle(0);
7902 // $('#'+uid)[0].scrollIntoView();
7904 $("#
" + hid).prop('title', title);
7906 return $("#
" + hid);
7909 // ================================================
7911 JSROOT.TabsDisplay = function(frameid) {
7912 JSROOT.MDIDisplay.call(this, frameid);
7916 JSROOT.TabsDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
7918 JSROOT.TabsDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
7919 var topid = this.frameid + '_tabs';
7921 if (document.getElementById(topid) == null) return;
7923 if (typeof userfunc != 'function') return;
7926 var active = $('#' + topid).tabs("option
", "active
");
7928 $('#' + topid + ' .tabs_draw').each(function() {
7929 // check if only_visible specified
7930 if (only_visible && (cnt++ != active)) return;
7936 JSROOT.TabsDisplay.prototype.ActivateFrame = function(frame) {
7937 var cnt = 0, id = -1;
7938 this.ForEachFrame(function(fr) {
7939 if ($(fr).attr('id') == frame.attr('id')) id = cnt;
7943 $('#' + this.frameid + "_tabs
").tabs("option
", "active
", id);
7946 JSROOT.TabsDisplay.prototype.CreateFrame = function(title) {
7947 var topid = this.frameid + '_tabs';
7949 var hid = topid + "_sub
" + this.cnt++;
7951 var li = '<li><a href="#
' + hid + '">' + title
7952 + '</a><span class="ui-icon ui-icon-close
" role="presentation
">Remove Tab</span></li>';
7953 var cont = '<div class="tabs_draw
" id="' + hid + '"></div>';
7955 if (document.getElementById(topid) == null) {
7956 $("#
" + this.frameid).append('<div id="' + topid + '">' + ' <ul>' + li + ' </ul>' + cont + '</div>');
7958 var tabs = $("#
" + topid).tabs({ heightStyle : "fill
" });
7960 tabs.delegate("span.ui-icon-close
", "click
", function() {
7961 var panelId = $(this).closest("li
").remove().attr("aria-controls
");
7962 $("#
" + panelId).remove();
7963 tabs.tabs("refresh
");
7967 // var tabs = $("#tabs
").tabs();
7969 $("#
" + topid).find(".ui-tabs-nav
").append(li);
7970 $("#
" + topid).append(cont);
7971 $("#
" + topid).tabs("refresh
");
7972 $("#
" + topid).tabs("option
", "active
", -1);
7974 $('#' + hid).empty();
7975 $('#' + hid).prop('title', title);
7976 return $('#' + hid);
7979 // ================================================
7981 JSROOT.GridDisplay = function(frameid, sizex, sizey) {
7982 // create grid display object
7983 // one could use followinf arguments
7984 // new JSROOT.GridDisplay('yourframeid','4x4');
7985 // new JSROOT.GridDisplay('yourframeid','3x2');
7986 // new JSROOT.GridDisplay('yourframeid', 3, 4);
7988 JSROOT.MDIDisplay.call(this, frameid);
7990 if (typeof sizex == "string") {
7991 if (sizex.search("grid
") == 0)
7992 sizex = sizex.slice(4).trim();
7994 var separ = sizex.search("x
");
7997 sizey = parseInt(sizex.slice(separ + 1));
7998 sizex = parseInt(sizex.slice(0, separ));
8000 sizex = parseInt(sizex);
8018 JSROOT.GridDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
8020 JSROOT.GridDisplay.prototype.IsSingle = function() {
8021 return (this.sizex <= 1) && (this.sizey <= 1);
8024 JSROOT.GridDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
8025 if (typeof userfunc != 'function') return;
8027 if (this.IsSingle()) {
8028 var elem = $("#
"+this.frameid);
8029 if (elem.prop('title')!=null)
8034 var topid = this.frameid + '_grid';
8036 if (document.getElementById(topid) == null) return;
8038 for (var cnt = 0; cnt < this.sizex * this.sizey; cnt++) {
8040 var elem = $( "#
" + topid + "_
" + cnt);
8042 if (elem.prop('title')!="")
8047 JSROOT.GridDisplay.prototype.CreateFrame = function(title) {
8049 var hid = this.frameid;
8051 if (!this.IsSingle()) {
8052 var topid = this.frameid + '_grid';
8053 if (document.getElementById(topid) == null) {
8055 var main = $("#
" + this.frameid);
8057 var h = Math.floor(main.height() / this.sizey);
8058 var w = Math.floor(main.width() / this.sizex);
8060 var content = "<table
id=
'" + topid + "' style=
'width:100%; height:100%; table-layout:fixed'>
";
8062 for (var i = 0; i < this.sizey; i++) {
8064 for (var j = 0; j < this.sizex; j++)
8065 content += "<td><div
id=
'" + topid + "_" + cnt++ + "'></div></td>
";
8068 content += "</table>
";
8071 main.append(content);
8073 main.find("[
id^=
" + this.frameid + "_grid_]
").width(w).height(h);
8074 // .droppable({ accepted: ".h_item
", drop: function(event, ui) { console.log("drop!
"); } });
8077 hid = topid + "_
" + this.cnt;
8078 if (++this.cnt >= this.sizex * this.sizey) this.cnt = 0;
8081 $("#
" + hid).empty();
8082 $("#
" + hid).prop('title', title);
8084 return $('#' + hid);
8087 JSROOT.GridDisplay.prototype.Reset = function() {
8088 JSROOT.MDIDisplay.prototype.Reset.call(this);
8089 if (this.IsSingle())
8090 $("#
" + this.frameid).prop('title', null);
8094 JSROOT.GridDisplay.prototype.CheckResize = function() {
8096 var main = $("#
" + this.frameid);
8098 var h = Math.floor(main.height() / this.sizey);
8099 var w = Math.floor(main.width() / this.sizex);
8101 // console.log("big width =
" + main.width() + " height =
" + main.height());
8103 // set height for all table cells, it is not done automatically by browser
8104 // for (var cnt=0;cnt<this.sizex*this.sizey;cnt++)
8105 // $("#
" + this.frameid + "_grid_
"+cnt).height(h);
8107 // $("[
id^=
" + this.frameid + "_grid_]
").height(h).width(w);
8109 main.find("[
id^=
" + this.frameid + "_grid_]
").height(h).width(w);
8111 JSROOT.MDIDisplay.prototype.CheckResize.call(this);
8114 JSROOT.RegisterForResize = function(handle, delay) {
8115 // function used to react on browser window resize event
8116 // While many resize events could come in short time,
8117 // resize will be handled with delay after last resize event
8118 // handle can be function or object with CheckResize function
8119 // one could specify delay after which resize event will be handled
8121 var myInterval = null;
8123 var myPeriod = delay ? delay / 2.5 : 100;
8124 if (myPeriod < 20) myPeriod = 20;
8126 function ResizeTimer() {
8127 if (myCounter < 0) return;
8129 if (myCounter < 3) return;
8131 if (myInterval != null) {
8132 clearInterval(myInterval);
8137 document.body.style.cursor = 'wait';
8139 if (typeof handle == 'function') handle();
8140 else if ((typeof handle == 'object') && (typeof handle['CheckResize'] == 'function'))
8141 handle.CheckResize();
8143 document.body.style.cursor = 'auto';
8146 function ProcessResize() {
8147 if (myInterval == null) {
8148 myInterval = setInterval(ResizeTimer, myPeriod);
8153 window.addEventListener('resize', ProcessResize);
8156 JSROOT.addDrawFunc("TCanvas
", JSROOT.Painter.drawCanvas);
8157 JSROOT.addDrawFunc("TPad
", JSROOT.Painter.drawPad);
8158 JSROOT.addDrawFunc("TFrame
", JSROOT.Painter.drawFrame);
8159 JSROOT.addDrawFunc("TLegend
", JSROOT.Painter.drawLegend);
8160 JSROOT.addDrawFunc("TPaveText
", JSROOT.Painter.drawPaveText);
8161 JSROOT.addDrawFunc("TPaveStats
", JSROOT.Painter.drawPaveText);
8162 JSROOT.addDrawFunc("TLatex
", JSROOT.Painter.drawText);
8163 JSROOT.addDrawFunc("TText
", JSROOT.Painter.drawText);
8164 JSROOT.addDrawFunc("TPaveLabel
", JSROOT.Painter.drawText);
8165 JSROOT.addDrawFunc(/^TH1/, JSROOT.Painter.drawHistogram1D);
8166 JSROOT.addDrawFunc("TProfile
", JSROOT.Painter.drawHistogram1D);
8167 JSROOT.addDrawFunc(/^TH2/, JSROOT.Painter.drawHistogram2D);
8168 JSROOT.addDrawFunc(/^TH3/, JSROOT.Painter.drawHistogram3D);
8169 JSROOT.addDrawFunc("THStack
", JSROOT.Painter.drawHStack);
8170 JSROOT.addDrawFunc("TF1
", JSROOT.Painter.drawFunction);
8171 JSROOT.addDrawFunc(/^TGraph/, JSROOT.Painter.drawGraph);
8172 JSROOT.addDrawFunc("TCutG
", JSROOT.Painter.drawGraph);
8173 JSROOT.addDrawFunc(/^RooHist/, JSROOT.Painter.drawGraph);
8174 JSROOT.addDrawFunc(/^RooCurve/, JSROOT.Painter.drawGraph);
8175 JSROOT.addDrawFunc("TMultiGraph
", JSROOT.Painter.drawMultiGraph);
8176 JSROOT.addDrawFunc("TStreamerInfoList
", JSROOT.Painter.drawStreamerInfo);
8178 JSROOT.getDrawFunc = function(classname) {
8179 if (typeof classname != 'string') return null;
8181 for (var i in JSROOT.fDrawFunc) {
8182 if ((typeof JSROOT.fDrawFunc[i].name) === "string") {
8183 if (JSROOT.fDrawFunc[i].name == classname) return JSROOT.fDrawFunc[i].func;
8185 if (classname.match(JSROOT.fDrawFunc[i].name)) return JSROOT.fDrawFunc[i].func;
8191 JSROOT.canDraw = function(classname) {
8192 return JSROOT.getDrawFunc(classname) != null;
8198 JSROOT.draw = function(divid, obj, opt) {
8199 if ((typeof obj != 'object') || (!('_typename' in obj))) return null;
8201 var draw_func = JSROOT.getDrawFunc(obj['_typename']);
8203 if (draw_func==null) return null;
8205 return draw_func(divid, obj, opt);
8213 JSROOT.redraw = function(divid, obj, opt) {
8214 if (obj==null) return;
8216 var can = d3.select("#
" + divid + " .root_canvas
");
8217 var can_painter = can.node() ? can.node()['pad_painter'] : null;
8219 if (can_painter != null) {
8220 if (obj._typename=="TCanvas
") {
8221 can_painter.RedrawObject(obj);
8225 for (var i in can_painter.painters) {
8226 var obj0 = can_painter.painters[i].GetObject();
8228 if ((obj0 != null) && (obj0._typename == obj._typename))
8229 if (can_painter.painters[i].UpdateObject(obj)) {
8230 can_painter.RedrawPad();
8231 return can_painter.painters[i];
8237 console.log("Cannot find painter to update
object of type
" + obj._typename);
8239 $("#
"+divid).empty();
8240 return JSROOT.draw(divid, obj, opt);
8245 // JSRootPainter.js ends
8247 // example of user code for streamer and painter
8253 Amore_String_Streamer = function(buf, obj, prop, streamer) {
8254 console.log("read
property " + prop + " of
typename " + streamer[prop]['typename']);
8255 obj[prop] = buf.ReadTString();
8258 Amore_Draw = function(divid, obj, opt) { // custom draw function.
8259 return JSROOT.draw(divid, obj['fVal'], opt);
8262 JSROOT.addUserStreamer("amore::core::String_t
", Amore_String_Streamer);
8264 JSROOT.addDrawFunc("amore::core::MonitorObjectHisto<TH1F>
", Amore_Draw);