00001
00002
00003
00004
00005 (function( factory ) {
00006 if ( typeof define === "function" && define.amd ) {
00007
00008 define( ['d3', 'JSRootPainter', 'JSRootMath'], factory );
00009 } else {
00010
00011 if (typeof d3 != 'object')
00012 throw new Error('This extension requires d3.v3.js', 'JSRootPainter.more.js');
00013
00014 if (typeof JSROOT == 'undefined')
00015 throw new Error('JSROOT is not defined', 'JSRootPainter.more.js');
00016
00017 if (typeof JSROOT.Painter != 'object')
00018 throw new Error('JSROOT.Painter not defined', 'JSRootPainter.more.js');
00019
00020
00021 factory(d3, JSROOT);
00022 }
00023 } (function(d3, JSROOT) {
00024
00025 JSROOT.ToolbarIcons.th2color = {
00026 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}]
00027 };
00028
00029 JSROOT.ToolbarIcons.th2colorz = {
00030 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)'}]
00031 };
00032
00033 JSROOT.ToolbarIcons.th2draw3d = {
00034 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 "+
00035 "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 "+
00036 "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 "+
00037 "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"
00038 };
00039
00040 JSROOT.Painter.CreateDefaultPalette = function() {
00041
00042 function HLStoRGB(h, l, s) {
00043 var r, g, b;
00044 if (s < 1e-300) {
00045 r = g = b = l;
00046 } else {
00047 function hue2rgb(p, q, t) {
00048 if (t < 0) t += 1;
00049 if (t > 1) t -= 1;
00050 if (t < 1 / 6) return p + (q - p) * 6 * t;
00051 if (t < 1 / 2) return q;
00052 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
00053 return p;
00054 }
00055 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
00056 var p = 2 * l - q;
00057 r = hue2rgb(p, q, h + 1 / 3);
00058 g = hue2rgb(p, q, h);
00059 b = hue2rgb(p, q, h - 1 / 3);
00060 }
00061 return 'rgb(' + Math.round(r * 255) + ',' + Math.round(g * 255) + ',' + Math.round(b * 255) + ')';
00062 }
00063
00064 var palette = [], saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50;
00065 for (var i = 0; i < maxPretty; ++i) {
00066 var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360.0;
00067 var rgbval = HLStoRGB(hue, lightness, saturation);
00068 palette.push(rgbval);
00069 }
00070 return palette;
00071 }
00072
00073 JSROOT.Painter.CreateGrayPalette = function() {
00074 var palette = [];
00075 for (var i = 0; i < 50; ++i) {
00076 var code = Math.round((i+2)/60 * 255 );
00077 palette.push('rgb('+code+','+code+','+code+')');
00078 }
00079 return palette;
00080 }
00081
00082 JSROOT.Painter.CreateGradientColorTable = function(Stops, Red, Green, Blue, NColors, alpha) {
00083
00084 var palette = [];
00085
00086 for (var g = 1; g < Stops.length; g++) {
00087
00088 var nColorsGradient = parseInt(Math.floor(NColors*Stops[g]) - Math.floor(NColors*Stops[g-1]));
00089 for (var c = 0; c < nColorsGradient; c++) {
00090 var col = Math.round(Red[g-1] + c * (Red[g] - Red[g-1])/nColorsGradient) + "," +
00091 Math.round(Green[g-1] + c * (Green[g] - Green[g-1])/ nColorsGradient) + "," +
00092 Math.round(Blue[g-1] + c * (Blue[g] - Blue[g-1])/ nColorsGradient);
00093 palette.push("rgb("+col+")");
00094 }
00095 }
00096
00097 return palette;
00098 }
00099
00100 JSROOT.Painter.GetColorPalette = function(col,alfa) {
00101 if ((col == null) || (col==0)) col = JSROOT.gStyle.Palette;
00102 if ((col>0) && (col<10)) return JSROOT.Painter.CreateGrayPalette();
00103 if (col < 51) return JSROOT.Painter.CreateDefaultPalette();
00104 if (col > 112) col = 57;
00105
00106 var red, green, blue,
00107 stops = [ 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000 ];
00108 switch(col) {
00109
00110
00111 case 51:
00112 red = [ 0, 9, 13, 17, 24, 32, 27, 25, 29];
00113 green = [ 0, 0, 0, 2, 37, 74, 113, 160, 221];
00114 blue = [ 28, 42, 59, 78, 98, 129, 154, 184, 221];
00115 break;
00116
00117
00118 case 52:
00119 red = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
00120 green = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
00121 blue = [ 0, 32, 64, 96, 128, 160, 192, 224, 255];
00122 break;
00123
00124
00125 case 53:
00126 red = [ 0, 45, 99, 156, 212, 230, 237, 234, 242];
00127 green = [ 0, 0, 0, 45, 101, 168, 238, 238, 243];
00128 blue = [ 0, 1, 1, 3, 9, 8, 11, 95, 230];
00129 break;
00130
00131
00132 case 54:
00133 red = [ 0, 22, 44, 68, 93, 124, 160, 192, 237];
00134 green = [ 0, 16, 41, 67, 93, 125, 162, 194, 241];
00135 blue = [ 97, 100, 99, 99, 93, 68, 44, 26, 74];
00136 break;
00137
00138
00139 case 55:
00140 red = [ 0, 5, 15, 35, 102, 196, 208, 199, 110];
00141 green = [ 0, 48, 124, 192, 206, 226, 97, 16, 0];
00142 blue = [ 99, 142, 198, 201, 90, 22, 13, 8, 2];
00143 break;
00144
00145
00146 case 56:
00147 red = [ 242, 234, 237, 230, 212, 156, 99, 45, 0];
00148 green = [ 243, 238, 238, 168, 101, 45, 0, 0, 0];
00149 blue = [ 230, 95, 11, 8, 9, 3, 1, 1, 0];
00150 break;
00151
00152
00153 case 57:
00154 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];
00155 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];
00156 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];
00157 break;
00158
00159
00160 case 58:
00161 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];
00162 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];
00163 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];
00164 break;
00165
00166
00167 case 59:
00168 red = [13, 23, 25, 63, 76, 104, 137, 161, 206];
00169 green = [95, 67, 37, 21, 0, 12, 35, 52, 79];
00170 blue = [ 4, 3, 2, 6, 11, 22, 49, 98, 208];
00171 break;
00172
00173
00174 case 60:
00175 red = [0, 61, 89, 122, 143, 160, 185, 204, 231];
00176 green = [0, 0, 0, 0, 14, 37, 72, 132, 235];
00177 blue = [0, 140, 224, 144, 4, 5, 6, 9, 13];
00178 break;
00179
00180
00181 case 61:
00182 red = [ 14, 7, 2, 0, 5, 11, 55, 131, 229];
00183 green = [105, 56, 26, 1, 42, 74, 131, 171, 229];
00184 blue = [ 2, 21, 35, 60, 92, 113, 160, 185, 229];
00185 break;
00186
00187
00188 case 62:
00189 red = [ 0, 0, 0, 70, 148, 231, 235, 237, 244];
00190 green = [ 0, 0, 0, 0, 0, 69, 67, 216, 244];
00191 blue = [ 0, 102, 228, 231, 177, 124, 137, 20, 244];
00192 break;
00193
00194
00195 case 63:
00196 red = [ 50, 56, 63, 68, 93, 121, 165, 192, 241];
00197 green = [ 66, 81, 91, 96, 111, 128, 155, 189, 241];
00198 blue = [ 97, 91, 75, 65, 77, 103, 143, 167, 217];
00199 break;
00200
00201
00202 case 64:
00203 red = [ 145, 166, 167, 156, 131, 114, 101, 112, 132];
00204 green = [ 158, 178, 179, 181, 163, 154, 144, 152, 159];
00205 blue = [ 190, 199, 201, 192, 176, 169, 160, 166, 190];
00206 break;
00207
00208
00209 case 65:
00210 red = [ 93, 91, 99, 108, 130, 125, 132, 155, 174];
00211 green = [ 126, 124, 128, 129, 131, 121, 119, 153, 173];
00212 blue = [ 103, 94, 87, 85, 80, 85, 107, 120, 146];
00213 break;
00214
00215
00216 case 66:
00217 red = [ 24, 40, 69, 90, 104, 114, 120, 132, 103];
00218 green = [ 29, 52, 94, 127, 150, 162, 159, 151, 101];
00219 blue = [ 29, 52, 96, 132, 162, 181, 184, 186, 131];
00220 break;
00221
00222
00223 case 67:
00224 red = [ 46, 38, 61, 92, 113, 121, 132, 150, 191];
00225 green = [ 46, 36, 40, 69, 110, 135, 131, 92, 34];
00226 blue = [ 46, 80, 74, 70, 81, 105, 165, 211, 225];
00227 break;
00228
00229
00230 case 68:
00231 red = [ 0, 4, 12, 30, 52, 101, 142, 190, 237];
00232 green = [ 0, 40, 86, 121, 140, 172, 187, 213, 240];
00233 blue = [ 0, 9, 14, 18, 21, 23, 27, 35, 101];
00234 break;
00235
00236
00237 case 69:
00238 red = [ 198, 206, 206, 211, 198, 181, 161, 171, 244];
00239 green = [ 103, 133, 150, 172, 178, 174, 163, 175, 244];
00240 blue = [ 49, 54, 55, 66, 91, 130, 184, 224, 244];
00241 break;
00242
00243
00244 case 70:
00245 red = [ 243, 243, 240, 240, 241, 239, 186, 151, 129];
00246 green = [ 0, 46, 99, 149, 194, 220, 183, 166, 147];
00247 blue = [ 6, 8, 36, 91, 169, 235, 246, 240, 233];
00248 break;
00249
00250
00251 case 71:
00252 red = [ 22, 19, 19, 25, 35, 53, 88, 139, 210];
00253 green = [ 0, 32, 69, 108, 135, 159, 183, 198, 215];
00254 blue = [ 77, 96, 110, 116, 110, 100, 90, 78, 70];
00255 break;
00256
00257
00258 case 72:
00259 red = [ 68, 116, 165, 182, 189, 180, 145, 111, 71];
00260 green = [ 37, 82, 135, 178, 204, 225, 221, 202, 147];
00261 blue = [ 16, 55, 105, 147, 196, 226, 232, 224, 178];
00262 break;
00263
00264
00265 case 73:
00266 red = [ 61, 99, 136, 181, 213, 225, 198, 136, 24];
00267 green = [ 149, 140, 96, 83, 132, 178, 190, 135, 22];
00268 blue = [ 214, 203, 168, 135, 110, 100, 111, 113, 22];
00269 break;
00270
00271
00272 case 74:
00273 red = [ 76, 120, 156, 183, 197, 180, 162, 154, 140];
00274 green = [ 34, 35, 42, 69, 102, 137, 164, 188, 197];
00275 blue = [ 64, 69, 78, 105, 142, 177, 205, 217, 198];
00276 break;
00277
00278
00279 case 75:
00280 red = [ 37, 102, 157, 188, 196, 214, 223, 235, 251];
00281 green = [ 37, 29, 25, 37, 67, 91, 132, 185, 251];
00282 blue = [ 37, 32, 33, 45, 66, 98, 137, 187, 251];
00283 break;
00284
00285
00286 case 76:
00287 red = [ 79, 100, 119, 137, 153, 172, 192, 205, 250];
00288 green = [ 63, 79, 93, 103, 115, 135, 167, 196, 250];
00289 blue = [ 51, 59, 66, 61, 62, 70, 110, 160, 250];
00290 break;
00291
00292
00293 case 77:
00294 red = [ 43, 44, 50, 66, 125, 172, 178, 155, 157];
00295 green = [ 63, 63, 85, 101, 138, 163, 122, 51, 39];
00296 blue = [ 121, 101, 58, 44, 47, 55, 57, 44, 43];
00297 break;
00298
00299
00300 case 78:
00301 red = [ 0, 41, 62, 79, 90, 87, 99, 140, 228];
00302 green = [ 0, 57, 81, 93, 85, 70, 71, 125, 228];
00303 blue = [ 95, 91, 91, 82, 60, 43, 44, 112, 228];
00304 break;
00305
00306
00307 case 79:
00308 red = [ 49, 59, 72, 88, 114, 141, 176, 205, 222];
00309 green = [ 78, 72, 66, 57, 59, 75, 106, 142, 173];
00310 blue = [ 78, 55, 46, 40, 39, 39, 40, 41, 47];
00311 break;
00312
00313
00314 case 80:
00315 red = [ 243, 222, 201, 185, 165, 158, 166, 187, 219];
00316 green = [ 94, 108, 132, 135, 125, 96, 68, 51, 61];
00317 blue = [ 7, 9, 12, 19, 45, 89, 118, 146, 118];
00318 break;
00319
00320
00321 case 81:
00322 red = [ 19, 44, 74, 105, 137, 166, 194, 206, 220];
00323 green = [ 19, 28, 40, 55, 82, 110, 159, 181, 220];
00324 blue = [ 19, 42, 68, 96, 129, 157, 188, 203, 220];
00325 break;
00326
00327
00328 case 82:
00329 red = [ 33, 44, 70, 99, 140, 165, 199, 211, 216];
00330 green = [ 38, 50, 76, 105, 140, 165, 191, 189, 167];
00331 blue = [ 55, 67, 97, 124, 140, 166, 163, 129, 52];
00332 break;
00333
00334
00335 case 83:
00336 red = [ 0, 33, 73, 124, 136, 152, 159, 171, 223];
00337 green = [ 0, 43, 92, 124, 134, 126, 121, 144, 223];
00338 blue = [ 0, 43, 68, 76, 73, 64, 72, 114, 223];
00339 break;
00340
00341
00342 case 84:
00343 red = [ 5, 18, 45, 124, 193, 223, 205, 128, 49];
00344 green = [ 48, 134, 207, 230, 193, 113, 28, 0, 7];
00345 blue = [ 6, 15, 41, 121, 193, 226, 208, 130, 49];
00346 break;
00347
00348
00349 case 85:
00350 red = [ 180, 106, 104, 135, 164, 188, 189, 165, 144];
00351 green = [ 72, 126, 154, 184, 198, 207, 205, 190, 179];
00352 blue = [ 41, 120, 158, 188, 194, 181, 145, 100, 62];
00353 break;
00354
00355
00356 case 86:
00357 red = [ 57, 72, 94, 117, 136, 154, 174, 192, 215];
00358 green = [ 0, 33, 68, 109, 140, 171, 192, 196, 209];
00359 blue = [ 116, 137, 173, 201, 200, 201, 203, 190, 187];
00360 break;
00361
00362
00363 case 87:
00364 red = [ 31, 71, 123, 160, 210, 222, 214, 199, 183];
00365 green = [ 40, 117, 171, 211, 231, 220, 190, 132, 65];
00366 blue = [ 234, 214, 228, 222, 210, 160, 105, 60, 34];
00367 break;
00368
00369
00370 case 88:
00371 red = [ 123, 108, 109, 126, 154, 172, 188, 196, 218];
00372 green = [ 184, 138, 130, 133, 154, 175, 188, 196, 218];
00373 blue = [ 208, 130, 109, 99, 110, 122, 150, 171, 218];
00374 break;
00375
00376
00377 case 89:
00378 red = [ 105, 106, 122, 143, 159, 172, 176, 181, 207];
00379 green = [ 252, 197, 194, 187, 174, 162, 153, 136, 125];
00380 blue = [ 146, 133, 144, 155, 163, 167, 166, 162, 174];
00381 break;
00382
00383
00384 case 90:
00385 red = [ 171, 141, 145, 152, 154, 159, 163, 158, 177];
00386 green = [ 236, 143, 100, 63, 53, 55, 44, 31, 6];
00387 blue = [ 59, 48, 46, 44, 42, 54, 82, 112, 179];
00388 break;
00389
00390
00391 case 91:
00392 red = [ 180, 190, 209, 223, 204, 228, 205, 152, 91];
00393 green = [ 93, 125, 147, 172, 181, 224, 233, 198, 158];
00394 blue = [ 236, 218, 160, 133, 114, 132, 162, 220, 218];
00395 break;
00396
00397
00398 case 92:
00399 red = [ 225, 183, 162, 135, 115, 111, 119, 145, 211];
00400 green = [ 205, 177, 166, 135, 124, 117, 117, 132, 172];
00401 blue = [ 186, 165, 155, 135, 126, 130, 150, 178, 226];
00402 break;
00403
00404
00405 case 93:
00406 red = [ 39, 43, 59, 63, 80, 116, 153, 177, 223];
00407 green = [ 39, 43, 59, 74, 91, 114, 139, 165, 223];
00408 blue = [ 39, 50, 59, 70, 85, 115, 151, 176, 223];
00409 break;
00410
00411
00412 case 94:
00413 red = [ 0, 38, 60, 76, 84, 89, 101, 128, 204];
00414 green = [ 0, 10, 15, 23, 35, 57, 83, 123, 199];
00415 blue = [ 0, 11, 22, 40, 63, 86, 97, 94, 85];
00416 break;
00417
00418
00419 case 95:
00420 red = [ 94, 112, 141, 165, 167, 140, 91, 49, 27];
00421 green = [ 27, 46, 88, 135, 166, 161, 135, 97, 58];
00422 blue = [ 42, 52, 81, 106, 139, 158, 155, 137, 116];
00423 break;
00424
00425
00426 case 96:
00427 red = [ 30, 49, 79, 117, 135, 151, 146, 138, 147];
00428 green = [ 63, 60, 72, 90, 94, 94, 68, 46, 16];
00429 blue = [ 18, 28, 41, 56, 62, 63, 50, 36, 21];
00430 break;
00431
00432
00433 case 97:
00434 red = [ 0, 30, 63, 101, 143, 152, 169, 187, 230];
00435 green = [ 0, 14, 28, 42, 58, 61, 67, 74, 91];
00436 blue = [ 39, 26, 21, 18, 15, 14, 14, 13, 13];
00437 break;
00438
00439
00440 case 98:
00441 red = [ 149, 140, 164, 179, 182, 181, 131, 87, 61];
00442 green = [ 62, 70, 107, 136, 144, 138, 117, 87, 74];
00443 blue = [ 40, 38, 45, 49, 49, 49, 38, 32, 34];
00444 break;
00445
00446
00447 case 99:
00448 red = [ 99, 112, 148, 165, 179, 182, 183, 183, 208];
00449 green = [ 39, 40, 57, 79, 104, 127, 148, 161, 198];
00450 blue = [ 15, 16, 18, 33, 51, 79, 103, 129, 177];
00451 break;
00452
00453
00454 case 100:
00455 red = [ 99, 116, 154, 174, 200, 196, 201, 201, 230];
00456 green = [ 0, 0, 8, 32, 58, 83, 119, 136, 173];
00457 blue = [ 5, 6, 7, 9, 9, 14, 17, 19, 24];
00458 break;
00459
00460
00461 case 101:
00462 red = [ 82, 106, 126, 141, 155, 163, 142, 107, 66];
00463 green = [ 62, 44, 69, 107, 135, 152, 149, 132, 119];
00464 blue = [ 39, 25, 31, 60, 73, 68, 49, 72, 188];
00465 break;
00466
00467
00468 case 102:
00469 red = [ 18, 29, 44, 72, 116, 158, 184, 208, 221];
00470 green = [ 27, 46, 71, 105, 146, 177, 189, 190, 183];
00471 blue = [ 39, 55, 80, 108, 130, 133, 124, 100, 76];
00472 break;
00473
00474
00475 case 103:
00476 red = [ 0, 48, 119, 173, 212, 224, 228, 228, 245];
00477 green = [ 0, 13, 30, 47, 79, 127, 167, 205, 245];
00478 blue = [ 0, 68, 75, 43, 16, 22, 55, 128, 245];
00479 break;
00480
00481
00482 case 104:
00483 red = [ 34, 70, 129, 187, 225, 226, 216, 193, 179];
00484 green = [ 48, 91, 147, 194, 226, 229, 196, 110, 12];
00485 blue = [ 234, 212, 216, 224, 206, 110, 53, 40, 29];
00486 break;
00487
00488
00489 case 105:
00490 red = [ 30, 55, 103, 147, 174, 203, 188, 151, 105];
00491 green = [ 0, 65, 138, 182, 187, 175, 121, 53, 9];
00492 blue = [ 191, 202, 212, 208, 171, 140, 97, 57, 30];
00493 break;
00494
00495
00496 case 106:
00497 red = [ 112, 97, 113, 125, 138, 159, 178, 188, 225];
00498 green = [ 16, 17, 24, 37, 56, 81, 110, 136, 189];
00499 blue = [ 38, 35, 46, 59, 78, 103, 130, 152, 201];
00500 break;
00501
00502
00503 case 107:
00504 red = [ 18, 72, 5, 23, 29, 201, 200, 98, 29];
00505 green = [ 0, 0, 43, 167, 211, 117, 0, 0, 0];
00506 blue = [ 51, 203, 177, 26, 10, 9, 8, 3, 0];
00507 break;
00508
00509
00510 case 108:
00511 red = [ 19, 42, 64, 88, 118, 147, 175, 187, 205];
00512 green = [ 19, 55, 89, 125, 154, 169, 161, 129, 70];
00513 blue = [ 19, 32, 47, 70, 100, 128, 145, 130, 75];
00514 break;
00515
00516
00517 case 109:
00518 red = [ 33, 31, 42, 68, 86, 111, 141, 172, 227];
00519 green = [ 255, 175, 145, 106, 88, 55, 15, 0, 0];
00520 blue = [ 255, 205, 202, 203, 208, 205, 203, 206, 231];
00521 break;
00522
00523
00524 case 110:
00525 red = [ 0, 25, 50, 79, 110, 145, 181, 201, 254];
00526 green = [ 0, 16, 30, 46, 63, 82, 101, 124, 179];
00527 blue = [ 0, 12, 21, 29, 39, 49, 61, 74, 103];
00528 break;
00529
00530
00531 case 111:
00532 red = [ 0, 13, 30, 44, 72, 120, 156, 200, 247];
00533 green = [ 0, 36, 84, 117, 141, 153, 151, 158, 247];
00534 blue = [ 0, 94, 100, 82, 56, 66, 76, 131, 247];
00535 break;
00536
00537
00538 case 112:
00539 red = [ 26, 51, 43, 33, 28, 35, 74, 144, 246];
00540 green = [ 9, 24, 55, 87, 118, 150, 180, 200, 222];
00541 blue = [ 30, 96, 112, 114, 112, 101, 72, 35, 0];
00542 break;
00543
00544 default:
00545 return JSROOT.Painter.CreateDefaultPalette();
00546 }
00547
00548 return JSROOT.Painter.CreateGradientColorTable(stops, red, green, blue, 255, alfa);
00549 }
00550
00551
00552
00553
00554 JSROOT.Painter.drawEllipse = function(divid, obj, opt) {
00555
00556 this.SetDivId(divid);
00557
00558 this.Redraw = function() {
00559 var ellipse = this.GetObject();
00560
00561 if(!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(ellipse);
00562 if (!this.fillatt) this.fillatt = this.createAttFill(ellipse);
00563
00564
00565 this.RecreateDrawG(this.main_painter() == null);
00566
00567 var x = this.AxisToSvg("x", ellipse.fX1);
00568 var y = this.AxisToSvg("y", ellipse.fY1);
00569 var rx = this.AxisToSvg("x", ellipse.fX1 + ellipse.fR1) - x;
00570 var ry = y - this.AxisToSvg("y", ellipse.fY1 + ellipse.fR2);
00571
00572 if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360) && (ellipse.fTheta == 0)) {
00573
00574 this.draw_g
00575 .append("svg:ellipse")
00576 .attr("cx", x.toFixed(1)).attr("cy", y.toFixed(1))
00577 .attr("rx", rx.toFixed(1)).attr("ry", ry.toFixed(1))
00578 .call(this.lineatt.func).call(this.fillatt.func);
00579 return;
00580 }
00581
00582
00583
00584 var ct = Math.cos(Math.PI*ellipse.fTheta/180.);
00585 var st = Math.sin(Math.PI*ellipse.fTheta/180.);
00586
00587 var dx1 = rx * Math.cos(ellipse.fPhimin*Math.PI/180.);
00588 var dy1 = ry * Math.sin(ellipse.fPhimin*Math.PI/180.);
00589 var x1 = dx1*ct - dy1*st;
00590 var y1 = -dx1*st - dy1*ct;
00591
00592 var dx2 = rx * Math.cos(ellipse.fPhimax*Math.PI/180.);
00593 var dy2 = ry * Math.sin(ellipse.fPhimax*Math.PI/180.);
00594 var x2 = dx2*ct - dy2*st;
00595 var y2 = -dx2*st - dy2*ct;
00596
00597 this.draw_g
00598 .attr("transform","translate("+x.toFixed(1)+","+y.toFixed(1)+")")
00599 .append("svg:path")
00600 .attr("d", "M 0,0" +
00601 " L " + x1.toFixed(1) + "," + y1.toFixed(1) +
00602 " A " + rx.toFixed(1) + " " + ry.toFixed(1) + " " + -ellipse.fTheta.toFixed(1) + " 1 0 " + x2.toFixed(1) + "," + y2.toFixed(1) +
00603 " L 0,0 Z")
00604 .call(this.lineatt.func).call(this.fillatt.func);
00605 }
00606
00607 this.Redraw();
00608 return this.DrawingReady();
00609 }
00610
00611
00612
00613 JSROOT.Painter.drawLine = function(divid, obj, opt) {
00614
00615 this.SetDivId(divid);
00616
00617 this.Redraw = function() {
00618 var line = this.GetObject(),
00619 lineatt = JSROOT.Painter.createAttLine(line);
00620
00621
00622 this.RecreateDrawG(this.main_painter() == null);
00623
00624 this.draw_g
00625 .append("svg:line")
00626 .attr("x1", this.AxisToSvg("x", line.fX1).toFixed(1))
00627 .attr("y1", this.AxisToSvg("y", line.fY1).toFixed(1))
00628 .attr("x2", this.AxisToSvg("x", line.fX2).toFixed(1))
00629 .attr("y2", this.AxisToSvg("y", line.fY2).toFixed(1))
00630 .call(lineatt.func);
00631 }
00632
00633 this.Redraw();
00634
00635 return this.DrawingReady();
00636 }
00637
00638
00639
00640 JSROOT.Painter.drawBox = function(divid, obj, opt) {
00641
00642 this.SetDivId(divid);
00643
00644 this.Redraw = function() {
00645 var box = this.GetObject(),
00646 lineatt = JSROOT.Painter.createAttLine(box),
00647 fillatt = this.createAttFill(box);
00648
00649
00650 this.RecreateDrawG(this.main_painter() == null);
00651
00652 var x1 = Math.round(this.AxisToSvg("x", box.fX1)),
00653 x2 = Math.round(this.AxisToSvg("x", box.fX2)),
00654 y1 = Math.round(this.AxisToSvg("y", box.fY1)),
00655 y2 = Math.round(this.AxisToSvg("y", box.fY2));
00656
00657 this.draw_g
00658 .append("svg:rect")
00659 .attr("x", Math.min(x1,x2))
00660 .attr("y", Math.min(y1,y2))
00661 .attr("width", Math.abs(x2-x1))
00662 .attr("height", Math.abs(y1-y2))
00663 .call(lineatt.func)
00664 .call(fillatt.func);
00665 }
00666
00667 this.Redraw();
00668
00669 return this.DrawingReady();
00670 }
00671
00672
00673
00674 JSROOT.Painter.drawArrow = function(divid, obj, opt) {
00675
00676 this.SetDivId(divid);
00677
00678 this.Redraw = function() {
00679 var arrow = this.GetObject();
00680 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(arrow);
00681 if (!this.fillatt) this.fillatt = this.createAttFill(arrow);
00682
00683 var wsize = Math.max(this.pad_width(), this.pad_height()) * arrow.fArrowSize;
00684 if (wsize<3) wsize = 3;
00685 var hsize = wsize * Math.tan(arrow.fAngle/2 * (Math.PI/180));
00686
00687
00688 this.RecreateDrawG(this.main_painter() == null);
00689
00690 var x1 = this.AxisToSvg("x", arrow.fX1),
00691 y1 = this.AxisToSvg("y", arrow.fY1),
00692 x2 = this.AxisToSvg("x", arrow.fX2),
00693 y2 = this.AxisToSvg("y", arrow.fY2),
00694 right_arrow = "M0,0" + " L"+wsize.toFixed(1) +","+hsize.toFixed(1) + " L0," + (hsize*2).toFixed(1),
00695 left_arrow = "M" + wsize.toFixed(1) + ", 0" + " L 0," + hsize.toFixed(1) + " L " + wsize.toFixed(1) + "," + (hsize*2).toFixed(1),
00696 m_start = null, m_mid = null, m_end = null, defs = null,
00697 oo = arrow.fOption, len = oo.length;
00698
00699 if (oo.indexOf("<")==0) {
00700 var closed = (oo.indexOf("<|") == 0);
00701 if (!defs) defs = this.draw_g.append("defs");
00702 m_start = "jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
00703 var beg = defs.append("svg:marker")
00704 .attr("id", m_start)
00705 .attr("markerWidth", wsize.toFixed(1))
00706 .attr("markerHeight", (hsize*2).toFixed(1))
00707 .attr("refX", "0")
00708 .attr("refY", hsize.toFixed(1))
00709 .attr("orient", "auto")
00710 .attr("markerUnits", "userSpaceOnUse")
00711 .append("svg:path")
00712 .style("fill","none")
00713 .attr("d", left_arrow + (closed ? " Z" : ""))
00714 .call(this.lineatt.func);
00715 if (closed) beg.call(this.fillatt.func);
00716 }
00717
00718 var midkind = 0;
00719 if (oo.indexOf("->-")>=0) midkind = 1; else
00720 if (oo.indexOf("-|>-")>=0) midkind = 11; else
00721 if (oo.indexOf("-<-")>=0) midkind = 2; else
00722 if (oo.indexOf("-<|-")>=0) midkind = 12;
00723
00724 if (midkind > 0) {
00725 var closed = midkind > 10;
00726 if (!defs) defs = this.draw_g.append("defs");
00727 m_mid = "jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
00728
00729 var mid = defs.append("svg:marker")
00730 .attr("id", m_mid)
00731 .attr("markerWidth", wsize.toFixed(1))
00732 .attr("markerHeight", (hsize*2).toFixed(1))
00733 .attr("refX", (wsize*0.5).toFixed(1))
00734 .attr("refY", hsize.toFixed(1))
00735 .attr("orient", "auto")
00736 .attr("markerUnits", "userSpaceOnUse")
00737 .append("svg:path")
00738 .style("fill","none")
00739 .attr("d", ((midkind % 10 == 1) ? right_arrow : left_arrow) +
00740 ((midkind > 10) ? " Z" : ""))
00741 .call(this.lineatt.func);
00742 if (midkind > 10) mid.call(this.fillatt.func);
00743 }
00744
00745 if (oo.lastIndexOf(">") == len-1) {
00746 var closed = (oo.lastIndexOf("|>") == len-2) && (len>1);
00747 if (!defs) defs = this.draw_g.append("defs");
00748 m_end = "jsroot_arrowmarker_" + JSROOT.Painter.arrowcnt++;
00749 var end = defs.append("svg:marker")
00750 .attr("id", m_end)
00751 .attr("markerWidth", wsize.toFixed(1))
00752 .attr("markerHeight", (hsize*2).toFixed(1))
00753 .attr("refX", wsize.toFixed(1))
00754 .attr("refY", hsize.toFixed(1))
00755 .attr("orient", "auto")
00756 .attr("markerUnits", "userSpaceOnUse")
00757 .append("svg:path")
00758 .style("fill","none")
00759 .attr("d", right_arrow + (closed ? " Z" : ""))
00760 .call(this.lineatt.func);
00761 if (closed) end.call(this.fillatt.func);
00762 }
00763
00764 var path = this.draw_g
00765 .append("svg:path")
00766 .attr("d", "M" + x1.toFixed(1) + "," + y1.toFixed(1) +
00767 ((m_mid == null) ? "" : "L" + (x1/2+x2/2).toFixed(1) + "," + (y1/2+y2/2).toFixed(1)) +
00768 " L" + x2.toFixed(1) + "," + y2.toFixed(1))
00769 .call(this.lineatt.func);
00770
00771 if (m_start!=null) path.style("marker-start","url(#" + m_start + ")");
00772 if (m_mid!=null) path.style("marker-mid","url(#" + m_mid + ")");
00773 if (m_end!=null) path.style("marker-end","url(#" + m_end + ")");
00774 }
00775
00776 if (!('arrowcnt' in JSROOT.Painter)) JSROOT.Painter.arrowcnt = 0;
00777
00778 this.Redraw();
00779 return this.DrawingReady();
00780 }
00781
00782
00783
00784 JSROOT.Painter.BuildSvgPath = function(kind, bins, height, ndig) {
00785
00786
00787
00788
00789 var smooth = kind.indexOf("bezier") >= 0;
00790
00791 if (ndig===undefined) ndig = smooth ? 2 : 0;
00792 if (height===undefined) height = 0;
00793
00794 function jsroot_d3_svg_lineSlope(p0, p1) {
00795 return (p1.gry - p0.gry) / (p1.grx - p0.grx);
00796 }
00797 function jsroot_d3_svg_lineFiniteDifferences(points) {
00798 var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = jsroot_d3_svg_lineSlope(p0, p1);
00799 while (++i < j) {
00800 m[i] = (d + (d = jsroot_d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
00801 }
00802 m[i] = d;
00803 return m;
00804 }
00805 function jsroot_d3_svg_lineMonotoneTangents(points) {
00806 var d, a, b, s, m = jsroot_d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
00807 while (++i < j) {
00808 d = jsroot_d3_svg_lineSlope(points[i], points[i + 1]);
00809 if (Math.abs(d) < 1e-6) {
00810 m[i] = m[i + 1] = 0;
00811 } else {
00812 a = m[i] / d;
00813 b = m[i + 1] / d;
00814 s = a * a + b * b;
00815 if (s > 9) {
00816 s = d * 3 / Math.sqrt(s);
00817 m[i] = s * a;
00818 m[i + 1] = s * b;
00819 }
00820 }
00821 }
00822 i = -1;
00823 while (++i <= j) {
00824 s = (points[Math.min(j, i + 1)].grx - points[Math.max(0, i - 1)].grx) / (6 * (1 + m[i] * m[i]));
00825 points[i].dgrx = s || 0;
00826 points[i].dgry = m[i]*s || 0;
00827 }
00828 }
00829
00830 var res = {}, bin = bins[0], prev, maxy = Math.max(bin.gry, height+5),
00831 currx = Math.round(bin.grx), curry = Math.round(bin.gry), dx, dy;
00832
00833 res.path = ((kind.charAt(0) == "L") ? "L" : "M") +
00834 bin.grx.toFixed(ndig) + "," + bin.gry.toFixed(ndig);
00835
00836
00837 if (smooth || kind.indexOf('calc')>=0)
00838 jsroot_d3_svg_lineMonotoneTangents(bins);
00839
00840 if (smooth) {
00841 res.path += "c" + bin.dgrx.toFixed(ndig) + "," + bin.dgry.toFixed(ndig) + ",";
00842 }
00843
00844 for(n=1; n<bins.length; ++n) {
00845 prev = bin;
00846 bin = bins[n];
00847 if (smooth) {
00848 if (n > 1) res.path += "s";
00849 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);
00850 maxy = Math.max(maxy, prev.gry);
00851 } else {
00852 dx = Math.round(bin.grx - currx);
00853 dy = Math.round(bin.gry - curry);
00854 res.path += "l" + dx + "," + dy;
00855 currx+=dx; curry+=dy;
00856 maxy = Math.max(maxy, curry);
00857 }
00858 }
00859
00860 if (height>0)
00861 res.close = "L" + bin.grx.toFixed(ndig) +"," + maxy.toFixed(ndig) +
00862 "L" + bins[0].grx.toFixed(ndig) +"," + maxy.toFixed(ndig) + "Z";
00863
00864 return res;
00865 }
00866
00867
00868
00869
00870 JSROOT.Painter.drawFunction = function(divid, tf1, opt) {
00871 this.bins = null;
00872
00873 this.Eval = function(x) {
00874 return this.GetObject().evalPar(x);
00875 }
00876
00877 this.CreateBins = function(ignore_zoom) {
00878 var main = this.main_painter(), gxmin = 0, gxmax = 0, tf1 = this.GetObject();
00879
00880 if ((main!==null) && !ignore_zoom) {
00881 if (main.zoom_xmin !== main.zoom_xmax) {
00882 gxmin = main.zoom_xmin;
00883 gxmax = main.zoom_xmax;
00884 } else {
00885 gxmin = main.xmin;
00886 gxmax = main.xmax;
00887 }
00888 }
00889
00890 if (tf1.fSave.length > 0) {
00891
00892
00893 var np = tf1.fSave.length - 2,
00894 xmin = tf1.fSave[np],
00895 xmax = tf1.fSave[np+1],
00896 dx = (xmax - xmin) / (np-1),
00897 res = [];
00898
00899 for (var n=0; n < np; ++n) {
00900 var xx = xmin + dx*n;
00901
00902 if ((gxmin !== gxmax) && ((xx + 2*dx < gxmin) || (xx - 2*dx > gxmax))) continue;
00903
00904 res.push({ x: xx, y: tf1.fSave[n] });
00905 }
00906 return res;
00907 }
00908
00909 var xmin = tf1.fXmin, xmax = tf1.fXmax, logx = false;
00910
00911 if (gxmin !== gxmax) {
00912 if (gxmin > xmin) xmin = gxmin;
00913 if (gxmax < xmax) xmax = gxmax;
00914 }
00915
00916 if ((main!==null) && main.options.Logx && (xmin>0) && (xmax>0)) {
00917 logx = true;
00918 xmin = Math.log(xmin);
00919 xmax = Math.log(xmax);
00920 }
00921
00922 var np = Math.max(tf1.fNpx, 101);
00923 var dx = (xmax - xmin) / (np - 1);
00924
00925 var res = [];
00926 for (var n=0; n < np; n++) {
00927 var xx = xmin + n*dx;
00928 if (logx) xx = Math.exp(xx);
00929 var yy = this.Eval(xx);
00930 if (!isNaN(yy)) res.push({ x : xx, y : yy });
00931 }
00932 return res;
00933 }
00934
00935 this.CreateDummyHisto = function() {
00936
00937 var xmin = 0, xmax = 1, ymin = 0, ymax = 1;
00938
00939 var bins = this.CreateBins(true);
00940
00941 if (bins!==null) {
00942
00943 xmin = xmax = bins[0].x;
00944 ymin = ymax = bins[0].y;
00945
00946 bins.forEach(function(bin) {
00947 xmin = Math.min(bin.x, xmin);
00948 xmax = Math.max(bin.x, xmax);
00949 ymin = Math.min(bin.y, ymin);
00950 ymax = Math.max(bin.y, ymax);
00951 });
00952
00953 if (ymax > 0.0) ymax *= 1.05;
00954 if (ymin < 0.0) ymin *= 1.05;
00955 }
00956
00957 var histo = JSROOT.Create("TH1I"),
00958 tf1 = this.GetObject();
00959
00960 histo.fName = tf1.fName + "_hist";
00961 histo.fTitle = tf1.fTitle;
00962
00963 histo.fXaxis.fXmin = xmin;
00964 histo.fXaxis.fXmax = xmax;
00965 histo.fYaxis.fXmin = ymin;
00966 histo.fYaxis.fXmax = ymax;
00967
00968 return histo;
00969 }
00970
00971 this.ProcessTooltipFunc = function(pnt) {
00972 var cleanup = false;
00973
00974 if ((pnt === null) || (this.bins===null)) {
00975 cleanup = true;
00976 } else
00977 if ((this.bins.length==0) || (pnt.x < this.bins[0].grx) || (pnt.x > this.bins[this.bins.length-1].grx)) {
00978 cleanup = true;
00979 }
00980
00981 if (cleanup) {
00982 if (this.draw_g !== null)
00983 this.draw_g.select(".tooltip_bin").remove();
00984 return null;
00985 }
00986
00987 var min = 100000, best = -1, bin;
00988
00989 for(var n=0; n<this.bins.length; ++n) {
00990 bin = this.bins[n];
00991 var dist = Math.abs(bin.grx - pnt.x);
00992 if (dist < min) { min = dist; best = n; }
00993 }
00994
00995 bin = this.bins[best];
00996
00997 var gbin = this.draw_g.select(".tooltip_bin");
00998 var radius = this.lineatt.width + 3;
00999
01000 if (gbin.empty())
01001 gbin = this.draw_g.append("svg:circle")
01002 .attr("class","tooltip_bin")
01003 .style("pointer-events","none")
01004 .attr("r", radius)
01005 .call(this.lineatt.func)
01006 .call(this.fillatt.func);
01007
01008 var res = { x: bin.grx,
01009 y: bin.gry,
01010 color1: this.lineatt.color,
01011 color2: this.fillatt.color,
01012 lines: [],
01013 exact : (Math.abs(bin.grx - pnt.x) < radius) && (Math.abs(bin.gry - pnt.y) < radius) };
01014
01015 res.changed = gbin.property("current_bin") !== best;
01016 res.menu = res.exact;
01017 res.menu_dist = Math.sqrt((bin.grx-pnt.x)*(bin.grx-pnt.x) + (bin.gry-pnt.y)*(bin.grx-pnt.x));
01018
01019 if (res.changed)
01020 gbin.attr("cx", bin.grx)
01021 .attr("cy", bin.gry)
01022 .property("current_bin", best);
01023
01024 var name = this.GetTipName();
01025 if (name.length > 0) res.lines.push(name);
01026
01027 var pmain = this.main_painter();
01028 if (pmain!==null)
01029 res.lines.push("x = " + pmain.AxisAsText("x",bin.x) + " y = " + pmain.AxisAsText("y",bin.y));
01030
01031 return res;
01032 }
01033
01034 this.Redraw = function() {
01035
01036 var w = this.frame_width(), h = this.frame_height(), tf1 = this.GetObject();
01037
01038 this.RecreateDrawG(false, "main_layer");
01039
01040
01041 this.bins = this.CreateBins(false);
01042
01043 var pthis = this;
01044 var pmain = this.main_painter();
01045 var name = this.GetTipName("\n");
01046
01047 if (!this.lineatt)
01048 this.lineatt = JSROOT.Painter.createAttLine(tf1);
01049 this.lineatt.used = false;
01050 if (!this.fillatt)
01051 this.fillatt = this.createAttFill(tf1, undefined, undefined, 1);
01052 this.fillatt.used = false;
01053
01054 var n, bin;
01055
01056 for(n=0; n<this.bins.length; ++n) {
01057 bin = this.bins[n];
01058
01059
01060 bin.grx = pmain.grx(bin.x);
01061 bin.gry = pmain.gry(bin.y);
01062 }
01063
01064 if (this.bins.length > 2) {
01065
01066 var h0 = h;
01067 if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) {
01068 h0 = Math.round(pmain.gry(0));
01069 if ((h0 > h) || (h0 < 0)) h0 = h;
01070 }
01071
01072 var path = JSROOT.Painter.BuildSvgPath("bezier", this.bins, h0, 2);
01073
01074 if (this.lineatt.color != "none")
01075 this.draw_g.append("svg:path")
01076 .attr("class", "line")
01077 .attr("d", path.path)
01078 .style("fill", "none")
01079 .call(this.lineatt.func);
01080
01081 if (this.fillatt.color != "none")
01082 this.draw_g.append("svg:path")
01083 .attr("class", "area")
01084 .attr("d", path.path + path.close)
01085 .style("stroke", "none")
01086 .call(this.fillatt.func);
01087 }
01088
01089 delete this.ProcessTooltip;
01090
01091 if (JSROOT.gStyle.Tooltip > 0)
01092 this.ProcessTooltip = this.ProcessTooltipFunc;
01093 }
01094
01095 this.CanZoomIn = function(axis,min,max) {
01096 if (axis!=="x") return false;
01097
01098 var tf1 = this.GetObject();
01099
01100 if (tf1.fSave.length > 0) {
01101
01102
01103 var nb_points = tf1.fNpx;
01104
01105 var xmin = tf1.fSave[nb_points + 1];
01106 var xmax = tf1.fSave[nb_points + 2];
01107
01108 return Math.abs(xmin - xmax) / nb_points < Math.abs(min - max);
01109 }
01110
01111
01112 return true;
01113 }
01114
01115 this.SetDivId(divid, -1);
01116 if (this.main_painter() === null) {
01117 var histo = this.CreateDummyHisto();
01118 JSROOT.Painter.drawHistogram1D(divid, histo, "AXIS");
01119 }
01120 this.SetDivId(divid);
01121 this.Redraw();
01122 return this.DrawingReady();
01123 }
01124
01125
01126
01127 JSROOT.Painter.drawHStack = function(divid, stack, opt) {
01128
01129
01130
01131
01132
01133
01134 this.nostack = false;
01135 this.firstpainter = null;
01136 this.painters = new Array;
01137
01138 this.SetDivId(divid);
01139
01140 if (!('fHists' in stack) || (stack.fHists.arr.length == 0)) return this.DrawingReady();
01141
01142 this['BuildStack'] = function() {
01143
01144
01145
01146 var stack = this.GetObject();
01147
01148 if (!('fHists' in stack)) return false;
01149 var nhists = stack.fHists.arr.length;
01150 if (nhists <= 0) return false;
01151 var lst = JSROOT.Create("TList");
01152 lst.Add(JSROOT.clone(stack.fHists.arr[0]));
01153 for (var i=1;i<nhists;++i) {
01154 var hnext = JSROOT.clone(stack.fHists.arr[i]);
01155 var hprev = lst.arr[i-1];
01156
01157 if ((hnext.fNbins != hprev.fNbins) ||
01158 (hnext.fXaxis.fXmin != hprev.fXaxis.fXmin) ||
01159 (hnext.fXaxis.fXmax != hprev.fXaxis.fXmax)) {
01160 JSROOT.console("When drawing THStack, cannot sum-up histograms " + hnext.fName + " and " + hprev.fName);
01161 delete hnext;
01162 delete lst;
01163 return false;
01164 }
01165
01166
01167 for (var n = 0; n < hnext.fArray.length; ++n)
01168 hnext.fArray[n] += hprev.fArray[n];
01169
01170 lst.Add(hnext);
01171 }
01172 stack.fStack = lst;
01173 return true;
01174 }
01175
01176 this['GetHistMinMax'] = function(hist, witherr) {
01177 var res = { min : 0, max : 0 };
01178 var domin = false, domax = false;
01179 if (hist.fMinimum != -1111)
01180 res.min = hist.fMinimum;
01181 else
01182 domin = true;
01183 if (hist.fMaximum != -1111)
01184 res.max = hist.fMaximum;
01185 else
01186 domax = true;
01187
01188 if (domin || domax) {
01189 var left = 1, right = hist.fXaxis.fNbins;
01190
01191 if (hist.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) {
01192 left = hist.fXaxis.fFirst;
01193 right = hist.fXaxis.fLast;
01194 }
01195 for (var bin = left; bin<=right; ++bin) {
01196 var val = hist.getBinContent(bin);
01197 var err = witherr ? hist.getBinError(bin) : 0;
01198 if (domin && ((bin==left) || (val-err < res.min))) res.min = val-err;
01199 if (domax && ((bin==left) || (val+err > res.max))) res.max = val+err;
01200 }
01201 }
01202
01203 return res;
01204 }
01205
01206 this['GetMinMax'] = function(opt) {
01207 var res = { min : 0, max : 0 },
01208 iserr = (opt.indexOf('e')>=0),
01209 stack = this.GetObject();
01210
01211 if (this.nostack) {
01212 for (var i = 0; i < stack.fHists.arr.length; ++i) {
01213 var resh = this.GetHistMinMax(stack.fHists.arr[i], iserr);
01214 if (i==0) res = resh; else {
01215 if (resh.min < res.min) res.min = resh.min;
01216 if (resh.max > res.max) res.max = resh.max;
01217 }
01218 }
01219
01220 if (stack.fMaximum != -1111)
01221 res.max = stack.fMaximum;
01222 else
01223 res.max *= 1.05;
01224
01225 if (stack.fMinimum != -1111) res.min = stack.fMinimum;
01226 } else {
01227 res.min = this.GetHistMinMax(stack.fStack.arr[0], iserr).min;
01228 res.max = this.GetHistMinMax(stack.fStack.arr[stack.fStack.arr.length-1], iserr).max * 1.05;
01229 }
01230
01231 var pad = this.root_pad();
01232 if ((pad!=null) && (pad.fLogy > 0)) {
01233 if (res.min<0) res.min = res.max * 1e-4;
01234 }
01235
01236 return res;
01237 }
01238
01239 this['DrawNextHisto'] = function(indx, opt) {
01240 var hist = null,
01241 stack = this.GetObject(),
01242 nhists = stack.fHists.arr.length;
01243
01244 if (indx>=nhists) return this.DrawingReady();
01245
01246 if (indx<0) hist = stack.fHistogram; else
01247 if (this.nostack) hist = stack.fHists.arr[indx];
01248 else hist = stack.fStack.arr[nhists - indx - 1];
01249
01250 var hopt = hist.fOption;
01251 if ((opt != "") && (hopt.indexOf(opt) == -1)) hopt += opt;
01252 if (indx>=0) hopt += "same";
01253 var subp = JSROOT.draw(this.divid, hist, hopt);
01254 if (indx<0) this.firstpainter = subp;
01255 else this.painters.push(subp);
01256 subp.WhenReady(this.DrawNextHisto.bind(this, indx+1, opt));
01257 }
01258
01259 this['drawStack'] = function(opt) {
01260 var pad = this.root_pad(),
01261 stack = this.GetObject(),
01262 histos = stack.fHists,
01263 nhists = histos.arr.length;
01264
01265 if (opt == null) opt = "";
01266 else opt = opt.toLowerCase();
01267
01268 var lsame = false;
01269 if (opt.indexOf("same") != -1) {
01270 lsame = true;
01271 opt.replace("same", "");
01272 }
01273 this.nostack = opt.indexOf("nostack") < 0 ? false : true;
01274
01275
01276 if (!this.nostack)
01277 this.nostack = ! this.BuildStack();
01278
01279 var mm = this.GetMinMax(opt);
01280
01281 if (stack.fHistogram === null) {
01282
01283 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
01284 for (var i = 0; i < nhists; ++i) {
01285 var h = histos.arr[i];
01286 if (i == 0 || h.fXaxis.fXmin < xmin)
01287 xmin = h.fXaxis.fXmin;
01288 if (i == 0 || h.fXaxis.fXmax > xmax)
01289 xmax = h.fXaxis.fXmax;
01290 if (i == 0 || h.fYaxis.fXmin < ymin)
01291 ymin = h.fYaxis.fXmin;
01292 if (i == 0 || h.fYaxis.fXmax > ymax)
01293 ymax = h.fYaxis.fXmax;
01294 }
01295
01296 var h = stack.fHists.arr[0];
01297 stack.fHistogram = JSROOT.Create("TH1I");
01298 stack.fHistogram.fName = "unnamed";
01299 stack.fHistogram.fXaxis = JSROOT.clone(h.fXaxis);
01300 stack.fHistogram.fYaxis = JSROOT.clone(h.fYaxis);
01301 stack.fHistogram.fXaxis.fXmin = xmin;
01302 stack.fHistogram.fXaxis.fXmax = xmax;
01303 stack.fHistogram.fYaxis.fXmin = ymin;
01304 stack.fHistogram.fYaxis.fXmax = ymax;
01305 }
01306 stack.fHistogram.fTitle = stack.fTitle;
01307 var histo = stack.fHistogram;
01308 if (!histo.TestBit(JSROOT.TH1StatusBits.kIsZoomed)) {
01309 if (pad && pad.fLogy)
01310 histo.fMaximum = mm.max * (1 + 0.2 * JSROOT.log10(mm.max / mm.min));
01311 else
01312 histo.fMaximum = mm.max;
01313 if (pad && pad.fLogy)
01314 histo.fMinimum = mm.min / (1 + 0.5 * JSROOT.log10(mm.max / mm.min));
01315 else
01316 histo.fMinimum = mm.min;
01317 }
01318
01319 this.DrawNextHisto(!lsame ? -1 : 0, opt);
01320 return this;
01321 }
01322
01323 this['UpdateObject'] = function(obj) {
01324 if (!this.MatchObjectType(obj)) return false;
01325
01326 var isany = false;
01327 if (this.firstpainter)
01328 if (this.firstpainter.UpdateObject(obj.fHistogram)) isany = true;
01329
01330 var nhists = obj.fHists.arr.length;
01331 for (var i = 0; i < nhists; ++i) {
01332 var hist = this.nostack ? obj.fHists.arr[i] : obj.fStack.arr[nhists - i - 1];
01333 if (this.painters[i].UpdateObject(hist)) isany = true;
01334 }
01335
01336 return isany;
01337 }
01338
01339 return this.drawStack(opt);
01340 }
01341
01342
01343
01344 JSROOT.TGraphPainter = function(graph) {
01345 JSROOT.TObjectPainter.call(this, graph);
01346 this.ownhisto = false;
01347 this.bins = null;
01348 this.xmin = this.ymin = this.xmax = this.ymax = 0;
01349 }
01350
01351 JSROOT.TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
01352
01353 JSROOT.TGraphPainter.prototype.Redraw = function() {
01354 this.DrawBins();
01355 }
01356
01357 JSROOT.TGraphPainter.prototype.DecodeOptions = function(opt) {
01358 this.draw_all = true;
01359 JSROOT.extend(this, { optionLine:0, optionAxis:0, optionCurve:0, optionRect:0,
01360 optionMark:0, optionBar:0, optionR:0, optionE:0, optionEF:0,
01361 optionFill:0, optionZ:0, optionBrackets:0,
01362 opt:"LP", out_of_range: false, has_errors: false, draw_errors: false, is_bent:false });
01363
01364 var graph = this.GetObject();
01365
01366 this.is_bent = graph._typename == 'TGraphBentErrors';
01367 this.has_errors = (graph._typename == 'TGraphErrors' ||
01368 graph._typename == 'TGraphAsymmErrors' ||
01369 this.is_bent || graph._typename.match(/^RooHist/));
01370 this.draw_errors = this.has_errors;
01371
01372 if ((opt != null) && (opt != "")) {
01373 this.opt = opt.toUpperCase();
01374 this.opt.replace('SAME', '');
01375 }
01376 if (this.opt.indexOf('L') != -1)
01377 this.optionLine = 1;
01378 if (this.opt.indexOf('F') != -1)
01379 this.optionFill = 1;
01380 if (this.opt.indexOf('A') != -1)
01381 this.optionAxis = 1;
01382 if (this.opt.indexOf('C') != -1) {
01383 this.optionCurve = 1;
01384 if (this.optionFill==0) this.optionLine = 1;
01385 }
01386 if (this.opt.indexOf('*') != -1)
01387 this.optionMark = 2;
01388 if (this.opt.indexOf('P') != -1)
01389 this.optionMark = 1;
01390 if (this.opt.indexOf('B') != -1) {
01391 this.optionBar = 1;
01392 this.draw_errors = false;
01393 }
01394 if (this.opt.indexOf('R') != -1)
01395 this.optionR = 1;
01396
01397 if (this.opt.indexOf('[]') != -1) {
01398 this.optionBrackets = 1;
01399 this.draw_errors = false;
01400 }
01401
01402 if (this.opt.indexOf('0') != -1) {
01403 this.optionMark = 1;
01404 this.draw_errors = true;
01405 this.out_of_range = true;
01406 }
01407
01408 if (this.opt.indexOf('1') != -1) {
01409 if (this.optionBar == 1) this.optionBar = 2;
01410 }
01411 if (this.opt.indexOf('2') != -1)
01412 this.optionRect = 1;
01413
01414 if (this.opt.indexOf('3') != -1) {
01415 this.optionEF = 1;
01416 this.optionLine = 0;
01417 this.draw_errors = false;
01418 }
01419 if (this.opt.indexOf('4') != -1) {
01420 this.optionEF = 2;
01421 this.optionLine = 0;
01422 this.draw_errors = false;
01423 }
01424
01425 if (this.opt.indexOf('2') != -1 || this.opt.indexOf('5') != -1) this.optionE = 1;
01426
01427
01428 if ((this.optionMark==1) && (graph.fMarkerStyle==1)) this.optionMark = 3;
01429
01430
01431 if (this.optionLine + this.optionFill + this.optionMark + this.optionBar + this.optionE +
01432 this.optionEF + this.optionRect + this.optionBrackets == 0) {
01433 if (this.opt.length == 0)
01434 this.optionLine = 1;
01435 }
01436
01437 if (graph._typename == 'TGraphErrors') {
01438 var maxEX = d3.max(graph.fEX);
01439 var maxEY = d3.max(graph.fEY);
01440 if (maxEX < 1.0e-300 && maxEY < 1.0e-300)
01441 this.draw_errors = false;
01442 }
01443 }
01444
01445 JSROOT.TGraphPainter.prototype.CreateBins = function() {
01446 var gr = this.GetObject();
01447 if (gr===null) return;
01448
01449 var p, kind = 0, npoints = gr.fNpoints;
01450 if ((gr._typename==="TCutG") && (npoints>3)) npoints--;
01451
01452 if (gr._typename == 'TGraphErrors') kind = 1; else
01453 if (gr._typename == 'TGraphAsymmErrors' || gr._typename == 'TGraphBentErrors'
01454 || gr._typename.match(/^RooHist/)) kind = 2;
01455
01456 this.bins = [];
01457
01458 for (p=0;p<npoints;++p) {
01459 var bin = { x: gr.fX[p], y: gr.fY[p] };
01460 if (kind === 1) {
01461 bin.exlow = bin.exhigh = gr.fEX[p];
01462 bin.eylow = bin.eyhigh = gr.fEY[p];
01463 } else
01464 if (kind === 2) {
01465 bin.exlow = gr.fEXlow[p];
01466 bin.exhigh = gr.fEXhigh[p];
01467 bin.eylow = gr.fEYlow[p];
01468 bin.eyhigh = gr.fEYhigh[p];
01469 }
01470 this.bins.push(bin);
01471
01472 if (p===0) {
01473 this.xmin = this.xmax = bin.x;
01474 this.ymin = this.ymax = bin.y;
01475 }
01476
01477 if (kind > 0) {
01478 this.xmin = Math.min(this.xmin, bin.x - bin.exlow, bin.x + bin.exhigh);
01479 this.xmax = Math.max(this.xmax, bin.x - bin.exlow, bin.x + bin.exhigh);
01480 this.ymin = Math.min(this.ymin, bin.y - bin.eylow, bin.y + bin.eyhigh);
01481 this.ymax = Math.max(this.ymax, bin.y - bin.eylow, bin.y + bin.eyhigh);
01482 } else {
01483 this.xmin = Math.min(this.xmin, bin.x);
01484 this.xmax = Math.max(this.xmax, bin.x);
01485 this.ymin = Math.min(this.ymin, bin.y);
01486 this.ymax = Math.max(this.ymax, bin.y);
01487 }
01488
01489 }
01490 }
01491
01492 JSROOT.TGraphPainter.prototype.CreateHistogram = function() {
01493
01494
01495 var xmin = this.xmin, xmax = this.xmax, ymin = this.ymin, ymax = this.ymax;
01496
01497 if (xmin >= xmax) xmax = xmin+1;
01498 if (ymin >= ymax) ymax = ymin+1;
01499 var dx = (xmax-xmin)*0.1, dy = (ymax-ymin)*0.1,
01500 uxmin = xmin - dx, uxmax = xmax + dx,
01501 minimum = ymin - dy, maximum = ymax + dy;
01502
01503 if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.9;
01504 if ((uxmax>0) && (xmax<=0)) uxmax = 0;
01505
01506 var graph = this.GetObject();
01507
01508 if (graph.fMinimum != -1111) minimum = ymin = graph.fMinimum;
01509 if (graph.fMaximum != -1111) maximum = ymax = graph.fMaximum;
01510 if ((minimum < 0) && (ymin >=0)) minimum = 0.9*ymin;
01511
01512 var histo = JSROOT.CreateTH1(100);
01513 histo.fName = graph.fName + "_h";
01514 histo.fTitle = graph.fTitle;
01515 histo.fXaxis.fXmin = uxmin;
01516 histo.fXaxis.fXmax = uxmax;
01517 histo.fYaxis.fXmin = minimum;
01518 histo.fYaxis.fXmax = maximum;
01519 histo.fMinimum = minimum;
01520 histo.fMaximum = maximum;
01521 histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats;
01522 return histo;
01523 }
01524
01525 JSROOT.TGraphPainter.prototype.OptimizeBins = function(filter_func) {
01526 if ((this.bins.length < 30) && !filter_func) return this.bins;
01527
01528 var selbins = null;
01529 if (typeof filter_func == 'function') {
01530 for (var n = 0; n < this.bins.length; ++n) {
01531 if (filter_func(this.bins[n],n)) {
01532 if (selbins==null)
01533 selbins = (n==0) ? [] : this.bins.slice(0, n);
01534 } else {
01535 if (selbins != null) selbins.push(this.bins[n]);
01536 }
01537 }
01538 }
01539 if (selbins == null) selbins = this.bins;
01540
01541 if ((selbins.length < 5000) || (JSROOT.gStyle.OptimizeDraw == 0)) return selbins;
01542 var step = Math.floor(selbins.length / 5000);
01543 if (step < 2) step = 2;
01544 var optbins = [];
01545 for (var n = 0; n < selbins.length; n+=step)
01546 optbins.push(selbins[n]);
01547
01548 return optbins;
01549 }
01550
01551 JSROOT.TGraphPainter.prototype.TooltipText = function(d, asarray) {
01552 var pmain = this.main_painter(), lines = [];
01553
01554 lines.push(this.GetTipName());
01555 lines.push("x = " + pmain.AxisAsText("x", d.x));
01556 lines.push("y = " + pmain.AxisAsText("y", d.y));
01557
01558 if (this.draw_errors && (pmain.x_kind=='normal') && ('exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0)))
01559 lines.push("error x = -" + pmain.AxisAsText("x", d.exlow) +
01560 "/+" + pmain.AxisAsText("x", d.exhigh));
01561
01562 if ((this.draw_errors || (this.optionEF > 0)) && (pmain.y_kind=='normal') && ('eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0)) )
01563 lines.push("error y = -" + pmain.AxisAsText("y", d.eylow) +
01564 "/+" + pmain.AxisAsText("y", d.eyhigh));
01565
01566 if (asarray) return lines;
01567
01568 var res = "";
01569 for (var n=0;n<lines.length;++n) res += ((n>0 ? "\n" : "") + lines[n]);
01570 return res;
01571 }
01572
01573 JSROOT.TGraphPainter.prototype.DrawBins = function() {
01574
01575 this.RecreateDrawG(false, "main_layer");
01576
01577 var pthis = this,
01578 pmain = this.main_painter(),
01579 w = this.frame_width(),
01580 h = this.frame_height(),
01581 graph = this.GetObject(),
01582 excl_width = 0;
01583
01584 if (!this.lineatt)
01585 this.lineatt = JSROOT.Painter.createAttLine(graph, undefined, true);
01586 if (!this.fillatt)
01587 this.fillatt = this.createAttFill(graph, undefined, undefined, 1);
01588 this.fillatt.used = false;
01589
01590 if (this.fillatt) this.fillatt.used = false;
01591 this.draw_kind = "none";
01592 this.marker_size = 0;
01593
01594 if (this.lineatt.excl_side!=0) {
01595 excl_width = this.lineatt.excl_side * this.lineatt.excl_width;
01596 if (this.lineatt.width>0) this.optionLine = 1;
01597 }
01598
01599 var drawbins = null;
01600
01601 if (this.optionEF > 0) {
01602
01603 drawbins = this.OptimizeBins();
01604
01605
01606 for (var n=0;n<drawbins.length;++n) {
01607 var bin = drawbins[n];
01608 bin.grx = pmain.grx(bin.x);
01609 bin.gry = pmain.gry(bin.y - bin.eylow);
01610 }
01611
01612 var path1 = JSROOT.Painter.BuildSvgPath(this.optionEF > 1 ? "bezier" : "line", drawbins),
01613 bins2 = [];
01614
01615 for (var n=drawbins.length-1;n>=0;--n) {
01616 var bin = drawbins[n];
01617 bin.gry = pmain.gry(bin.y + bin.eyhigh);
01618 bins2.push(bin);
01619 }
01620
01621
01622 var path2 = JSROOT.Painter.BuildSvgPath(this.optionEF > 1 ? "Lbezier" : "Lline", bins2);
01623
01624 this.draw_g.append("svg:path")
01625 .attr("d", path1.path + path2.path + "Z")
01626 .style("stroke", "none")
01627 .call(this.fillatt.func);
01628 this.draw_kind = "lines";
01629 }
01630
01631 if (this.optionLine == 1 || this.optionFill == 1 || (excl_width!==0)) {
01632
01633 var close_symbol = "";
01634 if (graph._typename=="TCutG") this.optionFill = 1;
01635
01636 if (this.optionFill == 1) {
01637 close_symbol = "Z";
01638 excl_width=0;
01639 }
01640
01641 if (drawbins===null) drawbins = this.OptimizeBins();
01642
01643 for (var n=0;n<drawbins.length;++n) {
01644 var bin = drawbins[n];
01645 bin.grx = pmain.grx(bin.x);
01646 bin.gry = pmain.gry(bin.y);
01647 }
01648
01649 var kind = "line";
01650 if (this.optionCurve === 1) kind = "bezier"; else
01651 if (excl_width!==0) kind+="calc";
01652
01653 var path = JSROOT.Painter.BuildSvgPath(kind, drawbins);
01654
01655 if (excl_width!==0) {
01656 var extrabins = [];
01657 for (var n=drawbins.length-1;n>=0;--n) {
01658 var bin = drawbins[n];
01659 var dlen = Math.sqrt(bin.dgrx*bin.dgrx + bin.dgry*bin.dgry);
01660
01661 bin.grx += excl_width*bin.dgry/dlen;
01662 bin.gry -= excl_width*bin.dgrx/dlen;
01663 extrabins.push(bin);
01664 }
01665
01666 var path2 = JSROOT.Painter.BuildSvgPath("L" + ((this.optionCurve === 1) ? "bezier" : "line"), extrabins);
01667
01668 this.draw_g.append("svg:path")
01669 .attr("d", path.path + path2.path + "Z")
01670 .style("stroke", "none")
01671 .call(this.fillatt.func)
01672 .style('opacity', 0.75);
01673 }
01674
01675 if (this.optionLine || this.optionFill) {
01676 var elem = this.draw_g.append("svg:path")
01677 .attr("d", path.path + close_symbol);
01678 if (this.optionLine)
01679 elem.call(this.lineatt.func);
01680 else
01681 elem.style('stroke','none');
01682
01683 if (this.optionFill > 0)
01684 elem.call(this.fillatt.func);
01685 else
01686 elem.style('fill','none');
01687 }
01688
01689 this.draw_kind = "lines";
01690 }
01691
01692 var nodes = null;
01693
01694 if (this.draw_errors || this.optionRect || this.optionBrackets || this.optionBar) {
01695
01696 drawbins = this.OptimizeBins(function(pnt,i) {
01697
01698 var grx = pmain.grx(pnt.x);
01699
01700
01701 if (!pthis.optionBar && ((grx<0) || (grx>w))) return true;
01702
01703 var gry = pmain.gry(pnt.y);
01704
01705 if (!pthis.optionBar && !pthis.out_of_range && ((gry<0) || (gry>h))) return true;
01706
01707 pnt.grx1 = Math.round(grx);
01708 pnt.gry1 = Math.round(gry);
01709
01710 if (pthis.has_errors) {
01711 pnt.grx0 = Math.round(pmain.grx(pnt.x - pnt.exlow) - grx);
01712 pnt.grx2 = Math.round(pmain.grx(pnt.x + pnt.exhigh) - grx);
01713 pnt.gry0 = Math.round(pmain.gry(pnt.y - pnt.eylow) - gry);
01714 pnt.gry2 = Math.round(pmain.gry(pnt.y + pnt.eyhigh) - gry);
01715
01716 if (pthis.is_bent) {
01717 pnt.grdx0 = Math.round(pmain.gry(pnt.y + graph.fEXlowd[i]) - gry);
01718 pnt.grdx2 = Math.round(pmain.gry(pnt.y + graph.fEXhighd[i]) - gry);
01719 pnt.grdy0 = Math.round(pmain.grx(pnt.x + graph.fEYlowd[i]) - grx);
01720 pnt.grdy2 = Math.round(pmain.grx(pnt.x + graph.fEYhighd[i]) - grx);
01721 } else {
01722 pnt.grdx0 = pnt.grdx2 = pnt.grdy0 = pnt.grdy2 = 0;
01723 }
01724 }
01725
01726 return false;
01727 });
01728
01729 this.draw_kind = "nodes";
01730
01731
01732 nodes = this.draw_g.selectAll(".grpoint")
01733 .data(drawbins)
01734 .enter()
01735 .append("svg:g")
01736 .attr("class", "grpoint")
01737 .attr("transform", function(d) { return "translate(" + d.grx1 + "," + d.gry1 + ")"; });
01738 }
01739
01740 if (this.optionBar) {
01741
01742 for (var i=1;i<drawbins.length-1;++i)
01743 drawbins[i].width = Math.max(2, (drawbins[i+1].grx1 - drawbins[i-1].grx1) / 2 - 2);
01744
01745
01746 switch (drawbins.length) {
01747 case 0: break;
01748 case 1: drawbins[0].width = w/4; break;
01749 case 2: drawbins[0].width = drawbins[1].width = (drawbins[1].grx1-drawbins[0].grx1)/2; break;
01750 default:
01751 drawbins[0].width = drawbins[1].width;
01752 drawbins[drawbins.length-1].width = drawbins[drawbins.length-2].width;
01753 }
01754
01755 var yy0 = Math.round(pmain.gry(0));
01756
01757 nodes.append("svg:rect")
01758 .attr("x", function(d) { return Math.round(-d.width/2); })
01759 .attr("y", function(d) {
01760 d.bar = true;
01761 if (pthis.optionBar!==1) return 0;
01762 return (d.gry1 > yy0) ? yy0-d.gry1 : 0;
01763 })
01764 .attr("width", function(d) { return Math.round(d.width); })
01765 .attr("height", function(d) {
01766 if (pthis.optionBar!==1) return h > d.gry1 ? h - d.gry1 : 0;
01767 return Math.abs(yy0 - d.gry1);
01768 })
01769 .call(this.fillatt.func);
01770 }
01771
01772 if (this.optionRect)
01773 nodes.filter(function(d) { return (d.exlow > 0) && (d.exhigh > 0) && (d.eylow > 0) && (d.eyhigh > 0); })
01774 .append("svg:rect")
01775 .attr("x", function(d) { d.rect = true; return d.grx0; })
01776 .attr("y", function(d) { return d.gry2; })
01777 .attr("width", function(d) { return d.grx2 - d.grx0; })
01778 .attr("height", function(d) { return d.gry0 - d.gry2; })
01779 .call(this.fillatt.func);
01780
01781 if (this.optionBrackets) {
01782 nodes.filter(function(d) { return (d.eylow > 0) || (d.eyhigh > 0); })
01783 .append("svg:path")
01784 .call(this.lineatt.func)
01785 .style('fill', "none")
01786 .attr("d", function(d) {
01787 d.bracket = true;
01788 return ((d.eylow > 0) ? "M-5,"+(d.gry0-3)+"v3h10v-3" : "") +
01789 ((d.eyhigh > 0) ? "M-5,"+(d.gry2+3)+"v-3h10v3" : "");
01790 });
01791 }
01792
01793 if (this.draw_errors) {
01794
01795 var lw = this.lineatt.width + JSROOT.gStyle.EndErrorSize,
01796 vv = "m0," + lw + "v-" + 2*lw,
01797 hh = "m" + lw + ",0h-" + 2*lw;
01798 lw = Math.floor((this.lineatt.width-1)/2);
01799 nodes.filter(function(d) { return (d.exlow > 0) || (d.exhigh > 0) || (d.eylow > 0) || (d.eyhigh > 0); })
01800 .append("svg:path")
01801 .call(this.lineatt.func)
01802 .style('fill', "none")
01803 .attr("d", function(d) {
01804 d.error = true;
01805 return ((d.exlow > 0) ? "M0,0L"+(d.grx0+lw)+","+d.grdx0+vv : "") +
01806 ((d.exhigh > 0) ? "M0,0L"+(d.grx2-lw)+","+d.grdx2+vv : "") +
01807 ((d.eylow > 0) ? "M0,0L"+d.grdy0+","+(d.gry0-lw)+hh : "") +
01808 ((d.eyhigh > 0) ? "M0,0L"+d.grdy2+","+(d.gry2+lw)+hh : "");
01809 });
01810 }
01811
01812 if (this.optionMark > 0) {
01813
01814 var step = Math.max(1, Math.round(this.bins.length / 50000)),
01815 path = "", n, pnt, grx, gry, marker_kind;
01816
01817 if (this.optionMark==2) marker_kind = 3; else
01818 if (this.optionMark==3) marker_kind = 1;
01819
01820 if (!this.markeratt)
01821 this.markeratt = JSROOT.Painter.createAttMarker(graph,marker_kind);
01822 else
01823 this.markeratt.Change(undefined, marker_kind);
01824
01825 this.marker_size = this.markeratt.size;
01826
01827 this.markeratt.reset_pos();
01828
01829 for (n=0;n<this.bins.length;n+=step) {
01830 pnt = this.bins[n];
01831 grx = pmain.grx(pnt.x);
01832 if ((grx > -this.marker_size) && (grx < w+this.marker_size)) {
01833 gry = pmain.gry(pnt.y);
01834 if ((gry >-this.marker_size) && (gry < h+this.marker_size)) {
01835 path += this.markeratt.create(grx, gry);
01836 }
01837 }
01838 }
01839
01840 if (path.length>0) {
01841 this.draw_g.append("svg:path")
01842 .attr("d", path)
01843 .call(this.markeratt.func);
01844 if ((nodes===null) && (this.draw_kind=="none"))
01845 this.draw_kind = (this.optionMark==3) ? "path" : "mark";
01846 }
01847 }
01848 }
01849
01850 JSROOT.TGraphPainter.prototype.ProcessTooltip = function(pnt) {
01851 if (pnt === null) {
01852 if (this.draw_g !== null)
01853 this.draw_g.select(".tooltip_bin").remove();
01854 return null;
01855 }
01856
01857 if ((this.draw_kind=="lines") || (this.draw_kind=="path") || (this.draw_kind=="mark"))
01858 return this.ProcessTooltipForPath(pnt);
01859
01860 if (this.draw_kind!="nodes") return null;
01861
01862 var width = this.frame_width(),
01863 height = this.frame_height(),
01864 pmain = this.main_painter(),
01865 painter = this,
01866 findbin = null, best_dist2 = 1e10, best = null;
01867
01868 this.draw_g.selectAll('.grpoint').each(function() {
01869 var d = d3.select(this).datum();
01870 if (d===undefined) return;
01871 var dist2 = Math.pow(pnt.x - d.grx1, 2);
01872 if (pnt.nproc===1) dist2 += Math.pow(pnt.y - d.gry1, 2);
01873 if (dist2 >= best_dist2) return;
01874
01875 var rect = null;
01876
01877 if (d.error || d.rect || d.marker || d.bracket) {
01878 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) };
01879 if (d.bracket) { rect.x1 = -5; rect.x2 = 5; }
01880 } else
01881 if (d.bar) {
01882 rect = { x1: -d.width/2, x2: d.width/2, y1: 0, y2: height - d.gry1 };
01883
01884 if (painter.optionBar===1) {
01885 var yy0 = pmain.gry(0);
01886 rect.y1 = (d.gry1 > yy0) ? yy0-d.gry1 : 0;
01887 rect.y2 = (d.gry1 > yy0) ? 0 : yy0-d.gry1;
01888 }
01889 } else {
01890 rect = { x1: -5, x2: 5, y1: -5, y2: 5 };
01891 }
01892 var matchx = (pnt.x >= d.grx1 + rect.x1) && (pnt.x <= d.grx1 + rect.x2);
01893 var matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2);
01894
01895 if (matchx && (matchy || (pnt.nproc > 1))) {
01896 best_dist2 = dist2;
01897 findbin = this;
01898 best = rect;
01899 best.exact = matchx && matchy;
01900 }
01901 });
01902
01903 var ttrect = this.draw_g.select(".tooltip_bin");
01904
01905 if (findbin == null) {
01906 ttrect.remove();
01907 return null;
01908 }
01909
01910 var d = d3.select(findbin).datum();
01911
01912 var res = { x: d.grx1, y: d.gry1,
01913 color1: this.lineatt.color,
01914 lines: this.TooltipText(d, true) };
01915 if (this.fillatt && this.fillatt.used) res.color2 = this.fillatt.color;
01916
01917 if (best.exact) res.exact = true;
01918 res.menu = res.exact;
01919 res.menu_dist = 3;
01920
01921 if (ttrect.empty())
01922 ttrect = this.draw_g.append("svg:rect")
01923 .attr("class","tooltip_bin h1bin")
01924 .style("pointer-events","none");
01925
01926 res.changed = ttrect.property("current_bin") !== findbin;
01927
01928 if (res.changed)
01929 ttrect.attr("x", d.grx1 + best.x1)
01930 .attr("width", best.x2 - best.x1)
01931 .attr("y", d.gry1 + best.y1)
01932 .attr("height", best.y2 - best.y1)
01933 .style("opacity", "0.3")
01934 .property("current_bin", findbin);
01935
01936 return res;
01937 }
01938
01939 JSROOT.TGraphPainter.prototype.ProcessTooltipForPath = function(pnt) {
01940
01941 if (this.bins === null) return null;
01942
01943 var islines = (this.draw_kind=="lines"),
01944 ismark = (this.draw_kind=="mark"),
01945 bestbin = null,
01946 bestdist = 1e10,
01947 pmain = this.main_painter(),
01948 dist, grx, gry, n, bin;
01949
01950 for (n=0;n<this.bins.length;++n) {
01951 bin = this.bins[n];
01952
01953 grx = pmain.grx(bin.x);
01954 dist = pnt.x-grx;
01955
01956 if (islines) {
01957 if ((n==0) && (dist < -10)) { bestbin = null; break; }
01958 } else {
01959 gry = pmain.gry(bin.y);
01960 dist = dist*dist + (pnt.y-gry)*(pnt.y-gry);
01961 }
01962
01963 if (Math.abs(dist) < bestdist) {
01964 bestdist = dist;
01965 bestbin = bin;
01966 }
01967 }
01968
01969
01970 if ((dist > 10) && islines) bestbin = null;
01971
01972 var radius = Math.max(this.lineatt.width + 3, 4);
01973
01974 if (this.marker_size > 0) radius = Math.max(Math.round(this.marker_size*7), radius);
01975
01976 if (bestbin !== null)
01977 bestdist = Math.sqrt(Math.pow(pnt.x-pmain.grx(bestbin.x),2) + Math.pow(pnt.y-pmain.gry(bestbin.y),2));
01978
01979
01980
01981 if (!islines && !ismark && (bestdist>radius)) bestbin = null;
01982
01983 if (ismark && (bestbin!==null)) {
01984 if ((pnt.nproc == 1) && (bestdist>radius)) bestbin = null; else
01985 if ((this.bins.length==1) && (bestdist>3*radius)) bestbin = null;
01986 }
01987
01988 var ttbin = this.draw_g.select(".tooltip_bin");
01989
01990 if (bestbin===null) {
01991 ttbin.remove();
01992 return null;
01993 }
01994
01995 var res = { x: pmain.grx(bestbin.x), y: pmain.gry(bestbin.y),
01996 color1: this.lineatt.color,
01997 lines: this.TooltipText(bestbin, true) };
01998
01999 if (this.fillatt && this.fillatt.used) res.color2 = this.fillatt.color;
02000
02001 if (!islines) {
02002 res.color1 = JSROOT.Painter.root_colors[this.GetObject().fMarkerColor];
02003 if (!res.color2) res.color2 = res.color1;
02004 }
02005
02006 if (ttbin.empty())
02007 ttbin = this.draw_g.append("svg:g")
02008 .attr("class","tooltip_bin");
02009
02010 var gry1, gry2;
02011
02012 if ((this.optionEF > 0) && islines) {
02013 gry1 = pmain.gry(bestbin.y - bestbin.eylow);
02014 gry2 = pmain.gry(bestbin.y + bestbin.eyhigh);
02015 } else {
02016 gry1 = gry2 = pmain.gry(bestbin.y);
02017 }
02018
02019 res.exact = (Math.abs(pnt.x - res.x) <= radius) &&
02020 ((Math.abs(pnt.y - gry1) <= radius) || (Math.abs(pnt.y - gry2) <= radius));
02021
02022 res.menu = res.exact;
02023 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));
02024
02025 res.changed = ttbin.property("current_bin") !== bestbin;
02026
02027 if (res.changed) {
02028 ttbin.selectAll("*").remove();
02029 ttbin.property("current_bin", bestbin);
02030
02031 if (ismark) {
02032 ttbin.append("svg:rect")
02033 .attr("class","h1bin")
02034 .style("pointer-events","none")
02035 .style("opacity", "0.3")
02036 .attr("x", (res.x - radius).toFixed(1))
02037 .attr("y", (res.y - radius).toFixed(1))
02038 .attr("width", (2*radius).toFixed(1))
02039 .attr("height", (2*radius).toFixed(1));
02040 } else {
02041 ttbin.append("svg:circle").attr("cy", gry1.toFixed(1))
02042 if (Math.abs(gry1-gry2) > 1)
02043 ttbin.append("svg:circle").attr("cy", gry2.toFixed(1));
02044
02045 var elem = ttbin.selectAll("circle")
02046 .attr("r", radius)
02047 .attr("cx", res.x.toFixed(1));
02048
02049 if (!islines) {
02050 elem.style('stroke', res.color1 == 'black' ? 'green' : 'black').style('fill','none');
02051 } else {
02052 if (this.optionLine)
02053 elem.call(this.lineatt.func);
02054 else
02055 elem.style('stroke','black');
02056 if (this.optionFill > 0)
02057 elem.call(this.fillatt.func);
02058 else
02059 elem.style('fill','none');
02060 }
02061 }
02062 }
02063
02064 return res;
02065 }
02066
02067 JSROOT.TGraphPainter.prototype.UpdateObject = function(obj) {
02068 if (!this.MatchObjectType(obj)) return false;
02069
02070
02071 if (this.ownhisto)
02072 this.main_painter().UpdateObject(obj.fHistogram);
02073
02074 var graph = this.GetObject();
02075
02076 graph.fX = obj.fX;
02077 graph.fY = obj.fY;
02078 graph.fNpoints = obj.fNpoints;
02079 this.CreateBins();
02080 return true;
02081 }
02082
02083 JSROOT.TGraphPainter.prototype.CanZoomIn = function(axis,min,max) {
02084
02085
02086 var gr = this.GetObject();
02087 if ((gr===null) || (axis!=="x")) return false;
02088
02089 for (var n=0; n < gr.fNpoints; ++n)
02090 if ((min < gr.fX[n]) && (gr.fX[n] < max)) return true;
02091
02092 return false;
02093 }
02094
02095 JSROOT.TGraphPainter.prototype.ButtonClick = function(funcname) {
02096
02097 if (funcname !== "ToggleZoom") return false;
02098
02099 var main = this.main_painter();
02100 if (main === null) return false;
02101
02102 if ((this.xmin===this.xmax) && (this.ymin = this.ymax)) return false;
02103
02104 main.Zoom(this.xmin, this.xmax, this.ymin, this.ymax);
02105
02106 return true;
02107 }
02108
02109
02110 JSROOT.TGraphPainter.prototype.DrawNextFunction = function(indx, callback) {
02111
02112
02113 var graph = this.GetObject();
02114
02115 if ((graph.fFunctions === null) || (indx >= graph.fFunctions.arr.length))
02116 return JSROOT.CallBack(callback);
02117
02118 var func = graph.fFunctions.arr[indx];
02119 var opt = graph.fFunctions.opt[indx];
02120
02121 var painter = JSROOT.draw(this.divid, func, opt);
02122 if (painter) return painter.WhenReady(this.DrawNextFunction.bind(this, indx+1, callback));
02123
02124 this.DrawNextFunction(indx+1, callback);
02125 }
02126
02127 JSROOT.Painter.drawGraph = function(divid, graph, opt) {
02128 JSROOT.extend(this, new JSROOT.TGraphPainter(graph));
02129
02130 this.CreateBins();
02131
02132 this.SetDivId(divid, -1);
02133
02134 if (this.main_painter() == null) {
02135 if (graph.fHistogram == null)
02136 graph.fHistogram = this.CreateHistogram();
02137 JSROOT.Painter.drawHistogram1D(divid, graph.fHistogram, "AXIS");
02138 this.ownhisto = true;
02139 }
02140
02141 this.SetDivId(divid);
02142 this.DecodeOptions(opt);
02143 this.DrawBins();
02144
02145 this.DrawNextFunction(0, this.DrawingReady.bind(this));
02146
02147 return this;
02148 }
02149
02150
02151
02152 JSROOT.Painter.drawMultiGraph = function(divid, mgraph, opt) {
02153
02154
02155 this.firstpainter = null;
02156 this.autorange = false;
02157 this.painters = [];
02158
02159 this.SetDivId(divid, -1);
02160
02161 this.UpdateObject = function(obj) {
02162 if (!this.MatchObjectType(obj)) return false;
02163
02164 var mgraph = this.GetObject(),
02165 graphs = obj.fGraphs;
02166
02167 mgraph.fTitle = obj.fTitle;
02168
02169 var isany = false;
02170 if (this.firstpainter) {
02171 var histo = obj.fHistogram;
02172 if (this.autorange && (histo == null))
02173 histo = this.ScanGraphsRange(graphs);
02174 if (this.firstpainter.UpdateObject(histo)) isany = true;
02175 }
02176
02177 for (var i = 0; i < graphs.arr.length; ++i) {
02178 if (i<this.painters.length)
02179 if (this.painters[i].UpdateObject(graphs.arr[i])) isany = true;
02180 }
02181
02182 return isany;
02183 }
02184
02185 this.ComputeGraphRange = function(res, gr) {
02186
02187 if (gr.fNpoints == 0) return;
02188 if (res.first) {
02189 res.xmin = res.xmax = gr.fX[0];
02190 res.ymin = res.ymax = gr.fY[0];
02191 res.first = false;
02192 }
02193 for (var i=0; i < gr.fNpoints; ++i) {
02194 res.xmin = Math.min(res.xmin, gr.fX[i]);
02195 res.xmax = Math.max(res.xmax, gr.fX[i]);
02196 res.ymin = Math.min(res.ymin, gr.fY[i]);
02197 res.ymax = Math.max(res.ymax, gr.fY[i]);
02198 }
02199 return res;
02200 }
02201
02202 this['padtoX'] = function(pad, x) {
02203
02204 if (pad.fLogx && (x < 50))
02205 return Math.exp(2.302585092994 * x);
02206 return x;
02207 }
02208
02209 this.ScanGraphsRange = function(graphs, histo, pad) {
02210 var mgraph = this.GetObject(),
02211 maximum, minimum, dx, dy, uxmin = 0, uxmax = 0, logx = false, logy = false,
02212 rw = { xmin: 0, xmax: 0, ymin: 0, ymax: 0, first: true };
02213
02214 if (pad!=null) {
02215 logx = pad.fLogx;
02216 logy = pad.fLogy;
02217 rw.xmin = pad.fUxmin;
02218 rw.xmax = pad.fUxmax;
02219 rw.ymin = pad.fUymin;
02220 rw.ymax = pad.fUymax;
02221 rw.first = false;
02222 }
02223 if (histo!=null) {
02224 minimum = histo.fYaxis.fXmin;
02225 maximum = histo.fYaxis.fXmax;
02226 if (pad!=null) {
02227 uxmin = this.padtoX(pad, rw.xmin);
02228 uxmax = this.padtoX(pad, rw.xmax);
02229 }
02230 } else {
02231 this.autorange = true;
02232
02233 for (var i = 0; i < graphs.arr.length; ++i)
02234 this.ComputeGraphRange(rw, graphs.arr[i]);
02235
02236 if (rw.xmin == rw.xmax) rw.xmax += 1.;
02237 if (rw.ymin == rw.ymax) rw.ymax += 1.;
02238 dx = 0.05 * (rw.xmax - rw.xmin);
02239 dy = 0.05 * (rw.ymax - rw.ymin);
02240 uxmin = rw.xmin - dx;
02241 uxmax = rw.xmax + dx;
02242 if (logy) {
02243 if (rw.ymin <= 0) rw.ymin = 0.001 * rw.ymax;
02244 minimum = rw.ymin / (1 + 0.5 * JSROOT.log10(rw.ymax / rw.ymin));
02245 maximum = rw.ymax * (1 + 0.2 * JSROOT.log10(rw.ymax / rw.ymin));
02246 } else {
02247 minimum = rw.ymin - dy;
02248 maximum = rw.ymax + dy;
02249 }
02250 if (minimum < 0 && rw.ymin >= 0)
02251 minimum = 0;
02252 if (maximum > 0 && rw.ymax <= 0)
02253 maximum = 0;
02254 }
02255
02256 if (uxmin < 0 && rw.xmin >= 0) {
02257 if (logx) uxmin = 0.9 * rw.xmin;
02258 else uxmin = 0;
02259 }
02260 if (uxmax > 0 && rw.xmax <= 0) {
02261 if (logx) uxmax = 1.1 * rw.xmax;
02262 else uxmax = 0;
02263 }
02264
02265 if (mgraph.fMinimum != -1111)
02266 rw.ymin = minimum = mgraph.fMinimum;
02267 if (mgraph.fMaximum != -1111)
02268 rw.ymax = maximum = mgraph.fMaximum;
02269
02270 if (minimum < 0 && rw.ymin >= 0) {
02271 if (logy) minimum = 0.9 * rw.ymin;
02272 }
02273 if (maximum > 0 && rw.ymax <= 0) {
02274 if (logy) maximum = 1.1 * rw.ymax;
02275 }
02276 if (minimum <= 0 && logy)
02277 minimum = 0.001 * maximum;
02278 if (uxmin <= 0 && logx) {
02279 if (uxmax > 1000)
02280 uxmin = 1;
02281 else
02282 uxmin = 0.001 * uxmax;
02283 }
02284
02285
02286 if (!histo) {
02287 histo = JSROOT.Create("TH1I");
02288 histo.fTitle = mgraph.fTitle;
02289 histo.fXaxis.fXmin = uxmin;
02290 histo.fXaxis.fXmax = uxmax;
02291 }
02292
02293 histo.fYaxis.fXmin = minimum;
02294 histo.fYaxis.fXmax = maximum;
02295
02296 return histo;
02297 }
02298
02299 this.DrawAxis = function() {
02300
02301
02302 var mgraph = this.GetObject();
02303
02304 var histo = this.ScanGraphsRange(mgraph.fGraphs, mgraph.fHistogram, this.root_pad());
02305
02306
02307
02308 this.firstpainter = JSROOT.Painter.drawHistogram1D(this.divid, histo, "AXIS");
02309 }
02310
02311 this.DrawNextFunction = function(indx, callback) {
02312
02313
02314 var mgraph = this.GetObject();
02315
02316 if ((mgraph.fFunctions == null) || (indx >= mgraph.fFunctions.arr.length))
02317 return JSROOT.CallBack(callback);
02318
02319 var func = mgraph.fFunctions.arr[indx];
02320 var opt = mgraph.fFunctions.opt[indx];
02321
02322 var painter = JSROOT.draw(this.divid, func, opt);
02323 if (painter) return painter.WhenReady(this.DrawNextFunction.bind(this, indx+1, callback));
02324
02325 this.DrawNextFunction(indx+1, callback);
02326 }
02327
02328 this.DrawNextGraph = function(indx, opt) {
02329 var graphs = this.GetObject().fGraphs;
02330
02331
02332 if (indx >= graphs.arr.length)
02333 return this.DrawNextFunction(0, this.DrawingReady.bind(this));
02334
02335 var drawopt = graphs.opt[indx];
02336 if ((drawopt==null) || (drawopt == "")) drawopt = opt;
02337 var subp = JSROOT.draw(this.divid, graphs.arr[indx], drawopt);
02338 this.painters.push(subp);
02339 subp.WhenReady(this.DrawNextGraph.bind(this, indx+1, opt));
02340 }
02341
02342 if (opt == null) opt = "";
02343 opt = opt.toUpperCase().replace("3D","").replace("FB","");
02344
02345 if ((opt.indexOf("A") >= 0) || (this.main_painter()==null)) {
02346 opt = opt.replace("A","");
02347 this.DrawAxis();
02348 }
02349 this.SetDivId(divid);
02350
02351 this.DrawNextGraph(0, opt);
02352
02353 return this;
02354 }
02355
02356
02357
02358 JSROOT.Painter.drawLegend = function(divid, obj, opt) {
02359
02360 JSROOT.extend(this, new JSROOT.TPavePainter(obj));
02361
02362 this.SetDivId(divid);
02363
02364 this.DrawLegendItems = function(w, h) {
02365
02366 var legend = this.GetObject(),
02367 nlines = legend.fPrimitives.arr.length,
02368 ncols = legend.fNColumns,
02369 nrows = nlines;
02370
02371 if (ncols<2) ncols = 1; else { while ((nrows-1)*ncols >= nlines) nrows--; }
02372
02373 this.StartTextDrawing(legend.fTextFont, h / (nlines * 1.2));
02374
02375 var tcolor = JSROOT.Painter.root_colors[legend.fTextColor],
02376 column_width = Math.round(w/ncols),
02377 padding_x = Math.round(0.03*w/ncols),
02378 padding_y = Math.round(0.03*h),
02379 step_y = (h - 2*padding_y)/nrows,
02380 any_opt = false;
02381
02382 for (var i = 0; i < nlines; ++i) {
02383 var leg = legend.fPrimitives.arr[i];
02384 var lopt = leg.fOption.toLowerCase();
02385
02386 var icol = i % ncols, irow = (i - icol) / ncols;
02387
02388 var x0 = icol * column_width;
02389 var tpos_x = x0 + Math.round(legend.fMargin*column_width);
02390
02391 var pos_y = Math.round(padding_y + irow*step_y);
02392 var mid_y = Math.round(padding_y + (irow+0.5)*step_y);
02393
02394 var o_fill = leg, o_marker = leg, o_line = leg;
02395
02396 var mo = leg.fObject;
02397
02398 var painter = null;
02399
02400 if ((mo !== null) && (typeof mo == 'object')) {
02401 if ('fLineColor' in mo) o_line = mo;
02402 if ('fFillColor' in mo) o_fill = mo;
02403 if ('fMarkerColor' in mo) o_marker = mo;
02404
02405 painter = this.FindPainterFor(mo);
02406 }
02407
02408
02409 if (lopt.indexOf('f') != -1) {
02410 var fillatt = (painter && painter.fillatt) ? painter.fillatt : this.createAttFill(o_fill);
02411
02412
02413 this.draw_g.append("svg:rect")
02414 .attr("x", x0 + padding_x)
02415 .attr("y", Math.round(pos_y+step_y*0.1))
02416 .attr("width", tpos_x - 2*padding_x - x0)
02417 .attr("height", Math.round(step_y*0.8))
02418 .call(fillatt.func);
02419 }
02420
02421
02422 if (lopt.indexOf('l') != -1) {
02423 var lineatt = (painter && painter.lineatt) ? painter.lineatt : JSROOT.Painter.createAttLine(o_line)
02424 this.draw_g.append("svg:line")
02425 .attr("x1", x0 + padding_x)
02426 .attr("y1", mid_y)
02427 .attr("x2", tpos_x - padding_x)
02428 .attr("y2", mid_y)
02429 .call(lineatt.func);
02430 }
02431
02432
02433 if (lopt.indexOf('e') != -1 && (lopt.indexOf('l') == -1 || lopt.indexOf('f') != -1)) {
02434 }
02435
02436
02437 if (lopt.indexOf('p') != -1) {
02438 var marker = (painter && painter.markeratt) ? painter.markeratt : JSROOT.Painter.createAttMarker(o_marker);
02439 this.draw_g
02440 .append("svg:path")
02441 .attr("d", marker.create((x0 + tpos_x)/2, mid_y))
02442 .call(marker.func);
02443 }
02444
02445 var pos_x = tpos_x;
02446 if (lopt.length>0) any_opt = true;
02447 else if (!any_opt) pos_x = x0 + padding_x;
02448
02449 this.DrawText("start", pos_x, pos_y, x0+column_width-pos_x-padding_x, step_y, leg.fLabel, tcolor);
02450 }
02451
02452
02453 this.FinishTextDrawing();
02454 }
02455
02456 this.PaveDrawFunc = this.DrawLegendItems;
02457
02458 this.Redraw();
02459
02460 return this.DrawingReady();
02461 }
02462
02463
02464
02465 JSROOT.Painter.drawPaletteAxis = function(divid,palette,opt) {
02466
02467
02468 palette.fBorderSize = 1;
02469 palette.fShadowColor = 0;
02470
02471 JSROOT.extend(this, new JSROOT.TPavePainter(palette));
02472
02473 this.SetDivId(divid);
02474
02475 this.z_handle = new JSROOT.TAxisPainter(palette.fAxis, true);
02476 this.z_handle.SetDivId(divid, -1);
02477
02478 this['MakeIcon'] = function(contour, z) {
02479 var h = this.frame_height();
02480 var res = "";
02481 var prev = { x : -1, y : -1, width: 0, height: 0, fill:"" };
02482 for (var i=0;i<contour.length-1;++i) {
02483 var z0 = z(contour[i]);
02484 var z1 = z(contour[i+1]);
02485 var col = this.main_painter().getValueColor(contour[i]);
02486
02487 var pnt = { x: 128, width: 256, y: Math.round(z1/h*512) , height: Math.round((z0-z1)/h*512), fill: col };
02488
02489 if (res.length == 0) res = "["; else res+=",";
02490
02491 var separ = "{";
02492 if (pnt.x != prev.x) { res += separ + "x:" + Math.round(pnt.x); separ =","; }
02493 if (pnt.y != prev.y) { res += separ + "y:" + Math.round(pnt.y); separ =","; }
02494 if (pnt.width != prev.width) { res += separ + "w:" + Math.round(pnt.width); separ =","; }
02495 if (pnt.height != prev.height) { res += separ + "h:" + Math.round(pnt.height); separ =","; }
02496 if (pnt.fill != prev.fill) { res += separ + "f:'" + pnt.fill + "'"; separ =","; }
02497 res += "}";
02498
02499 prev = pnt;
02500 }
02501
02502 res += "]";
02503 }
02504
02505 this.DrawAxisPalette = function(s_width, s_height) {
02506
02507 var pthis = this, palette = this.GetObject(), axis = palette.fAxis;
02508
02509 var nbr1 = axis.fNdiv % 100;
02510 if (nbr1<=0) nbr1 = 8;
02511
02512 var pos_x = parseInt(this.draw_g.attr("x")),
02513 pos_y = parseInt(this.draw_g.attr("y")),
02514 width = this.pad_width(),
02515 height = this.pad_height(),
02516 axisOffset = axis.fLabelOffset * width,
02517 contour = this.main_painter().fContour,
02518 zmin = 0, zmax = this.main_painter().gmaxbin;
02519
02520 if (contour!==null) {
02521 zmin = contour[0];
02522 zmax = contour[contour.length-1];
02523 }
02524
02525 var z = null, z_kind = "normal";
02526
02527 if (this.main_painter().options.Logz) {
02528 z = d3.scale.log();
02529 z_kind = "log";
02530 } else {
02531 z = d3.scale.linear();
02532 }
02533 z.domain([zmin, zmax]).range([s_height,0]);
02534
02535 if ((contour==null) || this._can_move)
02536
02537 this.draw_g.append("svg:rect")
02538 .attr("x", 0)
02539 .attr("y", 0)
02540 .attr("width", s_width)
02541 .attr("height", s_height)
02542 .attr("fill", 'white');
02543 else
02544 for (var i=0;i<contour.length-1;++i) {
02545 var z0 = z(contour[i]),
02546 z1 = z(contour[i+1]),
02547 col = this.main_painter().getValueColor(contour[i]);
02548
02549 var r = this.draw_g.append("svg:rect")
02550 .attr("x", 0)
02551 .attr("y", z1.toFixed(1))
02552 .attr("width", s_width)
02553 .attr("height", (z0-z1).toFixed(1))
02554 .style("fill", col)
02555 .style("stroke", col);
02556
02557
02558 if (JSROOT.gStyle.Tooltip > 0)
02559 r.on('mouseover', function() {
02560 d3.select(this).transition().duration(100).style("stroke", "black").style("stroke-width", "2");
02561 }).on('mouseout', function() {
02562 d3.select(this).transition().duration(100).style("stroke", d3.select(this).style('fill')).style("stroke-width", "");
02563 }).append("svg:title").text(contour[i].toFixed(2) + " - " + contour[i+1].toFixed(2));
02564
02565 if (JSROOT.gStyle.Zooming)
02566 r.on("dblclick", function() { pthis.main_painter().Unzoom("z"); });
02567 }
02568
02569
02570 this.z_handle.SetAxisConfig("zaxis", z_kind, z, zmin, zmax, zmin, zmax);
02571
02572 this.z_handle.DrawAxis(this.draw_g, s_width, s_height, "translate(" + s_width + ", 0)");
02573
02574 if (this._can_move && ('getBoundingClientRect' in this.draw_g.node())) {
02575 this._can_move = false;
02576
02577 var rect = this.draw_g.node().getBoundingClientRect();
02578
02579 var shift = (pos_x + parseInt(rect.width)) - Math.round(0.995*width) + 3;
02580
02581 if (shift>0) {
02582 this.draw_g.attr("x", pos_x - shift).attr("y", pos_y)
02583 .attr("transform", "translate(" + (pos_x-shift) + ", " + pos_y + ")");
02584 palette.fX1NDC -= shift/width;
02585 palette.fX2NDC -= shift/width;
02586 return;
02587 }
02588 }
02589
02590 if (!JSROOT.gStyle.Zooming) return;
02591
02592 var evnt = null, doing_zoom = false, sel1 = 0, sel2 = 0, zoom_rect = null;
02593
02594 function moveRectSel() {
02595
02596 if (!doing_zoom) return;
02597
02598 d3.event.preventDefault();
02599 var m = d3.mouse(evnt);
02600
02601 if (m[1] < sel1) sel1 = m[1]; else sel2 = m[1];
02602
02603 zoom_rect.attr("y", sel1)
02604 .attr("height", Math.abs(sel2-sel1));
02605 }
02606
02607 function endRectSel() {
02608 if (!doing_zoom) return;
02609
02610 d3.event.preventDefault();
02611 d3.select(window).on("mousemove.colzoomRect", null)
02612 .on("mouseup.colzoomRect", null);
02613 zoom_rect.remove();
02614 zoom_rect = null;
02615 doing_zoom = false;
02616
02617 var zmin = Math.min(z.invert(sel1), z.invert(sel2));
02618 var zmax = Math.max(z.invert(sel1), z.invert(sel2));
02619
02620 pthis.main_painter().Zoom(undefined, undefined, undefined, undefined, zmin, zmax);
02621 }
02622
02623 function startRectSel() {
02624
02625
02626 if (doing_zoom) return;
02627 doing_zoom = true;
02628
02629 d3.event.preventDefault();
02630
02631 evnt = this;
02632 var origin = d3.mouse(evnt);
02633
02634 sel1 = sel2 = origin[1];
02635
02636 zoom_rect = pthis.draw_g
02637 .append("svg:rect")
02638 .attr("class", "zoom")
02639 .attr("id", "colzoomRect")
02640 .attr("x", "0")
02641 .attr("width", s_width)
02642 .attr("y", sel1)
02643 .attr("height", 5);
02644
02645 d3.select(window).on("mousemove.colzoomRect", moveRectSel)
02646 .on("mouseup.colzoomRect", endRectSel, true);
02647
02648 d3.event.stopPropagation();
02649 }
02650
02651 this.draw_g.select(".axis_zoom")
02652 .on("mousedown", startRectSel)
02653 .on("dblclick", function() { pthis.main_painter().Unzoom("z"); });
02654 }
02655
02656 this.ShowContextMenu = function(evnt) {
02657 this.main_painter().ShowContextMenu("z", evnt, this.GetObject().fAxis);
02658 }
02659
02660 this.Redraw = function() {
02661 this.Enabled = true;
02662 var main = this.main_painter();
02663 this.UseContextMenu = (main !== null);
02664 if ((main !== null) && main.options)
02665 this.Enabled = (main.options.Zscale > 0) && (main.options.Color > 0) && (main.options.Lego === 0);
02666
02667 this.DrawPave();
02668 }
02669
02670 this.PaveDrawFunc = this.DrawAxisPalette;
02671
02672
02673 this.CompleteDraw = this.Redraw;
02674
02675 this._can_move = (opt === 'canmove');
02676
02677 this.Redraw();
02678
02679 return this.DrawingReady();
02680 }
02681
02682
02683
02684 JSROOT.TH2Painter = function(histo) {
02685 JSROOT.THistPainter.call(this, histo);
02686 this.fContour = null;
02687 this.fUserContour = false;
02688 this.fPalette = null;
02689 }
02690
02691 JSROOT.TH2Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
02692
02693 JSROOT.TH2Painter.prototype.FillHistContextMenu = function(menu) {
02694 if (!this.draw_content) return;
02695
02696
02697 menu.add("Auto zoom-in", this.AutoZoom);
02698
02699 menu.addDrawMenu("Draw with", ["col", "colz", "scat", "box", "text", "lego"], function(arg) {
02700 this.options = this.DecodeOptions(arg);
02701 if (this.options.Zscale > 0)
02702
02703 this.DrawNewPalette(true);
02704 this.RedrawPad();
02705 if (this.options.Lego == 0) this.AddInteractive();
02706 });
02707 }
02708
02709 JSROOT.TH2Painter.prototype.ButtonClick = function(funcname) {
02710 if (JSROOT.THistPainter.prototype.ButtonClick.call(this, funcname)) return true;
02711
02712 if (this !== this.main_painter()) return false;
02713
02714 switch(funcname) {
02715 case "ToggleColor": this.ToggleColor(); break;
02716 case "ToggleColorZ":
02717 if (this.options.Lego == 0 && this.options.Color > 0) this.ToggleColz();
02718 break;
02719 case "Toggle3D":
02720 this.options.Lego = this.options.Lego > 0 ? 0 : 1;
02721 this.RedrawPad();
02722 break;
02723 default: return false;
02724 }
02725
02726
02727 return true;
02728 }
02729
02730 JSROOT.TH2Painter.prototype.FillToolbar = function() {
02731 JSROOT.THistPainter.prototype.FillToolbar.call(this);
02732
02733 var pp = this.pad_painter(true);
02734 if (pp===null) return;
02735
02736 pp.AddButton(JSROOT.ToolbarIcons.th2color, "Toggle color", "ToggleColor");
02737 pp.AddButton(JSROOT.ToolbarIcons.th2colorz, "Toggle color palette", "ToggleColorZ");
02738 pp.AddButton(JSROOT.ToolbarIcons.th2draw3d, "Toggle 3D mode", "Toggle3D");
02739 }
02740
02741 JSROOT.TH2Painter.prototype.ToggleColor = function() {
02742
02743 var toggle = true;
02744
02745 if (this.options.Lego > 0) { this.options.Lego = 0; toggle = false; }
02746
02747 if (this.options.Color == 0) {
02748 this.options.Color = ('LastColor' in this.options) ? this.options.LastColor : 1;
02749 } else
02750 if (toggle) {
02751 this.options.LastColor = this.options.Color;
02752 this.options.Color = 0;
02753 }
02754
02755 if ((this.options.Color > 0) && (this.options.Zscale > 0))
02756 this.DrawNewPalette(true);
02757
02758 this.RedrawPad();
02759 }
02760
02761 JSROOT.TH2Painter.prototype.FindPalette = function(remove) {
02762
02763 var funcs = this.GetObject().fFunctions;
02764 if (funcs === null) return null;
02765
02766 for (var i = 0; i < funcs.arr.length; ++i) {
02767 var func = funcs.arr[i];
02768 if (func._typename !== 'TPaletteAxis') continue;
02769 if (remove) {
02770 funcs.RemoveAt(i);
02771 if (this.pad_painter())
02772 this.pad_painter().RemovePrimitive(func);
02773 return null;
02774 }
02775 return func;
02776 }
02777
02778 return null;
02779 }
02780
02781 JSROOT.TH2Painter.prototype.DrawNewPalette = function(force_resize) {
02782
02783
02784 var pal = this.FindPalette(), histo = this.GetObject();
02785
02786 if ((pal !== null) && !force_resize) return;
02787
02788 if (pal === null) {
02789 pal = JSROOT.Create('TPave');
02790
02791 JSROOT.extend(pal, { _typename: "TPaletteAxis", fName: "TPave", fH: null, fAxis: null,
02792 fX1NDC: 0.91, fX2NDC: 0.95, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1 } );
02793
02794 pal.fAxis = JSROOT.Create('TGaxis');
02795
02796
02797
02798 JSROOT.extend(pal.fAxis, { fTitle: histo.fZaxis.fTitle,
02799 fLineColor: 1, fLineSyle: 1, fLineWidth: 1,
02800 fTextAngle: 0, fTextSize: 0.04, fTextAlign: 11, fTextColor: 1, fTextFont: 42 });
02801
02802 if (histo.fFunctions == null)
02803 histo.fFunctions = JSROOT.Create("TList");
02804
02805
02806 histo.fFunctions.AddFirst(pal);
02807 }
02808
02809 var frame_painter = this.frame_painter();
02810
02811
02812 pal.fX2NDC = frame_painter.fX2NDC + 0.01 + (pal.fX2NDC - pal.fX1NDC);
02813 pal.fX1NDC = frame_painter.fX2NDC + 0.01;
02814 pal.fY1NDC = frame_painter.fY1NDC;
02815 pal.fY2NDC = frame_painter.fY2NDC;
02816
02817 var pal_painter = this.FindPainterFor(pal);
02818
02819 if (pal_painter === null) {
02820
02821 this.svg_canvas().property('current_pad', this.pad_name);
02822 pal_painter = JSROOT.draw(this.divid, pal, "canmove");
02823 this.svg_canvas().property('current_pad', '');
02824 } else {
02825 pal_painter._can_move = true;
02826 pal_painter.Redraw();
02827 }
02828
02829 if (pal.fX1NDC < frame_painter.fX2NDC) {
02830 frame_painter.fX2NDC = pal.fX1NDC - 0.01;
02831 frame_painter.Redraw();
02832 }
02833 }
02834
02835 JSROOT.TH2Painter.prototype.ToggleColz = function() {
02836 if (this.options.Zscale > 0) {
02837 this.options.Zscale = 0;
02838 } else {
02839 this.options.Zscale = 1;
02840 this.DrawNewPalette(true);
02841 }
02842
02843 this.RedrawPad();
02844 }
02845
02846 JSROOT.TH2Painter.prototype.AutoZoom = function() {
02847 var i1 = this.GetSelectIndex("x", "left", -1),
02848 i2 = this.GetSelectIndex("x", "right", 1),
02849 j1 = this.GetSelectIndex("y", "left", -1),
02850 j2 = this.GetSelectIndex("y", "right", 1),
02851 i,j, histo = this.GetObject();
02852
02853 if ((i1 == i2) || (j1 == j2)) return;
02854
02855
02856 var min = histo.getBinContent(i1 + 1, j1 + 1);
02857 for (i = i1; i < i2; ++i)
02858 for (j = j1; j < j2; ++j)
02859 if (histo.getBinContent(i + 1, j + 1) < min)
02860 min = histo.getBinContent(i + 1, j + 1);
02861 if (min>0) return;
02862
02863 var ileft = i2, iright = i1, jleft = j2, jright = j1;
02864
02865 for (i = i1; i < i2; ++i)
02866 for (j = j1; j < j2; ++j)
02867 if (histo.getBinContent(i + 1, j + 1) > min) {
02868 if (i < ileft) ileft = i;
02869 if (i >= iright) iright = i + 1;
02870 if (j < jleft) jleft = j;
02871 if (j >= jright) jright = j + 1;
02872 }
02873
02874 var xmin, xmax, ymin, ymax, isany = false;
02875
02876 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
02877 xmin = this.GetBinX(ileft);
02878 xmax = this.GetBinX(iright);
02879 isany = true;
02880 }
02881
02882 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
02883 ymin = this.GetBinY(jleft);
02884 ymax = this.GetBinY(jright);
02885 isany = true;
02886 }
02887
02888 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
02889 }
02890
02891
02892 JSROOT.TH2Painter.prototype.ScanContent = function() {
02893 var i,j,histo = this.GetObject();
02894
02895 this.nbinsx = histo.fXaxis.fNbins;
02896 this.nbinsy = histo.fYaxis.fNbins;
02897
02898
02899
02900 this.CreateAxisFuncs(true);
02901
02902
02903 this.gminbin = this.gmaxbin = histo.getBinContent(1, 1);
02904 this.gmin0bin = null;
02905 for (i = 0; i < this.nbinsx; ++i) {
02906 for (j = 0; j < this.nbinsy; ++j) {
02907 var bin_content = histo.getBinContent(i+1, j+1);
02908 if (bin_content < this.gminbin) this.gminbin = bin_content; else
02909 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
02910 if (bin_content > 0)
02911 if ((this.gmin0bin===null) || (this.gmin0bin > bin_content)) this.gmin0bin = bin_content;
02912 }
02913 }
02914
02915
02916 if (this.gmin0bin === null) this.gmin0bin = this.gmaxbin*1e-4;
02917
02918
02919 this.draw_content = this.gmaxbin > 0;
02920
02921
02922 if (this.is_main_painter() && (this.zoom_xmin === this.zoom_xmax) &&
02923 this.histo.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
02924 (this.histo.fXaxis.fFirst !== this.histo.fXaxis.fLast) &&
02925 ((this.histo.fXaxis.fFirst>1) || (this.histo.fXaxis.fLast <= this.nbinsx))) {
02926 this.zoom_xmin = this.histo.fXaxis.fFirst > 1 ? this.GetBinX(this.histo.fXaxis.fFirst-1) : this.xmin;
02927 this.zoom_xmax = this.histo.fXaxis.fLast <= this.nbinsx ? this.GetBinX(this.histo.fXaxis.fLast) : this.xmax;
02928 }
02929
02930
02931 if (this.is_main_painter() && (this.zoom_ymin === this.zoom_ymax) &&
02932 this.histo.fYaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
02933 (this.histo.fYaxis.fFirst !== this.histo.fYaxis.fLast) &&
02934 ((this.histo.fYaxis.fFirst>1) || (this.histo.fYaxis.fLast <= this.nbinsy))) {
02935 this.zoom_ymin = this.histo.fYaxis.fFirst > 1 ? this.GetBinY(this.histo.fYaxis.fFirst-1) : this.ymin;
02936 this.zoom_ymax = this.histo.fYaxis.fLast <= this.nbinsy ? this.GetBinY(this.histo.fYaxis.fLast) : this.ymax;
02937 }
02938 }
02939
02940 JSROOT.TH2Painter.prototype.CountStat = function(cond) {
02941 var histo = this.GetObject(),
02942 stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0,
02943 stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0,
02944 xleft = this.GetSelectIndex("x", "left"),
02945 xright = this.GetSelectIndex("x", "right"),
02946 yleft = this.GetSelectIndex("y", "left"),
02947 yright = this.GetSelectIndex("y", "right"),
02948 xi, xside, xx, yi, yside, yy, zz,
02949 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 };
02950
02951 for (xi = 0; xi <= this.nbinsx + 1; ++xi) {
02952 xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
02953 xx = this.GetBinX(xi - 0.5);
02954
02955 for (yi = 0; yi <= this.nbinsy + 1; ++yi) {
02956 yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
02957 yy = this.GetBinY(yi - 0.5);
02958
02959 zz = histo.getBinContent(xi, yi);
02960
02961 res.entries += zz;
02962
02963 res.matrix[yside * 3 + xside] += zz;
02964
02965 if ((xside != 1) || (yside != 1)) continue;
02966
02967 if ((cond!=null) && !cond(xx,yy)) continue;
02968
02969 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
02970
02971 stat_sum0 += zz;
02972 stat_sumx1 += xx * zz;
02973 stat_sumy1 += yy * zz;
02974 stat_sumx2 += xx * xx * zz;
02975 stat_sumy2 += yy * yy * zz;
02976 stat_sumxy += xx * yy * zz;
02977 }
02978 }
02979
02980 if (!this.IsAxisZoomed("x") && !this.IsAxisZoomed("y") && (histo.fTsumw > 0)) {
02981 stat_sum0 = histo.fTsumw;
02982 stat_sumx1 = histo.fTsumwx;
02983 stat_sumx2 = histo.fTsumwx2;
02984 stat_sumy1 = histo.fTsumwy;
02985 stat_sumy2 = histo.fTsumwy2;
02986 stat_sumxy = histo.fTsumwxy;
02987 }
02988
02989 if (stat_sum0 > 0) {
02990 res.meanx = stat_sumx1 / stat_sum0;
02991 res.meany = stat_sumy1 / stat_sum0;
02992 res.rmsx = Math.sqrt(stat_sumx2 / stat_sum0 - res.meanx * res.meanx);
02993 res.rmsy = Math.sqrt(stat_sumy2 / stat_sum0 - res.meany * res.meany);
02994 }
02995
02996 if (res.wmax===null) res.wmax = 0;
02997 res.integral = stat_sum0;
02998
02999 if (histo.fEntries > 1) res.entries = histo.fEntries;
03000
03001 return res;
03002 }
03003
03004 JSROOT.TH2Painter.prototype.FillStatistic = function(stat, dostat, dofit) {
03005 if (this.GetObject() === null) return false;
03006
03007 var pave = stat.GetObject(),
03008 data = this.CountStat(),
03009 print_name = Math.floor(dostat % 10),
03010 print_entries = Math.floor(dostat / 10) % 10,
03011 print_mean = Math.floor(dostat / 100) % 10,
03012 print_rms = Math.floor(dostat / 1000) % 10,
03013 print_under = Math.floor(dostat / 10000) % 10,
03014 print_over = Math.floor(dostat / 100000) % 10,
03015 print_integral = Math.floor(dostat / 1000000) % 10,
03016 print_skew = Math.floor(dostat / 10000000) % 10,
03017 print_kurt = Math.floor(dostat / 100000000) % 10;
03018
03019 if (print_name > 0)
03020 pave.AddText(this.GetObject().fName);
03021
03022 if (print_entries > 0)
03023 pave.AddText("Entries = " + stat.Format(data.entries,"entries"));
03024
03025 if (print_mean > 0) {
03026 pave.AddText("Mean x = " + stat.Format(data.meanx));
03027 pave.AddText("Mean y = " + stat.Format(data.meany));
03028 }
03029
03030 if (print_rms > 0) {
03031 pave.AddText("Std Dev x = " + stat.Format(data.rmsx));
03032 pave.AddText("Std Dev y = " + stat.Format(data.rmsy));
03033 }
03034
03035 if (print_integral > 0) {
03036 pave.AddText("Integral = " + stat.Format(data.matrix[4],"entries"));
03037 }
03038
03039 if (print_skew > 0) {
03040 pave.AddText("Skewness x = <undef>");
03041 pave.AddText("Skewness y = <undef>");
03042 }
03043
03044 if (print_kurt > 0)
03045 pave.AddText("Kurt = <undef>");
03046
03047 if ((print_under > 0) || (print_over > 0)) {
03048 var m = data.matrix;
03049
03050 pave.AddText("" + m[6].toFixed(0) + " | " + m[7].toFixed(0) + " | " + m[7].toFixed(0));
03051 pave.AddText("" + m[3].toFixed(0) + " | " + m[4].toFixed(0) + " | " + m[5].toFixed(0));
03052 pave.AddText("" + m[0].toFixed(0) + " | " + m[1].toFixed(0) + " | " + m[2].toFixed(0));
03053 }
03054
03055
03056 var nlines = pave.fLines.arr.length,
03057 stath = nlines * JSROOT.gStyle.StatFontSize;
03058 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
03059 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
03060 pave.fY1NDC = 0.93 - stath;
03061 pave.fY2NDC = 0.93;
03062 }
03063
03064 return true;
03065 }
03066
03067 JSROOT.TH2Painter.prototype.CreateContour = function(nlevels, zmin, zmax, zminpositive) {
03068 if (nlevels<1) nlevels = 20;
03069 this.fContour = [];
03070 this.zmin = zmin;
03071 this.zmax = zmax;
03072
03073 if (this.options.Logz) {
03074 if (this.zmax <= 0) this.zmax = 1.;
03075 if (this.zmin <= 0)
03076 this.zmin = (zminpositive > 0) ? 0.3*zminpositive : 0.0001*this.zmax;
03077 if (this.zmin >= this.zmax) this.zmin = 0.0001*this.zmax;
03078
03079 var logmin = Math.log(this.zmin)/Math.log(10);
03080 var logmax = Math.log(this.zmax)/Math.log(10);
03081 var dz = (logmax-logmin)/nlevels;
03082 this.fContour.push(this.zmin);
03083 for (var level=1; level<nlevels; level++)
03084 this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10)));
03085 this.fContour.push(this.zmax);
03086 } else {
03087 if ((this.zmin == this.zmax) && (this.zmin != 0)) {
03088 this.zmax += 0.01*Math.abs(this.zmax);
03089 this.zmin -= 0.01*Math.abs(this.zmin);
03090 }
03091 var dz = (this.zmax-this.zmin)/nlevels;
03092 for (var level=0; level<=nlevels; level++)
03093 this.fContour.push(this.zmin + dz*level);
03094 }
03095 }
03096
03097 JSROOT.TH2Painter.prototype.getContourIndex = function(zc) {
03098
03099
03100 if (this.fContour == null) {
03101
03102
03103 var histo = this.GetObject();
03104
03105 this.fUserContour = false;
03106 if ((histo.fContour!=null) && (histo.fContour.length>1) && histo.TestBit(JSROOT.TH1StatusBits.kUserContour)) {
03107 this.fContour = JSROOT.clone(histo.fContour);
03108 this.fUserContour = true;
03109 } else {
03110 var nlevels = 20, zmin = this.minbin, zmax = this.maxbin;
03111 if (histo.fContour != null) nlevels = histo.fContour.length;
03112 if (this.zoom_zmin != this.zoom_zmax) {
03113 zmin = this.zoom_zmin;
03114 zmax = this.zoom_zmax;
03115 }
03116 this.CreateContour(nlevels, zmin, zmax, this.minposbin);
03117 }
03118 }
03119
03120 if (this.fUserContour || this.options.Logz) {
03121 var cntr = this.fContour, l = 0, r = this.fContour.length-1, mid;
03122 if (zc < cntr[0]) return -1;
03123 if (zc >= cntr[r]) return r;
03124 while (l < r-1) {
03125 mid = Math.round((l+r)/2);
03126 if (cntr[mid] > zc) r = mid; else l = mid;
03127 }
03128 return l;
03129 }
03130
03131 return Math.floor(0.01+(zc-this.zmin)*(this.fContour.length-1)/(this.zmax-this.zmin));
03132 }
03133
03134 JSROOT.TH2Painter.prototype.getValueColor = function(zc, asindx) {
03135 var index = this.getContourIndex(zc);
03136
03137 if (index<0) {
03138
03139 if (this.options.Color !== 111) return null;
03140 index = 0;
03141 }
03142
03143 if (this.fPalette == null)
03144 this.fPalette = JSROOT.Painter.GetColorPalette(this.options.Palette);
03145
03146 var theColor = Math.floor((index+0.99)*this.fPalette.length/(this.fContour.length-1));
03147 if (theColor > this.fPalette.length-1) theColor = this.fPalette.length-1;
03148 return asindx ? theColor : this.fPalette[theColor];
03149 }
03150
03151 JSROOT.TH2Painter.prototype.CompressAxis = function(arr, maxlen, regular) {
03152 if (arr.length <= maxlen) return;
03153
03154
03155 var left = 0, right = arr.length-2;
03156 while ((left < right) && (arr[left].cnt===0)) ++left;
03157 while ((left < right) && (arr[right].cnt===0)) --right;
03158 if (right-left < maxlen) return;
03159
03160 function RemoveNulls() {
03161 var j = right;
03162 while (j>=left) {
03163 while ((j>=left) && (arr[j]!==null)) --j;
03164 var j2 = j;
03165 while ((j>=0) && (arr[j]===null)) --j;
03166 if (j < j2) { arr.splice(j+1, j2-j); right -= (j2-j); }
03167 --j;
03168 }
03169 };
03170
03171 if (!regular) {
03172 var grdist = Math.abs(arr[right+1].gr - arr[left].gr) / maxlen;
03173 var i = left;
03174 while (i <= right) {
03175 var gr0 = arr[i++].gr;
03176
03177 while ((i <= right) && (Math.abs(arr[i+1].gr - gr0) < grdist)) arr[i++] = null;
03178 }
03179 RemoveNulls();
03180 }
03181
03182 if (regular || ((right-left) > 1.5*maxlen)) {
03183
03184 var period = Math.floor((right-left) / maxlen);
03185 if (period<2) period = 2;
03186 var i = left;
03187 while (++i <= right) {
03188 for (var k=1;k<period;++k)
03189 if (++i <= right) arr[i] = null;
03190 }
03191 RemoveNulls();
03192 }
03193 }
03194
03195 JSROOT.TH2Painter.prototype.CreateDrawBins = function(w, h) {
03196
03197 var histo = this.GetObject(),
03198 i1 = this.GetSelectIndex("x", "left", 0),
03199 i2 = this.GetSelectIndex("x", "right", 1),
03200 j1 = this.GetSelectIndex("y", "left", 0),
03201 j2 = this.GetSelectIndex("y", "right", 1),
03202 name = this.GetTipName("\n"),
03203 xx = [], yy = [], i, j, x, y,
03204 nbins = 0, binz = 0, sumz = 0;
03205
03206 for (i = i1; i <= i2; ++i) {
03207 x = this.GetBinX(i);
03208 if (this.options.Logx && (x <= 0)) { i1 = i+1; continue; }
03209 xx.push({indx:i, axis: x, gr: this.grx(x), cnt:0});
03210 }
03211
03212 for (j = j1; j <= j2; ++j) {
03213 y = this.GetBinY(j);
03214 if (this.options.Logy && (y <= 0)) { j1 = j+1; continue; }
03215 yy.push({indx:j, axis:y, gr:this.gry(y), cnt:0});
03216 }
03217
03218
03219 this.maxbin = this.minbin = histo.getBinContent(i1 + 1, j1 + 1);
03220 for (i = i1; i < i2; ++i) {
03221 for (j = j1; j < j2; ++j) {
03222 binz = histo.getBinContent(i + 1, j + 1);
03223 if (binz != 0) nbins++;
03224 if (binz>this.maxbin) this.maxbin = binz; else
03225 if (binz<this.minbin) this.minbin = binz;
03226 }
03227 }
03228
03229 if (((this.options.Optimize > 0) && (nbins>1000)) || (this.options.Optimize > 10)) {
03230
03231
03232
03233 nbins = 0;
03234 for (i = i1; i < i2; ++i) {
03235 for (j = j1; j < j2; ++j) {
03236 binz = histo.getBinContent(i+1, j+1);
03237 if ((binz == 0) || (binz < this.minbin)) continue;
03238 nbins++;
03239 xx[i-i1].cnt+=1;
03240 yy[j-j1].cnt+=1;
03241 }
03242 }
03243 }
03244
03245 if (((this.options.Optimize > 0) && (nbins>1000)) || (this.options.Optimize > 10)) {
03246 var numx = this.options.Optimize > 10 ? 10 : 40;
03247 var numy = numx;
03248
03249 var coef = Math.abs(xx[0].gr - xx[xx.length-1].gr) / Math.abs(yy[0].gr - yy[yy.length-1].gr);
03250 if (coef > 1.) numy = Math.max(10, Math.round(numx / coef));
03251 else numx = Math.max(10, Math.round(numy * coef));
03252
03253 if ((this.options.Optimize > 1) || (xx.length > 50))
03254 this.CompressAxis(xx, numx, !this.options.Logx && this.regularx);
03255
03256 if ((this.options.Optimize > 1) || (yy.length > 50))
03257 this.CompressAxis(yy, numy, !this.options.Logy && this.regulary);
03258 }
03259
03260 var local_bins = [];
03261
03262 for (i = 0; i < xx.length-1; ++i) {
03263
03264 for (j = 0; j < yy.length-1; ++j) {
03265
03266 sumz = binz = histo.getBinContent(xx[i].indx + 1, yy[j].indx + 1);
03267
03268 if ((xx[i+1].indx > xx[i].indx+1) || (yy[j+1].indx > yy[j].indx+1)) {
03269 sumz = 0;
03270
03271 for (var i1 = xx[i].indx;i1 < xx[i+1].indx;++i1)
03272 for (var j1 = yy[j].indx;j1 < yy[j+1].indx;++j1) {
03273 var morez = histo.getBinContent(i1 + 1, j1 + 1);
03274 binz = Math.max(binz, morez);
03275 sumz += morez;
03276 }
03277 }
03278
03279 if ((binz == 0) || (binz < this.minbin)) continue;
03280
03281 var point = {
03282 x1: xx[i].axis,
03283 x2: xx[i+1].axis,
03284 y1: yy[j].axis,
03285 y2: yy[j+1].axis,
03286 z: binz
03287 };
03288
03289 if (JSROOT.gStyle.Tooltip > 0) {
03290 if (this.x_kind == 'labels')
03291 point.tip = name + "x = " + this.AxisAsText("x", xx[i].axis) + "<br/>";
03292 else {
03293 point.tip = name + "x = [" + this.AxisAsText("x", xx[i].axis) + ", " + this.AxisAsText("x", xx[i+1].axis) + ")";
03294
03295 if (xx[i].indx + 1 == xx[i+1].indx)
03296 point.tip += " bin=" + xx[i].indx + "<br/>";
03297 else
03298 point.tip += " bins=[" + xx[i].indx + "," + (xx[i+1].indx-1) + "]<br/>";
03299 }
03300 if (this.y_kind == 'labels')
03301 point.tip += "y = " + this.AxisAsText("y", yy[j].axis) + "<br/>";
03302 else {
03303 point.tip += "y = [" + this.AxisAsText("y", yy[j].axis) + ", " + this.AxisAsText("y", yy[j+1].axis) + ")";
03304 if (yy[j].indx + 1 == yy[j+1].indx)
03305 point.tip += " bin=" + yy[j].indx + "<br/>";
03306 else
03307 point.tip += " bins=[" + yy[j].indx + "," + (yy[j+1].indx-1) + "]<br/>";
03308 }
03309
03310 if (sumz == binz)
03311 point.tip += "entries = " + JSROOT.FFormat(sumz, JSROOT.gStyle.StatFormat);
03312 else
03313 point.tip += "sum = " + JSROOT.FFormat(sumz, JSROOT.gStyle.StatFormat) +
03314 " max = " + JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat);
03315 }
03316 local_bins.push(point);
03317 }
03318 }
03319
03320 return local_bins;
03321 }
03322
03323 JSROOT.TH2Painter.prototype.PrepareColorDraw = function(dorounding, pixel_density) {
03324 var histo = this.GetObject(), i, j, x, y, binz, binarea,
03325 res = {
03326 i1: this.GetSelectIndex("x", "left", 0),
03327 i2: this.GetSelectIndex("x", "right", 1),
03328 j1: this.GetSelectIndex("y", "left", 0),
03329 j2: this.GetSelectIndex("y", "right", 1),
03330 grx: [], gry: [], min: 0, max: 0
03331 };
03332
03333 if (pixel_density) dorounding = true;
03334
03335
03336 for (i = res.i1; i <= res.i2; ++i) {
03337 x = this.GetBinX(i);
03338 if (this.options.Logx && (x <= 0)) { res.i1 = i+1; continue; }
03339 res.grx[i] = this.grx(x);
03340 if (dorounding) res.grx[i] = Math.round(res.grx[i]);
03341 }
03342
03343 for (j = res.j1; j <= res.j2; ++j) {
03344 y = this.GetBinY(j);
03345 if (this.options.Logy && (y <= 0)) { res.j1 = j+1; continue; }
03346 res.gry[j] = this.gry(y);
03347 if (dorounding) res.gry[j] = Math.round(res.gry[j]);
03348 }
03349
03350
03351
03352 binz = histo.getBinContent(res.i1 + 1, res.j1 + 1);
03353 this.maxbin = this.minbin = this.minposbin = null;
03354
03355 for (i = res.i1; i < res.i2; ++i) {
03356 for (j = res.j1; j < res.j2; ++j) {
03357 binz = histo.getBinContent(i + 1, j + 1);
03358 if (pixel_density) {
03359 binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]);
03360 if (binarea <= 0) continue;
03361 res.max = Math.max(res.max, binz);
03362 if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz;
03363 binz = binz/binarea;
03364 }
03365 if (this.maxbin===null) {
03366 this.maxbin = this.minbin = binz;
03367 } else {
03368 this.maxbin = Math.max(this.maxbin, binz);
03369 this.minbin = Math.min(this.minbin, binz);
03370 }
03371 if (binz > 0)
03372 if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz;
03373 }
03374 }
03375
03376 this.fContour = null;
03377 this.fUserContour = false;
03378
03379 return res;
03380 }
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419 JSROOT.TH2Painter.prototype.DrawBinsColor = function(w,h) {
03420 var histo = this.GetObject(),
03421 handle = this.PrepareColorDraw(true),
03422 colPaths = [], currx = [], curry = [],
03423 colindx, cmd1, cmd2, i, j, binz;
03424
03425
03426 for (i = handle.i1; i < handle.i2; ++i) {
03427 for (j = handle.j1; j < handle.j2; ++j) {
03428 binz = histo.getBinContent(i + 1, j + 1);
03429 if ((binz == 0) || (binz < this.minbin)) continue;
03430
03431 colindx = this.getValueColor(binz, true);
03432 if (colindx === null) continue;
03433
03434 cmd1 = "M"+handle.grx[i]+","+handle.gry[j+1];
03435 if (colPaths[colindx] === undefined) {
03436 colPaths[colindx] = cmd1;
03437 } else{
03438 cmd2 = "m" + (handle.grx[i]-currx[colindx]) + "," + (handle.gry[j+1]-curry[colindx]);
03439 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
03440 }
03441
03442 currx[colindx] = handle.grx[i];
03443 curry[colindx] = handle.gry[j+1];
03444
03445 colPaths[colindx] += "v" + (handle.gry[j] - handle.gry[j+1]) +
03446 "h" + (handle.grx[i+1] - handle.grx[i]) +
03447 "v" + (handle.gry[j+1] - handle.gry[j]) + "z";
03448 }
03449 }
03450
03451 for (colindx=0;colindx<colPaths.length;++colindx)
03452 if (colPaths[colindx] !== undefined)
03453 this.draw_g
03454 .append("svg:path")
03455 .attr("palette-index", colindx)
03456 .attr("fill", this.fPalette[colindx])
03457 .attr("d", colPaths[colindx]);
03458
03459 return handle;
03460 }
03461
03462 JSROOT.TH2Painter.prototype.DrawBinsText = function(w, h, handle) {
03463 var histo = this.GetObject(),
03464 i,j,binz,colindx,binw,binh,lbl;
03465
03466 if (handle===null) handle = this.PrepareColorDraw(false);
03467
03468 var text_g = this.draw_g
03469 .append("svg:g")
03470 .attr("class","th2_text");
03471
03472 this.StartTextDrawing(42, 20, text_g);
03473
03474 for (i = handle.i1; i < handle.i2; ++i)
03475 for (j = handle.j1; j < handle.j2; ++j) {
03476 binz = histo.getBinContent(i + 1, j + 1);
03477 if ((binz == 0) || (binz < this.minbin)) continue;
03478
03479 colindx = this.getValueColor(binz, true);
03480 if (colindx === null) continue;
03481
03482 binw = handle.grx[i+1] - handle.grx[i];
03483 binh = handle.gry[j] - handle.gry[j+1];
03484 lbl = Math.round(binz);
03485
03486 if (lbl === binz)
03487 lbl = binz.toString();
03488 else
03489 lbl = JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat);
03490
03491 this.DrawText(22, Math.round(handle.grx[i] + binw*0.1), Math.round(handle.gry[j+1] + binh*0.1),
03492 Math.round(binw*0.8), Math.round(binh*0.8),
03493 lbl, "black", 0, text_g);
03494 }
03495
03496 this.FinishTextDrawing(text_g);
03497
03498 return handle;
03499 }
03500
03501 JSROOT.TH2Painter.prototype.DrawBinsBox = function(w,h) {
03502 var histo = this.GetObject(),
03503 handle = this.PrepareColorDraw(false),
03504 i, j, binz, colPaths = [], currx = [], curry = [],
03505 colindx, zdiff, dgrx, dgry, ww, hh, cmd1, cmd2;
03506
03507 var xfactor = 1, yfactor = 1, uselogz = false, logmin = 0, logmax = 1;
03508 if (this.options.Logz && (this.maxbin>0)) {
03509 uselogz = true;
03510 logmax = Math.log(this.maxbin);
03511 logmin = (this.minbin > 0) ? Math.log(this.minbin) : logmax - 10;
03512 if (logmin >= logmax) logmin = logmax - 10;
03513 xfactor = 0.5 / (logmax - logmin);
03514 yfactor = 0.5 / (logmax - logmin);
03515 } else {
03516 xfactor = 0.5 / (this.maxbin - this.minbin);
03517 yfactor = 0.5 / (this.maxbin - this.minbin);
03518 }
03519
03520
03521 for (i = handle.i1; i < handle.i2; ++i) {
03522 for (j = handle.j1; j < handle.j2; ++j) {
03523 binz = histo.getBinContent(i + 1, j + 1);
03524 if ((binz == 0) || (binz < this.minbin)) continue;
03525
03526 zdiff = uselogz ? (logmax - ((binz>0) ? Math.log(binz) : logmin)) : this.maxbin - binz;
03527
03528 ww = handle.grx[i+1] - handle.grx[i];
03529 hh = handle.gry[j] - handle.gry[j+1];
03530
03531 dgrx = zdiff * xfactor * ww;
03532 dgry = zdiff * yfactor * hh;
03533
03534 ww = Math.max(Math.round(ww - 2*dgrx), 1);
03535 hh = Math.max(Math.round(hh - 2*dgry), 1);
03536
03537 if (colPaths[i]===undefined) colPaths[i] = "";
03538 colPaths[i] += "M" + Math.round(handle.grx[i] + dgrx) + "," + Math.round(handle.gry[j+1] + dgry) +
03539 "v" + hh + "h" + ww + "v-" + hh + "z";
03540 }
03541 }
03542
03543 for (i=0;i<colPaths.length;++i)
03544 if (colPaths[i] !== undefined)
03545 this.draw_g.append("svg:path")
03546 .attr("hist-column", i)
03547 .attr("d", colPaths[i])
03548 .call(this.lineatt.func)
03549 .call(this.fillatt.func);
03550
03551 return handle;
03552 }
03553
03554 JSROOT.TH2Painter.prototype.DrawBinsScatter = function(w,h) {
03555 var histo = this.GetObject(),
03556 handle = this.PrepareColorDraw(true, true),
03557 colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [],
03558 colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1.;
03559
03560
03561 if (this.maxbin > 0.7) factor = 0.7/this.maxbin;
03562
03563 var nlevels = Math.round(handle.max - handle.min);
03564 this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin);
03565
03566
03567 for (i = handle.i1; i < handle.i2; ++i) {
03568 for (j = handle.j1; j < handle.j2; ++j) {
03569 binz = histo.getBinContent(i + 1, j + 1);
03570 if ((binz == 0) || (binz < this.minbin)) continue;
03571
03572 cw = handle.grx[i+1] - handle.grx[i];
03573 ch = handle.gry[j] - handle.gry[j+1];
03574 if (cw*ch <= 0) continue;
03575
03576 colindx = this.getContourIndex(binz/cw/ch);
03577 if (colindx < 0) continue;
03578
03579 cmd1 = "M"+handle.grx[i]+","+handle.gry[j+1];
03580 if (colPaths[colindx] === undefined) {
03581 colPaths[colindx] = cmd1;
03582 cell_w[colindx] = cw;
03583 cell_h[colindx] = ch;
03584 } else{
03585 cmd2 = "m" + (handle.grx[i]-currx[colindx]) + "," + (handle.gry[j+1] - curry[colindx]);
03586 colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1;
03587 cell_w[colindx] = Math.max(cell_w[colindx], cw);
03588 cell_h[colindx] = Math.max(cell_h[colindx], ch);
03589 }
03590
03591 currx[colindx] = handle.grx[i];
03592 curry[colindx] = handle.gry[j+1];
03593
03594 colPaths[colindx] += "v"+ch+"h"+cw+"v-"+ch+"z";
03595 }
03596 }
03597
03598 var layer = this.svg_frame().select('.main_layer');
03599 var defs = layer.select("defs");
03600 if (defs.empty() && (colPaths.length>0))
03601 defs = layer.insert("svg:defs",":first-child");
03602
03603 if (!this.markeratt)
03604 this.markeratt = JSROOT.Painter.createAttMarker(histo);
03605
03606 for (colindx=0;colindx<colPaths.length;++colindx)
03607 if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) {
03608 var pattern_class = "scatter_" + colindx;
03609 var pattern = defs.select('.'+pattern_class);
03610 if (pattern.empty())
03611 pattern = defs.append('svg:pattern')
03612 .attr("class", pattern_class)
03613 .attr("id", "jsroot_scatter_pattern_" + JSROOT.id_counter++)
03614 .attr("patternUnits","userSpaceOnUse");
03615 else
03616 pattern.selectAll("*").remove();
03617
03618 var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]);
03619 if (npix<1) npix = 1;
03620
03621 var arrx = new Float32Array(npix), arry = new Float32Array(npix);
03622
03623 if (npix===1) {
03624 arrx[0] = arry[0] = 0.5;
03625 } else {
03626 for (var n=0;n<npix;++n) {
03627 arrx[n] = Math.random();
03628 arry[n] = Math.random();
03629 }
03630 }
03631
03632
03633
03634 this.markeratt.reset_pos();
03635
03636 var path = "";
03637
03638 for (var n=0;n<npix;++n)
03639 path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]);
03640
03641 pattern.attr("width", cell_w[colindx])
03642 .attr("height", cell_h[colindx])
03643 .append("svg:path")
03644 .attr("d",path)
03645 .call(this.markeratt.func);
03646
03647 this.draw_g
03648 .append("svg:path")
03649 .attr("scatter-index", colindx)
03650 .attr("fill", 'url(#' + pattern.attr("id") + ')')
03651 .attr("d", colPaths[colindx]);
03652 }
03653
03654 return handle;
03655 }
03656
03657 JSROOT.TH2Painter.prototype.DrawBins = function() {
03658
03659 this.RecreateDrawG(false, "main_layer");
03660
03661 var w = this.frame_width(), h = this.frame_height();
03662
03663 var handle = null;
03664
03665
03666
03667 if (this.options.Color + this.options.Box + this.options.Scat + this.options.Text == 0)
03668 this.options.Scat = 1;
03669
03670 if (this.options.Color > 0)
03671 handle = this.DrawBinsColor(w, h);
03672 else
03673 if (this.options.Scat > 0)
03674 handle = this.DrawBinsScatter(w, h);
03675 else
03676 if (this.options.Box > 0)
03677 handle = this.DrawBinsBox(w, h);
03678
03679 if (this.options.Text>0)
03680 handle = this.DrawBinsText(w, h, handle);
03681
03682 this.tt_handle = handle;
03683 }
03684
03685 JSROOT.TH2Painter.prototype.GetBinTips = function (i, j) {
03686 var lines = [];
03687
03688 lines.push(this.GetTipName());
03689
03690 if (this.x_kind == 'labels')
03691 lines.push("x = " + this.AxisAsText("x", this.GetBinX(i)));
03692 else
03693 lines.push("x = [" + this.AxisAsText("x", this.GetBinX(i)) + ", " + this.AxisAsText("x", this.GetBinX(i+1)) + ")");
03694
03695 if (this.y_kind == 'labels')
03696 lines.push("y = " + this.AxisAsText("y", this.GetBinY(j)));
03697 else
03698 lines.push("y = [" + this.AxisAsText("y", this.GetBinY(j)) + ", " + this.AxisAsText("y", this.GetBinY(j+1)) + ")");
03699
03700 lines.push("bin = " + i + ", " + j);
03701
03702 var binz = this.GetObject().getBinContent(i+1,j+1);
03703 if (binz === Math.round(binz))
03704 lines.push("entries = " + binz);
03705 else
03706 lines.push("entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.StatFormat));
03707
03708 return lines;
03709 }
03710
03711 JSROOT.TH2Painter.prototype.ProcessTooltip = function(pnt) {
03712 if (pnt==null) {
03713 if (this.draw_g !== null)
03714 this.draw_g.select(".tooltip_bin").remove();
03715 this.ProvideUserTooltip(null);
03716 return null;
03717 }
03718
03719 var histo = this.GetObject(),
03720 h = this.tt_handle,
03721 i, j, find = 0;
03722
03723
03724 for (i = h.i1; i < h.i2; ++i)
03725 if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1])) { ++find; break; }
03726
03727 for (j = h.j1; j <= h.j2; ++j)
03728 if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j])) { ++find; break; }
03729
03730 var ttrect = this.draw_g.select(".tooltip_bin");
03731
03732 var binz = (find === 2) ? histo.getBinContent(i+1,j+1) : -100;
03733
03734
03735
03736 if ((find !== 2) || (binz === 0) || (binz < this.minbin)) {
03737 ttrect.remove();
03738 this.ProvideUserTooltip(null);
03739 return null;
03740 }
03741
03742 var res = { x: pnt.x, y: pnt.y,
03743 color1: this.lineatt.color, color2: this.fillatt.color,
03744 lines: this.GetBinTips(i, j), exact: true, menu: true };
03745
03746 if (this.options.Color > 0) res.color2 = this.getValueColor(binz);
03747
03748 if (ttrect.empty())
03749 ttrect = this.draw_g.append("svg:rect")
03750 .attr("class","tooltip_bin h1bin")
03751 .style("pointer-events","none");
03752
03753 res.changed = ttrect.property("current_bin") !== i*10000 + j;
03754
03755 if (res.changed)
03756 ttrect.attr("x", h.grx[i])
03757 .attr("width", h.grx[i+1] - h.grx[i])
03758 .attr("y", h.gry[j+1])
03759 .attr("height", h.gry[j] - h.gry[j+1])
03760 .style("opacity", "0.7")
03761 .property("current_bin", i*10000 + j);
03762
03763 if (this.IsUserTooltipCallback() && res.changed) {
03764 this.ProvideUserTooltip({ obj: histo, name: histo.fName,
03765 bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1,
03766 grx: pnt.x, gry: pnt.y });
03767 }
03768
03769 return res;
03770 }
03771
03772 JSROOT.TH2Painter.prototype.CanZoomIn = function(axis,min,max) {
03773
03774 if ((axis=="x") && (this.GetIndexX(max,0.5) - this.GetIndexX(min,0) > 1)) return true;
03775
03776 if ((axis=="y") && (this.GetIndexY(max,0.5) - this.GetIndexY(min,0) > 1)) return true;
03777
03778 if (axis=="z") return true;
03779
03780 return false;
03781 }
03782
03783 JSROOT.TH2Painter.prototype.Draw2D = function(call_back) {
03784
03785 if (typeof this['Create3DScene'] == 'function')
03786 this.Create3DScene(-1);
03787
03788 this.DrawAxes();
03789
03790 this.DrawGrids();
03791
03792 this.DrawBins();
03793
03794 this.DrawTitle();
03795
03796 JSROOT.CallBack(call_back);
03797 }
03798
03799 JSROOT.TH2Painter.prototype.CheckResize = function(size) {
03800
03801 var pad_painter = this.pad_painter();
03802 var changed = true, force = (this.options.Lego > 0) && !JSROOT.browser.isFirefox;
03803 if (pad_painter)
03804 changed = pad_painter.CheckCanvasResize(size, force);
03805 if (changed && (this.options.Lego > 0) && (typeof this['Resize3D'] == 'function'))
03806 this.Resize3D();
03807 return changed;
03808 }
03809
03810
03811 JSROOT.TH2Painter.prototype.Draw3D = function(call_back) {
03812 JSROOT.AssertPrerequisites('3d', function() {
03813 this['Create3DScene'] = JSROOT.Painter.HPainter_Create3DScene;
03814 this['Draw3DBins'] = JSROOT.Painter.TH2Painter_Draw3DBins;
03815 this['Draw3D'] = JSROOT.Painter.TH2Painter_Draw3D;
03816 this['Draw3D'](call_back);
03817 }.bind(this));
03818 }
03819
03820 JSROOT.TH2Painter.prototype.Redraw = function() {
03821 this.CreateXY();
03822
03823 var func_name = (this.options.Lego > 0) ? "Draw3D" : "Draw2D";
03824
03825 this[func_name]();
03826 }
03827
03828 JSROOT.Painter.drawHistogram2D = function(divid, histo, opt) {
03829
03830 JSROOT.extend(this, new JSROOT.TH2Painter(histo));
03831
03832 this.SetDivId(divid, 1);
03833
03834
03835 this.options = this.DecodeOptions(opt);
03836
03837 this.CheckPadOptions();
03838
03839 this.ScanContent();
03840
03841
03842 if (this.create_canvas && (this.options.Zscale > 0))
03843
03844 this.DrawNewPalette(true);
03845
03846
03847 this.CreateXY();
03848
03849
03850 if (JSROOT.gStyle.AutoStat && this.create_canvas)
03851 this.CreateStat();
03852
03853 var func_name = this.options.Lego > 0 ? "Draw3D" : "Draw2D";
03854
03855 this[func_name](function() {
03856 this.DrawNextFunction(0, function() {
03857 if (this.options.Lego == 0) {
03858 this.AddInteractive();
03859 if (this.options.AutoZoom) this.AutoZoom();
03860 }
03861 this.FillToolbar();
03862 this.DrawingReady();
03863 }.bind(this));
03864
03865 }.bind(this));
03866
03867 return this;
03868 }
03869
03870 return JSROOT.Painter;
03871
03872 }));