5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootPainter',
'd3'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 factory(require(
"./JSRootCore.js"), require(
"d3"));
10 if (typeof d3 !=
'object')
11 throw new Error(
'This extension requires d3.js',
'JSRootPainter.hist.js');
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootPainter.hist.js');
14 if (typeof JSROOT.Painter !=
'object')
15 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.hist.js');
18 } (
function(JSROOT, d3) {
22 JSROOT.sources.push(
"hist");
24 JSROOT.ToolbarIcons.th2color = {
25 recs: [{x:0,y:256,w:13,h:39,f:
'rgb(38,62,168)'},{x:13,y:371,w:39,h:39},{y:294,h:39},{y:256,h:39},{y:218,h:39},{x:51,y:410,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:90,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:
'rgb(22,82,205)'},{y:294},{y:256,h:39,f:
'rgb(16,100,220)'},{y:218,h:39},{y:179,h:39,f:
'rgb(22,82,205)'},{y:141,h:39},{y:102,h:39,f:
'rgb(38,62,168)'},{y:64},{y:0,h:27},{x:128,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:
'rgb(22,82,205)'},{y:294,f:
'rgb(20,129,214)'},{y:256,h:39,f:
'rgb(9,157,204)'},{y:218,h:39,f:
'rgb(14,143,209)'},{y:179,h:39,f:
'rgb(20,129,214)'},{y:141,h:39,f:
'rgb(16,100,220)'},{y:102,h:39,f:
'rgb(22,82,205)'},{y:64,f:
'rgb(38,62,168)'},{y:26,h:39},{y:0,h:27},{x:166,y:486,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:
'rgb(22,82,205)'},{y:333,h:39,f:
'rgb(20,129,214)'},{y:294,f:
'rgb(82,186,146)'},{y:256,h:39,f:
'rgb(179,189,101)'},{y:218,h:39,f:
'rgb(116,189,129)'},{y:179,h:39,f:
'rgb(82,186,146)'},{y:141,h:39,f:
'rgb(14,143,209)'},{y:102,h:39,f:
'rgb(16,100,220)'},{y:64,f:
'rgb(38,62,168)'},{y:26,h:39},{x:205,y:486,w:39,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:
'rgb(16,100,220)'},{y:333,h:39,f:
'rgb(9,157,204)'},{y:294,f:
'rgb(149,190,113)'},{y:256,h:39,f:
'rgb(244,198,59)'},{y:218,h:39},{y:179,h:39,f:
'rgb(226,192,75)'},{y:141,h:39,f:
'rgb(13,167,195)'},{y:102,h:39,f:
'rgb(18,114,217)'},{y:64,f:
'rgb(22,82,205)'},{y:26,h:39,f:
'rgb(38,62,168)'},{x:243,y:448,w:39,h:39},{y:410},{y:371,h:39,f:
'rgb(18,114,217)'},{y:333,h:39,f:
'rgb(30,175,179)'},{y:294,f:
'rgb(209,187,89)'},{y:256,h:39,f:
'rgb(251,230,29)'},{y:218,h:39,f:
'rgb(249,249,15)'},{y:179,h:39,f:
'rgb(226,192,75)'},{y:141,h:39,f:
'rgb(30,175,179)'},{y:102,h:39,f:
'rgb(18,114,217)'},{y:64,f:
'rgb(38,62,168)'},{y:26,h:39},{x:282,y:448,h:39},{y:410},{y:371,h:39,f:
'rgb(18,114,217)'},{y:333,h:39,f:
'rgb(14,143,209)'},{y:294,f:
'rgb(149,190,113)'},{y:256,h:39,f:
'rgb(226,192,75)'},{y:218,h:39,f:
'rgb(244,198,59)'},{y:179,h:39,f:
'rgb(149,190,113)'},{y:141,h:39,f:
'rgb(9,157,204)'},{y:102,h:39,f:
'rgb(18,114,217)'},{y:64,f:
'rgb(38,62,168)'},{y:26,h:39},{x:320,y:448,w:39,h:39},{y:410},{y:371,h:39,f:
'rgb(22,82,205)'},{y:333,h:39,f:
'rgb(20,129,214)'},{y:294,f:
'rgb(46,183,164)'},{y:256,h:39},{y:218,h:39,f:
'rgb(82,186,146)'},{y:179,h:39,f:
'rgb(9,157,204)'},{y:141,h:39,f:
'rgb(20,129,214)'},{y:102,h:39,f:
'rgb(16,100,220)'},{y:64,f:
'rgb(38,62,168)'},{y:26,h:39},{x:358,y:448,h:39},{y:410},{y:371,h:39,f:
'rgb(22,82,205)'},{y:333,h:39},{y:294,f:
'rgb(16,100,220)'},{y:256,h:39,f:
'rgb(20,129,214)'},{y:218,h:39,f:
'rgb(14,143,209)'},{y:179,h:39,f:
'rgb(18,114,217)'},{y:141,h:39,f:
'rgb(22,82,205)'},{y:102,h:39,f:
'rgb(38,62,168)'},{y:64},{y:26,h:39},{x:397,y:448,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294,f:
'rgb(22,82,205)'},{y:256,h:39},{y:218,h:39},{y:179,h:39,f:
'rgb(38,62,168)'},{y:141,h:39},{y:102,h:39},{y:64},{y:26,h:39},{x:435,y:410,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:474,y:256,h:39},{y:179,h:39}]
28 JSROOT.ToolbarIcons.th2colorz = {
29 recs: [{x:128,y:486,w:256,h:26,f:
'rgb(38,62,168)'},{y:461,f:
'rgb(22,82,205)'},{y:435,f:
'rgb(16,100,220)'},{y:410,f:
'rgb(18,114,217)'},{y:384,f:
'rgb(20,129,214)'},{y:358,f:
'rgb(14,143,209)'},{y:333,f:
'rgb(9,157,204)'},{y:307,f:
'rgb(13,167,195)'},{y:282,f:
'rgb(30,175,179)'},{y:256,f:
'rgb(46,183,164)'},{y:230,f:
'rgb(82,186,146)'},{y:205,f:
'rgb(116,189,129)'},{y:179,f:
'rgb(149,190,113)'},{y:154,f:
'rgb(179,189,101)'},{y:128,f:
'rgb(209,187,89)'},{y:102,f:
'rgb(226,192,75)'},{y:77,f:
'rgb(244,198,59)'},{y:51,f:
'rgb(253,210,43)'},{y:26,f:
'rgb(251,230,29)'},{y:0,f:
'rgb(249,249,15)'}]
32 JSROOT.ToolbarIcons.th2draw3d = {
33 path:
"M172.768,0H51.726C23.202,0,0.002,23.194,0.002,51.712v89.918c0,28.512,23.2,51.718,51.724,51.718h121.042 c28.518,0,51.724-23.2,51.724-51.718V51.712C224.486,23.194,201.286,0,172.768,0z M177.512,141.63c0,2.611-2.124,4.745-4.75,4.745 H51.726c-2.626,0-4.751-2.134-4.751-4.745V51.712c0-2.614,2.125-4.739,4.751-4.739h121.042c2.62,0,4.75,2.125,4.75,4.739 L177.512,141.63L177.512,141.63z "+
34 "M460.293,0H339.237c-28.521,0-51.721,23.194-51.721,51.712v89.918c0,28.512,23.2,51.718,51.721,51.718h121.045 c28.521,0,51.721-23.2,51.721-51.718V51.712C512.002,23.194,488.802,0,460.293,0z M465.03,141.63c0,2.611-2.122,4.745-4.748,4.745 H339.237c-2.614,0-4.747-2.128-4.747-4.745V51.712c0-2.614,2.133-4.739,4.747-4.739h121.045c2.626,0,4.748,2.125,4.748,4.739 V141.63z "+
35 "M172.768,256.149H51.726c-28.524,0-51.724,23.205-51.724,51.726v89.915c0,28.504,23.2,51.715,51.724,51.715h121.042 c28.518,0,51.724-23.199,51.724-51.715v-89.915C224.486,279.354,201.286,256.149,172.768,256.149z M177.512,397.784 c0,2.615-2.124,4.736-4.75,4.736H51.726c-2.626-0.006-4.751-2.121-4.751-4.736v-89.909c0-2.626,2.125-4.753,4.751-4.753h121.042 c2.62,0,4.75,2.116,4.75,4.753L177.512,397.784L177.512,397.784z "+
36 "M460.293,256.149H339.237c-28.521,0-51.721,23.199-51.721,51.726v89.915c0,28.504,23.2,51.715,51.721,51.715h121.045 c28.521,0,51.721-23.199,51.721-51.715v-89.915C512.002,279.354,488.802,256.149,460.293,256.149z M465.03,397.784 c0,2.615-2.122,4.736-4.748,4.736H339.237c-2.614,0-4.747-2.121-4.747-4.736v-89.909c0-2.626,2.121-4.753,4.747-4.753h121.045 c2.615,0,4.748,2.116,4.748,4.753V397.784z"
39 JSROOT.Painter.CreateDefaultPalette =
function() {
41 function HLStoRGB(h, l, s) {
46 function hue2rgb(p, q, t) {
49 if (t < 1 / 6)
return p + (q - p) * 6 * t;
50 if (t < 1 / 2)
return q;
51 if (t < 2 / 3)
return p + (q - p) * (2/3 - t) * 6;
54 var q = (l < 0.5) ? l * (1 + s) : l + s - l * s,
56 r = hue2rgb(p, q, h + 1/3);
58 b = hue2rgb(p, q, h - 1/3);
60 return 'rgb(' + Math.round(r*255) +
',' + Math.round(g*255) +
',' + Math.round(b*255) +
')';
63 var palette = [], saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50;
64 for (var i = 0; i < maxPretty; ++i) {
65 var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360,
66 rgbval = HLStoRGB(hue, lightness, saturation);
69 return new JSROOT.ColorPalette(palette);
72 JSROOT.Painter.CreateGrayPalette =
function() {
74 for (var i = 0; i < 50; ++i) {
75 var code = Math.round((i+2)/60*255);
76 palette.push(
'rgb('+code+
','+code+
','+code+
')');
78 return new JSROOT.ColorPalette(palette);
81 JSROOT.Painter.CreateGradientColorTable =
function(Stops, Red, Green, Blue, NColors, alpha) {
85 for (var g = 1; g < Stops.length; g++) {
87 var nColorsGradient = parseInt(Math.floor(NColors*Stops[g]) - Math.floor(NColors*Stops[g-1]));
88 for (var c = 0; c < nColorsGradient; c++) {
89 var col = Math.round(Red[g-1] + c * (Red[g] - Red[g-1])/nColorsGradient) +
"," +
90 Math.round(Green[g-1] + c * (Green[g] - Green[g-1])/ nColorsGradient) +
"," +
91 Math.round(Blue[g-1] + c * (Blue[g] - Blue[g-1])/ nColorsGradient);
92 palette.push(
"rgb("+col+
")");
96 return new JSROOT.ColorPalette(palette);
99 JSROOT.Painter.GetColorPalette =
function(col,alfa) {
100 col = col || JSROOT.gStyle.Palette;
101 if ((col>0) && (col<10))
return JSROOT.Painter.CreateGrayPalette();
102 if (col < 51)
return JSROOT.Painter.CreateDefaultPalette();
103 if (col > 113) col = 57;
104 var red, green, blue,
105 stops = [ 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000 ];
110 red = [ 0, 9, 13, 17, 24, 32, 27, 25, 29];
111 green = [ 0, 0, 0, 2, 37, 74, 113, 160, 221];
112 blue = [ 28, 42, 59, 78, 98, 129, 154, 184, 221];
117 red = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
118 green = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
119 blue = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
124 red = [ 0, 45, 99, 156, 212, 230, 237, 234, 242];
125 green = [ 0, 0, 0, 45, 101, 168, 238, 238, 243];
126 blue = [ 0, 1, 1, 3, 9, 8, 11, 95, 230];
131 red = [ 0, 22, 44, 68, 93, 124, 160, 192, 237];
132 green = [ 0, 16, 41, 67, 93, 125, 162, 194, 241];
133 blue = [ 97, 100, 99, 99, 93, 68, 44, 26, 74];
138 red = [ 0, 5, 15, 35, 102, 196, 208, 199, 110];
139 green = [ 0, 48, 124, 192, 206, 226, 97, 16, 0];
140 blue = [ 99, 142, 198, 201, 90, 22, 13, 8, 2];
145 red = [ 242, 234, 237, 230, 212, 156, 99, 45, 0];
146 green = [ 243, 238, 238, 168, 101, 45, 0, 0, 0];
147 blue = [ 230, 95, 11, 8, 9, 3, 1, 1, 0];
152 red = [ 0.2082*255, 0.0592*255, 0.0780*255, 0.0232*255, 0.1802*255, 0.5301*255, 0.8186*255, 0.9956*255, 0.9764*255];
153 green = [ 0.1664*255, 0.3599*255, 0.5041*255, 0.6419*255, 0.7178*255, 0.7492*255, 0.7328*255, 0.7862*255, 0.9832*255];
154 blue = [ 0.5293*255, 0.8684*255, 0.8385*255, 0.7914*255, 0.6425*255, 0.4662*255, 0.3499*255, 0.1968*255, 0.0539*255];
159 red = [ 0.0000, 0.0956*255, 0.0098*255, 0.2124*255, 0.6905*255, 0.9242*255, 0.7914*255, 0.7596*255, 1.0000*255];
160 green = [ 0.0000, 0.1147*255, 0.3616*255, 0.5041*255, 0.4577*255, 0.4691*255, 0.6905*255, 0.9237*255, 1.0000*255];
161 blue = [ 0.0000, 0.2669*255, 0.3121*255, 0.1318*255, 0.2236*255, 0.6741*255, 0.9882*255, 0.9593*255, 1.0000*255];
166 red = [13, 23, 25, 63, 76, 104, 137, 161, 206];
167 green = [95, 67, 37, 21, 0, 12, 35, 52, 79];
168 blue = [ 4, 3, 2, 6, 11, 22, 49, 98, 208];
173 red = [0, 61, 89, 122, 143, 160, 185, 204, 231];
174 green = [0, 0, 0, 0, 14, 37, 72, 132, 235];
175 blue = [0, 140, 224, 144, 4, 5, 6, 9, 13];
180 red = [ 14, 7, 2, 0, 5, 11, 55, 131, 229];
181 green = [105, 56, 26, 1, 42, 74, 131, 171, 229];
182 blue = [ 2, 21, 35, 60, 92, 113, 160, 185, 229];
187 red = [ 0, 0, 0, 70, 148, 231, 235, 237, 244];
188 green = [ 0, 0, 0, 0, 0, 69, 67, 216, 244];
189 blue = [ 0, 102, 228, 231, 177, 124, 137, 20, 244];
194 red = [ 50, 56, 63, 68, 93, 121, 165, 192, 241];
195 green = [ 66, 81, 91, 96, 111, 128, 155, 189, 241];
196 blue = [ 97, 91, 75, 65, 77, 103, 143, 167, 217];
201 red = [ 145, 166, 167, 156, 131, 114, 101, 112, 132];
202 green = [ 158, 178, 179, 181, 163, 154, 144, 152, 159];
203 blue = [ 190, 199, 201, 192, 176, 169, 160, 166, 190];
208 red = [ 93, 91, 99, 108, 130, 125, 132, 155, 174];
209 green = [ 126, 124, 128, 129, 131, 121, 119, 153, 173];
210 blue = [ 103, 94, 87, 85, 80, 85, 107, 120, 146];
215 red = [ 24, 40, 69, 90, 104, 114, 120, 132, 103];
216 green = [ 29, 52, 94, 127, 150, 162, 159, 151, 101];
217 blue = [ 29, 52, 96, 132, 162, 181, 184, 186, 131];
222 red = [ 46, 38, 61, 92, 113, 121, 132, 150, 191];
223 green = [ 46, 36, 40, 69, 110, 135, 131, 92, 34];
224 blue = [ 46, 80, 74, 70, 81, 105, 165, 211, 225];
229 red = [ 0, 4, 12, 30, 52, 101, 142, 190, 237];
230 green = [ 0, 40, 86, 121, 140, 172, 187, 213, 240];
231 blue = [ 0, 9, 14, 18, 21, 23, 27, 35, 101];
236 red = [ 198, 206, 206, 211, 198, 181, 161, 171, 244];
237 green = [ 103, 133, 150, 172, 178, 174, 163, 175, 244];
238 blue = [ 49, 54, 55, 66, 91, 130, 184, 224, 244];
243 red = [ 243, 243, 240, 240, 241, 239, 186, 151, 129];
244 green = [ 0, 46, 99, 149, 194, 220, 183, 166, 147];
245 blue = [ 6, 8, 36, 91, 169, 235, 246, 240, 233];
250 red = [ 22, 19, 19, 25, 35, 53, 88, 139, 210];
251 green = [ 0, 32, 69, 108, 135, 159, 183, 198, 215];
252 blue = [ 77, 96, 110, 116, 110, 100, 90, 78, 70];
257 red = [ 68, 116, 165, 182, 189, 180, 145, 111, 71];
258 green = [ 37, 82, 135, 178, 204, 225, 221, 202, 147];
259 blue = [ 16, 55, 105, 147, 196, 226, 232, 224, 178];
264 red = [ 61, 99, 136, 181, 213, 225, 198, 136, 24];
265 green = [ 149, 140, 96, 83, 132, 178, 190, 135, 22];
266 blue = [ 214, 203, 168, 135, 110, 100, 111, 113, 22];
271 red = [ 76, 120, 156, 183, 197, 180, 162, 154, 140];
272 green = [ 34, 35, 42, 69, 102, 137, 164, 188, 197];
273 blue = [ 64, 69, 78, 105, 142, 177, 205, 217, 198];
278 red = [ 37, 102, 157, 188, 196, 214, 223, 235, 251];
279 green = [ 37, 29, 25, 37, 67, 91, 132, 185, 251];
280 blue = [ 37, 32, 33, 45, 66, 98, 137, 187, 251];
285 red = [ 79, 100, 119, 137, 153, 172, 192, 205, 250];
286 green = [ 63, 79, 93, 103, 115, 135, 167, 196, 250];
287 blue = [ 51, 59, 66, 61, 62, 70, 110, 160, 250];
292 red = [ 43, 44, 50, 66, 125, 172, 178, 155, 157];
293 green = [ 63, 63, 85, 101, 138, 163, 122, 51, 39];
294 blue = [ 121, 101, 58, 44, 47, 55, 57, 44, 43];
299 red = [ 0, 41, 62, 79, 90, 87, 99, 140, 228];
300 green = [ 0, 57, 81, 93, 85, 70, 71, 125, 228];
301 blue = [ 95, 91, 91, 82, 60, 43, 44, 112, 228];
306 red = [ 49, 59, 72, 88, 114, 141, 176, 205, 222];
307 green = [ 78, 72, 66, 57, 59, 75, 106, 142, 173];
308 blue = [ 78, 55, 46, 40, 39, 39, 40, 41, 47];
313 red = [ 243, 222, 201, 185, 165, 158, 166, 187, 219];
314 green = [ 94, 108, 132, 135, 125, 96, 68, 51, 61];
315 blue = [ 7, 9, 12, 19, 45, 89, 118, 146, 118];
320 red = [ 19, 44, 74, 105, 137, 166, 194, 206, 220];
321 green = [ 19, 28, 40, 55, 82, 110, 159, 181, 220];
322 blue = [ 19, 42, 68, 96, 129, 157, 188, 203, 220];
327 red = [ 33, 44, 70, 99, 140, 165, 199, 211, 216];
328 green = [ 38, 50, 76, 105, 140, 165, 191, 189, 167];
329 blue = [ 55, 67, 97, 124, 140, 166, 163, 129, 52];
334 red = [ 0, 33, 73, 124, 136, 152, 159, 171, 223];
335 green = [ 0, 43, 92, 124, 134, 126, 121, 144, 223];
336 blue = [ 0, 43, 68, 76, 73, 64, 72, 114, 223];
341 red = [ 5, 18, 45, 124, 193, 223, 205, 128, 49];
342 green = [ 48, 134, 207, 230, 193, 113, 28, 0, 7];
343 blue = [ 6, 15, 41, 121, 193, 226, 208, 130, 49];
348 red = [ 180, 106, 104, 135, 164, 188, 189, 165, 144];
349 green = [ 72, 126, 154, 184, 198, 207, 205, 190, 179];
350 blue = [ 41, 120, 158, 188, 194, 181, 145, 100, 62];
355 red = [ 57, 72, 94, 117, 136, 154, 174, 192, 215];
356 green = [ 0, 33, 68, 109, 140, 171, 192, 196, 209];
357 blue = [ 116, 137, 173, 201, 200, 201, 203, 190, 187];
362 red = [ 31, 71, 123, 160, 210, 222, 214, 199, 183];
363 green = [ 40, 117, 171, 211, 231, 220, 190, 132, 65];
364 blue = [ 234, 214, 228, 222, 210, 160, 105, 60, 34];
369 red = [ 123, 108, 109, 126, 154, 172, 188, 196, 218];
370 green = [ 184, 138, 130, 133, 154, 175, 188, 196, 218];
371 blue = [ 208, 130, 109, 99, 110, 122, 150, 171, 218];
376 red = [ 105, 106, 122, 143, 159, 172, 176, 181, 207];
377 green = [ 252, 197, 194, 187, 174, 162, 153, 136, 125];
378 blue = [ 146, 133, 144, 155, 163, 167, 166, 162, 174];
383 red = [ 171, 141, 145, 152, 154, 159, 163, 158, 177];
384 green = [ 236, 143, 100, 63, 53, 55, 44, 31, 6];
385 blue = [ 59, 48, 46, 44, 42, 54, 82, 112, 179];
390 red = [ 180, 190, 209, 223, 204, 228, 205, 152, 91];
391 green = [ 93, 125, 147, 172, 181, 224, 233, 198, 158];
392 blue = [ 236, 218, 160, 133, 114, 132, 162, 220, 218];
397 red = [ 225, 183, 162, 135, 115, 111, 119, 145, 211];
398 green = [ 205, 177, 166, 135, 124, 117, 117, 132, 172];
399 blue = [ 186, 165, 155, 135, 126, 130, 150, 178, 226];
404 red = [ 39, 43, 59, 63, 80, 116, 153, 177, 223];
405 green = [ 39, 43, 59, 74, 91, 114, 139, 165, 223];
406 blue = [ 39, 50, 59, 70, 85, 115, 151, 176, 223];
411 red = [ 0, 38, 60, 76, 84, 89, 101, 128, 204];
412 green = [ 0, 10, 15, 23, 35, 57, 83, 123, 199];
413 blue = [ 0, 11, 22, 40, 63, 86, 97, 94, 85];
418 red = [ 94, 112, 141, 165, 167, 140, 91, 49, 27];
419 green = [ 27, 46, 88, 135, 166, 161, 135, 97, 58];
420 blue = [ 42, 52, 81, 106, 139, 158, 155, 137, 116];
425 red = [ 30, 49, 79, 117, 135, 151, 146, 138, 147];
426 green = [ 63, 60, 72, 90, 94, 94, 68, 46, 16];
427 blue = [ 18, 28, 41, 56, 62, 63, 50, 36, 21];
432 red = [ 0, 30, 63, 101, 143, 152, 169, 187, 230];
433 green = [ 0, 14, 28, 42, 58, 61, 67, 74, 91];
434 blue = [ 39, 26, 21, 18, 15, 14, 14, 13, 13];
439 red = [ 149, 140, 164, 179, 182, 181, 131, 87, 61];
440 green = [ 62, 70, 107, 136, 144, 138, 117, 87, 74];
441 blue = [ 40, 38, 45, 49, 49, 49, 38, 32, 34];
446 red = [ 99, 112, 148, 165, 179, 182, 183, 183, 208];
447 green = [ 39, 40, 57, 79, 104, 127, 148, 161, 198];
448 blue = [ 15, 16, 18, 33, 51, 79, 103, 129, 177];
453 red = [ 99, 116, 154, 174, 200, 196, 201, 201, 230];
454 green = [ 0, 0, 8, 32, 58, 83, 119, 136, 173];
455 blue = [ 5, 6, 7, 9, 9, 14, 17, 19, 24];
460 red = [ 82, 106, 126, 141, 155, 163, 142, 107, 66];
461 green = [ 62, 44, 69, 107, 135, 152, 149, 132, 119];
462 blue = [ 39, 25, 31, 60, 73, 68, 49, 72, 188];
467 red = [ 18, 29, 44, 72, 116, 158, 184, 208, 221];
468 green = [ 27, 46, 71, 105, 146, 177, 189, 190, 183];
469 blue = [ 39, 55, 80, 108, 130, 133, 124, 100, 76];
474 red = [ 0, 48, 119, 173, 212, 224, 228, 228, 245];
475 green = [ 0, 13, 30, 47, 79, 127, 167, 205, 245];
476 blue = [ 0, 68, 75, 43, 16, 22, 55, 128, 245];
481 red = [ 34, 70, 129, 187, 225, 226, 216, 193, 179];
482 green = [ 48, 91, 147, 194, 226, 229, 196, 110, 12];
483 blue = [ 234, 212, 216, 224, 206, 110, 53, 40, 29];
488 red = [ 30, 55, 103, 147, 174, 203, 188, 151, 105];
489 green = [ 0, 65, 138, 182, 187, 175, 121, 53, 9];
490 blue = [ 191, 202, 212, 208, 171, 140, 97, 57, 30];
495 red = [ 112, 97, 113, 125, 138, 159, 178, 188, 225];
496 green = [ 16, 17, 24, 37, 56, 81, 110, 136, 189];
497 blue = [ 38, 35, 46, 59, 78, 103, 130, 152, 201];
502 red = [ 18, 72, 5, 23, 29, 201, 200, 98, 29];
503 green = [ 0, 0, 43, 167, 211, 117, 0, 0, 0];
504 blue = [ 51, 203, 177, 26, 10, 9, 8, 3, 0];
509 red = [ 19, 42, 64, 88, 118, 147, 175, 187, 205];
510 green = [ 19, 55, 89, 125, 154, 169, 161, 129, 70];
511 blue = [ 19, 32, 47, 70, 100, 128, 145, 130, 75];
516 red = [ 33, 31, 42, 68, 86, 111, 141, 172, 227];
517 green = [ 255, 175, 145, 106, 88, 55, 15, 0, 0];
518 blue = [ 255, 205, 202, 203, 208, 205, 203, 206, 231];
523 red = [ 0, 25, 50, 79, 110, 145, 181, 201, 254];
524 green = [ 0, 16, 30, 46, 63, 82, 101, 124, 179];
525 blue = [ 0, 12, 21, 29, 39, 49, 61, 74, 103];
530 red = [ 0, 13, 30, 44, 72, 120, 156, 200, 247];
531 green = [ 0, 36, 84, 117, 141, 153, 151, 158, 247];
532 blue = [ 0, 94, 100, 82, 56, 66, 76, 131, 247];
537 red = [ 26, 51, 43, 33, 28, 35, 74, 144, 246];
538 green = [ 9, 24, 55, 87, 118, 150, 180, 200, 222];
539 blue = [ 30, 96, 112, 114, 112, 101, 72, 35, 0];
544 red = [ 0, 5, 65, 97, 124, 156, 189, 224, 255 ];
545 green = [ 32, 54, 77, 100, 123, 148, 175, 203, 234 ];
546 blue = [ 77, 110, 107, 111, 120, 119, 111, 94, 70 ];
550 return JSROOT.Painter.CreateDefaultPalette();
553 return JSROOT.Painter.CreateGradientColorTable(stops, red, green, blue, 255, alfa);
559 function TPavePainter(pave) {
560 JSROOT.TObjectPainter.call(
this, pave);
562 this.UseContextMenu =
true;
563 this.UseTextColor =
false;
565 this.AssignFinishPave();
568 TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
570 TPavePainter.prototype.AssignFinishPave =
function() {
573 if (this.FirstRun <= 0)
return;
575 if (this.FirstRun!==0)
return;
576 delete this.FinishPave;
579 this.FinishPave = func.bind(
this);
582 TPavePainter.prototype.DrawPave =
function(arg) {
585 this.UseTextColor =
false;
588 return this.RemoveDrawG();
590 var pt = this.GetObject(), opt = pt.fOption.toUpperCase();
593 this.stored = JSROOT.extend({}, pt);
595 var pad = this.root_pad();
597 if ((pt._typename ==
"TPaletteAxis") && !pt.fX1 && !pt.fX2 && !pt.fY1 && !pt.fY2) {
598 var fp = this.frame_painter();
600 pt.fX1NDC = fp.fX2NDC + 0.01;
601 pt.fX2NDC = Math.min(0.96, fp.fX2NDC + 0.06);
602 pt.fY1NDC = fp.fY1NDC;
603 pt.fY2NDC = fp.fY2NDC;
610 }
else if (opt.indexOf(
"NDC")>=0) {
611 pt.fX1NDC = pt.fX1; pt.fX2NDC = pt.fX2;
612 pt.fY1NDC = pt.fY1; pt.fY2NDC = pt.fY2;
615 if (pt.fX1 > 0) pt.fX1 = JSROOT.log10(pt.fX1);
616 if (pt.fX2 > 0) pt.fX2 = JSROOT.log10(pt.fX2);
619 if (pt.fY1 > 0) pt.fY1 = JSROOT.log10(pt.fY1);
620 if (pt.fY2 > 0) pt.fY2 = JSROOT.log10(pt.fY2);
622 pt.fX1NDC = (pt.fX1 - pad.fX1) / (pad.fX2 - pad.fX1);
623 pt.fY1NDC = (pt.fY1 - pad.fY1) / (pad.fY2 - pad.fY1);
624 pt.fX2NDC = (pt.fX2 - pad.fX1) / (pad.fX2 - pad.fX1);
625 pt.fY2NDC = (pt.fY2 - pad.fY1) / (pad.fY2 - pad.fY1);
627 pt.fX1NDC = pt.fY1NDC = 0.1;
628 pt.fX2NDC = pt.fY2NDC = 0.9;
631 if ((pt.fX1NDC == pt.fX2NDC) && (pt.fY1NDC == pt.fY2NDC) && (pt._typename ==
"TLegend")) {
632 pt.fX1NDC = Math.max(pad ? pad.fLeftMargin : 0, pt.fX2NDC - 0.3);
633 pt.fX2NDC = Math.min(pt.fX1NDC + 0.3, pad ? 1-pad.fRightMargin : 1);
634 var h0 = Math.max(pt.fPrimitives ? pt.fPrimitives.arr.length*0.05 : 0, 0.2);
635 pt.fY2NDC = Math.min(pad ? 1-pad.fTopMargin : 1, pt.fY1NDC + h0);
636 pt.fY1NDC = Math.max(pt.fY2NDC - h0, pad ? pad.fBottomMargin : 0);
640 var pos_x = Math.round(pt.fX1NDC *
this.pad_width()),
641 pos_y = Math.round((1.0 - pt.fY2NDC) *
this.pad_height()),
642 width = Math.round((pt.fX2NDC - pt.fX1NDC) *
this.pad_width()),
643 height = Math.round((pt.fY2NDC - pt.fY1NDC) *
this.pad_height()),
644 brd = pt.fBorderSize,
645 dx = (opt.indexOf(
"L")>=0) ? -1 : ((opt.indexOf(
"R")>=0) ? 1 : 0),
646 dy = (opt.indexOf(
"T")>=0) ? -1 : ((opt.indexOf(
"B")>=0) ? 1 : 0);
651 this.draw_g.attr(
"transform",
"translate(" + pos_x +
"," + pos_y +
")");
656 this.createAttLine({ attr: pt, width: (brd > 0) ? pt.fLineWidth : 0 });
658 this.createAttFill({ attr: pt });
660 if (pt._typename ==
"TDiamond") {
661 var h2 = Math.round(height/2), w2 = Math.round(width/2),
662 dpath =
"l"+w2+
",-"+h2 +
"l"+w2+
","+h2 +
"l-"+w2+
","+h2+
"z";
664 if ((brd > 1) && (pt.fShadowColor > 0) && (dx || dy) && !
this.fillatt.empty())
665 this.draw_g.append(
"svg:path")
666 .attr(
"d",
"M0,"+(h2+brd) + dpath)
667 .style(
"fill", this.get_color(pt.fShadowColor))
668 .style(
"stroke", this.get_color(pt.fShadowColor))
669 .style(
"stroke-width",
"1px");
671 this.draw_g.append(
"svg:path")
672 .attr(
"d",
"M0,"+h2 +dpath)
673 .call(this.fillatt.func)
674 .call(this.lineatt.func);
676 var text_g = this.draw_g.append(
"svg:g")
677 .attr(
"transform",
"translate(" + Math.round(width/4) +
"," + Math.round(height/4) +
")");
679 this.DrawPaveText(w2, h2, arg, text_g);
685 if ((brd > 1) && (pt.fShadowColor > 0) && !pt.fNpaves && (dx || dy)) {
686 var spath =
"", scol = this.get_color(pt.fShadowColor);
687 if (this.fillatt.empty()) {
688 if ((dx<0) && (dy<0))
689 spath =
"M0,0v"+(height-brd)+
"h-"+brd+
"v-"+height+
"h"+width+
"v"+brd;
691 spath =
"M0,"+height+
"v-"+(height-brd)+
"h-"+brd+
"v"+height+
"h"+width+
"v-"+brd;
694 spath =
"M"+(dx*brd)+
","+(dy*brd) +
"v"+height +
"h"+width +
"v-"+height
696 this.draw_g.append(
"svg:path")
697 .attr(
"d", spath +
"z")
699 .style(
"stroke", scol)
700 .style(
"stroke-width",
"1px");
704 for (var n = pt.fNpaves-1; n>0; --n)
705 this.draw_g.append(
"svg:path")
706 .attr(
"d",
"M" + (dx*4*n) +
","+ (dy*4*n) +
"h"+width +
"v"+height +
"h-"+width +
"z")
707 .call(this.fillatt.func)
708 .call(this.lineatt.func);
711 this.draw_g.append(
"svg:path")
712 .attr(
"d",
"M0,0h"+width +
"v"+height +
"h-"+width +
"z")
713 .call(this.fillatt.func)
714 .call(this.lineatt.func);
716 if (
'PaveDrawFunc' in
this)
717 this.PaveDrawFunc(width, height, arg);
719 if (JSROOT.BatchMode || (pt._typename==
"TPave"))
return;
723 rect.style(
"pointer-events",
"visibleFill")
724 .on(
"mouseenter", this.ShowObjectStatus.bind(
this))
727 this.draw_g.attr(
"x", pos_x)
729 .attr(
"width", width)
730 .attr(
"height", height);
732 this.AddDrag({ obj: pt, minwidth: 10, minheight: 20, canselect:
true,
733 redraw: this.DragRedraw.bind(
this),
734 ctxmenu: JSROOT.touches && JSROOT.gStyle.ContextMenu && this.UseContextMenu });
736 if (this.UseContextMenu && JSROOT.gStyle.ContextMenu)
737 this.draw_g.on(
"contextmenu", this.ShowContextMenu.bind(
this));
740 TPavePainter.prototype.DragRedraw =
function() {
741 this.InteractiveRedraw(
false,
"pave_moved");
745 TPavePainter.prototype.FillWebObjectOptions =
function(res) {
747 if (!this.snapid)
return null;
748 res = { _typename:
"TWebObjectOptions", snapid: this.snapid.toString(), opt: this.OptionsAsString(), fcust:
"", fopt: [] };
751 var pave = this.GetObject();
753 if (pave && pave.fInit) {
755 res.fopt = [pave.fX1NDC,pave.fY1NDC,pave.fX2NDC,pave.fY2NDC];
761 TPavePainter.prototype.DrawPaveLabel =
function(_width, _height) {
762 this.UseTextColor =
true;
764 var pave = this.GetObject();
766 this.StartTextDrawing(pave.fTextFont, _height/1.2);
768 this.DrawText({ align: pave.fTextAlign, width: _width, height: _height, text: pave.fLabel, color: this.get_color(pave.fTextColor) });
770 this.FinishTextDrawing(null, this.FinishPave);
773 TPavePainter.prototype.DrawPaveStats =
function(width, height) {
775 if (this.IsStats()) this.FillStatistic();
777 var pt = this.GetObject(), lines = [],
778 tcolor = this.get_color(pt.fTextColor),
779 first_stat = 0, num_cols = 0, maxlen = 0;
782 for (var j=0;j<pt.fLines.arr.length;++j) {
783 var entry = pt.fLines.arr[j];
784 if ((entry._typename==
"TText") || (entry._typename==
"TLatex"))
785 lines.push(entry.fTitle);
788 var nlines = lines.length;
791 for (var j = 0; j < nlines; ++j) {
793 if (j>0) maxlen = Math.max(maxlen, line.length);
794 if ((j == 0) || (line.indexOf(
'|') < 0))
continue;
795 if (first_stat === 0) first_stat = j;
796 var parts = line.split(
"|");
797 if (parts.length > num_cols)
798 num_cols = parts.length;
802 var stepy = height / nlines, has_head =
false, margin_x = pt.fMargin * width;
804 this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2));
806 this.UseTextColor =
true;
809 this.DrawText({ align: pt.fTextAlign, width: width, height: height, text: lines[0], color: tcolor, latex: 1 });
811 for (var j = 0; j < nlines; ++j) {
812 var posy = j*stepy, jcolor = tcolor;
813 this.UseTextColor =
true;
815 if (first_stat && (j >= first_stat)) {
816 var parts = lines[j].split(
"|");
817 for (var n = 0; n < parts.length; ++n)
818 this.DrawText({ align:
"middle", x: width * n / num_cols, y: posy, latex: 0,
819 width: width/num_cols, height: stepy, text: parts[n], color: jcolor });
820 }
else if (lines[j].indexOf(
'=') < 0) {
823 if (lines[j].length > maxlen + 5)
824 lines[j] = lines[j].substr(0,maxlen+2) +
"...";
826 this.DrawText({ align: (j == 0) ?
"middle" :
"start", x: margin_x, y: posy,
827 width: width-2*margin_x, height: stepy, text: lines[j], color: jcolor });
829 var parts = lines[j].split(
"="), sumw = 0;
830 for (var n = 0; n < 2; ++n)
831 sumw += this.DrawText({ align: (n == 0) ?
"start" :
"end", x: margin_x, y: posy,
832 width: width-2*margin_x, height: stepy, text: parts[n], color: jcolor });
833 this.TextScaleFactor(1.05*sumw/(width-2*margin_x), this.draw_g);
839 if ((pt.fBorderSize > 0) && has_head)
840 lpath +=
"M0," + Math.round(stepy) +
"h" + width;
842 if ((first_stat > 0) && (num_cols > 1)) {
843 for (var nrow = first_stat; nrow < nlines; ++nrow)
844 lpath +=
"M0," + Math.round(nrow * stepy) +
"h" + width;
845 for (var ncol = 0; ncol < num_cols - 1; ++ncol)
846 lpath +=
"M" + Math.round(width / num_cols * (ncol + 1)) +
"," + Math.round(first_stat * stepy) +
"V" + height;
849 if (lpath) this.draw_g.append(
"svg:path").attr(
"d",lpath).call(this.lineatt.func);
851 this.FinishTextDrawing(undefined, this.FinishPave);
853 this.draw_g.classed(
"most_upper_primitives",
true);
856 TPavePainter.prototype.DrawPaveText =
function(width, height, dummy_arg, text_g) {
858 var pt = this.GetObject(),
859 tcolor = this.get_color(pt.fTextColor),
860 nlines = 0, lines = [],
861 can_height = this.pad_height(),
862 pp = this.pad_painter(),
863 individual_positioning =
false,
864 draw_header = (pt.fLabel.length>0);
866 if (draw_header) this.FirstRun++;
868 if (!text_g) text_g = this.draw_g;
871 for (var j=0;j<pt.fLines.arr.length;++j) {
872 var entry = pt.fLines.arr[j];
873 if ((entry._typename==
"TText") || (entry._typename==
"TLatex")) {
875 if ((entry.fX>0) || (entry.fY>0)) individual_positioning =
true;
879 var fast_draw = (nlines==1) && pp && pp._fast_drawing, nline = 0;
882 for (var j=0;j<pt.fLines.arr.length;++j) {
883 var entry = pt.fLines.arr[j],
884 ytext = (nlines>0) ? Math.round((1-(nline-0.5)/nlines)*height) : 0;
885 switch (entry._typename) {
889 if (individual_positioning) {
892 var lx = entry.fX, ly = entry.fY;
894 if ((lx>0) && (lx<1)) lx = Math.round(lx*width);
else lx = pt.fMargin * width;
895 if ((ly>0) && (ly<1)) ly = Math.round((1-ly)*height);
else ly = ytext;
897 var jcolor = entry.fTextColor ? this.get_color(entry.fTextColor) :
"";
900 this.UseTextColor =
true;
903 this.StartTextDrawing(pt.fTextFont, (entry.fTextSize || pt.fTextSize) * can_height, text_g);
905 this.DrawText({ align: entry.fTextAlign || pt.fTextAlign, x: lx, y: ly, text: entry.fTitle, color: jcolor,
906 latex: (entry._typename ==
"TText") ? 0 : 1, draw_g: text_g, fast: fast_draw });
908 this.FinishTextDrawing(text_g, this.FinishPave);
918 var lx1 = entry.fX1, lx2 = entry.fX2,
919 ly1 = entry.fY1, ly2 = entry.fY2;
920 if (lx1!==0) lx1 = Math.round(lx1*width);
921 lx2 = lx2 ? Math.round(lx2*width) : width;
922 ly1 = ly1 ? Math.round((1-ly1)*height) : ytext;
923 ly2 = ly2 ? Math.round((1-ly2)*height) : ytext;
924 if (entry._typename ==
"TLine") {
925 var lineatt =
new JSROOT.TAttLineHandler(entry);
926 text_g.append(
"svg:line")
933 var fillatt = this.createAttFill(entry);
935 text_g.append(
"svg:rect")
938 .attr(
"width", lx2-lx1)
939 .attr(
"height", ly1-ly2)
946 if (individual_positioning) {
949 if (this.FinishPave) this.FinishPave();
954 var stepy = height / nlines, has_head =
false, margin_x = pt.fMargin * width, max_font_size = 0;
957 if ((nlines == 1) && (pt.fTextSize > 0)) {
958 max_font_size = Math.round(pt.fTextSize*can_height);
959 if (max_font_size < 3) max_font_size = 3;
962 this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2), text_g, max_font_size);
964 for (var j = 0; j < nlines; ++j) {
965 var arg = null, lj = lines[j];
968 arg = { x:0, y:0, width: width, height: height };
970 arg = { x: margin_x, y: j*stepy, width: width-2*margin_x, height: stepy };
971 if (lj.fTextColor) arg.color = this.get_color(lj.fTextColor);
972 if (lj.fTextSize) arg.font_size = Math.round(lj.fTextSize*can_height);
975 arg.align = pt.fTextAlign;
977 arg.latex = (lj._typename ==
"TText" ? 0 : 1);
978 arg.text = lj.fTitle;
979 arg.fast = fast_draw;
980 if (!arg.color) { this.UseTextColor =
true; arg.color = tcolor; }
985 this.FinishTextDrawing(text_g, this.FinishPave);
989 var x = Math.round(width*0.25),
990 y = Math.round(-height*0.02),
991 w = Math.round(width*0.5),
992 h = Math.round(height*0.04),
993 lbl_g = text_g.append(
"svg:g");
995 lbl_g.append(
"svg:path")
996 .attr(
"d",
"M"+x+
","+y +
"h"+w +
"v"+h +
"h-"+w +
"z")
997 .call(this.fillatt.func)
998 .call(this.lineatt.func);
1000 this.StartTextDrawing(pt.fTextFont, h/1.5, lbl_g);
1002 this.DrawText({ align: 22, x: x, y: y, width: w, height: h, text: pt.fLabel, color: tcolor, draw_g: lbl_g });
1004 this.FinishTextDrawing(lbl_g, this.FinishPave);
1006 this.UseTextColor =
true;
1010 TPavePainter.prototype.Format =
function(value, fmt) {
1013 if (!fmt) fmt =
"stat";
1015 var pave = this.GetObject();
1018 case "stat" : fmt = pave.fStatFormat || JSROOT.gStyle.fStatFormat;
break;
1019 case "fit": fmt = pave.fFitFormat || JSROOT.gStyle.fFitFormat;
break;
1020 case "entries":
if ((Math.abs(value) < 1e9) && (Math.round(value) == value))
return value.toFixed(0); fmt =
"14.7g";
break;
1021 case "last": fmt = this.lastformat;
break;
1024 delete this.lastformat;
1026 var res = JSROOT.FFormat(value, fmt ||
"6.4g");
1028 this.lastformat = JSROOT.lastFFormat;
1033 TPavePainter.prototype.DrawPaveLegend =
function(w, h) {
1035 var legend = this.GetObject(),
1036 nlines = legend.fPrimitives.arr.length,
1037 ncols = legend.fNColumns,
1040 if (ncols<2) ncols = 1;
else {
while ((nrows-1)*ncols >= nlines) nrows--; }
1042 function isEmpty(entry) {
1043 return !entry.fObject && !entry.fOption && (!entry.fLabel || (entry.fLabel ==
" "));
1047 for (var i=0;i<nlines;++i)
1048 if (isEmpty(legend.fPrimitives.arr[i])) nrows--;
1051 if (nrows<1) nrows = 1;
1053 var tcolor = this.get_color(legend.fTextColor),
1054 column_width = Math.round(w/ncols),
1055 padding_x = Math.round(0.03*w/ncols),
1056 padding_y = Math.round(0.03*h),
1057 step_y = (h - 2*padding_y)/nrows,
1058 font_size = 0.9*step_y,
1060 ph = this.pad_height(),
1061 fsize, any_opt =
false, i = -1;
1063 if (legend.fTextSize && (ph*legend.fTextSize > 2) && (ph*legend.fTextSize < font_size))
1064 font_size = max_font_size = Math.round(ph*legend.fTextSize);
1066 this.StartTextDrawing(legend.fTextFont, font_size,
this.draw_g, max_font_size);
1068 for (var ii = 0; ii < nlines; ++ii) {
1069 var leg = legend.fPrimitives.arr[ii];
1071 if (isEmpty(leg))
continue;
1073 if (ncols==1) ++i;
else i = ii;
1075 var lopt = leg.fOption.toLowerCase(),
1076 icol = i % ncols, irow = (i - icol) / ncols,
1077 x0 = icol * column_width,
1078 tpos_x = x0 + Math.round(legend.fMargin*column_width),
1079 pos_y = Math.round(padding_y + irow*step_y),
1080 mid_y = Math.round(padding_y + (irow+0.5)*step_y),
1081 o_fill = leg, o_marker = leg, o_line = leg,
1083 painter = null, isany =
false;
1085 if ((mo !== null) && (typeof mo ==
'object')) {
1086 if (
'fLineColor' in mo) o_line = mo;
1087 if (
'fFillColor' in mo) o_fill = mo;
1088 if (
'fMarkerColor' in mo) o_marker = mo;
1090 painter = this.FindPainterFor(mo);
1094 if (lopt.indexOf(
'f') != -1) {
1095 var fillatt = (painter && painter.fillatt) ? painter.fillatt :
this.createAttFill(o_fill);
1098 this.draw_g.append(
"svg:rect")
1099 .attr(
"x", x0 + padding_x)
1100 .attr(
"y", Math.round(pos_y+step_y*0.1))
1101 .attr(
"width", tpos_x - 2*padding_x - x0)
1102 .attr(
"height", Math.round(step_y*0.8))
1103 .call(fillatt.func);
1104 if (!fillatt.empty()) isany =
true;
1108 if (lopt.indexOf(
'l') != -1) {
1109 var lineatt = (painter && painter.lineatt) ? painter.lineatt :
new JSROOT.TAttLineHandler(o_line);
1110 this.draw_g.append(
"svg:line")
1111 .attr(
"x1", x0 + padding_x)
1113 .attr(
"x2", tpos_x - padding_x)
1115 .call(lineatt.func);
1116 if (lineatt.color !==
'none') isany =
true;
1120 if (lopt.indexOf(
'e') != -1 && (lopt.indexOf(
'l') == -1 || lopt.indexOf(
'f') != -1)) {
1124 if (lopt.indexOf(
'p') != -1) {
1125 var marker = (painter && painter.markeratt) ? painter.markeratt :
new JSROOT.TAttMarkerHandler(o_marker);
1128 .attr(
"d", marker.create((x0 + tpos_x)/2, mid_y))
1130 if (marker.color !==
'none') isany =
true;
1134 if (!isany && painter && painter.lineatt && (painter.lineatt.color !==
'none'))
1135 this.draw_g.append(
"svg:rect")
1136 .attr(
"x", x0 + padding_x)
1137 .attr(
"y", Math.round(pos_y+step_y*0.1))
1138 .attr(
"width", tpos_x - 2*padding_x - x0)
1139 .attr(
"height", Math.round(step_y*0.8))
1140 .attr(
"fill",
"none")
1141 .call(painter.lineatt.func);
1144 if (lopt.length>0) any_opt =
true;
1145 else if (!any_opt) pos_x = x0 + padding_x;
1148 this.DrawText({ align:
"start", x: pos_x, y: pos_y, width: x0+column_width-pos_x-padding_x, height: step_y, text: leg.fLabel, color: tcolor });
1152 this.FinishTextDrawing(this.draw_g, this.FinishPave);
1155 TPavePainter.prototype.DrawPaletteAxis =
function(s_width, s_height, arg) {
1158 palette = this.GetObject(),
1159 axis = palette.fAxis,
1160 can_move = (typeof arg ==
"string") && (arg.indexOf(
'can_move') > 0),
1161 postpone_draw = (typeof arg ==
"string") && (arg.indexOf(
'postpone') > 0),
1162 nbr1 = axis.fNdiv % 100,
1163 pos_x = parseInt(this.draw_g.attr(
"x")),
1164 pos_y = parseInt(this.draw_g.attr(
"y")),
1165 width = this.pad_width(),
1166 height = this.pad_height(),
1167 axisOffset = axis.fLabelOffset * width,
1168 main = this.main_painter(),
1169 framep = this.frame_painter(),
1170 zmin = 0, zmax = 100,
1171 contour = main.fContour;
1173 if (nbr1<=0) nbr1 = 8;
1174 axis.fTickSize = 0.6 * s_width / width;
1176 if (contour && framep) {
1177 zmin = Math.min(contour[0], framep.zmin);
1178 zmax = Math.max(contour[contour.length-1], framep.zmax);
1179 }
else if ((main.gmaxbin!==undefined) && (main.gminbin!==undefined)) {
1181 zmin = main.gminbin; zmax = main.gmaxbin;
1182 }
else if ((main.hmin!==undefined) && (main.hmax!==undefined)) {
1184 zmin = main.hmin; zmax = main.hmax;
1187 var z = null, z_kind =
"normal";
1189 if (this.root_pad().fLogz) {
1193 z = d3.scaleLinear();
1195 z.domain([zmin, zmax]).range([s_height,0]);
1197 this.draw_g.selectAll(
"rect").style(
"fill",
'white');
1199 if (!contour || postpone_draw)
1201 this.draw_g.append(
"svg:rect")
1204 .attr(
"width", s_width)
1205 .attr(
"height", s_height)
1206 .style(
"fill",
'white');
1208 for (var i=0;i<contour.length-1;++i) {
1209 var z0 = z(contour[i]),
1210 z1 = z(contour[i+1]),
1211 col = main.getContourColor((contour[i]+contour[i+1])/2);
1213 var r = this.draw_g.append(
"svg:rect")
1215 .attr(
"y", Math.round(z1))
1216 .attr(
"width", s_width)
1217 .attr(
"height", Math.round(z0) - Math.round(z1))
1219 .style(
"stroke", col)
1220 .property(
"fill0", col)
1221 .property(
"fill1", d3.rgb(col).darker(0.5).toString())
1223 if (this.IsTooltipAllowed())
1224 r.on(
'mouseover',
function() {
1225 d3.select(
this).transition().duration(100).style(
"fill", d3.select(
this).property(
'fill1'));
1226 }).on(
'mouseout',
function() {
1227 d3.select(
this).transition().duration(100).style(
"fill", d3.select(
this).property(
'fill0'));
1228 }).append(
"svg:title").text(contour[i].toFixed(2) +
" - " + contour[i+1].toFixed(2));
1230 if (JSROOT.gStyle.Zooming)
1231 r.on(
"dblclick",
function() { pthis.frame_painter().Unzoom(
"z"); });
1235 this.z_handle.SetAxisConfig(
"zaxis", z_kind, z, zmin, zmax, zmin, zmax);
1237 this.z_handle.max_tick_size = Math.round(s_width*0.7);
1239 this.z_handle.DrawAxis(
true, this.draw_g, s_width, s_height,
"translate(" + s_width +
", 0)");
1241 if (can_move && (
'getBoundingClientRect' in this.draw_g.node())) {
1242 var rect = this.draw_g.node().getBoundingClientRect();
1244 var shift = (pos_x + parseInt(rect.width)) - Math.round(0.995*width) + 3;
1247 this.draw_g.attr(
"x", pos_x - shift).attr(
"y", pos_y)
1248 .attr(
"transform",
"translate(" + (pos_x-shift) +
", " + pos_y +
")");
1249 palette.fX1NDC -= shift/width;
1250 palette.fX2NDC -= shift/width;
1254 var evnt = null, doing_zoom =
false, sel1 = 0, sel2 = 0, zoom_rect = null;
1256 function moveRectSel() {
1258 if (!doing_zoom)
return;
1260 d3.event.preventDefault();
1261 var m = d3.mouse(evnt);
1263 if (m[1] < sel1) sel1 = m[1];
else sel2 = m[1];
1265 zoom_rect.attr(
"y", sel1)
1266 .attr(
"height", Math.abs(sel2-sel1));
1269 function endRectSel() {
1270 if (!doing_zoom)
return;
1272 d3.event.preventDefault();
1273 d3.select(window).on(
"mousemove.colzoomRect", null)
1274 .on(
"mouseup.colzoomRect", null);
1279 var zmin = Math.min(z.invert(sel1), z.invert(sel2)),
1280 zmax = Math.max(z.invert(sel1), z.invert(sel2));
1282 pthis.frame_painter().Zoom(
"z", zmin, zmax);
1285 function startRectSel() {
1287 if (doing_zoom)
return;
1290 d3.event.preventDefault();
1293 var origin = d3.mouse(evnt);
1295 sel1 = sel2 = origin[1];
1297 zoom_rect = pthis.draw_g
1299 .attr(
"class",
"zoom")
1300 .attr(
"id",
"colzoomRect")
1302 .attr(
"width", s_width)
1306 d3.select(window).on(
"mousemove.colzoomRect", moveRectSel)
1307 .on(
"mouseup.colzoomRect", endRectSel,
true);
1309 d3.event.stopPropagation();
1312 if (JSROOT.gStyle.Zooming)
1313 this.draw_g.select(
".axis_zoom")
1314 .on(
"mousedown", startRectSel)
1315 .on(
"dblclick",
function() { pthis.frame_painter().Unzoom(
"z"); });
1317 if (this.FinishPave) this.FinishPave();
1320 TPavePainter.prototype.FillContextMenu =
function(menu) {
1321 var pave = this.GetObject();
1323 menu.add(
"header: " + pave._typename +
"::" + pave.fName);
1324 if (this.IsStats()) {
1325 menu.add(
"Default position",
function() {
1326 pave.fX2NDC = JSROOT.gStyle.fStatX;
1327 pave.fX1NDC = pave.fX2NDC - JSROOT.gStyle.fStatW;
1328 pave.fY2NDC = JSROOT.gStyle.fStatY;
1329 pave.fY1NDC = pave.fY2NDC - JSROOT.gStyle.fStatH;
1331 this.InteractiveRedraw(
true,
"pave_moved")
1334 menu.add(
"SetStatFormat",
function() {
1335 var fmt = prompt(
"Enter StatFormat", pave.fStatFormat);
1337 pave.fStatFormat = fmt;
1338 this.InteractiveRedraw(
true,
'exec:SetStatFormat("'+fmt+
'")');
1341 menu.add(
"SetFitFormat",
function() {
1342 var fmt = prompt(
"Enter FitFormat", pave.fFitFormat);
1344 pave.fFitFormat = fmt;
1345 this.InteractiveRedraw(
true,
'exec:SetFitFormat("'+fmt+
'")');
1348 menu.add(
"separator");
1349 menu.add(
"sub:SetOptStat",
function() {
1351 var fmt = prompt(
"Enter OptStat", pave.fOptStat);
1353 fmt = parseInt(fmt);
1354 if (!isNaN(fmt) && (fmt>=0)) {
1355 pave.fOptStat = parseInt(fmt);
1356 this.InteractiveRedraw(
true,
"exec:SetOptStat("+fmt+
")");
1360 function AddStatOpt(pos, name) {
1361 var opt = (pos<10) ? pave.fOptStat : pave.fOptFit;
1362 opt = parseInt(parseInt(opt) / parseInt(Math.pow(10,pos % 10))) % 10;
1363 menu.addchk(opt, name, opt * 100 + pos,
function(arg) {
1364 var newopt = (arg % 100 < 10) ? pave.fOptStat : pave.fOptFit;
1365 var oldopt = parseInt(arg / 100);
1366 newopt -= (oldopt>0 ? oldopt : -1) * parseInt(Math.pow(10, arg % 10));
1367 if (arg % 100 < 10) {
1368 pave.fOptStat = newopt;
1369 this.InteractiveRedraw(
true,
"exec:SetOptStat("+newopt+
")");
1371 pave.fOptFit = newopt;
1372 this.InteractiveRedraw(
true,
"exec:SetOptFit("+newopt+
")");
1377 AddStatOpt(0,
"Histogram name");
1378 AddStatOpt(1,
"Entries");
1379 AddStatOpt(2,
"Mean");
1380 AddStatOpt(3,
"Std Dev");
1381 AddStatOpt(4,
"Underflow");
1382 AddStatOpt(5,
"Overflow");
1383 AddStatOpt(6,
"Integral");
1384 AddStatOpt(7,
"Skewness");
1385 AddStatOpt(8,
"Kurtosis");
1386 menu.add(
"endsub:");
1388 menu.add(
"sub:SetOptFit",
function() {
1390 var fmt = prompt(
"Enter OptStat", pave.fOptFit);
1392 fmt = parseInt(fmt);
1393 if (!isNaN(fmt) && (fmt>=0)) {
1395 this.InteractiveRedraw(
true,
"exec:SetOptFit("+fmt+
")");
1399 AddStatOpt(10,
"Fit parameters");
1400 AddStatOpt(11,
"Par errors");
1401 AddStatOpt(12,
"Chi square / NDF");
1402 AddStatOpt(13,
"Probability");
1403 menu.add(
"endsub:");
1405 menu.add(
"separator");
1406 }
else if (pave.fName ===
"title")
1407 menu.add(
"Default position",
function() {
1413 this.InteractiveRedraw(
true,
"pave_moved");
1416 if (this.UseTextColor)
1417 this.TextAttContextMenu(menu);
1419 this.FillAttContextMenu(menu);
1421 if (menu.size() > 0)
1422 menu.add(
'Inspect',
this.ShowInspector);
1424 return menu.size() > 0;
1427 TPavePainter.prototype.ShowContextMenu =
function(evnt) {
1431 return this.frame_painter().ShowContextMenu(
"z", evnt, this.GetObject().fAxis);
1434 d3.event.stopPropagation();
1435 d3.event.preventDefault();
1441 this.ctx_menu_evnt = evnt;
1443 JSROOT.Painter.createMenu(
this,
function(menu) {
1444 menu.painter.FillContextMenu(menu);
1446 menu.painter.FillObjectExecMenu(menu,
"title",
function() {
1447 menu.show(menu.painter.ctx_menu_evnt);
1452 TPavePainter.prototype.IsStats =
function() {
1453 return this.MatchObjectType(
'TPaveStats');
1456 TPavePainter.prototype.ClearPave =
function() {
1457 this.GetObject().Clear();
1460 TPavePainter.prototype.AddText =
function(txt) {
1461 this.GetObject().AddText(txt);
1464 TPavePainter.prototype.FillFunctionStat =
function(f1, dofit) {
1465 if (!dofit || !f1)
return false;
1467 var print_fval = dofit % 10,
1468 print_ferrors = Math.floor(dofit/10) % 10,
1469 print_fchi2 = Math.floor(dofit/100) % 10,
1470 print_fprob = Math.floor(dofit/1000) % 10;
1472 if (print_fchi2 > 0)
1473 this.AddText(
"#chi^2 / ndf = " + this.Format(f1.fChisquare,
"fit") +
" / " + f1.fNDF);
1474 if (print_fprob > 0)
1475 this.AddText(
"Prob = " + ((
'Math' in JSROOT) ? this.Format(JSROOT.Math.Prob(f1.fChisquare, f1.fNDF)) :
"<not avail>"));
1477 for(var n=0;n<f1.GetNumPars();++n) {
1478 var parname = f1.GetParName(n), parvalue = f1.GetParValue(n), parerr = f1.GetParError(n);
1480 parvalue = (parvalue===undefined) ?
"<not avail>" : this.Format(Number(parvalue),
"fit");
1481 if (parerr !== undefined) {
1482 parerr = this.Format(parerr,
"last");
1483 if ((Number(parerr)===0) && (f1.GetParError(n) != 0)) parerr = this.Format(f1.GetParError(n),
"4.2g");
1486 if ((print_ferrors > 0) && parerr)
1487 this.AddText(parname +
" = " + parvalue +
" #pm " + parerr);
1489 this.AddText(parname +
" = " + parvalue);
1495 TPavePainter.prototype.FillStatistic =
function() {
1497 var pp = this.pad_painter();
1498 if (pp && pp._fast_drawing)
return false;
1500 var pave = this.GetObject(),
1501 main = pave.$main_painter || this.main_painter();
1503 if (pave.fName !==
"stats")
return false;
1504 if (!main || (typeof main.FillStatistic !==
'function'))
return false;
1506 var dostat = parseInt(pave.fOptStat), dofit = parseInt(pave.fOptFit);
1507 if (isNaN(dostat)) dostat = JSROOT.gStyle.fOptStat;
1508 if (isNaN(dofit)) dofit = JSROOT.gStyle.fOptFit;
1511 if (!main.FillStatistic(
this, dostat, dofit))
return false;
1514 var nlines = pave.fLines.arr.length,
1515 stath = nlines * JSROOT.gStyle.StatFontSize;
1516 if ((stath <= 0) || (JSROOT.gStyle.StatFont % 10 === 3)) {
1517 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
1518 pave.fY1NDC = pave.fY2NDC - stath;
1524 TPavePainter.prototype.IsDummyPos =
function(p) {
1525 if (!p)
return true;
1527 return !p.fInit && !p.fX1 && !p.fX2 && !p.fY1 && !p.fY2 && !p.fX1NDC && !p.fX2NDC && !p.fY1NDC && !p.fY2NDC;
1530 TPavePainter.prototype.UpdateObject =
function(obj) {
1531 if (!this.MatchObjectType(obj))
return false;
1533 var pave = this.GetObject();
1535 if (!pave.modified_NDC && !
this.IsDummyPos(obj)) {
1538 if (this.stored && !obj.fInit && (
this.stored.fX1 == obj.fX1)
1539 && (this.stored.fX2 == obj.fX2) && (this.stored.fY1 == obj.fY1) && (this.stored.fY2 == obj.fY2)) {
1542 if (this.stored.fX1NDC != obj.fX1NDC) pave.fX1NDC = obj.fX1NDC;
1543 if (this.stored.fX2NDC != obj.fX2NDC) pave.fX2NDC = obj.fX2NDC;
1544 if (this.stored.fY1NDC != obj.fY1NDC) pave.fY1NDC = obj.fY1NDC;
1545 if (this.stored.fY2NDC != obj.fY2NDC) pave.fY2NDC = obj.fY2NDC;
1547 pave.fInit = obj.fInit;
1548 pave.fX1 = obj.fX1; pave.fX2 = obj.fX2;
1549 pave.fY1 = obj.fY1; pave.fY2 = obj.fY2;
1550 pave.fX1NDC = obj.fX1NDC; pave.fX2NDC = obj.fX2NDC;
1551 pave.fY1NDC = obj.fY1NDC; pave.fY2NDC = obj.fY2NDC;
1554 this.stored = JSROOT.extend({}, obj);
1557 pave.fOption = obj.fOption;
1558 pave.fBorderSize = obj.fBorderSize;
1560 switch (obj._typename) {
1562 pave.fLines = JSROOT.clone(obj.fLines);
1565 pave.fLines = JSROOT.clone(obj.fLines);
1566 pave.fNpaves = obj.fNpaves;
1569 pave.fLabel = obj.fLabel;
1572 pave.fOptStat = obj.fOptStat;
1573 pave.fOptFit = obj.fOptFit;
1576 var oldprim = pave.fPrimitives;
1577 pave.fPrimitives = obj.fPrimitives;
1578 pave.fNColumns = obj.fNColumns;
1579 if (oldprim && oldprim.arr && pave.fPrimitives && pave.fPrimitives.arr && (oldprim.arr.length == pave.fPrimitives.arr.length)) {
1582 for (var k=0;k<oldprim.arr.length;++k) {
1583 var oldobj = oldprim.arr[k].fObject, newobj = pave.fPrimitives.arr[k].fObject;
1585 if (oldobj && newobj && oldobj._typename == newobj._typename && oldobj.fName == newobj.fName)
1586 pave.fPrimitives.arr[k].fObject = oldobj;
1590 case 'TPaletteAxis':
1591 pave.fBorderSize = 1;
1592 pave.fShadowColor = 0;
1599 TPavePainter.prototype.Redraw =
function() {
1603 TPavePainter.prototype.Cleanup =
function() {
1604 if (this.z_handle) {
1605 this.z_handle.Cleanup();
1606 delete this.z_handle;
1609 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
1612 function drawPave(divid, pave, opt) {
1615 if ((typeof opt ==
'string') && (opt.indexOf(
"onpad:")==0)) {
1616 onpad = opt.substr(6);
1620 var painter =
new JSROOT.TPavePainter(pave);
1622 painter.SetDivId(divid, 2, onpad);
1624 if ((pave.fName ===
"title") && (pave._typename ===
"TPaveText")) {
1625 var tpainter = painter.FindPainterFor(null,
"title");
1626 if (tpainter && (tpainter !== painter)) {
1627 tpainter.DeleteThis();
1628 }
else if ((opt ==
"postitle") || painter.IsDummyPos(pave)) {
1629 var st = JSROOT.gStyle, fp = painter.frame_painter();
1631 var midx = st.fTitleX, y2 = st.fTitleY, w = st.fTitleW, h = st.fTitleH;
1632 if (!h && fp) h = (y2-fp.fY2NDC)*0.7;
1633 if (!w && fp) w = fp.fX2NDC - fp.fX1NDC;
1634 if (!h || isNaN(h) || (h<0)) h = 0.06;
1635 if (!w || isNaN(w) || (w<0)) w = 0.44;
1636 pave.fX1NDC = midx - w/2;
1637 pave.fY1NDC = y2 - h;
1638 pave.fX2NDC = midx + w/2;
1643 }
else if (pave._typename ===
"TPaletteAxis") {
1644 pave.fBorderSize = 1;
1645 pave.fShadowColor = 0;
1649 if (!pave.fAxis.fChopt) pave.fAxis.fChopt =
"+";
1650 if (!pave.fAxis.fNdiv) pave.fAxis.fNdiv = 12;
1651 if (!pave.fAxis.fLabelOffset) pave.fAxis.fLabelOffset = 0.005;
1654 painter.z_handle =
new JSROOT.TAxisPainter(pave.fAxis,
true);
1655 painter.z_handle.SetDivId(divid, -1);
1657 painter.UseContextMenu =
true;
1660 switch (pave._typename) {
1662 painter.PaveDrawFunc = painter.DrawPaveLabel;
1665 painter.PaveDrawFunc = painter.DrawPaveStats;
1666 painter.$secondary =
true;
1671 painter.PaveDrawFunc = painter.DrawPaveText;
1674 painter.PaveDrawFunc = painter.DrawPaveLegend;
1676 case "TPaletteAxis":
1677 painter.PaveDrawFunc = painter.DrawPaletteAxis;
1681 painter.DrawPave(opt);
1684 return painter.PaveDrawFunc ? painter : painter.DrawingReady();
1691 function produceLegend(divid, opt) {
1692 var main_painter = JSROOT.GetMainPainter(divid);
1693 if (!main_painter)
return;
1695 var pp = main_painter.pad_painter(),
1696 pad = main_painter.root_pad();
1697 if (!pp || !pad)
return;
1699 var leg = JSROOT.Create(
"TLegend");
1701 for (var k=0;k<pp.painters.length;++k) {
1702 var painter = pp.painters[k],
1703 obj = painter.GetObject();
1707 var entry = JSROOT.Create(
"TLegendEntry");
1708 entry.fObject = obj;
1709 entry.fLabel = (opt ==
"all") ? obj.fName : painter.GetItemName();
1711 if (!entry.fLabel)
continue;
1713 if (painter.lineatt && painter.lineatt.used) entry.fOption+=
"l";
1714 if (painter.fillatt && painter.fillatt.used) entry.fOption+=
"f";
1715 if (painter.markeratt && painter.markeratt.used) entry.fOption+=
"m";
1716 if (!entry.fOption) entry.fOption =
"l";
1718 leg.fPrimitives.Add(entry);
1722 var szx = 0.4, szy = leg.fPrimitives.arr.length;
1727 JSROOT.extend(leg, {
1728 fX1NDC: szx*pad.fLeftMargin + (1-szx)*(1-pad.fRightMargin),
1729 fY1NDC: (1-szy)*(1-pad.fTopMargin) + szy*pad.fBottomMargin,
1730 fX2NDC: 0.99-pad.fRightMargin,
1731 fY2NDC: 0.99-pad.fTopMargin
1733 leg.fFillStyle = 1001;
1735 return drawPave(divid, leg);
1740 function THistDrawOptions(opt) {
1744 THistDrawOptions.prototype.Reset =
function() {
1746 { Axis: 0, RevX:
false, RevY:
false, Bar:
false, BarStyle: 0, Curve:
false,
1747 Hist:
true, Line:
false, Fill:
false,
1748 Error:
false, ErrorKind: -1, errorX: JSROOT.gStyle.fErrorX,
1749 Mark:
false, Same:
false, Scat:
false, ScatCoef: 1., Func:
true,
1750 Arrow:
false, Box:
false, BoxStyle: 0,
1751 Text:
false, TextAngle: 0, TextKind:
"", Char: 0, Color:
false, Contour: 0,
1752 Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0,
1753 Spec:
false, Pie:
false, List:
false, Zscale:
false, PadPalette:
false, Candle:
"",
1754 GLBox: 0, GLColor:
false, Project:
"",
1755 System: JSROOT.Painter.Coord.kCARTESIAN,
1756 AutoColor:
false, NoStat:
false, ForceStat:
false, PadStats:
false, PadTitle:
false, AutoZoom:
false,
1757 HighRes: 0, Zero:
true, Palette: 0, BaseLine:
false,
1758 Optimize: JSROOT.gStyle.OptimizeDraw, Mode3D:
false,
1759 FrontBox:
true, BackBox:
true,
1760 _pmc:
false, _plc:
false, _pfc:
false, need_fillcol:
false,
1761 minimum: -1111, maximum: -1111, ymin:0, ymax:0 });
1764 THistDrawOptions.prototype.Decode =
function(opt, hdim, histo, pad, painter) {
1767 var d =
new JSROOT.DrawOptions(opt), check3dbox =
"";
1769 if ((hdim===1) && (histo.fSumw2.length > 0))
1770 for (var n=0;n<histo.fSumw2.length;++n)
1771 if (histo.fSumw2[n] > 0) { this.Error =
true; this.Hist =
false; this.Zero =
false;
break; }
1773 this.ndim = hdim || 1;
1775 this.PadStats = d.check(
"USE_PAD_STATS");
1776 this.PadPalette = d.check(
"USE_PAD_PALETTE");
1777 this.PadTitle = d.check(
"USE_PAD_TITLE");
1779 if (d.check(
'PAL',
true)) this.Palette = d.partAsInt();
1781 if (d.check(
'MINIMUM:',
true)) this.minimum = parseFloat(d.part);
else this.minimum = histo.fMinimum;
1782 if (d.check(
'MAXIMUM:',
true)) this.maximum = parseFloat(d.part);
else this.maximum = histo.fMaximum;
1784 if (d.check(
'YMIN:',
true)) this.ymin = parseFloat(d.part);
1785 if (d.check(
'YMAX:',
true)) this.ymax = parseFloat(d.part);
1788 if (d.check(
'NOOPTIMIZE')) this.Optimize = 0;
1789 if (d.check(
'OPTIMIZE')) this.Optimize = 2;
1791 if (d.check(
'AUTOCOL')) this.AutoColor =
true;
1792 if (d.check(
'AUTOZOOM')) this.AutoZoom =
true;
1794 if (d.check(
'OPTSTAT',
true)) this.optstat = d.partAsInt();
1795 if (d.check(
'OPTFIT',
true)) this.optfit = d.partAsInt();
1797 if (d.check(
'NOSTAT')) this.NoStat =
true;
1798 if (d.check(
'STAT')) this.ForceStat =
true;
1800 if (d.check(
'NOTOOLTIP') && painter) painter.SetTooltipAllowed(
false);
1801 if (d.check(
'TOOLTIP') && painter) painter.SetTooltipAllowed(
true);
1803 if (d.check(
'LOGX') && pad) { pad.fLogx = 1; pad.fUxmin = 0; pad.fUxmax = 1; pad.fX1 = 0; pad.fX2 = 1; }
1804 if (d.check(
'LOGY') && pad) { pad.fLogy = 1; pad.fUymin = 0; pad.fUymax = 1; pad.fY1 = 0; pad.fY2 = 1; }
1805 if (d.check(
'LOGZ') && pad) pad.fLogz = 1;
1806 if (d.check(
'GRIDXY') && pad) pad.fGridx = pad.fGridy = 1;
1807 if (d.check(
'GRIDX') && pad) pad.fGridx = 1;
1808 if (d.check(
'GRIDY') && pad) pad.fGridy = 1;
1809 if (d.check(
'TICKXY') && pad) pad.fTickx = pad.fTicky = 1;
1810 if (d.check(
'TICKX') && pad) pad.fTickx = 1;
1811 if (d.check(
'TICKY') && pad) pad.fTicky = 1;
1813 if (d.check(
'FILL_',
true)) {
1814 if (d.partAsInt(1)>0) this.histoFillColor = d.partAsInt();
else
1815 for (var col=0;col<8;++col)
1816 if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) this.histoFillColor = col;
1818 if (d.check(
'LINE_',
true)) {
1819 if (d.partAsInt(1)>0) this.histoLineColor = JSROOT.Painter.root_colors[d.partAsInt()];
else
1820 for (var col=0;col<8;++col)
1821 if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) this.histoLineColor = d.part;
1824 if (d.check(
'X+')) this.AxisPos = 10;
1825 if (d.check(
'Y+')) this.AxisPos += 1;
1827 if (d.check(
'SAMES')) { this.Same =
true; this.ForceStat =
true; }
1828 if (d.check(
'SAME')) { this.Same =
true; this.Func =
true; }
1830 if (d.check(
'SPEC')) this.Spec =
true;
1832 if (d.check(
'BASE0') || d.check(
'MIN0')) this.BaseLine = 0;
else
1833 if (JSROOT.gStyle.fHistMinimumZero) this.BaseLine = 0;
1835 if (d.check(
'PIE')) this.Pie =
true;
1837 if (d.check(
'CANDLE',
true)) this.Candle = d.part;
1839 if (d.check(
'GLBOX',
true)) this.GLBox = 10 + d.partAsInt();
1840 if (d.check(
'GLCOL')) this.GLColor =
true;
1844 if (d.check(
'LEGO',
true)) {
1846 if (d.part.indexOf(
'0') >= 0) this.Zero =
false;
1847 if (d.part.indexOf(
'1') >= 0) this.Lego = 11;
1848 if (d.part.indexOf(
'2') >= 0) this.Lego = 12;
1849 if (d.part.indexOf(
'3') >= 0) this.Lego = 13;
1850 if (d.part.indexOf(
'4') >= 0) this.Lego = 14;
1851 check3dbox = d.part;
1852 if (d.part.indexOf(
'Z') >= 0) this.Zscale =
true;
1855 if (d.check(
'SURF',
true)) {
1856 this.Surf = d.partAsInt(10, 1);
1857 check3dbox = d.part;
1858 if (d.part.indexOf(
'Z')>=0) this.Zscale =
true;
1861 if (d.check(
'TF3',
true)) check3dbox = d.part;
1863 if (d.check(
'ISO',
true)) check3dbox = d.part;
1865 if (d.check(
'LIST')) this.List =
true;
1867 if (d.check(
'CONT',
true) && (hdim>1)) {
1869 if (d.part.indexOf(
'Z') >= 0) this.Zscale =
true;
1870 if (d.part.indexOf(
'1') >= 0) this.Contour = 11;
else
1871 if (d.part.indexOf(
'2') >= 0) this.Contour = 12;
else
1872 if (d.part.indexOf(
'3') >= 0) this.Contour = 13;
else
1873 if (d.part.indexOf(
'4') >= 0) this.Contour = 14;
1877 if (d.check(
'HBAR',
true)) this.BarStyle = 20;
else
1878 if (d.check(
'BAR',
true)) this.BarStyle = 10;
1879 if (this.BarStyle > 0) {
1881 this.need_fillcol =
true;
1882 this.BarStyle += d.partAsInt();
1888 if (d.check(
'BOX',
true))
1889 this.BoxStyle = 10 + d.partAsInt();
1891 this.Box = this.BoxStyle > 0;
1893 if (d.check(
'COL')) this.Color =
true;
1894 if (d.check(
'CHAR')) this.Char = 1;
1895 if (d.check(
'FUNC')) { this.Func =
true; this.Hist =
false; }
1896 if (d.check(
'AXIS')) this.Axis = 1;
1897 if (d.check(
'AXIG')) this.Axis = 2;
1899 if (d.check(
'TEXT',
true)) {
1902 this.TextAngle = Math.min(d.partAsInt(), 90);
1903 if (d.part.indexOf(
'N')>=0) this.TextKind =
"N";
1904 if (d.part.indexOf(
'E0')>=0) this.TextLine =
true;
1905 if (d.part.indexOf(
'E')>=0) this.TextKind =
"E";
1908 if (d.check(
'SCAT=',
true)) {
1910 this.ScatCoef = parseFloat(d.part);
1911 if (isNaN(this.ScatCoef) || (this.ScatCoef<=0)) this.ScatCoef = 1.;
1914 if (d.check(
'SCAT')) this.Scat =
true;
1915 if (d.check(
'POL')) this.System = JSROOT.Painter.Coord.kPOLAR;
1916 if (d.check(
'CYL')) this.System = JSROOT.Painter.Coord.kCYLINDRICAL;
1917 if (d.check(
'SPH')) this.System = JSROOT.Painter.Coord.kSPHERICAL;
1918 if (d.check(
'PSR')) this.System = JSROOT.Painter.Coord.kRAPIDITY;
1920 if (d.check(
'TRI',
true)) {
1923 check3dbox = d.part;
1924 if (d.part.indexOf(
'ERR') >= 0) this.Error =
true;
1927 if (d.check(
'AITOFF')) this.Proj = 1;
1928 if (d.check(
'MERCATOR')) this.Proj = 2;
1929 if (d.check(
'SINUSOIDAL')) this.Proj = 3;
1930 if (d.check(
'PARABOLIC')) this.Proj = 4;
1931 if (this.Proj > 0) this.Contour = 14;
1933 if (d.check(
'PROJX',
true)) this.Project =
"X" + d.partAsInt(0,1);
1934 if (d.check(
'PROJY',
true)) this.Project =
"Y" + d.partAsInt(0,1);
1937 if (check3dbox.indexOf(
'FB') >= 0) this.FrontBox =
false;
1938 if (check3dbox.indexOf(
'BB') >= 0) this.BackBox =
false;
1941 if ((hdim==3) && d.check(
'FB')) this.FrontBox =
false;
1942 if ((hdim==3) && d.check(
'BB')) this.BackBox =
false;
1944 this._pfc = d.check(
"PFC");
1945 this._plc = d.check(
"PLC") || this.AutoColor;
1946 this._pmc = d.check(
"PMC");
1948 if (d.check(
'L')) { this.Line =
true; this.Hist =
false; this.Error =
false; }
1949 if (d.check(
'F')) { this.Fill =
true; this.need_fillcol =
true; }
1951 if (d.check(
'A')) this.Axis = -1;
1952 if (this.Axis && d.check(
"RX")) this.RevX =
true;
1953 if (this.Axis && d.check(
"RY")) this.RevY =
true;
1955 if (d.check(
'B1')) { this.BarStyle = 1; this.BaseLine = 0; this.Hist =
false; this.need_fillcol =
true; }
1956 if (d.check(
'B')) { this.BarStyle = 1; this.Hist =
false; this.need_fillcol =
true; }
1957 if (d.check(
'C')) { this.Curve =
true; this.Hist =
false; }
1958 if (d.check(
'][')) { this.Off = 1; this.Hist =
true; }
1960 if (d.check(
'HIST')) { this.Hist =
true; this.Func =
true; this.Error =
false; }
1962 this.Bar = (this.BarStyle > 0);
1964 delete this.MarkStyle;
1966 if (d.check(
'P0')) { this.Mark =
true; this.Hist =
false; this.Zero =
true; }
1967 if (d.check(
'P')) { this.Mark =
true; this.Hist =
false; this.Zero =
false; }
1968 if (d.check(
'Z')) this.Zscale =
true;
1969 if (d.check(
'*')) { this.Mark =
true; this.MarkStyle = 3; this.Hist =
false; }
1970 if (d.check(
'H')) this.Hist =
true;
1972 if (d.check(
'E',
true)) {
1977 if (!isNaN(parseInt(d.part[0]))) this.ErrorKind = parseInt(d.part[0]);
1978 if ((this.ErrorKind === 3) || (this.ErrorKind === 4)) this.need_fillcol =
true;
1979 if (this.ErrorKind === 0) this.Zero =
true;
1980 if (d.part.indexOf(
'X0')>=0) this.errorX = 0;
1983 if (d.check(
'9')) this.HighRes = 1;
1984 if (d.check(
'0')) this.Zero =
false;
1985 if (this.Color && d.check(
'1')) this.Zero =
false;
1988 if ((this.Lego > 0) || (hdim == 3) ||
1989 ((this.Surf > 0) || this.Error && (hdim == 2))) this.Mode3D =
true;
1997 THistDrawOptions.prototype.asString =
function(painter) {
1998 var fp = painter ? painter.frame_painter() : null;
2005 if (!this.Zero) res +=
"0";
2006 if (this.Lego > 10) res += (this.Lego-10);
2007 if (this.Zscale) res+=
"Z";
2008 }
else if (this.Surf) {
2009 res =
"SURF" + (this.Surf-10);
2010 if (this.Zscale) res+=
"Z";
2012 if (!this.FrontBox) res+=
"FB";
2013 if (!this.BackBox) res+=
"BB";
2018 }
else if (this.Color) {
2020 if (!this.Zero) res+=
"0";
2021 if (this.Zscale) res+=
"Z";
2022 if (this.Axis < 0) res+=
"A";
2023 }
else if (this.Contour) {
2025 if (this.Contour > 10) res += (this.Contour-10);
2026 if (this.Zscale) res+=
"Z";
2027 }
else if (this.Bar) {
2028 res = (this.BaseLine ===
false) ?
"B" :
"B1";
2029 }
else if (this.Mark) {
2030 res = this.Zero ?
"P0" :
"P";
2031 }
else if (this.Scat) {
2033 }
else if (this.Error) {
2035 if (this.ErrorKind>=0) res += this.ErrorKind;
2036 }
else if (this.Line) {
2038 if (this.Fill) res +=
"F";
2043 if (this.TextAngle) res += this.TextAngle;
2044 res += this.TextKind;
2063 function THistPainter(histo) {
2064 JSROOT.TObjectPainter.call(
this, histo);
2065 this.draw_content =
true;
2068 this.accept_drops =
true;
2069 this.mode3d =
false;
2070 this.hist_painter_id = JSROOT.id_counter++;
2073 THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2075 THistPainter.prototype.GetHisto =
function() {
2076 return this.GetObject();
2079 THistPainter.prototype.GetAxis =
function(name) {
2080 var histo = this.GetObject();
2083 case "x":
return histo.fXaxis;
2084 case "y":
return histo.fYaxis;
2085 case "z":
return histo.fZaxis;
2090 THistPainter.prototype.IsTProfile =
function() {
2091 return this.MatchObjectType(
'TProfile');
2094 THistPainter.prototype.IsTH1K =
function() {
2095 return this.MatchObjectType(
'TH1K');
2098 THistPainter.prototype.IsTH2Poly =
function() {
2099 return this.MatchObjectType(/^TH2Poly/) || this.MatchObjectType(/^TProfile2Poly/);
2102 THistPainter.prototype.Clear3DScene =
function() {
2103 var fp = this.frame_painter();
2104 if (fp && typeof fp.Create3DScene ===
'function')
2105 fp.Create3DScene(-1);
2106 this.mode3d =
false;
2110 THistPainter.prototype.Cleanup =
function() {
2113 this.Clear3DScene();
2115 delete this.fPalette;
2116 delete this.fContour;
2117 delete this.options;
2119 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
2122 THistPainter.prototype.Dimension =
function() {
2123 var histo = this.GetHisto();
2124 if (!histo)
return 0;
2125 if (histo._typename.match(/^TH2/))
return 2;
2126 if (histo._typename.match(/^TProfile2D/))
return 2;
2127 if (histo._typename.match(/^TH3/))
return 3;
2133 THistPainter.prototype.DecodeOptions =
function(opt) {
2134 var histo = this.GetHisto(),
2135 hdim = this.Dimension(),
2136 pad = this.root_pad();
2139 this.options =
new THistDrawOptions;
2141 this.options.Reset();
2143 this.options.Decode(opt || histo.fOption, hdim, histo, pad,
this);
2145 this.OptionsStore(opt);
2148 THistPainter.prototype.CopyOptionsFrom =
function(src) {
2149 if (src ===
this)
return;
2150 var o = this.options, o0 = src.options;
2152 o.Mode3D = o0.Mode3D;
2159 o.Contour = o0.Contour;
2164 THistPainter.prototype.CopyOptionsToOthers =
function() {
2167 this.ForEachPainter(
function(painter) {
2168 if (painter === pthis)
return;
2169 if (typeof painter.CopyOptionsFrom ==
'function')
2170 painter.CopyOptionsFrom(pthis);
2174 THistPainter.prototype.ScanContent =
function(when_axis_changed) {
2180 alert(
"HistPainter.prototype.ScanContent not implemented");
2183 THistPainter.prototype.CheckPadRange =
function(use_pad) {
2186 if (this.is_main_painter())
2187 this.check_pad_range = use_pad ?
"pad_range" :
true;
2190 THistPainter.prototype.CheckHistDrawAttributes =
function() {
2192 var histo = this.GetHisto(),
2193 pp = this.pad_painter();
2195 if (pp && (this.options._pfc ||
this.options._plc ||
this.options._pmc)) {
2196 var icolor = pp.CreateAutoColor();
2197 if (this.options._pfc) { histo.fFillColor = icolor;
delete this.fillatt; }
2198 if (this.options._plc) { histo.fLineColor = icolor;
delete this.lineatt; }
2199 if (this.options._pmc) { histo.fMarkerColor = icolor;
delete this.markeratt; }
2200 this.options._pfc = this.options._plc = this.options._pmc =
false;
2203 this.createAttFill({ attr: histo, color: this.options.histoFillColor, kind: 1 });
2205 this.createAttLine({ attr: histo, color0: this.options.histoLineColor });
2212 THistPainter.prototype.UpdateObject =
function(obj, opt) {
2214 var histo = this.GetHisto(),
2215 fp = this.frame_painter();
2217 if (obj !== histo) {
2219 if (!this.MatchObjectType(obj))
return false;
2227 if (histo.TestBit(JSROOT.TH1StatusBits.kNoStats) != obj.TestBit(JSROOT.TH1StatusBits.kNoStats)) {
2228 histo.fBits = obj.fBits;
2230 var statpainter = this.FindPainterFor(this.FindStat());
2231 if (statpainter) statpainter.Enabled = !histo.TestBit(JSROOT.TH1StatusBits.kNoStats);
2237 if (this.snapid !== undefined)
2238 histo.fName = obj.fName;
2240 histo.fFillColor = obj.fFillColor;
2241 histo.fFillStyle = obj.fFillStyle;
2242 histo.fLineColor = obj.fLineColor;
2243 histo.fLineStyle = obj.fLineStyle;
2244 histo.fLineWidth = obj.fLineWidth;
2246 histo.fEntries = obj.fEntries;
2247 histo.fTsumw = obj.fTsumw;
2248 histo.fTsumwx = obj.fTsumwx;
2249 histo.fTsumwx2 = obj.fTsumwx2;
2250 histo.fXaxis.fNbins = obj.fXaxis.fNbins;
2251 if (this.Dimension() > 1) {
2252 histo.fTsumwy = obj.fTsumwy;
2253 histo.fTsumwy2 = obj.fTsumwy2;
2254 histo.fTsumwxy = obj.fTsumwxy;
2255 histo.fYaxis.fNbins = obj.fYaxis.fNbins;
2256 if (this.Dimension() > 2) {
2257 histo.fTsumwz = obj.fTsumwz;
2258 histo.fTsumwz2 = obj.fTsumwz2;
2259 histo.fTsumwxz = obj.fTsumwxz;
2260 histo.fTsumwyz = obj.fTsumwyz;
2261 histo.fZaxis.fNbins = obj.fZaxis.fNbins;
2265 histo.fArray = obj.fArray;
2266 histo.fNcells = obj.fNcells;
2267 histo.fTitle = obj.fTitle;
2268 histo.fMinimum = obj.fMinimum;
2269 histo.fMaximum = obj.fMaximum;
2270 function CopyAxis(tgt,src) {
2271 tgt.fTitle = src.fTitle;
2272 tgt.fLabels = src.fLabels;
2273 tgt.fXmin = src.fXmin;
2274 tgt.fXmax = src.fXmax;
2275 tgt.fTimeDisplay = src.fTimeDisplay;
2276 tgt.fTimeFormat = src.fTimeFormat;
2278 tgt.fAxisColor = src.fAxisColor;
2279 tgt.fLabelColor = src.fLabelColor;
2280 tgt.fLabelFont = src.fLabelFont;
2281 tgt.fLabelOffset = src.fLabelOffset;
2282 tgt.fLabelSize = src.fLabelSize;
2283 tgt.fNdivisions = src.fNdivisions;
2284 tgt.fTickLength = src.fTickLength;
2285 tgt.fTitleColor = src.fTitleColor;
2286 tgt.fTitleFont = src.fTitleFont;
2287 tgt.fTitleOffset = src.fTitleOffset;
2288 tgt.fTitleSize = src.fTitleSize;
2290 CopyAxis(histo.fXaxis, obj.fXaxis);
2291 CopyAxis(histo.fYaxis, obj.fYaxis);
2292 CopyAxis(histo.fZaxis, obj.fZaxis);
2294 if (this.snapid || !fp || !fp.zoom_changed_interactive) {
2295 function CopyZoom(tgt,src) {
2296 tgt.fFirst = src.fFirst;
2297 tgt.fLast = src.fLast;
2298 tgt.fBits = src.fBits;
2300 CopyZoom(histo.fXaxis, obj.fXaxis);
2301 CopyZoom(histo.fYaxis, obj.fYaxis);
2302 CopyZoom(histo.fZaxis, obj.fZaxis);
2304 histo.fSumw2 = obj.fSumw2;
2306 if (this.IsTProfile()) {
2307 histo.fBinEntries = obj.fBinEntries;
2308 }
else if (this.IsTH1K()) {
2309 histo.fNIn = obj.fNIn;
2310 histo.fReady =
false;
2311 }
else if (this.IsTH2Poly()) {
2312 histo.fBins = obj.fBins;
2315 if (this.options.Func) {
2317 var painters = [], newfuncs = [], pp = this.pad_painter(), pid = this.hist_painter_id;
2321 pp.ForEachPainterInPad(
function(objp) {
2322 if (objp.child_painter_id === pid)
2323 painters.push(objp);
2327 for (var n=0;n<obj.fFunctions.arr.length;++n) {
2328 var func = obj.fFunctions.arr[n];
2329 if (!func || !func._typename)
continue;
2330 var funcpainter = null, func_indx = -1;
2333 for (var i=0;i<painters.length;++i)
2334 if (painters[i].MatchObjectType(func._typename) && (painters[i].GetObject().fName === func.fName)) {
2335 funcpainter = painters[i];
2340 if (!funcpainter && func.fName)
2341 funcpainter = this.FindPainterFor(null, func.fName, func._typename);
2344 funcpainter.UpdateObject(func);
2345 if (func_indx >= 0) painters.splice(func_indx, 1);
2347 newfuncs.push(func);
2352 if (pp && (painters.length > 0))
2353 pp.CleanPrimitives(
function(p) {
return painters.indexOf(p) >= 0; });
2356 if (pp && (newfuncs.length > 0)) {
2357 var prev_name = pp.has_canvas ? pp.CurrentPadName(pp.this_pad_name) : undefined;
2358 for (var k=0;k<newfuncs.length;++k)
2359 JSROOT.draw(
this.divid, newfuncs[k],
"", function (painter) { painter.child_painter_id = pid; } )
2360 pp.CurrentPadName(prev_name);
2364 var changed_opt = (histo.fOption != obj.fOption);
2365 histo.fOption = obj.fOption;
2367 if (((opt !== undefined) && (this.options.original !== opt)) || changed_opt)
2368 this.DecodeOptions(opt || histo.fOption);
2371 if (this.snapid || !fp || !fp.zoom_changed_interactive)
2372 this.CheckPadRange();
2376 this.histogram_updated =
true;
2381 THistPainter.prototype.CreateAxisFuncs =
function(with_y_axis, with_z_axis) {
2385 var histo = this.GetHisto();
2387 function AssignFuncs(axis) {
2388 if (axis.fXbins.length >= axis.fNbins) {
2389 axis.regular =
false;
2390 axis.GetBinCoord =
function(bin) {
2391 var indx = Math.round(bin);
2392 if (indx <= 0)
return this.fXmin;
2393 if (indx > this.fNbins)
return this.fXmax;
2394 if (indx==bin)
return this.fXbins[indx];
2395 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
2396 return this.fXbins[indx] * Math.abs(bin-indx2) + this.fXbins[indx2] * Math.abs(bin-indx);
2398 axis.FindBin =
function(x,add) {
2399 for (var k = 1; k < this.fXbins.length; ++k)
2400 if (x < this.fXbins[k])
return Math.floor(k-1+add);
2404 axis.regular =
true;
2405 axis.binwidth = (axis.fXmax - axis.fXmin) / (axis.fNbins || 1);
2406 axis.GetBinCoord =
function(bin) {
return this.fXmin + bin*this.binwidth; };
2407 axis.FindBin =
function(x,add) {
return Math.floor((x - this.fXmin) / this.binwidth + add); };
2411 this.xmin = histo.fXaxis.fXmin;
2412 this.xmax = histo.fXaxis.fXmax;
2413 AssignFuncs(histo.fXaxis);
2415 this.ymin = histo.fYaxis.fXmin;
2416 this.ymax = histo.fYaxis.fXmax;
2418 if (!with_y_axis || (this.nbinsy==0))
return;
2420 AssignFuncs(histo.fYaxis);
2422 if (!with_z_axis || (this.nbinsz==0))
return;
2424 AssignFuncs(histo.fZaxis);
2430 THistPainter.prototype.CreateXY =
function() {
2431 if (!this.is_main_painter())
return;
2433 var histo = this.GetHisto(),
2434 fp = this.frame_painter();
2437 return console.warn(
"histogram drawn without frame - not supported");
2440 if (this.ymin === this.ymax) this.ymax += 1;
2442 fp.SetAxesRanges(histo.fXaxis,
this.xmin,
this.xmax, histo.fYaxis,
this.ymin,
this.ymax, histo.fZaxis, 0, 0);
2443 fp.CreateXY({ ndim: this.Dimension(),
2444 check_pad_range: this.check_pad_range,
2445 create_canvas: this.create_canvas,
2446 zoom_ymin: this.zoom_ymin,
2447 zoom_ymax: this.zoom_ymax,
2448 ymin_nz: this.ymin_nz,
2449 swap_xy: (this.options.BarStyle >= 20),
2450 reverse_x: this.options.RevX,
2451 reverse_y:
this.options.RevY,
2452 Proj:
this.options.Proj,
2453 extra_y_space:
this.options.Text && (
this.options.BarStyle > 0) });
2454 delete this.check_pad_range;
2457 THistPainter.prototype.DrawBins =
function() {
2458 alert(
"HistPainter.DrawBins not implemented");
2461 THistPainter.prototype.DrawAxes =
function() {
2464 if (!this.is_main_painter() || this.options.Same)
return;
2466 var fp = this.frame_painter();
2469 fp.DrawAxes(
false, this.options.Axis < 0,
this.options.AxisPos,
this.options.Zscale);
2473 THistPainter.prototype.ToggleTitle =
function(arg) {
2474 var histo = this.GetHisto();
2475 if (!this.is_main_painter() || !histo)
return false;
2476 if (arg===
'only-check')
return !histo.TestBit(JSROOT.TH1StatusBits.kNoTitle);
2477 histo.InvertBit(JSROOT.TH1StatusBits.kNoTitle);
2481 THistPainter.prototype.DrawTitle =
function() {
2484 if (!this.is_main_painter() || this.options.Same)
return;
2486 var histo = this.GetHisto(), st = JSROOT.gStyle,
2487 tpainter = this.FindPainterFor(null,
"title"),
2488 pt = tpainter ? tpainter.GetObject() : null;
2490 if (!pt) pt = this.FindInPrimitives(
"title");
2491 if (pt && (pt._typename !==
"TPaveText")) pt = null;
2493 var draw_title = !histo.TestBit(JSROOT.TH1StatusBits.kNoTitle) && (st.fOptTitle > 0);
2497 if (draw_title) pt.AddText(histo.fTitle);
2498 if (tpainter) tpainter.Redraw();
2499 }
else if (draw_title && !tpainter && histo.fTitle && !
this.options.PadTitle) {
2500 pt = JSROOT.Create(
"TPaveText");
2502 pt.fTextFont = st.fTitleFont;
2503 pt.fTextSize = st.fTitleFontSize;
2504 pt.fTextColor = st.fTitleTextColor;
2505 pt.fTextAlign = st.fTitleAlign;
2506 pt.fFillColor = st.fTitleColor;
2507 pt.fFillStyle = st.fTitleStyle;
2508 pt.fBorderSize = st.fTitleBorderSize;
2510 pt.AddText(histo.fTitle);
2511 tpainter = JSROOT.Painter.drawPave(this.divid, pt,
"postitle");
2512 if (tpainter) tpainter.$secondary =
true;
2516 THistPainter.prototype.processTitleChange =
function(arg) {
2518 var histo = this.GetHisto(),
2519 tpainter = this.FindPainterFor(null,
"title");
2521 if (!histo || !tpainter)
return null;
2524 return (!this.is_main_painter() || this.options.Same) ? null : histo;
2526 var pt = tpainter.GetObject();
2528 pt.AddText(histo.fTitle);
2532 this.WebCanvasExec(
'SetTitle("' + histo.fTitle +
'")');
2535 THistPainter.prototype.UpdateStatWebCanvas =
function() {
2536 if (!this.snapid)
return;
2538 var stat = this.FindStat(),
2539 statpainter = this.FindPainterFor(stat);
2541 if (statpainter && !statpainter.snapid) statpainter.Redraw();
2544 THistPainter.prototype.ToggleStat =
function(arg) {
2546 var stat = this.FindStat(), statpainter = null;
2551 if (arg.indexOf(
'-check') > 0)
return false;
2553 stat = this.CreateStat(
true);
2555 statpainter = this.FindPainterFor(stat);
2558 if (arg==
'only-check')
return statpainter ? statpainter.Enabled :
false;
2560 if (arg==
'fitpar-check')
return stat ? stat.fOptFit :
false;
2562 if (arg==
'fitpar-toggle') {
2563 if (!stat)
return false;
2564 stat.fOptFit = stat.fOptFit ? 0 : 1111;
2565 if (statpainter) statpainter.Redraw();
2570 statpainter.Enabled = !statpainter.Enabled;
2573 statpainter.Redraw();
2574 return statpainter.Enabled;
2577 JSROOT.draw(this.divid, stat,
"onpad:" + this.pad_name);
2582 THistPainter.prototype.GetSelectIndex =
function(axis, side, add) {
2585 main = this.frame_painter(),
2586 nbin =
this[
'nbins'+axis] || 0,
2587 taxis = this.GetAxis(axis),
2588 min = main ? main[
'zoom_' + axis +
'min'] : 0,
2589 max = main ? main[
'zoom_' + axis +
'max'] : 0;
2591 if ((min !== max) && taxis) {
2593 indx = taxis.FindBin(min, add || 0);
2595 indx = taxis.FindBin(max, (add || 0) + 0.5);
2596 if (indx<0) indx = 0;
else if (indx>nbin) indx = nbin;
2598 indx = (side ==
"left") ? 0 : nbin;
2603 if ((taxis.fFirst === taxis.fLast) || !taxis.TestBit(JSROOT.EAxisBits.kAxisRange) ||
2604 ((taxis.fFirst<=1) && (taxis.fLast>=nbin))) taxis = undefined;
2607 if (side ==
"left") {
2608 if (indx < 0) indx = 0;
2609 if (taxis && (taxis.fFirst>1) && (indx<taxis.fFirst)) indx = taxis.fFirst-1;
2611 if (indx > nbin) indx = nbin;
2612 if (taxis && (taxis.fLast <= nbin) && (indx>taxis.fLast)) indx = taxis.fLast;
2620 THistPainter.prototype.FindFunction =
function(type_name, obj_name) {
2621 var histo = this.GetObject(),
2622 funcs = histo && histo.fFunctions ? histo.fFunctions.arr : null;
2624 if (!funcs)
return null;
2626 for (var i = 0; i < funcs.length; ++i) {
2627 if (obj_name && (funcs[i].fName !== obj_name))
continue;
2628 if (funcs[i]._typename === type_name)
return funcs[i];
2636 THistPainter.prototype.FindStat =
function() {
2637 if (this.options.PadStats) {
2638 var p = this.FindPainterFor(null,
"stats",
"TPaveStats");
2639 return p ? p.GetObject() : null;
2642 return this.FindFunction(
'TPaveStats',
'stats');
2645 THistPainter.prototype.IgnoreStatsFill =
function() {
2646 return !this.GetObject() || (!this.draw_content && !this.create_stats) || (this.options.Axis>0);
2652 THistPainter.prototype.CreateStat =
function(force) {
2654 var histo = this.GetHisto();
2656 if (this.options.PadStats || !histo)
return null;
2658 if (!force && !this.options.ForceStat) {
2659 if (this.options.NoStat || histo.TestBit(JSROOT.TH1StatusBits.kNoStats) || !JSROOT.gStyle.AutoStat)
return null;
2661 if (!this.draw_content || !this.is_main_painter())
return null;
2664 var stats = this.FindStat(), st = JSROOT.gStyle,
2665 optstat = this.options.optstat, optfit = this.options.optfit;
2667 if (optstat !== undefined) {
2668 if (stats) stats.fOptStat = optstat;
2669 delete this.options.optstat;
2671 optstat = histo.$custom_stat || st.fOptStat;
2674 if (optfit !== undefined) {
2675 if (stats) stats.fOptFit = optfit;
2676 delete this.options.optfit;
2678 optfit = st.fOptFit;
2681 if (!stats && !optstat && !optfit)
return null;
2683 this.create_stats =
true;
2685 if (stats)
return stats;
2687 stats = JSROOT.Create(
'TPaveStats');
2688 JSROOT.extend(stats, { fName:
'stats',
2693 stats.fX1NDC = st.fStatX - st.fStatW;
2694 stats.fY1NDC = st.fStatY - st.fStatH;
2695 stats.fX2NDC = st.fStatX;
2696 stats.fY2NDC = st.fStatY;
2698 stats.fFillColor = st.fStatColor;
2699 stats.fFillStyle = st.fStatStyle;
2701 stats.fTextAngle = 0;
2702 stats.fTextSize = st.fStatFontSize;
2703 stats.fTextAlign = 12;
2704 stats.fTextColor = st.fStatTextColor;
2705 stats.fTextFont = st.fStatFont;
2707 if (histo._typename.match(/^TProfile/) || histo._typename.match(/^TH2/))
2708 stats.fY1NDC = 0.67;
2710 stats.AddText(histo.fName);
2712 this.AddFunction(stats);
2717 THistPainter.prototype.AddFunction =
function(obj, asfirst) {
2718 var histo = this.GetObject();
2719 if (!histo || !obj)
return;
2721 if (!histo.fFunctions)
2722 histo.fFunctions = JSROOT.Create(
"TList");
2725 histo.fFunctions.AddFirst(obj);
2727 histo.fFunctions.Add(obj);
2731 THistPainter.prototype.DrawNextFunction =
function(indx, callback, painter) {
2733 if (painter && (typeof painter ==
"object"))
2734 painter.child_painter_id =
this.hist_painter_id;
2736 var histo =
this.GetHisto();
2737 if (!this.options.Func || !histo.fFunctions ||
2738 (indx >= histo.fFunctions.arr.length))
return JSROOT.CallBack(callback);
2740 var func = histo.fFunctions.arr[indx],
2741 opt = histo.fFunctions.opt[indx],
2743 func_painter = this.FindPainterFor(func);
2747 if (func_painter === null) {
2748 if (func._typename ===
'TPaveText' || func._typename ===
'TPaveStats') {
2749 do_draw = !histo.TestBit(JSROOT.TH1StatusBits.kNoStats) && !this.options.NoStat;
2750 }
else if (func._typename ===
'TF1') {
2751 do_draw = !func.TestBit(JSROOT.BIT(9));
2753 do_draw = (func._typename !==
'TPaletteAxis');
2758 return JSROOT.draw(this.divid, func, opt, this.DrawNextFunction.bind(
this, indx+1, callback));
2760 this.DrawNextFunction(indx+1, callback);
2764 THistPainter.prototype.UnzoomUserRange =
function(dox, doy, doz) {
2766 var res =
false, painter =
this, histo = this.GetHisto();
2768 if (!histo)
return false;
2770 function UnzoomTAxis(obj) {
2771 if (!obj)
return false;
2772 if (!obj.TestBit(JSROOT.EAxisBits.kAxisRange))
return false;
2773 if (obj.fFirst === obj.fLast)
return false;
2774 if ((obj.fFirst <= 1) && (obj.fLast >= obj.fNbins))
return false;
2775 obj.InvertBit(JSROOT.EAxisBits.kAxisRange);
2779 function UzoomMinMax(ndim, hist) {
2780 if (painter.Dimension()!==ndim)
return false;
2781 if ((painter.options.minimum===-1111) && (painter.options.maximum===-1111))
return false;
2782 if (!painter.draw_content)
return false;
2783 painter.options.minimum = painter.options.maximum = -1111;
2784 painter.ScanContent(
true);
2788 if (dox && UnzoomTAxis(histo.fXaxis)) res =
true;
2789 if (doy && (UnzoomTAxis(histo.fYaxis) || UzoomMinMax(1, histo))) res =
true;
2790 if (doz && (UnzoomTAxis(histo.fZaxis) || UzoomMinMax(2, histo))) res =
true;
2795 THistPainter.prototype.AllowDefaultYZooming =
function() {
2800 if (this.Dimension()>1)
return true;
2801 if (this.draw_content)
return false;
2803 var pad_painter = this.pad_painter();
2804 if (pad_painter && pad_painter.painters)
2805 for (var k = 0; k < pad_painter.painters.length; ++k) {
2806 var subpainter = pad_painter.painters[k];
2807 if ((subpainter!==
this) && subpainter.wheel_zoomy!==undefined)
2808 return subpainter.wheel_zoomy;
2820 THistPainter.prototype.AddInteractive =
function() {
2822 if (this.is_main_painter()) {
2823 var fp = this.frame_painter();
2824 if (fp) fp.AddInteractive();
2828 THistPainter.prototype.ShowContextMenu =
function(kind, evnt, obj) {
2837 var menu_painter =
this, frame_corner =
false, fp = null;
2840 d3.event.preventDefault();
2841 d3.event.stopPropagation();
2844 if (kind === undefined) {
2845 var ms = d3.mouse(this.svg_frame().node()),
2846 tch = d3.touches(this.svg_frame().node()),
2847 pp = this.pad_painter(),
2848 pnt = null, sel = null;
2850 fp = this.frame_painter();
2852 if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch:
true };
else
2853 if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch:
false };
2855 if ((pnt !== null) && (pp !== null)) {
2856 pnt.painters =
true;
2857 var hints = pp.GetTooltips(pnt), bestdist = 1000;
2858 for (var n=0;n<hints.length;++n)
2859 if (hints[n] && hints[n].menu) {
2860 var dist = (
'menu_dist' in hints[n]) ? hints[n].menu_dist : 7;
2861 if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; }
2865 if (sel!==null) menu_painter = sel;
else
2866 if (fp!==null) kind =
"frame";
2868 if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20);
2870 if (fp) fp.SetLastEventPos(pnt);
2875 menu_painter.ctx_menu_evnt = evnt;
2877 JSROOT.Painter.createMenu(menu_painter,
function(menu) {
2878 var domenu = menu.painter.FillContextMenu(menu, kind, obj);
2881 if (fp && (!domenu || (frame_corner && (kind!==
"frame"))))
2882 domenu = fp.FillContextMenu(menu);
2885 menu.painter.FillObjectExecMenu(menu, kind,
function() {
2887 menu.painter.SwitchTooltip(
false);
2888 menu.show(menu.painter.ctx_menu_evnt, menu.painter.SwitchTooltip.bind(menu.painter,
true));
2895 THistPainter.prototype.ChangeUserRange =
function(arg) {
2896 var histo = this.GetHisto(),
2897 taxis = histo ? histo[
'f'+arg+
"axis"] : null;
2900 var curr =
"[1," + taxis.fNbins+
"]";
2901 if (taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
2902 curr =
"[" +taxis.fFirst+
"," + taxis.fLast+
"]";
2904 var res = prompt(
"Enter user range for axis " + arg +
" like [1," + taxis.fNbins +
"]", curr);
2906 res = JSON.parse(res);
2908 if (!res || (res.length!=2) || isNaN(res[0]) || isNaN(res[1]))
return;
2909 taxis.fFirst = parseInt(res[0]);
2910 taxis.fLast = parseInt(res[1]);
2912 var newflag = (taxis.fFirst < taxis.fLast) && (taxis.fFirst >= 1) && (taxis.fLast<=taxis.fNbins);
2913 if (newflag != taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
2914 taxis.InvertBit(JSROOT.EAxisBits.kAxisRange);
2919 THistPainter.prototype.FillContextMenu =
function(menu) {
2921 var histo = this.GetHisto(),
2922 fp = this.frame_painter();
2925 menu.add(
"header:"+ histo._typename +
"::" + histo.fName);
2927 if (this.draw_content) {
2928 menu.addchk(this.ToggleStat(
'only-check'),
"Show statbox",
function() { this.ToggleStat(); });
2929 if (this.Dimension() == 1) {
2930 menu.add(
"User range X",
"X", this.ChangeUserRange);
2932 menu.add(
"sub:User ranges");
2933 menu.add(
"X",
"X", this.ChangeUserRange);
2934 menu.add(
"Y",
"Y", this.ChangeUserRange);
2935 if (this.Dimension() > 2)
2936 menu.add(
"Z",
"Z", this.ChangeUserRange);
2940 if (typeof this.FillHistContextMenu ==
'function')
2941 this.FillHistContextMenu(menu);
2944 if (this.options.Mode3D) {
2947 if (menu.size() > 0)
2948 menu.add(
"separator");
2950 var main = this.main_painter() ||
this;
2952 menu.addchk(main.IsTooltipAllowed(),
'Show tooltips',
function() {
2953 main.SetTooltipAllowed(
"toggle");
2956 menu.addchk(fp.enable_highlight,
'Highlight bins',
function() {
2957 fp.enable_highlight = !fp.enable_highlight;
2958 if (!fp.enable_highlight && fp.BinHighlight3D && fp.mode3d) fp.BinHighlight3D(null);
2961 if (fp && fp.Render3D) {
2962 menu.addchk(main.options.FrontBox,
'Front box',
function() {
2963 main.options.FrontBox = !main.options.FrontBox;
2966 menu.addchk(main.options.BackBox,
'Back box',
function() {
2967 main.options.BackBox = !main.options.BackBox;
2972 if (this.draw_content) {
2973 menu.addchk(!this.options.Zero,
'Suppress zeros',
function() {
2974 this.options.Zero = !
this.options.Zero;
2975 this.InteractiveRedraw(
"pad");
2978 if ((this.options.Lego==12) || (this.options.Lego==14)) {
2979 menu.addchk(this.options.Zscale,
"Z scale",
function() {
2982 if (this.FillPaletteMenu) this.FillPaletteMenu(menu);
2986 if (main.control && typeof main.control.reset ===
'function')
2987 menu.add(
'Reset camera',
function() {
2988 main.control.reset();
2992 this.FillAttContextMenu(menu);
2994 if (this.histogram_updated && fp.zoom_changed_interactive)
2995 menu.add(
'Let update zoom',
function() {
2996 fp.zoom_changed_interactive = 0;
3002 THistPainter.prototype.ButtonClick =
function(funcname) {
3005 var fp = this.frame_painter();
3007 if (!this.is_main_painter() || !fp)
return false;
3011 if ((fp.zoom_xmin !== fp.zoom_xmax) || (fp.zoom_ymin !== fp.zoom_ymax) || (fp.zoom_zmin !== fp.zoom_zmax)) {
3013 fp.zoom_changed_interactive = 0;
3016 if (this.draw_content && (typeof this.AutoZoom ===
'function')) {
3021 case "ToggleLogX": fp.ToggleLog(
"x");
break;
3022 case "ToggleLogY": fp.ToggleLog(
"y");
break;
3023 case "ToggleLogZ": fp.ToggleLog(
"z");
break;
3024 case "ToggleStatBox": this.ToggleStat();
return true;
break;
3029 THistPainter.prototype.FillToolbar =
function(not_shown) {
3030 var pp = this.pad_painter();
3033 pp.AddButton(JSROOT.ToolbarIcons.auto_zoom,
'Toggle between unzoom and autozoom-in',
'ToggleZoom',
"Ctrl *");
3034 pp.AddButton(JSROOT.ToolbarIcons.arrow_right,
"Toggle log x",
"ToggleLogX",
"PageDown");
3035 pp.AddButton(JSROOT.ToolbarIcons.arrow_up,
"Toggle log y",
"ToggleLogY",
"PageUp");
3036 if (this.Dimension() > 1)
3037 pp.AddButton(JSROOT.ToolbarIcons.arrow_diag,
"Toggle log z",
"ToggleLogZ");
3038 if (this.draw_content)
3039 pp.AddButton(JSROOT.ToolbarIcons.statbox,
'Toggle stat box',
"ToggleStatBox");
3040 if (!not_shown) pp.ShowButtons();
3044 THistPainter.prototype.Get3DToolTip =
function(indx) {
3045 var histo = this.GetHisto(),
3046 tip = { bin: indx, name: histo.fName, title: histo.fTitle };
3047 switch (this.Dimension()) {
3049 tip.ix = indx; tip.iy = 1;
3050 tip.value = histo.getBinContent(tip.ix);
3051 tip.error = histo.getBinError(indx);
3052 tip.lines = this.GetBinTips(indx-1);
3055 tip.ix = indx % (this.nbinsx + 2);
3056 tip.iy = (indx - tip.ix) / (this.nbinsx + 2);
3057 tip.value = histo.getBinContent(tip.ix, tip.iy);
3058 tip.error = histo.getBinError(indx);
3059 tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1);
3062 tip.ix = indx % (this.nbinsx+2);
3063 tip.iy = ((indx - tip.ix) / (this.nbinsx+2)) % (this.nbinsy+2);
3064 tip.iz = (indx - tip.ix - tip.iy * (this.nbinsx+2)) / (this.nbinsx+2) / (this.nbinsy+2);
3065 tip.value = histo.getBinContent(tip.ix, tip.iy, tip.iz);
3066 tip.error = histo.getBinError(indx);
3067 tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1, tip.iz-1);
3074 THistPainter.prototype.CreateContour =
function(nlevels, zmin, zmax, zminpositive) {
3076 if (nlevels<1) nlevels = JSROOT.gStyle.fNumberContours;
3078 this.colzmin = zmin;
3079 this.colzmax = zmax;
3081 if (this.root_pad().fLogz) {
3082 if (this.colzmax <= 0) this.colzmax = 1.;
3083 if (this.colzmin <= 0)
3084 if ((zminpositive===undefined) || (zminpositive <= 0))
3085 this.colzmin = 0.0001*this.colzmax;
3087 this.colzmin = ((zminpositive < 3) || (zminpositive>100)) ? 0.3*zminpositive : 1;
3088 if (this.colzmin >= this.colzmax) this.colzmin = 0.0001*this.colzmax;
3090 var logmin = Math.log(this.colzmin)/Math.log(10),
3091 logmax = Math.log(this.colzmax)/Math.log(10),
3092 dz = (logmax-logmin)/nlevels;
3093 this.fContour.push(this.colzmin);
3094 for (var level=1; level<nlevels; level++)
3095 this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10)));
3096 this.fContour.push(this.colzmax);
3097 this.fCustomContour =
true;
3099 if ((this.colzmin === this.colzmax) && (this.colzmin !== 0)) {
3100 this.colzmax += 0.01*Math.abs(this.colzmax);
3101 this.colzmin -= 0.01*Math.abs(this.colzmin);
3103 var dz = (this.colzmax-this.colzmin)/nlevels;
3104 for (var level=0; level<=nlevels; level++)
3105 this.fContour.push(
this.colzmin + dz*level);
3108 var fp = this.frame_painter();
3109 if ((this.Dimension() < 3) && fp) {
3110 fp.zmin = this.colzmin;
3111 fp.zmax = this.colzmax;
3114 return this.fContour;
3117 THistPainter.prototype.GetContour =
function() {
3118 if (this.fContour)
return this.fContour;
3120 var main = this.main_painter(),
3121 fp = this.frame_painter();
3122 if (main && (main !==
this) && main.fContour) {
3123 this.fContour = main.fContour;
3124 this.fCustomContour = main.fCustomContour;
3125 this.colzmin = main.colzmin;
3126 this.colzmax = main.colzmax;
3127 return this.fContour;
3132 var histo = this.GetObject(), nlevels = JSROOT.gStyle.fNumberContours,
3133 zmin = this.minbin, zmax = this.maxbin, zminpos = this.minposbin;
3134 if (zmin === zmax) { zmin = this.gminbin; zmax = this.gmaxbin; zminpos = this.gminposbin }
3135 if (histo.fContour) nlevels = histo.fContour.length;
3136 if ((this.options.minimum !== -1111) && (
this.options.maximum != -1111)) {
3137 zmin = this.options.minimum;
3138 zmax = this.options.maximum;
3140 if (fp && (fp.zoom_zmin != fp.zoom_zmax)) {
3141 zmin = fp.zoom_zmin;
3142 zmax = fp.zoom_zmax;
3145 if (histo.fContour && (histo.fContour.length>1) && histo.TestBit(JSROOT.TH1StatusBits.kUserContour)) {
3146 this.fContour = JSROOT.clone(histo.fContour);
3147 this.fCustomContour =
true;
3148 this.colzmin = zmin;
3149 this.colzmax = zmax;
3150 if (zmax > this.fContour[this.fContour.length-1]) this.fContour.push(zmax);
3151 if ((this.Dimension()<3) && fp) {
3152 fp.zmin = this.colzmin;
3153 fp.zmax = this.colzmax;
3155 return this.fContour;
3158 this.fCustomContour =
false;
3160 return this.CreateContour(nlevels, zmin, zmax, zminpos);
3164 THistPainter.prototype.getContourIndex =
function(zc) {
3166 var cntr = this.GetContour();
3168 if (this.fCustomContour) {
3169 var l = 0, r = cntr.length-1, mid;
3170 if (zc < cntr[0])
return -1;
3171 if (zc >= cntr[r])
return r;
3173 mid = Math.round((l+r)/2);
3174 if (cntr[mid] > zc) r = mid;
else l = mid;
3180 if (zc < this.colzmin)
return this.options.Zero ? -1 : 0;
3183 if (zc===this.colzmin)
return ((this.colzmin != 0) || !this.options.Zero ||
this.IsTH2Poly()) ? 0 : -1;
3185 return Math.floor(0.01+(zc-this.colzmin)*(cntr.length-1)/(
this.colzmax-
this.colzmin));
3190 THistPainter.prototype.getContourColor =
function(zc, asindx) {
3191 var zindx = this.getContourIndex(zc);
3192 if (zindx < 0)
return null;
3194 var cntr = this.GetContour(),
3195 palette = this.GetPalette(),
3196 indx = palette.calcColorIndex(zindx, cntr.length);
3198 return asindx ? indx : palette.getColor(indx);
3201 THistPainter.prototype.GetPalette =
function(force) {
3202 if (!this.fPalette || force)
3203 this.fPalette = this.get_palette(
true, this.options.Palette);
3204 return this.fPalette;
3207 THistPainter.prototype.FillPaletteMenu =
function(menu) {
3209 var curr = this.options.Palette, hpainter =
this;
3210 if ((curr===null) || (curr===0)) curr = JSROOT.gStyle.Palette;
3212 function change(arg) {
3213 hpainter.options.Palette = parseInt(arg);
3214 hpainter.GetPalette(
true);
3218 function add(
id, name, more) {
3219 menu.addchk((
id===curr) || more,
'<nobr>' + name +
'</nobr>',
id, change);
3222 menu.add(
"sub:Palette");
3224 add(50,
"ROOT 5", (curr>=10) && (curr<51));
3225 add(51,
"Deep Sea");
3226 add(52,
"Grayscale", (curr>0) && (curr<10));
3227 add(53,
"Dark body radiator");
3228 add(54,
"Two-color hue");
3230 add(56,
"Inverted dark body radiator");
3231 add(57,
"Bird", (curr>113));
3232 add(58,
"Cubehelix");
3233 add(59,
"Green Red Violet");
3234 add(60,
"Blue Red Yellow");
3236 add(62,
"Color Printable On Grey");
3238 add(64,
"Aquamarine");
3240 add(66,
"Atlantic");
3242 menu.add(
"endsub:");
3245 THistPainter.prototype.DrawColorPalette =
function(enabled, postpone_draw, can_move) {
3248 if (!this.is_main_painter())
return null;
3250 var pal = this.FindFunction(
'TPaletteAxis'),
3251 pal_painter = this.FindPainterFor(pal);
3253 if (this._can_move_colz) { can_move =
true;
delete this._can_move_colz; }
3255 if (!pal_painter && !pal) {
3256 pal_painter = this.FindPainterFor(undefined, undefined,
"TPaletteAxis");
3258 pal = pal_painter.GetObject();
3260 this.AddFunction(pal,
true);
3266 pal_painter.Enabled =
false;
3267 pal_painter.RemoveDrawG();
3275 if (this.options.PadPalette)
return null;
3277 pal = JSROOT.Create(
'TPave');
3279 JSROOT.extend(pal, { _typename:
"TPaletteAxis", fName:
"TPave", fH: null, fAxis: JSROOT.Create(
'TGaxis'),
3280 fX1NDC: 0.91, fX2NDC: 0.95, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1 } );
3282 var zaxis = this.GetHisto().fZaxis;
3284 JSROOT.extend(pal.fAxis, { fTitle: zaxis.fTitle, fTitleSize: zaxis.fTitleSize, fChopt:
"+",
3285 fLineColor: zaxis.fAxisColor, fLineSyle: 1, fLineWidth: 1,
3286 fTextAngle: 0, fTextSize: zaxis.fLabelSize, fTextAlign: 11,
3287 fTextColor: zaxis.fLabelColor, fTextFont: zaxis.fLabelFont });
3290 this.AddFunction(pal,
true);
3295 var frame_painter = this.frame_painter();
3298 if (can_move && frame_painter) {
3299 pal.fX2NDC = frame_painter.fX2NDC + 0.01 + (pal.fX2NDC - pal.fX1NDC);
3300 pal.fX1NDC = frame_painter.fX2NDC + 0.01;
3301 pal.fY1NDC = frame_painter.fY1NDC;
3302 pal.fY2NDC = frame_painter.fY2NDC;
3306 if (postpone_draw) arg+=
";postpone";
3307 if (can_move && !this.do_redraw_palette) arg+=
";can_move";
3311 var prev = this.CurrentPadName(this.pad_name);
3314 pal_painter = JSROOT.draw(this.divid, pal, arg);
3315 this.CurrentPadName(prev);
3317 pal_painter.Enabled =
true;
3318 pal_painter.DrawPave(arg);
3322 pal_painter.$secondary =
true;
3325 pal_painter.Redraw =
function() {};
3328 if (can_move && frame_painter && (pal.fX1NDC-0.005 < frame_painter.fX2NDC) && !this.do_redraw_palette) {
3330 this.do_redraw_palette =
true;
3332 frame_painter.fX2NDC = pal.fX1NDC - 0.01;
3333 frame_painter.Redraw();
3335 if (!postpone_draw) this.Redraw();
3337 delete this.do_redraw_palette;
3343 THistPainter.prototype.ToggleColz =
function() {
3344 var can_toggle = this.options.Mode3D ? (this.options.Lego === 12 || this.options.Lego === 14 || this.options.Surf === 11 || this.options.Surf === 12) :
3345 this.options.Color ||
this.options.Contour;
3348 this.options.Zscale = !this.options.Zscale;
3349 this.DrawColorPalette(this.options.Zscale,
false,
true);
3353 THistPainter.prototype.ToggleMode3D =
function() {
3354 this.options.Mode3D = !this.options.Mode3D;
3356 if (this.options.Mode3D) {
3357 if (!this.options.Surf && !
this.options.Lego && !
this.options.Error) {
3358 if ((this.nbinsx>=50) || (this.nbinsy>=50))
3359 this.options.Lego = this.options.Color ? 14 : 13;
3361 this.options.Lego = this.options.Color ? 12 : 1;
3363 this.options.Zero =
false;
3367 this.CopyOptionsToOthers();
3368 this.InteractiveRedraw(
"pad",
"drawopt");
3371 THistPainter.prototype.PrepareColorDraw =
function(args) {
3373 if (!args) args = { rounding:
true, extra: 0, middle: 0 };
3375 if (args.extra === undefined) args.extra = 0;
3376 if (args.middle === undefined) args.middle = 0;
3378 var histo = this.GetHisto(),
3379 xaxis = histo.fXaxis, yaxis = histo.fYaxis,
3380 pmain = this.frame_painter(),
3381 hdim = this.Dimension(),
3382 i, j, x, y, binz, binarea,
3384 i1: this.GetSelectIndex(
"x",
"left", 0 - args.extra),
3385 i2: this.GetSelectIndex(
"x",
"right", 1 + args.extra),
3386 j1: (hdim===1) ? 0 : this.GetSelectIndex(
"y",
"left", 0 - args.extra),
3387 j2: (hdim===1) ? 1 : this.GetSelectIndex(
"y",
"right", 1 + args.extra),
3388 min: 0, max: 0, sumz: 0, xbar1: 0, xbar2: 1, ybar1: 0, ybar2: 1
3391 res.grx =
new Float32Array(res.i2+1);
3392 res.gry =
new Float32Array(res.j2+1);
3394 if (typeof histo.fBarOffset ==
'number' && typeof histo.fBarWidth ==
'number'
3395 && (histo.fBarOffset || histo.fBarWidth !== 1000)) {
3396 if (histo.fBarOffset <= 1000) {
3397 res.xbar1 = res.ybar1 = 0.001*histo.fBarOffset;
3398 }
else if (histo.fBarOffset <= 3000) {
3399 res.xbar1 = 0.001*(histo.fBarOffset-2000);
3400 }
else if (histo.fBarOffset <= 5000) {
3401 res.ybar1 = 0.001*(histo.fBarOffset-4000);
3404 if (histo.fBarWidth <= 1000) {
3405 res.xbar2 = Math.min(1., res.xbar1 + 0.001*histo.fBarWidth);
3406 res.ybar2 = Math.min(1., res.ybar1 + 0.001*histo.fBarWidth);
3407 }
else if (histo.fBarWidth <= 3000) {
3408 res.xbar2 = Math.min(1., res.xbar1 + 0.001*(histo.fBarWidth-2000));
3410 }
else if (histo.fBarWidth <= 5000) {
3412 res.ybar2 = Math.min(1., res.ybar1 + 0.001*(histo.fBarWidth-4000));
3416 if (args.original) {
3417 res.original =
true;
3418 res.origx =
new Float32Array(res.i2+1);
3419 res.origy =
new Float32Array(res.j2+1);
3422 if (args.pixel_density) args.rounding =
true;
3425 console.warn(
"cannot draw histogram without frame");
3430 for (i = res.i1; i <= res.i2; ++i) {
3431 x = xaxis.GetBinCoord(i + args.middle);
3432 if (pmain.logx && (x <= 0)) { res.i1 = i+1;
continue; }
3433 if (res.origx) res.origx[i] = x;
3434 res.grx[i] = pmain.grx(x);
3435 if (args.rounding) res.grx[i] = Math.round(res.grx[i]);
3438 if (res.grx[i] < -pmain.size_xy3d) { res.i1 = i; res.grx[i] = -pmain.size_xy3d; }
3439 if (res.grx[i] > pmain.size_xy3d) { res.i2 = i; res.grx[i] = pmain.size_xy3d; }
3444 res.gry[0] = pmain.gry(0);
3445 res.gry[1] = pmain.gry(1);
3447 for (j = res.j1; j <= res.j2; ++j) {
3448 y = yaxis.GetBinCoord(j + args.middle);
3449 if (pmain.logy && (y <= 0)) { res.j1 = j+1;
continue; }
3450 if (res.origy) res.origy[j] = y;
3451 res.gry[j] = pmain.gry(y);
3452 if (args.rounding) res.gry[j] = Math.round(res.gry[j]);
3455 if (res.gry[j] < -pmain.size_xy3d) { res.j1 = j; res.gry[j] = -pmain.size_xy3d; }
3456 if (res.gry[j] > pmain.size_xy3d) { res.j2 = j; res.gry[j] = pmain.size_xy3d; }
3462 binz = histo.getBinContent(res.i1 + 1, res.j1 + 1);
3463 this.maxbin = this.minbin = this.minposbin = null;
3465 for (i = res.i1; i < res.i2; ++i) {
3466 for (j = res.j1; j < res.j2; ++j) {
3467 binz = histo.getBinContent(i + 1, j + 1);
3469 if (args.pixel_density) {
3470 binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]);
3471 if (binarea <= 0)
continue;
3472 res.max = Math.max(res.max, binz);
3473 if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz;
3474 binz = binz/binarea;
3476 if (this.maxbin===null) {
3477 this.maxbin = this.minbin = binz;
3479 this.maxbin = Math.max(this.maxbin, binz);
3480 this.minbin = Math.min(this.minbin, binz);
3483 if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz;
3488 this.fContour = null;
3489 this.fCustomContour =
false;
3505 function TH1Painter(histo) {
3506 THistPainter.call(
this, histo);
3509 TH1Painter.prototype = Object.create(THistPainter.prototype);
3511 TH1Painter.prototype.ConvertTH1K =
function() {
3512 var histo = this.GetObject();
3514 if (histo.fReady)
return;
3516 var arr = histo.fArray;
3517 histo.fNcells = histo.fXaxis.fNbins + 2;
3518 histo.fArray =
new Float64Array(histo.fNcells);
3519 for (var n=0;n<histo.fNcells;++n) histo.fArray[n] = 0;
3520 for (var n=0;n<histo.fNIn;++n) histo.Fill(arr[n]);
3521 histo.fReady =
true;
3527 TH1Painter.prototype.ScanContent =
function(when_axis_changed) {
3529 if (when_axis_changed && !this.nbinsx) when_axis_changed =
false;
3531 if (this.IsTH1K()) this.ConvertTH1K();
3533 var histo = this.GetHisto();
3535 if (!when_axis_changed) {
3536 this.nbinsx = histo.fXaxis.fNbins;
3538 this.CreateAxisFuncs(
false);
3541 var left = this.GetSelectIndex(
"x",
"left"),
3542 right = this.GetSelectIndex(
"x",
"right");
3544 if (when_axis_changed) {
3545 if ((left === this.scan_xleft) && (right === this.scan_xright))
return;
3549 this.draw_content = !(this.options.Axis > 0);
3551 this.scan_xleft = left;
3552 this.scan_xright = right;
3554 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0, first =
true,
3555 profile = this.IsTProfile(), value, err;
3557 for (var i = 0; i < this.nbinsx; ++i) {
3558 value = histo.getBinContent(i + 1);
3559 hsum += profile ? histo.fBinEntries[i + 1] : value;
3561 if ((i<left) || (i>=right))
continue;
3563 if ((value > 0) && ((hmin_nz == 0) || (value < hmin_nz))) hmin_nz = value;
3566 hmin = hmax = value;
3570 err = this.options.Error ? histo.getBinError(i + 1) : 0;
3572 hmin = Math.min(hmin, value - err);
3573 hmax = Math.max(hmax, value + err);
3578 hsum += histo.fBinEntries[0] + histo.fBinEntries[this.nbinsx + 1];
3580 hsum += histo.getBinContent(0) + histo.getBinContent(this.nbinsx + 1);
3582 this.stat_entries = hsum;
3583 if (histo.fEntries > 1) this.stat_entries = histo.fEntries;
3588 this.ymin_nz = hmin_nz;
3590 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300) && (Math.abs(hmax) < 1e-300)))
3591 this.draw_content =
false;
3593 var set_zoom =
false, set_zoom2 =
false;
3595 if (this.draw_content) {
3597 if (hmin == 0) { this.ymin = 0; this.ymax = 1; }
3598 else if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
3599 else { this.ymin = 0; this.ymax = hmin * 2; }
3601 var dy = (hmax - hmin) * 0.05;
3602 this.ymin = hmin - dy;
3603 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
3604 this.ymax = hmax + dy;
3606 }
else if (this.options.ymin !==
this.options.ymax) {
3607 this.ymin = this.options.ymin;
3608 this.ymax = this.options.ymax;
3612 hmin = this.options.minimum;
3613 hmax = this.options.maximum;
3615 if ((hmin === hmax) && (hmin !== -1111)) {
3617 hmin *= 2; hmax = 0;
3619 hmin = 0; hmax*=2;
if (!hmax) hmax = 1;
3623 if ((hmin != -1111) && (hmax != -1111) && !this.draw_content && !set_zoom2) {
3627 if (hmin != -1111) {
3628 if (hmin < this.ymin) this.ymin = hmin;
else set_zoom =
true;
3630 if (hmax != -1111) {
3631 if (hmax > this.ymax) this.ymax = hmax;
else set_zoom =
true;
3635 if (!when_axis_changed) {
3636 if (set_zoom && (this.draw_content || set_zoom2)) {
3637 this.zoom_ymin = (hmin == -1111) ? this.ymin : hmin;
3638 this.zoom_ymax = (hmax == -1111) ? this.ymax : hmax;
3640 delete this.zoom_ymin;
3641 delete this.zoom_ymax;
3646 if (this.Dimension() > 1) this.wheel_zoomy =
true;
else
3647 if (this.draw_content) this.wheel_zoomy =
false;
3651 TH1Painter.prototype.CountStat =
function(cond) {
3652 var profile = this.IsTProfile(),
3653 histo = this.GetHisto(), xaxis = histo.fXaxis,
3654 left = this.GetSelectIndex(
"x",
"left"),
3655 right = this.GetSelectIndex(
"x",
"right"),
3656 stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0,
3657 i, xx = 0, w = 0, xmax = null, wmax = null,
3658 fp = this.frame_painter(),
3659 res = { name: histo.fName, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: 0, entries: this.stat_entries, xmax:0, wmax:0 };
3661 for (i = left; i < right; ++i) {
3662 xx = xaxis.GetBinCoord(i + 0.5);
3664 if (cond && !cond(xx))
continue;
3667 w = histo.fBinEntries[i + 1];
3668 stat_sumwy += histo.fArray[i + 1];
3669 stat_sumwy2 += histo.fSumw2[i + 1];
3671 w = histo.getBinContent(i + 1);
3674 if ((xmax===null) || (w>wmax)) { xmax = xx; wmax = w; }
3677 stat_sumwx += w * xx;
3678 stat_sumwx2 += w * xx * xx;
3682 if (!fp.IsAxisZoomed(
"x") && (histo.fTsumw>0)) {
3683 stat_sumw = histo.fTsumw;
3684 stat_sumwx = histo.fTsumwx;
3685 stat_sumwx2 = histo.fTsumwx2;
3688 res.integral = stat_sumw;
3690 if (stat_sumw > 0) {
3691 res.meanx = stat_sumwx / stat_sumw;
3692 res.meany = stat_sumwy / stat_sumw;
3693 res.rmsx = Math.sqrt(Math.abs(stat_sumwx2 / stat_sumw - res.meanx * res.meanx));
3694 res.rmsy = Math.sqrt(Math.abs(stat_sumwy2 / stat_sumw - res.meany * res.meany));
3706 TH1Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
3709 if (this.IgnoreStatsFill())
return false;
3711 var histo = this.GetHisto(),
3712 data = this.CountStat(),
3713 print_name = dostat % 10,
3714 print_entries = Math.floor(dostat / 10) % 10,
3715 print_mean = Math.floor(dostat / 100) % 10,
3716 print_rms = Math.floor(dostat / 1000) % 10,
3717 print_under = Math.floor(dostat / 10000) % 10,
3718 print_over = Math.floor(dostat / 100000) % 10,
3719 print_integral = Math.floor(dostat / 1000000) % 10,
3720 print_skew = Math.floor(dostat / 10000000) % 10,
3721 print_kurt = Math.floor(dostat / 100000000) % 10;
3727 stat.AddText(data.name);
3729 if (this.IsTProfile()) {
3731 if (print_entries > 0)
3732 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
3734 if (print_mean > 0) {
3735 stat.AddText(
"Mean = " + stat.Format(data.meanx));
3736 stat.AddText(
"Mean y = " + stat.Format(data.meany));
3739 if (print_rms > 0) {
3740 stat.AddText(
"Std Dev = " + stat.Format(data.rmsx));
3741 stat.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
3746 if (print_entries > 0)
3747 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
3750 stat.AddText(
"Mean = " + stat.Format(data.meanx));
3753 stat.AddText(
"Std Dev = " + stat.Format(data.rmsx));
3755 if (print_under > 0)
3756 stat.AddText(
"Underflow = " + stat.Format((histo.fArray.length > 0) ? histo.fArray[0] : 0,
"entries"));
3759 stat.AddText(
"Overflow = " + stat.Format((histo.fArray.length > 0) ? histo.fArray[histo.fArray.length - 1] : 0,
"entries"));
3761 if (print_integral > 0)
3762 stat.AddText(
"Integral = " + stat.Format(data.integral,
"entries"));
3765 stat.AddText(
"Skew = <not avail>");
3768 stat.AddText(
"Kurt = <not avail>");
3771 if (dofit) stat.FillFunctionStat(this.FindFunction(
'TF1'), dofit);
3777 TH1Painter.prototype.DrawBars =
function(width, height) {
3781 var left = this.GetSelectIndex(
"x",
"left", -1),
3782 right = this.GetSelectIndex(
"x",
"right", 1),
3783 pmain = this.frame_painter(),
3784 pad = this.root_pad(),
3785 histo = this.GetHisto(), xaxis = histo.fXaxis,
3787 show_text = this.options.Text, text_col, text_angle, text_size,
3788 i, x1, x2, grx1, grx2, y, gry1, gry2, w,
3789 bars =
"", barsl =
"", barsr =
"",
3790 side = (this.options.BarStyle > 10) ? this.options.BarStyle % 10 : 0;
3792 if (side>4) side = 4;
3793 gry2 = pmain.swap_xy ? 0 : height;
3794 if ((this.options.BaseLine !==
false) && !isNaN(this.options.BaseLine))
3795 if (this.options.BaseLine >= pmain.scale_ymin)
3796 gry2 = Math.round(pmain.gry(
this.options.BaseLine));
3799 text_col = this.get_color(histo.fMarkerColor);
3800 text_angle = -1*this.options.TextAngle;
3803 if ((histo.fMarkerSize!==1) && text_angle)
3804 text_size = 0.02*height*histo.fMarkerSize;
3806 this.StartTextDrawing(42, text_size, this.draw_g, text_size);
3810 for (i = left; i < right; ++i) {
3811 x1 = xaxis.GetBinLowEdge(i+1);
3812 x2 = xaxis.GetBinLowEdge(i+2);
3814 if (pmain.logx && (x2 <= 0))
continue;
3816 grx1 = Math.round(pmain.grx(x1));
3817 grx2 = Math.round(pmain.grx(x2));
3819 y = histo.getBinContent(i+1);
3820 if (pmain.logy && (y < pmain.scale_ymin))
continue;
3821 gry1 = Math.round(pmain.gry(y));
3824 grx1 += Math.round(histo.fBarOffset/1000*w);
3825 w = Math.round(histo.fBarWidth/1000*w);
3828 bars +=
"M"+gry2+
","+grx1 +
"h"+(gry1-gry2) +
"v"+w +
"h"+(gry2-gry1) +
"z";
3830 bars +=
"M"+grx1+
","+gry1 +
"h"+w +
"v"+(gry2-gry1) +
"h"+(-w)+
"z";
3834 w = Math.round(w * side / 10);
3835 if (pmain.swap_xy) {
3836 barsl +=
"M"+gry2+
","+grx1 +
"h"+(gry1-gry2) +
"v" + w +
"h"+(gry2-gry1) +
"z";
3837 barsr +=
"M"+gry2+
","+grx2 +
"h"+(gry1-gry2) +
"v" + (-w) +
"h"+(gry2-gry1) +
"z";
3839 barsl +=
"M"+grx1+
","+gry1 +
"h"+w +
"v"+(gry2-gry1) +
"h"+(-w)+
"z";
3840 barsr +=
"M"+grx2+
","+gry1 +
"h"+(-w) +
"v"+(gry2-gry1) +
"h"+w +
"z";
3844 if (show_text && y) {
3845 var lbl = (y === Math.round(y)) ? y.toString() : JSROOT.FFormat(y, JSROOT.gStyle.fPaintTextFormat);
3848 this.DrawText({ align: 12, x: Math.round(gry1 + text_size/2), y: Math.round(grx1+0.1), height: Math.round(w*0.8), text: lbl, color: text_col, latex: 0 });
3849 else if (text_angle)
3850 this.DrawText({ align: 12, x: grx1+w/2, y: Math.round(gry1 - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 });
3852 this.DrawText({ align: 22, x: Math.round(grx1 + w*0.1), y: Math.round(gry1-2-text_size), width: Math.round(w*0.8), height: text_size, text: lbl, color: text_col, latex: 0 });
3857 this.draw_g.append(
"svg:path")
3859 .call(this.fillatt.func);
3862 this.draw_g.append(
"svg:path")
3864 .call(this.fillatt.func)
3865 .style(
"fill", d3.rgb(
this.fillatt.color).brighter(0.5).toString());
3868 this.draw_g.append(
"svg:path")
3870 .call(this.fillatt.func)
3871 .style(
"fill", d3.rgb(
this.fillatt.color).darker(0.5).toString());
3874 this.FinishTextDrawing(this.draw_g);
3877 TH1Painter.prototype.DrawFilledErrors =
function(width, height) {
3880 var left = this.GetSelectIndex(
"x",
"left", -1),
3881 right = this.GetSelectIndex(
"x",
"right", 1),
3882 pmain = this.frame_painter(),
3883 histo = this.GetHisto(), xaxis = histo.fXaxis,
3884 i, x, grx, y, yerr, gry1, gry2,
3885 bins1 = [], bins2 = [];
3887 for (i = left; i < right; ++i) {
3888 x = xaxis.GetBinCoord(i+0.5);
3889 if (pmain.logx && (x <= 0))
continue;
3890 grx = Math.round(pmain.grx(x));
3892 y = histo.getBinContent(i+1);
3893 yerr = histo.getBinError(i+1);
3894 if (pmain.logy && (y-yerr < pmain.scale_ymin))
continue;
3896 gry1 = Math.round(pmain.gry(y + yerr));
3897 gry2 = Math.round(pmain.gry(y - yerr));
3899 bins1.push({ grx:grx, gry: gry1 });
3900 bins2.unshift({ grx:grx, gry: gry2 });
3903 var kind = (this.options.ErrorKind === 4) ?
"bezier" :
"line",
3904 path1 = JSROOT.Painter.BuildSvgPath(kind, bins1),
3905 path2 = JSROOT.Painter.BuildSvgPath(
"L"+kind, bins2);
3907 this.draw_g.append(
"svg:path")
3908 .attr(
"d", path1.path + path2.path +
"Z")
3909 .style(
"stroke",
"none")
3910 .call(this.fillatt.func);
3913 TH1Painter.prototype.DrawBins =
function() {
3917 this.CheckHistDrawAttributes();
3919 var width = this.frame_width(), height = this.frame_height();
3921 if (!this.draw_content || (width<=0) || (height<=0))
3922 return this.RemoveDrawG();
3924 if (this.options.Bar)
3925 return this.DrawBars(width, height);
3927 if ((this.options.ErrorKind === 3) || (
this.options.ErrorKind === 4))
3928 return this.DrawFilledErrors(width, height);
3930 var left = this.GetSelectIndex(
"x",
"left", -1),
3931 right = this.GetSelectIndex(
"x",
"right", 2),
3932 pmain = this.frame_painter(),
3933 pad = this.root_pad(),
3934 histo = this.GetHisto(),
3935 xaxis = histo.fXaxis,
3937 res =
"", lastbin =
false,
3938 startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, bestimin, bestimax,
3939 exclude_zero = !this.options.Zero,
3940 show_errors = this.options.Error,
3941 show_markers = this.options.Mark,
3942 show_line = this.options.Line || this.options.Curve,
3943 show_text = this.options.Text,
3944 text_profile = show_text && (this.options.TextKind ==
"E") && this.IsTProfile() && histo.fBinEntries,
3945 path_fill = null, path_err = null, path_marker = null, path_line = null,
3946 do_marker =
false, do_err =
false,
3947 endx =
"", endy =
"", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, midx, mmx1, mmx2,
3948 mpath =
"", text_col, text_angle, text_size;
3950 if (show_errors && !show_markers && (histo.fMarkerStyle > 1))
3951 show_markers =
true;
3953 if (this.options.ErrorKind === 2) {
3954 if (this.fillatt.empty()) show_markers =
true;
3955 else path_fill =
"";
3956 }
else if (this.options.Error) {
3961 if (show_line) path_line =
"";
3965 this.createAttMarker({ attr: histo, style: this.options.MarkStyle });
3966 if (this.markeratt.size > 0) {
3970 this.markeratt.reset_pos();
3972 show_markers =
false;
3976 var draw_markers = show_errors || show_markers,
3977 draw_any_but_hist = draw_markers || show_text || show_line,
3978 draw_hist = this.options.Hist && (!this.lineatt.empty() || !this.fillatt.empty());
3980 if (!draw_hist && !draw_any_but_hist)
3981 return this.RemoveDrawG();
3986 text_col = this.get_color(histo.fMarkerColor);
3987 text_angle = -1*this.options.TextAngle;
3990 if ((histo.fMarkerSize!==1) && text_angle)
3991 text_size = 0.02*height*histo.fMarkerSize;
3993 if (!text_angle && !this.options.TextKind) {
3994 var space = width / (right - left + 1);
3995 if (space < 3 * text_size) {
3997 text_size = Math.round(space*0.7);
4001 this.StartTextDrawing(42, text_size, this.draw_g, text_size);
4006 var use_minmax = ((right-left) > 3*width);
4008 if (this.options.ErrorKind === 1) {
4009 var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize;
4010 endx =
"m0," + lw +
"v-" + 2*lw +
"m0," + lw;
4011 endy =
"m" + lw +
",0h-" + 2*lw +
"m" + lw +
",0";
4012 dend = Math.floor((this.lineatt.width-1)/2);
4015 if (draw_any_but_hist) use_minmax =
true;
4018 function extract_bin(bin) {
4019 bincont = histo.getBinContent(bin+1);
4020 if (exclude_zero && (bincont===0))
return false;
4021 mx1 = Math.round(pmain.grx(xaxis.GetBinLowEdge(bin+1)));
4022 mx2 = Math.round(pmain.grx(xaxis.GetBinLowEdge(bin+2)));
4023 midx = Math.round((mx1+mx2)/2);
4024 my = Math.round(pmain.gry(bincont));
4027 binerr = histo.getBinError(bin+1);
4028 yerr1 = Math.round(my - pmain.gry(bincont + binerr));
4029 yerr2 = Math.round(pmain.gry(bincont - binerr) - my);
4034 function draw_errbin(bin) {
4035 if (pthis.options.errorX > 0) {
4036 mmx1 = Math.round(midx - (mx2-mx1)*pthis.options.errorX);
4037 mmx2 = Math.round(midx + (mx2-mx1)*pthis.options.errorX);
4038 path_err +=
"M" + (mmx1+dend) +
","+ my + endx +
"h" + (mmx2-mmx1-2*dend) + endx;
4040 path_err +=
"M" + midx +
"," + (my-yerr1+dend) + endy +
"v" + (yerr1+yerr2-2*dend) + endy;
4043 function draw_bin(bin) {
4044 if (extract_bin(bin)) {
4046 var cont = text_profile ? histo.fBinEntries[bin+1] : bincont;
4049 var lbl = (cont === Math.round(cont)) ? cont.toString() : JSROOT.FFormat(cont, JSROOT.gStyle.fPaintTextFormat);
4052 pthis.DrawText({ align: 12, x: midx, y: Math.round(my - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 });
4054 pthis.DrawText({ align: 22, x: Math.round(mx1 + (mx2-mx1)*0.1), y: Math.round(my-2-text_size), width: Math.round((mx2-mx1)*0.8), height: text_size, text: lbl, color: text_col, latex: 0 });
4058 if (show_line && (path_line !== null))
4059 path_line += ((path_line.length===0) ?
"M" :
"L") + midx +
"," + my;
4062 if ((my >= -yerr1) && (my <= height + yerr2)) {
4063 if (path_fill !== null)
4064 path_fill +=
"M" + mx1 +
","+(my-yerr1) +
4065 "h" + (mx2-mx1) +
"v" + (yerr1+yerr2+1) +
"h-" + (mx2-mx1) +
"z";
4066 if ((path_marker !== null) && do_marker)
4067 path_marker += pthis.markeratt.create(midx, my);
4068 if ((path_err !== null) && do_err)
4076 if (do_marker || do_err)
4077 if (!JSROOT.gStyle.OptimizeDraw || ((right-left<50000) && (JSROOT.gStyle.OptimizeDraw==1))) {
4078 for (i = left; i < right; ++i) {
4079 if (extract_bin(i)) {
4080 if (path_marker !== null)
4081 path_marker += pthis.markeratt.create(midx, my);
4082 if (path_err !== null)
4086 do_err = do_marker =
false;
4090 for (i = left; i <= right; ++i) {
4092 x = xaxis.GetBinLowEdge(i+1);
4094 if (this.logx && (x <= 0))
continue;
4096 grx = Math.round(pmain.grx(x));
4098 lastbin = (i === right);
4100 if (lastbin && (left<right)) {
4103 y = histo.getBinContent(i+1);
4104 gry = Math.round(pmain.gry(y));
4107 if (res.length === 0) {
4108 bestimin = bestimax = i;
4109 prevx = startx = currx = grx;
4110 prevy = curry_min = curry_max = curry = gry;
4111 res =
"M"+currx+
","+curry;
4112 }
else if (use_minmax) {
4113 if ((grx === currx) && !lastbin) {
4114 if (gry < curry_min) bestimax = i;
else
4115 if (gry > curry_max) bestimin = i;
4117 curry_min = Math.min(curry_min, gry);
4118 curry_max = Math.max(curry_max, gry);
4122 if (draw_any_but_hist) {
4123 if (bestimin === bestimax) { draw_bin(bestimin); }
else
4124 if (bestimin < bestimax) { draw_bin(bestimin); draw_bin(bestimax); }
else {
4125 draw_bin(bestimax); draw_bin(bestimin);
4130 if (draw_hist && ((curry_min !== curry_max) || (prevy !== curry_min))) {
4132 if (prevx !== currx)
4133 res +=
"h"+(currx-prevx);
4135 if (curry === curry_min) {
4136 if (curry_max !== prevy)
4137 res +=
"v" + (curry_max - prevy);
4138 if (curry_min !== curry_max)
4139 res +=
"v" + (curry_min - curry_max);
4141 if (curry_min !== prevy)
4142 res +=
"v" + (curry_min - prevy);
4143 if (curry_max !== curry_min)
4144 res +=
"v" + (curry_max - curry_min);
4145 if (curry !== curry_max)
4146 res +=
"v" + (curry - curry_max);
4153 if (lastbin && (prevx !== grx))
4154 res +=
"h"+(grx-prevx);
4156 bestimin = bestimax = i;
4157 curry_min = curry_max = curry = gry;
4161 }
else if ((gry !== curry) || lastbin) {
4162 if (grx !== currx) res +=
"h"+(grx-currx);
4163 if (gry !== curry) res +=
"v"+(gry-curry);
4169 var close_path =
"";
4170 if (!this.fillatt.empty()) {
4171 var h0 = height + 3, gry0 = Math.round(pmain.gry(0));
4172 if (gry0 <= 0) h0 = -3;
else if (gry0 < height) h0 = gry0;
4173 close_path =
"L"+currx+
","+h0 +
"L"+startx+
","+h0 +
"Z";
4174 if (res.length>0) res += close_path;
4177 if (draw_markers || show_line) {
4178 if ((path_fill !== null) && (path_fill.length > 0))
4179 this.draw_g.append(
"svg:path")
4180 .attr(
"d", path_fill)
4181 .call(this.fillatt.func);
4183 if ((path_err !== null) && (path_err.length > 0))
4184 this.draw_g.append(
"svg:path")
4185 .attr(
"d", path_err)
4186 .call(this.lineatt.func);
4188 if ((path_line !== null) && (path_line.length > 0)) {
4189 if (!this.fillatt.empty())
4190 this.draw_g.append(
"svg:path")
4191 .attr(
"d", this.options.Fill ? (path_line + close_path) : res)
4192 .attr(
"stroke",
"none")
4193 .call(this.fillatt.func);
4195 this.draw_g.append(
"svg:path")
4196 .attr(
"d", path_line)
4197 .attr(
"fill",
"none")
4198 .call(this.lineatt.func);
4201 if ((path_marker !== null) && (path_marker.length > 0))
4202 this.draw_g.append(
"svg:path")
4203 .attr(
"d", path_marker)
4204 .call(this.markeratt.func);
4208 if ((res.length > 0) && draw_hist) {
4209 this.draw_g.append(
"svg:path")
4211 .style(
"stroke-linejoin",
"miter")
4212 .call(this.lineatt.func)
4213 .call(this.fillatt.func);
4217 this.FinishTextDrawing(this.draw_g);
4221 TH1Painter.prototype.GetBinTips =
function(bin) {
4223 name = this.GetTipName(),
4224 pmain = this.frame_painter(),
4225 histo = this.GetHisto(),
4226 x1 = histo.fXaxis.GetBinLowEdge(bin+1),
4227 x2 = histo.fXaxis.GetBinLowEdge(bin+2),
4228 cont = histo.getBinContent(bin+1),
4229 xlbl =
"", xnormal =
false;
4231 if (name.length>0) tips.push(name);
4233 if (pmain.x_kind ===
'labels') xlbl = pmain.AxisAsText(
"x", x1);
else
4234 if (pmain.x_kind ===
'time') xlbl = pmain.AxisAsText(
"x", (x1+x2)/2);
else
4235 { xnormal =
true; xlbl =
"[" + pmain.AxisAsText(
"x", x1) +
", " + pmain.AxisAsText(
"x", x2) +
")"; }
4237 if (this.options.Error ||
this.options.Mark) {
4238 tips.push(
"x = " + xlbl);
4239 tips.push(
"y = " + pmain.AxisAsText(
"y", cont));
4240 if (this.options.Error) {
4241 if (xnormal) tips.push(
"error x = " + ((x2 - x1) / 2).toPrecision(4));
4242 tips.push(
"error y = " + histo.getBinError(bin + 1).toPrecision(4));
4245 tips.push(
"bin = " + (bin+1));
4246 tips.push(
"x = " + xlbl);
4247 if (histo[
'$baseh']) cont -= histo[
'$baseh'].getBinContent(bin+1);
4248 if (cont === Math.round(cont))
4249 tips.push(
"entries = " + cont);
4251 tips.push(
"entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.fStatFormat));
4258 TH1Painter.prototype.ProcessTooltip =
function(pnt) {
4259 if ((pnt === null) || !this.draw_content || !this.draw_g || this.options.Mode3D) {
4260 if (this.draw_g !== null)
4261 this.draw_g.select(
".tooltip_bin").remove();
4265 var width = this.frame_width(),
4266 height = this.frame_height(),
4267 pmain = this.frame_painter(),
4268 pad = this.root_pad(),
4270 histo = this.GetHisto(),
4271 findbin = null, show_rect =
true,
4272 grx1, midx, grx2, gry1, midy, gry2, gapx = 2,
4273 left = this.GetSelectIndex(
"x",
"left", -1),
4274 right = this.GetSelectIndex(
"x",
"right", 2),
4275 l = left, r = right, pnt_x = pnt.x, pnt_y = pnt.y;
4277 function GetBinGrX(i) {
4278 var xx = histo.fXaxis.GetBinLowEdge(i+1);
4279 return (pmain.logx && (xx<=0)) ? null : pmain.grx(xx);
4282 function GetBinGrY(i) {
4283 var yy = histo.getBinContent(i + 1);
4284 if (pmain.logy && (yy < pmain.scale_ymin))
4285 return pmain.swap_xy ? -1000 : 10*height;
4286 return Math.round(pmain.gry(yy));
4289 if (pmain.swap_xy) {
4290 var d = pnt.x; pnt_x = pnt_y; pnt_y = d;
4291 d = height; height = width; width = d;
4295 var m = Math.round((l+r)*0.5), xx = GetBinGrX(m);
4296 if ((xx === null) || (xx < pnt_x - 0.5)) {
4297 if (pmain.swap_xy) r = m;
else l = m;
4298 }
else if (xx > pnt_x + 0.5) {
4299 if (pmain.swap_xy) l = m;
else r = m;
4300 }
else { l++; r--; }
4304 grx1 = GetBinGrX(findbin);
4306 if (pmain.swap_xy) {
4307 while ((l>left) && (GetBinGrX(l-1) < grx1 + 2)) --l;
4308 while ((r<right) && (GetBinGrX(r+1) > grx1 - 2)) ++r;
4310 while ((l>left) && (GetBinGrX(l-1) > grx1 - 2)) --l;
4311 while ((r<right) && (GetBinGrX(r+1) < grx1 + 2)) ++r;
4318 for (var m=l;m<=r;m++) {
4319 var dist = Math.abs(GetBinGrY(m) - pnt_y);
4320 if (dist < best) { best = dist; findbin = m; }
4324 if (best > height/10)
4325 findbin = Math.round(l + (r-l) / height * pnt_y);
4327 grx1 = GetBinGrX(findbin);
4330 grx1 = Math.round(grx1);
4331 grx2 = Math.round(GetBinGrX(findbin+1));
4333 if (this.options.Bar) {
4334 var w = grx2 - grx1;
4335 grx1 += Math.round(histo.fBarOffset/1000*w);
4336 grx2 = grx1 + Math.round(histo.fBarWidth/1000*w);
4339 if (grx1 > grx2) { var d = grx1; grx1 = grx2; grx2 = d; }
4341 midx = Math.round((grx1+grx2)/2);
4343 midy = gry1 = gry2 = GetBinGrY(findbin);
4345 if (this.options.Bar) {
4350 gry1 = Math.round(pmain.gry(((
this.options.BaseLine!==
false) && (
this.options.BaseLine > pmain.scale_ymin)) ?
this.options.BaseLine : pmain.scale_ymin));
4352 if (gry1 > gry2) { var d = gry1; gry1 = gry2; gry2 = d; }
4354 if (!pnt.touch && (pnt.nproc === 1))
4355 if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null;
4357 }
else if (this.options.Error ||
this.options.Mark ||
this.options.Line ||
this.options.Curve) {
4362 if (this.markeratt) msize = Math.max(msize, this.markeratt.GetFullSize());
4364 if (this.options.Error) {
4365 var cont = histo.getBinContent(findbin+1),
4366 binerr = histo.getBinError(findbin+1);
4368 gry1 = Math.round(pmain.gry(cont + binerr));
4369 gry2 = Math.round(pmain.gry(cont - binerr));
4371 if ((cont==0) && this.IsTProfile()) findbin = null;
4373 var dx = (grx2-grx1)*this.options.errorX;
4374 grx1 = Math.round(midx - dx);
4375 grx2 = Math.round(midx + dx);
4379 if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; }
4381 gry1 = Math.min(gry1, midy - msize);
4382 gry2 = Math.max(gry2, midy + msize);
4384 if (!pnt.touch && (pnt.nproc === 1))
4385 if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null;
4391 show_rect = (pnt.nproc === 1) && (right-left < width);
4396 if (!this.fillatt.empty()) {
4397 gry2 = Math.round(pmain.gry(0));
4398 if (gry2 < 0) gry2 = 0;
else if (gry2 > height) gry2 = height;
4399 if (gry2 < gry1) { var d = gry1; gry1 = gry2; gry2 = d; }
4403 if (((pnt.y < gry1) || (pnt.y > gry2)) && !pnt.touch) findbin = null;
4407 if (findbin!==null) {
4409 if ((findbin === left) && (grx1 > pnt_x + gapx)) findbin = null;
else
4410 if ((findbin === right-1) && (grx2 < pnt_x - gapx)) findbin = null;
else
4412 if ((pnt_x < grx1 - gapx) || (pnt_x > grx2 + gapx)) findbin = null;
else
4414 if (!this.options.Zero && (histo.getBinContent(findbin+1)===0)) findbin = null;
4417 var ttrect = this.draw_g.select(
".tooltip_bin");
4419 if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) {
4424 var res = { name: histo.fName, title: histo.fTitle,
4425 x: midx, y: midy, exact:
true,
4426 color1: this.lineatt ? this.lineatt.color :
'green',
4427 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
'blue',
4428 lines: this.GetBinTips(findbin) };
4439 ttrect = this.draw_g.append(
"svg:rect")
4440 .attr(
"class",
"tooltip_bin h1bin")
4441 .style(
"pointer-events",
"none");
4443 res.changed = ttrect.property(
"current_bin") !== findbin;
4446 ttrect.attr(
"x", pmain.swap_xy ? gry1 : grx1)
4447 .attr(
"width", pmain.swap_xy ? gry2-gry1 : grx2-grx1)
4448 .attr(
"y", pmain.swap_xy ? grx1 : gry1)
4449 .attr(
"height", pmain.swap_xy ? grx2-grx1 : gry2-gry1)
4450 .style(
"opacity",
"0.3")
4451 .property(
"current_bin", findbin);
4453 res.exact = (Math.abs(midy - pnt_y) <= 5) || ((pnt_y>=gry1) && (pnt_y<=gry2));
4457 res.menu_dist = Math.sqrt((midx-pnt_x)*(midx-pnt_x) + (midy-pnt_y)*(midy-pnt_y));
4460 var radius = this.lineatt.width + 3;
4463 ttrect = this.draw_g.append(
"svg:circle")
4464 .attr(
"class",
"tooltip_bin")
4465 .style(
"pointer-events",
"none")
4467 .call(this.lineatt.func)
4468 .call(this.fillatt.func);
4470 res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius);
4472 res.menu = res.exact;
4473 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
4475 res.changed = ttrect.property(
"current_bin") !== findbin;
4478 ttrect.attr(
"cx", midx)
4480 .property(
"current_bin", findbin);
4484 res.user_info = { obj: histo, name: histo.fName,
4485 bin: findbin, cont: histo.getBinContent(findbin+1),
4486 grx: midx, gry: midy };
4491 TH1Painter.prototype.FillHistContextMenu =
function(menu) {
4493 menu.add(
"Auto zoom-in", this.AutoZoom);
4495 var sett = JSROOT.getDrawSettings(
"ROOT." + this.GetObject()._typename,
'nosame');
4497 menu.addDrawMenu(
"Draw with", sett.opts,
function(arg) {
4498 if (arg===
'inspect')
4499 return this.ShowInspector();
4501 this.DecodeOptions(arg);
4503 if (this.options.need_fillcol &&
this.fillatt &&
this.fillatt.empty())
4504 this.fillatt.Change(5,1001);
4507 this.InteractiveRedraw(
"pad",
"drawopt");
4511 TH1Painter.prototype.AutoZoom =
function() {
4512 var left = this.GetSelectIndex(
"x",
"left", -1),
4513 right = this.GetSelectIndex(
"x",
"right", 1),
4514 dist = right - left, histo = this.GetHisto();
4516 if ((dist == 0) || !histo)
return;
4519 var min = histo.getBinContent(left + 1);
4520 for (var indx = left; indx < right; ++indx)
4521 min = Math.min(min, histo.getBinContent(indx+1));
4522 if (min > 0)
return;
4524 while ((left < right) && (histo.getBinContent(left+1) <= min)) ++left;
4525 while ((left < right) && (histo.getBinContent(right) <= min)) --right;
4528 if ((left === right-1) && (left > 2) && (right < this.nbinsx-2)) {
4532 if ((right - left < dist) && (left < right))
4533 this.frame_painter().Zoom(histo.fXaxis.GetBinLowEdge(left+1), histo.fXaxis.GetBinLowEdge(right+1));
4536 TH1Painter.prototype.CanZoomIn =
function(axis,min,max) {
4537 var histo = this.GetHisto();
4539 if ((axis==
"x") && histo && (histo.fXaxis.FindBin(max,0.5) - histo.fXaxis.FindBin(min,0) > 1))
return true;
4541 if ((axis==
"y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6))
return true;
4547 TH1Painter.prototype.CallDrawFunc =
function(callback, resize) {
4549 var main = this.main_painter(),
4550 fp = this.frame_painter();
4552 if ((main!==
this) && fp && (fp.mode3d !==
this.options.Mode3D))
4553 this.CopyOptionsFrom(main);
4555 var funcname = this.options.Mode3D ?
"Draw3D" :
"Draw2D";
4557 this[funcname](callback, resize);
4560 TH1Painter.prototype.Draw2D =
function(call_back) {
4561 this.Clear3DScene();
4562 this.mode3d =
false;
4564 this.ScanContent(
true);
4568 if (typeof this.DrawColorPalette ===
'function')
4569 this.DrawColorPalette(
false);
4574 this.UpdateStatWebCanvas();
4575 this.AddInteractive();
4576 JSROOT.CallBack(call_back);
4579 TH1Painter.prototype.Draw3D =
function(call_back, resize) {
4581 JSROOT.AssertPrerequisites(
'hist3d',
function() {
4582 this.Draw3D(call_back, resize);
4586 TH1Painter.prototype.Redraw =
function(resize) {
4587 this.CallDrawFunc(null, resize);
4590 function drawHistogram1D(divid, histo, opt) {
4592 var painter =
new TH1Painter(histo);
4594 painter.SetDivId(divid, 1);
4597 painter.DecodeOptions(opt);
4599 painter.CheckPadRange(!painter.options.Mode3D);
4601 painter.ScanContent();
4603 painter.CreateStat();
4605 painter.CallDrawFunc(
function() {
4606 painter.DrawNextFunction(0,
function() {
4607 if (!painter.options.Mode3D && painter.options.AutoZoom) painter.AutoZoom();
4608 painter.FillToolbar();
4609 painter.DrawingReady();
4627 function TH2Painter(histo) {
4628 THistPainter.call(
this, histo);
4629 this.fContour = null;
4630 this.fCustomContour =
false;
4631 this.fPalette = null;
4632 this.wheel_zoomy =
true;
4635 TH2Painter.prototype = Object.create(THistPainter.prototype);
4637 TH2Painter.prototype.Cleanup =
function() {
4638 delete this.fCustomContour;
4639 delete this.tt_handle;
4641 THistPainter.prototype.Cleanup.call(
this);
4644 TH2Painter.prototype.ToggleProjection =
function(kind, width) {
4646 if ((kind==
"Projections") || (kind==
"Off")) kind =
"";
4648 if ((typeof kind ==
'string') && (kind.length>1)) {
4649 width = parseInt(kind.substr(1));
4653 if (!width) width = 1;
4655 if (kind && (this.is_projection==kind)) {
4656 if (this.projection_width === width) {
4659 this.projection_width = width;
4664 delete this.proj_hist;
4666 var new_proj = (this.is_projection === kind) ?
"" : kind;
4667 this.is_projection =
"";
4668 this.projection_width = width;
4670 var canp = this.canv_painter();
4671 if (canp) canp.ToggleProjection(new_proj, this.RedrawProjection.bind(
this,
"toggling", new_proj));
4674 TH2Painter.prototype.RedrawProjection =
function(ii1, ii2, jj1, jj2) {
4675 if (ii1 ===
"toggling") {
4676 this.is_projection = ii2;
4677 ii1 = ii2 = undefined;
4679 if (!this.is_projection)
return;
4681 if (jj2 == undefined) {
4682 if (!this.tt_handle)
return;
4683 ii1 = Math.round((this.tt_handle.i1 +
this.tt_handle.i2)/2); ii2 = ii1+1;
4684 jj1 = Math.round((this.tt_handle.j1 +
this.tt_handle.j2)/2); jj2 = jj1+1;
4687 var canp = this.canv_painter(), histo = this.GetHisto();
4689 if (canp && !canp._readonly && (
this.snapid !== undefined)) {
4691 var exec =
"EXECANDSEND:D" + this.is_projection +
"PROJ:" + this.snapid +
":";
4692 if (this.is_projection ==
"X")
4693 exec +=
'ProjectionX("_projx",' + (jj1+1) +
',' + jj2 +
',"")';
4695 exec +=
'ProjectionY("_projy",' + (ii1+1) +
',' + ii2 +
',"")';
4696 canp.SendWebsocket(exec);
4700 if (!this.proj_hist) {
4701 if (this.is_projection ==
"X") {
4702 this.proj_hist = JSROOT.CreateHistogram(
"TH1D", this.nbinsx);
4703 JSROOT.extend(this.proj_hist.fXaxis, histo.fXaxis);
4704 this.proj_hist.fName =
"xproj";
4705 this.proj_hist.fTitle =
"X projection";
4707 this.proj_hist = JSROOT.CreateHistogram(
"TH1D", this.nbinsy);
4708 JSROOT.extend(this.proj_hist.fXaxis, histo.fYaxis);
4709 this.proj_hist.fName =
"yproj";
4710 this.proj_hist.fTitle =
"Y projection";
4714 if (this.is_projection ==
"X") {
4715 for (var i=0;i<this.nbinsx;++i) {
4717 for (var j=jj1;j<jj2;++j) sum += histo.getBinContent(i+1,j+1);
4718 this.proj_hist.setBinContent(i+1, sum);
4721 for (var j=0;j<this.nbinsy;++j) {
4723 for (var i=ii1;i<ii2;++i) sum += histo.getBinContent(i+1,j+1);
4724 this.proj_hist.setBinContent(j+1, sum);
4728 return canp.DrawProjection(this.is_projection, this.proj_hist);
4731 TH2Painter.prototype.ExecuteMenuCommand =
function(method, args) {
4732 if (THistPainter.prototype.ExecuteMenuCommand.call(
this,method, args))
return true;
4734 if ((method.fName ==
'SetShowProjectionX') || (method.fName ==
'SetShowProjectionY')) {
4735 this.ToggleProjection(method.fName[17], args && parseInt(args) ? parseInt(args) : 1);
4742 TH2Painter.prototype.FillHistContextMenu =
function(menu) {
4745 if (!this.IsTH2Poly()) {
4746 menu.add(
"sub:Projections", this.ToggleProjection);
4747 var kind = this.is_projection ||
"";
4748 if (kind) kind += this.projection_width;
4749 var kinds = [
"X1",
"X2",
"X3",
"X5",
"X10",
"Y1",
"Y2",
"Y3",
"Y5",
"Y10"];
4750 if (this.is_projection) kinds.push(
"Off");
4751 for (var k=0;k<kinds.length;++k)
4752 menu.addchk(kind==kinds[k], kinds[k], kinds[k],
this.ToggleProjection);
4753 menu.add(
"endsub:");
4755 menu.add(
"Auto zoom-in", this.AutoZoom);
4758 var sett = JSROOT.getDrawSettings(
"ROOT." + this.GetObject()._typename,
'nosame');
4760 menu.addDrawMenu(
"Draw with", sett.opts,
function(arg) {
4761 if (arg===
'inspect')
4762 return this.ShowInspector();
4763 this.DecodeOptions(arg);
4764 this.InteractiveRedraw(
"pad",
"drawopt");
4767 if (this.options.Color)
4768 this.FillPaletteMenu(menu);
4771 TH2Painter.prototype.ButtonClick =
function(funcname) {
4772 if (THistPainter.prototype.ButtonClick.call(
this, funcname))
return true;
4774 if (
this !== this.main_painter())
return false;
4777 case "ToggleColor": this.ToggleColor();
break;
4778 case "ToggleColorZ": this.ToggleColz();
break;
4779 case "Toggle3D": this.ToggleMode3D();
break;
4780 default:
return false;
4787 TH2Painter.prototype.FillToolbar =
function() {
4788 THistPainter.prototype.FillToolbar.call(
this,
true);
4790 var pp = this.pad_painter();
4793 if (!this.IsTH2Poly())
4794 pp.AddButton(JSROOT.ToolbarIcons.th2color,
"Toggle color",
"ToggleColor");
4795 pp.AddButton(JSROOT.ToolbarIcons.th2colorz,
"Toggle color palette",
"ToggleColorZ");
4796 pp.AddButton(JSROOT.ToolbarIcons.th2draw3d,
"Toggle 3D mode",
"Toggle3D");
4800 TH2Painter.prototype.ToggleColor =
function() {
4802 if (this.options.Mode3D) {
4803 this.options.Mode3D =
false;
4804 this.options.Color =
true;
4806 this.options.Color = !this.options.Color;
4809 this._can_move_colz =
true;
4811 this.CopyOptionsToOthers();
4818 TH2Painter.prototype.AutoZoom =
function() {
4819 if (this.IsTH2Poly())
return;
4821 var i1 = this.GetSelectIndex(
"x",
"left", -1),
4822 i2 = this.GetSelectIndex(
"x",
"right", 1),
4823 j1 = this.GetSelectIndex(
"y",
"left", -1),
4824 j2 = this.GetSelectIndex(
"y",
"right", 1),
4825 i,j, histo = this.GetObject();
4827 if ((i1 == i2) || (j1 == j2))
return;
4830 var min = histo.getBinContent(i1 + 1, j1 + 1);
4831 for (i = i1; i < i2; ++i)
4832 for (j = j1; j < j2; ++j)
4833 min = Math.min(min, histo.getBinContent(i+1, j+1));
4834 if (min > 0)
return;
4836 var ileft = i2, iright = i1, jleft = j2, jright = j1;
4838 for (i = i1; i < i2; ++i)
4839 for (j = j1; j < j2; ++j)
4840 if (histo.getBinContent(i + 1, j + 1) > min) {
4841 if (i < ileft) ileft = i;
4842 if (i >= iright) iright = i + 1;
4843 if (j < jleft) jleft = j;
4844 if (j >= jright) jright = j + 1;
4847 var xmin, xmax, ymin, ymax, isany =
false;
4849 if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; }
4850 if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; }
4852 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
4853 xmin = histo.fXaxis.GetBinLowEdge(ileft+1);
4854 xmax = histo.fXaxis.GetBinLowEdge(iright+1);
4858 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
4859 ymin = histo.fYaxis.GetBinLowEdge(jleft+1);
4860 ymax = histo.fYaxis.GetBinLowEdge(jright+1);
4865 this.frame_painter().Zoom(xmin, xmax, ymin, ymax);
4868 TH2Painter.prototype.ScanContent =
function(when_axis_changed) {
4871 if (when_axis_changed && this.nbinsx && this.nbinsy)
return;
4873 var i, j, histo = this.GetObject();
4875 this.nbinsx = histo.fXaxis.fNbins;
4876 this.nbinsy = histo.fYaxis.fNbins;
4880 this.CreateAxisFuncs(
true);
4882 if (this.IsTH2Poly()) {
4883 this.gminposbin = null;
4884 this.gminbin = this.gmaxbin = 0;
4886 for (var n=0, len=histo.fBins.arr.length; n<len; ++n) {
4887 var bin_content = histo.fBins.arr[n].fContent;
4888 if (n===0) this.gminbin = this.gmaxbin = bin_content;
4890 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
4891 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
4893 if (bin_content > 0)
4894 if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content;
4898 this.gminbin = this.gmaxbin = histo.getBinContent(1, 1);
4899 this.gminposbin = null;
4900 for (i = 0; i < this.nbinsx; ++i) {
4901 for (j = 0; j < this.nbinsy; ++j) {
4902 var bin_content = histo.getBinContent(i+1, j+1);
4903 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
4904 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
4905 if (bin_content > 0)
4906 if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content;
4912 if (this.gminposbin === null) this.gminposbin = this.gmaxbin*1e-4;
4914 if (this.options.Axis > 0) {
4915 this.draw_content =
false;
4917 this.draw_content = (this.gmaxbin > 0);
4918 if (!this.draw_content && this.options.Zero &&
this.IsTH2Poly()) {
4919 this.draw_content =
true;
4920 this.options.Line = 1;
4925 TH2Painter.prototype.CountStat =
function(cond) {
4926 var histo = this.GetHisto(), xaxis = histo.fXaxis, yaxis = histo.fYaxis,
4927 stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0,
4928 stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0,
4929 xside, yside, xx, yy, zz,
4930 fp = this.frame_painter(),
4931 res = { name: histo.fName, entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix: [0,0,0,0,0,0,0,0,0], xmax: 0, ymax:0, wmax: null };
4933 if (this.IsTH2Poly()) {
4935 var len = histo.fBins.arr.length, i, bin, n, gr, ngr, numgraphs, numpoints,
4936 pmain = this.frame_painter();
4938 for (i=0;i<len;++i) {
4939 bin = histo.fBins.arr[i];
4941 xside = 1; yside = 1;
4943 if (bin.fXmin > pmain.scale_xmax) xside = 2;
else
4944 if (bin.fXmax < pmain.scale_xmin) xside = 0;
4945 if (bin.fYmin > pmain.scale_ymax) yside = 2;
else
4946 if (bin.fYmax < pmain.scale_ymin) yside = 0;
4948 xx = yy = numpoints = 0;
4949 gr = bin.fPoly; numgraphs = 1;
4950 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
4952 for (ngr=0;ngr<numgraphs;++ngr) {
4953 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
4955 for (n=0;n<gr.fNpoints;++n) {
4962 if (numpoints > 1) {
4963 xx = xx / numpoints;
4964 yy = yy / numpoints;
4971 res.matrix[yside * 3 + xside] += zz;
4973 if ((xside != 1) || (yside != 1))
continue;
4975 if (cond && !cond(xx,yy))
continue;
4977 if ((res.wmax===null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
4980 stat_sumx1 += xx * zz;
4981 stat_sumy1 += yy * zz;
4982 stat_sumx2 += xx * xx * zz;
4983 stat_sumy2 += yy * yy * zz;
4984 stat_sumxy += xx * yy * zz;
4987 var xleft = this.GetSelectIndex(
"x",
"left"),
4988 xright = this.GetSelectIndex(
"x",
"right"),
4989 yleft = this.GetSelectIndex(
"y",
"left"),
4990 yright = this.GetSelectIndex(
"y",
"right"),
4993 for (xi = 0; xi <= this.nbinsx + 1; ++xi) {
4994 xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
4995 xx = xaxis.GetBinCoord(xi - 0.5);
4997 for (yi = 0; yi <= this.nbinsy + 1; ++yi) {
4998 yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
4999 yy = yaxis.GetBinCoord(yi - 0.5);
5001 zz = histo.getBinContent(xi, yi);
5005 res.matrix[yside * 3 + xside] += zz;
5007 if ((xside != 1) || (yside != 1))
continue;
5009 if ((cond!=null) && !cond(xx,yy))
continue;
5011 if ((res.wmax===null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
5014 stat_sumx1 += xx * zz;
5015 stat_sumy1 += yy * zz;
5016 stat_sumx2 += xx * xx * zz;
5017 stat_sumy2 += yy * yy * zz;
5018 stat_sumxy += xx * yy * zz;
5023 if (!fp.IsAxisZoomed(
"x") && !fp.IsAxisZoomed(
"y") && (histo.fTsumw > 0)) {
5024 stat_sum0 = histo.fTsumw;
5025 stat_sumx1 = histo.fTsumwx;
5026 stat_sumx2 = histo.fTsumwx2;
5027 stat_sumy1 = histo.fTsumwy;
5028 stat_sumy2 = histo.fTsumwy2;
5029 stat_sumxy = histo.fTsumwxy;
5032 if (stat_sum0 > 0) {
5033 res.meanx = stat_sumx1 / stat_sum0;
5034 res.meany = stat_sumy1 / stat_sum0;
5035 res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx));
5036 res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany));
5039 if (res.wmax===null) res.wmax = 0;
5040 res.integral = stat_sum0;
5042 if (histo.fEntries > 1) res.entries = histo.fEntries;
5047 TH2Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
5050 if (this.IgnoreStatsFill())
return false;
5052 var data = this.CountStat(),
5053 print_name = Math.floor(dostat % 10),
5054 print_entries = Math.floor(dostat / 10) % 10,
5055 print_mean = Math.floor(dostat / 100) % 10,
5056 print_rms = Math.floor(dostat / 1000) % 10,
5057 print_under = Math.floor(dostat / 10000) % 10,
5058 print_over = Math.floor(dostat / 100000) % 10,
5059 print_integral = Math.floor(dostat / 1000000) % 10,
5060 print_skew = Math.floor(dostat / 10000000) % 10,
5061 print_kurt = Math.floor(dostat / 100000000) % 10;
5066 stat.AddText(data.name);
5068 if (print_entries > 0)
5069 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
5071 if (print_mean > 0) {
5072 stat.AddText(
"Mean x = " + stat.Format(data.meanx));
5073 stat.AddText(
"Mean y = " + stat.Format(data.meany));
5076 if (print_rms > 0) {
5077 stat.AddText(
"Std Dev x = " + stat.Format(data.rmsx));
5078 stat.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
5081 if (print_integral > 0)
5082 stat.AddText(
"Integral = " + stat.Format(data.matrix[4],
"entries"));
5084 if (print_skew > 0) {
5085 stat.AddText(
"Skewness x = <undef>");
5086 stat.AddText(
"Skewness y = <undef>");
5090 stat.AddText(
"Kurt = <undef>");
5092 if ((print_under > 0) || (print_over > 0)) {
5093 var m = data.matrix;
5095 stat.AddText(
"" + m[6].toFixed(0) +
" | " + m[7].toFixed(0) +
" | " + m[7].toFixed(0));
5096 stat.AddText(
"" + m[3].toFixed(0) +
" | " + m[4].toFixed(0) +
" | " + m[5].toFixed(0));
5097 stat.AddText(
"" + m[0].toFixed(0) +
" | " + m[1].toFixed(0) +
" | " + m[2].toFixed(0));
5100 if (dofit) stat.FillFunctionStat(this.FindFunction(
'TF1'), dofit);
5105 TH2Painter.prototype.DrawBinsColor =
function(w,h) {
5106 var histo = this.GetHisto(),
5107 handle = this.PrepareColorDraw(),
5108 colPaths = [], currx = [], curry = [],
5109 colindx, cmd1, cmd2, i, j, binz, x1, dx, y2, dy;
5112 for (i = handle.i1; i < handle.i2; ++i) {
5114 dx = handle.grx[i+1] - handle.grx[i];
5115 x1 = Math.round(handle.grx[i] + dx*handle.xbar1);
5116 dx = Math.round(dx*(handle.xbar2-handle.xbar1));
5118 for (j = handle.j1; j < handle.j2; ++j) {
5119 binz = histo.getBinContent(i + 1, j + 1);
5120 colindx = this.getContourColor(binz,
true);
5122 if (!this.options.Zero)
continue;
5123 if ((colindx === null) && this._show_empty_bins) colindx = 0;
5125 if (colindx === null)
continue;
5127 dy = handle.gry[j]-handle.gry[j+1];
5128 y2 = Math.round(handle.gry[j+1] + dy*handle.ybar1);
5129 dy = Math.round(dy*(handle.ybar2-handle.ybar1));
5131 cmd1 =
"M"+x1+
","+y2;
5132 if (colPaths[colindx] === undefined) {
5133 colPaths[colindx] = cmd1;
5135 cmd2 =
"m" + (x1-currx[colindx]) +
"," + (y2-curry[colindx]);
5136 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
5139 currx[colindx] = x1;
5140 curry[colindx] = y2;
5142 colPaths[colindx] +=
"v"+dy +
"h"+dx +
"v"+(-dy) +
"z";
5146 for (colindx=0;colindx<colPaths.length;++colindx)
5147 if (colPaths[colindx] !== undefined)
5150 .attr(
"palette-index", colindx)
5151 .attr(
"fill", this.fPalette.getColor(colindx))
5152 .attr(
"d", colPaths[colindx]);
5157 TH2Painter.prototype.BuildContour =
function(handle, levels, palette, contour_func) {
5158 var histo = this.GetObject(), ddd = 0,
5163 xarr =
new Float32Array(2*kMAXCONTOUR),
5164 yarr =
new Float32Array(2*kMAXCONTOUR),
5165 itarr =
new Int32Array(2*kMAXCONTOUR),
5166 lj = 0, ipoly, poly, polys = [], np, npmax = 0,
5167 x = [0.,0.,0.,0.], y = [0.,0.,0.,0.], zc = [0.,0.,0.,0.], ir = [0,0,0,0],
5168 i, j, k, n, m, ix, ljfill, count,
5169 xsave, ysave, itars, ix, jx;
5171 function BinarySearch(zc) {
5172 for (var kk=0;kk<levels.length;++kk)
5173 if (zc<levels[kk])
return kk-1;
5174 return levels.length-1;
5177 function PaintContourLine(elev1, icont1, x1, y1, elev2, icont2, x2, y2) {
5179 var vert = (x1 === x2),
5180 tlen = vert ? (y2 - y1) : (x2 - x1),
5182 tdif = elev2 - elev1,
5184 maxii = kMAXCONTOUR/2 -3 + lj,
5186 xlen, pdif, diff, elev;
5188 while (n <= icont2 && ii <= maxii) {
5191 diff = elev - elev1;
5196 yarr[ii] = y1 + xlen;
5198 xarr[ii] = x1 + xlen;
5209 var arrx = handle.original ? handle.origx : handle.grx,
5210 arry = handle.original ? handle.origy : handle.gry;
5212 for (j = handle.j1; j < handle.j2-1; ++j) {
5214 y[1] = y[0] = (arry[j] + arry[j+1])/2;
5215 y[3] = y[2] = (arry[j+1] + arry[j+2])/2;
5217 for (i = handle.i1; i < handle.i2-1; ++i) {
5219 zc[0] = histo.getBinContent(i+1, j+1);
5220 zc[1] = histo.getBinContent(i+2, j+1);
5221 zc[2] = histo.getBinContent(i+2, j+2);
5222 zc[3] = histo.getBinContent(i+1, j+2);
5225 ir[k] = BinarySearch(zc[k]);
5227 if ((ir[0] !== ir[1]) || (ir[1] !== ir[2]) || (ir[2] !== ir[3]) || (ir[3] !== ir[0])) {
5228 x[3] = x[0] = (arrx[i] + arrx[i+1])/2;
5229 x[2] = x[1] = (arrx[i+1] + arrx[i+2])/2;
5231 if (zc[0] <= zc[1]) n = 0;
else n = 1;
5232 if (zc[2] <= zc[3]) m = 2;
else m = 3;
5233 if (zc[n] > zc[m]) n = m;
5236 for (ix=1;ix<=4;ix++) {
5238 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],
5239 zc[m-1],ir[m-1],x[m-1],y[m-1]);
5244 if (zc[0] <= zc[1]) n = 0;
else n = 1;
5245 if (zc[2] <= zc[3]) m = 2;
else m = 3;
5246 if (zc[n] > zc[m]) n = m;
5249 for (ix=1;ix<=4;ix++) {
5252 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],
5253 zc[m-1],ir[m-1],x[m-1],y[m-1]);
5260 for (ix=1; ix<=lj-5; ix +=2) {
5262 while (itarr[ix-1] != itarr[ix]) {
5266 for (jx=ix; jx<=lj-5; jx +=2) {
5267 xarr[jx] = xarr[jx+2];
5268 yarr[jx] = yarr[jx+2];
5269 itarr[jx] = itarr[jx+2];
5273 itarr[lj-3] = itars;
5274 if (count > kMAXCOUNT)
break;
5279 if (count > kMAXCOUNT)
continue;
5281 for (ix=1; ix<=lj-2; ix +=2) {
5283 ipoly = itarr[ix-1];
5285 if ((ipoly >= 0) && (ipoly < levels.length)) {
5286 poly = polys[ipoly];
5288 poly = polys[ipoly] = JSROOT.CreateTPolyLine(kMAXCONTOUR*4,
true);
5290 np = poly.fLastPoint;
5291 if (np < poly.fN-2) {
5292 poly.fX[np+1] = Math.round(xarr[ix-1]); poly.fY[np+1] = Math.round(yarr[ix-1]);
5293 poly.fX[np+2] = Math.round(xarr[ix]); poly.fY[np+2] = Math.round(yarr[ix]);
5294 poly.fLastPoint = np+2;
5295 npmax = Math.max(npmax, poly.fLastPoint+1);
5305 var polysort =
new Int32Array(levels.length), first = 0;
5307 for (ipoly=0;ipoly<levels.length;ipoly++) {
5308 if (levels[ipoly] >= 0) { first = ipoly;
break; }
5312 for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;}
5313 for (ipoly=first;ipoly<levels.length;ipoly++) { polysort[k] = ipoly; k++;}
5315 var xp =
new Float32Array(2*npmax),
5316 yp =
new Float32Array(2*npmax);
5318 for (k=0;k<levels.length;++k) {
5320 ipoly = polysort[k];
5321 poly = polys[ipoly];
5322 if (!poly)
continue;
5324 var colindx = palette.calcColorIndex(ipoly, levels.length),
5325 xx = poly.fX, yy = poly.fY, np = poly.fLastPoint+1,
5326 istart = 0, iminus, iplus, xmin = 0, ymin = 0, nadd;
5332 xp[iminus]= xx[istart]; yp[iminus] = yy[istart];
5333 xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1];
5334 xx[istart] = xx[istart+1] = xmin;
5335 yy[istart] = yy[istart+1] = ymin;
5338 for (i=2;i<np;i+=2) {
5339 if ((iplus < 2*npmax-1) && (xx[i] === xp[iplus]) && (yy[i] === yp[iplus])) {
5341 xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1];
5342 xx[i] = xx[i+1] = xmin;
5343 yy[i] = yy[i+1] = ymin;
5346 if ((iminus > 0) && (xx[i+1] === xp[iminus]) && (yy[i+1] === yp[iminus])) {
5348 xp[iminus] = xx[i]; yp[iminus] = yy[i];
5349 xx[i] = xx[i+1] = xmin;
5350 yy[i] = yy[i+1] = ymin;
5354 if (nadd == 0)
break;
5357 if ((iminus+1 < iplus) && (iminus>=0))
5358 contour_func(colindx, xp, yp, iminus, iplus, ipoly);
5361 for (i=2;i<np;i+=2) {
5362 if (xx[i] !== xmin && yy[i] !== ymin) {
5368 if (istart === 0)
break;
5373 TH2Painter.prototype.DrawBinsContour =
function(frame_w,frame_h) {
5374 var handle = this.PrepareColorDraw({ rounding:
false, extra: 100, original: this.options.Proj != 0 });
5377 var levels = this.GetContour(),
5378 palette = this.GetPalette(),
5379 painter =
this, main = this.frame_painter();
5381 function BuildPath(xp,yp,iminus,iplus) {
5382 var cmd =
"", last = null, pnt = null, i;
5383 for (i=iminus;i<=iplus;++i) {
5385 switch (main.projection) {
5386 case 1: pnt = main.ProjectAitoff2xy(xp[i], yp[i]);
break;
5387 case 2: pnt = main.ProjectMercator2xy(xp[i], yp[i]);
break;
5388 case 3: pnt = main.ProjectSinusoidal2xy(xp[i], yp[i]);
break;
5389 case 4: pnt = main.ProjectParabolic2xy(xp[i], yp[i]);
break;
5392 pnt.x = main.grx(pnt.x);
5393 pnt.y = main.gry(pnt.y);
5395 pnt = { x: xp[i], y: yp[i] };
5397 pnt.x = Math.round(pnt.x);
5398 pnt.y = Math.round(pnt.y);
5399 if (!cmd) cmd =
"M" + pnt.x +
"," + pnt.y;
5400 else if ((pnt.x != last.x) && (pnt.y != last.y)) cmd +=
"l" + (pnt.x - last.x) +
"," + (pnt.y - last.y);
5401 else if (pnt.x != last.x) cmd +=
"h" + (pnt.x - last.x);
5402 else if (pnt.y != last.y) cmd +=
"v" + (pnt.y - last.y);
5408 if (this.options.Contour===14) {
5409 var dd =
"M0,0h"+frame_w+
"v"+frame_h+
"h-"+frame_w;
5410 if (this.options.Proj) {
5411 var sz = handle.j2 - handle.j1, xd =
new Float32Array(sz*2), yd =
new Float32Array(sz*2);
5412 for (var i=0;i<sz;++i) {
5413 xd[i] = handle.origx[handle.i1];
5414 yd[i] = (handle.origy[handle.j1]*(i+0.5) + handle.origy[handle.j2]*(sz-0.5-i))/sz;
5415 xd[i+sz] = handle.origx[handle.i2];
5416 yd[i+sz] = (handle.origy[handle.j2]*(i+0.5) + handle.origy[handle.j1]*(sz-0.5-i))/sz;
5418 dd = BuildPath(xd,yd,0,2*sz-1);
5423 .attr(
"d", dd +
"z")
5424 .style(
'stroke',
'none')
5425 .style(
"fill", palette.calcColor(0, levels.length));
5428 this.BuildContour(handle, levels, palette,
5429 function(colindx,xp,yp,iminus,iplus) {
5430 var icol = palette.getColor(colindx),
5431 fillcolor = icol, lineatt = null;
5433 switch (painter.options.Contour) {
5435 case 11: fillcolor =
'none'; lineatt =
new JSROOT.TAttLineHandler({ color: icol } );
break;
5436 case 12: fillcolor =
'none'; lineatt =
new JSROOT.TAttLineHandler({ color: 1, style: (colindx%5 + 1), width: 1 });
break;
5437 case 13: fillcolor =
'none'; lineatt = painter.lineatt;
break;
5441 var elem = painter.draw_g
5443 .attr(
"class",
"th2_contour")
5444 .attr(
"d", BuildPath(xp,yp,iminus,iplus) + (fillcolor ==
'none' ?
"" :
"z"))
5445 .style(
"fill", fillcolor);
5448 elem.call(lineatt.func);
5450 elem.style(
'stroke',
'none');
5454 handle.hide_only_zeros =
true;
5459 TH2Painter.prototype.CreatePolyBin =
function(pmain, bin, text_pos) {
5460 var cmd =
"", ngr, ngraphs = 1, gr = null;
5462 if (bin.fPoly._typename==
'TMultiGraph')
5463 ngraphs = bin.fPoly.fGraphs.arr.length;
5468 bin._sumx = bin._sumy = bin._suml = 0;
5470 function AddPoint(x1,y1,x2,y2) {
5471 var len = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
5472 bin._sumx += (x1+x2)*len/2;
5473 bin._sumy += (y1+y2)*len/2;
5477 for (ngr = 0; ngr < ngraphs; ++ ngr) {
5478 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
5480 var npnts = gr.fNpoints, n,
5481 x = gr.fX, y = gr.fY,
5482 grx = Math.round(pmain.grx(x[0])),
5483 gry = Math.round(pmain.gry(y[0])),
5486 if ((npnts>2) && (x[0]==x[npnts-1]) && (y[0]==y[npnts-1])) npnts--;
5488 cmd +=
"M"+grx+
","+gry;
5490 for (n=1;n<npnts;++n) {
5491 nextx = Math.round(pmain.grx(x[n]));
5492 nexty = Math.round(pmain.gry(y[n]));
5493 if (text_pos) AddPoint(grx,gry, nextx, nexty);
5494 if ((grx!==nextx) || (gry!==nexty)) {
5495 if (grx===nextx) cmd +=
"v" + (nexty - gry);
else
5496 if (gry===nexty) cmd +=
"h" + (nextx - grx);
else
5497 cmd +=
"l" + (nextx - grx) +
"," + (nexty - gry);
5499 grx = nextx; gry = nexty;
5502 if (text_pos) AddPoint(grx, gry, Math.round(pmain.grx(x[0])), Math.round(pmain.gry(y[0])));
5507 if (bin._suml > 0) {
5508 bin._midx = Math.round(bin._sumx / bin._suml);
5509 bin._midy = Math.round(bin._sumy / bin._suml);
5511 bin._midx = Math.round(pmain.grx((bin.fXmin + bin.fXmax)/2));
5512 bin._midy = Math.round(pmain.gry((bin.fYmin + bin.fYmax)/2));
5519 TH2Painter.prototype.DrawPolyBinsColor =
function(w,h) {
5520 var histo = this.GetObject(),
5521 pmain = this.frame_painter(),
5522 colPaths = [], textbins = [],
5523 colindx, cmd, bin, item,
5524 i, len = histo.fBins.arr.length;
5527 this.fContour = null;
5528 this.fCustomContour =
false;
5531 this.maxbin = this.gmaxbin;
5532 this.minbin = this.gminbin;
5533 this.minposbin = this.gminposbin;
5535 for (i = 0; i < len; ++ i) {
5536 bin = histo.fBins.arr[i];
5537 colindx = this.getContourColor(bin.fContent,
true);
5538 if (colindx === null)
continue;
5539 if (bin.fContent === 0) {
5540 if (!this.options.Zero || !
this.options.Line)
continue;
5545 if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) ||
5546 (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin))
continue;
5548 cmd = this.CreatePolyBin(pmain, bin, this.options.Text && bin.fContent);
5550 if (colPaths[colindx] === undefined)
5551 colPaths[colindx] = cmd;
5553 colPaths[colindx] += cmd;
5555 if (this.options.Text && bin.fContent) textbins.push(bin);
5558 for (colindx=0;colindx<colPaths.length;++colindx)
5559 if (colPaths[colindx]) {
5562 .attr(
"palette-index", colindx)
5563 .attr(
"fill", colindx ? this.fPalette.getColor(colindx) :
'none')
5564 .attr(
"d", colPaths[colindx]);
5565 if (this.options.Line)
5566 item.call(this.lineatt.func);
5569 if (textbins.length > 0) {
5570 var text_col = this.get_color(histo.fMarkerColor),
5571 text_angle = -1*this.options.TextAngle,
5572 text_g = this.draw_g.append(
"svg:g").attr(
"class",
"th2poly_text"),
5575 if ((histo.fMarkerSize!==1) && text_angle)
5576 text_size = Math.round(0.02*h*histo.fMarkerSize);
5578 this.StartTextDrawing(42, text_size, text_g, text_size);
5580 for (i = 0; i < textbins.length; ++ i) {
5585 if (!this.options.TextKind) {
5586 lbl = (Math.round(bin.fContent) === bin.fContent) ? bin.fContent.toString() :
5587 JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fPaintTextFormat);
5589 if (bin.fPoly) lbl = bin.fPoly.fName;
5590 if (lbl ===
"Graph") lbl =
"";
5591 if (!lbl) lbl = bin.fNumber;
5594 this.DrawText({ align: 22, x: bin._midx, y: bin._midy, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g });
5597 this.FinishTextDrawing(text_g, null);
5600 return { poly:
true };
5603 TH2Painter.prototype.DrawBinsText =
function(w, h, handle) {
5604 var histo = this.GetObject(),
5605 i,j,binz,errz,colindx,binw,binh,lbl,lble,posx,posy,sizex,sizey,
5606 text_col = this.get_color(histo.fMarkerColor),
5607 text_angle = -1*this.options.TextAngle,
5608 text_g = this.draw_g.append(
"svg:g").attr(
"class",
"th2_text"),
5609 text_size = 20, text_offset = 0,
5610 profile2d = this.MatchObjectType(
'TProfile2D') && (typeof histo.getBinEntries==
'function'),
5611 show_err = (this.options.TextKind ==
"E"),
5612 use_latex = (show_err && !this.options.TextLine) ? 1 : 0;
5614 if (handle===null) handle = this.PrepareColorDraw({ rounding:
false });
5616 if ((histo.fMarkerSize!==1) && text_angle)
5617 text_size = Math.round(0.02*h*histo.fMarkerSize);
5619 if (histo.fBarOffset!==0) text_offset = histo.fBarOffset*1e-3;
5621 this.StartTextDrawing(42, text_size, text_g, text_size);
5623 for (i = handle.i1; i < handle.i2; ++i)
5624 for (j = handle.j1; j < handle.j2; ++j) {
5625 binz = histo.getBinContent(i+1, j+1);
5626 if ((binz === 0) && !this._show_empty_bins)
continue;
5628 binw = handle.grx[i+1] - handle.grx[i];
5629 binh = handle.gry[j] - handle.gry[j+1];
5632 binz = histo.getBinEntries(i+1, j+1);
5634 lbl = (binz === Math.round(binz)) ? binz.toString() :
5635 JSROOT.FFormat(binz, JSROOT.gStyle.fPaintTextFormat);
5638 errz = histo.getBinError(histo.getBin(i+1,j+1));
5639 lble = (errz === Math.round(errz)) ? errz.toString() :
5640 JSROOT.FFormat(errz, JSROOT.gStyle.fPaintTextFormat);
5641 if (this.options.TextLine)
5642 lbl +=
'\xB1' + lble;
5644 lbl =
"#splitline{" + lbl +
"}{#pm" + lble +
"}";
5648 posx = Math.round(handle.grx[i] + binw*0.5);
5649 posy = Math.round(handle.gry[j+1] + binh*(0.5 + text_offset));
5653 posx = Math.round(handle.grx[i] + binw*0.1);
5654 posy = Math.round(handle.gry[j+1] + binh*(0.1 + text_offset));
5655 sizex = Math.round(binw*0.8);
5656 sizey = Math.round(binh*0.8);
5659 this.DrawText({ align: 22, x: posx, y: posy, width: sizex, height: sizey, rotate: text_angle, text: lbl, color: text_col, latex: use_latex, draw_g: text_g });
5662 this.FinishTextDrawing(text_g, null);
5664 handle.hide_only_zeros =
true;
5669 TH2Painter.prototype.DrawBinsArrow =
function(w, h) {
5670 var histo = this.GetObject(), cmd =
"",
5671 i,j,binz,colindx,binw,binh,lbl, loop, dn = 1e-30, dx, dy, xc,yc,
5672 dxn,dyn,x1,x2,y1,y2, anr,si,co,
5673 handle = this.PrepareColorDraw({ rounding:
false }),
5674 scale_x = (handle.grx[handle.i2] - handle.grx[handle.i1])/(handle.i2 - handle.i1 + 1-0.03)/2,
5675 scale_y = (handle.gry[handle.j2] - handle.gry[handle.j1])/(handle.j2 - handle.j1 + 1-0.03)/2;
5677 for (var loop=0;loop<2;++loop)
5678 for (i = handle.i1; i < handle.i2; ++i)
5679 for (j = handle.j1; j < handle.j2; ++j) {
5681 if (i === handle.i1) {
5682 dx = histo.getBinContent(i+2, j+1) - histo.getBinContent(i+1, j+1);
5683 }
else if (i === handle.i2-1) {
5684 dx = histo.getBinContent(i+1, j+1) - histo.getBinContent(i, j+1);
5686 dx = 0.5*(histo.getBinContent(i+2, j+1) - histo.getBinContent(i, j+1));
5688 if (j === handle.j1) {
5689 dy = histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j+1);
5690 }
else if (j === handle.j2-1) {
5691 dy = histo.getBinContent(i+1, j+1) - histo.getBinContent(i+1, j);
5693 dy = 0.5*(histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j));
5697 dn = Math.max(dn, Math.abs(dx), Math.abs(dy));
5699 xc = (handle.grx[i] + handle.grx[i+1])/2;
5700 yc = (handle.gry[j] + handle.gry[j+1])/2;
5701 dxn = scale_x*dx/dn;
5702 dyn = scale_y*dy/dn;
5707 dx = Math.round(x2-x1);
5708 dy = Math.round(y2-y1);
5710 if ((dx!==0) || (dy!==0)) {
5711 cmd +=
"M"+Math.round(x1)+
","+Math.round(y1)+
"l"+dx+
","+dy;
5713 if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
5714 anr = Math.sqrt(2/(dx*dx + dy*dy));
5715 si = Math.round(anr*(dx + dy));
5716 co = Math.round(anr*(dx - dy));
5717 if ((si!==0) && (co!==0))
5718 cmd+=
"l"+(-si)+
","+co +
"m"+si+
","+(-co) +
"l"+(-co)+
","+(-si);
5726 .attr(
"class",
"th2_arrows")
5728 .style(
"fill",
"none")
5729 .call(this.lineatt.func);
5735 TH2Painter.prototype.DrawBinsBox =
function(w,h) {
5737 var histo = this.GetObject(),
5738 handle = this.PrepareColorDraw({ rounding:
false }),
5739 main = this.main_painter();
5742 if (main.maxbin === main.minbin) {
5743 main.maxbin = main.gmaxbin;
5744 main.minbin = main.gminbin;
5745 main.minposbin = main.gminposbin;
5747 if (main.maxbin === main.minbin)
5748 main.minbin = Math.min(0, main.maxbin-1);
5751 var absmax = Math.max(Math.abs(main.maxbin), Math.abs(main.minbin)),
5752 absmin = Math.max(0, main.minbin),
5753 i, j, binz, absz, res =
"", cross =
"", btn1 =
"", btn2 =
"",
5754 colindx, zdiff, dgrx, dgry, xx, yy, ww, hh, cmd1, cmd2,
5755 xyfactor = 1, uselogz =
false, logmin = 0, logmax = 1;
5757 if (this.root_pad().fLogz && (absmax>0)) {
5759 logmax = Math.log(absmax);
5760 if (absmin>0) logmin = Math.log(absmin);
else
5761 if ((main.minposbin>=1) && (main.minposbin<100)) logmin = Math.log(0.7);
else
5762 logmin = (main.minposbin > 0) ? Math.log(0.7*main.minposbin) : logmax - 10;
5763 if (logmin >= logmax) logmin = logmax - 10;
5764 xyfactor = 1. / (logmax - logmin);
5766 xyfactor = 1. / (absmax - absmin);
5770 for (i = handle.i1; i < handle.i2; ++i) {
5771 for (j = handle.j1; j < handle.j2; ++j) {
5772 binz = histo.getBinContent(i + 1, j + 1);
5773 absz = Math.abs(binz);
5774 if ((absz === 0) || (absz < absmin))
continue;
5776 zdiff = uselogz ? ((absz>0) ? Math.log(absz) - logmin : 0) : (absz - absmin);
5778 zdiff = 0.5 * ((zdiff < 0) ? 1 : (1 - Math.sqrt(zdiff * xyfactor)));
5780 if (zdiff < 0) zdiff = 0;
5782 ww = handle.grx[i+1] - handle.grx[i];
5783 hh = handle.gry[j] - handle.gry[j+1];
5788 xx = Math.round(handle.grx[i] + dgrx);
5789 yy = Math.round(handle.gry[j+1] + dgry);
5791 ww = Math.max(Math.round(ww - 2*dgrx), 1);
5792 hh = Math.max(Math.round(hh - 2*dgry), 1);
5794 res +=
"M"+xx+
","+yy +
"v"+hh +
"h"+ww +
"v-"+hh +
"z";
5796 if ((binz<0) && (this.options.BoxStyle === 10))
5797 cross +=
"M"+xx+
","+yy +
"l"+ww+
","+hh +
"M"+(xx+ww)+
","+yy +
"l-"+ww+
","+hh;
5799 if ((this.options.BoxStyle === 11) && (ww>5) && (hh>5)) {
5800 var pww = Math.round(ww*0.1),
5801 phh = Math.round(hh*0.1),
5802 side1 =
"M"+xx+
","+yy +
"h"+ww +
"l"+(-pww)+
","+phh +
"h"+(2*pww-ww) +
5803 "v"+(hh-2*phh)+
"l"+(-pww)+
","+phh +
"z",
5804 side2 =
"M"+(xx+ww)+
","+(yy+hh) +
"v"+(-hh) +
"l"+(-pww)+
","+phh +
"v"+(hh-2*phh)+
5805 "h"+(2*pww-ww) +
"l"+(-pww)+
","+phh +
"z";
5806 if (binz<0) { btn2+=side1; btn1+=side2; }
5807 else { btn1+=side1; btn2+=side2; }
5812 if (res.length > 0) {
5813 var elem = this.draw_g.append(
"svg:path")
5815 .call(this.fillatt.func);
5816 if ((this.options.BoxStyle === 11) || !
this.fillatt.empty())
5817 elem.style(
'stroke',
'none');
5819 elem.call(this.lineatt.func);
5822 if ((btn1.length>0) && (
this.fillatt.color !==
'none'))
5823 this.draw_g.append(
"svg:path")
5825 .style(
"stroke",
"none")
5826 .call(this.fillatt.func)
5827 .style(
"fill", d3.rgb(
this.fillatt.color).brighter(0.5).toString());
5830 this.draw_g.append(
"svg:path")
5832 .style(
"stroke",
"none")
5833 .call(this.fillatt.func)
5834 .style(
"fill", this.fillatt.color ===
'none' ?
'red' : d3.rgb(
this.fillatt.color).darker(0.5).toString());
5836 if (cross.length > 0) {
5837 var elem = this.draw_g.append(
"svg:path")
5839 .style(
"fill",
"none");
5840 if (this.lineatt.color !==
'none')
5841 elem.call(this.lineatt.func);
5843 elem.style(
'stroke',
'black');
5849 TH2Painter.prototype.DrawCandle =
function(w,h) {
5850 var histo = this.GetHisto(),
5851 handle = this.PrepareColorDraw(),
5852 pmain = this.frame_painter(),
5853 i, j, y, sum0, sum1, sum2, cont, center, counter, integral, w, pnt,
5854 bars =
"", markers =
"", posy;
5856 if (histo.fMarkerColor === 1) histo.fMarkerColor = histo.fLineColor;
5859 this.createAttMarker({ attr: histo, style: 5 });
5862 this.markeratt.reset_pos();
5867 for (i = handle.i1; i < handle.i2; ++i) {
5872 for (j = 0; j < this.nbinsy; ++j) {
5873 integral += histo.getBinContent(i+1,j+1);
5875 pnt = { bin:i, meany:0, m25y:0, p25y:0, median:0, iqr:0, whiskerp:0, whiskerm:0};
5877 for (j = 0; j < this.nbinsy; ++j) {
5878 cont = histo.getBinContent(i+1,j+1);
5879 posy = histo.fYaxis.GetBinCenter(j+1);
5880 if (counter/integral < 0.001 && (counter + cont)/integral >=0.001) pnt.whiskerm = posy;
5881 if (counter/integral < 0.25 && (counter + cont)/integral >=0.25) pnt.m25y = posy;
5882 if (counter/integral < 0.5 && (counter + cont)/integral >=0.5) pnt.median = posy;
5883 if (counter/integral < 0.75 && (counter + cont)/integral >=0.75) pnt.p25y = posy;
5884 if (counter/integral < 0.999 && (counter + cont)/integral >=0.999) pnt.whiskerp = posy;
5890 pnt.meany = sum1/counter;
5892 pnt.iqr = pnt.p25y-pnt.m25y;
5895 if ((pnt.m25y-1.5*pnt.iqr) > pnt.whsikerm) {
5896 pnt.whiskerm = pnt.m25y-1.5*pnt.iqr;
5898 if ((pnt.p25y+1.5*pnt.iqr) < pnt.whiskerp) {
5899 pnt.whiskerp = pnt.p25y+1.5*pnt.iqr;
5903 if (pmain.logy && (pnt.whiskerm<=0))
continue;
5905 w = handle.grx[i+1] - handle.grx[i];
5907 center = (handle.grx[i+1] + handle.grx[i]) / 2 + histo.fBarOffset/1000*w;
5908 if (histo.fBarWidth>0) w = w * histo.fBarWidth / 1000;
5910 pnt.x1 = Math.round(center - w/2);
5911 pnt.x2 = Math.round(center + w/2);
5912 center = Math.round(center);
5914 pnt.y0 = Math.round(pmain.gry(pnt.median));
5916 bars +=
"M" + pnt.x1 +
"," + pnt.y0 +
"h" + (pnt.x2-pnt.x1);
5918 pnt.y1 = Math.round(pmain.gry(pnt.p25y));
5919 pnt.y2 = Math.round(pmain.gry(pnt.m25y));
5922 bars +=
"M" + pnt.x1 +
"," + pnt.y1 +
5923 "v" + (pnt.y2-pnt.y1) +
"h" + (pnt.x2-pnt.x1) +
"v-" + (pnt.y2-pnt.y1) +
"z";
5925 pnt.yy1 = Math.round(pmain.gry(pnt.whiskerp));
5926 pnt.yy2 = Math.round(pmain.gry(pnt.whiskerm));
5929 bars +=
"M" + center +
"," + pnt.y1 +
"v" + (pnt.yy1-pnt.y1);
5930 bars +=
"M" + pnt.x1 +
"," + pnt.yy1 +
"h" + (pnt.x2-pnt.x1);
5933 bars +=
"M" + center +
"," + pnt.y2 +
"v" + (pnt.yy2-pnt.y2);
5934 bars +=
"M" + pnt.x1 +
"," + pnt.yy2 +
"h" + (pnt.x2-pnt.x1);
5937 for (j = 0; j < this.nbinsy; ++j) {
5938 cont = histo.getBinContent(i+1,j+1);
5939 posy = histo.fYaxis.GetBinCenter(j+1);
5940 if (cont > 0 && posy < pnt.whiskerm) markers += this.markeratt.create(center, posy);
5941 if (cont > 0 && posy > pnt.whiskerp) markers += this.markeratt.create(center, posy);
5944 handle.candle.push(pnt);
5947 if (bars.length > 0)
5948 this.draw_g.append(
"svg:path")
5950 .call(this.lineatt.func)
5951 .call(this.fillatt.func);
5953 if (markers.length > 0)
5954 this.draw_g.append(
"svg:path")
5956 .call(this.markeratt.func);
5961 TH2Painter.prototype.DrawBinsScatter =
function(w,h) {
5962 var histo = this.GetObject(),
5963 handle = this.PrepareColorDraw({ rounding:
true, pixel_density:
true }),
5964 colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [],
5965 colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1.,
5966 scale = this.options.ScatCoef * ((
this.gmaxbin) > 2000 ? 2000. /
this.gmaxbin : 1.);
5968 JSROOT.seed(handle.sumz);
5970 if (scale*handle.sumz < 1e5) {
5973 this.createAttMarker({ attr: histo });
5975 this.markeratt.reset_pos();
5977 var path =
"", k, npix;
5978 for (i = handle.i1; i < handle.i2; ++i) {
5979 cw = handle.grx[i+1] - handle.grx[i];
5980 for (j = handle.j1; j < handle.j2; ++j) {
5981 ch = handle.gry[j] - handle.gry[j+1];
5982 binz = histo.getBinContent(i + 1, j + 1);
5984 npix = Math.round(scale*binz);
5985 if (npix<=0)
continue;
5987 for (k=0;k<npix;++k)
5988 path += this.markeratt.create(
5989 Math.round(handle.grx[i] + cw * JSROOT.random()),
5990 Math.round(handle.gry[j+1] + ch * JSROOT.random()));
5997 .call(this.markeratt.func);
6003 if (this.maxbin > 0.7) factor = 0.7/this.maxbin;
6005 var nlevels = Math.round(handle.max - handle.min);
6006 this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin);
6009 for (i = handle.i1; i < handle.i2; ++i) {
6010 for (j = handle.j1; j < handle.j2; ++j) {
6011 binz = histo.getBinContent(i + 1, j + 1);
6012 if ((binz <= 0) || (binz < this.minbin))
continue;
6014 cw = handle.grx[i+1] - handle.grx[i];
6015 ch = handle.gry[j] - handle.gry[j+1];
6016 if (cw*ch <= 0)
continue;
6018 colindx = this.getContourIndex(binz/cw/ch);
6019 if (colindx < 0)
continue;
6021 cmd1 =
"M"+handle.grx[i]+
","+handle.gry[j+1];
6022 if (colPaths[colindx] === undefined) {
6023 colPaths[colindx] = cmd1;
6024 cell_w[colindx] = cw;
6025 cell_h[colindx] = ch;
6027 cmd2 =
"m" + (handle.grx[i]-currx[colindx]) +
"," + (handle.gry[j+1] - curry[colindx]);
6028 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
6029 cell_w[colindx] = Math.max(cell_w[colindx], cw);
6030 cell_h[colindx] = Math.max(cell_h[colindx], ch);
6033 currx[colindx] = handle.grx[i];
6034 curry[colindx] = handle.gry[j+1];
6036 colPaths[colindx] +=
"v"+ch+
"h"+cw+
"v-"+ch+
"z";
6040 var layer = this.svg_frame().select(
'.main_layer'),
6041 defs = layer.select(
"defs");
6042 if (defs.empty() && (colPaths.length>0))
6043 defs = layer.insert(
"svg:defs",
":first-child");
6045 this.createAttMarker({ attr: histo });
6047 for (colindx=0;colindx<colPaths.length;++colindx)
6048 if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) {
6049 var pattern_class =
"scatter_" + colindx,
6050 pattern = defs.select(
'.' + pattern_class);
6051 if (pattern.empty())
6052 pattern = defs.append(
'svg:pattern')
6053 .attr(
"class", pattern_class)
6054 .attr(
"id",
"jsroot_scatter_pattern_" + JSROOT.id_counter++)
6055 .attr(
"patternUnits",
"userSpaceOnUse");
6057 pattern.selectAll(
"*").remove();
6059 var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]);
6060 if (npix<1) npix = 1;
6062 var arrx =
new Float32Array(npix), arry =
new Float32Array(npix);
6065 arrx[0] = arry[0] = 0.5;
6067 for (var n=0;n<npix;++n) {
6068 arrx[n] = JSROOT.random();
6069 arry[n] = JSROOT.random();
6075 this.markeratt.reset_pos();
6079 for (var n=0;n<npix;++n)
6080 path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]);
6082 pattern.attr(
"width", cell_w[colindx])
6083 .attr(
"height", cell_h[colindx])
6086 .call(this.markeratt.func);
6090 .attr(
"scatter-index", colindx)
6091 .attr(
"fill",
'url(#' + pattern.attr(
"id") +
')')
6092 .attr(
"d", colPaths[colindx]);
6098 TH2Painter.prototype.DrawBins =
function() {
6100 if (!this.draw_content)
6101 return this.RemoveDrawG();
6103 this.CheckHistDrawAttributes();
6107 var w = this.frame_width(),
6108 h = this.frame_height(),
6111 if (this.IsTH2Poly()) {
6112 handle = this.DrawPolyBinsColor(w, h);
6114 if (this.options.Scat)
6115 handle = this.DrawBinsScatter(w, h);
6116 else if (this.options.Color)
6117 handle = this.DrawBinsColor(w, h);
6118 else if (this.options.Box)
6119 handle = this.DrawBinsBox(w, h);
6120 else if (this.options.Arrow)
6121 handle = this.DrawBinsArrow(w, h);
6122 else if (this.options.Contour)
6123 handle = this.DrawBinsContour(w, h);
6124 else if (this.options.Candle)
6125 handle = this.DrawCandle(w, h);
6127 if (this.options.Text)
6128 handle = this.DrawBinsText(w, h, handle);
6131 handle = this.DrawBinsScatter(w, h);
6134 this.tt_handle = handle;
6138 TH2Painter.prototype.GetBinTips =
function (i, j) {
6139 var lines = [], pmain = this.frame_painter(),
6140 histo = this.GetHisto(),
6141 binz = histo.getBinContent(i+1,j+1)
6143 lines.push(this.GetTipName());
6145 if (pmain.x_kind ==
'labels')
6146 lines.push(
"x = " + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(i+1)));
6148 lines.push(
"x = [" + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(i+1)) +
", " + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(i+2)) +
")");
6150 if (pmain.y_kind ==
'labels')
6151 lines.push(
"y = " + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(j+1)));
6153 lines.push(
"y = [" + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(j+1)) +
", " + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(j+2)) +
")");
6155 lines.push(
"bin = " + i +
", " + j);
6157 if (histo.$baseh) binz -= histo.$baseh.getBinContent(i+1,j+1);
6159 lines.push(
"entries = " + ((binz === Math.round(binz)) ? binz : JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat)));
6161 if ((this.options.TextKind ==
"E") || this.MatchObjectType(
'TProfile2D')) {
6162 var errz = histo.getBinError(histo.getBin(i+1,j+1));
6163 lines.push(
"error = " + ((errz === Math.round(errz)) ? errz.toString() : JSROOT.FFormat(errz, JSROOT.gStyle.fPaintTextFormat)));
6169 TH2Painter.prototype.GetCandleTips =
function(p) {
6170 var lines = [], main = this.frame_painter(), histo = this.GetHisto();
6172 lines.push(this.GetTipName());
6174 lines.push(
"x = " + main.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(p.bin+1)));
6176 lines.push(
'mean y = ' + JSROOT.FFormat(p.meany, JSROOT.gStyle.fStatFormat))
6177 lines.push(
'm25 = ' + JSROOT.FFormat(p.m25y, JSROOT.gStyle.fStatFormat))
6178 lines.push(
'p25 = ' + JSROOT.FFormat(p.p25y, JSROOT.gStyle.fStatFormat))
6183 TH2Painter.prototype.ProvidePolyBinHints =
function(binindx, realx, realy) {
6185 var histo = this.GetHisto(),
6186 bin = histo.fBins.arr[binindx],
6187 pmain = this.frame_painter(),
6188 binname = bin.fPoly.fName,
6189 lines = [], numpoints = 0;
6191 if (binname ===
"Graph") binname =
"";
6192 if (binname.length === 0) binname = bin.fNumber;
6194 if ((realx===undefined) && (realy===undefined)) {
6196 var gr = bin.fPoly, numgraphs = 1;
6197 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
6199 for (var ngr=0;ngr<numgraphs;++ngr) {
6200 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
6202 for (var n=0;n<gr.fNpoints;++n) {
6209 if (numpoints > 1) {
6210 realx = realx / numpoints;
6211 realy = realy / numpoints;
6215 lines.push(this.GetTipName());
6216 lines.push(
"x = " + pmain.AxisAsText(
"x", realx));
6217 lines.push(
"y = " + pmain.AxisAsText(
"y", realy));
6218 if (numpoints > 0) lines.push(
"npnts = " + numpoints);
6219 lines.push(
"bin = " + binname);
6220 if (bin.fContent === Math.round(bin.fContent))
6221 lines.push(
"content = " + bin.fContent);
6223 lines.push(
"content = " + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fStatFormat));
6227 TH2Painter.prototype.ProcessTooltip =
function(pnt) {
6228 if (!pnt || !this.draw_content || !this.draw_g || !this.tt_handle || this.options.Proj) {
6229 if (this.draw_g !== null)
6230 this.draw_g.select(
".tooltip_bin").remove();
6234 var histo = this.GetHisto(),
6236 ttrect = this.draw_g.select(
".tooltip_bin");
6241 var pmain = this.frame_painter(),
6242 realx, realy, foundindx = -1;
6244 if (pmain.grx === pmain.x) realx = pmain.x.invert(pnt.x);
6245 if (pmain.gry === pmain.y) realy = pmain.y.invert(pnt.y);
6247 if ((realx!==undefined) && (realy!==undefined)) {
6248 var i, len = histo.fBins.arr.length, bin;
6250 for (i = 0; (i < len) && (foundindx < 0); ++ i) {
6251 bin = histo.fBins.arr[i];
6254 if ((realx < bin.fXmin) || (realx > bin.fXmax) ||
6255 (realy < bin.fYmin) || (realy > bin.fYmax))
continue;
6258 if ((bin.fContent === 0) && !this.options.Zero)
continue;
6260 var gr = bin.fPoly, numgraphs = 1;
6261 if (gr._typename ===
'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; }
6263 for (var ngr=0;ngr<numgraphs;++ngr) {
6264 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
6265 if (gr.IsInside(realx,realy)) {
6273 if (foundindx < 0) {
6278 var res = { name: histo.fName, title: histo.fTitle,
6280 color1: this.lineatt ? this.lineatt.color :
'green',
6281 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
"blue",
6282 exact:
true, menu:
true,
6283 lines: this.ProvidePolyBinHints(foundindx, realx, realy) };
6291 ttrect = this.draw_g.append(
"svg:path")
6292 .attr(
"class",
"tooltip_bin h1bin")
6293 .style(
"pointer-events",
"none");
6295 res.changed = ttrect.property(
"current_bin") !== foundindx;
6298 ttrect.attr(
"d", this.CreatePolyBin(pmain, bin))
6299 .style(
"opacity",
"0.7")
6300 .property(
"current_bin", foundindx);
6304 res.user_info = { obj: histo, name: histo.fName,
6307 grx: pnt.x, gry: pnt.y };
6311 }
else if (h.candle) {
6316 for (i=0;i<h.candle.length;++i) {
6318 if ((p.x1 <= pnt.x) && (pnt.x <= p.x2) && (p.yy1 <= pnt.y) && (pnt.y <= p.yy2))
break;
6321 if (i>=h.candle.length) {
6326 var res = { name: histo.fName, title: histo.fTitle,
6328 color1: this.lineatt ? this.lineatt.color :
'green',
6329 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
"blue",
6330 lines: this.GetCandleTips(p), exact:
true, menu:
true };
6338 ttrect = this.draw_g.append(
"svg:rect")
6339 .attr(
"class",
"tooltip_bin h1bin")
6340 .style(
"pointer-events",
"none");
6342 res.changed = ttrect.property(
"current_bin") !== i;
6345 ttrect.attr(
"x", p.x1)
6346 .attr(
"width", p.x2-p.x1)
6348 .attr(
"height", p.yy2- p.yy1)
6349 .style(
"opacity",
"0.7")
6350 .property(
"current_bin", i);
6354 res.user_info = { obj: histo, name: histo.fName,
6355 bin: i+1, cont: p.median, binx: i+1, biny: 1,
6356 grx: pnt.x, gry: pnt.y };
6361 var i, j, binz = 0, colindx = null,
6362 i1, i2, j1, j2, x1, x2, y1, y2;
6365 for (i = h.i1; i < h.i2; ++i)
6366 if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1]))
break;
6368 for (j = h.j1; j < h.j2; ++j)
6369 if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j]))
break;
6371 if ((i < h.i2) && (j < h.j2)) {
6373 i1 = i; i2 = i+1; j1 = j; j2 = j+1;
6374 x1 = h.grx[i1]; x2 = h.grx[i2];
6375 y1 = h.gry[j2]; y2 = h.gry[j1];
6379 if (this.options.Color) {
6381 var dx = x2 - x1, dy = y2 - y1;
6382 x2 = Math.round(x1 + dx*h.xbar2);
6383 x1 = Math.round(x1 + dx*h.xbar1);
6384 y2 = Math.round(y1 + dy*h.ybar2);
6385 y1 = Math.round(y1 + dy*h.ybar1);
6386 if ((pnt.x<x1) || (pnt.x>=x2) || (pnt.y<y1) || (pnt.y>=y2)) match =
false;
6389 binz = histo.getBinContent(i+1,j+1);
6390 if (this.is_projection) {
6392 }
else if (!match) {
6394 }
else if (h.hide_only_zeros) {
6395 colindx = (binz === 0) && !this._show_empty_bins ? null : 0;
6397 colindx = this.getContourColor(binz,
true);
6398 if ((colindx === null) && (binz === 0) && this._show_empty_bins) colindx = 0;
6402 if (colindx === null) {
6407 var res = { name: histo.fName, title: histo.fTitle,
6409 color1: this.lineatt ? this.lineatt.color :
'green',
6410 color2: this.fillatt ? this.fillatt.fillcoloralt(
'blue') :
"blue",
6411 lines: this.GetBinTips(i, j), exact:
true, menu:
true };
6413 if (this.options.Color) res.color2 = this.GetPalette().getColor(colindx);
6415 if (pnt.disabled && !
this.is_projection) {
6420 ttrect = this.draw_g.append(
"svg:rect")
6421 .attr(
"class",
"tooltip_bin h1bin")
6422 .style(
"pointer-events",
"none");
6424 var binid = i*10000 + j;
6426 if (this.is_projection ==
"X") {
6427 x1 = 0; x2 = this.frame_width();
6428 if (this.projection_width > 1) {
6429 var dd = (this.projection_width-1)/2;
6430 if (j2+dd >= h.j2) { j2 = Math.min(Math.round(j2+dd), h.j2); j1 = Math.max(j2 - this.projection_width, h.j1); }
6431 else { j1 = Math.max(Math.round(j1-dd), h.j1); j2 = Math.min(j1 + this.projection_width, h.j2); }
6433 y1 = h.gry[j2]; y2 = h.gry[j1];
6434 binid = j1*777 + j2*333;
6435 }
else if (this.is_projection ==
"Y") {
6436 y1 = 0; y2 = this.frame_height();
6437 if (this.projection_width > 1) {
6438 var dd = (this.projection_width-1)/2;
6439 if (i2+dd >= h.i2) { i2 = Math.min(Math.round(i2+dd), h.i2); i1 = Math.max(i2 - this.projection_width, h.i1); }
6440 else { i1 = Math.max(Math.round(i1-dd), h.i1); i2 = Math.min(i1 + this.projection_width, h.i2); }
6442 x1 = h.grx[i1], x2 = h.grx[i2],
6443 binid = i1*777 + i2*333;
6446 res.changed = ttrect.property(
"current_bin") !== binid;
6449 ttrect.attr(
"x", x1)
6450 .attr(
"width", x2 - x1)
6452 .attr(
"height", y2 - y1)
6453 .style(
"opacity",
"0.7")
6454 .property(
"current_bin", binid);
6456 if (this.is_projection && res.changed)
6457 this.RedrawProjection(i1, i2, j1, j2);
6461 res.user_info = { obj: histo, name: histo.fName,
6462 bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1,
6463 grx: pnt.x, gry: pnt.y };
6468 TH2Painter.prototype.CanZoomIn =
function(axis,min,max) {
6470 if (axis==
"z")
return true;
6472 var obj = this.GetHisto();
6473 if (obj) obj = (axis==
"y") ? obj.fYaxis : obj.fXaxis;
6475 return !obj || (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1);
6478 TH2Painter.prototype.Draw2D =
function(call_back, resize) {
6480 this.Clear3DScene();
6481 this.mode3d =
false;
6486 var pp = this.DrawColorPalette(this.options.Zscale && (
this.options.Color ||
this.options.Contour),
true);
6493 if (pp) pp.DrawPave();
6497 this.UpdateStatWebCanvas();
6499 this.AddInteractive();
6501 JSROOT.CallBack(call_back);
6504 TH2Painter.prototype.Draw3D =
function(call_back, resize) {
6506 JSROOT.AssertPrerequisites(
'hist3d',
function() {
6507 this.Draw3D(call_back, resize);
6511 TH2Painter.prototype.CallDrawFunc =
function(callback, resize) {
6513 var main = this.main_painter(),
6514 fp = this.frame_painter();
6516 if ((main!==
this) && fp && (fp.mode3d !==
this.options.Mode3D))
6517 this.CopyOptionsFrom(main);
6519 var funcname = this.options.Mode3D ?
"Draw3D" :
"Draw2D";
6520 this[funcname](callback, resize);
6523 TH2Painter.prototype.Redraw =
function(resize) {
6524 this.CallDrawFunc(null, resize);
6527 function drawHistogram2D(divid, histo, opt) {
6529 var painter =
new JSROOT.TH2Painter(histo);
6531 painter.SetDivId(divid, 1);
6534 painter.DecodeOptions(opt);
6536 if (painter.IsTH2Poly()) {
6537 if (painter.options.Mode3D) painter.options.Lego = 12;
6538 else if (!painter.options.Color) painter.options.Color =
true;
6541 painter._show_empty_bins =
false;
6543 painter._can_move_colz =
true;
6546 painter.CheckPadRange(!painter.options.Mode3D && (painter.options.Contour != 14));
6548 painter.ScanContent();
6550 painter.CreateStat();
6552 painter.CallDrawFunc(
function() {
6553 this.DrawNextFunction(0,
function() {
6554 if (!this.Mode3D && this.options.AutoZoom)
this.AutoZoom();
6556 if (this.options.Project && !
this.mode3d)
6557 this.ToggleProjection(this.options.Project);
6558 this.DrawingReady();
6568 function createTF2Histogram(func, nosave, hist) {
6569 var nsave = 0, npx = 0, npy = 0;
6571 nsave = func.fSave.length;
6572 npx = Math.round(func.fSave[nsave-2]);
6573 npy = Math.round(func.fSave[nsave-1]);
6574 if (nsave !== (npx+1)*(npy+1) + 6) nsave = 0;
6578 var dx = (func.fSave[nsave-5] - func.fSave[nsave-6]) / npx / 2,
6579 dy = (func.fSave[nsave-3] - func.fSave[nsave-4]) / npy / 2;
6581 if (!hist) hist = JSROOT.CreateHistogram(
"TH2F", npx+1, npy+1);
6583 hist.fXaxis.fXmin = func.fSave[nsave-6] - dx;
6584 hist.fXaxis.fXmax = func.fSave[nsave-5] + dx;
6586 hist.fYaxis.fXmin = func.fSave[nsave-4] - dy;
6587 hist.fYaxis.fXmax = func.fSave[nsave-3] + dy;
6589 for (var k=0,j=0;j<=npy;++j)
6590 for (var i=0;i<=npx;++i)
6591 hist.setBinContent(hist.getBin(i+1,j+1), func.fSave[k++]);
6594 npx = Math.max(func.fNpx, 2);
6595 npy = Math.max(func.fNpy, 2);
6597 if (!hist) hist = JSROOT.CreateHistogram(
"TH2F", npx, npy);
6599 hist.fXaxis.fXmin = func.fXmin;
6600 hist.fXaxis.fXmax = func.fXmax;
6602 hist.fYaxis.fXmin = func.fYmin;
6603 hist.fYaxis.fXmax = func.fYmax;
6605 for (var j=0;j<npy;++j)
6606 for (var i=0;i<npx;++i) {
6607 var x = func.fXmin + (i + 0.5) * (func.fXmax - func.fXmin) / npx,
6608 y = func.fYmin + (j + 0.5) * (func.fYmax - func.fYmin) / npy;
6610 hist.setBinContent(hist.getBin(i+1,j+1), func.evalPar(x,y));
6614 hist.fName =
"Func";
6615 hist.fTitle = func.fTitle;
6616 hist.fMinimum = func.fMinimum;
6617 hist.fMaximum = func.fMaximum;
6619 hist.fLineColor = func.fLineColor;
6620 hist.fLineStyle = func.fLineStyle;
6621 hist.fLineWidth = func.fLineWidth;
6622 hist.fFillColor = func.fFillColor;
6623 hist.fFillStyle = func.fFillStyle;
6624 hist.fMarkerColor = func.fMarkerColor;
6625 hist.fMarkerStyle = func.fMarkerStyle;
6626 hist.fMarkerSize = func.fMarkerSize;
6628 hist.fBits |= JSROOT.TH1StatusBits.kNoStats;
6644 function drawTF2(divid, func, opt) {
6646 var d =
new JSROOT.DrawOptions(opt);
6648 var hist = createTF2Histogram(func, d.check(
'NOSAVE'));
6650 if (d.empty()) opt =
"cont3";
else
6651 if (d.opt ===
"SAME") opt =
"cont2 same";
6654 var hpainter = drawHistogram2D(divid, hist, opt);
6656 hpainter.tf2_typename = func._typename;
6657 hpainter.tf2_nosave = d.check(
'NOSAVE');
6659 hpainter.UpdateObject =
function(obj, opt) {
6660 if (!obj || (this.tf2_typename != obj._typename))
return false;
6662 createTF2Histogram(obj, this.tf2_nosave, this.GetHisto());
6672 function THStackPainter(stack, opt) {
6673 JSROOT.TObjectPainter.call(
this, stack, opt);
6675 this.firstpainter = null;
6679 THStackPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
6681 THStackPainter.prototype.Cleanup =
function() {
6682 var pp = this.pad_painter();
6683 if (pp) pp.CleanPrimitives(this.Selector.bind(
this,
true));
6684 delete this.firstpainter;
6685 delete this.painters;
6686 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
6689 THStackPainter.prototype.HasErrors =
function(hist) {
6690 if (hist.fSumw2 && (hist.fSumw2.length > 0))
6691 for (var n=0;n<hist.fSumw2.length;++n)
6692 if (hist.fSumw2[n] > 0)
return true;
6696 THStackPainter.prototype.BuildStack =
function(stack) {
6700 if (!stack.fHists)
return false;
6701 var nhists = stack.fHists.arr.length;
6702 if (nhists <= 0)
return false;
6703 var lst = JSROOT.Create(
"TList");
6704 lst.Add(JSROOT.clone(stack.fHists.arr[0]), stack.fHists.opt[0]);
6705 for (var i=1;i<nhists;++i) {
6706 var hnext = JSROOT.clone(stack.fHists.arr[i]),
6707 hnextopt = stack.fHists.opt[i],
6708 hprev = lst.arr[i-1];
6710 if ((hnext.fNbins != hprev.fNbins) ||
6711 (hnext.fXaxis.fXmin != hprev.fXaxis.fXmin) ||
6712 (hnext.fXaxis.fXmax != hprev.fXaxis.fXmax)) {
6713 JSROOT.console(
"When drawing THStack, cannot sum-up histograms " + hnext.fName +
" and " + hprev.fName);
6719 for (var n = 0; n < hnext.fArray.length; ++n)
6720 hnext.fArray[n] += hprev.fArray[n];
6722 lst.Add(hnext, hnextopt);
6728 THStackPainter.prototype.GetHistMinMax =
function(hist, witherr) {
6729 var res = { min : 0, max : 0 },
6730 domin =
true, domax =
true;
6731 if (hist.fMinimum !== -1111) {
6732 res.min = hist.fMinimum;
6735 if (hist.fMaximum !== -1111) {
6736 res.max = hist.fMaximum;
6740 if (!domin && !domax)
return res;
6742 var i1 = 1, i2 = hist.fXaxis.fNbins, j1 = 1, j2 = 1, first =
true;
6744 if (hist.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) {
6745 i1 = hist.fXaxis.fFirst;
6746 i2 = hist.fXaxis.fLast;
6749 if (hist._typename.indexOf(
"TH2")===0) {
6750 j2 = hist.fYaxis.fNbins;
6751 if (hist.fYaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) {
6752 j1 = hist.fYaxis.fFirst;
6753 j2 = hist.fYaxis.fLast;
6756 for (var j=j1; j<=j2;++j)
6757 for (var i=i1; i<=i2;++i) {
6758 var val = hist.getBinContent(i, j),
6759 err = witherr ? hist.getBinError(hist.getBin(i,j)) : 0;
6760 if (domin && (first || (val-err < res.min))) res.min = val-err;
6761 if (domax && (first || (val+err > res.max))) res.max = val+err;
6768 THStackPainter.prototype.GetMinMax =
function(iserr, pad) {
6769 var res = { min: 0, max: 0 },
6770 stack = this.GetObject();
6772 if (this.options.nostack) {
6773 for (var i = 0; i < stack.fHists.arr.length; ++i) {
6774 var resh = this.GetHistMinMax(stack.fHists.arr[i], iserr);
6778 res.min = Math.min(res.min, resh.min);
6779 res.max = Math.max(res.max, resh.max);
6783 res.min = this.GetHistMinMax(stack.fStack.arr[0], iserr).min;
6784 res.max = this.GetHistMinMax(stack.fStack.arr[stack.fStack.arr.length-1], iserr).max;
6787 if (stack.fMaximum != -1111) res.max = stack.fMaximum;
6789 if (stack.fMinimum != -1111) res.min = stack.fMinimum;
6791 if (pad && (this.options.ndim == 1 ? pad.fLogy : pad.fLogz)) {
6792 if (res.max<=0) res.max = 1;
6793 if (res.min<=0) res.min = 1e-4*res.max;
6794 var kmin = 1/(1 + 0.5*JSROOT.log10(res.max / res.min)),
6795 kmax = 1 + 0.2*JSROOT.log10(res.max / res.min);
6799 if ((res.min>0) && (res.min < 0.05*res.max)) res.min = 0;
6805 THStackPainter.prototype.DrawNextHisto =
function(indx, mm, subp, reenter) {
6806 if (mm ===
"callback") {
6808 if (indx<0) this.firstpainter = subp;
6809 else this.painters.push(subp);
6813 var stack = this.GetObject(),
6814 hist = stack.fHistogram, hopt =
"",
6815 hlst = this.options.nostack ? stack.fHists : stack.fStack,
6816 nhists = (hlst && hlst.arr) ? hlst.arr.length : 0, rindx = 0;
6818 if (indx>=nhists)
return this.DrawingReady();
6820 if ((indx % 500 === 499) && !reenter)
6821 return setTimeout(this.DrawNextHisto.bind(
this, indx, mm, subp,
true), 0);
6824 rindx = this.options.horder ? indx : nhists-indx-1;
6825 hist = hlst.arr[rindx];
6826 hopt = hlst.opt[rindx] || hist.fOption || this.options.hopt;
6827 if (hopt.toUpperCase().indexOf(this.options.hopt)<0) hopt += this.options.hopt;
6828 if (this.options.draw_errors && !hopt) hopt =
"E";
6829 hopt +=
" same nostat";
6832 if (this.options._pfc ||
this.options._plc ||
this.options._pmc) {
6833 if (!this.pallette && JSROOT.Painter.GetColorPalette)
6834 this.palette = JSROOT.Painter.GetColorPalette();
6836 var color = this.palette.calcColor(rindx, nhists+1);
6837 var icolor = this.add_color(color);
6839 if (this.options._pfc) hist.fFillColor = icolor;
6840 if (this.options._plc) hist.fLineColor = icolor;
6841 if (this.options._pmc) hist.fMarkerColor = icolor;
6846 hopt = this.options.hopt +
" axis";
6848 if (mm) hopt +=
";minimum:" + mm.min +
";maximum:" + mm.max;
6853 if ((rindx > 0) && !this.options.nostack) hist.$baseh = hlst.arr[rindx - 1];
6855 JSROOT.draw(this.divid, hist, hopt, this.DrawNextHisto.bind(
this, indx,
"callback"));
6858 THStackPainter.prototype.DecodeOptions =
function(opt) {
6859 if (!this.options) this.options = {};
6860 JSROOT.extend(this.options, { ndim: 1, nostack:
false, same:
false, horder:
true, has_errors:
false, draw_errors:
false, hopt:
"" });
6862 var stack = this.GetObject(),
6863 hist = stack.fHistogram || (stack.fHists ? stack.fHists.arr[0] : null) || (stack.fStack ? stack.fStack.arr[0] : null);
6865 if (hist && (hist._typename.indexOf(
"TH2")==0)) this.options.ndim = 2;
6867 if ((this.options.ndim==2) && !opt) opt =
"lego1";
6869 if (stack.fHists && !
this.options.nostack) {
6870 for (var k=0;k<stack.fHists.arr.length;++k)
6871 this.options.has_errors =
this.options.has_errors ||
this.HasErrors(stack.fHists.arr[k]);
6874 var d =
new JSROOT.DrawOptions(opt);
6876 this.options.nostack = d.check(
"NOSTACK");
6877 if (d.check(
"STACK")) this.options.nostack =
false;
6878 this.options.same = d.check(
"SAME");
6880 this.options._pfc = d.check(
"PFC");
6881 this.options._plc = d.check(
"PLC");
6882 this.options._pmc = d.check(
"PMC");
6884 this.options.hopt = d.remain();
6886 var dolego = d.check(
"LEGO");
6888 this.options.errors = d.check(
"E");
6891 if (!this.options.nostack &&
this.options.has_errors && !dolego && !d.check(
"HIST") && (this.options.hopt.indexOf(
"E")<0)) this.options.draw_errors =
true;
6893 this.options.horder = this.options.nostack || dolego;
6896 THStackPainter.prototype.CreateHistogram =
function(stack) {
6897 var histos = stack.fHists,
6898 numhistos = histos ? histos.arr.length : 0;
6901 var histo = JSROOT.CreateHistogram(
"TH1I", 100);
6902 histo.fTitle = stack.fTitle;
6906 var h0 = histos.arr[0];
6907 var histo = JSROOT.CreateHistogram((this.options.ndim==1) ?
"TH1I" :
"TH2I", h0.fXaxis.fNbins, h0.fYaxis.fNbins);
6908 histo.fName =
"axis_hist";
6909 JSROOT.extend(histo.fXaxis, h0.fXaxis);
6910 if (this.options.ndim==2)
6911 JSROOT.extend(histo.fYaxis, h0.fYaxis);
6914 for (var n=1;n<numhistos;++n) {
6915 var h = histos.arr[n];
6917 if (!histo.fXaxis.fLabels) {
6918 histo.fXaxis.fXmin = Math.min(histo.fXaxis.fXmin, h.fXaxis.fXmin);
6919 histo.fXaxis.fXmax = Math.max(histo.fXaxis.fXmax, h.fXaxis.fXmax);
6922 if ((this.options.ndim==2) && !histo.fYaxis.fLabels) {
6923 histo.fYaxis.fXmin = Math.min(histo.fYaxis.fXmin, h.fYaxis.fXmin);
6924 histo.fYaxis.fXmax = Math.max(histo.fYaxis.fXmax, h.fYaxis.fXmax);
6928 histo.fTitle = stack.fTitle;
6933 THStackPainter.prototype.drawStack =
function() {
6935 var stack = this.GetObject();
6938 if (!this.options.nostack)
6939 this.options.nostack = ! this.BuildStack(stack);
6941 if (!stack.fHistogram && !
this.options.same)
6942 stack.fHistogram = this.CreateHistogram(stack);
6944 var mm = this.GetMinMax(this.options.errors ||
this.options.draw_errors,
this.root_pad());
6946 this.DrawNextHisto(this.options.same ? 0 : -1, mm);
6950 THStackPainter.prototype.UpdateObject =
function(obj) {
6951 if (!this.MatchObjectType(obj))
return false;
6953 var stack = this.GetObject();
6955 stack.fHists = obj.fHists;
6956 stack.fStack = obj.fStack;
6958 if (!this.options.nostack) {
6959 this.options.nostack = !this.BuildStack(stack);
6963 if (this.firstpainter) {
6964 var src = obj.fHistogram;
6966 src = stack.fHistogram = this.CreateHistogram(stack);
6968 this.firstpainter.UpdateObject(src);
6970 var mm = this.GetMinMax(this.options.errors ||
this.options.draw_errors,
this.root_pad());
6972 this.firstpainter.options.minimum = mm.min;
6973 this.firstpainter.options.maximum = mm.max;
6975 if (this.options.ndim == 1) {
6976 this.firstpainter.ymin = mm.min;
6977 this.firstpainter.ymax = mm.max;
6984 var pp = this.pad_painter();
6985 if (pp) pp.CleanPrimitives(this.Selector.bind(
this,
false));
6988 this.did_update = isany;
6994 THStackPainter.prototype.Selector =
function(fullclear, painter) {
6995 if (fullclear && (painter===this.firstpainter))
return true;
6996 return this.painters.indexOf(painter) >= 0;
7000 THStackPainter.prototype.Redraw =
function() {
7002 if (!this.did_update)
return;
7005 delete this.did_update;
7007 if (this.firstpainter)
7008 this.firstpainter.Redraw();
7010 this.DrawNextHisto(0, null);
7013 function drawHStack(divid, stack, opt) {
7019 var painter =
new THStackPainter(stack, opt);
7020 painter.SetDivId(divid, -1);
7021 painter.DecodeOptions(opt);
7023 if (!stack.fHists || (stack.fHists.arr.length == 0))
return painter.DrawingReady();
7025 painter.drawStack();
7027 painter.SetDivId(divid);
7035 JSROOT.Painter.drawLegend = drawPave;
7036 JSROOT.Painter.drawPaveText = drawPave;
7038 JSROOT.Painter.drawPave = drawPave;
7039 JSROOT.Painter.produceLegend = produceLegend;
7040 JSROOT.Painter.drawHistogram1D = drawHistogram1D;
7041 JSROOT.Painter.drawHistogram2D = drawHistogram2D;
7042 JSROOT.Painter.drawTF2 = drawTF2;
7043 JSROOT.Painter.drawHStack = drawHStack;
7045 JSROOT.TPavePainter = TPavePainter;
7046 JSROOT.THistPainter = THistPainter;
7047 JSROOT.TH1Painter = TH1Painter;
7048 JSROOT.TH2Painter = TH2Painter;
7049 JSROOT.THStackPainter = THStackPainter;