6 if ( typeof define ===
"function" && define.amd ) {
8 define( [
'd3',
'JSRootPainter',
'JSRootMath'], factory );
11 if (typeof d3 !=
'object')
12 throw new Error(
'This extension requires d3.v3.js',
'JSRootPainter.more.js');
14 if (typeof JSROOT ==
'undefined')
15 throw new Error(
'JSROOT is not defined',
'JSRootPainter.more.js');
17 if (typeof JSROOT.Painter !=
'object')
18 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.more.js');
23 } (
function(d3, JSROOT) {
25 JSROOT.ToolbarIcons.th2color = {
26 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}]
29 JSROOT.ToolbarIcons.th2colorz = {
30 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)'}]
33 JSROOT.ToolbarIcons.th2draw3d = {
34 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 "+
35 "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 "+
36 "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 "+
37 "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"
40 JSROOT.Painter.CreateDefaultPalette =
function() {
42 function HLStoRGB(h, l, s) {
47 function hue2rgb(p, q, t) {
50 if (t < 1 / 6)
return p + (q - p) * 6 * t;
51 if (t < 1 / 2)
return q;
52 if (t < 2 / 3)
return p + (q - p) * (2 / 3 - t) * 6;
55 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
57 r = hue2rgb(p, q, h + 1 / 3);
59 b = hue2rgb(p, q, h - 1 / 3);
61 return 'rgb(' + Math.round(r * 255) +
',' + Math.round(g * 255) +
',' + Math.round(b * 255) +
')';
64 var palette = [], saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50;
65 for (var i = 0; i < maxPretty; ++i) {
66 var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360.0;
67 var rgbval = HLStoRGB(hue, lightness, saturation);
73 JSROOT.Painter.CreateGrayPalette =
function() {
75 for (var i = 0; i < 50; ++i) {
76 var code = Math.round((i+2)/60 * 255 );
77 palette.push(
'rgb('+code+
','+code+
','+code+
')');
82 JSROOT.Painter.CreateGradientColorTable =
function(Stops, Red, Green, Blue, NColors, alpha) {
86 for (var g = 1; g < Stops.length; g++) {
88 var nColorsGradient = parseInt(Math.floor(NColors*Stops[g]) - Math.floor(NColors*Stops[g-1]));
89 for (var c = 0; c < nColorsGradient; c++) {
90 var col = Math.round(Red[g-1] + c * (Red[g] - Red[g-1])/nColorsGradient) +
"," +
91 Math.round(Green[g-1] + c * (Green[g] - Green[g-1])/ nColorsGradient) +
"," +
92 Math.round(Blue[g-1] + c * (Blue[g] - Blue[g-1])/ nColorsGradient);
93 palette.push(
"rgb("+col+
")");
100 JSROOT.Painter.GetColorPalette =
function(col,alfa) {
101 if ((col == null) || (col==0)) col = JSROOT.gStyle.Palette;
102 if ((col>0) && (col<10))
return JSROOT.Painter.CreateGrayPalette();
103 if (col < 51)
return JSROOT.Painter.CreateDefaultPalette();
104 if (col > 112) col = 57;
106 var red, green, blue,
107 stops = [ 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000 ];
112 red = [ 0, 9, 13, 17, 24, 32, 27, 25, 29];
113 green = [ 0, 0, 0, 2, 37, 74, 113, 160, 221];
114 blue = [ 28, 42, 59, 78, 98, 129, 154, 184, 221];
119 red = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
120 green = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
121 blue = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
126 red = [ 0, 45, 99, 156, 212, 230, 237, 234, 242];
127 green = [ 0, 0, 0, 45, 101, 168, 238, 238, 243];
128 blue = [ 0, 1, 1, 3, 9, 8, 11, 95, 230];
133 red = [ 0, 22, 44, 68, 93, 124, 160, 192, 237];
134 green = [ 0, 16, 41, 67, 93, 125, 162, 194, 241];
135 blue = [ 97, 100, 99, 99, 93, 68, 44, 26, 74];
140 red = [ 0, 5, 15, 35, 102, 196, 208, 199, 110];
141 green = [ 0, 48, 124, 192, 206, 226, 97, 16, 0];
142 blue = [ 99, 142, 198, 201, 90, 22, 13, 8, 2];
147 red = [ 242, 234, 237, 230, 212, 156, 99, 45, 0];
148 green = [ 243, 238, 238, 168, 101, 45, 0, 0, 0];
149 blue = [ 230, 95, 11, 8, 9, 3, 1, 1, 0];
154 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];
155 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];
156 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];
161 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];
162 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];
163 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];
168 red = [13, 23, 25, 63, 76, 104, 137, 161, 206];
169 green = [95, 67, 37, 21, 0, 12, 35, 52, 79];
170 blue = [ 4, 3, 2, 6, 11, 22, 49, 98, 208];
175 red = [0, 61, 89, 122, 143, 160, 185, 204, 231];
176 green = [0, 0, 0, 0, 14, 37, 72, 132, 235];
177 blue = [0, 140, 224, 144, 4, 5, 6, 9, 13];
182 red = [ 14, 7, 2, 0, 5, 11, 55, 131, 229];
183 green = [105, 56, 26, 1, 42, 74, 131, 171, 229];
184 blue = [ 2, 21, 35, 60, 92, 113, 160, 185, 229];
189 red = [ 0, 0, 0, 70, 148, 231, 235, 237, 244];
190 green = [ 0, 0, 0, 0, 0, 69, 67, 216, 244];
191 blue = [ 0, 102, 228, 231, 177, 124, 137, 20, 244];
196 red = [ 50, 56, 63, 68, 93, 121, 165, 192, 241];
197 green = [ 66, 81, 91, 96, 111, 128, 155, 189, 241];
198 blue = [ 97, 91, 75, 65, 77, 103, 143, 167, 217];
203 red = [ 145, 166, 167, 156, 131, 114, 101, 112, 132];
204 green = [ 158, 178, 179, 181, 163, 154, 144, 152, 159];
205 blue = [ 190, 199, 201, 192, 176, 169, 160, 166, 190];
210 red = [ 93, 91, 99, 108, 130, 125, 132, 155, 174];
211 green = [ 126, 124, 128, 129, 131, 121, 119, 153, 173];
212 blue = [ 103, 94, 87, 85, 80, 85, 107, 120, 146];
217 red = [ 24, 40, 69, 90, 104, 114, 120, 132, 103];
218 green = [ 29, 52, 94, 127, 150, 162, 159, 151, 101];
219 blue = [ 29, 52, 96, 132, 162, 181, 184, 186, 131];
224 red = [ 46, 38, 61, 92, 113, 121, 132, 150, 191];
225 green = [ 46, 36, 40, 69, 110, 135, 131, 92, 34];
226 blue = [ 46, 80, 74, 70, 81, 105, 165, 211, 225];
231 red = [ 0, 4, 12, 30, 52, 101, 142, 190, 237];
232 green = [ 0, 40, 86, 121, 140, 172, 187, 213, 240];
233 blue = [ 0, 9, 14, 18, 21, 23, 27, 35, 101];
238 red = [ 198, 206, 206, 211, 198, 181, 161, 171, 244];
239 green = [ 103, 133, 150, 172, 178, 174, 163, 175, 244];
240 blue = [ 49, 54, 55, 66, 91, 130, 184, 224, 244];
245 red = [ 243, 243, 240, 240, 241, 239, 186, 151, 129];
246 green = [ 0, 46, 99, 149, 194, 220, 183, 166, 147];
247 blue = [ 6, 8, 36, 91, 169, 235, 246, 240, 233];
252 red = [ 22, 19, 19, 25, 35, 53, 88, 139, 210];
253 green = [ 0, 32, 69, 108, 135, 159, 183, 198, 215];
254 blue = [ 77, 96, 110, 116, 110, 100, 90, 78, 70];
259 red = [ 68, 116, 165, 182, 189, 180, 145, 111, 71];
260 green = [ 37, 82, 135, 178, 204, 225, 221, 202, 147];
261 blue = [ 16, 55, 105, 147, 196, 226, 232, 224, 178];
266 red = [ 61, 99, 136, 181, 213, 225, 198, 136, 24];
267 green = [ 149, 140, 96, 83, 132, 178, 190, 135, 22];
268 blue = [ 214, 203, 168, 135, 110, 100, 111, 113, 22];
273 red = [ 76, 120, 156, 183, 197, 180, 162, 154, 140];
274 green = [ 34, 35, 42, 69, 102, 137, 164, 188, 197];
275 blue = [ 64, 69, 78, 105, 142, 177, 205, 217, 198];
280 red = [ 37, 102, 157, 188, 196, 214, 223, 235, 251];
281 green = [ 37, 29, 25, 37, 67, 91, 132, 185, 251];
282 blue = [ 37, 32, 33, 45, 66, 98, 137, 187, 251];
287 red = [ 79, 100, 119, 137, 153, 172, 192, 205, 250];
288 green = [ 63, 79, 93, 103, 115, 135, 167, 196, 250];
289 blue = [ 51, 59, 66, 61, 62, 70, 110, 160, 250];
294 red = [ 43, 44, 50, 66, 125, 172, 178, 155, 157];
295 green = [ 63, 63, 85, 101, 138, 163, 122, 51, 39];
296 blue = [ 121, 101, 58, 44, 47, 55, 57, 44, 43];
301 red = [ 0, 41, 62, 79, 90, 87, 99, 140, 228];
302 green = [ 0, 57, 81, 93, 85, 70, 71, 125, 228];
303 blue = [ 95, 91, 91, 82, 60, 43, 44, 112, 228];
308 red = [ 49, 59, 72, 88, 114, 141, 176, 205, 222];
309 green = [ 78, 72, 66, 57, 59, 75, 106, 142, 173];
310 blue = [ 78, 55, 46, 40, 39, 39, 40, 41, 47];
315 red = [ 243, 222, 201, 185, 165, 158, 166, 187, 219];
316 green = [ 94, 108, 132, 135, 125, 96, 68, 51, 61];
317 blue = [ 7, 9, 12, 19, 45, 89, 118, 146, 118];
322 red = [ 19, 44, 74, 105, 137, 166, 194, 206, 220];
323 green = [ 19, 28, 40, 55, 82, 110, 159, 181, 220];
324 blue = [ 19, 42, 68, 96, 129, 157, 188, 203, 220];
329 red = [ 33, 44, 70, 99, 140, 165, 199, 211, 216];
330 green = [ 38, 50, 76, 105, 140, 165, 191, 189, 167];
331 blue = [ 55, 67, 97, 124, 140, 166, 163, 129, 52];
336 red = [ 0, 33, 73, 124, 136, 152, 159, 171, 223];
337 green = [ 0, 43, 92, 124, 134, 126, 121, 144, 223];
338 blue = [ 0, 43, 68, 76, 73, 64, 72, 114, 223];
343 red = [ 5, 18, 45, 124, 193, 223, 205, 128, 49];
344 green = [ 48, 134, 207, 230, 193, 113, 28, 0, 7];
345 blue = [ 6, 15, 41, 121, 193, 226, 208, 130, 49];
350 red = [ 180, 106, 104, 135, 164, 188, 189, 165, 144];
351 green = [ 72, 126, 154, 184, 198, 207, 205, 190, 179];
352 blue = [ 41, 120, 158, 188, 194, 181, 145, 100, 62];
357 red = [ 57, 72, 94, 117, 136, 154, 174, 192, 215];
358 green = [ 0, 33, 68, 109, 140, 171, 192, 196, 209];
359 blue = [ 116, 137, 173, 201, 200, 201, 203, 190, 187];
364 red = [ 31, 71, 123, 160, 210, 222, 214, 199, 183];
365 green = [ 40, 117, 171, 211, 231, 220, 190, 132, 65];
366 blue = [ 234, 214, 228, 222, 210, 160, 105, 60, 34];
371 red = [ 123, 108, 109, 126, 154, 172, 188, 196, 218];
372 green = [ 184, 138, 130, 133, 154, 175, 188, 196, 218];
373 blue = [ 208, 130, 109, 99, 110, 122, 150, 171, 218];
378 red = [ 105, 106, 122, 143, 159, 172, 176, 181, 207];
379 green = [ 252, 197, 194, 187, 174, 162, 153, 136, 125];
380 blue = [ 146, 133, 144, 155, 163, 167, 166, 162, 174];
385 red = [ 171, 141, 145, 152, 154, 159, 163, 158, 177];
386 green = [ 236, 143, 100, 63, 53, 55, 44, 31, 6];
387 blue = [ 59, 48, 46, 44, 42, 54, 82, 112, 179];
392 red = [ 180, 190, 209, 223, 204, 228, 205, 152, 91];
393 green = [ 93, 125, 147, 172, 181, 224, 233, 198, 158];
394 blue = [ 236, 218, 160, 133, 114, 132, 162, 220, 218];
399 red = [ 225, 183, 162, 135, 115, 111, 119, 145, 211];
400 green = [ 205, 177, 166, 135, 124, 117, 117, 132, 172];
401 blue = [ 186, 165, 155, 135, 126, 130, 150, 178, 226];
406 red = [ 39, 43, 59, 63, 80, 116, 153, 177, 223];
407 green = [ 39, 43, 59, 74, 91, 114, 139, 165, 223];
408 blue = [ 39, 50, 59, 70, 85, 115, 151, 176, 223];
413 red = [ 0, 38, 60, 76, 84, 89, 101, 128, 204];
414 green = [ 0, 10, 15, 23, 35, 57, 83, 123, 199];
415 blue = [ 0, 11, 22, 40, 63, 86, 97, 94, 85];
420 red = [ 94, 112, 141, 165, 167, 140, 91, 49, 27];
421 green = [ 27, 46, 88, 135, 166, 161, 135, 97, 58];
422 blue = [ 42, 52, 81, 106, 139, 158, 155, 137, 116];
427 red = [ 30, 49, 79, 117, 135, 151, 146, 138, 147];
428 green = [ 63, 60, 72, 90, 94, 94, 68, 46, 16];
429 blue = [ 18, 28, 41, 56, 62, 63, 50, 36, 21];
434 red = [ 0, 30, 63, 101, 143, 152, 169, 187, 230];
435 green = [ 0, 14, 28, 42, 58, 61, 67, 74, 91];
436 blue = [ 39, 26, 21, 18, 15, 14, 14, 13, 13];
441 red = [ 149, 140, 164, 179, 182, 181, 131, 87, 61];
442 green = [ 62, 70, 107, 136, 144, 138, 117, 87, 74];
443 blue = [ 40, 38, 45, 49, 49, 49, 38, 32, 34];
448 red = [ 99, 112, 148, 165, 179, 182, 183, 183, 208];
449 green = [ 39, 40, 57, 79, 104, 127, 148, 161, 198];
450 blue = [ 15, 16, 18, 33, 51, 79, 103, 129, 177];
455 red = [ 99, 116, 154, 174, 200, 196, 201, 201, 230];
456 green = [ 0, 0, 8, 32, 58, 83, 119, 136, 173];
457 blue = [ 5, 6, 7, 9, 9, 14, 17, 19, 24];
462 red = [ 82, 106, 126, 141, 155, 163, 142, 107, 66];
463 green = [ 62, 44, 69, 107, 135, 152, 149, 132, 119];
464 blue = [ 39, 25, 31, 60, 73, 68, 49, 72, 188];
469 red = [ 18, 29, 44, 72, 116, 158, 184, 208, 221];
470 green = [ 27, 46, 71, 105, 146, 177, 189, 190, 183];
471 blue = [ 39, 55, 80, 108, 130, 133, 124, 100, 76];
476 red = [ 0, 48, 119, 173, 212, 224, 228, 228, 245];
477 green = [ 0, 13, 30, 47, 79, 127, 167, 205, 245];
478 blue = [ 0, 68, 75, 43, 16, 22, 55, 128, 245];
483 red = [ 34, 70, 129, 187, 225, 226, 216, 193, 179];
484 green = [ 48, 91, 147, 194, 226, 229, 196, 110, 12];
485 blue = [ 234, 212, 216, 224, 206, 110, 53, 40, 29];
490 red = [ 30, 55, 103, 147, 174, 203, 188, 151, 105];
491 green = [ 0, 65, 138, 182, 187, 175, 121, 53, 9];
492 blue = [ 191, 202, 212, 208, 171, 140, 97, 57, 30];
497 red = [ 112, 97, 113, 125, 138, 159, 178, 188, 225];
498 green = [ 16, 17, 24, 37, 56, 81, 110, 136, 189];
499 blue = [ 38, 35, 46, 59, 78, 103, 130, 152, 201];
504 red = [ 18, 72, 5, 23, 29, 201, 200, 98, 29];
505 green = [ 0, 0, 43, 167, 211, 117, 0, 0, 0];
506 blue = [ 51, 203, 177, 26, 10, 9, 8, 3, 0];
511 red = [ 19, 42, 64, 88, 118, 147, 175, 187, 205];
512 green = [ 19, 55, 89, 125, 154, 169, 161, 129, 70];
513 blue = [ 19, 32, 47, 70, 100, 128, 145, 130, 75];
518 red = [ 33, 31, 42, 68, 86, 111, 141, 172, 227];
519 green = [ 255, 175, 145, 106, 88, 55, 15, 0, 0];
520 blue = [ 255, 205, 202, 203, 208, 205, 203, 206, 231];
525 red = [ 0, 25, 50, 79, 110, 145, 181, 201, 254];
526 green = [ 0, 16, 30, 46, 63, 82, 101, 124, 179];
527 blue = [ 0, 12, 21, 29, 39, 49, 61, 74, 103];
532 red = [ 0, 13, 30, 44, 72, 120, 156, 200, 247];
533 green = [ 0, 36, 84, 117, 141, 153, 151, 158, 247];
534 blue = [ 0, 94, 100, 82, 56, 66, 76, 131, 247];
539 red = [ 26, 51, 43, 33, 28, 35, 74, 144, 246];
540 green = [ 9, 24, 55, 87, 118, 150, 180, 200, 222];
541 blue = [ 30, 96, 112, 114, 112, 101, 72, 35, 0];
545 return JSROOT.Painter.CreateDefaultPalette();
548 return JSROOT.Painter.CreateGradientColorTable(stops, red, green, blue, 255, alfa);
554 JSROOT.Painter.drawEllipse =
function(divid, obj, opt) {
556 this.SetDivId(divid);
558 this.Redraw =
function() {
559 var ellipse = this.GetObject();
561 if(!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(ellipse);
562 if (!this.fillatt) this.fillatt = this.createAttFill(ellipse);
565 this.RecreateDrawG(this.main_painter() == null);
567 var x = this.AxisToSvg(
"x", ellipse.fX1);
568 var y = this.AxisToSvg(
"y", ellipse.fY1);
569 var rx = this.AxisToSvg(
"x", ellipse.fX1 + ellipse.fR1) - x;
570 var ry = y - this.AxisToSvg(
"y", ellipse.fY1 + ellipse.fR2);
572 if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360) && (ellipse.fTheta == 0)) {
575 .append(
"svg:ellipse")
576 .attr(
"cx", x.toFixed(1)).attr(
"cy", y.toFixed(1))
577 .attr(
"rx", rx.toFixed(1)).attr(
"ry", ry.toFixed(1))
578 .call(this.lineatt.func).call(this.fillatt.func);
584 var ct = Math.cos(Math.PI*ellipse.fTheta/180.);
585 var st = Math.sin(Math.PI*ellipse.fTheta/180.);
587 var dx1 = rx * Math.cos(ellipse.fPhimin*Math.PI/180.);
588 var dy1 = ry * Math.sin(ellipse.fPhimin*Math.PI/180.);
589 var x1 = dx1*ct - dy1*st;
590 var y1 = -dx1*st - dy1*ct;
592 var dx2 = rx * Math.cos(ellipse.fPhimax*Math.PI/180.);
593 var dy2 = ry * Math.sin(ellipse.fPhimax*Math.PI/180.);
594 var x2 = dx2*ct - dy2*st;
595 var y2 = -dx2*st - dy2*ct;
598 .attr(
"transform",
"translate("+x.toFixed(1)+
","+y.toFixed(1)+
")")
601 " L " + x1.toFixed(1) +
"," + y1.toFixed(1) +
602 " A " + rx.toFixed(1) +
" " + ry.toFixed(1) +
" " + -ellipse.fTheta.toFixed(1) +
" 1 0 " + x2.toFixed(1) +
"," + y2.toFixed(1) +
604 .call(this.lineatt.func).call(this.fillatt.func);
608 return this.DrawingReady();
613 JSROOT.Painter.drawLine =
function(divid, obj, opt) {
615 this.SetDivId(divid);
617 this.Redraw =
function() {
618 var line = this.GetObject(),
619 lineatt = JSROOT.Painter.createAttLine(line);
622 this.RecreateDrawG(this.main_painter() == null);
626 .attr(
"x1", this.AxisToSvg(
"x", line.fX1).toFixed(1))
627 .attr(
"y1", this.AxisToSvg(
"y", line.fY1).toFixed(1))
628 .attr(
"x2", this.AxisToSvg(
"x", line.fX2).toFixed(1))
629 .attr(
"y2", this.AxisToSvg(
"y", line.fY2).toFixed(1))
635 return this.DrawingReady();
640 JSROOT.Painter.drawBox =
function(divid, obj, opt) {
642 this.SetDivId(divid);
644 this.Redraw =
function() {
645 var box = this.GetObject(),
646 lineatt = JSROOT.Painter.createAttLine(box),
647 fillatt = this.createAttFill(box);
650 this.RecreateDrawG(this.main_painter() == null);
652 var x1 = Math.round(this.AxisToSvg(
"x", box.fX1)),
653 x2 = Math.round(this.AxisToSvg(
"x", box.fX2)),
654 y1 = Math.round(this.AxisToSvg(
"y", box.fY1)),
655 y2 = Math.round(this.AxisToSvg(
"y", box.fY2));
659 .attr(
"x", Math.min(x1,x2))
660 .attr(
"y", Math.min(y1,y2))
661 .attr(
"width", Math.abs(x2-x1))
662 .attr(
"height", Math.abs(y1-y2))
669 return this.DrawingReady();
674 JSROOT.Painter.drawArrow =
function(divid, obj, opt) {
676 this.SetDivId(divid);
678 this.Redraw =
function() {
679 var arrow = this.GetObject();
680 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(arrow);
681 if (!this.fillatt) this.fillatt = this.createAttFill(arrow);
683 var wsize = Math.max(this.pad_width(), this.pad_height()) * arrow.fArrowSize;
684 if (wsize<3) wsize = 3;
685 var hsize = wsize * Math.tan(arrow.fAngle/2 * (Math.PI/180));
688 this.RecreateDrawG(this.main_painter() == null);
690 var x1 = this.AxisToSvg(
"x", arrow.fX1),
691 y1 = this.AxisToSvg(
"y", arrow.fY1),
692 x2 = this.AxisToSvg(
"x", arrow.fX2),
693 y2 = this.AxisToSvg(
"y", arrow.fY2),
694 right_arrow =
"M0,0" +
" L"+wsize.toFixed(1) +
","+hsize.toFixed(1) +
" L0," + (hsize*2).toFixed(1),
695 left_arrow =
"M" + wsize.toFixed(1) +
", 0" +
" L 0," + hsize.toFixed(1) +
" L " + wsize.toFixed(1) +
"," + (hsize*2).toFixed(1),
696 m_start = null, m_mid = null, m_end = null, defs = null,
697 oo = arrow.fOption, len = oo.length;
699 if (oo.indexOf(
"<")==0) {
700 var closed = (oo.indexOf(
"<|") == 0);
701 if (!defs) defs = this.draw_g.append(
"defs");
702 m_start =
"jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
703 var beg = defs.append(
"svg:marker")
705 .attr(
"markerWidth", wsize.toFixed(1))
706 .attr(
"markerHeight", (hsize*2).toFixed(1))
708 .attr(
"refY", hsize.toFixed(1))
709 .attr(
"orient",
"auto")
710 .attr(
"markerUnits",
"userSpaceOnUse")
712 .style(
"fill",
"none")
713 .attr(
"d", left_arrow + (closed ?
" Z" :
""))
714 .call(this.lineatt.func);
715 if (closed) beg.call(this.fillatt.func);
719 if (oo.indexOf(
"->-")>=0) midkind = 1;
else
720 if (oo.indexOf(
"-|>-")>=0) midkind = 11;
else
721 if (oo.indexOf(
"-<-")>=0) midkind = 2;
else
722 if (oo.indexOf(
"-<|-")>=0) midkind = 12;
725 var closed = midkind > 10;
726 if (!defs) defs = this.draw_g.append(
"defs");
727 m_mid =
"jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
729 var mid = defs.append(
"svg:marker")
731 .attr(
"markerWidth", wsize.toFixed(1))
732 .attr(
"markerHeight", (hsize*2).toFixed(1))
733 .attr(
"refX", (wsize*0.5).toFixed(1))
734 .attr(
"refY", hsize.toFixed(1))
735 .attr(
"orient",
"auto")
736 .attr(
"markerUnits",
"userSpaceOnUse")
738 .style(
"fill",
"none")
739 .attr(
"d", ((midkind % 10 == 1) ? right_arrow : left_arrow) +
740 ((midkind > 10) ?
" Z" :
""))
741 .call(this.lineatt.func);
742 if (midkind > 10) mid.call(this.fillatt.func);
745 if (oo.lastIndexOf(
">") == len-1) {
746 var closed = (oo.lastIndexOf(
"|>") == len-2) && (len>1);
747 if (!defs) defs = this.draw_g.append(
"defs");
748 m_end =
"jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
749 var end = defs.append(
"svg:marker")
751 .attr(
"markerWidth", wsize.toFixed(1))
752 .attr(
"markerHeight", (hsize*2).toFixed(1))
753 .attr(
"refX", wsize.toFixed(1))
754 .attr(
"refY", hsize.toFixed(1))
755 .attr(
"orient",
"auto")
756 .attr(
"markerUnits",
"userSpaceOnUse")
758 .style(
"fill",
"none")
759 .attr(
"d", right_arrow + (closed ?
" Z" :
""))
760 .call(this.lineatt.func);
761 if (closed) end.call(this.fillatt.func);
764 var path = this.draw_g
766 .attr(
"d",
"M" + x1.toFixed(1) +
"," + y1.toFixed(1) +
767 ((m_mid == null) ?
"" :
"L" + (x1/2+x2/2).toFixed(1) +
"," + (y1/2+y2/2).toFixed(1)) +
768 " L" + x2.toFixed(1) +
"," + y2.toFixed(1))
769 .call(this.lineatt.func);
771 if (m_start!=null) path.style(
"marker-start",
"url(#" + m_start +
")");
772 if (m_mid!=null) path.style(
"marker-mid",
"url(#" + m_mid +
")");
773 if (m_end!=null) path.style(
"marker-end",
"url(#" + m_end +
")");
776 if (!(
'arrowcnt' in JSROOT.Painter)) JSROOT.Painter.arrowcnt = 0;
779 return this.DrawingReady();
784 JSROOT.Painter.BuildSvgPath =
function(kind, bins, height, ndig) {
789 var smooth = kind.indexOf(
"bezier") >= 0;
791 if (ndig===undefined) ndig = smooth ? 2 : 0;
792 if (height===undefined) height = 0;
794 function jsroot_d3_svg_lineSlope(p0, p1) {
795 return (p1.gry - p0.gry) / (p1.grx - p0.grx);
797 function jsroot_d3_svg_lineFiniteDifferences(points) {
798 var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = jsroot_d3_svg_lineSlope(p0, p1);
800 m[i] = (d + (d = jsroot_d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
805 function jsroot_d3_svg_lineMonotoneTangents(points) {
806 var d, a, b, s, m = jsroot_d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
808 d = jsroot_d3_svg_lineSlope(points[i], points[i + 1]);
809 if (Math.abs(d) < 1e-6) {
816 s = d * 3 / Math.sqrt(s);
824 s = (points[Math.min(j, i + 1)].grx - points[Math.max(0, i - 1)].grx) / (6 * (1 + m[i] * m[i]));
825 points[i].dgrx = s || 0;
826 points[i].dgry = m[i]*s || 0;
830 var res = {}, bin = bins[0], prev, maxy = Math.max(bin.gry, height+5),
831 currx = Math.round(bin.grx), curry = Math.round(bin.gry), dx, dy;
833 res.path = ((kind.charAt(0) ==
"L") ?
"L" :
"M") +
834 bin.grx.toFixed(ndig) +
"," + bin.gry.toFixed(ndig);
837 if (smooth || kind.indexOf(
'calc')>=0)
838 jsroot_d3_svg_lineMonotoneTangents(bins);
841 res.path +=
"c" + bin.dgrx.toFixed(ndig) +
"," + bin.dgry.toFixed(ndig) +
",";
844 for(n=1; n<bins.length; ++n) {
848 if (n > 1) res.path +=
"s";
849 res.path += (bin.grx-bin.dgrx-prev.grx).toFixed(ndig) +
"," + (bin.gry-bin.dgry-prev.gry).toFixed(ndig) +
"," + (bin.grx-prev.grx).toFixed(ndig) +
"," + (bin.gry-prev.gry).toFixed(ndig);
850 maxy = Math.max(maxy, prev.gry);
852 dx = Math.round(bin.grx - currx);
853 dy = Math.round(bin.gry - curry);
854 res.path +=
"l" + dx +
"," + dy;
855 currx+=dx; curry+=dy;
856 maxy = Math.max(maxy, curry);
861 res.close =
"L" + bin.grx.toFixed(ndig) +
"," + maxy.toFixed(ndig) +
862 "L" + bins[0].grx.toFixed(ndig) +
"," + maxy.toFixed(ndig) +
"Z";
870 JSROOT.Painter.drawFunction =
function(divid, tf1, opt) {
873 this.Eval =
function(x) {
874 return this.GetObject().evalPar(x);
877 this.CreateBins =
function(ignore_zoom) {
878 var main = this.main_painter(), gxmin = 0, gxmax = 0, tf1 = this.GetObject();
880 if ((main!==null) && !ignore_zoom) {
881 if (main.zoom_xmin !== main.zoom_xmax) {
882 gxmin = main.zoom_xmin;
883 gxmax = main.zoom_xmax;
890 if (tf1.fSave.length > 0) {
893 var np = tf1.fSave.length - 2,
894 xmin = tf1.fSave[np],
895 xmax = tf1.fSave[np+1],
896 dx = (xmax - xmin) / (np-1),
899 for (var n=0; n < np; ++n) {
900 var xx = xmin + dx*n;
902 if ((gxmin !== gxmax) && ((xx + 2*dx < gxmin) || (xx - 2*dx > gxmax)))
continue;
904 res.push({ x: xx, y: tf1.fSave[n] });
909 var xmin = tf1.fXmin, xmax = tf1.fXmax, logx =
false;
911 if (gxmin !== gxmax) {
912 if (gxmin > xmin) xmin = gxmin;
913 if (gxmax < xmax) xmax = gxmax;
916 if ((main!==null) && main.options.Logx && (xmin>0) && (xmax>0)) {
918 xmin = Math.log(xmin);
919 xmax = Math.log(xmax);
922 var np = Math.max(tf1.fNpx, 101);
923 var dx = (xmax - xmin) / (np - 1);
926 for (var n=0; n < np; n++) {
927 var xx = xmin + n*dx;
928 if (logx) xx = Math.exp(xx);
929 var yy = this.Eval(xx);
930 if (!isNaN(yy)) res.push({ x : xx, y : yy });
935 this.CreateDummyHisto =
function() {
937 var xmin = 0, xmax = 1, ymin = 0, ymax = 1;
939 var bins = this.CreateBins(
true);
943 xmin = xmax = bins[0].x;
944 ymin = ymax = bins[0].y;
946 bins.forEach(
function(bin) {
947 xmin = Math.min(bin.x, xmin);
948 xmax = Math.max(bin.x, xmax);
949 ymin = Math.min(bin.y, ymin);
950 ymax = Math.max(bin.y, ymax);
953 if (ymax > 0.0) ymax *= 1.05;
954 if (ymin < 0.0) ymin *= 1.05;
957 var histo = JSROOT.Create(
"TH1I"),
958 tf1 = this.GetObject();
960 histo.fName = tf1.fName +
"_hist";
961 histo.fTitle = tf1.fTitle;
963 histo.fXaxis.fXmin = xmin;
964 histo.fXaxis.fXmax = xmax;
965 histo.fYaxis.fXmin = ymin;
966 histo.fYaxis.fXmax = ymax;
971 this.ProcessTooltipFunc =
function(pnt) {
974 if ((pnt === null) || (this.bins===null)) {
977 if ((this.bins.length==0) || (pnt.x < this.bins[0].grx) || (pnt.x >
this.bins[
this.bins.length-1].grx)) {
982 if (this.draw_g !== null)
983 this.draw_g.select(
".tooltip_bin").remove();
987 var min = 100000, best = -1, bin;
989 for(var n=0; n<this.bins.length; ++n) {
991 var dist = Math.abs(bin.grx - pnt.x);
992 if (dist < min) { min = dist; best = n; }
995 bin = this.bins[best];
997 var gbin = this.draw_g.select(
".tooltip_bin");
998 var radius = this.lineatt.width + 3;
1001 gbin = this.draw_g.append(
"svg:circle")
1002 .attr(
"class",
"tooltip_bin")
1003 .style(
"pointer-events",
"none")
1005 .call(this.lineatt.func)
1006 .call(this.fillatt.func);
1008 var res = { x: bin.grx,
1010 color1: this.lineatt.color,
1011 color2: this.fillatt.color,
1013 exact : (Math.abs(bin.grx - pnt.x) < radius) && (Math.abs(bin.gry - pnt.y) < radius) };
1015 res.changed = gbin.property(
"current_bin") !== best;
1016 res.menu = res.exact;
1017 res.menu_dist = Math.sqrt((bin.grx-pnt.x)*(bin.grx-pnt.x) + (bin.gry-pnt.y)*(bin.grx-pnt.x));
1020 gbin.attr(
"cx", bin.grx)
1021 .attr(
"cy", bin.gry)
1022 .property(
"current_bin", best);
1024 var name = this.GetTipName();
1025 if (name.length > 0) res.lines.push(name);
1027 var pmain = this.main_painter();
1029 res.lines.push(
"x = " + pmain.AxisAsText(
"x",bin.x) +
" y = " + pmain.AxisAsText(
"y",bin.y));
1034 this.Redraw =
function() {
1036 var w = this.frame_width(), h = this.frame_height(), tf1 = this.GetObject();
1038 this.RecreateDrawG(
false,
"main_layer");
1041 this.bins = this.CreateBins(
false);
1044 var pmain = this.main_painter();
1045 var name = this.GetTipName(
"\n");
1048 this.lineatt = JSROOT.Painter.createAttLine(tf1);
1049 this.lineatt.used =
false;
1051 this.fillatt = this.createAttFill(tf1, undefined, undefined, 1);
1052 this.fillatt.used =
false;
1056 for(n=0; n<this.bins.length; ++n) {
1060 bin.grx = pmain.grx(bin.x);
1061 bin.gry = pmain.gry(bin.y);
1064 if (this.bins.length > 2) {
1067 if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) {
1068 h0 = Math.round(pmain.gry(0));
1069 if ((h0 > h) || (h0 < 0)) h0 = h;
1072 var path = JSROOT.Painter.BuildSvgPath(
"bezier", this.bins, h0, 2);
1074 if (this.lineatt.color !=
"none")
1075 this.draw_g.append(
"svg:path")
1076 .attr(
"class",
"line")
1077 .attr(
"d", path.path)
1078 .style(
"fill",
"none")
1079 .call(this.lineatt.func);
1081 if (this.fillatt.color !=
"none")
1082 this.draw_g.append(
"svg:path")
1083 .attr(
"class",
"area")
1084 .attr(
"d", path.path + path.close)
1085 .style(
"stroke",
"none")
1086 .call(this.fillatt.func);
1089 delete this.ProcessTooltip;
1091 if (JSROOT.gStyle.Tooltip > 0)
1092 this.ProcessTooltip = this.ProcessTooltipFunc;
1095 this.CanZoomIn =
function(axis,min,max) {
1096 if (axis!==
"x")
return false;
1098 var tf1 = this.GetObject();
1100 if (tf1.fSave.length > 0) {
1103 var nb_points = tf1.fNpx;
1105 var xmin = tf1.fSave[nb_points + 1];
1106 var xmax = tf1.fSave[nb_points + 2];
1108 return Math.abs(xmin - xmax) / nb_points < Math.abs(min - max);
1115 this.SetDivId(divid, -1);
1116 if (this.main_painter() === null) {
1117 var histo = this.CreateDummyHisto();
1118 JSROOT.Painter.drawHistogram1D(divid, histo,
"AXIS");
1120 this.SetDivId(divid);
1122 return this.DrawingReady();
1127 JSROOT.Painter.drawHStack =
function(divid, stack, opt) {
1134 this.nostack =
false;
1135 this.firstpainter = null;
1136 this.painters =
new Array;
1138 this.SetDivId(divid);
1140 if (!(
'fHists' in stack) || (stack.fHists.arr.length == 0))
return this.DrawingReady();
1142 this[
'BuildStack'] =
function() {
1146 var stack = this.GetObject();
1148 if (!(
'fHists' in stack))
return false;
1149 var nhists = stack.fHists.arr.length;
1150 if (nhists <= 0)
return false;
1151 var lst = JSROOT.Create(
"TList");
1152 lst.Add(JSROOT.clone(stack.fHists.arr[0]));
1153 for (var i=1;i<nhists;++i) {
1154 var hnext = JSROOT.clone(stack.fHists.arr[i]);
1155 var hprev = lst.arr[i-1];
1157 if ((hnext.fNbins != hprev.fNbins) ||
1158 (hnext.fXaxis.fXmin != hprev.fXaxis.fXmin) ||
1159 (hnext.fXaxis.fXmax != hprev.fXaxis.fXmax)) {
1160 JSROOT.console(
"When drawing THStack, cannot sum-up histograms " + hnext.fName +
" and " + hprev.fName);
1167 for (var n = 0; n < hnext.fArray.length; ++n)
1168 hnext.fArray[n] += hprev.fArray[n];
1176 this[
'GetHistMinMax'] =
function(hist, witherr) {
1177 var res = { min : 0, max : 0 };
1178 var domin =
false, domax =
false;
1179 if (hist.fMinimum != -1111)
1180 res.min = hist.fMinimum;
1183 if (hist.fMaximum != -1111)
1184 res.max = hist.fMaximum;
1188 if (domin || domax) {
1189 var left = 1, right = hist.fXaxis.fNbins;
1191 if (hist.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) {
1192 left = hist.fXaxis.fFirst;
1193 right = hist.fXaxis.fLast;
1195 for (var bin = left; bin<=right; ++bin) {
1196 var val = hist.getBinContent(bin);
1197 var err = witherr ? hist.getBinError(bin) : 0;
1198 if (domin && ((bin==left) || (val-err < res.min))) res.min = val-err;
1199 if (domax && ((bin==left) || (val+err > res.max))) res.max = val+err;
1206 this[
'GetMinMax'] =
function(opt) {
1207 var res = { min : 0, max : 0 },
1208 iserr = (opt.indexOf(
'e')>=0),
1209 stack = this.GetObject();
1212 for (var i = 0; i < stack.fHists.arr.length; ++i) {
1213 var resh = this.GetHistMinMax(stack.fHists.arr[i], iserr);
1214 if (i==0) res = resh;
else {
1215 if (resh.min < res.min) res.min = resh.min;
1216 if (resh.max > res.max) res.max = resh.max;
1220 if (stack.fMaximum != -1111)
1221 res.max = stack.fMaximum;
1225 if (stack.fMinimum != -1111) res.min = stack.fMinimum;
1227 res.min = this.GetHistMinMax(stack.fStack.arr[0], iserr).min;
1228 res.max = this.GetHistMinMax(stack.fStack.arr[stack.fStack.arr.length-1], iserr).max * 1.05;
1231 var pad = this.root_pad();
1232 if ((pad!=null) && (pad.fLogy > 0)) {
1233 if (res.min<0) res.min = res.max * 1e-4;
1239 this[
'DrawNextHisto'] =
function(indx, opt) {
1241 stack = this.GetObject(),
1242 nhists = stack.fHists.arr.length;
1244 if (indx>=nhists)
return this.DrawingReady();
1246 if (indx<0) hist = stack.fHistogram;
else
1247 if (this.nostack) hist = stack.fHists.arr[indx];
1248 else hist = stack.fStack.arr[nhists - indx - 1];
1250 var hopt = hist.fOption;
1251 if ((opt !=
"") && (hopt.indexOf(opt) == -1)) hopt += opt;
1252 if (indx>=0) hopt +=
"same";
1253 var subp = JSROOT.draw(this.divid, hist, hopt);
1254 if (indx<0) this.firstpainter = subp;
1255 else this.painters.push(subp);
1256 subp.WhenReady(this.DrawNextHisto.bind(
this, indx+1, opt));
1259 this[
'drawStack'] =
function(opt) {
1260 var pad = this.root_pad(),
1261 stack = this.GetObject(),
1262 histos = stack.fHists,
1263 nhists = histos.arr.length;
1265 if (opt == null) opt =
"";
1266 else opt = opt.toLowerCase();
1269 if (opt.indexOf(
"same") != -1) {
1271 opt.replace(
"same",
"");
1273 this.nostack = opt.indexOf(
"nostack") < 0 ?
false :
true;
1277 this.nostack = ! this.BuildStack();
1279 var mm = this.GetMinMax(opt);
1281 if (stack.fHistogram === null) {
1283 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
1284 for (var i = 0; i < nhists; ++i) {
1285 var h = histos.arr[i];
1286 if (i == 0 || h.fXaxis.fXmin < xmin)
1287 xmin = h.fXaxis.fXmin;
1288 if (i == 0 || h.fXaxis.fXmax > xmax)
1289 xmax = h.fXaxis.fXmax;
1290 if (i == 0 || h.fYaxis.fXmin < ymin)
1291 ymin = h.fYaxis.fXmin;
1292 if (i == 0 || h.fYaxis.fXmax > ymax)
1293 ymax = h.fYaxis.fXmax;
1296 var h = stack.fHists.arr[0];
1297 stack.fHistogram = JSROOT.Create(
"TH1I");
1298 stack.fHistogram.fName =
"unnamed";
1299 stack.fHistogram.fXaxis = JSROOT.clone(h.fXaxis);
1300 stack.fHistogram.fYaxis = JSROOT.clone(h.fYaxis);
1301 stack.fHistogram.fXaxis.fXmin = xmin;
1302 stack.fHistogram.fXaxis.fXmax = xmax;
1303 stack.fHistogram.fYaxis.fXmin = ymin;
1304 stack.fHistogram.fYaxis.fXmax = ymax;
1306 stack.fHistogram.fTitle = stack.fTitle;
1307 var histo = stack.fHistogram;
1308 if (!histo.TestBit(JSROOT.TH1StatusBits.kIsZoomed)) {
1309 if (pad && pad.fLogy)
1310 histo.fMaximum = mm.max * (1 + 0.2 * JSROOT.log10(mm.max / mm.min));
1312 histo.fMaximum = mm.max;
1313 if (pad && pad.fLogy)
1314 histo.fMinimum = mm.min / (1 + 0.5 * JSROOT.log10(mm.max / mm.min));
1316 histo.fMinimum = mm.min;
1319 this.DrawNextHisto(!lsame ? -1 : 0, opt);
1323 this[
'UpdateObject'] =
function(obj) {
1324 if (!this.MatchObjectType(obj))
return false;
1327 if (this.firstpainter)
1328 if (this.firstpainter.UpdateObject(obj.fHistogram)) isany =
true;
1330 var nhists = obj.fHists.arr.length;
1331 for (var i = 0; i < nhists; ++i) {
1332 var hist = this.nostack ? obj.fHists.arr[i] : obj.fStack.arr[nhists - i - 1];
1333 if (this.painters[i].UpdateObject(hist)) isany =
true;
1339 return this.drawStack(opt);
1344 JSROOT.TGraphPainter =
function(graph) {
1345 JSROOT.TObjectPainter.call(
this, graph);
1346 this.ownhisto =
false;
1348 this.xmin = this.ymin = this.xmax = this.ymax = 0;
1351 JSROOT.TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
1353 JSROOT.TGraphPainter.prototype.Redraw =
function() {
1357 JSROOT.TGraphPainter.prototype.DecodeOptions =
function(opt) {
1358 this.draw_all =
true;
1359 JSROOT.extend(
this, { optionLine:0, optionAxis:0, optionCurve:0, optionRect:0,
1360 optionMark:0, optionBar:0, optionR:0, optionE:0, optionEF:0,
1361 optionFill:0, optionZ:0, optionBrackets:0,
1362 opt:
"LP", out_of_range:
false, has_errors:
false, draw_errors:
false, is_bent:
false });
1364 var graph = this.GetObject();
1366 this.is_bent = graph._typename ==
'TGraphBentErrors';
1367 this.has_errors = (graph._typename ==
'TGraphErrors' ||
1368 graph._typename ==
'TGraphAsymmErrors' ||
1369 this.is_bent || graph._typename.match(/^RooHist/));
1370 this.draw_errors = this.has_errors;
1372 if ((opt != null) && (opt !=
"")) {
1373 this.opt = opt.toUpperCase();
1374 this.opt.replace(
'SAME',
'');
1376 if (this.opt.indexOf(
'L') != -1)
1377 this.optionLine = 1;
1378 if (this.opt.indexOf(
'F') != -1)
1379 this.optionFill = 1;
1380 if (this.opt.indexOf(
'A') != -1)
1381 this.optionAxis = 1;
1382 if (this.opt.indexOf(
'C') != -1) {
1383 this.optionCurve = 1;
1384 if (this.optionFill==0) this.optionLine = 1;
1386 if (this.opt.indexOf(
'*') != -1)
1387 this.optionMark = 2;
1388 if (this.opt.indexOf(
'P') != -1)
1389 this.optionMark = 1;
1390 if (this.opt.indexOf(
'B') != -1) {
1392 this.draw_errors =
false;
1394 if (this.opt.indexOf(
'R') != -1)
1397 if (this.opt.indexOf(
'[]') != -1) {
1398 this.optionBrackets = 1;
1399 this.draw_errors =
false;
1402 if (this.opt.indexOf(
'0') != -1) {
1403 this.optionMark = 1;
1404 this.draw_errors =
true;
1405 this.out_of_range =
true;
1408 if (this.opt.indexOf(
'1') != -1) {
1409 if (this.optionBar == 1) this.optionBar = 2;
1411 if (this.opt.indexOf(
'2') != -1)
1412 this.optionRect = 1;
1414 if (this.opt.indexOf(
'3') != -1) {
1416 this.optionLine = 0;
1417 this.draw_errors =
false;
1419 if (this.opt.indexOf(
'4') != -1) {
1421 this.optionLine = 0;
1422 this.draw_errors =
false;
1425 if (this.opt.indexOf(
'2') != -1 || this.opt.indexOf(
'5') != -1) this.optionE = 1;
1428 if ((this.optionMark==1) && (graph.fMarkerStyle==1)) this.optionMark = 3;
1431 if (this.optionLine + this.optionFill + this.optionMark + this.optionBar + this.optionE +
1432 this.optionEF + this.optionRect + this.optionBrackets == 0) {
1433 if (this.opt.length == 0)
1434 this.optionLine = 1;
1437 if (graph._typename ==
'TGraphErrors') {
1438 var maxEX = d3.max(graph.fEX);
1439 var maxEY = d3.max(graph.fEY);
1440 if (maxEX < 1.0e-300 && maxEY < 1.0e-300)
1441 this.draw_errors =
false;
1445 JSROOT.TGraphPainter.prototype.CreateBins =
function() {
1446 var gr = this.GetObject();
1447 if (gr===null)
return;
1449 var p, kind = 0, npoints = gr.fNpoints;
1450 if ((gr._typename===
"TCutG") && (npoints>3)) npoints--;
1452 if (gr._typename ==
'TGraphErrors') kind = 1;
else
1453 if (gr._typename ==
'TGraphAsymmErrors' || gr._typename ==
'TGraphBentErrors'
1454 || gr._typename.match(/^RooHist/)) kind = 2;
1458 for (p=0;p<npoints;++p) {
1459 var bin = { x: gr.fX[p], y: gr.fY[p] };
1461 bin.exlow = bin.exhigh = gr.fEX[p];
1462 bin.eylow = bin.eyhigh = gr.fEY[p];
1465 bin.exlow = gr.fEXlow[p];
1466 bin.exhigh = gr.fEXhigh[p];
1467 bin.eylow = gr.fEYlow[p];
1468 bin.eyhigh = gr.fEYhigh[p];
1470 this.bins.push(bin);
1473 this.xmin = this.xmax = bin.x;
1474 this.ymin = this.ymax = bin.y;
1478 this.xmin = Math.min(this.xmin, bin.x - bin.exlow, bin.x + bin.exhigh);
1479 this.xmax = Math.max(this.xmax, bin.x - bin.exlow, bin.x + bin.exhigh);
1480 this.ymin = Math.min(this.ymin, bin.y - bin.eylow, bin.y + bin.eyhigh);
1481 this.ymax = Math.max(this.ymax, bin.y - bin.eylow, bin.y + bin.eyhigh);
1483 this.xmin = Math.min(this.xmin, bin.x);
1484 this.xmax = Math.max(this.xmax, bin.x);
1485 this.ymin = Math.min(this.ymin, bin.y);
1486 this.ymax = Math.max(this.ymax, bin.y);
1492 JSROOT.TGraphPainter.prototype.CreateHistogram =
function() {
1495 var xmin = this.xmin, xmax = this.xmax, ymin = this.ymin, ymax = this.ymax;
1497 if (xmin >= xmax) xmax = xmin+1;
1498 if (ymin >= ymax) ymax = ymin+1;
1499 var dx = (xmax-xmin)*0.1, dy = (ymax-ymin)*0.1,
1500 uxmin = xmin - dx, uxmax = xmax + dx,
1501 minimum = ymin - dy, maximum = ymax + dy;
1503 if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.9;
1504 if ((uxmax>0) && (xmax<=0)) uxmax = 0;
1506 var graph = this.GetObject();
1508 if (graph.fMinimum != -1111) minimum = ymin = graph.fMinimum;
1509 if (graph.fMaximum != -1111) maximum = ymax = graph.fMaximum;
1510 if ((minimum < 0) && (ymin >=0)) minimum = 0.9*ymin;
1512 var histo = JSROOT.CreateTH1(100);
1513 histo.fName = graph.fName +
"_h";
1514 histo.fTitle = graph.fTitle;
1515 histo.fXaxis.fXmin = uxmin;
1516 histo.fXaxis.fXmax = uxmax;
1517 histo.fYaxis.fXmin = minimum;
1518 histo.fYaxis.fXmax = maximum;
1519 histo.fMinimum = minimum;
1520 histo.fMaximum = maximum;
1521 histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats;
1525 JSROOT.TGraphPainter.prototype.OptimizeBins =
function(filter_func) {
1526 if ((this.bins.length < 30) && !filter_func)
return this.bins;
1529 if (typeof filter_func ==
'function') {
1530 for (var n = 0; n < this.bins.length; ++n) {
1531 if (filter_func(this.bins[n],n)) {
1533 selbins = (n==0) ? [] : this.bins.slice(0, n);
1535 if (selbins != null) selbins.push(this.bins[n]);
1539 if (selbins == null) selbins = this.bins;
1541 if ((selbins.length < 5000) || (JSROOT.gStyle.OptimizeDraw == 0))
return selbins;
1542 var step = Math.floor(selbins.length / 5000);
1543 if (step < 2) step = 2;
1545 for (var n = 0; n < selbins.length; n+=step)
1546 optbins.push(selbins[n]);
1551 JSROOT.TGraphPainter.prototype.TooltipText =
function(d, asarray) {
1552 var pmain = this.main_painter(), lines = [];
1554 lines.push(this.GetTipName());
1555 lines.push(
"x = " + pmain.AxisAsText(
"x", d.x));
1556 lines.push(
"y = " + pmain.AxisAsText(
"y", d.y));
1558 if (this.draw_errors && (pmain.x_kind==
'normal') && (
'exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0)))
1559 lines.push(
"error x = -" + pmain.AxisAsText(
"x", d.exlow) +
1560 "/+" + pmain.AxisAsText(
"x", d.exhigh));
1562 if ((this.draw_errors || (this.optionEF > 0)) && (pmain.y_kind==
'normal') && (
'eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0)) )
1563 lines.push(
"error y = -" + pmain.AxisAsText(
"y", d.eylow) +
1564 "/+" + pmain.AxisAsText(
"y", d.eyhigh));
1566 if (asarray)
return lines;
1569 for (var n=0;n<lines.length;++n) res += ((n>0 ?
"\n" :
"") + lines[n]);
1573 JSROOT.TGraphPainter.prototype.DrawBins =
function() {
1575 this.RecreateDrawG(
false,
"main_layer");
1578 pmain = this.main_painter(),
1579 w = this.frame_width(),
1580 h = this.frame_height(),
1581 graph = this.GetObject(),
1585 this.lineatt = JSROOT.Painter.createAttLine(graph, undefined,
true);
1587 this.fillatt = this.createAttFill(graph, undefined, undefined, 1);
1588 this.fillatt.used =
false;
1590 if (this.fillatt) this.fillatt.used =
false;
1591 this.draw_kind =
"none";
1592 this.marker_size = 0;
1594 if (this.lineatt.excl_side!=0) {
1595 excl_width = this.lineatt.excl_side * this.lineatt.excl_width;
1596 if (this.lineatt.width>0) this.optionLine = 1;
1599 var drawbins = null;
1601 if (this.optionEF > 0) {
1603 drawbins = this.OptimizeBins();
1606 for (var n=0;n<drawbins.length;++n) {
1607 var bin = drawbins[n];
1608 bin.grx = pmain.grx(bin.x);
1609 bin.gry = pmain.gry(bin.y - bin.eylow);
1612 var path1 = JSROOT.Painter.BuildSvgPath(this.optionEF > 1 ?
"bezier" :
"line", drawbins),
1615 for (var n=drawbins.length-1;n>=0;--n) {
1616 var bin = drawbins[n];
1617 bin.gry = pmain.gry(bin.y + bin.eyhigh);
1622 var path2 = JSROOT.Painter.BuildSvgPath(this.optionEF > 1 ?
"Lbezier" :
"Lline", bins2);
1624 this.draw_g.append(
"svg:path")
1625 .attr(
"d", path1.path + path2.path +
"Z")
1626 .style(
"stroke",
"none")
1627 .call(this.fillatt.func);
1628 this.draw_kind =
"lines";
1631 if (this.optionLine == 1 || this.optionFill == 1 || (excl_width!==0)) {
1633 var close_symbol =
"";
1634 if (graph._typename==
"TCutG") this.optionFill = 1;
1636 if (this.optionFill == 1) {
1641 if (drawbins===null) drawbins = this.OptimizeBins();
1643 for (var n=0;n<drawbins.length;++n) {
1644 var bin = drawbins[n];
1645 bin.grx = pmain.grx(bin.x);
1646 bin.gry = pmain.gry(bin.y);
1650 if (this.optionCurve === 1) kind =
"bezier";
else
1651 if (excl_width!==0) kind+=
"calc";
1653 var path = JSROOT.Painter.BuildSvgPath(kind, drawbins);
1655 if (excl_width!==0) {
1657 for (var n=drawbins.length-1;n>=0;--n) {
1658 var bin = drawbins[n];
1659 var dlen = Math.sqrt(bin.dgrx*bin.dgrx + bin.dgry*bin.dgry);
1661 bin.grx += excl_width*bin.dgry/dlen;
1662 bin.gry -= excl_width*bin.dgrx/dlen;
1663 extrabins.push(bin);
1666 var path2 = JSROOT.Painter.BuildSvgPath(
"L" + ((this.optionCurve === 1) ?
"bezier" :
"line"), extrabins);
1668 this.draw_g.append(
"svg:path")
1669 .attr(
"d", path.path + path2.path +
"Z")
1670 .style(
"stroke",
"none")
1671 .call(this.fillatt.func)
1672 .style(
'opacity', 0.75);
1675 if (this.optionLine || this.optionFill) {
1676 var elem = this.draw_g.append(
"svg:path")
1677 .attr(
"d", path.path + close_symbol);
1678 if (this.optionLine)
1679 elem.call(this.lineatt.func);
1681 elem.style(
'stroke',
'none');
1683 if (this.optionFill > 0)
1684 elem.call(this.fillatt.func);
1686 elem.style(
'fill',
'none');
1689 this.draw_kind =
"lines";
1694 if (this.draw_errors || this.optionRect || this.optionBrackets || this.optionBar) {
1696 drawbins = this.OptimizeBins(
function(pnt,i) {
1698 var grx = pmain.grx(pnt.x);
1701 if (!pthis.optionBar && ((grx<0) || (grx>w)))
return true;
1703 var gry = pmain.gry(pnt.y);
1705 if (!pthis.optionBar && !pthis.out_of_range && ((gry<0) || (gry>h)))
return true;
1707 pnt.grx1 = Math.round(grx);
1708 pnt.gry1 = Math.round(gry);
1710 if (pthis.has_errors) {
1711 pnt.grx0 = Math.round(pmain.grx(pnt.x - pnt.exlow) - grx);
1712 pnt.grx2 = Math.round(pmain.grx(pnt.x + pnt.exhigh) - grx);
1713 pnt.gry0 = Math.round(pmain.gry(pnt.y - pnt.eylow) - gry);
1714 pnt.gry2 = Math.round(pmain.gry(pnt.y + pnt.eyhigh) - gry);
1716 if (pthis.is_bent) {
1717 pnt.grdx0 = Math.round(pmain.gry(pnt.y + graph.fEXlowd[i]) - gry);
1718 pnt.grdx2 = Math.round(pmain.gry(pnt.y + graph.fEXhighd[i]) - gry);
1719 pnt.grdy0 = Math.round(pmain.grx(pnt.x + graph.fEYlowd[i]) - grx);
1720 pnt.grdy2 = Math.round(pmain.grx(pnt.x + graph.fEYhighd[i]) - grx);
1722 pnt.grdx0 = pnt.grdx2 = pnt.grdy0 = pnt.grdy2 = 0;
1729 this.draw_kind =
"nodes";
1732 nodes = this.draw_g.selectAll(
".grpoint")
1736 .attr(
"class",
"grpoint")
1737 .attr(
"transform",
function(d) {
return "translate(" + d.grx1 +
"," + d.gry1 +
")"; });
1740 if (this.optionBar) {
1742 for (var i=1;i<drawbins.length-1;++i)
1743 drawbins[i].width = Math.max(2, (drawbins[i+1].grx1 - drawbins[i-1].grx1) / 2 - 2);
1746 switch (drawbins.length) {
1748 case 1: drawbins[0].width = w/4;
break;
1749 case 2: drawbins[0].width = drawbins[1].width = (drawbins[1].grx1-drawbins[0].grx1)/2;
break;
1751 drawbins[0].width = drawbins[1].width;
1752 drawbins[drawbins.length-1].width = drawbins[drawbins.length-2].width;
1755 var yy0 = Math.round(pmain.gry(0));
1757 nodes.append(
"svg:rect")
1758 .attr(
"x",
function(d) {
return Math.round(-d.width/2); })
1759 .attr(
"y",
function(d) {
1761 if (pthis.optionBar!==1)
return 0;
1762 return (d.gry1 > yy0) ? yy0-d.gry1 : 0;
1764 .attr(
"width",
function(d) {
return Math.round(d.width); })
1765 .attr(
"height",
function(d) {
1766 if (pthis.optionBar!==1)
return h > d.gry1 ? h - d.gry1 : 0;
1767 return Math.abs(yy0 - d.gry1);
1769 .call(this.fillatt.func);
1772 if (this.optionRect)
1773 nodes.filter(
function(d) {
return (d.exlow > 0) && (d.exhigh > 0) && (d.eylow > 0) && (d.eyhigh > 0); })
1775 .attr(
"x",
function(d) { d.rect =
true;
return d.grx0; })
1776 .attr(
"y",
function(d) {
return d.gry2; })
1777 .attr(
"width",
function(d) {
return d.grx2 - d.grx0; })
1778 .attr(
"height",
function(d) {
return d.gry0 - d.gry2; })
1779 .call(this.fillatt.func);
1781 if (this.optionBrackets) {
1782 nodes.filter(
function(d) {
return (d.eylow > 0) || (d.eyhigh > 0); })
1784 .call(this.lineatt.func)
1785 .style(
'fill',
"none")
1786 .attr(
"d",
function(d) {
1788 return ((d.eylow > 0) ?
"M-5,"+(d.gry0-3)+
"v3h10v-3" :
"") +
1789 ((d.eyhigh > 0) ?
"M-5,"+(d.gry2+3)+
"v-3h10v3" :
"");
1793 if (this.draw_errors) {
1795 var lw = this.lineatt.width + JSROOT.gStyle.EndErrorSize,
1796 vv =
"m0," + lw +
"v-" + 2*lw,
1797 hh =
"m" + lw +
",0h-" + 2*lw;
1798 lw = Math.floor((this.lineatt.width-1)/2);
1799 nodes.filter(
function(d) {
return (d.exlow > 0) || (d.exhigh > 0) || (d.eylow > 0) || (d.eyhigh > 0); })
1801 .call(this.lineatt.func)
1802 .style(
'fill',
"none")
1803 .attr(
"d",
function(d) {
1805 return ((d.exlow > 0) ?
"M0,0L"+(d.grx0+lw)+
","+d.grdx0+vv :
"") +
1806 ((d.exhigh > 0) ?
"M0,0L"+(d.grx2-lw)+
","+d.grdx2+vv :
"") +
1807 ((d.eylow > 0) ?
"M0,0L"+d.grdy0+
","+(d.gry0-lw)+hh :
"") +
1808 ((d.eyhigh > 0) ?
"M0,0L"+d.grdy2+
","+(d.gry2+lw)+hh :
"");
1812 if (this.optionMark > 0) {
1814 var step = Math.max(1, Math.round(
this.bins.length / 50000)),
1815 path =
"", n, pnt, grx, gry, marker_kind;
1817 if (this.optionMark==2) marker_kind = 3;
else
1818 if (this.optionMark==3) marker_kind = 1;
1820 if (!this.markeratt)
1821 this.markeratt = JSROOT.Painter.createAttMarker(graph,marker_kind);
1823 this.markeratt.Change(undefined, marker_kind);
1825 this.marker_size = this.markeratt.size;
1827 this.markeratt.reset_pos();
1829 for (n=0;n<this.bins.length;n+=step) {
1831 grx = pmain.grx(pnt.x);
1832 if ((grx > -this.marker_size) && (grx < w+this.marker_size)) {
1833 gry = pmain.gry(pnt.y);
1834 if ((gry >-this.marker_size) && (gry < h+this.marker_size)) {
1835 path += this.markeratt.create(grx, gry);
1840 if (path.length>0) {
1841 this.draw_g.append(
"svg:path")
1843 .call(this.markeratt.func);
1844 if ((nodes===null) && (this.draw_kind==
"none"))
1845 this.draw_kind = (this.optionMark==3) ?
"path" :
"mark";
1850 JSROOT.TGraphPainter.prototype.ProcessTooltip =
function(pnt) {
1852 if (this.draw_g !== null)
1853 this.draw_g.select(
".tooltip_bin").remove();
1857 if ((this.draw_kind==
"lines") || (this.draw_kind==
"path") || (this.draw_kind==
"mark"))
1858 return this.ProcessTooltipForPath(pnt);
1860 if (this.draw_kind!=
"nodes")
return null;
1862 var width = this.frame_width(),
1863 height = this.frame_height(),
1864 pmain = this.main_painter(),
1866 findbin = null, best_dist2 = 1e10, best = null;
1868 this.draw_g.selectAll(
'.grpoint').each(
function() {
1869 var d = d3.select(
this).datum();
1870 if (d===undefined)
return;
1871 var dist2 = Math.pow(pnt.x - d.grx1, 2);
1872 if (pnt.nproc===1) dist2 += Math.pow(pnt.y - d.gry1, 2);
1873 if (dist2 >= best_dist2)
return;
1877 if (d.error || d.rect || d.marker || d.bracket) {
1878 rect = { x1: Math.min(-3, d.grx0), x2: Math.max(3, d.grx2), y1: Math.min(-3, d.gry2), y2: Math.max(3, d.gry0) };
1879 if (d.bracket) { rect.x1 = -5; rect.x2 = 5; }
1882 rect = { x1: -d.width/2, x2: d.width/2, y1: 0, y2: height - d.gry1 };
1884 if (painter.optionBar===1) {
1885 var yy0 = pmain.gry(0);
1886 rect.y1 = (d.gry1 > yy0) ? yy0-d.gry1 : 0;
1887 rect.y2 = (d.gry1 > yy0) ? 0 : yy0-d.gry1;
1890 rect = { x1: -5, x2: 5, y1: -5, y2: 5 };
1892 var matchx = (pnt.x >= d.grx1 + rect.x1) && (pnt.x <= d.grx1 + rect.x2);
1893 var matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2);
1895 if (matchx && (matchy || (pnt.nproc > 1))) {
1899 best.exact = matchx && matchy;
1903 var ttrect = this.draw_g.select(
".tooltip_bin");
1905 if (findbin == null) {
1910 var d = d3.select(findbin).datum();
1912 var res = { x: d.grx1, y: d.gry1,
1913 color1: this.lineatt.color,
1914 lines: this.TooltipText(d,
true) };
1915 if (this.fillatt && this.fillatt.used) res.color2 = this.fillatt.color;
1917 if (best.exact) res.exact =
true;
1918 res.menu = res.exact;
1922 ttrect = this.draw_g.append(
"svg:rect")
1923 .attr(
"class",
"tooltip_bin h1bin")
1924 .style(
"pointer-events",
"none");
1926 res.changed = ttrect.property(
"current_bin") !== findbin;
1929 ttrect.attr(
"x", d.grx1 + best.x1)
1930 .attr(
"width", best.x2 - best.x1)
1931 .attr(
"y", d.gry1 + best.y1)
1932 .attr(
"height", best.y2 - best.y1)
1933 .style(
"opacity",
"0.3")
1934 .property(
"current_bin", findbin);
1939 JSROOT.TGraphPainter.prototype.ProcessTooltipForPath =
function(pnt) {
1941 if (this.bins === null)
return null;
1943 var islines = (this.draw_kind==
"lines"),
1944 ismark = (this.draw_kind==
"mark"),
1947 pmain = this.main_painter(),
1948 dist, grx, gry, n, bin;
1950 for (n=0;n<this.bins.length;++n) {
1953 grx = pmain.grx(bin.x);
1957 if ((n==0) && (dist < -10)) { bestbin = null;
break; }
1959 gry = pmain.gry(bin.y);
1960 dist = dist*dist + (pnt.y-gry)*(pnt.y-gry);
1963 if (Math.abs(dist) < bestdist) {
1970 if ((dist > 10) && islines) bestbin = null;
1972 var radius = Math.max(this.lineatt.width + 3, 4);
1974 if (this.marker_size > 0) radius = Math.max(Math.round(
this.marker_size*7), radius);
1976 if (bestbin !== null)
1977 bestdist = Math.sqrt(Math.pow(pnt.x-pmain.grx(bestbin.x),2) + Math.pow(pnt.y-pmain.gry(bestbin.y),2));
1981 if (!islines && !ismark && (bestdist>radius)) bestbin = null;
1983 if (ismark && (bestbin!==null)) {
1984 if ((pnt.nproc == 1) && (bestdist>radius)) bestbin = null;
else
1985 if ((this.bins.length==1) && (bestdist>3*radius)) bestbin = null;
1988 var ttbin = this.draw_g.select(
".tooltip_bin");
1990 if (bestbin===null) {
1995 var res = { x: pmain.grx(bestbin.x), y: pmain.gry(bestbin.y),
1996 color1: this.lineatt.color,
1997 lines: this.TooltipText(bestbin,
true) };
1999 if (this.fillatt && this.fillatt.used) res.color2 = this.fillatt.color;
2002 res.color1 = JSROOT.Painter.root_colors[this.GetObject().fMarkerColor];
2003 if (!res.color2) res.color2 = res.color1;
2007 ttbin = this.draw_g.append(
"svg:g")
2008 .attr(
"class",
"tooltip_bin");
2012 if ((this.optionEF > 0) && islines) {
2013 gry1 = pmain.gry(bestbin.y - bestbin.eylow);
2014 gry2 = pmain.gry(bestbin.y + bestbin.eyhigh);
2016 gry1 = gry2 = pmain.gry(bestbin.y);
2019 res.exact = (Math.abs(pnt.x - res.x) <= radius) &&
2020 ((Math.abs(pnt.y - gry1) <= radius) || (Math.abs(pnt.y - gry2) <= radius));
2022 res.menu = res.exact;
2023 res.menu_dist = Math.sqrt((pnt.x-res.x)*(pnt.x-res.x) + Math.pow(Math.min(Math.abs(pnt.y-gry1),Math.abs(pnt.y-gry2)),2));
2025 res.changed = ttbin.property(
"current_bin") !== bestbin;
2028 ttbin.selectAll(
"*").remove();
2029 ttbin.property(
"current_bin", bestbin);
2032 ttbin.append(
"svg:rect")
2033 .attr(
"class",
"h1bin")
2034 .style(
"pointer-events",
"none")
2035 .style(
"opacity",
"0.3")
2036 .attr(
"x", (res.x - radius).toFixed(1))
2037 .attr(
"y", (res.y - radius).toFixed(1))
2038 .attr(
"width", (2*radius).toFixed(1))
2039 .attr(
"height", (2*radius).toFixed(1));
2041 ttbin.append(
"svg:circle").attr(
"cy", gry1.toFixed(1))
2042 if (Math.abs(gry1-gry2) > 1)
2043 ttbin.append(
"svg:circle").attr(
"cy", gry2.toFixed(1));
2045 var elem = ttbin.selectAll(
"circle")
2047 .attr(
"cx", res.x.toFixed(1));
2050 elem.style(
'stroke', res.color1 ==
'black' ?
'green' :
'black').style(
'fill',
'none');
2052 if (this.optionLine)
2053 elem.call(this.lineatt.func);
2055 elem.style(
'stroke',
'black');
2056 if (this.optionFill > 0)
2057 elem.call(this.fillatt.func);
2059 elem.style(
'fill',
'none');
2067 JSROOT.TGraphPainter.prototype.UpdateObject =
function(obj) {
2068 if (!this.MatchObjectType(obj))
return false;
2072 this.main_painter().UpdateObject(obj.fHistogram);
2074 var graph = this.GetObject();
2078 graph.fNpoints = obj.fNpoints;
2083 JSROOT.TGraphPainter.prototype.CanZoomIn =
function(axis,min,max) {
2086 var gr = this.GetObject();
2087 if ((gr===null) || (axis!==
"x"))
return false;
2089 for (var n=0; n < gr.fNpoints; ++n)
2090 if ((min < gr.fX[n]) && (gr.fX[n] < max))
return true;
2095 JSROOT.TGraphPainter.prototype.ButtonClick =
function(funcname) {
2097 if (funcname !==
"ToggleZoom")
return false;
2099 var main = this.main_painter();
2100 if (main === null)
return false;
2102 if ((this.xmin===this.xmax) && (this.ymin = this.ymax))
return false;
2104 main.Zoom(this.xmin, this.xmax, this.ymin, this.ymax);
2110 JSROOT.TGraphPainter.prototype.DrawNextFunction =
function(indx, callback) {
2113 var graph = this.GetObject();
2115 if ((graph.fFunctions === null) || (indx >= graph.fFunctions.arr.length))
2116 return JSROOT.CallBack(callback);
2118 var func = graph.fFunctions.arr[indx];
2119 var opt = graph.fFunctions.opt[indx];
2121 var painter = JSROOT.draw(this.divid, func, opt);
2122 if (painter)
return painter.WhenReady(this.DrawNextFunction.bind(
this, indx+1, callback));
2124 this.DrawNextFunction(indx+1, callback);
2127 JSROOT.Painter.drawGraph =
function(divid, graph, opt) {
2128 JSROOT.extend(
this,
new JSROOT.TGraphPainter(graph));
2132 this.SetDivId(divid, -1);
2134 if (this.main_painter() == null) {
2135 if (graph.fHistogram == null)
2136 graph.fHistogram = this.CreateHistogram();
2137 JSROOT.Painter.drawHistogram1D(divid, graph.fHistogram,
"AXIS");
2138 this.ownhisto =
true;
2141 this.SetDivId(divid);
2142 this.DecodeOptions(opt);
2145 this.DrawNextFunction(0, this.DrawingReady.bind(
this));
2152 JSROOT.Painter.drawMultiGraph =
function(divid, mgraph, opt) {
2155 this.firstpainter = null;
2156 this.autorange =
false;
2159 this.SetDivId(divid, -1);
2161 this.UpdateObject =
function(obj) {
2162 if (!this.MatchObjectType(obj))
return false;
2164 var mgraph = this.GetObject(),
2165 graphs = obj.fGraphs;
2167 mgraph.fTitle = obj.fTitle;
2170 if (this.firstpainter) {
2171 var histo = obj.fHistogram;
2172 if (this.autorange && (histo == null))
2173 histo = this.ScanGraphsRange(graphs);
2174 if (this.firstpainter.UpdateObject(histo)) isany =
true;
2177 for (var i = 0; i < graphs.arr.length; ++i) {
2178 if (i<this.painters.length)
2179 if (this.painters[i].UpdateObject(graphs.arr[i])) isany =
true;
2185 this.ComputeGraphRange =
function(res, gr) {
2187 if (gr.fNpoints == 0)
return;
2189 res.xmin = res.xmax = gr.fX[0];
2190 res.ymin = res.ymax = gr.fY[0];
2193 for (var i=0; i < gr.fNpoints; ++i) {
2194 res.xmin = Math.min(res.xmin, gr.fX[i]);
2195 res.xmax = Math.max(res.xmax, gr.fX[i]);
2196 res.ymin = Math.min(res.ymin, gr.fY[i]);
2197 res.ymax = Math.max(res.ymax, gr.fY[i]);
2202 this[
'padtoX'] =
function(pad, x) {
2204 if (pad.fLogx && (x < 50))
2205 return Math.exp(2.302585092994 * x);
2209 this.ScanGraphsRange =
function(graphs, histo, pad) {
2210 var mgraph = this.GetObject(),
2211 maximum, minimum, dx, dy, uxmin = 0, uxmax = 0, logx =
false, logy =
false,
2212 rw = { xmin: 0, xmax: 0, ymin: 0, ymax: 0, first:
true };
2217 rw.xmin = pad.fUxmin;
2218 rw.xmax = pad.fUxmax;
2219 rw.ymin = pad.fUymin;
2220 rw.ymax = pad.fUymax;
2224 minimum = histo.fYaxis.fXmin;
2225 maximum = histo.fYaxis.fXmax;
2227 uxmin = this.padtoX(pad, rw.xmin);
2228 uxmax = this.padtoX(pad, rw.xmax);
2231 this.autorange =
true;
2233 for (var i = 0; i < graphs.arr.length; ++i)
2234 this.ComputeGraphRange(rw, graphs.arr[i]);
2236 if (rw.xmin == rw.xmax) rw.xmax += 1.;
2237 if (rw.ymin == rw.ymax) rw.ymax += 1.;
2238 dx = 0.05 * (rw.xmax - rw.xmin);
2239 dy = 0.05 * (rw.ymax - rw.ymin);
2240 uxmin = rw.xmin - dx;
2241 uxmax = rw.xmax + dx;
2243 if (rw.ymin <= 0) rw.ymin = 0.001 * rw.ymax;
2244 minimum = rw.ymin / (1 + 0.5 * JSROOT.log10(rw.ymax / rw.ymin));
2245 maximum = rw.ymax * (1 + 0.2 * JSROOT.log10(rw.ymax / rw.ymin));
2247 minimum = rw.ymin - dy;
2248 maximum = rw.ymax + dy;
2250 if (minimum < 0 && rw.ymin >= 0)
2252 if (maximum > 0 && rw.ymax <= 0)
2256 if (uxmin < 0 && rw.xmin >= 0) {
2257 if (logx) uxmin = 0.9 * rw.xmin;
2260 if (uxmax > 0 && rw.xmax <= 0) {
2261 if (logx) uxmax = 1.1 * rw.xmax;
2265 if (mgraph.fMinimum != -1111)
2266 rw.ymin = minimum = mgraph.fMinimum;
2267 if (mgraph.fMaximum != -1111)
2268 rw.ymax = maximum = mgraph.fMaximum;
2270 if (minimum < 0 && rw.ymin >= 0) {
2271 if (logy) minimum = 0.9 * rw.ymin;
2273 if (maximum > 0 && rw.ymax <= 0) {
2274 if (logy) maximum = 1.1 * rw.ymax;
2276 if (minimum <= 0 && logy)
2277 minimum = 0.001 * maximum;
2278 if (uxmin <= 0 && logx) {
2282 uxmin = 0.001 * uxmax;
2287 histo = JSROOT.Create(
"TH1I");
2288 histo.fTitle = mgraph.fTitle;
2289 histo.fXaxis.fXmin = uxmin;
2290 histo.fXaxis.fXmax = uxmax;
2293 histo.fYaxis.fXmin = minimum;
2294 histo.fYaxis.fXmax = maximum;
2299 this.DrawAxis =
function() {
2302 var mgraph = this.GetObject();
2304 var histo = this.ScanGraphsRange(mgraph.fGraphs, mgraph.fHistogram,
this.root_pad());
2308 this.firstpainter = JSROOT.Painter.drawHistogram1D(this.divid, histo,
"AXIS");
2311 this.DrawNextFunction =
function(indx, callback) {
2314 var mgraph = this.GetObject();
2316 if ((mgraph.fFunctions == null) || (indx >= mgraph.fFunctions.arr.length))
2317 return JSROOT.CallBack(callback);
2319 var func = mgraph.fFunctions.arr[indx];
2320 var opt = mgraph.fFunctions.opt[indx];
2322 var painter = JSROOT.draw(this.divid, func, opt);
2323 if (painter)
return painter.WhenReady(this.DrawNextFunction.bind(
this, indx+1, callback));
2325 this.DrawNextFunction(indx+1, callback);
2328 this.DrawNextGraph =
function(indx, opt) {
2329 var graphs = this.GetObject().fGraphs;
2332 if (indx >= graphs.arr.length)
2333 return this.DrawNextFunction(0, this.DrawingReady.bind(
this));
2335 var drawopt = graphs.opt[indx];
2336 if ((drawopt==null) || (drawopt ==
"")) drawopt = opt;
2337 var subp = JSROOT.draw(this.divid, graphs.arr[indx], drawopt);
2338 this.painters.push(subp);
2339 subp.WhenReady(this.DrawNextGraph.bind(
this, indx+1, opt));
2342 if (opt == null) opt =
"";
2343 opt = opt.toUpperCase().replace(
"3D",
"").replace(
"FB",
"");
2345 if ((opt.indexOf(
"A") >= 0) || (this.main_painter()==null)) {
2346 opt = opt.replace(
"A",
"");
2349 this.SetDivId(divid);
2351 this.DrawNextGraph(0, opt);
2358 JSROOT.Painter.drawLegend =
function(divid, obj, opt) {
2360 JSROOT.extend(
this,
new JSROOT.TPavePainter(obj));
2362 this.SetDivId(divid);
2364 this.DrawLegendItems =
function(w, h) {
2366 var legend = this.GetObject(),
2367 nlines = legend.fPrimitives.arr.length,
2368 ncols = legend.fNColumns,
2371 if (ncols<2) ncols = 1;
else {
while ((nrows-1)*ncols >= nlines) nrows--; }
2373 this.StartTextDrawing(legend.fTextFont, h / (nlines * 1.2));
2375 var tcolor = JSROOT.Painter.root_colors[legend.fTextColor],
2376 column_width = Math.round(w/ncols),
2377 padding_x = Math.round(0.03*w/ncols),
2378 padding_y = Math.round(0.03*h),
2379 step_y = (h - 2*padding_y)/nrows,
2382 for (var i = 0; i < nlines; ++i) {
2383 var leg = legend.fPrimitives.arr[i];
2384 var lopt = leg.fOption.toLowerCase();
2386 var icol = i % ncols, irow = (i - icol) / ncols;
2388 var x0 = icol * column_width;
2389 var tpos_x = x0 + Math.round(legend.fMargin*column_width);
2391 var pos_y = Math.round(padding_y + irow*step_y);
2392 var mid_y = Math.round(padding_y + (irow+0.5)*step_y);
2394 var o_fill = leg, o_marker = leg, o_line = leg;
2396 var mo = leg.fObject;
2400 if ((mo !== null) && (typeof mo ==
'object')) {
2401 if (
'fLineColor' in mo) o_line = mo;
2402 if (
'fFillColor' in mo) o_fill = mo;
2403 if (
'fMarkerColor' in mo) o_marker = mo;
2405 painter = this.FindPainterFor(mo);
2409 if (lopt.indexOf(
'f') != -1) {
2410 var fillatt = (painter && painter.fillatt) ? painter.fillatt :
this.createAttFill(o_fill);
2413 this.draw_g.append(
"svg:rect")
2414 .attr(
"x", x0 + padding_x)
2415 .attr(
"y", Math.round(pos_y+step_y*0.1))
2416 .attr(
"width", tpos_x - 2*padding_x - x0)
2417 .attr(
"height", Math.round(step_y*0.8))
2418 .call(fillatt.func);
2422 if (lopt.indexOf(
'l') != -1) {
2423 var lineatt = (painter && painter.lineatt) ? painter.lineatt : JSROOT.Painter.createAttLine(o_line)
2424 this.draw_g.append(
"svg:line")
2425 .attr(
"x1", x0 + padding_x)
2427 .attr(
"x2", tpos_x - padding_x)
2429 .call(lineatt.func);
2433 if (lopt.indexOf(
'e') != -1 && (lopt.indexOf(
'l') == -1 || lopt.indexOf(
'f') != -1)) {
2437 if (lopt.indexOf(
'p') != -1) {
2438 var marker = (painter && painter.markeratt) ? painter.markeratt : JSROOT.Painter.createAttMarker(o_marker);
2441 .attr(
"d", marker.create((x0 + tpos_x)/2, mid_y))
2446 if (lopt.length>0) any_opt =
true;
2447 else if (!any_opt) pos_x = x0 + padding_x;
2449 this.DrawText(
"start", pos_x, pos_y, x0+column_width-pos_x-padding_x, step_y, leg.fLabel, tcolor);
2453 this.FinishTextDrawing();
2456 this.PaveDrawFunc = this.DrawLegendItems;
2460 return this.DrawingReady();
2465 JSROOT.Painter.drawPaletteAxis =
function(divid,palette,opt) {
2468 palette.fBorderSize = 1;
2469 palette.fShadowColor = 0;
2471 JSROOT.extend(
this,
new JSROOT.TPavePainter(palette));
2473 this.SetDivId(divid);
2475 this.z_handle =
new JSROOT.TAxisPainter(palette.fAxis,
true);
2476 this.z_handle.SetDivId(divid, -1);
2478 this[
'MakeIcon'] =
function(contour, z) {
2479 var h = this.frame_height();
2481 var prev = { x : -1, y : -1, width: 0, height: 0, fill:
"" };
2482 for (var i=0;i<contour.length-1;++i) {
2483 var z0 = z(contour[i]);
2484 var z1 = z(contour[i+1]);
2485 var col = this.main_painter().getValueColor(contour[i]);
2487 var pnt = { x: 128, width: 256, y: Math.round(z1/h*512) , height: Math.round((z0-z1)/h*512), fill: col };
2489 if (res.length == 0) res =
"[";
else res+=
",";
2492 if (pnt.x != prev.x) { res += separ +
"x:" + Math.round(pnt.x); separ =
","; }
2493 if (pnt.y != prev.y) { res += separ +
"y:" + Math.round(pnt.y); separ =
","; }
2494 if (pnt.width != prev.width) { res += separ +
"w:" + Math.round(pnt.width); separ =
","; }
2495 if (pnt.height != prev.height) { res += separ +
"h:" + Math.round(pnt.height); separ =
","; }
2496 if (pnt.fill != prev.fill) { res += separ +
"f:'" + pnt.fill +
"'"; separ =
","; }
2505 this.DrawAxisPalette =
function(s_width, s_height) {
2507 var pthis =
this, palette = this.GetObject(), axis = palette.fAxis;
2509 var nbr1 = axis.fNdiv % 100;
2510 if (nbr1<=0) nbr1 = 8;
2512 var pos_x = parseInt(this.draw_g.attr(
"x")),
2513 pos_y = parseInt(this.draw_g.attr(
"y")),
2514 width = this.pad_width(),
2515 height = this.pad_height(),
2516 axisOffset = axis.fLabelOffset * width,
2517 contour = this.main_painter().fContour,
2518 zmin = 0, zmax = this.main_painter().gmaxbin;
2520 if (contour!==null) {
2522 zmax = contour[contour.length-1];
2525 var z = null, z_kind =
"normal";
2527 if (this.main_painter().options.Logz) {
2531 z = d3.scale.linear();
2533 z.domain([zmin, zmax]).range([s_height,0]);
2535 if ((contour==null) || this._can_move)
2537 this.draw_g.append(
"svg:rect")
2540 .attr(
"width", s_width)
2541 .attr(
"height", s_height)
2542 .attr(
"fill",
'white');
2544 for (var i=0;i<contour.length-1;++i) {
2545 var z0 = z(contour[i]),
2546 z1 = z(contour[i+1]),
2547 col = this.main_painter().getValueColor(contour[i]);
2549 var r = this.draw_g.append(
"svg:rect")
2551 .attr(
"y", z1.toFixed(1))
2552 .attr(
"width", s_width)
2553 .attr(
"height", (z0-z1).toFixed(1))
2555 .style(
"stroke", col);
2558 if (JSROOT.gStyle.Tooltip > 0)
2559 r.on(
'mouseover',
function() {
2560 d3.select(
this).transition().duration(100).style(
"stroke",
"black").style(
"stroke-width",
"2");
2561 }).on(
'mouseout',
function() {
2562 d3.select(
this).transition().duration(100).style(
"stroke", d3.select(
this).style(
'fill')).style(
"stroke-width",
"");
2563 }).append(
"svg:title").text(contour[i].toFixed(2) +
" - " + contour[i+1].toFixed(2));
2565 if (JSROOT.gStyle.Zooming)
2566 r.on(
"dblclick",
function() { pthis.main_painter().Unzoom(
"z"); });
2570 this.z_handle.SetAxisConfig(
"zaxis", z_kind, z, zmin, zmax, zmin, zmax);
2572 this.z_handle.DrawAxis(this.draw_g, s_width, s_height,
"translate(" + s_width +
", 0)");
2574 if (this._can_move && (
'getBoundingClientRect' in this.draw_g.node())) {
2575 this._can_move =
false;
2577 var rect = this.draw_g.node().getBoundingClientRect();
2579 var shift = (pos_x + parseInt(rect.width)) - Math.round(0.995*width) + 3;
2582 this.draw_g.attr(
"x", pos_x - shift).attr(
"y", pos_y)
2583 .attr(
"transform",
"translate(" + (pos_x-shift) +
", " + pos_y +
")");
2584 palette.fX1NDC -= shift/width;
2585 palette.fX2NDC -= shift/width;
2590 if (!JSROOT.gStyle.Zooming)
return;
2592 var evnt = null, doing_zoom =
false, sel1 = 0, sel2 = 0, zoom_rect = null;
2594 function moveRectSel() {
2596 if (!doing_zoom)
return;
2598 d3.event.preventDefault();
2599 var m = d3.mouse(evnt);
2601 if (m[1] < sel1) sel1 = m[1];
else sel2 = m[1];
2603 zoom_rect.attr(
"y", sel1)
2604 .attr(
"height", Math.abs(sel2-sel1));
2607 function endRectSel() {
2608 if (!doing_zoom)
return;
2610 d3.event.preventDefault();
2611 d3.select(window).on(
"mousemove.colzoomRect", null)
2612 .on(
"mouseup.colzoomRect", null);
2617 var zmin = Math.min(z.invert(sel1), z.invert(sel2));
2618 var zmax = Math.max(z.invert(sel1), z.invert(sel2));
2620 pthis.main_painter().Zoom(undefined, undefined, undefined, undefined, zmin, zmax);
2623 function startRectSel() {
2626 if (doing_zoom)
return;
2629 d3.event.preventDefault();
2632 var origin = d3.mouse(evnt);
2634 sel1 = sel2 = origin[1];
2636 zoom_rect = pthis.draw_g
2638 .attr(
"class",
"zoom")
2639 .attr(
"id",
"colzoomRect")
2641 .attr(
"width", s_width)
2645 d3.select(window).on(
"mousemove.colzoomRect", moveRectSel)
2646 .on(
"mouseup.colzoomRect", endRectSel,
true);
2648 d3.event.stopPropagation();
2651 this.draw_g.select(
".axis_zoom")
2652 .on(
"mousedown", startRectSel)
2653 .on(
"dblclick",
function() { pthis.main_painter().Unzoom(
"z"); });
2656 this.ShowContextMenu =
function(evnt) {
2657 this.main_painter().ShowContextMenu(
"z", evnt, this.GetObject().fAxis);
2660 this.Redraw =
function() {
2661 this.Enabled =
true;
2662 var main = this.main_painter();
2663 this.UseContextMenu = (main !== null);
2664 if ((main !== null) && main.options)
2665 this.Enabled = (main.options.Zscale > 0) && (main.options.Color > 0) && (main.options.Lego === 0);
2670 this.PaveDrawFunc = this.DrawAxisPalette;
2673 this.CompleteDraw = this.Redraw;
2675 this._can_move = (opt ===
'canmove');
2679 return this.DrawingReady();
2684 JSROOT.TH2Painter =
function(histo) {
2685 JSROOT.THistPainter.call(
this, histo);
2686 this.fContour = null;
2687 this.fUserContour =
false;
2688 this.fPalette = null;
2691 JSROOT.TH2Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
2693 JSROOT.TH2Painter.prototype.FillHistContextMenu =
function(menu) {
2694 if (!this.draw_content)
return;
2697 menu.add(
"Auto zoom-in", this.AutoZoom);
2699 menu.addDrawMenu(
"Draw with", [
"col",
"colz",
"scat",
"box",
"text",
"lego"],
function(arg) {
2700 this.options = this.DecodeOptions(arg);
2701 if (this.options.Zscale > 0)
2703 this.DrawNewPalette(
true);
2705 if (this.options.Lego == 0) this.AddInteractive();
2709 JSROOT.TH2Painter.prototype.ButtonClick =
function(funcname) {
2710 if (JSROOT.THistPainter.prototype.ButtonClick.call(
this, funcname))
return true;
2712 if (
this !== this.main_painter())
return false;
2715 case "ToggleColor": this.ToggleColor();
break;
2716 case "ToggleColorZ":
2717 if (this.options.Lego == 0 &&
this.options.Color > 0) this.ToggleColz();
2720 this.options.Lego = this.options.Lego > 0 ? 0 : 1;
2723 default:
return false;
2730 JSROOT.TH2Painter.prototype.FillToolbar =
function() {
2731 JSROOT.THistPainter.prototype.FillToolbar.call(
this);
2733 var pp = this.pad_painter(
true);
2734 if (pp===null)
return;
2736 pp.AddButton(JSROOT.ToolbarIcons.th2color,
"Toggle color",
"ToggleColor");
2737 pp.AddButton(JSROOT.ToolbarIcons.th2colorz,
"Toggle color palette",
"ToggleColorZ");
2738 pp.AddButton(JSROOT.ToolbarIcons.th2draw3d,
"Toggle 3D mode",
"Toggle3D");
2741 JSROOT.TH2Painter.prototype.ToggleColor =
function() {
2745 if (this.options.Lego > 0) { this.options.Lego = 0; toggle =
false; }
2747 if (this.options.Color == 0) {
2748 this.options.Color = (
'LastColor' in this.options) ? this.options.LastColor : 1;
2751 this.options.LastColor = this.options.Color;
2752 this.options.Color = 0;
2755 if ((this.options.Color > 0) && (this.options.Zscale > 0))
2756 this.DrawNewPalette(
true);
2761 JSROOT.TH2Painter.prototype.FindPalette =
function(
remove) {
2763 var funcs = this.GetObject().fFunctions;
2764 if (funcs === null)
return null;
2766 for (var i = 0; i < funcs.arr.length; ++i) {
2767 var func = funcs.arr[i];
2768 if (func._typename !==
'TPaletteAxis')
continue;
2771 if (this.pad_painter())
2772 this.pad_painter().RemovePrimitive(func);
2781 JSROOT.TH2Painter.prototype.DrawNewPalette =
function(force_resize) {
2784 var pal = this.FindPalette(), histo = this.GetObject();
2786 if ((pal !== null) && !force_resize)
return;
2789 pal = JSROOT.Create(
'TPave');
2791 JSROOT.extend(pal, { _typename:
"TPaletteAxis", fName:
"TPave", fH: null, fAxis: null,
2792 fX1NDC: 0.91, fX2NDC: 0.95, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1 } );
2794 pal.fAxis = JSROOT.Create(
'TGaxis');
2798 JSROOT.extend(pal.fAxis, { fTitle: histo.fZaxis.fTitle,
2799 fLineColor: 1, fLineSyle: 1, fLineWidth: 1,
2800 fTextAngle: 0, fTextSize: 0.04, fTextAlign: 11, fTextColor: 1, fTextFont: 42 });
2802 if (histo.fFunctions == null)
2803 histo.fFunctions = JSROOT.Create(
"TList");
2806 histo.fFunctions.AddFirst(pal);
2809 var frame_painter = this.frame_painter();
2812 pal.fX2NDC = frame_painter.fX2NDC + 0.01 + (pal.fX2NDC - pal.fX1NDC);
2813 pal.fX1NDC = frame_painter.fX2NDC + 0.01;
2814 pal.fY1NDC = frame_painter.fY1NDC;
2815 pal.fY2NDC = frame_painter.fY2NDC;
2817 var pal_painter = this.FindPainterFor(pal);
2819 if (pal_painter === null) {
2821 this.svg_canvas().property(
'current_pad', this.pad_name);
2822 pal_painter = JSROOT.draw(this.divid, pal,
"canmove");
2823 this.svg_canvas().property(
'current_pad',
'');
2825 pal_painter._can_move =
true;
2826 pal_painter.Redraw();
2829 if (pal.fX1NDC < frame_painter.fX2NDC) {
2830 frame_painter.fX2NDC = pal.fX1NDC - 0.01;
2831 frame_painter.Redraw();
2835 JSROOT.TH2Painter.prototype.ToggleColz =
function() {
2836 if (this.options.Zscale > 0) {
2837 this.options.Zscale = 0;
2839 this.options.Zscale = 1;
2840 this.DrawNewPalette(
true);
2846 JSROOT.TH2Painter.prototype.AutoZoom =
function() {
2847 var i1 = this.GetSelectIndex(
"x",
"left", -1),
2848 i2 = this.GetSelectIndex(
"x",
"right", 1),
2849 j1 = this.GetSelectIndex(
"y",
"left", -1),
2850 j2 = this.GetSelectIndex(
"y",
"right", 1),
2851 i,j, histo = this.GetObject();
2853 if ((i1 == i2) || (j1 == j2))
return;
2856 var min = histo.getBinContent(i1 + 1, j1 + 1);
2857 for (i = i1; i < i2; ++i)
2858 for (j = j1; j < j2; ++j)
2859 if (histo.getBinContent(i + 1, j + 1) < min)
2860 min = histo.getBinContent(i + 1, j + 1);
2863 var ileft = i2, iright = i1, jleft = j2, jright = j1;
2865 for (i = i1; i < i2; ++i)
2866 for (j = j1; j < j2; ++j)
2867 if (histo.getBinContent(i + 1, j + 1) > min) {
2868 if (i < ileft) ileft = i;
2869 if (i >= iright) iright = i + 1;
2870 if (j < jleft) jleft = j;
2871 if (j >= jright) jright = j + 1;
2874 var xmin, xmax, ymin, ymax, isany =
false;
2876 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
2877 xmin = this.GetBinX(ileft);
2878 xmax = this.GetBinX(iright);
2882 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
2883 ymin = this.GetBinY(jleft);
2884 ymax = this.GetBinY(jright);
2888 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
2892 JSROOT.TH2Painter.prototype.ScanContent =
function() {
2893 var i,j,histo = this.GetObject();
2895 this.nbinsx = histo.fXaxis.fNbins;
2896 this.nbinsy = histo.fYaxis.fNbins;
2900 this.CreateAxisFuncs(
true);
2903 this.gminbin = this.gmaxbin = histo.getBinContent(1, 1);
2904 this.gmin0bin = null;
2905 for (i = 0; i < this.nbinsx; ++i) {
2906 for (j = 0; j < this.nbinsy; ++j) {
2907 var bin_content = histo.getBinContent(i+1, j+1);
2908 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
2909 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
2910 if (bin_content > 0)
2911 if ((this.gmin0bin===null) || (this.gmin0bin > bin_content)) this.gmin0bin = bin_content;
2916 if (this.gmin0bin === null) this.gmin0bin = this.gmaxbin*1e-4;
2919 this.draw_content = this.gmaxbin > 0;
2922 if (this.is_main_painter() && (this.zoom_xmin === this.zoom_xmax) &&
2923 this.histo.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
2924 (this.histo.fXaxis.fFirst !== this.histo.fXaxis.fLast) &&
2925 ((this.histo.fXaxis.fFirst>1) || (this.histo.fXaxis.fLast <= this.nbinsx))) {
2926 this.zoom_xmin = this.histo.fXaxis.fFirst > 1 ? this.GetBinX(this.histo.fXaxis.fFirst-1) : this.xmin;
2927 this.zoom_xmax = this.histo.fXaxis.fLast <= this.nbinsx ? this.GetBinX(this.histo.fXaxis.fLast) : this.xmax;
2931 if (this.is_main_painter() && (this.zoom_ymin === this.zoom_ymax) &&
2932 this.histo.fYaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
2933 (this.histo.fYaxis.fFirst !== this.histo.fYaxis.fLast) &&
2934 ((this.histo.fYaxis.fFirst>1) || (this.histo.fYaxis.fLast <= this.nbinsy))) {
2935 this.zoom_ymin = this.histo.fYaxis.fFirst > 1 ? this.GetBinY(this.histo.fYaxis.fFirst-1) : this.ymin;
2936 this.zoom_ymax = this.histo.fYaxis.fLast <= this.nbinsy ? this.GetBinY(this.histo.fYaxis.fLast) : this.ymax;
2940 JSROOT.TH2Painter.prototype.CountStat =
function(cond) {
2941 var histo = this.GetObject(),
2942 stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0,
2943 stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0,
2944 xleft = this.GetSelectIndex(
"x",
"left"),
2945 xright = this.GetSelectIndex(
"x",
"right"),
2946 yleft = this.GetSelectIndex(
"y",
"left"),
2947 yright = this.GetSelectIndex(
"y",
"right"),
2948 xi, xside, xx, yi, yside, yy, zz,
2949 res = { 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 };
2951 for (xi = 0; xi <= this.nbinsx + 1; ++xi) {
2952 xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
2953 xx = this.GetBinX(xi - 0.5);
2955 for (yi = 0; yi <= this.nbinsy + 1; ++yi) {
2956 yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
2957 yy = this.GetBinY(yi - 0.5);
2959 zz = histo.getBinContent(xi, yi);
2963 res.matrix[yside * 3 + xside] += zz;
2965 if ((xside != 1) || (yside != 1))
continue;
2967 if ((cond!=null) && !cond(xx,yy))
continue;
2969 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
2972 stat_sumx1 += xx * zz;
2973 stat_sumy1 += yy * zz;
2974 stat_sumx2 += xx * xx * zz;
2975 stat_sumy2 += yy * yy * zz;
2976 stat_sumxy += xx * yy * zz;
2980 if (!this.IsAxisZoomed(
"x") && !this.IsAxisZoomed(
"y") && (histo.fTsumw > 0)) {
2981 stat_sum0 = histo.fTsumw;
2982 stat_sumx1 = histo.fTsumwx;
2983 stat_sumx2 = histo.fTsumwx2;
2984 stat_sumy1 = histo.fTsumwy;
2985 stat_sumy2 = histo.fTsumwy2;
2986 stat_sumxy = histo.fTsumwxy;
2989 if (stat_sum0 > 0) {
2990 res.meanx = stat_sumx1 / stat_sum0;
2991 res.meany = stat_sumy1 / stat_sum0;
2992 res.rmsx = Math.sqrt(stat_sumx2 / stat_sum0 - res.meanx * res.meanx);
2993 res.rmsy = Math.sqrt(stat_sumy2 / stat_sum0 - res.meany * res.meany);
2996 if (res.wmax===null) res.wmax = 0;
2997 res.integral = stat_sum0;
2999 if (histo.fEntries > 1) res.entries = histo.fEntries;
3004 JSROOT.TH2Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
3005 if (this.GetObject() === null)
return false;
3007 var pave = stat.GetObject(),
3008 data = this.CountStat(),
3009 print_name = Math.floor(dostat % 10),
3010 print_entries = Math.floor(dostat / 10) % 10,
3011 print_mean = Math.floor(dostat / 100) % 10,
3012 print_rms = Math.floor(dostat / 1000) % 10,
3013 print_under = Math.floor(dostat / 10000) % 10,
3014 print_over = Math.floor(dostat / 100000) % 10,
3015 print_integral = Math.floor(dostat / 1000000) % 10,
3016 print_skew = Math.floor(dostat / 10000000) % 10,
3017 print_kurt = Math.floor(dostat / 100000000) % 10;
3020 pave.AddText(this.GetObject().fName);
3022 if (print_entries > 0)
3023 pave.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
3025 if (print_mean > 0) {
3026 pave.AddText(
"Mean x = " + stat.Format(data.meanx));
3027 pave.AddText(
"Mean y = " + stat.Format(data.meany));
3030 if (print_rms > 0) {
3031 pave.AddText(
"Std Dev x = " + stat.Format(data.rmsx));
3032 pave.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
3035 if (print_integral > 0) {
3036 pave.AddText(
"Integral = " + stat.Format(data.matrix[4],
"entries"));
3039 if (print_skew > 0) {
3040 pave.AddText(
"Skewness x = <undef>");
3041 pave.AddText(
"Skewness y = <undef>");
3045 pave.AddText(
"Kurt = <undef>");
3047 if ((print_under > 0) || (print_over > 0)) {
3048 var m = data.matrix;
3050 pave.AddText(
"" + m[6].toFixed(0) +
" | " + m[7].toFixed(0) +
" | " + m[7].toFixed(0));
3051 pave.AddText(
"" + m[3].toFixed(0) +
" | " + m[4].toFixed(0) +
" | " + m[5].toFixed(0));
3052 pave.AddText(
"" + m[0].toFixed(0) +
" | " + m[1].toFixed(0) +
" | " + m[2].toFixed(0));
3056 var nlines = pave.fLines.arr.length,
3057 stath = nlines * JSROOT.gStyle.StatFontSize;
3058 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
3059 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
3060 pave.fY1NDC = 0.93 - stath;
3067 JSROOT.TH2Painter.prototype.CreateContour =
function(nlevels, zmin, zmax, zminpositive) {
3068 if (nlevels<1) nlevels = 20;
3073 if (this.options.Logz) {
3074 if (this.zmax <= 0) this.zmax = 1.;
3076 this.zmin = (zminpositive > 0) ? 0.3*zminpositive : 0.0001*this.zmax;
3077 if (this.zmin >= this.zmax) this.zmin = 0.0001*this.zmax;
3079 var logmin = Math.log(this.zmin)/Math.log(10);
3080 var logmax = Math.log(this.zmax)/Math.log(10);
3081 var dz = (logmax-logmin)/nlevels;
3082 this.fContour.push(this.zmin);
3083 for (var level=1; level<nlevels; level++)
3084 this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10)));
3085 this.fContour.push(this.zmax);
3087 if ((this.zmin == this.zmax) && (this.zmin != 0)) {
3088 this.zmax += 0.01*Math.abs(this.zmax);
3089 this.zmin -= 0.01*Math.abs(this.zmin);
3091 var dz = (this.zmax-this.zmin)/nlevels;
3092 for (var level=0; level<=nlevels; level++)
3093 this.fContour.push(
this.zmin + dz*level);
3097 JSROOT.TH2Painter.prototype.getContourIndex =
function(zc) {
3100 if (this.fContour == null) {
3103 var histo = this.GetObject();
3105 this.fUserContour =
false;
3106 if ((histo.fContour!=null) && (histo.fContour.length>1) && histo.TestBit(JSROOT.TH1StatusBits.kUserContour)) {
3107 this.fContour = JSROOT.clone(histo.fContour);
3108 this.fUserContour =
true;
3110 var nlevels = 20, zmin = this.minbin, zmax = this.maxbin;
3111 if (histo.fContour != null) nlevels = histo.fContour.length;
3112 if (this.zoom_zmin != this.zoom_zmax) {
3113 zmin = this.zoom_zmin;
3114 zmax = this.zoom_zmax;
3116 this.CreateContour(nlevels, zmin, zmax, this.minposbin);
3120 if (this.fUserContour || this.options.Logz) {
3121 var cntr = this.fContour, l = 0, r = this.fContour.length-1, mid;
3122 if (zc < cntr[0])
return -1;
3123 if (zc >= cntr[r])
return r;
3125 mid = Math.round((l+r)/2);
3126 if (cntr[mid] > zc) r = mid;
else l = mid;
3131 return Math.floor(0.01+(zc-this.zmin)*(this.fContour.length-1)/(
this.zmax-
this.zmin));
3134 JSROOT.TH2Painter.prototype.getValueColor =
function(zc, asindx) {
3135 var index = this.getContourIndex(zc);
3139 if (this.options.Color !== 111)
return null;
3143 if (this.fPalette == null)
3144 this.fPalette = JSROOT.Painter.GetColorPalette(this.options.Palette);
3146 var theColor = Math.floor((index+0.99)*this.fPalette.length/(
this.fContour.length-1));
3147 if (theColor > this.fPalette.length-1) theColor = this.fPalette.length-1;
3148 return asindx ? theColor : this.fPalette[theColor];
3151 JSROOT.TH2Painter.prototype.CompressAxis =
function(arr, maxlen, regular) {
3152 if (arr.length <= maxlen)
return;
3155 var left = 0, right = arr.length-2;
3156 while ((left < right) && (arr[left].cnt===0)) ++left;
3157 while ((left < right) && (arr[right].cnt===0)) --right;
3158 if (right-left < maxlen)
return;
3160 function RemoveNulls() {
3163 while ((j>=left) && (arr[j]!==null)) --j;
3165 while ((j>=0) && (arr[j]===null)) --j;
3166 if (j < j2) { arr.splice(j+1, j2-j); right -= (j2-j); }
3172 var grdist = Math.abs(arr[right+1].gr - arr[left].gr) / maxlen;
3174 while (i <= right) {
3175 var gr0 = arr[i++].gr;
3177 while ((i <= right) && (Math.abs(arr[i+1].gr - gr0) < grdist)) arr[i++] = null;
3182 if (regular || ((right-left) > 1.5*maxlen)) {
3184 var period = Math.floor((right-left) / maxlen);
3185 if (period<2) period = 2;
3187 while (++i <= right) {
3188 for (var k=1;k<period;++k)
3189 if (++i <= right) arr[i] = null;
3195 JSROOT.TH2Painter.prototype.CreateDrawBins =
function(w, h) {
3197 var histo = this.GetObject(),
3198 i1 = this.GetSelectIndex(
"x",
"left", 0),
3199 i2 = this.GetSelectIndex(
"x",
"right", 1),
3200 j1 = this.GetSelectIndex(
"y",
"left", 0),
3201 j2 = this.GetSelectIndex(
"y",
"right", 1),
3202 name = this.GetTipName(
"\n"),
3203 xx = [], yy = [], i, j, x, y,
3204 nbins = 0, binz = 0, sumz = 0;
3206 for (i = i1; i <= i2; ++i) {
3207 x = this.GetBinX(i);
3208 if (this.options.Logx && (x <= 0)) { i1 = i+1;
continue; }
3209 xx.push({indx:i, axis: x, gr: this.grx(x), cnt:0});
3212 for (j = j1; j <= j2; ++j) {
3213 y = this.GetBinY(j);
3214 if (this.options.Logy && (y <= 0)) { j1 = j+1;
continue; }
3215 yy.push({indx:j, axis:y, gr:this.gry(y), cnt:0});
3219 this.maxbin = this.minbin = histo.getBinContent(i1 + 1, j1 + 1);
3220 for (i = i1; i < i2; ++i) {
3221 for (j = j1; j < j2; ++j) {
3222 binz = histo.getBinContent(i + 1, j + 1);
3223 if (binz != 0) nbins++;
3224 if (binz>this.maxbin) this.maxbin = binz;
else
3225 if (binz<this.minbin) this.minbin = binz;
3229 if (((this.options.Optimize > 0) && (nbins>1000)) || (
this.options.Optimize > 10)) {
3234 for (i = i1; i < i2; ++i) {
3235 for (j = j1; j < j2; ++j) {
3236 binz = histo.getBinContent(i+1, j+1);
3237 if ((binz == 0) || (binz < this.minbin))
continue;
3245 if (((this.options.Optimize > 0) && (nbins>1000)) || (
this.options.Optimize > 10)) {
3246 var numx = this.options.Optimize > 10 ? 10 : 40;
3249 var coef = Math.abs(xx[0].gr - xx[xx.length-1].gr) / Math.abs(yy[0].gr - yy[yy.length-1].gr);
3250 if (coef > 1.) numy = Math.max(10, Math.round(numx / coef));
3251 else numx = Math.max(10, Math.round(numy * coef));
3253 if ((this.options.Optimize > 1) || (xx.length > 50))
3254 this.CompressAxis(xx, numx, !this.options.Logx &&
this.regularx);
3256 if ((this.options.Optimize > 1) || (yy.length > 50))
3257 this.CompressAxis(yy, numy, !this.options.Logy &&
this.regulary);
3260 var local_bins = [];
3262 for (i = 0; i < xx.length-1; ++i) {
3264 for (j = 0; j < yy.length-1; ++j) {
3266 sumz = binz = histo.getBinContent(xx[i].indx + 1, yy[j].indx + 1);
3268 if ((xx[i+1].indx > xx[i].indx+1) || (yy[j+1].indx > yy[j].indx+1)) {
3271 for (var i1 = xx[i].indx;i1 < xx[i+1].indx;++i1)
3272 for (var j1 = yy[j].indx;j1 < yy[j+1].indx;++j1) {
3273 var morez = histo.getBinContent(i1 + 1, j1 + 1);
3274 binz = Math.max(binz, morez);
3279 if ((binz == 0) || (binz < this.minbin))
continue;
3289 if (JSROOT.gStyle.Tooltip > 0) {
3290 if (this.x_kind ==
'labels')
3291 point.tip = name +
"x = " + this.AxisAsText(
"x", xx[i].axis) +
"<br/>";
3293 point.tip = name +
"x = [" + this.AxisAsText(
"x", xx[i].axis) +
", " + this.AxisAsText(
"x", xx[i+1].axis) +
")";
3295 if (xx[i].indx + 1 == xx[i+1].indx)
3296 point.tip +=
" bin=" + xx[i].indx +
"<br/>";
3298 point.tip +=
" bins=[" + xx[i].indx +
"," + (xx[i+1].indx-1) +
"]<br/>";
3300 if (this.y_kind ==
'labels')
3301 point.tip +=
"y = " + this.AxisAsText(
"y", yy[j].axis) +
"<br/>";
3303 point.tip +=
"y = [" + this.AxisAsText(
"y", yy[j].axis) +
", " + this.AxisAsText(
"y", yy[j+1].axis) +
")";
3304 if (yy[j].indx + 1 == yy[j+1].indx)
3305 point.tip +=
" bin=" + yy[j].indx +
"<br/>";
3307 point.tip +=
" bins=[" + yy[j].indx +
"," + (yy[j+1].indx-1) +
"]<br/>";
3311 point.tip +=
"entries = " + JSROOT.FFormat(sumz, JSROOT.gStyle.StatFormat);
3313 point.tip +=
"sum = " + JSROOT.FFormat(sumz, JSROOT.gStyle.StatFormat) +
3314 " max = " + JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat);
3316 local_bins.push(point);
3323 JSROOT.TH2Painter.prototype.PrepareColorDraw =
function(dorounding, pixel_density) {
3324 var histo = this.GetObject(), i, j, x, y, binz, binarea,
3326 i1: this.GetSelectIndex(
"x",
"left", 0),
3327 i2: this.GetSelectIndex(
"x",
"right", 1),
3328 j1: this.GetSelectIndex(
"y",
"left", 0),
3329 j2: this.GetSelectIndex(
"y",
"right", 1),
3330 grx: [], gry: [], min: 0, max: 0
3333 if (pixel_density) dorounding =
true;
3336 for (i = res.i1; i <= res.i2; ++i) {
3337 x = this.GetBinX(i);
3338 if (this.options.Logx && (x <= 0)) { res.i1 = i+1;
continue; }
3339 res.grx[i] = this.grx(x);
3340 if (dorounding) res.grx[i] = Math.round(res.grx[i]);
3343 for (j = res.j1; j <= res.j2; ++j) {
3344 y = this.GetBinY(j);
3345 if (this.options.Logy && (y <= 0)) { res.j1 = j+1;
continue; }
3346 res.gry[j] = this.gry(y);
3347 if (dorounding) res.gry[j] = Math.round(res.gry[j]);
3352 binz = histo.getBinContent(res.i1 + 1, res.j1 + 1);
3353 this.maxbin = this.minbin = this.minposbin = null;
3355 for (i = res.i1; i < res.i2; ++i) {
3356 for (j = res.j1; j < res.j2; ++j) {
3357 binz = histo.getBinContent(i + 1, j + 1);
3358 if (pixel_density) {
3359 binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]);
3360 if (binarea <= 0)
continue;
3361 res.max = Math.max(res.max, binz);
3362 if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz;
3363 binz = binz/binarea;
3365 if (this.maxbin===null) {
3366 this.maxbin = this.minbin = binz;
3368 this.maxbin = Math.max(this.maxbin, binz);
3369 this.minbin = Math.min(this.minbin, binz);
3372 if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz;
3376 this.fContour = null;
3377 this.fUserContour =
false;
3419 JSROOT.TH2Painter.prototype.DrawBinsColor =
function(w,h) {
3420 var histo = this.GetObject(),
3421 handle = this.PrepareColorDraw(
true),
3422 colPaths = [], currx = [], curry = [],
3423 colindx, cmd1, cmd2, i, j, binz;
3426 for (i = handle.i1; i < handle.i2; ++i) {
3427 for (j = handle.j1; j < handle.j2; ++j) {
3428 binz = histo.getBinContent(i + 1, j + 1);
3429 if ((binz == 0) || (binz < this.minbin))
continue;
3431 colindx = this.getValueColor(binz,
true);
3432 if (colindx === null)
continue;
3434 cmd1 =
"M"+handle.grx[i]+
","+handle.gry[j+1];
3435 if (colPaths[colindx] === undefined) {
3436 colPaths[colindx] = cmd1;
3438 cmd2 =
"m" + (handle.grx[i]-currx[colindx]) +
"," + (handle.gry[j+1]-curry[colindx]);
3439 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
3442 currx[colindx] = handle.grx[i];
3443 curry[colindx] = handle.gry[j+1];
3445 colPaths[colindx] +=
"v" + (handle.gry[j] - handle.gry[j+1]) +
3446 "h" + (handle.grx[i+1] - handle.grx[i]) +
3447 "v" + (handle.gry[j+1] - handle.gry[j]) +
"z";
3451 for (colindx=0;colindx<colPaths.length;++colindx)
3452 if (colPaths[colindx] !== undefined)
3455 .attr(
"palette-index", colindx)
3456 .attr(
"fill", this.fPalette[colindx])
3457 .attr(
"d", colPaths[colindx]);
3462 JSROOT.TH2Painter.prototype.DrawBinsText =
function(w, h, handle) {
3463 var histo = this.GetObject(),
3464 i,j,binz,colindx,binw,binh,lbl;
3466 if (handle===null) handle = this.PrepareColorDraw(
false);
3468 var text_g = this.draw_g
3470 .attr(
"class",
"th2_text");
3472 this.StartTextDrawing(42, 20, text_g);
3474 for (i = handle.i1; i < handle.i2; ++i)
3475 for (j = handle.j1; j < handle.j2; ++j) {
3476 binz = histo.getBinContent(i + 1, j + 1);
3477 if ((binz == 0) || (binz < this.minbin))
continue;
3479 colindx = this.getValueColor(binz,
true);
3480 if (colindx === null)
continue;
3482 binw = handle.grx[i+1] - handle.grx[i];
3483 binh = handle.gry[j] - handle.gry[j+1];
3484 lbl = Math.round(binz);
3487 lbl = binz.toString();
3489 lbl = JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat);
3491 this.DrawText(22, Math.round(handle.grx[i] + binw*0.1), Math.round(handle.gry[j+1] + binh*0.1),
3492 Math.round(binw*0.8), Math.round(binh*0.8),
3493 lbl,
"black", 0, text_g);
3496 this.FinishTextDrawing(text_g);
3501 JSROOT.TH2Painter.prototype.DrawBinsBox =
function(w,h) {
3502 var histo = this.GetObject(),
3503 handle = this.PrepareColorDraw(
false),
3504 i, j, binz, colPaths = [], currx = [], curry = [],
3505 colindx, zdiff, dgrx, dgry, ww, hh, cmd1, cmd2;
3507 var xfactor = 1, yfactor = 1, uselogz =
false, logmin = 0, logmax = 1;
3508 if (this.options.Logz && (
this.maxbin>0)) {
3510 logmax = Math.log(this.maxbin);
3511 logmin = (this.minbin > 0) ? Math.log(
this.minbin) : logmax - 10;
3512 if (logmin >= logmax) logmin = logmax - 10;
3513 xfactor = 0.5 / (logmax - logmin);
3514 yfactor = 0.5 / (logmax - logmin);
3516 xfactor = 0.5 / (this.maxbin - this.minbin);
3517 yfactor = 0.5 / (this.maxbin - this.minbin);
3521 for (i = handle.i1; i < handle.i2; ++i) {
3522 for (j = handle.j1; j < handle.j2; ++j) {
3523 binz = histo.getBinContent(i + 1, j + 1);
3524 if ((binz == 0) || (binz < this.minbin))
continue;
3526 zdiff = uselogz ? (logmax - ((binz>0) ? Math.log(binz) : logmin)) : this.maxbin - binz;
3528 ww = handle.grx[i+1] - handle.grx[i];
3529 hh = handle.gry[j] - handle.gry[j+1];
3531 dgrx = zdiff * xfactor * ww;
3532 dgry = zdiff * yfactor * hh;
3534 ww = Math.max(Math.round(ww - 2*dgrx), 1);
3535 hh = Math.max(Math.round(hh - 2*dgry), 1);
3537 if (colPaths[i]===undefined) colPaths[i] =
"";
3538 colPaths[i] +=
"M" + Math.round(handle.grx[i] + dgrx) +
"," + Math.round(handle.gry[j+1] + dgry) +
3539 "v" + hh +
"h" + ww +
"v-" + hh +
"z";
3543 for (i=0;i<colPaths.length;++i)
3544 if (colPaths[i] !== undefined)
3545 this.draw_g.append(
"svg:path")
3546 .attr(
"hist-column", i)
3547 .attr(
"d", colPaths[i])
3548 .call(this.lineatt.func)
3549 .call(this.fillatt.func);
3554 JSROOT.TH2Painter.prototype.DrawBinsScatter =
function(w,h) {
3555 var histo = this.GetObject(),
3556 handle = this.PrepareColorDraw(
true,
true),
3557 colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [],
3558 colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1.;
3561 if (this.maxbin > 0.7) factor = 0.7/this.maxbin;
3563 var nlevels = Math.round(handle.max - handle.min);
3564 this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin);
3567 for (i = handle.i1; i < handle.i2; ++i) {
3568 for (j = handle.j1; j < handle.j2; ++j) {
3569 binz = histo.getBinContent(i + 1, j + 1);
3570 if ((binz == 0) || (binz < this.minbin))
continue;
3572 cw = handle.grx[i+1] - handle.grx[i];
3573 ch = handle.gry[j] - handle.gry[j+1];
3574 if (cw*ch <= 0)
continue;
3576 colindx = this.getContourIndex(binz/cw/ch);
3577 if (colindx < 0)
continue;
3579 cmd1 =
"M"+handle.grx[i]+
","+handle.gry[j+1];
3580 if (colPaths[colindx] === undefined) {
3581 colPaths[colindx] = cmd1;
3582 cell_w[colindx] = cw;
3583 cell_h[colindx] = ch;
3585 cmd2 =
"m" + (handle.grx[i]-currx[colindx]) +
"," + (handle.gry[j+1] - curry[colindx]);
3586 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
3587 cell_w[colindx] = Math.max(cell_w[colindx], cw);
3588 cell_h[colindx] = Math.max(cell_h[colindx], ch);
3591 currx[colindx] = handle.grx[i];
3592 curry[colindx] = handle.gry[j+1];
3594 colPaths[colindx] +=
"v"+ch+
"h"+cw+
"v-"+ch+
"z";
3598 var layer = this.svg_frame().select(
'.main_layer');
3599 var defs = layer.select(
"defs");
3600 if (defs.empty() && (colPaths.length>0))
3601 defs = layer.insert(
"svg:defs",
":first-child");
3603 if (!this.markeratt)
3604 this.markeratt = JSROOT.Painter.createAttMarker(histo);
3606 for (colindx=0;colindx<colPaths.length;++colindx)
3607 if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) {
3608 var pattern_class =
"scatter_" + colindx;
3609 var pattern = defs.select(
'.'+pattern_class);
3610 if (pattern.empty())
3611 pattern = defs.append(
'svg:pattern')
3612 .attr(
"class", pattern_class)
3613 .attr(
"id",
"jsroot_scatter_pattern_" + JSROOT.id_counter++)
3614 .attr(
"patternUnits",
"userSpaceOnUse");
3616 pattern.selectAll(
"*").remove();
3618 var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]);
3619 if (npix<1) npix = 1;
3621 var arrx =
new Float32Array(npix), arry =
new Float32Array(npix);
3624 arrx[0] = arry[0] = 0.5;
3626 for (var n=0;n<npix;++n) {
3627 arrx[n] = Math.random();
3628 arry[n] = Math.random();
3634 this.markeratt.reset_pos();
3638 for (var n=0;n<npix;++n)
3639 path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]);
3641 pattern.attr(
"width", cell_w[colindx])
3642 .attr(
"height", cell_h[colindx])
3645 .call(this.markeratt.func);
3649 .attr(
"scatter-index", colindx)
3650 .attr(
"fill",
'url(#' + pattern.attr(
"id") +
')')
3651 .attr(
"d", colPaths[colindx]);
3657 JSROOT.TH2Painter.prototype.DrawBins =
function() {
3659 this.RecreateDrawG(
false,
"main_layer");
3661 var w = this.frame_width(), h = this.frame_height();
3667 if (this.options.Color +
this.options.Box +
this.options.Scat +
this.options.Text == 0)
3668 this.options.Scat = 1;
3670 if (this.options.Color > 0)
3671 handle = this.DrawBinsColor(w, h);
3673 if (this.options.Scat > 0)
3674 handle = this.DrawBinsScatter(w, h);
3676 if (this.options.Box > 0)
3677 handle = this.DrawBinsBox(w, h);
3679 if (this.options.Text>0)
3680 handle = this.DrawBinsText(w, h, handle);
3682 this.tt_handle = handle;
3685 JSROOT.TH2Painter.prototype.GetBinTips =
function (i, j) {
3688 lines.push(this.GetTipName());
3690 if (this.x_kind ==
'labels')
3691 lines.push(
"x = " + this.AxisAsText(
"x", this.GetBinX(i)));
3693 lines.push(
"x = [" + this.AxisAsText(
"x", this.GetBinX(i)) +
", " + this.AxisAsText(
"x", this.GetBinX(i+1)) +
")");
3695 if (this.y_kind ==
'labels')
3696 lines.push(
"y = " + this.AxisAsText(
"y", this.GetBinY(j)));
3698 lines.push(
"y = [" + this.AxisAsText(
"y", this.GetBinY(j)) +
", " + this.AxisAsText(
"y", this.GetBinY(j+1)) +
")");
3700 lines.push(
"bin = " + i +
", " + j);
3702 var binz = this.GetObject().getBinContent(i+1,j+1);
3703 if (binz === Math.round(binz))
3704 lines.push(
"entries = " + binz);
3706 lines.push(
"entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat));
3711 JSROOT.TH2Painter.prototype.ProcessTooltip =
function(pnt) {
3713 if (this.draw_g !== null)
3714 this.draw_g.select(
".tooltip_bin").remove();
3715 this.ProvideUserTooltip(null);
3719 var histo = this.GetObject(),
3724 for (i = h.i1; i < h.i2; ++i)
3725 if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1])) { ++find;
break; }
3727 for (j = h.j1; j <= h.j2; ++j)
3728 if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j])) { ++find;
break; }
3730 var ttrect = this.draw_g.select(
".tooltip_bin");
3732 var binz = (find === 2) ? histo.getBinContent(i+1,j+1) : -100;
3736 if ((find !== 2) || (binz === 0) || (binz < this.minbin)) {
3738 this.ProvideUserTooltip(null);
3742 var res = { x: pnt.x, y: pnt.y,
3743 color1: this.lineatt.color, color2: this.fillatt.color,
3744 lines: this.GetBinTips(i, j), exact:
true, menu:
true };
3746 if (this.options.Color > 0) res.color2 = this.getValueColor(binz);
3749 ttrect = this.draw_g.append(
"svg:rect")
3750 .attr(
"class",
"tooltip_bin h1bin")
3751 .style(
"pointer-events",
"none");
3753 res.changed = ttrect.property(
"current_bin") !== i*10000 + j;
3756 ttrect.attr(
"x", h.grx[i])
3757 .attr(
"width", h.grx[i+1] - h.grx[i])
3758 .attr(
"y", h.gry[j+1])
3759 .attr(
"height", h.gry[j] - h.gry[j+1])
3760 .style(
"opacity",
"0.7")
3761 .property(
"current_bin", i*10000 + j);
3763 if (this.IsUserTooltipCallback() && res.changed) {
3764 this.ProvideUserTooltip({ obj: histo, name: histo.fName,
3765 bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1,
3766 grx: pnt.x, gry: pnt.y });
3772 JSROOT.TH2Painter.prototype.CanZoomIn =
function(axis,min,max) {
3774 if ((axis==
"x") && (this.GetIndexX(max,0.5) - this.GetIndexX(min,0) > 1))
return true;
3776 if ((axis==
"y") && (this.GetIndexY(max,0.5) - this.GetIndexY(min,0) > 1))
return true;
3778 if (axis==
"z")
return true;
3783 JSROOT.TH2Painter.prototype.Draw2D =
function(call_back) {
3785 if (typeof
this[
'Create3DScene'] ==
'function')
3786 this.Create3DScene(-1);
3796 JSROOT.CallBack(call_back);
3799 JSROOT.TH2Painter.prototype.CheckResize =
function(size) {
3801 var pad_painter = this.pad_painter();
3802 var changed =
true, force = (this.options.Lego > 0) && !JSROOT.browser.isFirefox;
3804 changed = pad_painter.CheckCanvasResize(size, force);
3805 if (changed && (this.options.Lego > 0) && (typeof
this[
'Resize3D'] ==
'function'))
3811 JSROOT.TH2Painter.prototype.Draw3D =
function(call_back) {
3812 JSROOT.AssertPrerequisites(
'3d',
function() {
3813 this[
'Create3DScene'] = JSROOT.Painter.HPainter_Create3DScene;
3814 this[
'Draw3DBins'] = JSROOT.Painter.TH2Painter_Draw3DBins;
3815 this[
'Draw3D'] = JSROOT.Painter.TH2Painter_Draw3D;
3816 this[
'Draw3D'](call_back);
3820 JSROOT.TH2Painter.prototype.Redraw =
function() {
3823 var func_name = (this.options.Lego > 0) ?
"Draw3D" :
"Draw2D";
3828 JSROOT.Painter.drawHistogram2D =
function(divid, histo, opt) {
3830 JSROOT.extend(
this,
new JSROOT.TH2Painter(histo));
3832 this.SetDivId(divid, 1);
3835 this.options = this.DecodeOptions(opt);
3837 this.CheckPadOptions();
3842 if (this.create_canvas && (this.options.Zscale > 0))
3844 this.DrawNewPalette(
true);
3850 if (JSROOT.gStyle.AutoStat &&
this.create_canvas)
3853 var func_name = this.options.Lego > 0 ?
"Draw3D" :
"Draw2D";
3855 this[func_name](
function() {
3856 this.DrawNextFunction(0,
function() {
3857 if (this.options.Lego == 0) {
3858 this.AddInteractive();
3859 if (this.options.AutoZoom) this.AutoZoom();
3862 this.DrawingReady();
3870 return JSROOT.Painter;