00001
00002
00003
00004 (function() {
00005
00006 if (typeof JSROOT != 'object') {
00007 var e1 = new Error('JSROOT is not defined');
00008 e1.source = 'JSRootPainter.js';
00009 throw e1;
00010 }
00011
00012 if (typeof d3 != 'object') {
00013 var e1 = new Error('This extension requires d3.v3.js');
00014 e1.source = 'JSRootPainter.js';
00015 throw e1;
00016 }
00017
00018 if (typeof JSROOT.Painter == 'object') {
00019 var e1 = new Error('JSROOT.Painter already defined');
00020 e1.source = 'JSRootPainter.js';
00021 throw e1;
00022 }
00023
00024
00025 JSROOT.fDrawFunc = new Array;
00026
00027 JSROOT.addDrawFunc = function(_name, _func) {
00028 JSROOT.fDrawFunc.push({ name:_name, func:_func });
00029 }
00030
00031 JSROOT.gStyle = {
00032 Tooltip : true,
00033 ContextMenu : true,
00034 Zooming : true,
00035 MoveResize : true,
00036 DragAndDrop : false,
00037 OptimizeDraw : 1,
00038 DefaultCol : 1,
00039 AutoStat : true,
00040 OptStat : 1111,
00041 StatNDC : { fX1NDC : 0.78, fY1NDC: 0.75, fX2NDC: 0.98, fY2NDC: 0.91 },
00042 StatText : { fTextAngle: 0, fTextSize: 9, fTextAlign: 12, fTextColor: 1, fTextFont: 42 },
00043 StatFill : { fFillColor: 0, fFillStyle: 1001 },
00044 TimeOffset : 788918400000,
00045 StatFormat : function(v) { return (Math.abs(v) < 1e5) ? v.toFixed(5) : v.toExponential(7); },
00046 StatEntriesFormat : function(v) { return (Math.abs(v) < 1e7) ? v.toFixed(0) : v.toExponential(7); }
00047 };
00048
00052 JSROOT.Painter = {};
00053
00054 JSROOT.Painter.readStyleFromURL = function(url) {
00055 var optimize = JSROOT.GetUrlOption("optimize", url);
00056 if (optimize=="") JSROOT.gStyle.OptimizeDraw = 2; else
00057 if (optimize!=null) {
00058 JSROOT.gStyle.OptimizeDraw = parseInt(optimize);
00059 if (JSROOT.gStyle.OptimizeDraw==NaN) JSROOT.gStyle.OptimizeDraw = 2;
00060 }
00061
00062 var inter = JSROOT.GetUrlOption("interactive", url);
00063 if ((inter=="") || (inter=="1")) inter = "11111"; else
00064 if (inter=="0") inter = "00000";
00065 if ((inter!=null) && (inter.length==5)) {
00066 JSROOT.gStyle.Tooltip = (inter.charAt(0) != '0');
00067 JSROOT.gStyle.ContextMenu = (inter.charAt(1) != '0');
00068 JSROOT.gStyle.Zooming = (inter.charAt(2) != '0');
00069 JSROOT.gStyle.MoveResize = (inter.charAt(3) != '0');
00070 JSROOT.gStyle.DragAndDrop = (inter.charAt(4) != '0');
00071 }
00072
00073 var col = JSROOT.GetUrlOption("col", url);
00074 if (col!=null) {
00075 col = parseInt(col);
00076 if ((col!=NaN) && (col>0) && (col<4)) JSROOT.gStyle.DefaultCol = col;
00077 }
00078 }
00079
00083 JSROOT.Painter.createmenu = function(event, menuname) {
00084
00085 if (!menuname) menuname = "root_ctx_menu";
00086
00087 var xMousePosition = event.clientX + window.pageXOffset;
00088 var yMousePosition = event.clientY + window.pageYOffset;
00089
00090 var x = document.getElementById(menuname);
00091 if (x) x.parentNode.removeChild(x);
00092
00093 var d = document.createElement('div');
00094 d.setAttribute('class', 'ctxmenu');
00095 d.setAttribute('id', menuname);
00096 document.body.appendChild(d);
00097 d.style.left = xMousePosition + "px";
00098 d.style.top = yMousePosition + "px";
00099 d.onmouseover = function(e) {
00100 this.style.cursor = 'pointer';
00101 }
00102 d.onclick = function(e) {
00103 var x = document.getElementById(menuname);
00104 if (x) x.parentNode.removeChild(x);
00105 }
00106
00107 document.body.onclick = function(e) {
00108 var x = document.getElementById(menuname);
00109 if (x)
00110 x.parentNode.removeChild(x);
00111 }
00112
00113 return d;
00114 }
00115
00119 JSROOT.Painter.menuitem = function(menu, txt, func) {
00120 var p = document.createElement('p');
00121 menu.appendChild(p);
00122 p.onclick = func;
00123 p.setAttribute('class', 'ctxline');
00124 p.innerHTML = txt;
00125 }
00126
00127 JSROOT.Painter.Coord = {
00128 kCARTESIAN : 1,
00129 kPOLAR : 2,
00130 kCYLINDRICAL : 3,
00131 kSPHERICAL : 4,
00132 kRAPIDITY : 5
00133 }
00134
00136 JSROOT.Painter.root_colors = function() {
00137 var colorMap = new Array('white', 'black', 'red', 'green', 'blue',
00138 'rgb(255,255,0)', 'rgb(255,0,255)', 'rgb(0,255,255)',
00139 'rgb(89, 211,84)', 'rgb(89,84,216)', 'rgb(254,254,254)',
00140 'rgb(191,181,173)', 'rgb(76,76,76)', 'rgb(102,102,102)',
00141 'rgb(127,127,127)', 'rgb(153,153,153)', 'rgb(178,178,178)',
00142 'rgb(204,204,204)', 'rgb(229,229,229)', 'rgb(242,242,242)',
00143 'rgb(204,198,170)', 'rgb(204,198,170)', 'rgb(193,191,168)',
00144 'rgb(186,181,163)', 'rgb(178,165,150)', 'rgb(183,163,155)',
00145 'rgb(173,153,140)', 'rgb(155,142,130)', 'rgb(135,102,86)',
00146 'rgb(175,206,198)', 'rgb(132,193,163)', 'rgb(137,168,160)',
00147 'rgb(130,158,140)', 'rgb(173,188,198)', 'rgb(122,142,153)',
00148 'rgb(117,137,145)', 'rgb(104,130,150)', 'rgb(109,122,132)',
00149 'rgb(124,153,209)', 'rgb(127,127,155)', 'rgb(170,165,191)',
00150 'rgb(211,206,135)', 'rgb(221,186,135)', 'rgb(188,158,130)',
00151 'rgb(198,153,124)', 'rgb(191,130,119)', 'rgb(206,94,96)',
00152 'rgb(170,142,147)', 'rgb(165,119,122)', 'rgb(147,104,112)',
00153 'rgb(211,89,84)');
00154
00155 var circleColors = [ 632, 416, 600, 400, 616, 432 ];
00156
00157 var rectangleColors = [ 800, 820, 840, 860, 880, 900 ];
00158
00159 var set1 = [ 255, 204, 204, 255, 153, 153, 204, 153, 153, 255, 102, 102,
00160 204, 102, 102, 153, 102, 102, 255, 51, 51, 204, 51, 51, 153, 51,
00161 51, 102, 51, 51, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51, 0, 0 ];
00162 var set2 = [ 204, 255, 204, 153, 255, 153, 153, 204, 153, 102, 255, 102,
00163 102, 204, 102, 102, 153, 102, 51, 255, 51, 51, 204, 51, 51, 153,
00164 51, 51, 102, 51, 0, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51, 0 ];
00165 var set3 = [ 204, 204, 255, 153, 153, 255, 153, 153, 204, 102, 102, 255,
00166 102, 102, 204, 102, 102, 153, 51, 51, 255, 51, 51, 204, 51, 51,
00167 153, 51, 51, 102, 0, 0, 255, 0, 0, 204, 0, 0, 153, 0, 0, 102, 0, 0, 51 ];
00168 var set4 = [ 255, 255, 204, 255, 255, 153, 204, 204, 153, 255, 255, 102,
00169 204, 204, 102, 153, 153, 102, 255, 255, 51, 204, 204, 51, 153, 153,
00170 51, 102, 102, 51, 255, 255, 0, 204, 204, 0, 153, 153, 0, 102, 102, 0, 51, 51, 0 ];
00171 var set5 = [ 255, 204, 255, 255, 153, 255, 204, 153, 204, 255, 102, 255,
00172 204, 102, 204, 153, 102, 153, 255, 51, 255, 204, 51, 204, 153, 51,
00173 153, 102, 51, 102, 255, 0, 255, 204, 0, 204, 153, 0, 153, 102, 0, 102, 51, 0, 51 ];
00174 var set6 = [ 204, 255, 255, 153, 255, 255, 153, 204, 204, 102, 255, 255,
00175 102, 204, 204, 102, 153, 153, 51, 255, 255, 51, 204, 204, 51, 153,
00176 153, 51, 102, 102, 0, 255, 255, 0, 204, 204, 0, 153, 153, 0, 102, 102, 0, 51, 51 ];
00177
00178 var circleSets = new Array(set1, set2, set3, set4, set5, set6);
00179
00180 var set7 = [ 255, 204, 153, 204, 153, 102, 153, 102, 51, 153, 102, 0,
00181 204, 153, 51, 255, 204, 102, 255, 153, 0, 255, 204, 51, 204, 153,
00182 0, 255, 204, 0, 255, 153, 51, 204, 102, 0, 102, 51, 0, 153, 51, 0,
00183 204, 102, 51, 255, 153, 102, 255, 102, 0, 255, 102, 51, 204, 51, 0,
00184 255, 51, 0 ];
00185 var set8 = [ 153, 255, 51, 102, 204, 0, 51, 102, 0, 51, 153, 0, 102, 204,
00186 51, 153, 255, 102, 102, 255, 0, 102, 255, 51, 51, 204, 0, 51, 255,
00187 0, 204, 255, 153, 153, 204, 102, 102, 153, 51, 102, 153, 0, 153,
00188 204, 51, 204, 255, 102, 153, 255, 0, 204, 255, 51, 153, 204, 0,
00189 204, 255, 0 ];
00190 var set9 = [ 153, 255, 204, 102, 204, 153, 51, 153, 102, 0, 153, 102, 51,
00191 204, 153, 102, 255, 204, 0, 255, 102, 51, 255, 204, 0, 204, 153, 0,
00192 255, 204, 51, 255, 153, 0, 204, 102, 0, 102, 51, 0, 153, 51, 51,
00193 204, 102, 102, 255, 153, 0, 255, 153, 51, 255, 102, 0, 204, 51, 0,
00194 255, 51 ];
00195 var set10 = [ 153, 204, 255, 102, 153, 204, 51, 102, 153, 0, 51, 153, 51,
00196 102, 204, 102, 153, 255, 0, 102, 255, 51, 102, 255, 0, 51, 204, 0,
00197 51, 255, 51, 153, 255, 0, 102, 204, 0, 51, 102, 0, 102, 153, 51,
00198 153, 204, 102, 204, 255, 0, 153, 255, 51, 204, 255, 0, 153, 204, 0,
00199 204, 255 ];
00200 var set11 = [ 204, 153, 255, 153, 102, 204, 102, 51, 153, 102, 0, 153,
00201 153, 51, 204, 204, 102, 255, 153, 0, 255, 204, 51, 255, 153, 0,
00202 204, 204, 0, 255, 153, 51, 255, 102, 0, 204, 51, 0, 102, 51, 0,
00203 153, 102, 51, 204, 153, 102, 255, 102, 0, 255, 102, 51, 255, 51, 0,
00204 204, 51, 0, 255 ];
00205 var set12 = [ 255, 51, 153, 204, 0, 102, 102, 0, 51, 153, 0, 51, 204, 51,
00206 102, 255, 102, 153, 255, 0, 102, 255, 51, 102, 204, 0, 51, 255, 0,
00207 51, 255, 153, 204, 204, 102, 153, 153, 51, 102, 153, 0, 102, 204,
00208 51, 153, 255, 102, 204, 255, 0, 153, 204, 0, 153, 255, 51, 204,
00209 255, 0, 153 ];
00210
00211 var rectSets = new Array(set7, set8, set9, set10, set11, set12);
00212
00213 for (var i = 0; i < 6; i++) {
00214 for (var j = 0; j < 15; j++) {
00215 var colorn = circleColors[i] + j - 10;
00216 colorMap[colorn] = 'rgb(' + circleSets[i][3 * j] + ',' + circleSets[i][3 * j + 1] + ',' + circleSets[i][3 * j + 2] + ')';
00217 colorn = rectangleColors[i] + j - 9;
00218 colorMap[colorn] = 'rgb(' + rectSets[i][3 * j] + ',' + rectSets[i][3 * j + 1] + ',' + rectSets[i][3 * j + 2] + ')';
00219 }
00220 }
00221 return colorMap;
00222 }();
00223
00224 JSROOT.Painter.adoptRootColors = function(objarr) {
00225 if (!objarr || !objarr.arr) return;
00226
00227 for (var n in objarr.arr) {
00228 var col = objarr.arr[n];
00229 if ((col==null) || (col['_typename'] != 'TColor')) continue;
00230
00231 var num = col.fNumber;
00232 if ((num<0) || (num>4096)) continue;
00233
00234 var rgb = "rgb(" + (col.fRed*255).toFixed(0) + "," + (col.fGreen*255).toFixed(0) + "," + (col.fBlue*255).toFixed(0) + ")";
00235
00236 if (rgb == 'rgb(255,255,255)') rgb = 'white';
00237
00238 while (num>JSROOT.Painter.root_colors.length)
00239 JSROOT.Painter.root_colors.push(rgb);
00240
00241 if (JSROOT.Painter.root_colors[num] != rgb) {
00242 JSROOT.Painter.root_colors[num] = rgb;
00243 }
00244 }
00245 }
00246
00247 JSROOT.Painter.root_line_styles = new Array("", "", "3, 3", "1, 2",
00248 "3, 4, 1, 4", "5, 3, 1, 3", "5, 3, 1, 3, 1, 3, 1, 3", "5, 5",
00249 "5, 3, 1, 3, 1, 3", "20, 5", "20, 10, 1, 10", "1, 2");
00250
00251
00252 JSROOT.Painter.root_markers = new Array('fcircle', 'fcircle', 'fcross',
00253 'dcross', 'ocircle', 'gcross', 'fcircle', 'fcircle', 'fcircle',
00254 'fcircle', 'fcircle', 'fcircle', 'fcircle', 'fcircle', 'fcircle',
00255 'fcircle', 'fcircle', 'fcircle', 'fcircle', 'fcircle', 'fcircle',
00256 'fsquare', 'ftriangle-up', 'ftriangle-down', 'ocircle', 'osquare',
00257 'otriangle-up', 'odiamond', 'ocross', 'fstar', 'ostar', 'dcross',
00258 'otriangle-down', 'fdiamond', 'fcross');
00259
00261 JSROOT.Painter.createAttMarker = function(attmarker) {
00262
00263 var marker_name = JSROOT.Painter.root_markers[attmarker['fMarkerStyle']];
00264
00265 var info = { shape: 0, toFill: true, toRotate: false };
00266
00267 if (typeof (marker_name) != 'undefined') {
00268 switch (marker_name.charAt(0)) {
00269 case 'd': info.shape = 7; break;
00270 case 'o': info.toFill = false; break;
00271 case 'g': info.toRotate = true; break;
00272 }
00273
00274 switch (marker_name.substr(1)) {
00275 case "circle": info.shape = 0; break;
00276 case "cross": info.shape = 1; break;
00277 case "diamond": info.shape = 2; break;
00278 case "square": info.shape = 3; break;
00279 case "triangle-up": info.shape = 4; break;
00280 case "triangle-down": info.shape = 5; break;
00281 case "star": info.shape = 6; break;
00282 }
00283 }
00284
00285 var markerSize = attmarker['fMarkerSize'];
00286
00287 var markerScale = (info.shape == 0) ? 32 : 64;
00288 if (attmarker['fMarkerStyle'] == 1) markerScale = 1;
00289
00290 var marker_color = JSROOT.Painter.root_colors[attmarker['fMarkerColor']];
00291
00292 var res = { stroke: marker_color, fill: marker_color, marker: "" };
00293 if (!info.toFill) res['fill'] = 'none';
00294
00295 if (info.shape==6)
00296 res['marker'] = "M " + (-4*markerSize) + " " + (-1*markerSize) +
00297 " L " + 4*markerSize + " " + (-1*markerSize) +
00298 " L " + (-2.4*markerSize) + " " + 4*markerSize +
00299 " L 0 " + (-4*markerSize) +
00300 " L " + 2.8*markerSize + " " + 4*markerSize + " z";
00301 else
00302 if (info.shape==7)
00303 res['marker'] = "M " + (-4*markerSize) + " " + (-4*markerSize) +
00304 " L " + 4*markerSize + " " + 4*markerSize +
00305 " M 0 " + (-4*markerSize) + " 0 " + 4*markerSize +
00306 " M " + 4*markerSize + " " + (-4*markerSize) +
00307 " L " + (-4*markerSize) + " " + 4*markerSize +
00308 " M " + (-4*markerSize) + " 0 L " + 4*markerSize + " 0";
00309 else
00310 res['marker'] = d3.svg.symbol().type(d3.svg.symbolTypes[info.shape]).size(markerSize * markerScale);
00311
00312 res.SetMarker = function(selection) {
00313 selection.style("fill", this.fill)
00314 selection.style("stroke", this.stroke)
00315 selection.attr("d", this.marker);
00316
00317 }
00318 res.func = res.SetMarker.bind(res);
00319
00320 return res;
00321 }
00322
00323 JSROOT.Painter.createAttLine = function(attline, borderw) {
00324
00325 var color = 0, _width = 0, style = 0;
00326
00327 if (attline=='black') { color = 1; _width = 1; } else
00328 if (attline=='none') { _width = 0; } else
00329 if (typeof attline == 'object') {
00330 if ('fLineColor' in attline) color = attline['fLineColor'];
00331 if ('fLineWidth' in attline) _width = attline['fLineWidth'];
00332 if ('fLineStyle' in attline) style = attline['fLineStyle'];
00333 }
00334 if (borderw!=null) _width = borderw;
00335
00336 var line = {
00337 color: JSROOT.Painter.root_colors[color],
00338 width: _width,
00339 dash: JSROOT.Painter.root_line_styles[style]
00340 };
00341
00342 if ((_width==0) || (color==0)) line.color = 'none';
00343
00344 line.SetLine = function(selection) {
00345 selection.style('stroke', this.color);
00346 if (this.color!='none') {
00347 selection.style('stroke-width', this.width);
00348 selection.style('stroke-dasharray', this.dash);
00349 }
00350 }
00351 line.func = line.SetLine.bind(line);
00352
00353 return line;
00354 }
00355
00356
00357 JSROOT.Painter.clearCuts = function(chopt) {
00358
00359 var left = chopt.indexOf('[');
00360 var right = chopt.indexOf(']');
00361 if ((left>=0) && (right>=0) && (left<right))
00362 for (var i = left; i <= right; i++) chopt[i] = ' ';
00363 return chopt;
00364 }
00365
00366 JSROOT.Painter.root_fonts = new Array('Arial', 'Times New Roman',
00367 'bold Times New Roman', 'bold italic Times New Roman', 'Arial',
00368 'oblique Arial', 'bold Arial', 'bold oblique Arial', 'Courier New',
00369 'oblique Courier New', 'bold Courier New', 'bold oblique Courier New',
00370 'Symbol', 'Times New Roman', 'Wingdings', 'Symbol');
00371
00372 JSROOT.Painter.getFontDetails = function(fontIndex, size) {
00373
00374 var fontName = JSROOT.Painter.root_fonts[Math.floor(fontIndex / 10)];
00375
00376 var res = { name: "Arial", size: 11, weight: null, style: null };
00377
00378 if (size != null) res.size = Math.round(size);
00379
00380 if (fontName == null)
00381 fontName = "";
00382
00383 if (fontName.indexOf("bold") != -1) {
00384 res.weight = "bold";
00385
00386
00387 fontName = fontName.substring(5, fontName.length);
00388 }
00389 if (fontName.charAt(0) == 'i') {
00390 res.style = "italic";
00391 fontName = fontName.substring(7, fontName.length);
00392 } else if (fontName.charAt(0) == 'o') {
00393 res.style = "oblique";
00394 fontName = fontName.substring(8, fontName.length);
00395 }
00396 if (name == 'Symbol') {
00397 res.weight = null;
00398 res.style = null;
00399 }
00400
00401 res.name = fontName;
00402
00403 res.SetFont = function(selection) {
00404 selection.attr("font-family", this.name)
00405 .attr("font-size", this.size)
00406 .attr("xml:space","preserve");
00407 if (this.weight!=null)
00408 selection.attr("font-weight", this.weight);
00409 if (this.style!=null)
00410 selection.attr("font-style", this.style);
00411 }
00412
00413 res.stringWidth = function(svg, line) {
00414
00415 var text = svg.append("svg:text")
00416 .attr("class", "temp_text")
00417 .attr("xml:space","preserve")
00418 .style("opacity", 0)
00419 .text(line);
00420 this.SetFont(text);
00421 var w = text.node().getBBox().width;
00422 text.remove();
00423 return w;
00424 }
00425
00426 res.func = res.SetFont.bind(res);
00427
00428 return res;
00429 }
00430
00431
00432 JSROOT.Painter.padtoX = function(pad, x) {
00433
00434 if (pad['fLogx'] && x < 50)
00435 return Math.exp(2.302585092994 * x);
00436 return x;
00437 }
00438
00439 JSROOT.Painter.moveChildToEnd = function(child) {
00440 if (!child) return;
00441 var prnt = child.node().parentNode;
00442 prnt.removeChild(child.node());
00443 prnt.appendChild(child.node());
00444 }
00445
00446 JSROOT.Painter.ytoPad = function(y, pad) {
00447 if (pad['fLogy']) {
00448 if (y > 0)
00449 y = JSROOT.Math.log10(y);
00450 else
00451 y = pad['fUymin'];
00452 }
00453 return y;
00454 };
00455
00469 JSROOT.Painter.HLStoRGB = function(h, l, s) {
00470 var r, g, b;
00471 if (s < 1e-300) {
00472 r = g = b = l;
00473 } else {
00474 function hue2rgb(p, q, t) {
00475 if (t < 0) t += 1;
00476 if (t > 1) t -= 1;
00477 if (t < 1 / 6) return p + (q - p) * 6 * t;
00478 if (t < 1 / 2) return q;
00479 if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
00480 return p;
00481 }
00482 var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
00483 var p = 2 * l - q;
00484 r = hue2rgb(p, q, h + 1 / 3);
00485 g = hue2rgb(p, q, h);
00486 b = hue2rgb(p, q, h - 1 / 3);
00487 }
00488 return 'rgb(' + Math.round(r * 255) + ', ' + Math.round(g * 255) + ', ' + Math.round(b * 255) + ')';
00489 }
00490
00491 JSROOT.Painter.chooseTimeFormat = function(range, nticks) {
00492 if (nticks < 1) nticks = 1;
00493 var awidth = range / nticks;
00494 var reasformat = 0;
00495
00496
00497
00498 if (awidth >= .5) {
00499 reasformat = 1;
00500
00501 if (awidth >= 30) {
00502 awidth /= 60; reasformat = 2;
00503
00504 if (awidth >= 30) {
00505 awidth /= 60; reasformat = 3;
00506
00507 if (awidth >= 12) {
00508 awidth /= 24; reasformat = 4;
00509
00510 if (awidth >= 15.218425) {
00511 awidth /= 30.43685; reasformat = 5;
00512
00513 if (awidth >= 6) {
00514 awidth /= 12; reasformat = 6;
00515 if (awidth >= 2) {
00516 awidth /= 12; reasformat = 7;
00517 }
00518 }
00519 }
00520 }
00521 }
00522 }
00523 }
00524
00525 switch (reasformat) {
00526 case 0: return "%S";
00527 case 1: return "%Mm%S";
00528 case 2: return "%Hh%M";
00529 case 3: return "%d-%Hh";
00530 case 4: return "%d/%m";
00531 case 5: return "%d/%m/%y";
00532 case 6: return "%d/%m/%y";
00533 case 7: return "%m/%y";
00534 }
00535
00536 return "%Y";
00537 }
00538
00539 JSROOT.Painter.getTimeFormat = function(axis) {
00540 var timeFormat = axis['fTimeFormat'];
00541 var idF = timeFormat.indexOf('%F');
00542 if (idF >= 0)
00543 return timeFormat.substr(0, idF);
00544 return timeFormat;
00545 }
00546
00547 JSROOT.Painter.getTimeOffset = function(axis) {
00548 var timeFormat = axis['fTimeFormat'];
00549
00550 var idF = timeFormat.indexOf('%F');
00551
00552 if (idF >= 0) {
00553 var lnF = timeFormat.length;
00554 var stringtimeoffset = timeFormat.substr(idF + 2, lnF);
00555 for (var i = 0; i < 3; ++i)
00556 stringtimeoffset = stringtimeoffset.replace('-', '/');
00557
00558 if ((stringtimeoffset == "0") || (stringtimeoffset == "")) return 0;
00559
00560 var stimeoffset = new Date(stringtimeoffset);
00561 var timeoffset = stimeoffset.getTime();
00562 var ids = stringtimeoffset.indexOf('s');
00563 if (ids >= 0) {
00564 var lns = stringtimeoffset.length;
00565 var sdp = stringtimeoffset.substr(ids + 1, lns);
00566 var dp = parseFloat(sdp);
00567 timeoffset += dp;
00568 }
00569 return timeoffset;
00570 }
00571
00572 return JSROOT.gStyle['TimeOffset'];
00573 }
00574
00575 JSROOT.Painter.formatExp = function(label) {
00576 var str = label;
00577 if (parseFloat(str) == 1.0) return '1';
00578 if (parseFloat(str) == 10.0) return '10';
00579 var str = str.replace('e+', 'x10@');
00580 var str = str.replace('e-', 'x10@-');
00581 var _val = str.substring(0, str.indexOf('@'));
00582 var _exp = str.substr(str.indexOf('@'));
00583 _val = _val.replace('@', '');
00584 _exp = _exp.replace('@', '');
00585 var u, size = _exp.length;
00586 for (var j = 0; j < size; ++j) {
00587 var u, c = _exp.charAt(j);
00588 if (c == '+') u = '\u207A'; else
00589 if (c == '-') u = '\u207B'; else {
00590 var e = parseInt(c);
00591 if (e == 1) u = String.fromCharCode(0xB9); else
00592 if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e); else
00593 u = String.fromCharCode(0x2070 + e);
00594 }
00595 _exp = _exp.replace(c, u);
00596 }
00597 _val = _val.replace('1x', '');
00598 return _val + _exp;
00599 };
00600
00601 JSROOT.Painter.translateExp = function(str) {
00602 var lstr = str.match(/\^{[0-9]*}/gi);
00603 if (lstr != null) {
00604 var symbol = '';
00605 for (var i = 0; i < lstr.length; ++i) {
00606 symbol = lstr[i].replace(' ', '');
00607 symbol = symbol.replace('^{', '');
00608 symbol = symbol.replace('}', '');
00609 var size = symbol.length;
00610 for (var j = 0; j < size; ++j) {
00611 var c = symbol.charAt(j);
00612 var u, e = parseInt(c);
00613 if (e == 1) u = String.fromCharCode(0xB9);
00614 else if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
00615 else u = String.fromCharCode(0x2070 + e);
00616 symbol = symbol.replace(c, u);
00617 }
00618 str = str.replace(lstr[i], symbol);
00619 }
00620 }
00621 return str;
00622 };
00623
00624 JSROOT.Painter.symbols_map = {
00625
00626 '#alpha' : '\u03B1',
00627 '#beta' : '\u03B2',
00628 '#chi' : '\u03C7',
00629 '#delta' : '\u03B4',
00630 '#varepsilon' : '\u03B5',
00631 '#phi' : '\u03C6',
00632 '#gamma' : '\u03B3',
00633 '#eta' : '\u03B7',
00634 '#iota' : '\u03B9',
00635 '#varphi' : '\u03C6',
00636 '#kappa' : '\u03BA',
00637 '#lambda' : '\u03BB',
00638 '#mu' : '\u03BC',
00639 '#nu' : '\u03BD',
00640 '#omicron' : '\u03BF',
00641 '#pi' : '\u03C0',
00642 '#theta' : '\u03B8',
00643 '#rho' : '\u03C1',
00644 '#sigma' : '\u03C3',
00645 '#tau' : '\u03C4',
00646 '#upsilon' : '\u03C5',
00647 '#varomega' : '\u03D6',
00648 '#omega' : '\u03C9',
00649 '#xi' : '\u03BE',
00650 '#psi' : '\u03C8',
00651 '#zeta' : '\u03B6',
00652 '#Alpha' : '\u0391',
00653 '#Beta' : '\u0392',
00654 '#Chi' : '\u03A7',
00655 '#Delta' : '\u0394',
00656 '#Epsilon' : '\u0395',
00657 '#Phi' : '\u03A6',
00658 '#Gamma' : '\u0393',
00659 '#Eta' : '\u0397',
00660 '#Iota' : '\u0399',
00661 '#vartheta' : '\u03D1',
00662 '#Kappa' : '\u039A',
00663 '#Lambda' : '\u039B',
00664 '#Mu' : '\u039C',
00665 '#Nu' : '\u039D',
00666 '#Omicron' : '\u039F',
00667 '#Pi' : '\u03A0',
00668 '#Theta' : '\u0398',
00669 '#Rho' : '\u03A1',
00670 '#Sigma' : '\u03A3',
00671 '#Tau' : '\u03A4',
00672 '#Upsilon' : '\u03A5',
00673 '#varsigma' : '\u03C2',
00674 '#Omega' : '\u03A9',
00675 '#Xi' : '\u039E',
00676 '#Psi' : '\u03A8',
00677 '#Zeta' : '\u0396',
00678 '#varUpsilon' : '\u03D2',
00679 '#epsilon' : '\u03B5',
00680
00681
00682 '#sqrt' : '\u221A',
00683
00684
00685 '#leq' : '\u2264',
00686 '#/' : '\u2044',
00687 '#infty' : '\u221E',
00688 '#voidb' : '\u0192',
00689 '#club' : '\u2663',
00690 '#diamond' : '\u2666',
00691 '#heart' : '\u2665',
00692 '#spade' : '\u2660',
00693 '#leftrightarrow' : '\u2194',
00694 '#leftarrow' : '\u2190',
00695 '#uparrow' : '\u2191',
00696 '#rightarrow' : '\u2192',
00697 '#downarrow' : '\u2193',
00698 '#circ' : '\u02C6',
00699 '#pm' : '\xB1',
00700 '#doublequote' : '\u2033',
00701 '#geq' : '\u2265',
00702 '#times' : '\xD7',
00703 '#propto' : '\u221D',
00704 '#partial' : '\u2202',
00705 '#bullet' : '\u2022',
00706 '#divide' : '\xF7',
00707 '#neq' : '\u2260',
00708 '#equiv' : '\u2261',
00709 '#approx' : '\u2248',
00710 '#3dots' : '\u2026',
00711 '#cbar' : '\u007C',
00712 '#topbar' : '\xAF',
00713 '#downleftarrow' : '\u21B5',
00714 '#aleph' : '\u2135',
00715 '#Jgothic' : '\u2111',
00716 '#Rgothic' : '\u211C',
00717 '#voidn' : '\u2118',
00718 '#otimes' : '\u2297',
00719 '#oplus' : '\u2295',
00720 '#oslash' : '\u2205',
00721 '#cap' : '\u2229',
00722 '#cup' : '\u222A',
00723 '#supseteq' : '\u2287',
00724 '#supset' : '\u2283',
00725 '#notsubset' : '\u2284',
00726 '#subseteq' : '\u2286',
00727 '#subset' : '\u2282',
00728 '#int' : '\u222B',
00729 '#in' : '\u2208',
00730 '#notin' : '\u2209',
00731 '#angle' : '\u2220',
00732 '#nabla' : '\u2207',
00733 '#oright' : '\xAE',
00734 '#ocopyright' : '\xA9',
00735 '#trademark' : '\u2122',
00736 '#prod' : '\u220F',
00737 '#surd' : '\u221A',
00738 '#upoint' : '\u22C5',
00739 '#corner' : '\xAC',
00740 '#wedge' : '\u2227',
00741 '#vee' : '\u2228',
00742 '#Leftrightarrow' : '\u21D4',
00743 '#Leftarrow' : '\u21D0',
00744 '#Uparrow' : '\u21D1',
00745 '#Rightarrow' : '\u21D2',
00746 '#Downarrow' : '\u21D3',
00747 '#LT' : '\x3C',
00748 '#void1' : '\xAE',
00749 '#copyright' : '\xA9',
00750 '#void3' : '\u2122',
00751 '#sum' : '\u2211',
00752 '#arctop' : '',
00753 '#lbar' : '',
00754 '#arcbottom' : '',
00755 '#void8' : '',
00756 '#bottombar' : '\u230A',
00757 '#arcbar' : '',
00758 '#ltbar' : '',
00759 '#AA' : '\u212B',
00760 '#aa' : '\u00E5',
00761 '#void06' : '',
00762 '#GT' : '\x3E',
00763 '#forall' : '\u2200',
00764 '#exists' : '\u2203',
00765 '#bar' : '',
00766 '#vec' : '',
00767 '#dot' : '\u22C5',
00768 '#hat' : '\xB7',
00769 '#ddot' : '',
00770 '#acute' : '\acute',
00771 '#grave' : '',
00772 '#check' : '\u2713',
00773 '#tilde' : '\u02DC',
00774 '#slash' : '\u2044',
00775 '#hbar' : '\u0127',
00776 '#box' : '',
00777 '#Box' : '',
00778 '#parallel' : '',
00779 '#perp' : '\u22A5',
00780 '#odot' : ''
00781 };
00782
00783 JSROOT.Painter.translateLaTeX = function(string) {
00784 var str = string;
00785 str = this.translateExp(str);
00786 while (str.indexOf('^{o}') != -1)
00787 str = str.replace('^{o}', '\xBA');
00788 var lstr = str.match(/\#sqrt{(.*?)}/gi);
00789 if (lstr != null)
00790 for (var i = 0; i < lstr.length; ++i) {
00791 var symbol = lstr[i].replace(' ', '');
00792 symbol = symbol.replace('#sqrt{', '#sqrt');
00793 symbol = symbol.replace('}', '');
00794 str = str.replace(lstr[i], symbol);
00795 }
00796 lstr = str.match(/\_{(.*?)}/gi);
00797 if (lstr != null)
00798 for (var i = 0; i < lstr.length; ++i) {
00799 var symbol = lstr[i].replace(' ', '');
00800 symbol = symbol.replace('_{', '');
00801 symbol = symbol.replace('}', '');
00802 str = str.replace(lstr[i], symbol);
00803 }
00804 lstr = str.match(/\^{(.*?)}/gi);
00805 if (lstr != null)
00806 for (i = 0; i < lstr.length; ++i) {
00807 var symbol = lstr[i].replace(' ', '');
00808 symbol = symbol.replace('^{', '');
00809 symbol = symbol.replace('}', '');
00810 str = str.replace(lstr[i], symbol);
00811 }
00812 while (str.indexOf('#/') != -1)
00813 str = str.replace('#/', JSROOT.Painter.symbols_map['#/']);
00814 for ( var x in JSROOT.Painter.symbols_map) {
00815 while (str.indexOf(x) != -1)
00816 str = str.replace(x, JSROOT.Painter.symbols_map[x]);
00817 }
00818 return str;
00819 }
00820
00821
00822
00823 JSROOT.TBasePainter = function() {
00824 }
00825
00826 JSROOT.TBasePainter.prototype.Cleanup = function() {
00827
00828 }
00829
00830 JSROOT.TBasePainter.prototype.GetObject = function() {
00831 return null;
00832 }
00833
00834 JSROOT.TBasePainter.prototype.UpdateObject = function(obj) {
00835 return false;
00836 }
00837
00838 JSROOT.TBasePainter.prototype.RedrawPad = function(resize) {
00839 }
00840
00841 JSROOT.TBasePainter.prototype.RedrawObject = function(obj) {
00842 if (this.UpdateObject(obj)) {
00843 var current = document.body.style.cursor;
00844 document.body.style.cursor = 'wait';
00845 this.RedrawPad();
00846 document.body.style.cursor = current;
00847 }
00848 }
00849
00850 JSROOT.TBasePainter.prototype.CheckResize = function(force) {
00851 }
00852
00853 JSROOT.TBasePainter.prototype.SetDivId = function(divid) {
00854
00855
00856
00857 this['divid'] = divid;
00858
00859 $("#" + divid).children().eq(0).prop('painter', this);
00860 }
00861
00862
00863
00864 JSROOT.TObjectPainter = function(obj) {
00865 JSROOT.TBasePainter.call(this);
00866 this.obj_typename = (obj!=null) && ('_typename' in obj) ? obj['_typename'] : "";
00867 this.draw_g = null;
00868 this.pad_name = "";
00869 this.main = null;
00870 }
00871
00872 JSROOT.TObjectPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
00873
00874 JSROOT.TObjectPainter.prototype.CheckResize = function(force) {
00875
00876 var can = this.svg_canvas();
00877
00878 var pad_painter = can ? can['pad_painter'] : null;
00879
00880 if (pad_painter) pad_painter.CheckCanvasResize();
00881 }
00882
00883 JSROOT.TObjectPainter.prototype.RemoveDrawG = function() {
00884
00885
00886
00887 if (this.draw_g != null) {
00888 this.draw_g.remove();
00889 this.draw_g = null;
00890 }
00891 }
00892
00893 JSROOT.TObjectPainter.prototype.RecreateDrawG = function(take_pad, layer) {
00894
00895
00896 if (this.draw_g)
00897 this.draw_g.selectAll("*").remove();
00898
00899 if (take_pad) {
00900 if (layer==null) layer = ".text_layer"
00901 if (!this.draw_g)
00902 this.draw_g = this.svg_pad(true).select(layer).append("svg:g");
00903 } else {
00904 var frame = this.svg_frame(true);
00905
00906 var w = frame.attr("width");
00907 var h = frame.attr("height");
00908
00909 if (!this.draw_g) {
00910 if (layer==null) layer = ".main_layer";
00911 this.draw_g = frame.select(layer).append("svg");
00912 }
00913
00914 this.draw_g.attr("x", 0)
00915 .attr("y", 0)
00916 .attr("width",w)
00917 .attr("height", h)
00918 .attr("viewBox", "0 0 " + w + " " + h)
00919 .attr('overflow', 'hidden');
00920 }
00921 }
00922
00924 JSROOT.TObjectPainter.prototype.svg_canvas = function(asselect) {
00925 var res = d3.select("#" + this.divid + " .root_canvas");
00926 return asselect ? res : res.node();
00927 }
00928
00930 JSROOT.TObjectPainter.prototype.svg_pad = function(asselect) {
00931 var c = this.svg_canvas(true);
00932 if (this.pad_name != '')
00933 c = c.select("[pad=" + this.pad_name + ']');
00934 return asselect ? c : c.node();
00935 }
00936
00937 JSROOT.TObjectPainter.prototype.root_pad = function() {
00938 var p = this.svg_pad();
00939 var pad_painter = p ? p['pad_painter'] : null;
00940 return pad_painter ? pad_painter.pad : null;
00941 }
00942
00944 JSROOT.TObjectPainter.prototype.svg_frame = function(asselect) {
00945 var f = this.svg_pad(true).select(".root_frame");
00946 return asselect ? f : f.node();
00947 }
00948
00950 JSROOT.TObjectPainter.prototype.main_painter = function() {
00951 if (!this.main) {
00952 var svg_p = this.svg_pad();
00953 if (svg_p) this.main = svg_p['mainpainter'];
00954 }
00955 return this.main;
00956 }
00957
00958 JSROOT.TObjectPainter.prototype.is_main_painter = function() {
00959 return this == this.main_painter();
00960 }
00961
00962 JSROOT.TObjectPainter.prototype.SetDivId = function(divid, is_main) {
00963
00964
00965
00966
00967
00968
00969
00970 this['divid'] = divid;
00971
00972 if (is_main == null) is_main = 0;
00973
00974 this['create_canvas'] = false;
00975
00976
00977 var svg_c = this.svg_canvas();
00978
00979 if ((svg_c==null) && (is_main>0)) {
00980 JSROOT.Painter.drawCanvas(divid, null);
00981 svg_c = this.svg_canvas();
00982 this['create_canvas'] = true;
00983 }
00984
00985 if (svg_c == null) {
00986 if ((is_main < 0) || (this.obj_typename=="TCanvas")) return;
00987
00988 console.log("Special case for " + this.obj_typename + " assign painter to first DOM element");
00989 $("#" + divid).children().eq(0).prop('painter', this);
00990 return;
00991 }
00992
00993
00994 this.pad_name = svg_c['current_pad'];
00995
00996 if (is_main < 0) return;
00997
00998
00999 if ((is_main > 0) && (this.svg_frame()==null)) {
01000 JSROOT.Painter.drawFrame(divid, null);
01001 if (this.svg_frame()==null) return alert("Fail to draw dummy TFrame");
01002 this['create_canvas'] = true;
01003 }
01004
01005 var svg_p = this.svg_pad();
01006 if (svg_p['pad_painter'] != this)
01007 svg_p['pad_painter'].painters.push(this);
01008
01009 if ((is_main > 0) && (svg_p['mainpainter']==null))
01010
01011 svg_p['mainpainter'] = this;
01012 }
01013
01014 JSROOT.TObjectPainter.prototype.createAttFill = function(attfill, pattern, color) {
01015
01016 if ((pattern==null) && attfill) pattern = attfill['fFillStyle'];
01017 if ((color==null) && attfill) color = attfill['fFillColor'];
01018
01019 var fill = { color: "none" };
01020 fill.SetFill = function(selection) {
01021 selection.style('fill', this.color);
01022 if ('antialias' in this)
01023 selection.style('antialias', this.antialias);
01024 }
01025 fill.func = fill.SetFill.bind(fill);
01026
01027 if (typeof attfill == 'string') {
01028 fill.color = attfill;
01029 return fill;
01030 }
01031
01032 if ((pattern < 1001) || ((pattern >= 4000) && (pattern <= 4100))) return fill;
01033
01034 fill.color = JSROOT.Painter.root_colors[color];
01035 if (typeof fill.color != 'string') fill.color = "none";
01036
01037 var svg = this.svg_canvas(true);
01038
01039 if ((pattern < 3000) || (pattern>3025) || svg.empty()) return fill;
01040
01041 var id = "pat_" + pattern + "_" + color;
01042
01043 fill.color = "url(#" + id + ")";
01044 fill.antialias = false;
01045
01046 if (document.getElementById(id) != null) return fill;
01047
01048 var line_color = JSROOT.Painter.root_colors[color];
01049
01050 switch (pattern) {
01051 case 3001:
01052 svg.append('svg:pattern')
01053 .attr("id", id).attr("patternUnits","userSpaceOnUse")
01054 .attr("width", "3px").attr("height", "2px").style("stroke", line_color)
01055 .append('svg:rect')
01056 .attr("x", 0).attr("y", 0).attr("width", 1).attr("height", 1).style("stroke",line_color)
01057 .append('svg:rect')
01058 .attr("x", 2).attr("y", 0).attr("width", 1).attr("height", 1).style("stroke", line_color)
01059 .append('svg:rect')
01060 .attr("x", 1).attr("y", 1).attr("width", 1).attr("height", 1).style("stroke", line_color);
01061 break;
01062 case 3002:
01063 svg.append('svg:pattern')
01064 .attr("id", id).attr("patternUnits", "userSpaceOnUse")
01065 .attr("width", "4px").attr("height", "2px").style("stroke", line_color)
01066 .append('svg:rect')
01067 .attr("x", 1).attr("y", 0).attr("width", 1).attr("height", 1).style("stroke", line_color)
01068 .append('svg:rect')
01069 .attr("x", 3).attr("y", 1).attr("width", 1).attr("height", 1).style("stroke", line_color);
01070 break;
01071 case 3003:
01072 svg.append('svg:pattern')
01073 .attr("id", id).attr("patternUnits", "userSpaceOnUse")
01074 .attr("width", "4px").attr("height", "4px").style("stroke", line_color)
01075 .append('svg:rect')
01076 .attr("x", 2).attr("y", 1).attr("width", 1).attr("height", 1).style("stroke", line_color)
01077 .append('svg:rect')
01078 .attr("x", 0).attr("y", 3).attr("width", 1).attr("height", 1).style("stroke", line_color);
01079 break;
01080 case 3004:
01081 svg.append('svg:pattern')
01082 .attr("id", id).attr("patternUnits", "userSpaceOnUse")
01083 .attr("width", "8px").attr("height", "8px").style("stroke", line_color)
01084 .append("svg:line")
01085 .attr("x1", 8).attr("y1", 0).attr("x2", 0).attr("y2", 8)
01086 .style("stroke",line_color).style("stroke-width", 1);
01087 break;
01088 case 3005:
01089 svg.append('svg:pattern')
01090 .attr("id", id).attr("patternUnits", "userSpaceOnUse")
01091 .attr("width", "8px").attr("height", "8px").style("stroke", line_color)
01092 .append("svg:line")
01093 .attr("x1", 0).attr("y1", 0).attr("x2", 8).attr("y2", 8)
01094 .style("stroke",line_color).style("stroke-width", 1);
01095 break;
01096 case 3006:
01097 svg.append('svg:pattern')
01098 .attr("id", id).attr("patternUnits", "userSpaceOnUse")
01099 .attr("width", "4px").attr("height", "4px").style("stroke", line_color)
01100 .append("svg:line")
01101 .attr("x1", 1).attr("y1", 0).attr("x2", 1).attr("y2", 3)
01102 .style("stroke",line_color).style("stroke-width", 1);
01103 break;
01104 case 3007:
01105 svg.append('svg:pattern')
01106 .attr("id", id).attr("patternUnits","userSpaceOnUse")
01107 .attr("width", "4px").attr("height", "4px").style("stroke", line_color)
01108 .append("svg:line")
01109 .attr("x1", 0).attr("y1", 1).attr("x2", 3).attr("y2", 1)
01110 .style("stroke",line_color).style("stroke-width", 1);
01111 break;
01112 default:
01113 svg.append('svg:pattern')
01114 .attr("id", id).attr("patternUnits","userSpaceOnUse")
01115 .attr("width", "8px").attr("height", "8px").style("stroke", line_color)
01116 .append("svg:line")
01117 .attr("x1", 8).attr("y1", 0).attr("x2", 0).attr("y2", 8)
01118 .style("stroke",line_color).style("stroke-width", 1);
01119 break;
01120 }
01121
01122 return fill;
01123 }
01124
01125
01126 JSROOT.TObjectPainter.prototype.ForEachPainter = function(userfunc) {
01127
01128 var svg_c = this.svg_canvas();
01129 if (svg_c!=null) {
01130 userfunc(svg_c['pad_painter']);
01131 var painters = svg_c['pad_painter'].painters;
01132 for (var k in painters) userfunc(painters[k]);
01133 } else {
01134 var painter = $("#" + this.divid).children().eq(0).prop('painter');
01135 if (painter!=null) userfunc(painter);
01136 }
01137 }
01138
01139 JSROOT.TObjectPainter.prototype.Cleanup = function() {
01140
01141 $("#" + this.divid).empty();
01142 }
01143
01144 JSROOT.TObjectPainter.prototype.RedrawPad = function(resize) {
01145
01146
01147
01148 var pad = this.svg_pad();
01149
01150 var pad_painter = pad ? pad['pad_painter'] : null;
01151
01152 if (pad_painter) pad_painter.Redraw(true);
01153 }
01154
01155 JSROOT.TObjectPainter.prototype.RemoveDrag = function(id) {
01156 var drag_rect_name = id + "_drag_rect";
01157 var resize_rect_name = id + "_resize_rect";
01158 if (this[drag_rect_name]) {
01159 this[drag_rect_name].remove();
01160 this[drag_rect_name] = null;
01161 }
01162 if (this[resize_rect_name]) {
01163 this[resize_rect_name].remove();
01164 this[resize_rect_name] = null;
01165 }
01166 }
01167
01168 JSROOT.TObjectPainter.prototype.AddDrag = function(id, draw_g, callback) {
01169 if (!JSROOT.gStyle.MoveResize) return;
01170
01171 var pthis = this;
01172
01173 var drag_rect_name = id + "_drag_rect";
01174 var resize_rect_name = id + "_resize_rect";
01175
01176 var rect_width = function() { return Number(draw_g.attr("width")); }
01177 var rect_height = function() { return Number(draw_g.attr("height")); }
01178
01179 var acc_x = 0, acc_y = 0, pad_w = 1, pad_h = 1;
01180
01181 var drag_move = d3.behavior.drag().origin(Object)
01182 .on("dragstart", function() {
01183 d3.event.sourceEvent.preventDefault();
01184
01185 acc_x = 0; acc_y = 0;
01186 pad_w = Number(pthis.svg_pad(true).attr("width")) - rect_width();
01187 pad_h = Number(pthis.svg_pad(true).attr("height")) - rect_height();
01188
01189 pthis[drag_rect_name] =
01190 pthis.svg_pad(true)
01191 .append("rect")
01192 .attr("class", "zoom")
01193 .attr("id", drag_rect_name)
01194 .attr("x", draw_g.attr("x"))
01195 .attr("y", draw_g.attr("y"))
01196 .attr("width", rect_width())
01197 .attr("height", rect_height())
01198 .style("cursor", "move");
01199 }).on("drag", function() {
01200 d3.event.sourceEvent.preventDefault();
01201
01202 var x = Number(pthis[drag_rect_name].attr("x"));
01203 var y = Number(pthis[drag_rect_name].attr("y"));
01204 var dx = d3.event.dx, dy = d3.event.dy;
01205
01206 if (((acc_x<0) && (dx>0)) || ((acc_x>0) && (dx<0))) { acc_x += dx; dx = 0; }
01207 if (((acc_y<0) && (dy>0)) || ((acc_y>0) && (dy<0))) { acc_y += dy; dy = 0; }
01208
01209 if ((x + dx < 0) || (x +dx > pad_w)) acc_x += dx; else x+=dx;
01210 if ((y+dy < 0) || (y+dy > pad_h)) acc_y += dy; else y += dy;
01211
01212 pthis[drag_rect_name].attr("x", x);
01213 pthis[drag_rect_name].attr("y", y);
01214
01215 JSROOT.Painter.moveChildToEnd(pthis[drag_rect_name]);
01216
01217 d3.event.sourceEvent.stopPropagation();
01218 }).on("dragend", function() {
01219 d3.event.sourceEvent.preventDefault();
01220
01221 pthis[drag_rect_name].style("cursor", "auto");
01222
01223 var x = Number(pthis[drag_rect_name].attr("x"));
01224 var y = Number(pthis[drag_rect_name].attr("y"));
01225
01226 var dx = x - Number(draw_g.attr("x"));
01227 var dy = y - Number(draw_g.attr("y"));
01228
01229 pthis[drag_rect_name].remove();
01230 pthis[drag_rect_name] = null;
01231
01232 draw_g.attr("x", x).attr("y", y);
01233
01234 callback.move(x, y, dx, dy);
01235
01236 pthis[resize_rect_name]
01237 .attr("x", rect_width() - 20)
01238 .attr("y", rect_height() - 20);
01239 });
01240
01241 var drag_resize = d3.behavior.drag().origin(Object)
01242 .on( "dragstart", function() {
01243 d3.event.sourceEvent.stopPropagation();
01244 d3.event.sourceEvent.preventDefault();
01245
01246 acc_x = 0; acc_y = 0;
01247 pad_w = Number(pthis.svg_pad(true).attr("width")) - Number(draw_g.attr("x"));
01248 pad_h = Number(pthis.svg_pad(true).attr("height")) - Number(draw_g.attr("y"));
01249 pthis[drag_rect_name] =
01250 pthis.svg_pad(true)
01251 .append("rect")
01252 .attr("class", "zoom")
01253 .attr("id", drag_rect_name)
01254 .attr("x", draw_g.attr("x"))
01255 .attr("y", draw_g.attr("y"))
01256 .attr("width", rect_width())
01257 .attr("height", rect_height())
01258 .style("cursor", "se-resize");
01259 }).on("drag", function() {
01260 d3.event.sourceEvent.preventDefault();
01261
01262 var w = Number(pthis[drag_rect_name].attr("width"));
01263 var h = Number(pthis[drag_rect_name].attr("height"));
01264 var dx = d3.event.dx, dy = d3.event.dy;
01265 if ((acc_x>0) && (dx<0)) { acc_x += dx; dx = 0; }
01266 if ((acc_y>0) && (dy<0)) { acc_y += dy; dy = 0; }
01267 if (w+dx > pad_w) acc_x += dx; else w+=dx;
01268 if (h+dy > pad_h) acc_y += dy; else h+=dy;
01269 pthis[drag_rect_name].attr("width", w);
01270 pthis[drag_rect_name].attr("height", h);
01271
01272 JSROOT.Painter.moveChildToEnd(pthis[drag_rect_name]);
01273
01274 d3.event.sourceEvent.stopPropagation();
01275 }).on( "dragend", function() {
01276 d3.event.sourceEvent.preventDefault();
01277 pthis[drag_rect_name].style("cursor", "auto");
01278
01279 var newwidth = Number(pthis[drag_rect_name].attr("width"));
01280 var newheight = Number(pthis[drag_rect_name].attr("height"));
01281
01282 draw_g.attr('width', newwidth).attr('height', newheight);
01283
01284 pthis[drag_rect_name].remove();
01285 pthis[drag_rect_name] = null;
01286
01287 callback.resize(newwidth, newheight);
01288
01289
01290 pthis[resize_rect_name]
01291 .attr("x", newwidth - 20)
01292 .attr("y", newheight - 20);
01293 });
01294
01295 draw_g.call(drag_move);
01296
01297 this[resize_rect_name] =
01298 draw_g.append("rect")
01299 .attr("class", resize_rect_name)
01300 .style("opacity", "0")
01301 .style("cursor", "se-resize")
01302 .attr("x", rect_width() - 20)
01303 .attr("y", rect_height() - 20)
01304 .attr("width", 20)
01305 .attr("height", 20)
01306 .call(drag_resize);
01307 }
01308
01309 JSROOT.TObjectPainter.prototype.FindPainterFor = function(selobj,selname) {
01310
01311
01312
01313
01314 var painters = this.svg_pad() ? this.svg_pad().pad_painter.painters : null;
01315 if (painters == null) return null;
01316
01317 for (var n in painters) {
01318 var pobj = painters[n].GetObject();
01319 if (pobj==null) continue;
01320
01321 if (selobj && (pobj === selobj)) return painters[n];
01322
01323 if (selname && ('fName' in pobj) && (pobj['fName']==selname)) return painters[n];
01324 }
01325
01326 return null;
01327 }
01328
01329 JSROOT.TObjectPainter.prototype.Redraw = function() {
01330
01331
01332
01333 }
01334
01335
01336
01337 JSROOT.TFramePainter = function(tframe) {
01338 JSROOT.TObjectPainter.call(this, tframe);
01339 this.tframe = tframe;
01340 }
01341
01342 JSROOT.TFramePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
01343
01344 JSROOT.TFramePainter.prototype.GetObject = function() {
01345 return this.tframe;
01346 }
01347
01348 JSROOT.TFramePainter.prototype.Shrink = function(shrink_left, shrink_right) {
01349 var ndc = this.svg_frame() ? this.svg_frame()['NDC'] : null;
01350 if (ndc) {
01351 ndc.x1 += shrink_left;
01352 ndc.x2 -= shrink_right;
01353 }
01354 }
01355
01356 JSROOT.TFramePainter.prototype.DrawFrameSvg = function() {
01357 var width = Number(this.svg_pad(true).attr("width")),
01358 height = Number(this.svg_pad(true).attr("height"));
01359 var w = width, h = height;
01360
01361 var ndc = this.svg_frame() ? this.svg_frame()['NDC'] : null;
01362 if (ndc == null) ndc = { x1 : 0.07, y1 : 0.12, x2 : 0.95, y2 : 0.88 };
01363
01364 var root_pad = this.root_pad();
01365
01366 var lm = width * ndc.x1;
01367 var rm = width * (1 - ndc.x2);
01368 var tm = height * ndc.y1;
01369 var bm = height * (1 - ndc.y2);
01370
01371 var framecolor = this.createAttFill('white'),
01372 lineatt = JSROOT.Painter.createAttLine('black'),
01373 bordermode = 0, bordersize = 0;
01374
01375 if (this.tframe) {
01376 bordermode = this.tframe['fBorderMode'];
01377 bordersize = this.tframe['fBorderSize'];
01378 lineatt = JSROOT.Painter.createAttLine(this.tframe);
01379 if (root_pad) {
01380 var xspan = width / Math.abs(root_pad['fX2'] - root_pad['fX1']);
01381 var yspan = height / Math.abs(root_pad['fY2'] - root_pad['fY1']);
01382 var px1 = (this.tframe['fX1'] - root_pad['fX1']) * xspan;
01383 var py1 = (this.tframe['fY1'] - root_pad['fY1']) * yspan;
01384 var px2 = (this.tframe['fX2'] - root_pad['fX1']) * xspan;
01385 var py2 = (this.tframe['fY2'] - root_pad['fY1']) * yspan;
01386 var pxl, pxt, pyl, pyt;
01387 if (px1 < px2) { pxl = px1; pxt = px2; }
01388 else { pxl = px2; pxt = px1; }
01389 if (py1 < py2) { pyl = py1; pyt = py2; }
01390 else { pyl = py2; pyt = py1; }
01391 lm = pxl;
01392 bm = pyl;
01393 w = pxt - pxl;
01394 h = pyt - pyl;
01395 tm = height - pyt;
01396 rm = width - pxt;
01397 } else {
01398 lm = this.tframe['fX1'] * width;
01399 tm = this.tframe['fY1'] * height;
01400 bm = (1.0 - this.tframe['fY2']) * height;
01401 rm = (1.0 - this.tframe['fX2'] + shrink_right) * width;
01402 w -= (lm + rm);
01403 h -= (tm + bm);
01404 }
01405 framecolor = this.createAttFill(this.tframe);
01406 } else {
01407 if (root_pad) {
01408 framecolor = this.createAttFill(null, root_pad['fFrameFillStyle'], root_pad['fFrameFillColor']);
01409 }
01410 w -= (lm + rm);
01411 h -= (tm + bm);
01412 }
01413
01414
01415 if (framecolor.color == 'none') framecolor.color = 'white';
01416
01417
01418 var frame_g = this.svg_pad(true).select(".root_frame");
01419
01420 var top_rect = null;
01421
01422 if (frame_g.empty()) {
01423 frame_g = this.svg_pad(true).select(".frame_layer").append("svg:g").attr("class", "root_frame");
01424
01425 top_rect = frame_g.append("svg:rect");
01426
01427
01428 frame_g.append('svg:g').attr('class','grid_layer');
01429 frame_g.append('svg:g').attr('class','main_layer');
01430 frame_g.append('svg:g').attr('class','axis_layer');
01431 } else {
01432 top_rect = frame_g.select("rect");
01433 }
01434
01435
01436 frame_g.node()['NDC'] = {
01437 x1 : lm / width,
01438 x2 : (lm + w) / width,
01439 y1 : tm / height,
01440 y2 : (tm + h) / height
01441 };
01442
01443
01444 frame_g.node()['frame_painter'] = this;
01445
01446 lm = Math.round(lm); tm = Math.round(tm);
01447 w = Math.round(w); h = Math.round(h);
01448
01449 frame_g.attr("x", lm)
01450 .attr("y", tm)
01451 .attr("width", w)
01452 .attr("height", h)
01453 .attr("transform", "translate(" + lm + "," + tm + ")");
01454
01455 top_rect.attr("x", 0)
01456 .attr("y", 0)
01457 .attr("width", w)
01458 .attr("height", h)
01459 .call(framecolor.func)
01460 .call(lineatt.func);
01461 }
01462
01463 JSROOT.TFramePainter.prototype.Redraw = function() {
01464 this.DrawFrameSvg();
01465 }
01466
01467 JSROOT.Painter.drawFrame = function(divid, obj) {
01468 var p = new JSROOT.TFramePainter(obj);
01469 p.SetDivId(divid);
01470 p.DrawFrameSvg();
01471 return p;
01472 }
01473
01474
01475
01476 JSROOT.TF1Painter = function(tf1) {
01477 JSROOT.TObjectPainter.call(this, tf1);
01478 this.tf1 = tf1;
01479 }
01480
01481 JSROOT.TF1Painter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
01482
01483 JSROOT.TF1Painter.prototype.GetObject = function() {
01484 return this.tf1;
01485 }
01486
01487 JSROOT.TF1Painter.prototype.Redraw = function() {
01488 this.DrawBins();
01489 }
01490
01491 JSROOT.TF1Painter.prototype.Eval = function(x) {
01492 return this.tf1.evalPar(x);
01493 }
01494
01495 JSROOT.TF1Painter.prototype.CreateDummyHisto = function() {
01496 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
01497 if (this.tf1['fNsave'] > 0) {
01498
01499
01500 var nb_points = this.tf1['fNpx'];
01501 for (var i = 0; i < nb_points; ++i) {
01502 var h = this.tf1['fSave'][i];
01503 if ((i == 0) || (h > ymax))
01504 ymax = h;
01505 if ((i == 0) || (h < ymin))
01506 ymin = h;
01507 }
01508 xmin = this.tf1['fSave'][nb_points + 1];
01509 xmax = this.tf1['fSave'][nb_points + 2];
01510 } else {
01511
01512
01513 if (this.tf1['fNpfits'] <= 103)
01514 this.tf1['fNpfits'] = 103;
01515 xmin = this.tf1['fXmin'];
01516 xmax = this.tf1['fXmax'];
01517
01518 var nb_points = Math.max(this.tf1['fNpx'], this.tf1['fNpfits']);
01519
01520 var binwidthx = (xmax - xmin) / nb_points;
01521 var left = -1, right = -1;
01522 for (var i = 0; i < nb_points; ++i) {
01523 var h = this.Eval(xmin + (i * binwidthx));
01524 if (isNaN(h)) continue;
01525
01526 if (left < 0) {
01527 left = i;
01528 ymax = h;
01529 ymin = h;
01530 }
01531 if ((right < 0) || (right == i - 1))
01532 right = i;
01533
01534 if (h > ymax)
01535 ymax = h;
01536 if (h < ymin)
01537 ymin = h;
01538 }
01539
01540 if (left < right) {
01541 xmax = xmin + right * binwidthx;
01542 xmin = xmin + left * binwidthx;
01543 }
01544 }
01545
01546 if (ymax > 0.0) ymax *= 1.05;
01547 if (ymin < 0.0) ymin *= 1.05;
01548
01549 var histo = JSROOT.Create("TH1I");
01550
01551 histo['fName'] = this.tf1['fName'] + "_hist";
01552 histo['fTitle'] = this.tf1['fTitle'];
01553
01554 histo['fXaxis']['fXmin'] = xmin;
01555 histo['fXaxis']['fXmax'] = xmax;
01556 histo['fYaxis']['fXmin'] = ymin;
01557 histo['fYaxis']['fXmax'] = ymax;
01558
01559 return histo;
01560 }
01561
01562 JSROOT.TF1Painter.prototype.CreateBins = function() {
01563
01564 var pthis = this;
01565
01566 if (this.tf1['fNsave'] > 0) {
01567
01568
01569 var nb_points = this.tf1['fNpx'];
01570
01571 var xmin = this.tf1['fSave'][nb_points + 1];
01572 var xmax = this.tf1['fSave'][nb_points + 2];
01573 var binwidthx = (xmax - xmin) / nb_points;
01574
01575 this['bins'] = d3.range(nb_points).map(function(p) {
01576 return {
01577 x : xmin + (p * binwidthx),
01578 y : pthis.tf1['fSave'][p]
01579 };
01580 });
01581 this['interpolate_method'] = 'monotone';
01582 } else {
01583 if (this.tf1['fNpfits'] <= 103)
01584 this.tf1['fNpfits'] = 333;
01585 var xmin = this.tf1['fXmin'];
01586 var xmax = this.tf1['fXmax'];
01587 var nb_points = Math.max(this.tf1['fNpx'], this.tf1['fNpfits']);
01588 var binwidthx = (xmax - xmin) / nb_points;
01589 this['bins'] = d3.range(nb_points).map(function(p) {
01590 var xx = xmin + (p * binwidthx);
01591 var yy = pthis.Eval(xx);
01592 if (isNaN(yy)) yy = 0;
01593 return {
01594 x : xx,
01595 y : yy
01596 };
01597 });
01598 this['interpolate_method'] = 'cardinal-open';
01599 }
01600 }
01601
01602 JSROOT.TF1Painter.prototype.DrawBins = function() {
01603 var w = Number(this.svg_frame(true).attr("width")),
01604 h = Number(this.svg_frame(true).attr("height"));
01605
01606 this.RecreateDrawG();
01607
01608 var pthis = this;
01609 var x = this.main_painter().x;
01610 var y = this.main_painter().y;
01611
01612 var attline = JSROOT.Painter.createAttLine(this.tf1);
01613 var fill = this.createAttFill(this.tf1);
01614 if (fill.color == 'white') fill.color = 'none';
01615
01616 var line = d3.svg.line()
01617 .x(function(d) { return x(d.x).toFixed(1); })
01618 .y(function(d) { return y(d.y).toFixed(1); })
01619 .interpolate(this.interpolate_method);
01620
01621 var area = d3.svg.area()
01622 .x(function(d) { return x(d.x).toFixed(1); })
01623 .y1(h)
01624 .y0(function(d) { return y(d.y).toFixed(1); });
01625
01626 if (attline.color != "none")
01627 this.draw_g.append("svg:path")
01628 .attr("class", "line")
01629 .attr("d",line(pthis.bins))
01630 .style("fill", "none")
01631 .call(attline.func);
01632
01633 if (fill.color != "none")
01634 this.draw_g.append("svg:path")
01635 .attr("class", "area")
01636 .attr("d",area(pthis.bins))
01637 .style("stroke", "none")
01638 .call(fill.func);
01639
01640
01641 if (JSROOT.gStyle.Tooltip)
01642 this.draw_g.selectAll()
01643 .data(this.bins).enter()
01644 .append("svg:circle")
01645 .attr("cx", function(d) { return x(d.x).toFixed(1); })
01646 .attr("cy", function(d) { return y(d.y).toFixed(1); })
01647 .attr("r", 4)
01648 .style("opacity", 0)
01649 .append("svg:title")
01650 .text( function(d) { return "x = " + d.x.toPrecision(4) + " \ny = " + d.y.toPrecision(4); });
01651 }
01652
01653 JSROOT.TF1Painter.prototype.UpdateObject = function(obj) {
01654 if (obj['_typename'] != this.tf1['_typename']) return false;
01655
01656 this.tf1 = obj;
01657 this.CreateBins();
01658 return true;
01659 }
01660
01661 JSROOT.Painter.drawFunction = function(divid, tf1) {
01662 var painter = new JSROOT.TF1Painter(tf1);
01663
01664 painter.SetDivId(divid, -1);
01665
01666 if (painter.main_painter() == null) {
01667 var histo = painter.CreateDummyHisto();
01668 JSROOT.Painter.drawHistogram1D(divid, histo);
01669 }
01670
01671 painter.SetDivId(divid);
01672
01673 painter.CreateBins();
01674
01675 painter.DrawBins();
01676
01677 return painter;
01678 }
01679
01680
01681
01682 JSROOT.TGraphPainter = function(graph) {
01683 JSROOT.TObjectPainter.call(this, graph);
01684 this.graph = graph;
01685 this.ownhisto = false;
01686 }
01687
01688 JSROOT.TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
01689
01690 JSROOT.TGraphPainter.prototype.GetObject = function() {
01691 return this.graph;
01692 }
01693
01694 JSROOT.TGraphPainter.prototype.Redraw = function() {
01695 this.DrawBins();
01696 }
01697
01698 JSROOT.TGraphPainter.prototype.DecodeOptions = function(opt) {
01699 this.logx = false;
01700 this.logy = false;
01701 this.logz = false;
01702 this.gridx = false;
01703 this.gridy = false;
01704 this.draw_all = true;
01705 this.optionLine = 0;
01706 this.optionAxis = 0;
01707 this.optionCurve = 0;
01708 this.optionStar = 0;
01709 this.optionMark = 0;
01710 this.optionBar = 0;
01711 this.optionR = 0;
01712 this.optionOne = 0;
01713 this.optionE = 0;
01714 this.optionFill = 0;
01715 this.optionZ = 0;
01716 this.optionCurveFill = 0;
01717 this.draw_errors = true;
01718 this.optionNone = 0;
01719 this.opt = "LP";
01720
01721 if ((opt != null) && (opt != "")) {
01722 this.opt = opt.toUpperCase();
01723 this.opt.replace('SAME', '');
01724 }
01725
01726 if (this.opt.indexOf('L') != -1)
01727 this.optionLine = 1;
01728 if (this.opt.indexOf('A') != -1)
01729 this.optionAxis = 1;
01730 if (this.opt.indexOf('C') != -1)
01731 this.optionCurve = 1;
01732 if (this.opt.indexOf('*') != -1)
01733 this.optionStar = 1;
01734 if (this.opt.indexOf('P') != -1)
01735 this.optionMark = 1;
01736 if (this.opt.indexOf('B') != -1)
01737 this.optionBar = 1;
01738 if (this.opt.indexOf('R') != -1)
01739 this.optionR = 1;
01740 if (this.opt.indexOf('1') != -1)
01741 this.optionOne = 1;
01742 if (this.opt.indexOf('F') != -1)
01743 this.optionFill = 1;
01744 if (this.opt.indexOf('2') != -1 || this.opt.indexOf('3') != -1
01745 || this.opt.indexOf('4') != -1 || this.opt.indexOf('5') != -1)
01746 this.optionE = 1;
01747
01748
01749 if (this.optionLine + this.optionFill + this.optionCurve + this.optionStar + this.optionMark + this.optionBar + this.optionE == 0) {
01750 if (this.opt.length == 0)
01751 this.optionLine = 1;
01752 else {
01753 this.optionNone = 1;
01754 return;
01755 }
01756 }
01757 if (this.optionStar)
01758 this.graph['fMarkerStyle'] = 3;
01759
01760 if (this.optionCurve && this.optionFill) {
01761 this.optionCurveFill = 1;
01762 this.optionFill = 0;
01763 }
01764
01765 var pad = this.root_pad();
01766 if (pad) {
01767 this.logx = pad['fLogx'];
01768 this.logy = pad['fLogy'];
01769 this.logz = pad['fLogz'];
01770 this.gridx = pad['fGridx'];
01771 this.gridy = pad['fGridy'];
01772 }
01773
01774 this.xaxis_type = this.logx ? 'logarithmic' : 'linear';
01775 this.yaxis_type = this.logy ? 'logarithmic' : 'linear';
01776
01777 if (this.graph['_typename'] == 'TGraph') {
01778
01779 if (this.graph['fHistogram']['fXaxis']['fTimeDisplay']) {
01780 this.xaxis_type = 'datetime';
01781 }
01782
01783 if (this.graph['fHistogram']['fYaxis']['fTimeDisplay']) {
01784 this.yaxis_type = 'datetime';
01785 }
01786 } else if (this.graph['_typename'] == 'TGraphErrors') {
01787 this.maxEX = d3.max(this.graph['fEX']);
01788 this.maxEY = d3.max(this.graph['fEY']);
01789 if (this.maxEX < 1.0e-300 && this.maxEY < 1.0e-300)
01790 this.draw_errors = false;
01791 }
01792 this.seriesType = 'scatter';
01793 if (this.optionBar == 1) this.seriesType = 'bar';
01794 this.showMarker = false;
01795 if (this.optionMark == 1 || this.optionStar == 1) this.showMarker = true;
01796
01797 if (this.optionLine == 1 || this.optionCurve == 1 || this.optionFill == 1)
01798 this.seriesType = 'line';
01799
01800 if (this.optionBar == 1) {
01801 this.binwidthx = (this.graph['fHistogram']['fXaxis']['fXmax'] -
01802 this.graph['fHistogram']['fXaxis']['fXmin'])
01803 / (this.graph['fNpoints'] - 1);
01804 }
01805 }
01806
01807 JSROOT.TGraphPainter.prototype.CreateBins = function() {
01808 var pthis = this;
01809
01810 var npoints = this.graph['fNpoints'];
01811 if ((this.graph._typename=="TCutG") && (npoints>3)) npoints--;
01812
01813 this.lineatt = JSROOT.Painter.createAttLine(this.graph);
01814
01815 this.bins = d3.range(npoints).map(
01816 function(p) {
01817 if (pthis.optionBar == 1) {
01818 return {
01819 x : pthis.graph['fX'][p] - (pthis.binwidthx / 2),
01820 y : pthis.graph['fY'][p],
01821 bw : pthis.binwidthx,
01822 bh : pthis.graph['fY'][p]
01823 }
01824 } else if (pthis.graph['_typename'] == 'TGraphErrors') {
01825 return {
01826 x : pthis.graph['fX'][p],
01827 y : pthis.graph['fY'][p],
01828 exlow : pthis.graph['fEX'][p],
01829 exhigh : pthis.graph['fEX'][p],
01830 eylow : pthis.graph['fEY'][p],
01831 eyhigh : pthis.graph['fEY'][p]
01832 };
01833 } else if (pthis.graph['_typename'] == 'TGraphAsymmErrors'
01834 || pthis.graph['_typename'].match(/^RooHist/)) {
01835 return {
01836 x : pthis.graph['fX'][p],
01837 y : pthis.graph['fY'][p],
01838 exlow : pthis.graph['fEXlow'][p],
01839 exhigh : pthis.graph['fEXhigh'][p],
01840 eylow : pthis.graph['fEYlow'][p],
01841 eyhigh : pthis.graph['fEYhigh'][p]
01842 };
01843 } else {
01844 return {
01845 x : pthis.graph['fX'][p],
01846 y : pthis.graph['fY'][p]
01847 };
01848 }
01849 });
01850
01851 this.exclusionGraph = false;
01852 if (this.lineatt.width <= 99) return;
01853
01854
01855
01856 this.exclusionGraph = true;
01857
01858 var normx, normy;
01859 var n = this.graph['fNpoints'];
01860 var xo = new Array(n + 2),
01861 yo = new Array(n + 2),
01862 xt = new Array(n + 2),
01863 yt = new Array(n + 2),
01864 xf = new Array(2 * n + 2),
01865 yf = new Array(2 * n + 2);
01866
01867
01868
01869
01870 var a, i, j, nf, wk = 1;
01871 if (this.lineatt.width > 32767) {
01872 this.lineatt.width = 65536 - this.lineatt.width;
01873 wk = -1;
01874 }
01875 wk *= (this.lineatt.width / 100) * 0.005;
01876 this.lineatt.width = this.lineatt.width % 100;
01877 if (this.lineatt.width > 0) this.optionLine = 1;
01878
01879 var w = Number(this.svg_frame(true).attr("width")),
01880 h = Number(this.svg_frame(true).attr("height"));
01881
01882 var ratio = w / h;
01883
01884 var xmin = this.main_painter().xmin, xmax = this.main_painter().xmax,
01885 ymin = this.main_painter().ymin, ymax = this.main_painter().ymax;
01886 for (i = 0; i < n; i++) {
01887 xo[i] = (this.graph['fX'][i] - xmin) / (xmax - xmin);
01888 yo[i] = (this.graph['fY'][i] - ymin) / (ymax - ymin);
01889 if (w > h)
01890 yo[i] = yo[i] / ratio;
01891 else if (h > w)
01892 xo[i] = xo[i] / ratio;
01893 }
01894
01895
01896 xf[0] = xo[0];
01897 yf[0] = yo[0];
01898 nf = 0;
01899 for (i = 1; i < n; i++) {
01900 if (xo[i] == xo[i - 1] && yo[i] == yo[i - 1]) continue;
01901 nf++;
01902 xf[nf] = xo[i];
01903 if (xf[i] == xf[i - 1])
01904 xf[i] += 0.000001;
01905
01906 yf[nf] = yo[i];
01907 }
01908
01909
01910
01911 if (xf[1] == xf[0]) {
01912 a = Math.PI / 2.0;
01913 } else {
01914 a = Math.atan((yf[1] - yf[0]) / (xf[1] - xf[0]));
01915 }
01916 if (xf[0] <= xf[1]) {
01917 xt[0] = xf[0] - wk * Math.sin(a);
01918 yt[0] = yf[0] + wk * Math.cos(a);
01919 } else {
01920 xt[0] = xf[0] + wk * Math.sin(a);
01921 yt[0] = yf[0] - wk * Math.cos(a);
01922 }
01923 if (xf[nf] == xf[nf - 1]) {
01924 a = Math.PI / 2.0;
01925 } else {
01926 a = Math.atan((yf[nf] - yf[nf - 1]) / (xf[nf] - xf[nf - 1]));
01927 }
01928 if (xf[nf] >= xf[nf - 1]) {
01929 xt[nf] = xf[nf] - wk * Math.sin(a);
01930 yt[nf] = yf[nf] + wk * Math.cos(a);
01931 } else {
01932 xt[nf] = xf[nf] + wk * Math.sin(a);
01933 yt[nf] = yf[nf] - wk * Math.cos(a);
01934 }
01935
01936 var a1, a2, a3, xi0, yi0, xi1, yi1, xi2, yi2;
01937 for (i = 1; i < nf; i++) {
01938 xi0 = xf[i];
01939 yi0 = yf[i];
01940 xi1 = xf[i + 1];
01941 yi1 = yf[i + 1];
01942 xi2 = xf[i - 1];
01943 yi2 = yf[i - 1];
01944 if (xi1 == xi0) {
01945 a1 = Math.PI / 2.0;
01946 } else {
01947 a1 = Math.atan((yi1 - yi0) / (xi1 - xi0));
01948 }
01949 if (xi1 < xi0)
01950 a1 = a1 + Math.PI;
01951 if (xi2 == xi0) {
01952 a2 = Math.PI / 2.0;
01953 } else {
01954 a2 = Math.atan((yi0 - yi2) / (xi0 - xi2));
01955 }
01956 if (xi0 < xi2)
01957 a2 = a2 + Math.PI;
01958 x1 = xi0 - wk * Math.sin(a1);
01959 y1 = yi0 + wk * Math.cos(a1);
01960 x2 = xi0 - wk * Math.sin(a2);
01961 y2 = yi0 + wk * Math.cos(a2);
01962 xm = (x1 + x2) * 0.5;
01963 ym = (y1 + y2) * 0.5;
01964 if (xm == xi0) {
01965 a3 = Math.PI / 2.0;
01966 } else {
01967 a3 = Math.atan((ym - yi0) / (xm - xi0));
01968 }
01969 x3 = xi0 - wk * Math.sin(a3 + (Math.PI / 2.0));
01970 y3 = yi0 + wk * Math.cos(a3 + (Math.PI / 2.0));
01971
01972
01973 if ((xm - xi0) * (x3 - xi0) < 0 && (ym - yi0) * (y3 - yi0) < 0) {
01974 x3 = 2 * xi0 - x3;
01975 y3 = 2 * yi0 - y3;
01976 }
01977 if ((xm == x1) && (ym == y1)) {
01978 x3 = xm;
01979 y3 = ym;
01980 }
01981 xt[i] = x3;
01982 yt[i] = y3;
01983 }
01984
01985 if (xf[nf] == xf[0] && yf[nf] == yf[0]) {
01986 xm = (xt[nf] + xt[0]) * 0.5;
01987 ym = (yt[nf] + yt[0]) * 0.5;
01988 if (xm == xf[0]) {
01989 a3 = Math.PI / 2.0;
01990 } else {
01991 a3 = Math.atan((ym - yf[0]) / (xm - xf[0]));
01992 }
01993 x3 = xf[0] + wk * Math.sin(a3 + (Math.PI / 2.0));
01994 y3 = yf[0] - wk * Math.cos(a3 + (Math.PI / 2.0));
01995 if ((xm - xf[0]) * (x3 - xf[0]) < 0 && (ym - yf[0]) * (y3 - yf[0]) < 0) {
01996 x3 = 2 * xf[0] - x3;
01997 y3 = 2 * yf[0] - y3;
01998 }
01999 xt[nf] = x3;
02000 xt[0] = x3;
02001 yt[nf] = y3;
02002 yt[0] = y3;
02003 }
02004
02005 var xc, yc, c1, b1, c2, b2;
02006 var cross = false;
02007 var nf2 = nf;
02008 for (i = nf2; i > 0; i--) {
02009 for (j = i - 1; j > 0; j--) {
02010 if (xt[i - 1] == xt[i] || xt[j - 1] == xt[j])
02011 continue;
02012 c1 = (yt[i - 1] - yt[i]) / (xt[i - 1] - xt[i]);
02013 b1 = yt[i] - c1 * xt[i];
02014 c2 = (yt[j - 1] - yt[j]) / (xt[j - 1] - xt[j]);
02015 b2 = yt[j] - c2 * xt[j];
02016 if (c1 != c2) {
02017 xc = (b2 - b1) / (c1 - c2);
02018 yc = c1 * xc + b1;
02019 if (xc > Math.min(xt[i], xt[i - 1])
02020 && xc < Math.max(xt[i], xt[i - 1])
02021 && xc > Math.min(xt[j], xt[j - 1])
02022 && xc < Math.max(xt[j], xt[j - 1])
02023 && yc > Math.min(yt[i], yt[i - 1])
02024 && yc < Math.max(yt[i], yt[i - 1])
02025 && yc > Math.min(yt[j], yt[j - 1])
02026 && yc < Math.max(yt[j], yt[j - 1])) {
02027 nf++;
02028 xf[nf] = xt[i];
02029 yf[nf] = yt[i];
02030 nf++;
02031 xf[nf] = xc;
02032 yf[nf] = yc;
02033 i = j;
02034 cross = true;
02035 break;
02036 } else {
02037 continue;
02038 }
02039 } else {
02040 continue;
02041 }
02042 }
02043 if (!cross) {
02044 nf++;
02045 xf[nf] = xt[i];
02046 yf[nf] = yt[i];
02047 }
02048 cross = false;
02049 }
02050 nf++;
02051 xf[nf] = xt[0];
02052 yf[nf] = yt[0];
02053 nf++;
02054 for (i = 0; i < nf; i++) {
02055 if (w > h) {
02056 xf[i] = xmin + (xf[i] * (xmax - xmin));
02057 yf[i] = ymin + (yf[i] * (ymax - ymin)) * ratio;
02058 } else if (h > w) {
02059 xf[i] = xmin + (xf[i] * (xmax - xmin)) * ratio;
02060 yf[i] = ymin + (yf[i] * (ymax - ymin));
02061 } else {
02062 xf[i] = xmin + (xf[i] * (xmax - xmin));
02063 yf[i] = ymin + (yf[i] * (ymax - ymin));
02064 }
02065 if (this.logx && xf[i] <= 0.0)
02066 xf[i] = xmin;
02067 if (this.logy && yf[i] <= 0.0)
02068 yf[i] = ymin;
02069 }
02070
02071 this.excl = d3.range(nf).map(function(p) { return { x : xf[p], y : yf[p] }; });
02072
02073 this.excl_ff = 1;
02074
02075
02076 xo.splice(0, xo.length);
02077 yo.splice(0, yo.length);
02078 xo = null;
02079 yo = null;
02080 xt.splice(0, xt.length);
02081 yt.splice(0, yt.length);
02082 xt = null;
02083 yt = null;
02084 xf.splice(0, xf.length);
02085 yf.splice(0, yf.length);
02086 xf = null;
02087 yf = null;
02088 }
02089
02090 JSROOT.TGraphPainter.prototype.DrawBins = function() {
02091
02092 var w = Number(this.svg_frame(true).attr("width")),
02093 h = Number(this.svg_frame(true).attr("height"));
02094
02095 this.RecreateDrawG();
02096
02097 var pthis = this;
02098
02099 var fill = this.createAttFill(this.graph);
02100
02101 function TooltipText(d) {
02102
02103 var res = "x = " + pthis.main_painter().AxisAsText("x", d.x) + "\n" +
02104 "y = " + pthis.main_painter().AxisAsText("y", d.y);
02105
02106 if (pthis.draw_errors && ('exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0)))
02107 res += "\nerror x = -" + pthis.main_painter().AxisAsText("x", d.exlow) +
02108 "/+" + pthis.main_painter().AxisAsText("x", d.exhigh);
02109
02110 if (pthis.draw_errors && ('eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0)) )
02111 res += "\nerror y = -" + pthis.main_painter().AxisAsText("y", d.eylow) +
02112 "/+" + pthis.main_painter().AxisAsText("y", d.eyhigh);
02113
02114 return res;
02115 }
02116
02117 var x = this.main_painter().x;
02118 var y = this.main_painter().y;
02119 var line = d3.svg.line()
02120 .x(function(d) { return Math.round(x(d.x)); })
02121 .y(function(d) { return Math.round(y(d.y)); });
02122
02123 if (this.seriesType == 'bar') {
02124 var fillcolor = JSROOT.Painter.root_colors[this.graph['fFillColor']];
02125 if (typeof (fillcolor) == 'undefined') fillcolor = "rgb(204,204,204)";
02126
02127 var xdom = this.main_painter().x.domain();
02128 var xfactor = xdom[1] - xdom[0];
02129 this.draw_errors = false;
02130
02131 var nodes = this.draw_g.selectAll("bar_graph")
02132 .data(pthis.bins).enter()
02133 .append("svg:rect")
02134 .attr("x", function(d) { return x(d.x) })
02135 .attr("y", function(d) { return y(d.y) })
02136 .attr("width", function(d) { return (w / (xdom[1] - xdom[0])) - 1 })
02137 .attr("height", function(d) { return y(d.y) - y(d.y + d.bh); })
02138 .style("fill", fillcolor);
02139
02140 if (JSROOT.gStyle.Tooltip)
02141 nodes.append("svg:title").text(function(d) { return "x = " + d.x.toPrecision(4) + " \nentries = " + d.y.toPrecision(4); });
02142 }
02143 if (this.exclusionGraph) {
02144
02145 this.showMarker = false;
02146
02147 this.draw_g.append("svg:path")
02148 .attr("d", line(pthis.excl))
02149 .style("stroke", "none")
02150 .style("stroke-width", pthis.excl_ff)
02151 .call(fill.func)
02152 .style('opacity', 0.75);
02153 }
02154
02155 if (this.seriesType == 'line') {
02156
02157 var close_symbol = "";
02158 if (this.graph._typename=="TCutG") close_symbol = " Z";
02159
02160 var lineatt = this.lineatt;
02161 if (this.optionLine == 0) lineatt = JSROOT.Painter.createAttLine('none');
02162
02163 if (this.optionFill == 1) {
02164
02165 } else {
02166 fill.color = 'none';
02167 }
02168
02169 this.draw_g.append("svg:path")
02170 .attr("d", line(pthis.bins) + close_symbol)
02171 .attr("class", "draw_line")
02172 .call(lineatt.func)
02173 .call(fill.func);
02174
02175
02176 if (JSROOT.gStyle.Tooltip && !this.showMarker)
02177 this.draw_g.selectAll("draw_line")
02178 .data(pthis.bins).enter()
02179 .append("svg:circle")
02180 .attr("cx", function(d) { return Math.round(x(d.x)); })
02181 .attr("cy", function(d) { return Math.round(y(d.y)); })
02182 .attr("r", 3)
02183 .style("opacity", 0)
02184 .append("svg:title")
02185 .text(TooltipText);
02186 }
02187
02188 if (this.draw_errors)
02189 this.draw_errors = (this.graph['_typename'] == 'TGraphErrors' ||
02190 this.graph['_typename'] == 'TGraphAsymmErrors' ||
02191 this.graph['_typename'].match(/^RooHist/)) && !this.optionBar;
02192
02193 var nodes = null;
02194
02195 if (this.draw_errors || this.showMarker) {
02196 var draw_bins = new Array;
02197 for (var i in this.bins) {
02198 var pnt = this.bins[i];
02199 var grx = x(pnt.x);
02200 var gry = y(pnt.y);
02201 if ((grx<0) || (grx>w) || (gry<0) || (gry>h)) continue;
02202
02203
02204 pnt['grx1'] = grx.toFixed(1);
02205 pnt['gry1'] = gry.toFixed(1);
02206 if (pnt.exlow > 0) pnt['grx0'] = (x(pnt.x - pnt.exlow) - grx).toFixed(1);
02207 if (pnt.exhigh > 0) pnt['grx2'] = (x(pnt.x + pnt.exhigh) - grx).toFixed(1);
02208 if (pnt.eylow > 0) pnt['gry0'] = (y(pnt.y - pnt.eylow) - gry).toFixed(1);
02209 if (pnt.eyhigh > 0) pnt['gry2'] = (y(pnt.y + pnt.eyhigh) - gry).toFixed(1);
02210
02211 draw_bins.push(pnt);
02212 }
02213
02214 nodes = this.draw_g.selectAll("g.node")
02215 .data(draw_bins)
02216 .enter()
02217 .append("svg:g")
02218 .attr("transform", function(d) { return "translate(" + d.grx1 + "," + d.gry1 + ")"; })
02219 }
02220
02221 if (JSROOT.gStyle.Tooltip && nodes)
02222 nodes.append("svg:title").text(TooltipText);
02223
02224 if (this.draw_errors) {
02225
02226 nodes.filter(function(d) { return (d.exlow > 0) || (d.exhigh > 0); })
02227 .append("svg:line")
02228 .attr("x1", function(d) { return d.grx0; })
02229 .attr("y1", 0)
02230 .attr("x2", function(d) { return d.grx2; })
02231 .attr("y2", 0)
02232 .style("stroke", this.lineatt.color)
02233 .style("stroke-width", this.lineatt.width);
02234
02235 nodes.filter(function(d) { return (d.exlow > 0); })
02236 .append("svg:line")
02237 .attr("y1", -3)
02238 .attr("x1", function(d) { return d.grx0; })
02239 .attr("y2", 3)
02240 .attr("x2", function(d) { return d.grx0; })
02241 .style("stroke", this.lineatt.color)
02242 .style("stroke-width", this.lineatt.width);
02243
02244 nodes.filter(function(d) { return (d.exhigh > 0); })
02245 .append("svg:line")
02246 .attr("y1", -3)
02247 .attr("x1", function(d) { return d.grx2; })
02248 .attr("y2", 3)
02249 .attr("x2", function(d) { return d.grx2; })
02250 .style("stroke", this.lineatt.color)
02251 .style( "stroke-width", this.lineatt.width);
02252
02253
02254
02255 nodes.filter(function(d) { return (d.eylow > 0) || (d.eyhigh > 0); })
02256 .append("svg:line")
02257 .attr("x1", 0)
02258 .attr("y1", function(d) { return d.gry0; })
02259 .attr("x2", 0)
02260 .attr("y2", function(d) { return d.gry2; })
02261 .style("stroke", this.lineatt.color)
02262 .style("stroke-width", this.lineatt.width);
02263
02264 nodes.filter(function(d) { return (d.eylow > 0); })
02265 .append("svg:line")
02266 .attr("x1", -3)
02267 .attr("y1", function(d) { return d.gry0; })
02268 .attr("x2", 3)
02269 .attr("y2", function(d) { return d.gry0; })
02270 .style("stroke", this.lineatt.color)
02271 .style("stroke-width", this.lineatt.width);
02272
02273 nodes.filter(function(d) { return (d.eyhigh > 0); })
02274 .append("svg:line")
02275 .attr("x1", -3)
02276 .attr("y1", function(d) { return d.gry2; })
02277 .attr("x2", 3)
02278 .attr("y2", function(d) { return d.gry2; })
02279 .style("stroke", this.lineatt.color)
02280 .style("stroke-width", this.lineatt.width);
02281 }
02282
02283 if (this.showMarker) {
02284
02285 var marker = JSROOT.Painter.createAttMarker(this.graph);
02286
02287 nodes.append("svg:path").call(marker.func);
02288 }
02289 }
02290
02291 JSROOT.TGraphPainter.prototype.UpdateObject = function(obj) {
02292 if (obj['_typename'] != this.graph['_typename'])
02293 return false;
02294
02295
02296 if (this.ownhisto)
02297 this.main_painter().UpdateObject(obj['fHistogram']);
02298
02299
02300 this.graph['fX'] = obj['fX'];
02301 this.graph['fY'] = obj['fY'];
02302 this.graph['fNpoints'] = obj['fNpoints'];
02303 this.CreateBins();
02304 return true;
02305 }
02306
02307 JSROOT.Painter.drawGraph = function(divid, graph, opt) {
02308
02309 var painter = new JSROOT.TGraphPainter(graph);
02310 painter.SetDivId(divid, -1);
02311
02312 if (painter.main_painter() == null) {
02313 if (graph['fHistogram']==null) {
02314 alert("drawing first graph without fHistogram field, not (yet) supported");
02315 return null;
02316 }
02317 JSROOT.Painter.drawHistogram1D(divid, graph['fHistogram']);
02318 painter.ownhisto = true;
02319 }
02320
02321 painter.SetDivId(divid);
02322
02323 painter.DecodeOptions(opt);
02324
02325 painter.CreateBins();
02326
02327 painter.DrawBins();
02328
02329 return painter;
02330 }
02331
02332
02333
02334 JSROOT.TPavePainter = function(pave) {
02335 JSROOT.TObjectPainter.call(this, pave);
02336 this.pavetext = pave;
02337 this.Enabled = true;
02338 }
02339
02340 JSROOT.TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
02341
02342 JSROOT.TPavePainter.prototype.GetObject = function() {
02343 return this.pavetext;
02344 }
02345
02346 JSROOT.TPavePainter.prototype.DrawPaveText = function() {
02347 var pavetext = this.pavetext;
02348
02349 var w = Number(this.svg_pad(true).attr("width")),
02350 h = Number(this.svg_pad(true).attr("height"));
02351
02352 var pos_x = Math.round(pavetext['fX1NDC'] * w);
02353
02354 var pos_y = Math.round((1.0 - pavetext['fY1NDC']) * h);
02355 var width = Math.round(Math.abs(pavetext['fX2NDC'] - pavetext['fX1NDC']) * w);
02356 var height = Math.round(Math.abs(pavetext['fY2NDC'] - pavetext['fY1NDC']) * h);
02357 pos_y -= height;
02358 var nlines = pavetext['fLines'].arr.length;
02359 var tcolor = JSROOT.Painter.root_colors[pavetext['fTextColor']];
02360 var scolor = JSROOT.Painter.root_colors[pavetext['fShadowColor']];
02361 var fcolor = this.createAttFill(pavetext);
02362
02363
02364
02365
02366
02367 var align = 'start', halign = Math.round(pavetext['fTextAlign'] / 10);
02368 var baseline = 'bottom', valign = pavetext['fTextAlign'] % 10;
02369 if (halign == 1) align = 'start';
02370 else if (halign == 2) align = 'middle';
02371 else if (halign == 3) align = 'end';
02372 if (valign == 1) baseline = 'bottom';
02373 else if (valign == 2) baseline = 'middle';
02374 else if (valign == 3) baseline = 'top';
02375
02376 var h_margin = Math.round(pavetext['fMargin'] * width);
02377
02378 var font = JSROOT.Painter.getFontDetails(pavetext['fTextFont'], height / (nlines * 1.2));
02379
02380 var lwidth = pavetext['fBorderSize'] ? pavetext['fBorderSize'] : 0;
02381 var attline = JSROOT.Painter.createAttLine(pavetext, lwidth>0 ? 1 : 0);
02382
02383 var first_stat = 0, num_cols = 0, maxlw = 0;
02384 var lines = new Array;
02385
02386
02387 for (var j = 0; j < nlines; ++j) {
02388 var line = JSROOT.Painter.translateLaTeX(pavetext['fLines'].arr[j]['fTitle']);
02389 lines.push(line);
02390 var lw = h_margin + font.stringWidth(this.svg_pad(true), line) + h_margin;
02391 if (lw > maxlw) maxlw = lw;
02392 if ((j == 0) || (line.indexOf('|') < 0)) continue;
02393 if (first_stat === 0) first_stat = j;
02394 var parts = line.split("|");
02395 if (parts.length > num_cols)
02396 num_cols = parts.length;
02397 }
02398
02399 if (maxlw > width)
02400 font.size = Math.floor(font.size * (width / maxlw));
02401 else
02402 if ((nlines==1) && (lwidth==0) && (maxlw < width - 40)) {
02403
02404 var diff = width - maxlw;
02405 width -= diff;
02406 pos_x += diff/2;
02407 pavetext['fX1NDC'] = pos_x / w;
02408 pavetext['fX2NDC'] = (pos_x + width) / w;
02409 }
02410
02411 var h_margin = Math.round(pavetext['fMargin'] * width);
02412 var text_pos_x = h_margin / 2;
02413 if (nlines == 1)
02414 switch (halign) {
02415 case 1: text_pos_x = h_margin; break;
02416 case 2: text_pos_x = width / 2; break;
02417 case 3: text_pos_x = width - h_margin; break;
02418 }
02419
02420 var pthis = this;
02421
02422
02423 this.RecreateDrawG(true,".stat_layer");
02424
02425
02426 this.draw_g
02427 .attr("x", pos_x)
02428 .attr("y", pos_y)
02429 .attr("width", width)
02430 .attr("height", height)
02431 .attr("transform", "translate(" + pos_x + "," + pos_y + ")");
02432
02433 this.draw_g.append("rect")
02434 .attr("x", 0)
02435 .attr("y", 0)
02436 .attr("width", width)
02437 .attr("height", height)
02438 .call(fcolor.func)
02439 .call(attline.func);
02440
02441
02442 var stepy = (height - 0.2*font.size) / nlines;
02443
02444 if (nlines == 1) {
02445 this.draw_g.append("text")
02446 .attr("text-anchor", align)
02447 .attr("x", text_pos_x)
02448 .attr("y", ((height / 2) + (font.size / 3)).toFixed(1))
02449 .call(font.func)
02450 .attr("fill", tcolor)
02451 .text(lines[0]);
02452 } else {
02453
02454 for (var j = 0; j < nlines; ++j) {
02455 var jcolor = JSROOT.Painter.root_colors[pavetext['fLines'].arr[j]['fTextColor']];
02456 if (pavetext['fLines'].arr[j]['fTextColor'] == 0) jcolor = tcolor;
02457 var posy = (j+0.5)*stepy + font.size*0.5 - 1;
02458
02459 if (pavetext['_typename'] == 'TPaveStats') {
02460 if ((first_stat > 0) && (j >= first_stat)) {
02461 var parts = lines[j].split("|");
02462 for (var n = 0; n < parts.length; n++)
02463 this.draw_g.append("text")
02464 .attr("text-anchor", "middle")
02465 .attr("x", (width * (n + 0.5) / num_cols).toFixed(1))
02466 .attr("y", posy.toFixed(1))
02467 .call(font.func)
02468 .attr("fill", jcolor)
02469 .text(parts[n]);
02470 } else if ((j == 0) || (lines[j].indexOf('=') < 0)) {
02471 this.draw_g.append("text")
02472 .attr("text-anchor", (j == 0) ? "middle" : "start")
02473 .attr("x", ((j == 0) ? width / 2 : pavetext['fMargin'] * width).toFixed(1))
02474 .attr("y", posy.toFixed(1))
02475 .call(font.func)
02476 .attr("fill", jcolor)
02477 .text(lines[j]);
02478 } else {
02479 var parts = lines[j].split("=");
02480 for (var n = 0; n < 2; n++)
02481 this.draw_g.append("text")
02482 .attr("text-anchor", (n == 0) ? "start" : "end")
02483 .attr("x", ((n == 0) ? pavetext['fMargin'] * width : (1 - pavetext['fMargin']) * width).toFixed(1))
02484 .attr("y", posy.toFixed(1))
02485 .call(font.func)
02486 .attr("fill", jcolor)
02487 .text(parts[n]);
02488 }
02489 } else {
02490 this.draw_g.append("text")
02491 .attr("text-anchor", "start")
02492 .attr("x", text_pos_x.toFixed(1))
02493 .attr("y", posy.toFixed(1))
02494 .call(font.func)
02495 .attr("fill", jcolor)
02496 .text(lines[j]);
02497 }
02498 }
02499 }
02500
02501 if (pavetext['fBorderSize'] && (pavetext['_typename'] == 'TPaveStats')) {
02502 this.draw_g.append("svg:line")
02503 .attr("class", "pavedraw")
02504 .attr("x1", 0)
02505 .attr("y1", stepy)
02506 .attr("x2", width)
02507 .attr("y2", stepy)
02508 .call(attline.func);
02509 }
02510
02511 if ((first_stat > 0) && (num_cols > 1)) {
02512 for (var nrow = first_stat; nrow < nlines; nrow++)
02513 this.draw_g.append("svg:line")
02514 .attr("x1", 0)
02515 .attr("y1", nrow * stepy)
02516 .attr("x2", width)
02517 .attr("y2", nrow * stepy)
02518 .call(attline.func);
02519
02520 for (var ncol = 0; ncol < num_cols - 1; ncol++)
02521 this.draw_g.append("svg:line")
02522 .attr("x1", width / num_cols * (ncol + 1))
02523 .attr("y1", first_stat * stepy)
02524 .attr("x2", width / num_cols * (ncol + 1))
02525 .attr("y2", height)
02526 .call(attline.func);
02527 }
02528
02529 if (lwidth && lwidth > 1) {
02530 this.draw_g.append("svg:line")
02531 .attr("x1", width + (lwidth / 2))
02532 .attr("y1", lwidth + 1)
02533 .attr("x2", width + (lwidth / 2))
02534 .attr("y2", height + lwidth - 1)
02535 .style("stroke", attline.color)
02536 .style("stroke-width", lwidth);
02537 this.draw_g.append("svg:line")
02538 .attr("x1", lwidth + 1)
02539 .attr("y1", height + (lwidth / 2))
02540 .attr("x2", width + lwidth - 1)
02541 .attr("y2", height + (lwidth / 2))
02542 .style("stroke", attline.color)
02543 .style("stroke-width", lwidth);
02544 }
02545
02546 this.AddDrag("stat", this.draw_g, {
02547 move : function(x, y, dx, dy) {
02548 pthis.draw_g.attr("transform", "translate(" + x + "," + y + ")");
02549
02550 pthis.pavetext['fX1NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
02551 pthis.pavetext['fX2NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
02552 pthis.pavetext['fY1NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
02553 pthis.pavetext['fY2NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
02554 },
02555 resize : function(width, height) {
02556 pthis.pavetext['fX2NDC'] = pthis.pavetext['fX1NDC'] + width / Number(pthis.svg_pad(true).attr("width"));
02557 pthis.pavetext['fY1NDC'] = pthis.pavetext['fY2NDC'] - height / Number(pthis.svg_pad(true).attr("height"));
02558
02559 pthis.DrawPaveText();
02560 }
02561 });
02562 }
02563
02564 JSROOT.TPavePainter.prototype.AddLine = function(txt) {
02565 this.pavetext.AddText(txt);
02566
02567 }
02568
02569 JSROOT.TPavePainter.prototype.IsStats = function() {
02570 if (!this.pavetext) return false;
02571 return this.pavetext['fName'] == "stats";
02572 }
02573
02574 JSROOT.TPavePainter.prototype.FillStatistic = function() {
02575 if (!this.IsStats()) return;
02576
02577 var dostat = new Number(this.pavetext['fOptStat']);
02578 if (!dostat) dostat = new Number(JSROOT.gStyle.OptStat);
02579
02580
02581 if ('FillStatistic' in this.main_painter()) {
02582
02583
02584 this.pavetext['fLines'].arr.length = 0;
02585
02586 this.main_painter().FillStatistic(this, dostat);
02587 }
02588 }
02589
02590 JSROOT.TPavePainter.prototype.UpdateObject = function(obj) {
02591 if (obj._typename != 'TPaveText') return false;
02592 this.pavetext['fLines'] = JSROOT.clone(obj['fLines']);
02593 return true;
02594 }
02595
02596 JSROOT.TPavePainter.prototype.Redraw = function() {
02597
02598 this.RemoveDrawG();
02599
02600
02601 if (!this.Enabled) {
02602 this.RemoveDrag("stat");
02603 return;
02604 }
02605
02606 this.FillStatistic();
02607
02608 this.DrawPaveText();
02609 }
02610
02611 JSROOT.Painter.drawPaveText = function(divid, pavetext) {
02612 if (pavetext['fX1NDC'] < 0.0 || pavetext['fY1NDC'] < 0.0 ||
02613 pavetext['fX1NDC'] > 1.0 || pavetext['fY1NDC'] > 1.0)
02614 return null;
02615
02616 var painter = new JSROOT.TPavePainter(pavetext);
02617
02618 painter.SetDivId(divid);
02619
02620
02621
02622 painter.FillStatistic();
02623
02624 painter.DrawPaveText();
02625
02626 return painter;
02627 }
02628
02629
02630
02631 JSROOT.TPadPainter = function(pad, iscan) {
02632 JSROOT.TObjectPainter.call(this, pad);
02633 if (this.obj_typename=="") this.obj_typename = iscan ? "TCanvas" : "TPad";
02634 this.pad = pad;
02635 this.iscan = iscan;
02636 this.painters = new Array;
02637 }
02638
02639 JSROOT.TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
02640
02641 JSROOT.TPadPainter.prototype.CreateCanvasSvg = function(only_resize) {
02642
02643 var render_to = $("#" + this.divid);
02644
02645 var w = render_to.width(), h = render_to.height();
02646
02647 var svg = null;
02648
02649 if (only_resize) {
02650 svg = this.svg_canvas(true);
02651 if ((svg.property('last_width') == w) && (svg.property('last_height') == h)) return false;
02652 } else {
02653
02654 if (h < 10) {
02655
02656
02657 var factor = 0.66;
02658
02659
02660 if ((this.pad!=null) && ('fCw' in this.pad) && ('fCh' in this.pad) && (this.pad['fCw'] > 0)) {
02661 factor = this.pad['fCh'] / this.pad['fCw'];
02662 if ((factor < 0.1) || (factor > 10))
02663 factor = 0.66;
02664 }
02665
02666 h = w * factor;
02667
02668 render_to.height(h);
02669 }
02670
02671 var fill = null;
02672
02673 if (this.pad && 'fFillColor' in this.pad)
02674 fill = this.createAttFill(this.pad);
02675 else
02676 fill = this.createAttFill('white');
02677
02678 render_to.css("background-color", fill.color);
02679
02680 svg = d3.select("#" + this.divid)
02681 .append("svg")
02682 .attr("class", "root_canvas")
02683 .style("background-color", fill.color)
02684 .property('pad_painter', this)
02685 .property('mainpainter', null)
02686 .property('current_pad', "")
02687
02688 svg.append("svg:g").attr("class","frame_layer");
02689 svg.append("svg:g").attr("class","text_layer");
02690 svg.append("svg:g").attr("class","stat_layer");
02691 }
02692
02693
02694 svg.attr("width", w)
02695 .attr("height", h)
02696 .attr("viewBox", "0 0 " + w + " " + h)
02697 .property('last_width', w)
02698 .property('last_height', h);
02699
02700 return true;
02701 }
02702
02703
02704 JSROOT.TPadPainter.prototype.CreatePadSvg = function(only_resize) {
02705 var width = Number(this.svg_canvas(true).attr("width")),
02706 height = Number(this.svg_canvas(true).attr("height"));
02707 var x = Math.round(this.pad['fAbsXlowNDC'] * width);
02708 var y = Math.round(height - this.pad['fAbsYlowNDC'] * height);
02709 var w = Math.round(this.pad['fAbsWNDC'] * width);
02710 var h = Math.round(this.pad['fAbsHNDC'] * height);
02711 y -= h;
02712
02713 var fill = this.createAttFill(this.pad);
02714 var attline = JSROOT.Painter.createAttLine(this.pad)
02715 if (this.pad['fBorderMode'] == 0) attline.color = 'none';
02716
02717 var svg_pad = null, svg_rect = null;
02718
02719 if (only_resize) {
02720 svg_pad = this.svg_pad(true);
02721 svg_rect = svg_pad.select(".root_pad_border");
02722 } else {
02723 svg_pad = this.svg_canvas(true).append("g")
02724 .attr("class", "root_pad")
02725 .attr("pad", this.pad['fName'])
02726 .property('pad_painter', this)
02727 .property('mainpainter', null);
02728 svg_rect = svg_pad.append("svg:rect").attr("class", "root_pad_border");
02729 svg_pad.append("svg:g").attr("class","frame_layer");
02730 svg_pad.append("svg:g").attr("class","text_layer");
02731 svg_pad.append("svg:g").attr("class","stat_layer");
02732 }
02733
02734 svg_pad.attr("width", w)
02735 .attr("height", h)
02736 .attr("viewBox", x + " " + y + " " + (x+w) + " " + (y+h))
02737 .attr("transform", "translate(" + x + "," + y + ")");
02738
02739 svg_rect.attr("x", 0)
02740 .attr("y", 0)
02741 .attr("width", w)
02742 .attr("height", h)
02743 .call(fill.func)
02744 .call(attline.func);
02745 }
02746
02747 JSROOT.TPadPainter.prototype.CheckColors = function(can) {
02748 if (can==null) return;
02749 for (var i in can.fPrimitives.arr) {
02750 var obj = can.fPrimitives.arr[i];
02751 if (obj==null) continue;
02752 if ((obj._typename=="TObjArray") && (obj.name == "ListOfColors")) {
02753 JSROOT.Painter.adoptRootColors(obj);
02754 can.fPrimitives.arr.splice(i,1);
02755 can.fPrimitives.opt.splice(i,1);
02756 return;
02757 }
02758 }
02759 }
02760
02761 JSROOT.TPadPainter.prototype.DrawPrimitives = function() {
02762 if (this.pad==null) return;
02763
02764 for (var i in this.pad.fPrimitives.arr) {
02765 var pp = JSROOT.draw(this.divid, this.pad.fPrimitives.arr[i], this.pad.fPrimitives.opt[i]);
02766 if (pp) pp['_primitive'] = true;
02767 }
02768 }
02769
02770 JSROOT.TPadPainter.prototype.Redraw = function(resize) {
02771 if (resize && !this.iscan) this.CreatePadSvg(true);
02772
02773
02774 for (var i in this.painters)
02775 this.painters[i].Redraw(resize);
02776 }
02777
02778
02779 JSROOT.TPadPainter.prototype.CheckCanvasResize = function() {
02780 if (!this.iscan) return;
02781
02782 var changed = this.CreateCanvasSvg(true);
02783 if (changed) this.Redraw(true);
02784 }
02785
02786
02787 JSROOT.TPadPainter.prototype.UpdateObject = function(obj) {
02788
02789 if ((obj == null) || !('fPrimitives' in obj)) return false;
02790
02791 if (this.iscan) this.CheckColors(obj);
02792
02793 if (obj.fPrimitives.arr.length != this.pad.fPrimitives.arr.length) return false;
02794
02795 var isany = false, p = 0;
02796
02797 for (var n in obj.fPrimitives.arr) {
02798 var sub = obj.fPrimitives.arr[n];
02799
02800 while (p<this.painters.length) {
02801 var pp = this.painters[p++];
02802 if (!('_primitive' in pp)) continue;
02803 if (pp.UpdateObject(sub)) isany = true;
02804 break;
02805 }
02806 }
02807
02808 return isany;
02809 }
02810
02811 JSROOT.Painter.drawCanvas = function(divid, can) {
02812 var painter = new JSROOT.TPadPainter(can, true);
02813 painter.SetDivId(divid, -1);
02814 painter.CreateCanvasSvg();
02815 painter.SetDivId(divid);
02816
02817 if (can==null) {
02818 JSROOT.Painter.drawFrame(divid, null);
02819 } else {
02820 painter.CheckColors(can);
02821 painter.DrawPrimitives();
02822 }
02823
02824 return painter;
02825 }
02826
02827 JSROOT.Painter.drawPad = function(divid, pad) {
02828
02829 var painter = new JSROOT.TPadPainter(pad, false);
02830 painter.SetDivId(divid);
02831
02832 painter.CreatePadSvg();
02833
02834 painter.pad_name = pad['fName'];
02835
02836
02837 var prev_name = painter.svg_canvas()['current_pad'];
02838 painter.svg_canvas()['current_pad'] = pad['fName'];
02839
02840 painter.DrawPrimitives();
02841
02842
02843 painter.svg_canvas()['current_pad'] = prev_name;
02844
02845 return painter;
02846 }
02847
02848
02849
02850 JSROOT.TColzPalettePainter = function(palette) {
02851 JSROOT.TObjectPainter.call(this, palette);
02852 this.palette = palette;
02853 }
02854
02855 JSROOT.TColzPalettePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
02856
02857 JSROOT.TColzPalettePainter.prototype.GetObject = function() {
02858 return this.palette;
02859 }
02860
02861 JSROOT.TColzPalettePainter.prototype.DrawPalette = function() {
02862 var palette = this.palette;
02863 var axis = palette['fAxis'];
02864
02865 var minbin = this.main_painter().minbin;
02866 var maxbin = this.main_painter().maxbin;
02867 var nbr1 = axis['fNdiv'] % 100;
02868 if (nbr1<=0) nbr1 = 8;
02869
02870 var width = Number(this.svg_pad(true).attr("width")),
02871 height = Number(this.svg_pad(true).attr("height"));
02872
02873 var s_height = Math.round(Math.abs(palette['fY2NDC'] - palette['fY1NDC']) * height);
02874
02875 var axisOffset = axis['fLabelOffset'] * width;
02876 var tickSize = axis['fTickSize'] * width;
02877
02878 var z = d3.scale.linear().clamp(true).domain([ minbin, maxbin ]).range( [ s_height, 0 ]).nice();
02879
02880 var labelfont = JSROOT.Painter.getFontDetails(axis['fLabelFont'], axis['fLabelSize'] * height);
02881
02882 var pos_x = Math.round(palette['fX1NDC'] * width);
02883 var pos_y = Math.round(height*(1 - palette['fY1NDC']));
02884
02885 var s_width = Math.round(Math.abs(palette['fX2NDC'] - palette['fX1NDC']) * width);
02886 pos_y -= s_height;
02887
02888
02889 this.RecreateDrawG(true, ".text_layer");
02890
02891 this.draw_g
02892 .attr("x", pos_x).attr("y", pos_y)
02893 .attr("width", s_width).attr("height", s_height)
02894 .attr("transform", "translate(" + pos_x + ", " + pos_y + ")");
02895
02896 var paletteColors = this.main_painter().paletteColors;
02897
02898
02899 var rectHeight = 1. * s_height / paletteColors.length;
02900
02901 this.draw_g.selectAll("colorRect")
02902 .data(paletteColors)
02903 .enter()
02904 .append("svg:rect")
02905 .attr("class", "colorRect")
02906 .attr("x", 0)
02907 .attr("y", function(d, i) { return (s_height - (i + 1) * rectHeight).toFixed(1); })
02908 .attr("width", s_width)
02909 .attr("height", rectHeight.toFixed(1))
02910 .attr("fill", function(d) { return d; })
02911 .attr("stroke", function(d) { return d; });
02912
02913
02914
02915
02916
02917 var z_axis = d3.svg.axis().scale(z)
02918 .orient("right")
02919 .tickPadding(axisOffset)
02920 .tickSize(-tickSize, -tickSize / 2, 0)
02921 .ticks(nbr1);
02922
02923 var zax = this.draw_g.append("svg:g")
02924 .attr("class", "zaxis")
02925 .attr("transform", "translate(" + s_width + ", 0)")
02926 .call(z_axis);
02927
02928 zax.selectAll("text")
02929 .call(labelfont.func)
02930 .attr("fill", JSROOT.Painter.root_colors[axis['fLabelColor']]);
02931
02932
02933
02934
02935 var title = axis['fTitle'];
02936 if (title != "" && typeof (axis['fTitleFont']) != 'undefined') {
02937 var titlefont = JSROOT.Painter.getFontDetails(axis['fTitleFont'], axis['fTitleSize'] * height);
02938 this.draw_g.append("text")
02939 .attr("class", "Z axis label")
02940 .attr("x", s_width + labelfont.size)
02941 .attr("y", s_height)
02942 .attr("text-anchor", "end")
02943 .call(titlefont.func);
02944 }
02945
02946 var pthis = this;
02947
02948 this.AddDrag("colz", this.draw_g, {
02949 move : function(x, y, dx, dy) {
02950
02951 pthis.draw_g.attr("transform", "translate(" + x + "," + y + ")");
02952
02953 pthis.palette['fX1NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
02954 pthis.palette['fX2NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
02955 pthis.palette['fY1NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
02956 pthis.palette['fY2NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
02957 },
02958 resize : function(width, height) {
02959 pthis.palette['fX2NDC'] = pthis.palette['fX1NDC'] + width / Number(pthis.svg_pad(true).attr("width"));
02960 pthis.palette['fY1NDC'] = pthis.palette['fY2NDC'] - height / Number(pthis.svg_pad(true).attr("height"));
02961
02962 pthis.RemoveDrawG();
02963 pthis.DrawPalette();
02964 }
02965 });
02966 }
02967
02968 JSROOT.TColzPalettePainter.prototype.Redraw = function() {
02969
02970 var enabled = true;
02971
02972 if ('options' in this.main_painter())
02973 enabled = (this.main_painter().options.Zscale > 0) && (this.main_painter().options.Color > 0);
02974
02975 if (enabled) {
02976 this.DrawPalette();
02977 } else {
02978
02979 this.RemoveDrawG();
02980 this.RemoveDrag("colz");
02981 }
02982 }
02983
02984 JSROOT.Painter.drawPaletteAxis = function(divid, palette) {
02985 var painter = new JSROOT.TColzPalettePainter(palette);
02986
02987 painter.SetDivId(divid);
02988
02989 painter.DrawPalette();
02990
02991 return painter;
02992 }
02993
02994
02995
02996 JSROOT.THistPainter = function(histo) {
02997 JSROOT.TObjectPainter.call(this, histo);
02998 this.histo = histo;
02999 this.shrink_frame_left = 0.;
03000 this.draw_content = true;
03001 this.nbinsx = 0;
03002 this.nbinsy = 0;
03003 }
03004
03005 JSROOT.THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
03006
03007 JSROOT.THistPainter.prototype.GetObject = function() {
03008 return this.histo;
03009 }
03010
03011 JSROOT.THistPainter.prototype.IsTProfile = function() {
03012 return this.histo && this.histo['_typename'] == 'TProfile';
03013 }
03014
03015 JSROOT.THistPainter.prototype.IsTH2Poly = function() {
03016 return this.histo && this.histo['_typename'].match(/^TH2Poly/);
03017 }
03018
03019 JSROOT.THistPainter.prototype.Dimension = function() {
03020 if (!this.histo) return 0;
03021 if ('fDimension' in this.histo) return this.histo['fDimension'];
03022 if (this.histo['_typename'].match(/^TH2/)) return 2;
03023 if (this.histo['_typename'].match(/^TH3/)) return 3;
03024 return 1;
03025 }
03026
03027 JSROOT.THistPainter.prototype.DecodeOptions = function(opt) {
03028 if ((opt == null) || (opt == "")) opt = this.histo['fOption'];
03029
03030
03031 var hdim = this.Dimension();
03032 var nch = opt.length;
03033 var option = {
03034 Axis: 0, Bar: 0, Curve: 0, Error: 0, Hist: 0, Line: 0,
03035 Mark: 0, Fill: 0, Same: 0, Scat: 0, Func: 0, Star: 0,
03036 Arrow: 0, Box: 0, Text: 0, Char: 0, Color: 0, Contour: 0,
03037 Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0,
03038 Spec: 0, Pie: 0, List: 0, Zscale: 0, FrontBox: 1, BackBox: 1,
03039 System: JSROOT.Painter.Coord.kCARTESIAN,
03040 HighRes: 0, Zero: 0, Logx: 0, Logy: 0, Logz: 0, Gridx: 0, Gridy: 0
03041 };
03042
03043 var chopt = opt.toUpperCase();
03044 chopt = JSROOT.Painter.clearCuts(chopt);
03045 if (hdim > 1) option.Scat = 1;
03046 if (!nch) option.Hist = 1;
03047 if (this.IsTProfile()) option.Error = 2;
03048 if ('fFunctions' in this.histo) option.Func = 1;
03049
03050 if (chopt.indexOf('LOGX') != -1) {
03051 option.Logx = 1;
03052 chopt = chopt.replace('LOGX', '');
03053 }
03054 if (chopt.indexOf('LOGY') != -1) {
03055 option.Logy = 1;
03056 chopt = chopt.replace('LOGY', '');
03057 }
03058
03059 var l = chopt.indexOf('SPEC');
03060 if (l != -1) {
03061 option.Scat = 0;
03062 chopt = chopt.replace('SPEC', ' ');
03063 var bs = 0;
03064 l = chopt.indexOf('BF(');
03065 if (l != -1) bs = parseInt(chopt)
03066 option.Spec = Math.max(1600, bs);
03067 return option;
03068 }
03069 if (chopt.indexOf('GL') != -1) chopt = chopt.replace('GL', ' ');
03070 if (chopt.indexOf('X+') != -1) {
03071 option.AxisPos = 10;
03072 chopt = chopt.replace('X+', ' ');
03073 }
03074 if (chopt.indexOf('Y+') != -1) {
03075 option.AxisPos += 1;
03076 chopt = chopt.replace('Y+', ' ');
03077 }
03078 if ((option.AxisPos == 10 || option.AxisPos == 1) && (nch == 2))
03079 option.Hist = 1;
03080 if (option.AxisPos == 11 && nch == 4)
03081 option.Hist = 1;
03082 if (chopt.indexOf('SAMES') != -1) {
03083 if (nch == 5) option.Hist = 1;
03084 option.Same = 2;
03085 chopt = chopt.replace('SAMES', ' ');
03086 }
03087 if (chopt.indexOf('SAME') != -1) {
03088 if (nch == 4) option.Hist = 1;
03089 option.Same = 1;
03090 chopt = chopt.replace('SAME', ' ');
03091 }
03092 if (chopt.indexOf('PIE') != -1) {
03093 option.Pie = 1;
03094 chopt = chopt.replace('PIE', ' ');
03095 }
03096 l = chopt.indexOf('LEGO');
03097 if (l != -1) {
03098 option.Scat = 0;
03099 option.Lego = 1;
03100 chopt = chopt.replace('LEGO', ' ');
03101 if (chopt[l + 4] == '1') {
03102 option.Lego = 11;
03103 chopt[l + 4] = ' ';
03104 }
03105 if (chopt[l + 4] == '2') {
03106 option.Lego = 12;
03107 chopt[l + 4] = ' ';
03108 }
03109 if (chopt[l + 4] == '3') {
03110 option.Lego = 13;
03111 chopt[l + 4] = ' ';
03112 }
03113 l = chopt.indexOf('FB');
03114 if (l != -1) {
03115 option.FrontBox = 0;
03116 chopt = chopt.replace('FB', ' ');
03117 }
03118 l = chopt.indexOf('BB');
03119 if (l != -1) {
03120 option.BackBox = 0;
03121 chopt = chopt.replace('BB', ' ');
03122 }
03123 l = chopt.indexOf('0');
03124 if (l != -1) {
03125 option.Zero = 1;
03126 chopt = chopt.replace('0', ' ');
03127 }
03128 }
03129 l = chopt.indexOf('SURF');
03130 if (l != -1) {
03131 option.Scat = 0;
03132 option.Surf = 1;
03133 chopt = chopt.replace('SURF', ' ');
03134 if (chopt[l + 4] == '1') {
03135 option.Surf = 11;
03136 chopt[l + 4] = ' ';
03137 }
03138 if (chopt[l + 4] == '2') {
03139 option.Surf = 12;
03140 chopt[l + 4] = ' ';
03141 }
03142 if (chopt[l + 4] == '3') {
03143 option.Surf = 13;
03144 chopt[l + 4] = ' ';
03145 }
03146 if (chopt[l + 4] == '4') {
03147 option.Surf = 14;
03148 chopt[l + 4] = ' ';
03149 }
03150 if (chopt[l + 4] == '5') {
03151 option.Surf = 15;
03152 chopt[l + 4] = ' ';
03153 }
03154 if (chopt[l + 4] == '6') {
03155 option.Surf = 16;
03156 chopt[l + 4] = ' ';
03157 }
03158 if (chopt[l + 4] == '7') {
03159 option.Surf = 17;
03160 chopt[l + 4] = ' ';
03161 }
03162 l = chopt.indexOf('FB');
03163 if (l != -1) {
03164 option.FrontBox = 0;
03165 chopt = chopt.replace('FB', ' ');
03166 }
03167 l = chopt.indexOf('BB');
03168 if (l != -1) {
03169 option.BackBox = 0;
03170 chopt = chopt.replace('BB', ' ');
03171 }
03172 }
03173 l = chopt.indexOf('TF3');
03174 if (l != -1) {
03175 l = chopt.indexOf('FB');
03176 if (l != -1) {
03177 option.FrontBox = 0;
03178 chopt = chopt.replace('FB', ' ');
03179 }
03180 l = chopt.indexOf('BB');
03181 if (l != -1) {
03182 option.BackBox = 0;
03183 chopt = chopt.replace('BB', ' ');
03184 }
03185 }
03186 l = chopt.indexOf('ISO');
03187 if (l != -1) {
03188 l = chopt.indexOf('FB');
03189 if (l != -1) {
03190 option.FrontBox = 0;
03191 chopt = chopt.replace('FB', ' ');
03192 }
03193 l = chopt.indexOf('BB');
03194 if (l != -1) {
03195 option.BackBox = 0;
03196 chopt = chopt.replace('BB', ' ');
03197 }
03198 }
03199 l = chopt.indexOf('LIST');
03200 if (l != -1) {
03201 option.List = 1;
03202 chopt = chopt.replace('LIST', ' ');
03203 }
03204 l = chopt.indexOf('CONT');
03205 if (l != -1) {
03206 chopt = chopt.replace('CONT', ' ');
03207 if (hdim > 1) {
03208 option.Scat = 0;
03209 option.Contour = 1;
03210 if (chopt[l + 4] == '1') {
03211 option.Contour = 11;
03212 chopt[l + 4] = ' ';
03213 }
03214 if (chopt[l + 4] == '2') {
03215 option.Contour = 12;
03216 chopt[l + 4] = ' ';
03217 }
03218 if (chopt[l + 4] == '3') {
03219 option.Contour = 13;
03220 chopt[l + 4] = ' ';
03221 }
03222 if (chopt[l + 4] == '4') {
03223 option.Contour = 14;
03224 chopt[l + 4] = ' ';
03225 }
03226 if (chopt[l + 4] == '5') {
03227 option.Contour = 15;
03228 chopt[l + 4] = ' ';
03229 }
03230 } else {
03231 option.Hist = 1;
03232 }
03233 }
03234 l = chopt.indexOf('HBAR');
03235 if (l != -1) {
03236 option.Hist = 0;
03237 option.Bar = 20;
03238 chopt = chopt.replace('HBAR', ' ');
03239 if (chopt[l + 4] == '1') {
03240 option.Bar = 21;
03241 chopt[l + 4] = ' ';
03242 }
03243 if (chopt[l + 4] == '2') {
03244 option.Bar = 22;
03245 chopt[l + 4] = ' ';
03246 }
03247 if (chopt[l + 4] == '3') {
03248 option.Bar = 23;
03249 chopt[l + 4] = ' ';
03250 }
03251 if (chopt[l + 4] == '4') {
03252 option.Bar = 24;
03253 chopt[l + 4] = ' ';
03254 }
03255 }
03256 l = chopt.indexOf('BAR');
03257 if (l != -1) {
03258 option.Hist = 0;
03259 option.Bar = 10;
03260 chopt = chopt.replace('BAR', ' ');
03261 if (chopt[l + 3] == '1') {
03262 option.Bar = 11;
03263 chopt[l + 3] = ' ';
03264 }
03265 if (chopt[l + 3] == '2') {
03266 option.Bar = 12;
03267 chopt[l + 3] = ' ';
03268 }
03269 if (chopt[l + 3] == '3') {
03270 option.Bar = 13;
03271 chopt[l + 3] = ' ';
03272 }
03273 if (chopt[l + 3] == '4') {
03274 option.Bar = 14;
03275 chopt[l + 3] = ' ';
03276 }
03277 }
03278 l = chopt.indexOf('ARR');
03279 if (l != -1) {
03280 chopt = chopt.replace('ARR', ' ');
03281 if (hdim > 1) {
03282 option.Arrow = 1;
03283 option.Scat = 0;
03284 } else {
03285 option.Hist = 1;
03286 }
03287 }
03288 l = chopt.indexOf('BOX');
03289 if (l != -1) {
03290 chopt = chopt.replace('BOX', ' ');
03291 if (hdim > 1) {
03292 Hoption.Scat = 0;
03293 Hoption.Box = 1;
03294 if (chopt[l + 3] == '1') {
03295 option.Box = 11;
03296 chopt[l + 3] = ' ';
03297 }
03298 } else {
03299 option.Hist = 1;
03300 }
03301 }
03302
03303 l = chopt.indexOf('COL');
03304 if (l!=-1) {
03305 var name = 'COL';
03306
03307 if (chopt.charAt(l+3)=='1') { option.Color = 1; name += "1"; l++; } else
03308 if (chopt.charAt(l+3)=='2') { option.Color = 2; name += "2"; l++; } else
03309 if (chopt.charAt(l+3)=='3') { option.Color = 3; name += "3"; l++; } else
03310 option.Color = JSROOT.gStyle.DefaultCol;
03311
03312 if (chopt.charAt(l+4)=='Z') { option.Zscale = 1; name += 'Z'; }
03313 chopt = chopt.replace(name, '');
03314 if (hdim == 1) {
03315 option.Hist = 1;
03316 } else {
03317 option.Scat = 0;
03318 }
03319 }
03320
03321 if (chopt.indexOf('CHAR') != -1) {
03322 option.Char = 1;
03323 chopt = chopt.replace('CHAR', ' ');
03324 option.Scat = 0;
03325 }
03326 l = chopt.indexOf('FUNC');
03327 if (l != -1) {
03328 option.Func = 2;
03329 chopt = chopt.replace('FUNC', ' ');
03330 option.Hist = 0;
03331 }
03332 l = chopt.indexOf('HIST');
03333 if (l != -1) {
03334 option.Hist = 2;
03335 chopt = chopt.replace('HIST', ' ');
03336 option.Func = 0;
03337 option.Error = 0;
03338 }
03339 if (chopt.indexOf('AXIS') != -1) {
03340 option.Axis = 1;
03341 chopt = chopt.replace('AXIS', ' ');
03342 }
03343 if (chopt.indexOf('AXIG') != -1) {
03344 option.Axis = 2;
03345 chopt = chopt.replace('AXIG', ' ');
03346 }
03347 if (chopt.indexOf('SCAT') != -1) {
03348 option.Scat = 1;
03349 chopt = chopt.replace('SCAT', ' ');
03350 }
03351 l = chopt.indexOf('TEXT');
03352 if (l != -1) {
03353 var angle = parseInt(chopt);
03354 if (!isNaN(angle)) {
03355 if (angle < 0)
03356 angle = 0;
03357 if (angle > 90)
03358 angle = 90;
03359 option.Text = 1000 + angle;
03360 } else {
03361 option.Text = 1;
03362 }
03363 chopt = chopt.replace('TEXT', ' ');
03364 l = chopt.indexOf('N');
03365 if (l != -1 && this.IsTH2Poly())
03366 option.Text += 3000;
03367 option.Scat = 0;
03368 }
03369 if (chopt.indexOf('POL') != -1) {
03370 option.System = JSROOT.Painter.Coord.kPOLAR;
03371 chopt = chopt.replace('POL', ' ');
03372 }
03373 if (chopt.indexOf('CYL') != -1) {
03374 option.System = JSROOT.Painter.Coord.kCYLINDRICAL;
03375 chopt = chopt.replace('CYL', ' ');
03376 }
03377 if (chopt.indexOf('SPH') != -1) {
03378 option.System = JSROOT.Painter.Coord.kSPHERICAL;
03379 chopt = chopt.replace('SPH', ' ');
03380 }
03381 l = chopt.indexOf('PSR');
03382 if (l != -1) {
03383 option.System = JSROOT.Painter.Coord.kRAPIDITY;
03384 chopt = chopt.replace('PSR', ' ');
03385 }
03386 l = chopt.indexOf('TRI');
03387 if (l != -1) {
03388 option.Scat = 0;
03389 option.Color = 0;
03390 option.Tri = 1;
03391 chopt = chopt.replace('TRI', ' ');
03392 l = chopt.indexOf('FB');
03393 if (l != -1) {
03394 option.FrontBox = 0;
03395 chopt = chopt.replace('FB', ' ');
03396 }
03397 l = chopt.indexOf('BB');
03398 if (l != -1) {
03399 option.BackBox = 0;
03400 chopt = chopt.replace('BB', ' ');
03401 }
03402 l = chopt.indexOf('ERR');
03403 if (l != -1)
03404 chopt = chopt.replace('ERR', ' ');
03405 }
03406 l = chopt.indexOf('AITOFF');
03407 if (l != -1) {
03408 Hoption.Proj = 1;
03409 chopt = chopt.replace('AITOFF', ' ');
03410 }
03411 l = chopt.indexOf('MERCATOR');
03412 if (l != -1) {
03413 option.Proj = 2;
03414 chopt = chopt.replace('MERCATOR', ' ');
03415 }
03416 l = chopt.indexOf('SINUSOIDAL');
03417 if (l != -1) {
03418 option.Proj = 3;
03419 chopt = chopt.replace('SINUSOIDAL', ' ');
03420
03421 }
03422 l = chopt.indexOf('PARABOLIC');
03423 if (l != -1) {
03424 option.Proj = 4;
03425 chopt = chopt.replace('PARABOLIC', ' ');
03426
03427 }
03428 if (option.Proj > 0) {
03429 option.Scat = 0;
03430 option.Contour = 14;
03431 }
03432 if (chopt.indexOf('A') != -1)
03433 option.Axis = -1;
03434 if (chopt.indexOf('B') != -1)
03435 option.Bar = 1;
03436 if (chopt.indexOf('C') != -1) {
03437 option.Curve = 1;
03438 option.Hist = -1;
03439 }
03440 if (chopt.indexOf('F') != -1)
03441 option.Fill = 1;
03442 if (chopt.indexOf('][') != -1) {
03443 option.Off = 1;
03444 option.Hist = 1;
03445 }
03446 if (chopt.indexOf('F2') != -1) option.Fill = 2;
03447 if (chopt.indexOf('L') != -1) {
03448 option.Line = 1;
03449 option.Hist = -1;
03450 }
03451 if (chopt.indexOf('P') != -1) {
03452 option.Mark = 1;
03453 option.Hist = -1;
03454 }
03455 if (chopt.indexOf('Z') != -1) option.Zscale = 1;
03456 if (chopt.indexOf('*') != -1) option.Star = 1;
03457 if (chopt.indexOf('H') != -1) option.Hist = 2;
03458 if (chopt.indexOf('P0') != -1) option.Mark = 10;
03459 if (this.IsTH2Poly()) {
03460 if (option.Fill + option.Line + option.Mark != 0) option.Scat = 0;
03461 }
03462
03463 if (chopt.indexOf('E') != -1) {
03464 if (hdim == 1) {
03465 option.Error = 1;
03466 if (chopt.indexOf('E0') != -1) option.Error = 10;
03467 if (chopt.indexOf('E1') != -1) option.Error = 11;
03468 if (chopt.indexOf('E2') != -1) option.Error = 12;
03469 if (chopt.indexOf('E3') != -1) option.Error = 13;
03470 if (chopt.indexOf('E4') != -1) option.Error = 14;
03471 if (chopt.indexOf('E5') != -1) option.Error = 15;
03472 if (chopt.indexOf('E6') != -1) option.Error = 16;
03473 if (chopt.indexOf('X0') != -1) {
03474 if (option.Error == 1) option.Error += 20;
03475 option.Error += 10;
03476 }
03477 if (option.Text && this.IsTProfile()) {
03478 option.Text += 2000;
03479 option.Error = 0;
03480 }
03481 } else {
03482 if (option.Error == 0) {
03483 option.Error = 100;
03484 option.Scat = 0;
03485 }
03486 if (option.Text) {
03487 option.Text += 2000;
03488 option.Error = 0;
03489 }
03490 }
03491 }
03492 if (chopt.indexOf('9') != -1) option.HighRes = 1;
03493 if (option.Surf == 15) {
03494 if (option.System == JSROOT.Painter.Coord.kPOLAR
03495 || option.System == JSROOT.Painter.Coord.kCARTESIAN) {
03496 option.Surf = 13;
03497
03498
03499 }
03500 }
03501
03502
03503 if (option.Bar == 1) option.Hist = -1;
03504
03505 return option;
03506 }
03507
03508 JSROOT.THistPainter.prototype.ScanContent = function() {
03509
03510
03511
03512
03513 alert("HistPainter.prototype.ScanContent not implemented");
03514 }
03515
03516 JSROOT.THistPainter.prototype.CheckPadOptions = function() {
03517
03518 var pad = this.root_pad();
03519
03520 if (pad!=null) {
03521
03522 this.options.Logx = pad['fLogx'];
03523 this.options.Logy = pad['fLogy'];
03524 this.options.Logz = pad['fLogz'];
03525 this.options.Gridx = pad['fGridx'];
03526 this.options.Gridy = pad['fGridy'];
03527 }
03528
03529 if (this.main_painter() !== this) return;
03530
03531 this['zoom_xmin'] = 0;
03532 this['zoom_xmax'] = 0;
03533 this['zoom_xpad'] = true;
03534
03535 this['zoom_ymin'] = 0;
03536 this['zoom_ymax'] = 0;
03537 this['zoom_ypad'] = true;
03538
03539 if ((pad!=null) && ('fUxmin' in pad) && !this.create_canvas) {
03540 this['zoom_xmin'] = pad.fUxmin;
03541 this['zoom_xmax'] = pad.fUxmax;
03542 this['zoom_ymin'] = pad.fUymin;
03543 this['zoom_ymax'] = pad.fUymax;
03544
03545 if (pad.fLogx > 0) {
03546 this['zoom_xmin'] = Math.exp(this['zoom_xmin'] * Math.log(10));
03547 this['zoom_xmax'] = Math.exp(this['zoom_xmax'] * Math.log(10));
03548 }
03549
03550 if (pad.fLogy > 0) {
03551 this['zoom_ymin'] = Math.exp(this['zoom_ymin'] * Math.log(10));
03552 this['zoom_ymax'] = Math.exp(this['zoom_ymax'] * Math.log(10));
03553 }
03554 }
03555 }
03556
03557
03558 JSROOT.THistPainter.prototype.UpdateObject = function(obj) {
03559 if (obj['_typename'] != this.histo['_typename']) {
03560 alert("JSROOT.THistPainter.UpdateObject - wrong class " + obj['_typename'] + " expected " + this.histo['_typename']);
03561 return false;
03562 }
03563
03564
03565
03566
03567
03568
03569
03570
03571 this.histo['fArray'] = obj['fArray'];
03572 this.histo['fN'] = obj['fN'];
03573 this.histo['fTitle'] = obj['fTitle'];
03574 this.histo['fXaxis']['fNbins'] = obj['fXaxis']['fNbins'];
03575 this.histo['fXaxis']['fXmin'] = obj['fXaxis']['fXmin'];
03576 this.histo['fXaxis']['fXmax'] = obj['fXaxis']['fXmax'];
03577 this.histo['fYaxis']['fXmin'] = obj['fYaxis']['fXmin'];
03578 this.histo['fYaxis']['fXmax'] = obj['fYaxis']['fXmax'];
03579
03580 if (this.IsTProfile()) {
03581 this.histo['fBinEntries'] = obj['fBinEntries'];
03582 this.histo['fSumw2'] = obj['fSumw2'];
03583 }
03584
03585 this.ScanContent();
03586
03587 return true;
03588 }
03589
03590 JSROOT.THistPainter.prototype.CreateXY = function() {
03591
03592
03593
03594 if (!this.is_main_painter()) {
03595 this['x'] = this.main_painter()['x'];
03596 this['y'] = this.main_painter()['y'];
03597 return;
03598 }
03599
03600 var w = Number(this.svg_frame(true).attr("width")),
03601 h = Number(this.svg_frame(true).attr("height"));
03602
03603 this['scale_xmin'] = this.xmin;
03604 this['scale_xmax'] = this.xmax;
03605 if (this.zoom_xmin != this.zoom_xmax) {
03606 this['scale_xmin'] = this.zoom_xmin;
03607 this['scale_xmax'] = this.zoom_xmax;
03608 }
03609
03610 if (this.options.Logx) {
03611 if (this.scale_xmax <= 0) this.scale_xmax = 0;
03612
03613 if ((this.scale_xmin <= 0) && (this.nbinsx>0))
03614 for (var i=0;i<this.nbinsx;i++) {
03615 var left = this.xmin + i*this.binwidthx;
03616 if (left>0) { this.scale_xmin = left; break; }
03617 }
03618
03619 if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) {
03620 this.scale_xmin = this.scale_xmax * 0.0001;
03621 }
03622
03623 this['x'] = d3.scale.log().domain([ this.scale_xmin, this.scale_xmax ]).range([ 0, w ]);
03624 } else {
03625 this['x'] = d3.scale.linear().domain([ this.scale_xmin, this.scale_xmax ]).range([ 0, w ]);
03626 }
03627
03628 this['scale_ymin'] = this.ymin;
03629 this['scale_ymax'] = this.ymax;
03630
03631 if (this.zoom_ypad) {
03632 if (this.histo.fMinimum != -1111) this.zoom_ymin = this.histo.fMinimum;
03633 if (this.histo.fMaximum != -1111) this.zoom_ymax = this.histo.fMaximum;
03634 this['zoom_ypad'] = false;
03635 }
03636
03637 if (this.zoom_ymin != this.zoom_ymax) {
03638 this['scale_ymin'] = this.zoom_ymin;
03639 this['scale_ymax'] = this.zoom_ymax;
03640 }
03641
03642 if (this.options.Logy) {
03643 if (this.scale_ymax <= 0) this.scale_ymax = 1;
03644
03645 if ((this.scale_ymin <= 0) && (this.nbinsy>0))
03646 for (var i=0;i<this.nbinsy;i++) {
03647 var down = this.ymin + i*this.binwidthy;
03648 if (down>0) { this.scale_ymin = down; break; }
03649 }
03650
03651 if ((this.scale_ymin <= 0) && ('ymin_nz' in this) && (this.ymin_nz > 0))
03652 this.scale_ymin = 0.3*this.ymin_nz;
03653
03654 if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax))
03655 this.scale_ymin = 0.000001 * this.scale_ymax;
03656 this['y'] = d3.scale.log().domain([ this.scale_ymin, this.scale_ymax ]).range([ h, 0 ]);
03657 } else {
03658 this['y'] = d3.scale.linear().domain([ this.scale_ymin, this.scale_ymax ]).range([ h, 0 ]);
03659 }
03660 }
03661
03662 JSROOT.THistPainter.prototype.DrawGrids = function() {
03663
03664 if (!this.is_main_painter()) return;
03665
03666 var layer = this.svg_frame(true).select(".grid_layer");
03667
03668 layer.selectAll(".xgrid").remove();
03669 layer.selectAll(".ygrid").remove();
03670
03671
03672
03673 if (this.options.Gridx) {
03674
03675 var h = Number(this.svg_frame(true).attr("height"));
03676
03677 var xticks = this.x.ticks(this.x_nticks);
03678
03679 layer.selectAll(".xgrid")
03680 .data(xticks).enter()
03681 .append("svg:line")
03682 .attr("class", "xgrid")
03683 .attr("x1", this.x)
03684 .attr("y1", h)
03685 .attr("x2", this.x)
03686 .attr("y2",0)
03687 .style("stroke", "black")
03688 .style("stroke-width", 1)
03689 .style("stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
03690 }
03691
03692
03693 if (this.options.Gridy) {
03694 var w = Number(this.svg_frame(true).attr("width"));
03695
03696 var yticks = this.y.ticks(this.y_nticks);
03697
03698 layer.selectAll('.ygrid')
03699 .data(yticks).enter()
03700 .append("svg:line")
03701 .attr("class", "ygrid")
03702 .attr("x1", 0)
03703 .attr("y1", this.y)
03704 .attr("x2", w)
03705 .attr("y2", this.y)
03706 .style("stroke", "black")
03707 .style("stroke-width", 1)
03708 .style("stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
03709 }
03710 }
03711
03712 JSROOT.THistPainter.prototype.DrawBins = function() {
03713 alert("HistPainter.DrawBins not implemented");
03714 }
03715
03716 JSROOT.THistPainter.prototype.AxisAsText = function(axis, value) {
03717 if (axis == "x") {
03718
03719 if ('dfx' in this) {
03720 return this.dfx(new Date(this.timeoffsetx + value * 1000));
03721 }
03722
03723 if (Math.abs(value) < 1e-14)
03724 if (Math.abs(this.xmax - this.xmin) > 1e-5)
03725 value = 0;
03726 return value.toPrecision(4);
03727 }
03728
03729 if (axis == "y") {
03730 if ('dfy' in this) {
03731 return this.dfy(new Date(this.timeoffsety + value * 1000));
03732 }
03733 if (Math.abs(value) < 1e-14)
03734 if (Math.abs(this.ymax - this.ymin) > 1e-5)
03735 value = 0;
03736 return value.toPrecision(4);
03737 }
03738
03739 return value.toPrecision(4);
03740 }
03741
03742 JSROOT.THistPainter.prototype.DrawAxes = function(shrink_forbidden) {
03743
03744
03745 if (!this.is_main_painter()) return;
03746
03747 var w = Number(this.svg_frame(true).attr("width")),
03748 h = Number(this.svg_frame(true).attr("height"));
03749 var noexpx = this.histo['fXaxis'].TestBit(JSROOT.EAxisBits.kNoExponent);
03750 var noexpy = this.histo['fYaxis'].TestBit(JSROOT.EAxisBits.kNoExponent);
03751 var moreloglabelsx = this.histo['fXaxis'].TestBit(JSROOT.EAxisBits.kMoreLogLabels);
03752 var moreloglabelsy = this.histo['fYaxis'].TestBit(JSROOT.EAxisBits.kMoreLogLabels);
03753 if (this.histo['fXaxis']['fXmax'] < 100 && this.histo['fXaxis']['fXmax'] / this.histo['fXaxis']['fXmin'] < 100) noexpx = true;
03754 if (this.histo['fYaxis']['fXmax'] < 100 && this.histo['fYaxis']['fXmax'] / this.histo['fYaxis']['fXmin'] < 100) noexpy = true;
03755
03756 var xax_g = this.svg_frame(true).selectAll(".xaxis_container");
03757 if (xax_g.empty())
03758 xax_g = this.svg_frame(true).select(".axis_layer").append("svg:g").attr("class","xaxis_container");
03759
03760 xax_g.selectAll("*").remove();
03761 xax_g.attr("transform", "translate(0," + h + ")");
03762
03763 var yax_g = this.svg_frame(true).selectAll(".yaxis_container");
03764 if (yax_g.empty()) yax_g = this.svg_frame(true).select(".axis_layer").append("svg:g").attr("class", "yaxis_container");
03765 yax_g.selectAll("*").remove();
03766
03767 var x_axis = null, y_axis = null;
03768
03769 var ndivx = this.histo['fXaxis']['fNdivisions'];
03770 this['x_nticks'] = ndivx % 100;
03771 var n2ax = (ndivx % 10000 - this.x_nticks) / 100;
03772 var n3ax = ndivx / 10000;
03773
03774 var ndivy = this.histo['fYaxis']['fNdivisions'];
03775 this['y_nticks'] = ndivy % 100;
03776 var n2ay = (ndivy % 10000 - this.y_nticks) / 100;
03777 var n3ay = ndivy / 10000;
03778
03779
03780 var label = JSROOT.Painter.translateLaTeX(this.histo['fXaxis']['fTitle']);
03781 var xAxisLabelOffset = 3 + (this.histo['fXaxis']['fLabelOffset'] * h);
03782
03783 var xlabelfont = JSROOT.Painter.getFontDetails(this.histo['fXaxis']['fLabelFont'], this.histo['fXaxis']['fLabelSize'] * h);
03784
03785 var ylabelfont = JSROOT.Painter.getFontDetails(this.histo['fYaxis']['fLabelFont'], this.histo['fYaxis']['fLabelSize'] * h);
03786
03787 if (label.length > 0) {
03788 var xtitlefont = JSROOT.Painter.getFontDetails(this.histo['fXaxis']['fTitleFont'], this.histo['fXaxis']['fTitleSize'] * h);
03789 xax_g.append("text")
03790 .attr("class", "x_axis_label")
03791 .attr("x", w)
03792 .attr("y", xlabelfont.size + xAxisLabelOffset * this.histo['fXaxis']['fTitleOffset'] + xtitlefont.size)
03793 .attr("text-anchor", "end")
03794 .call(xtitlefont.func)
03795 .text(label);
03796 }
03797
03798
03799 label = JSROOT.Painter.translateLaTeX(this.histo['fYaxis']['fTitle']);
03800
03801 var yAxisLabelOffset = 3 + (this.histo['fYaxis']['fLabelOffset'] * w);
03802
03803 if (label.length > 0) {
03804 var ytitlefont = JSROOT.Painter.getFontDetails(this.histo['fYaxis']['fTitleFont'], this.histo['fYaxis']['fTitleSize'] * h);
03805 yax_g.append("text")
03806 .attr("class", "y_axis_label")
03807 .attr("x", 0)
03808 .attr("y", - ylabelfont.size - ytitlefont.size - yAxisLabelOffset * this.histo['fYaxis']['fTitleOffset'])
03809 .call(ytitlefont.func)
03810 .attr("text-anchor", "end")
03811 .text(label)
03812 .attr("transform", "rotate(270, 0, 0)");
03813 }
03814
03815 var xAxisColor = this.histo['fXaxis']['fAxisColor'];
03816 var xDivLength = this.histo['fXaxis']['fTickLength'] * h;
03817 var yAxisColor = this.histo['fYaxis']['fAxisColor'];
03818 var yDivLength = this.histo['fYaxis']['fTickLength'] * w;
03819
03820 var pthis = this;
03821
03822
03823
03824
03825 var xrange = this.xmax - this.xmin;
03826 if (this.histo['fXaxis']['fTimeDisplay']) {
03827 if (this.x_nticks > 8) this.x_nticks = 8;
03828
03829 var timeformatx = JSROOT.Painter.getTimeFormat(this.histo['fXaxis']);
03830
03831 this['timeoffsetx'] = JSROOT.Painter.getTimeOffset(this.histo['fXaxis']);
03832
03833 var scale_xrange = this.scale_xmax - this.scale_xmin;
03834
03835 if ((timeformatx.length == 0) || (scale_xrange < 0.1 * xrange)) {
03836 timeformatx = JSROOT.Painter.chooseTimeFormat(scale_xrange, this.x_nticks);
03837 }
03838
03839 this['dfx'] = d3.time.format(timeformatx);
03840
03841 x_axis = d3.svg.axis().scale(this.x).orient("bottom")
03842 .tickPadding(xAxisLabelOffset)
03843 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
03844 .tickFormat(function(d) { return pthis.dfx(new Date(pthis.timeoffsetx + d * 1000)); })
03845 .ticks(this.x_nticks);
03846 } else if (this.options.Logx) {
03847 x_axis = d3.svg.axis().scale(this.x).orient("bottom")
03848 .tickPadding(xAxisLabelOffset)
03849 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
03850 .tickFormat(function(d) {
03851 var val = parseFloat(d);
03852 var vlog = Math.abs(JSROOT.Math.log10(val));
03853 if (moreloglabelsx) {
03854 if (vlog % 1 < 0.7 || vlog % 1 > 0.9999) {
03855 if (noexpx)
03856 return val.toFixed();
03857 else
03858 return JSROOT.Painter.formatExp(val.toExponential(0));
03859 } else
03860 return null;
03861 } else {
03862 if (vlog % 1 < 0.0001 || vlog % 1 > 0.9999) {
03863 if (noexpx)
03864 return val.toFixed();
03865 else
03866 return JSROOT.Painter.formatExp(val.toExponential(0));
03867 } else
03868 return null;
03869 }
03870 });
03871 } else {
03872 x_axis = d3.svg.axis()
03873 .scale(this.x)
03874 .orient("bottom")
03875 .tickPadding(xAxisLabelOffset)
03876 .tickSize(-xDivLength, -xDivLength / 2, -xDivLength / 4)
03877 .tickFormat(function(d) {
03878
03879 if ((Math.abs(d) < 1e-14) && (Math.abs(xrange) > 1e-5)) d = 0;
03880 return parseFloat(d.toPrecision(12)); })
03881 .ticks(this.x_nticks);
03882 }
03883
03884 var yrange = this.ymax - this.ymin;
03885 if (this.histo['fYaxis']['fTimeDisplay']) {
03886 if (this.y_nticks > 8) this.y_nticks = 8;
03887 var timeformaty = JSROOT.Painter.getTimeFormat(this.histo['fYaxis']);
03888
03889 this['timeoffsety'] = JSROOT.Painter
03890 .getTimeOffset(this.histo['fYaxis']);
03891
03892 var scale_yrange = this.scale_ymax - this.scale_ymin;
03893
03894 if ((timeformaty.length == 0) || (scale_yrange < 0.1 * yrange))
03895 timeformaty = JSROOT.Painter.chooseTimeFormat(scale_yrange, this.y_nticks);
03896
03897 this['dfy'] = d3.time.format(timeformaty);
03898
03899 y_axis = d3.svg.axis()
03900 .scale(this.y)
03901 .orient("left")
03902 .tickPadding(yAxisLabelOffset)
03903 .tickSize(-yDivLength, -yDivLength / 2,-yDivLength / 4)
03904 .tickFormat(function(d) { return pthis.dfy(new Date(pthis.timeoffsety + d * 1000)); })
03905 .ticks(this.y_nticks);
03906 } else if (this.options.Logy) {
03907 y_axis = d3.svg.axis()
03908 .scale(this.y)
03909 .orient("left")
03910 .tickPadding(yAxisLabelOffset)
03911 .tickSize(-yDivLength, -yDivLength / 2, -yDivLength / 4)
03912 .tickFormat(function(d) {
03913 var val = parseFloat(d);
03914 var vlog = Math.abs(JSROOT.Math.log10(val));
03915 if (moreloglabelsy) {
03916 if (vlog % 1 < 0.7 || vlog % 1 > 0.9999) {
03917 if (noexpy)
03918 return val.toFixed();
03919 else
03920 return JSROOT.Painter.formatExp(val.toExponential(0));
03921 } else
03922 return null;
03923 } else {
03924 if (vlog % 1 < 0.0001 || vlog % 1 > 0.9999) {
03925 if (noexpy)
03926 return val.toFixed();
03927 else
03928 return JSROOT.Painter.formatExp(val.toExponential(0));
03929 } else
03930 return null;
03931 }
03932 });
03933 } else {
03934 if (this.y_nticks >= 10) this.y_nticks -= 2;
03935 y_axis = d3.svg.axis()
03936 .scale(this.y)
03937 .orient("left")
03938 .tickPadding(yAxisLabelOffset)
03939 .tickSize(-yDivLength, -yDivLength / 2,-yDivLength / 4)
03940 .tickFormat(function(d) {
03941 if ((Math.abs(d) < 1e-14) && (Math.abs(yrange) > 1e-5)) d = 0;
03942 return parseFloat(d.toPrecision(12)); })
03943 .ticks(this.y_nticks);
03944 }
03945
03946 xax_g.append("svg:g").attr("class", "xaxis").call(x_axis);
03947
03948
03949 if ((n2ax > 0) && !this.options.Logx) {
03950 var x_axis_sub =
03951 d3.svg.axis().scale(this.x).orient("bottom")
03952 .tickPadding(xAxisLabelOffset).innerTickSize(-xDivLength / 2)
03953 .tickFormat(function(d) { return; })
03954 .ticks(this.x.ticks(this.x_nticks).length * n2ax);
03955
03956 xax_g.append("svg:g").attr("class", "xaxis").call(x_axis_sub);
03957 }
03958
03959 yax_g.append("svg:g").attr("class", "yaxis").call(y_axis);
03960
03961
03962 if ((n2ay > 0) && !this.options.Logy) {
03963 var y_axis_sub = d3.svg.axis().scale(this.y).orient("left")
03964 .tickPadding(yAxisLabelOffset).innerTickSize(-yDivLength / 2)
03965 .tickFormat(function(d) { return; })
03966 .ticks(this.y.ticks(this.y_nticks).length * n2ay);
03967
03968 yax_g.append("svg:g").attr("class", "yaxis").call(y_axis_sub);
03969 }
03970
03971 xax_g.selectAll("text").call(xlabelfont.func);
03972
03973 yax_g.selectAll("text").call(ylabelfont.func);
03974
03975
03976 if (JSROOT.gStyle.Zooming) {
03977 xax_g.append("svg:rect")
03978 .attr("class", "xaxis_zoom")
03979 .attr("x", 0)
03980 .attr("y", 0)
03981 .attr("width", w)
03982 .attr("height", xlabelfont.size + 3)
03983 .style('opacity', "0");
03984
03985
03986 yax_g.append("svg:rect")
03987 .attr("class", "yaxis_zoom")
03988 .attr("x",-2 * ylabelfont.size - 3)
03989 .attr("y", 0)
03990 .attr("width", 2 * ylabelfont.size + 3)
03991 .attr("height", h)
03992 .style('opacity', "0");
03993 }
03994
03995 if ((shrink_forbidden==null) && typeof yax_g.node()['getBoundingClientRect'] == 'function') {
03996
03997 var rect1 = yax_g.node().getBoundingClientRect();
03998 var rect2 = this.svg_pad().getBoundingClientRect();
03999 var position = rect1.left - rect2.left;
04000
04001 var shrink = 0.;
04002
04003 if (position < 0) {
04004 shrink = -position/w + 0.001;
04005 this.shrink_frame_left += shrink;
04006 } else
04007 if ((this.shrink_frame_left > 0) && (position/w > this.shrink_frame_left)) {
04008 shrink = -this.shrink_frame_left;
04009 this.shrink_frame_left = 0.;
04010 }
04011
04012 if (shrink != 0) {
04013 this.svg_frame()['frame_painter'].Shrink(shrink, 0);
04014 this.svg_frame()['frame_painter'].Redraw();
04015 this.CreateXY();
04016 this.DrawAxes(true);
04017 }
04018 }
04019 }
04020
04021 JSROOT.THistPainter.prototype.DrawTitle = function() {
04022
04023 var painter = this.FindPainterFor(null,"title");
04024
04025 if (painter!=null) {
04026 painter.pavetext.Clear();
04027 painter.pavetext.AddText(this.histo['fTitle']);
04028 } else {
04029
04030 var pavetext = JSROOT.Create("TPaveText");
04031
04032 jQuery.extend(pavetext, { fName: "title",
04033 fX1NDC: 0.2809483, fY1NDC: 0.9339831,
04034 fX2NDC: 0.7190517, fY2NDC: 0.995});
04035 pavetext.AddText(this.histo['fTitle']);
04036
04037 painter = JSROOT.Painter.drawPaveText(this.divid, pavetext);
04038 }
04039 }
04040
04041 JSROOT.THistPainter.prototype.ToggleStat = function() {
04042
04043 var stat = this.FindStat();
04044
04045 if (stat == null) {
04046
04047
04048 stat = this.CreateStat();
04049
04050 this.Redraw();
04051
04052 return;
04053 }
04054
04055 var statpainter = this.FindPainterFor(stat);
04056 if (statpainter == null) {
04057 alert("Did not found painter for existing stat??");
04058 return;
04059 }
04060
04061 statpainter.Enabled = !statpainter.Enabled;
04062
04063
04064
04065 statpainter.Redraw();
04066 }
04067
04068 JSROOT.THistPainter.prototype.GetSelectIndex = function(axis, size, add) {
04069
04070 var indx = 0;
04071 var obj = this.main_painter();
04072 if (obj == null) obj = this;
04073 var nbin = 0;
04074 if (!add) add = 0;
04075
04076 if (axis == "x") {
04077 nbin = this.nbinsx;
04078 if (obj.zoom_xmin != obj.zoom_xmax) {
04079 if (size == "left")
04080 indx = Math.floor((obj.zoom_xmin - this.xmin) / this.binwidthx + add);
04081 else
04082 indx = Math.round((obj.zoom_xmax - this.xmin) / this.binwidthx + 0.5 + add);
04083 } else {
04084 indx = (size == "left") ? 0 : nbin;
04085 }
04086
04087 } else
04088 if (axis == "y") {
04089 nbin = this.nbinsy;
04090 if (obj.zoom_ymin != obj.zoom_ymax) {
04091 if (size == "left")
04092 indx = Math.floor((obj.zoom_ymin - this.ymin) / this.binwidthy + add);
04093 else
04094 indx = Math.round((obj.zoom_ymax - this.ymin) / this.binwidthy + 0.5 + add);
04095 } else {
04096 indx = (size == "left") ? 0 : nbin;
04097 }
04098 }
04099
04100 if (size == "left") {
04101 if (indx < 0) indx = 0;
04102 } else {
04103 if (indx > nbin) indx = nbin;
04104 }
04105
04106 return indx;
04107 }
04108
04109 JSROOT.THistPainter.prototype.FindStat = function() {
04110
04111 if ('fFunctions' in this.histo)
04112 for ( var i in this.histo.fFunctions.arr) {
04113
04114 var func = this.histo.fFunctions.arr[i];
04115
04116 if (func['_typename'] == 'TPaveText' || func['_typename'] == 'TPaveStats') {
04117 return func;
04118 }
04119 }
04120
04121 return null;
04122 }
04123
04124 JSROOT.THistPainter.prototype.CreateStat = function() {
04125
04126 if (!this.draw_content) return null;
04127 if (this.FindStat() != null) return null;
04128
04129 var stats = JSROOT.Create('TPaveStats');
04130 jQuery.extend(stats, { _AutoCreated: true,
04131 fName : 'stats',
04132 fOptStat: JSROOT.gStyle.OptStat,
04133 fBorderSize : 1} );
04134 jQuery.extend(stats, JSROOT.gStyle.StatNDC);
04135 jQuery.extend(stats, JSROOT.gStyle.StatText);
04136 jQuery.extend(stats, JSROOT.gStyle.StatFill);
04137
04138 if (this.histo['_typename'] && (this.histo['_typename'].match(/^TProfile/) || this.histo['_typename'].match(/^TH2/)))
04139 stats['fY1NDC'] = 0.67;
04140
04141 stats.AddText(this.histo['fName']);
04142
04143 if (!'fFunctions' in this.histo)
04144 this.histo['fFunctions'] = JSROOT.Create("TList");
04145
04146 this.histo.fFunctions.arr.push(stats);
04147
04148 return stats;
04149 }
04150
04151 JSROOT.THistPainter.prototype.DrawFunctions = function() {
04152
04153
04154
04155
04156 if (!('fFunctions' in this.histo)) return;
04157
04158
04159
04160 var lastpainter = this;
04161
04162 var kNotDraw = JSROOT.BIT(9);
04163
04164 var EStatusBits = {
04165 kCanDelete : JSROOT.BIT(0),
04166 kMustCleanup : JSROOT.BIT(3),
04167 kObjInCanvas : JSROOT.BIT(3),
04168 kIsReferenced : JSROOT.BIT(4),
04169 kHasUUID : JSROOT.BIT(5),
04170 kCannotPick : JSROOT.BIT(6),
04171 kNoContextMenu : JSROOT.BIT(8),
04172 kInvalidObject : JSROOT.BIT(13)
04173 }
04174
04175 for ( var i in this.histo.fFunctions.arr) {
04176
04177 var func = this.histo.fFunctions.arr[i];
04178
04179 var funcpainter = this.FindPainterFor(func);
04180
04181
04182
04183 if (funcpainter != null) continue;
04184
04185 if (func['_typename'] == 'TPaveText' || func['_typename'] == 'TPaveStats') {
04186 funcpainter = JSROOT.Painter.drawPaveText(this.divid, func);
04187 } else
04188
04189 if (func['_typename'] == 'TF1') {
04190 var is_pad = this.root_pad() != null;
04191 if ((!is_pad && !func.TestBit(kNotDraw))
04192 || (is_pad && func.TestBit(EStatusBits.kObjInCanvas)))
04193 funcpainter = JSROOT.Painter.drawFunction(this.divid, func);
04194 } else
04195
04196 if (func['_typename'] == 'TPaletteAxis') {
04197 funcpainter = JSROOT.Painter.drawPaletteAxis(this.divid, func);
04198 }
04199 }
04200 }
04201
04202 JSROOT.THistPainter.prototype.Redraw = function() {
04203 this.CreateXY();
04204 this.DrawAxes();
04205 this.DrawGrids();
04206 this.DrawBins();
04207 if (this.create_canvas) this.DrawTitle();
04208 }
04209
04210 JSROOT.THistPainter.prototype.Unzoom = function(dox, doy) {
04211 var obj = this.main_painter();
04212 if (!obj) obj = this;
04213
04214 var changed = false;
04215
04216 if (dox) {
04217 if (obj['zoom_xmin'] != obj['zoom_xmax']) changed = true;
04218 obj['zoom_xmin'] = 0;
04219 obj['zoom_xmax'] = 0;
04220 }
04221 if (doy) {
04222 if (obj['zoom_ymin'] != obj['zoom_ymax']) changed = true;
04223 obj['zoom_ymin'] = 0;
04224 obj['zoom_ymax'] = 0;
04225 }
04226
04227 if (changed) this.RedrawPad();
04228 }
04229
04230 JSROOT.THistPainter.prototype.Zoom = function(xmin, xmax, ymin, ymax) {
04231 var obj = this.main_painter();
04232 if (!obj) obj = this;
04233
04234 var isany = false;
04235
04236 if ((xmin != xmax) && (Math.abs(xmax-xmin) > obj.binwidthx*2.0)) {
04237 obj['zoom_xmin'] = xmin;
04238 obj['zoom_xmax'] = xmax;
04239 isany = true;
04240 }
04241 if ((ymin != ymax) && (Math.abs(ymax-ymin) > (('binwidthy' in obj) ? (obj.binwidthy*2.0) : Math.abs(obj.ymax-obj.ymin)*1e-6))) {
04242 obj['zoom_ymin'] = ymin;
04243 obj['zoom_ymax'] = ymax;
04244 isany = true;
04245 }
04246
04247 if (isany) this.RedrawPad();
04248 }
04249
04250 JSROOT.THistPainter.prototype.AddInteractive = function() {
04251
04252
04253 if (!JSROOT.gStyle.Zooming || !this.is_main_painter()) return;
04254
04255
04256
04257 var width = Number(this.svg_frame(true).attr("width")),
04258 height = Number(this.svg_frame(true).attr("height"));
04259 var e, origin, curr = null, rect = null;
04260 var lasttouch = new Date(0);
04261
04262 var zoom_kind = 0;
04263
04264 var disable_tooltip = false;
04265
04266
04267
04268 var pthis = this;
04269
04270 function closeAllExtras() {
04271 var x = document.getElementById('root_ctx_menu');
04272 if (x) x.parentNode.removeChild(x);
04273 if (rect != null) { rect.remove(); rect = null; }
04274 zoom_kind = 0;
04275 if (disable_tooltip) {
04276 JSROOT.gStyle.Tooltip = true;
04277 disable_tooltip = false;
04278 }
04279 }
04280
04281 function showContextMenu() {
04282
04283 d3.event.preventDefault();
04284
04285
04286 if (zoom_kind > 100) return;
04287
04288
04289 closeAllExtras();
04290
04291 var menu = JSROOT.Painter.createmenu(d3.event, 'root_ctx_menu');
04292
04293 menu['painter'] = pthis;
04294
04295 JSROOT.Painter.menuitem(menu, pthis.histo['fName']);
04296 JSROOT.Painter.menuitem(menu, "----------------");
04297
04298 pthis.FillContextMenu(menu);
04299 }
04300
04301 function startTouchSel() {
04302
04303
04304 if (zoom_kind != 0) {
04305 d3.event.preventDefault();
04306 d3.event.stopPropagation();
04307 return;
04308 }
04309
04310
04311 width = Number(pthis.svg_frame(true).attr("width"));
04312 height = Number(pthis.svg_frame(true).attr("height"));
04313
04314 e = this;
04315
04316 var arr = d3.touches(e);
04317
04318
04319 if (arr.length == 1) {
04320
04321 var now = new Date();
04322 var diff = now.getTime() - lasttouch.getTime();
04323
04324 if ((diff < 300) && (curr != null)
04325 && (Math.abs(curr[0] - arr[0][0]) < 30)
04326 && (Math.abs(curr[1] - arr[0][1]) < 30)) {
04327
04328 d3.event.preventDefault();
04329 d3.event.stopPropagation();
04330
04331 closeAllExtras();
04332 pthis.Unzoom(true, true);
04333 } else {
04334 lasttouch = now;
04335 curr = arr[0];
04336 }
04337 }
04338
04339 if (arr.length != 2) return;
04340
04341 d3.event.preventDefault();
04342
04343 closeAllExtras();
04344
04345 var pnt1 = arr[0];
04346 var pnt2 = arr[1];
04347
04348 curr = new Array;
04349 origin = new Array;
04350
04351 curr.push(Math.min(pnt1[0], pnt2[0]));
04352 curr.push(Math.min(pnt1[1], pnt2[1]));
04353 origin.push(Math.max(pnt1[0], pnt2[0]));
04354 origin.push(Math.max(pnt1[1], pnt2[1]));
04355
04356 if (curr[0] < 0) {
04357 zoom_kind = 103;
04358 curr[0] = 0;
04359 origin[0] = width;
04360 } else if (origin[1] > height) {
04361 zoom_kind = 102;
04362 curr[1] = 0;
04363 origin[1] = height;
04364 } else {
04365 zoom_kind = 101;
04366 }
04367
04368
04369
04370
04371 rect = pthis.svg_frame(true).append("rect")
04372 .attr("class", "zoom")
04373 .attr("id", "zoomRect")
04374 .attr("x", curr[0])
04375 .attr("y", curr[1])
04376 .attr("width", origin[0] - curr[0])
04377 .attr("height", origin[1] - curr[1]);
04378
04379
04380
04381 d3.select(window).on("touchmove.zoomRect", moveTouchSel)
04382 .on("touchcancel.zoomRect", endTouchSel)
04383 .on("touchend.zoomRect", endTouchSel, true);
04384 d3.event.stopPropagation();
04385 }
04386
04387 function moveTouchSel() {
04388 if (zoom_kind < 100) return;
04389
04390 d3.event.preventDefault();
04391
04392
04393 var arr = d3.touches(e);
04394
04395 if (arr.length != 2) {
04396 closeAllExtras();
04397 zoom_kind = 0;
04398 return;
04399 }
04400
04401 var pnt1 = arr[0];
04402 var pnt2 = arr[1];
04403
04404 if (zoom_kind != 103) {
04405 curr[0] = Math.min(pnt1[0], pnt2[0]);
04406 origin[0] = Math.max(pnt1[0], pnt2[0]);
04407 }
04408 if (zoom_kind != 102) {
04409 curr[1] = Math.min(pnt1[1], pnt2[1]);
04410 origin[1] = Math.max(pnt1[1], pnt2[1]);
04411 }
04412
04413 rect.attr("x", curr[0])
04414 .attr("y", curr[1])
04415 .attr("width", origin[0] - curr[0])
04416 .attr("height", origin[1] - curr[1]);
04417
04418 if (JSROOT.gStyle.Tooltip && ((origin[0] - curr[0]>10) || (origin[1] - curr[1]>10))) {
04419 JSROOT.gStyle.Tooltip = false;
04420 disable_tooltip = true;
04421 }
04422
04423 d3.event.stopPropagation();
04424 }
04425
04426 function endTouchSel() {
04427
04428 if (zoom_kind < 100) return;
04429
04430 d3.event.preventDefault();
04431 d3.select(window).on("touchmove.zoomRect", null)
04432 .on("touchend.zoomRect", null)
04433 .on("touchcancel.zoomRect", null);
04434 d3.select("body").classed("noselect", false);
04435
04436 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
04437
04438 var isany = false;
04439
04440 if ((zoom_kind != 103) && (Math.abs(curr[0] - origin[0]) > 10)) {
04441 xmin = Math.min(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
04442 xmax = Math.max(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
04443 isany = true;
04444 }
04445
04446 if ((zoom_kind != 102) && (Math.abs(curr[1] - origin[1]) > 10)) {
04447 ymin = Math.min(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
04448 ymax = Math.max(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
04449 isany = true;
04450 }
04451
04452 d3.select("body").style("-webkit-user-select", "auto");
04453
04454 if (disable_tooltip)
04455 JSROOT.gStyle.Tooltip = true;
04456
04457 rect.remove();
04458 rect = null;
04459 zoom_kind = 0;
04460
04461 if (isany) pthis.Zoom(xmin, xmax, ymin, ymax);
04462
04463 d3.event.stopPropagation();
04464 }
04465
04466 function detectLeftButton(event) {
04467 if ('buttons' in event) return event.buttons === 1;
04468 else if ('which' in event) return event.which === 1;
04469 else return event.button === 1;
04470 }
04471
04472 function startRectSel() {
04473
04474
04475
04476
04477
04478 if (zoom_kind > 100) return;
04479
04480 d3.event.preventDefault();
04481
04482
04483 width = Number(pthis.svg_frame(true).attr("width"));
04484 height = Number(pthis.svg_frame(true).attr("height"));
04485
04486 closeAllExtras();
04487
04488 e = this;
04489 origin = d3.mouse(e);
04490
04491 curr = new Array;
04492 curr.push(Math.max(0, Math.min(width, origin[0])));
04493 curr.push(Math.max(0, Math.min(height, origin[1])));
04494
04495 if (origin[0] < 0) {
04496 zoom_kind = 3;
04497 origin[0] = 0;
04498 origin[1] = curr[1];
04499 curr[0] = width;
04500 curr[1] += 1;
04501 } else if (origin[1] > height) {
04502 zoom_kind = 2;
04503 origin[0] = curr[0];
04504 origin[1] = 0;
04505 curr[0] += 1;
04506 curr[1] = height;
04507 } else {
04508 zoom_kind = 1;
04509 origin[0] = curr[0];
04510 origin[1] = curr[1];
04511 }
04512
04513
04514
04515
04516 rect = pthis.svg_frame(true)
04517 .append("rect")
04518 .attr("class", "zoom")
04519 .attr("id", "zoomRect");
04520
04521 pthis.svg_frame(true).on("dblclick", unZoom);
04522
04523 d3.select(window).on("mousemove.zoomRect", moveRectSel)
04524 .on("mouseup.zoomRect", endRectSel, true);
04525
04526 d3.event.stopPropagation();
04527 }
04528
04529 function unZoom() {
04530 d3.event.preventDefault();
04531 var m = d3.mouse(e);
04532 closeAllExtras();
04533 if (m[0] < 0) pthis.Unzoom(false, true); else
04534 if (m[1] > height) pthis.Unzoom(true, false); else {
04535 pthis.Unzoom(true, true);
04536 pthis.svg_frame(true).on("dblclick", null);
04537 }
04538 }
04539
04540 function moveRectSel() {
04541
04542 if ((zoom_kind == 0) || (zoom_kind > 100)) return;
04543
04544 d3.event.preventDefault();
04545 var m = d3.mouse(e);
04546
04547 m[0] = Math.max(0, Math.min(width, m[0]));
04548 m[1] = Math.max(0, Math.min(height, m[1]));
04549
04550 switch (zoom_kind) {
04551 case 1: curr[0] = m[0]; curr[1] = m[1]; break;
04552 case 2: curr[0] = m[0]; break;
04553 case 3: curr[1] = m[1]; break;
04554 }
04555
04556 rect.attr("x", Math.min(origin[0], curr[0]))
04557 .attr("y", Math.min(origin[1], curr[1]))
04558 .attr("width", Math.abs(curr[0] - origin[0]))
04559 .attr("height", Math.abs(curr[1] - origin[1]));
04560
04561 if (JSROOT.gStyle.Tooltip && ((Math.abs(curr[0] - origin[0])>10) || (Math.abs(curr[1] - origin[1])>10))) {
04562 JSROOT.gStyle.Tooltip = false;
04563 disable_tooltip = true;
04564 }
04565 }
04566
04567 function endRectSel() {
04568 if ((zoom_kind == 0) || (zoom_kind > 100)) return;
04569
04570 d3.event.preventDefault();
04571
04572
04573 d3.select(window).on("mousemove.zoomRect", null)
04574 .on("mouseup.zoomRect", null);
04575 d3.select("body").classed("noselect", false);
04576
04577 var m = d3.mouse(e);
04578
04579 m[0] = Math.max(0, Math.min(width, m[0]));
04580 m[1] = Math.max(0, Math.min(height, m[1]));
04581
04582 switch (zoom_kind) {
04583 case 1: curr[0] = m[0]; curr[1] = m[1]; break;
04584 case 2: curr[0] = m[0]; break;
04585 case 3: curr[1] = m[1]; break;
04586 }
04587
04588 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
04589
04590 var isany = false;
04591
04592 if ((zoom_kind != 3) && (Math.abs(curr[0] - origin[0]) > 10)) {
04593 xmin = Math.min(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
04594 xmax = Math.max(pthis.x.invert(origin[0]), pthis.x.invert(curr[0]));
04595 isany = true;
04596 }
04597
04598 if ((zoom_kind != 2) && (Math.abs(curr[1] - origin[1]) > 10)) {
04599 ymin = Math.min(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
04600 ymax = Math.max(pthis.y.invert(origin[1]), pthis.y.invert(curr[1]));
04601 isany = true;
04602 }
04603
04604 d3.select("body").style("-webkit-user-select", "auto");
04605
04606 if (disable_tooltip) {
04607 JSROOT.gStyle.Tooltip = true;
04608 disable_tooltip = false;
04609 }
04610
04611 rect.remove();
04612 rect = null;
04613 zoom_kind = 0;
04614
04615 if (isany) pthis.Zoom(xmin, xmax, ymin, ymax);
04616 }
04617
04618 this.svg_frame(true).on("mousedown", startRectSel);
04619 this.svg_frame(true).on("touchstart", startTouchSel);
04620 this.svg_frame(true).on("contextmenu", showContextMenu);
04621
04622 }
04623
04624 JSROOT.THistPainter.prototype.FillContextMenu = function(menu) {
04625 JSROOT.Painter.menuitem(menu, "Unzoom X", function() {
04626 menu['painter'].Unzoom(true, false);
04627 });
04628 JSROOT.Painter.menuitem(menu, "Unzoom Y", function() {
04629 menu['painter'].Unzoom(false, true);
04630 });
04631 JSROOT.Painter.menuitem(menu, "Unzoom", function() {
04632 menu['painter'].Unzoom(true, true);
04633 });
04634
04635 JSROOT.Painter.menuitem(menu, JSROOT.gStyle.Tooltip ? "Disable tooltip" : "Enable tooltip", function() {
04636 JSROOT.gStyle.Tooltip = !JSROOT.gStyle.Tooltip;
04637 menu['painter'].RedrawPad();
04638 });
04639
04640 if (this.options) {
04641
04642 var item = this.options.Logx > 0 ? "Linear X" : "Log X";
04643
04644 JSROOT.Painter.menuitem(menu, item, function() {
04645 menu['painter'].options.Logx = 1 - menu['painter'].options.Logx;
04646 menu['painter'].RedrawPad();
04647 });
04648
04649 var item = this.options.Logy > 0 ? "Linear Y" : "Log Y";
04650 JSROOT.Painter.menuitem(menu, item, function() {
04651 menu['painter'].options.Logy = 1 - menu['painter'].options.Logy;
04652 menu['painter'].RedrawPad();
04653 });
04654 }
04655 if (this.draw_content)
04656 JSROOT.Painter.menuitem(menu, "Toggle stat", function() {
04657 menu['painter'].ToggleStat();
04658 });
04659 }
04660
04661
04662
04663 JSROOT.TH1Painter = function(histo) {
04664 JSROOT.THistPainter.call(this, histo);
04665 }
04666
04667 JSROOT.TH1Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
04668
04669 JSROOT.TH1Painter.prototype.ScanContent = function() {
04670
04671
04672
04673 this.fill = this.createAttFill(this.histo);
04674 if (this.fill.color == 'white') this.fill.color = 'none';
04675
04676 this.attline = JSROOT.Painter.createAttLine(this.histo);
04677
04678 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0;
04679
04680 var profile = this.IsTProfile();
04681
04682 this.nbinsx = this.histo['fXaxis']['fNbins'];
04683
04684 for (var i = 0; i < this.nbinsx; ++i) {
04685 var value = this.histo.getBinContent(i + 1);
04686 hsum += profile ? this.histo.fBinEntries[i + 1] : value;
04687 if (i == 0) hmin = hmax = value;
04688 if (value < hmin) hmin = value; else
04689 if (value > hmax) hmax = value;
04690 if (value > 0)
04691 if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value;
04692 }
04693
04694
04695 if (profile)
04696 hsum += this.histo.fBinEntries[0] + this.histo.fBinEntries[this.nbinsx + 1];
04697 else
04698 hsum += this.histo.getBinContent(0) + this.histo.getBinContent(this.nbinsx + 1);
04699
04700 this.stat_entries = hsum;
04701
04702
04703 this.xmin = this.histo['fXaxis']['fXmin'];
04704 this.xmax = this.histo['fXaxis']['fXmax'];
04705
04706 this.binwidthx = (this.xmax - this.xmin);
04707 if (this.nbinsx > 0)
04708 this.binwidthx = this.binwidthx / this.nbinsx;
04709
04710 this.ymin = this.histo['fYaxis']['fXmin'];
04711 this.ymax = this.histo['fYaxis']['fXmax'];
04712 this.ymin_nz = hmin_nz;
04713
04714 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) {
04715 if (this.histo['fMinimum'] != -1111) this.ymin = this.histo['fMinimum'];
04716 if (this.histo['fMaximum'] != -1111) this.ymax = this.histo['fMaximum'];
04717 this.draw_content = false;
04718 } else {
04719 if (this.histo['fMinimum'] != -1111) hmin = this.histo['fMinimum'];
04720 if (this.histo['fMaximum'] != -1111) hmax = this.histo['fMaximum'];
04721 if (hmin >= hmax) {
04722 if (hmin == 0) { this.ymax = 0; this.ymax = 1; } else
04723 if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
04724 else { this.ymin = 0; this.ymax = hmin * 2; }
04725 } else {
04726 var dy = (hmax - hmin) * 0.1;
04727 this.ymin = hmin - dy;
04728 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
04729 this.ymax = hmax + dy;
04730 }
04731 this.draw_content = true;
04732 }
04733
04734
04735 if (this.options.Bar == 0 && this.options.Hist == 0
04736 && this.options.Error == 0 && this.options.Same == 0) {
04737 this.draw_content = false;
04738 }
04739 if (this.options.Axis > 0) {
04740 this.draw_content = false;
04741 }
04742 }
04743
04744 JSROOT.TH1Painter.prototype.CountStat = function(cond) {
04745 var profile = this.IsTProfile();
04746
04747 var stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0;
04748
04749 var left = this.GetSelectIndex("x", "left");
04750 var right = this.GetSelectIndex("x", "right");
04751
04752 var xx = 0, w = 0, xmax = null, wmax = null;
04753
04754 for (var i = left; i < right; i++) {
04755 xx = this.xmin + (i + 0.5) * this.binwidthx;
04756
04757 if ((cond!=null) && !cond(xx)) continue;
04758
04759 if (profile) {
04760 w = this.histo.fBinEntries[i + 1];
04761 stat_sumwy += this.histo.fArray[i + 1];
04762 stat_sumwy2 += this.histo.fSumw2[i + 1];
04763 } else {
04764 w = this.histo.getBinContent(i + 1);
04765 }
04766
04767 if ((xmax==null) || (w>wmax)) { xmax = xx; wmax = w; }
04768
04769 stat_sumw += w;
04770 stat_sumwx += w * xx;
04771 stat_sumwx2 += w * xx * xx;
04772 }
04773
04774 var res = { meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: stat_sumw, entries: this.stat_entries, xmax:0, wmax:0 };
04775
04776 if (stat_sumw > 0) {
04777 res.meanx = stat_sumwx / stat_sumw;
04778 res.meany = stat_sumwy / stat_sumw;
04779 res.rmsx = Math.sqrt(stat_sumwx2 / stat_sumw - res.meanx * res.meanx);
04780 res.rmsy = Math.sqrt(stat_sumwy2 / stat_sumw - res.meany * res.meany);
04781 }
04782
04783 if (xmax!=null) {
04784 res.xmax = xmax;
04785 res.wmax = wmax;
04786 }
04787
04788 return res;
04789 }
04790
04791 JSROOT.TH1Painter.prototype.FillStatistic = function(stat, dostat) {
04792 if (!this.histo) return false;
04793
04794 var data = this.CountStat();
04795
04796 var print_name = Math.floor(dostat % 10);
04797 var print_entries = Math.floor(dostat / 10) % 10;
04798 var print_mean = Math.floor(dostat / 100) % 10;
04799 var print_rms = Math.floor(dostat / 1000) % 10;
04800 var print_under = Math.floor(dostat / 10000) % 10;
04801 var print_over = Math.floor(dostat / 100000) % 10;
04802 var print_integral = Math.floor(dostat / 1000000) % 10;
04803 var print_skew = Math.floor(dostat / 10000000) % 10;
04804 var print_kurt = Math.floor(dostat / 100000000) % 10;
04805
04806 if (print_name > 0)
04807 stat.AddLine(this.histo['fName']);
04808
04809 if (this.IsTProfile()) {
04810
04811 if (print_entries > 0)
04812 stat.AddLine("Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
04813
04814 if (print_mean > 0) {
04815 stat.AddLine("Mean = " + JSROOT.gStyle.StatFormat(data.meanx));
04816 stat.AddLine("Mean y = " + JSROOT.gStyle.StatFormat(data.meany));
04817 }
04818
04819 if (print_rms > 0) {
04820 stat.AddLine("RMS = " + JSROOT.gStyle.StatFormat(data.rmsx));
04821 stat.AddLine("RMS y = " + JSROOT.gStyle.StatFormat(data.rmsy));
04822 }
04823
04824 } else {
04825
04826 if (print_entries > 0)
04827 stat.AddLine("Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
04828
04829 if (print_mean > 0) {
04830 stat.AddLine("Mean = " + JSROOT.gStyle.StatFormat(data.meanx));
04831 }
04832
04833 if (print_rms > 0) {
04834 stat.AddLine("RMS = " + JSROOT.gStyle.StatFormat(data.rmsx));
04835 }
04836
04837 if (print_under > 0) {
04838 var res = 0;
04839 if (this.histo['fArray'].length > 0)
04840 res = this.histo['fArray'][0];
04841 stat.AddLine("Underflow = " + JSROOT.gStyle.StatFormat(res));
04842 }
04843
04844 if (print_over > 0) {
04845 var res = 0;
04846 if (this.histo['fArray'].length > 0)
04847 res = this.histo['fArray'][this.histo['fArray'].length - 1];
04848 stat.AddLine("Overflow = " + JSROOT.gStyle.StatFormat(res));
04849 }
04850
04851 if (print_integral > 0) {
04852 stat.AddLine("Integral = " + JSROOT.gStyle.StatEntriesFormat(data.integral));
04853 }
04854
04855 if (print_skew > 0)
04856 stat.AddLine("Skew = not avail");
04857
04858 if (print_kurt > 0)
04859 stat.AddLine("Kurt = not avail");
04860 }
04861
04862
04863 var nlines = stat.pavetext['fLines'].arr.length;
04864 var stath = nlines * JSROOT.gStyle.StatFontSize;
04865 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
04866 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
04867 stat.pavetext['fY1NDC'] = 0.93 - stath;
04868 stat.pavetext['fY2NDC'] = 0.93;
04869 }
04870
04871 return true;
04872 }
04873
04874 JSROOT.TH1Painter.prototype.CreateDrawBins = function(width, height, exclude_zeros) {
04875
04876
04877 var left = this.GetSelectIndex("x", "left", -1);
04878 var right = this.GetSelectIndex("x", "right", 2);
04879
04880 var draw_bins = new Array;
04881
04882 var can_optimize = ((JSROOT.gStyle.OptimizeDraw > 0) && (right-left > 5000)) ||
04883 ((JSROOT.gStyle.OptimizeDraw > 1) && (right-left > 2*width));
04884
04885 var x1, x2 = this.xmin + left * this.binwidthx;
04886 var grx1 = -1111, grx2 = -1111, gry;
04887
04888 var point = null;
04889 var searchmax = false;
04890
04891 for (var i = left; i < right; i++) {
04892
04893 x1 = x2;
04894 x2 += this.binwidthx;
04895
04896 if (this.options.Logx && (x1 <= 0)) continue;
04897
04898 grx1 = grx2;
04899 grx2 = this.x(x2);
04900 if (grx1 < 0) grx1 = this.x(x1);
04901
04902 var pmax = i, cont = this.histo.getBinContent(i + 1);
04903
04904 if (can_optimize) {
04905 searchmax = !searchmax;
04906
04907
04908 while ((i+1<right) && (this.x(x2 + this.binwidthx) < grx2 + 0.5)) {
04909 i++; x2 += this.binwidthx;
04910 var ccc = this.histo.getBinContent(i + 1);
04911 if (searchmax ? ccc>cont : ccc<cont) {
04912 cont = ccc;
04913 pmax = i;
04914 }
04915 }
04916 grx2 = this.x(x2);
04917 }
04918
04919
04920 if (exclude_zeros && (cont==0)) continue;
04921
04922 if (this.options.Logy && (cont < this.scale_ymin))
04923 gry = height + 10;
04924 else
04925 gry = this.y(cont);
04926
04927 point = { x : grx1, y : gry };
04928
04929 if (this.options.Error > 0) {
04930 point['xerr'] = (grx2 - grx1) / 2;
04931 point['yerr'] = gry - this.y(cont + this.histo.getBinError(pmax + 1));
04932 }
04933
04934 if (this.options.Error > 0) {
04935 point['x'] = (grx1 + grx2) / 2;
04936 point['tip'] = "x = " + this.AxisAsText("x", (x1 + x2)/2 ) + "\n" +
04937 "y = " + this.AxisAsText("y", cont) + "\n" +
04938 "error x = " + ((x2 - x1) / 2).toPrecision(4) + "\n" +
04939 "error y = " + this.histo.getBinError(pmax + 1).toPrecision(4);
04940 } else {
04941 point['width'] = grx2 - grx1;
04942
04943 point['tip'] = "bin = " + (pmax + 1) + "\n" +
04944 "x = [" + this.AxisAsText("x", x1) + ", " + this.AxisAsText("x", x2) + "]\n" +
04945 "entries = " + cont;
04946 }
04947
04948 draw_bins.push(point);
04949 }
04950
04951
04952 if ((right == this.nbinsx) && (this.options.Error == 0) && (point!=null)) {
04953 var extrapoint = jQuery.extend(true, {}, point);
04954 extrapoint.x = grx2;
04955 draw_bins.push(extrapoint);
04956 }
04957
04958 return draw_bins;
04959 }
04960
04961 JSROOT.TH1Painter.prototype.DrawAsMarkers = function(draw_bins, w, h) {
04962
04963
04964 var draw_bins = this.CreateDrawBins(w, h, this.IsTProfile() || (this.Mark==10));
04965
04966
04967 var nodes = this.draw_g.selectAll("g")
04968 .data(draw_bins)
04969 .enter()
04970 .append("svg:g")
04971 .attr("transform", function(d) { return "translate(" + d.x.toFixed(1) + "," + d.y.toFixed(1) + ")";});
04972
04973 if (JSROOT.gStyle.Tooltip)
04974 nodes.append("svg:title").text(function(d) { return d.tip; });
04975
04976 var xerr = null, yerr = null;
04977
04978
04979 if (this.options.Error > 0)
04980 nodes.append("svg:line")
04981 .attr("x1", function(d) { return (-d.xerr).toFixed(1); })
04982 .attr("y1", 0)
04983 .attr("x2", function(d) { return d.xerr.toFixed(1); })
04984 .attr("y2", 0)
04985 .call(this.attline.func);
04986
04987 if (this.options.Error == 11) {
04988 nodes.append("svg:line")
04989 .attr("y1", -3)
04990 .attr("x1", function(d) { return (-d.xerr).toFixed(1); })
04991 .attr("y2", 3)
04992 .attr("x2", function(d) { return (-d.xerr).toFixed(1); })
04993 .call(this.attline.func);
04994 nodes.append("svg:line")
04995 .attr("y1", -3)
04996 .attr("x1", function(d) { return d.xerr.toFixed(1); })
04997 .attr("y2", 3)
04998 .attr("x2", function(d) { return d.xerr.toFixed(1); })
04999 .call(this.attline.func);
05000 }
05001
05002
05003 if (this.options.Error > 0)
05004 nodes.append("svg:line")
05005 .attr("x1", 0)
05006 .attr("y1", function(d) { return (-d.yerr).toFixed(1); })
05007 .attr("x2", 0)
05008 .attr("y2", function(d) { return d.yerr.toFixed(1); })
05009 .call(this.attline.func);
05010
05011 if (this.options.Error == 11) {
05012 nodes.append("svg:line")
05013 .attr("x1", -3)
05014 .attr("y1", function(d) { return (-d.yerr).toFixed(1); })
05015 .attr("x2", 3)
05016 .attr("y2", function(d) { return (-d.yerr).toFixed(1); })
05017 .call(this.attline.func);
05018 nodes.append("svg:line")
05019 .attr("x1", -3)
05020 .attr("y1", function(d) { return d.yerr.toFixed(1); })
05021 .attr("x2", 3)
05022 .attr("y2", function(d) { return d.yerr.toFixed(1); })
05023 .call(this.attline.func);
05024 }
05025
05026
05027 if ((this.histo['fMarkerStyle'] == 1) && (this.options.Error > 0)) return;
05028
05029 var marker = JSROOT.Painter.createAttMarker(this.histo);
05030
05031 nodes.append("svg:path").call(marker.func);
05032 }
05033
05034 JSROOT.TH1Painter.prototype.DrawBins = function() {
05035
05036 var width = Number(this.svg_frame(true).attr("width")),
05037 height = Number(this.svg_frame(true).attr("height"));
05038
05039 if (!this.draw_content || (width<=0) || (height<=0)) {
05040 this.RemoveDrawG();
05041 return;
05042 }
05043
05044 this.RecreateDrawG();
05045
05046 if (this.IsTProfile() || (this.options.Error > 0) || (this.options.Mark > 0))
05047 return this.DrawAsMarkers(width, height);
05048
05049 var draw_bins = this.CreateDrawBins(width, height);
05050
05051 if (this.fill.color != 'none') {
05052
05053
05054 var area = d3.svg.area()
05055 .x(function(d) { return d.x.toFixed(1); })
05056 .y0(function(d) { return d.y.toFixed(1); })
05057 .y1(function(d) { return height; })
05058 .interpolate("step-after");
05059
05060 this.draw_g.append("svg:path")
05061 .attr("d", area(draw_bins))
05062 .call(this.attline.func)
05063 .call(this.fill.func);
05064 } else {
05065
05066 var line = d3.svg.line()
05067 .x(function(d) { return d.x.toFixed(1); })
05068 .y(function(d) { return d.y.toFixed(1); })
05069 .interpolate("step-after");
05070
05071 this.draw_g
05072 .append("svg:path")
05073 .attr("d", line(draw_bins))
05074 .call(this.attline.func)
05075 .style("fill", "none");
05076 }
05077
05078 if (JSROOT.gStyle.Tooltip) {
05079
05080 this.draw_g.selectAll("selections")
05081 .data(draw_bins).enter()
05082 .append("svg:line")
05083 .attr("x1", function(d) { return d.x + d.width / 2; })
05084 .attr("y1", function(d) { return Math.max(0, d.y); })
05085 .attr("x2", function(d) { return d.x + d.width / 2; })
05086 .attr("y2", function(d) { return height; })
05087 .style("opacity", 0)
05088 .style("stroke", "#4572A7")
05089 .style("stroke-width", function(d) { return d.width; })
05090 .on('mouseover', function() {
05091 if (JSROOT.gStyle.Tooltip && (d3.select(this).style("opacity")=="0"))
05092 d3.select(this).transition().duration(100).style("opacity", "0.3");
05093 })
05094 .on('mouseout', function() {
05095 d3.select(this).transition().duration(100).style("opacity", "0");
05096 })
05097 .append("svg:title").text(function(d) { return d.tip; });
05098 }
05099 }
05100
05101 JSROOT.TH1Painter.prototype.FillContextMenu = function(menu) {
05102 JSROOT.THistPainter.prototype.FillContextMenu.call(this, menu);
05103 if (this.draw_content)
05104 JSROOT.Painter.menuitem(menu, "Auto zoom-in", function() { menu['painter'].AutoZoom(); });
05105 }
05106
05107 JSROOT.TH1Painter.prototype.AutoZoom = function() {
05108 var left = this.GetSelectIndex("x", "left", -1);
05109 var right = this.GetSelectIndex("x", "right", 1);
05110
05111 var dist = (right - left);
05112
05113 if (dist == 0)
05114 return;
05115
05116 var min = this.histo.getBinContent(left + 1);
05117
05118
05119 for (var indx = left; indx < right; indx++)
05120 if (this.histo.getBinContent(indx + 1) < min)
05121 min = this.histo.getBinContent(indx + 1);
05122
05123 while ((left < right) && (this.histo.getBinContent(left + 1) <= min)) left++;
05124 while ((left < right) && (this.histo.getBinContent(right) <= min)) right--;
05125
05126 if ((right - left < dist) && (left < right))
05127 this.Zoom(this.xmin + left * this.binwidthx, this.xmin + right * this.binwidthx, 0, 0);
05128 }
05129
05130 JSROOT.Painter.drawHistogram1D = function(divid, histo, opt) {
05131
05132
05133 var painter = new JSROOT.TH1Painter(histo);
05134 painter.SetDivId(divid, 1);
05135
05136
05137 painter.options = painter.DecodeOptions(opt);
05138
05139 painter.CheckPadOptions();
05140
05141 painter.ScanContent();
05142
05143 painter.CreateXY();
05144
05145 painter.DrawAxes();
05146
05147 painter.DrawGrids();
05148
05149 painter.DrawBins();
05150
05151 if (painter.create_canvas) painter.DrawTitle();
05152
05153 if (JSROOT.gStyle.AutoStat && painter.create_canvas) painter.CreateStat();
05154
05155 painter.DrawFunctions();
05156
05157 painter.AddInteractive();
05158
05159 return painter;
05160 }
05161
05162
05163
05164 JSROOT.TH2Painter = function(histo) {
05165 JSROOT.THistPainter.call(this, histo);
05166 this.paletteColors = [];
05167 }
05168
05169 JSROOT.TH2Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
05170
05171 JSROOT.TH2Painter.prototype.FillContextMenu = function(menu) {
05172 JSROOT.THistPainter.prototype.FillContextMenu.call(this, menu);
05173 JSROOT.Painter.menuitem(menu, "Auto zoom-in", function() { menu['painter'].AutoZoom(); });
05174 JSROOT.Painter.menuitem(menu, "Draw in 3D", function() { menu['painter'].Draw3D(); });
05175 JSROOT.Painter.menuitem(menu, "Toggle col", function() {
05176 if (menu['painter'].options.Color == 0)
05177 menu['painter'].options.Color = JSROOT.gStyle.DefaultCol;
05178 else
05179 menu['painter'].options.Color = -1 * menu['painter'].options.Color;
05180 menu['painter'].RedrawPad();
05181 });
05182
05183 if (this.options.Color > 0)
05184 JSROOT.Painter.menuitem(menu, "Toggle colz", function() { menu['painter'].ToggleColz(); });
05185 }
05186
05187 JSROOT.TH2Painter.prototype.FindPalette = function(remove) {
05188 if ('fFunctions' in this.histo)
05189 for ( var i in this.histo.fFunctions.arr) {
05190 var func = this.histo.fFunctions.arr[i];
05191 if (func['_typename'] != 'TPaletteAxis')
05192 continue;
05193 if (remove) {
05194 this.histo.fFunctions.arr.splice(i, 1);
05195 return null;
05196 }
05197
05198 return func;
05199 }
05200
05201 return null;
05202 }
05203
05204 JSROOT.TH2Painter.prototype.ToggleColz = function() {
05205 if (this.FindPalette() == null) {
05206 var shrink = this.CreatePalette(0.04);
05207 this.svg_frame()['frame_painter'].Shrink(0, shrink);
05208 this.options.Zscale = 1;
05209
05210 JSROOT.Painter.drawPaletteAxis(this.divid, this.FindPalette());
05211 } else {
05212 if (this.options.Zscale > 0)
05213 this.options.Zscale = 0;
05214 else
05215 this.options.Zscale = 1;
05216 }
05217
05218 this.RedrawPad();
05219 }
05220
05221 JSROOT.TH2Painter.prototype.AutoZoom = function() {
05222 var i1 = this.GetSelectIndex("x", "left", -1);
05223 var i2 = this.GetSelectIndex("x", "right", 1);
05224 var j1 = this.GetSelectIndex("y", "left", -1);
05225 var j2 = this.GetSelectIndex("y", "right", 1);
05226
05227 if ((i1 == i2) || (j1 == j2)) return;
05228
05229 var min = this.histo.getBinContent(i1 + 1, j1 + 1);
05230
05231
05232 for (var i = i1; i < i2; i++)
05233 for (var j = j1; j < j2; j++)
05234 if (this.histo.getBinContent(i + 1, j + 1) < min)
05235 min = this.histo.getBinContent(i + 1, j + 1);
05236
05237 var ileft = i2, iright = i1, jleft = j2, jright = j1;
05238
05239 for (var i = i1; i < i2; i++)
05240 for (var j = j1; j < j2; j++)
05241 if (this.histo.getBinContent(i + 1, j + 1) > min) {
05242 if (i < ileft) ileft = i;
05243 if (i >= iright) iright = i + 1;
05244 if (j < jleft) jleft = j;
05245 if (j >= jright) jright = j + 1;
05246 }
05247
05248 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
05249
05250 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
05251 xmin = this.xmin + ileft * this.binwidthx;
05252 xmax = this.xmin + iright * this.binwidthx;
05253 }
05254
05255 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
05256 ymin = this.ymin + jleft * this.binwidthy;
05257 ymax = this.ymin + jright * this.binwidthy;
05258 }
05259
05260 this.Zoom(xmin, xmax, ymin, ymax);
05261 }
05262
05263 JSROOT.TH2Painter.prototype.CreatePalette = function(rel_width) {
05264 if (this.FindPalette() != null) return 0.;
05265
05266 if (!rel_width || rel_width <= 0) rel_width = 0.04;
05267
05268 var pal = {};
05269 pal['_typename'] = 'TPaletteAxis';
05270 pal['fName'] = 'palette';
05271
05272 pal['_AutoCreated'] = true;
05273
05274 pal['fX1NDC'] = this.svg_frame()['NDC'].x2 - rel_width;
05275 pal['fY1NDC'] = this.svg_frame()['NDC'].y1;
05276 pal['fX2NDC'] = this.svg_frame()['NDC'].x2;
05277 pal['fY2NDC'] = this.svg_frame()['NDC'].y2;
05278 pal['fInit'] = 1;
05279 pal['fShadowColor'] = 1;
05280 pal['fCorenerRadius'] = 0;
05281 pal['fResizing'] = false;
05282 pal['fBorderSize'] = 4;
05283 pal['fName'] = "TPave";
05284 pal['fOption'] = "br";
05285 pal['fLineColor'] = 1;
05286 pal['fLineSyle'] = 1;
05287 pal['fLineWidth'] = 1;
05288 pal['fFillColor'] = 1;
05289 pal['fFillSyle'] = 1;
05290
05291 var axis = {};
05292
05293 axis['_typename'] = 'TGaxis';
05294 axis['fTickSize'] = 0.03;
05295 axis['fLabelOffset'] = 0.005;
05296 axis['fLabelSize'] = 0.035;
05297 axis['fTitleOffset'] = 1;
05298 axis['fTitleSize'] = 0.035;
05299 axis['fNdiv'] = 8;
05300 axis['fLabelColor'] = 1;
05301 axis['fLabelFont'] = 42;
05302 axis['fChopt'] = "";
05303 axis['fName'] = "";
05304 axis['fTitle'] = "";
05305 axis['fTimeFormat'] = "";
05306 axis['fFunctionName'] = "";
05307 axis['fWmin'] = 0;
05308 axis['fWmax'] = 100;
05309 axis['fLineColor'] = 1;
05310 axis['fLineSyle'] = 1;
05311 axis['fLineWidth'] = 1;
05312 axis['fTextAngle'] = 0;
05313 axis['fTextSize'] = 0.04;
05314 axis['fTextAlign'] = 11;
05315 axis['fTextColor'] = 1;
05316 axis['fTextFont'] = 42;
05317
05318 pal['fAxis'] = axis;
05319
05320 if (!'fFunctions' in this.histo)
05321 this.histo['fFunctions'] = JSROOT.Create("TList");
05322
05323
05324 this.histo.fFunctions.arr.unshift(pal);
05325
05326
05327
05328
05329 var width = Number(this.svg_frame(true).attr("width")),
05330 height = Number(this.svg_frame(true).attr("height"));
05331
05332 var axisOffset = Math.round(axis['fLabelOffset'] * width);
05333 var tickSize = Math.round(axis['fTickSize'] * width);
05334 var axisfont = JSROOT.Painter.getFontDetails(axis['fLabelFont'], axis['fLabelSize'] * height);
05335
05336 var ticks = d3.scale.linear().clamp(true)
05337 .domain([ this.minbin, this.maxbin ])
05338 .range([ height, 0 ]).nice().ticks(axis['fNdiv'] % 100);
05339
05340 var maxlen = 0;
05341 for (var i in ticks) {
05342 var len = axisfont.stringWidth(this.svg_frame(true), ticks[i]);
05343 if (len > maxlen) maxlen = len;
05344 }
05345
05346 var rel = (maxlen + axisOffset) / width;
05347
05348 if (pal['fX2NDC'] + rel > 0.98) {
05349 var shift = pal['fX2NDC'] + rel - 0.98;
05350
05351 pal['fX1NDC'] -= shift;
05352 pal['fX2NDC'] -= shift;
05353 rel_width += shift;
05354 }
05355
05356 return rel_width + 0.01;
05357 }
05358
05359 JSROOT.TH2Painter.prototype.ScanContent = function() {
05360 this.fillcolor = JSROOT.Painter.root_colors[this.histo['fFillColor']];
05361
05362
05363 this.attline = JSROOT.Painter.createAttLine(this.histo);
05364 if (this.attline.color == 'none') this.attline.color = '#4572A7';
05365
05366 this.nbinsx = this.histo['fXaxis']['fNbins'];
05367 this.nbinsy = this.histo['fYaxis']['fNbins'];
05368
05369
05370 this.xmin = this.histo['fXaxis']['fXmin'];
05371 this.xmax = this.histo['fXaxis']['fXmax'];
05372 this.ymin = this.histo['fYaxis']['fXmin'];
05373 this.ymax = this.histo['fYaxis']['fXmax'];
05374
05375 this.binwidthx = (this.xmax - this.xmin);
05376 if (this.nbinsx > 0)
05377 this.binwidthx = this.binwidthx / this.nbinsx;
05378
05379 this.binwidthy = (this.ymax - this.ymin);
05380 if (this.nbinsy > 0)
05381 this.binwidthy = this.binwidthy / this.nbinsy
05382
05383 this.gmaxbin = this.histo.getBinContent(1, 1);
05384 this.gminbin = this.gmaxbin;
05385 for (var i = 0; i < this.nbinsx; ++i) {
05386 for (var j = 0; j < this.nbinsy; ++j) {
05387 var bin_content = this.histo.getBinContent(i + 1, j + 1);
05388 if (bin_content < this.gminbin) this.gminbin = bin_content; else
05389 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
05390 }
05391 }
05392
05393
05394 this.draw_content = this.gmaxbin > 0;
05395 }
05396
05397 JSROOT.TH2Painter.prototype.CountStat = function(cond) {
05398 var stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0, stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy2 = 0;
05399
05400 var res = { entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix : [], xmax: 0, ymax:0, wmax: null };
05401 for (var n = 0; n < 9; n++) res.matrix.push(0);
05402
05403 var xleft = this.GetSelectIndex("x", "left");
05404 var xright = this.GetSelectIndex("x", "right");
05405
05406 var yleft = this.GetSelectIndex("y", "left");
05407 var yright = this.GetSelectIndex("y", "right");
05408
05409 for (var xi = 0; xi <= this.nbinsx + 1; xi++) {
05410 var xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1);
05411 var xx = this.xmin + (xi - 0.5) * this.binwidthx;
05412
05413 for (var yi = 0; yi <= this.nbinsx + 1; yi++) {
05414 var yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1);
05415 var yy = this.ymin + (yi - 0.5) * this.binwidthy;
05416
05417 var zz = this.histo.getBinContent(xi, yi);
05418
05419 res.entries += zz;
05420
05421 res.matrix[yside * 3 + xside] += zz;
05422
05423 if ((xside != 1) || (yside != 1)) continue;
05424
05425 if ((cond!=null) && !cond(xx,yy)) continue;
05426
05427 if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; }
05428
05429 stat_sum0 += zz;
05430 stat_sumx1 += xx * zz;
05431 stat_sumy1 += yy * zz;
05432 stat_sumx2 += xx * xx * zz;
05433 stat_sumy2 += yy * yy * zz;
05434 stat_sumxy2 += xx * yy * zz;
05435 }
05436 }
05437
05438 if (stat_sum0 > 0) {
05439 res.meanx = stat_sumx1 / stat_sum0;
05440 res.meany = stat_sumy1 / stat_sum0;
05441 res.rmsx = Math.sqrt(stat_sumx2 / stat_sum0 - res.meanx * res.meanx);
05442 res.rmsy = Math.sqrt(stat_sumy2 / stat_sum0 - res.meany * res.meany);
05443 }
05444
05445 if (res.wmax==null) res.wmax = 0;
05446 res.integral = stat_sum0;
05447
05448 return res;
05449 }
05450
05451 JSROOT.TH2Painter.prototype.FillStatistic = function(stat, dostat) {
05452 if (!this.histo) return false;
05453
05454 var data = this.CountStat();
05455
05456 var print_name = Math.floor(dostat % 10);
05457 var print_entries = Math.floor(dostat / 10) % 10;
05458 var print_mean = Math.floor(dostat / 100) % 10;
05459 var print_rms = Math.floor(dostat / 1000) % 10;
05460 var print_under = Math.floor(dostat / 10000) % 10;
05461 var print_over = Math.floor(dostat / 100000) % 10;
05462 var print_integral = Math.floor(dostat / 1000000) % 10;
05463 var print_skew = Math.floor(dostat / 10000000) % 10;
05464 var print_kurt = Math.floor(dostat / 100000000) % 10;
05465
05466 if (print_name > 0)
05467 stat.AddLine(this.histo['fName']);
05468
05469 if (print_entries > 0)
05470 stat.AddLine("Entries = " + JSROOT.gStyle.StatEntriesFormat(data.entries));
05471
05472 if (print_mean > 0) {
05473 stat.AddLine("Mean x = " + JSROOT.gStyle.StatFormat(data.meanx));
05474 stat.AddLine("Mean y = " + JSROOT.gStyle.StatFormat(data.meany));
05475 }
05476
05477 if (print_rms > 0) {
05478 stat.AddLine("RMS x = " + JSROOT.gStyle.StatFormat(data.rmsx));
05479 stat.AddLine("RMS y = " + JSROOT.gStyle.StatFormat(data.rmsy));
05480 }
05481
05482 if (print_integral > 0) {
05483 stat.AddLine("Integral = " + JSROOT.gStyle.StatEntriesFormat(data.matrix[4]));
05484 }
05485
05486 if (print_skew > 0) {
05487 stat.AddLine("Skewness x = <undef>");
05488 stat.AddLine("Skewness y = <undef>");
05489 }
05490
05491 if (print_kurt > 0)
05492 stat.AddLine("Kurt = <undef>");
05493
05494 if ((print_under > 0) || (print_over > 0)) {
05495 var m = data.matrix;
05496
05497 stat.AddLine("" + m[6].toFixed(0) + " | " + m[7].toFixed(0) + " | " + m[7].toFixed(0));
05498 stat.AddLine("" + m[3].toFixed(0) + " | " + m[4].toFixed(0) + " | " + m[5].toFixed(0));
05499 stat.AddLine("" + m[0].toFixed(0) + " | " + m[1].toFixed(0) + " | " + m[2].toFixed(0));
05500 }
05501
05502
05503 var nlines = stat.pavetext['fLines'].arr.length;
05504 var stath = nlines * JSROOT.gStyle.StatFontSize;
05505 if (stath <= 0 || 3 == (JSROOT.gStyle.StatFont % 10)) {
05506 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
05507 stat.pavetext['fY1NDC'] = 0.93 - stath;
05508 stat.pavetext['fY2NDC'] = 0.93;
05509 }
05510 return true;
05511 }
05512
05513 JSROOT.TH2Painter.prototype.getValueColor = function(zc) {
05514 var wmin = this.minbin, wmax = this.maxbin;
05515 var wlmin = wmin, wlmax = wmax;
05516 var ndivz = this.histo['fContour'].length;
05517 if (ndivz < 16) ndivz = 16;
05518 var scale = ndivz / (wlmax - wlmin);
05519 if (this.options.Logz) {
05520 if (wmin <= 0 && wmax > 0)
05521 wmin = Math.min(1.0, 0.001 * wmax);
05522 wlmin = Math.log(wmin) / Math.log(10);
05523 wlmax = Math.log(wmax) / Math.log(10);
05524 }
05525
05526 if (this.paletteColors.length == 0) {
05527 var saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50;
05528 for (var i = 0; i < maxPretty; i++) {
05529 var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360.0;
05530 var rgbval = JSROOT.Painter.HLStoRGB(hue, lightness, saturation);
05531 this.paletteColors.push(rgbval);
05532 }
05533 }
05534 if (this.options.Logz) zc = Math.log(zc) / Math.log(10);
05535 if (zc < wlmin) zc = wlmin;
05536 var ncolors = this.paletteColors.length;
05537 var color = Math.round(0.01 + (zc - wlmin) * scale);
05538 var theColor = Math.round((color + 0.99) * ncolors / ndivz) - 1;
05539 var icol = theColor % ncolors;
05540 if (icol < 0) icol = 0;
05541
05542 return this.paletteColors[icol];
05543 }
05544
05545 JSROOT.TH2Painter.prototype.CreateDrawBins = function(w, h, coordinates_kind, tipkind) {
05546 var i1 = this.GetSelectIndex("x", "left", 0);
05547 var i2 = this.GetSelectIndex("x", "right", 0);
05548 var j1 = this.GetSelectIndex("y", "left", 0);
05549 var j2 = this.GetSelectIndex("y", "right", 0);
05550
05551 var x1, y1, x2, y2, grx1, gry1, grx2, gry2, fillcol, shrx, shry, binz, point, wx ,wy;
05552
05553
05554 this.maxbin = this.minbin = this.histo.getBinContent(i1 + 1, j1 + 1);
05555 for (var i = i1; i < i2; i++) {
05556 for (var j = j1; j < j2; j++) {
05557 binz = this.histo.getBinContent(i + 1, j + 1);
05558 if (binz>this.maxbin) this.maxbin = binz; else
05559 if (binz<this.minbin) this.minbin = binz;
05560 }
05561 }
05562
05563 var xfactor = 1, yfactor = 1;
05564 if (coordinates_kind == 1) {
05565 xfactor = 0.5 * w / (i2 - i1) / (this.maxbin - this.minbin);
05566 yfactor = 0.5 * h / (j2 - j1) / (this.maxbin - this.minbin);
05567 }
05568
05569 var local_bins = new Array;
05570
05571 x2 = this.xmin + i1 * this.binwidthx;
05572 grx2 = -11111;
05573 for (var i = i1; i < i2; i++) {
05574 x1 = x2;
05575 x2 += this.binwidthx;
05576
05577 if (this.options.Logx && (x1 <= 0)) continue;
05578
05579 grx1 = grx2;
05580 if (grx1 < 0) grx1 = this.x(x1);
05581 grx2 = this.x(x2);
05582
05583 y2 = this.ymin + j1 * this.binwidthy;
05584 gry2 = -1111;
05585 for (var j = j1; j < j2; j++) {
05586 y1 = y2;
05587 y2 += this.binwidthy;
05588 if (this.options.Logy && (y1 <= 0)) continue;
05589 gry1 = gry2;
05590 if (gry1 < 0) gry1 = this.y(y1);
05591 gry2 = this.y(y2);
05592 binz = this.histo.getBinContent(i + 1, j + 1);
05593 if ((binz == 0) || (binz < this.minbin)) continue;
05594
05595 switch (coordinates_kind) {
05596 case 0:
05597 point = {
05598 x : grx1,
05599 y : gry2,
05600 width : grx2 - grx1 + 1,
05601 height : gry1 - gry2 + 1,
05602 stroke : "none",
05603 fill : this.getValueColor(binz)
05604 }
05605 point['tipcolor'] = (point['fill'] == "black") ? "grey" : "black";
05606 break;
05607
05608 case 1:
05609 shrx = xfactor * (this.maxbin - binz);
05610 shry = yfactor * (this.maxbin - binz);
05611 point = {
05612 x : grx1 + shrx,
05613 y : gry2 + shry,
05614 width : grx2 - grx1 - 2 * shrx,
05615 height : gry1 - gry2 - 2 * shry,
05616 stroke : this.attline.color,
05617 fill : this.fillcolor
05618 }
05619 point['tipcolor'] = (point['fill'] == "black") ? "grey" : "black";
05620 break;
05621
05622 case 2:
05623 point = {
05624 x : (x1 + x2) / 2,
05625 y : (y1 + y2) / 2,
05626 z : binz
05627 }
05628 break;
05629 }
05630
05631 if (tipkind == 1)
05632 point['tip'] = "x = [" + this.AxisAsText("x", x1) + ", " + this.AxisAsText("x", x2) + "]\n" +
05633 "y = [" + this.AxisAsText("y", y1) + ", " + this.AxisAsText("y", y2) + "]\n" +
05634 "entries = " + binz;
05635 else if (tipkind == 2)
05636 point['tip'] = "x = " + this.AxisAsText("x", x1) + "\n" +
05637 "y = " + this.AxisAsText("y", y1) + "\n" +
05638 "entries = " + binz;
05639
05640 local_bins.push(point);
05641 }
05642 }
05643
05644 return local_bins;
05645 }
05646
05647 JSROOT.TH2Painter.prototype.DrawSimpleCanvas = function(w,h) {
05648
05649 var i1 = this.GetSelectIndex("x", "left", 0);
05650 var i2 = this.GetSelectIndex("x", "right", 0);
05651 var j1 = this.GetSelectIndex("y", "left", 0);
05652 var j2 = this.GetSelectIndex("y", "right", 0);
05653
05654 this.maxbin = this.minbin = this.histo.getBinContent(i1 + 1, j1 + 1);
05655 for (var i = i1; i < i2; i++) {
05656 for (var j = j1; j < j2; j++) {
05657 binz = this.histo.getBinContent(i + 1, j + 1);
05658 if (binz>this.maxbin) this.maxbin = binz; else
05659 if (binz<this.minbin) this.minbin = binz;
05660 }
05661 }
05662
05663 var dx = i2-i1, dy = j2-j1;
05664
05665 var canvas =
05666 this.draw_g.append("foreignObject")
05667 .attr("width", w)
05668 .attr("height", h)
05669 .append("xhtml:canvas")
05670 .attr("width", dx)
05671 .attr("height", dy)
05672 .attr("style", "width: " + w + "px; height: "+ h + "px");
05673
05674 var context = canvas.node().getContext("2d");
05675 var image = context.createImageData(dx, dy);
05676
05677 var p = -1;
05678
05679 for (var j = j2-1; j >= j1; j--) {
05680 for (var i = i1; i < i2; i++) {
05681 var bin = this.histo.getBinContent(i + 1, j + 1);
05682 var col = bin>this.minbin ? this.getValueColor(bin) : 'white';
05683 var c = d3.rgb(col);
05684 image.data[++p] = c.r;
05685 image.data[++p] = c.g;
05686 image.data[++p] = c.b;
05687 image.data[++p] = 255;
05688 }
05689 }
05690
05691 context.putImageData(image, 0, 0);
05692 }
05693
05694 JSROOT.TH2Painter.prototype.DrawNormalCanvas = function(w,h) {
05695
05696 var local_bins = this.CreateDrawBins(w, h, 0, 0);
05697
05698 var foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject' );
05699
05700
05701 var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
05702
05703 $(canvas).attr('width', w).attr('height',h)
05704
05705
05706
05707 $(foreignObject).attr("width", w).attr("height", h).append(canvas);
05708
05709 $(this.draw_g.node()).append(foreignObject);
05710
05711 var ctx = canvas.getContext("2d");
05712
05713
05714
05715
05716
05717
05718
05719
05720
05721
05722
05723
05724 for (var i in local_bins) {
05725 var bin = local_bins[i];
05726 ctx.fillStyle = bin.fill;
05727 ctx.fillRect(bin.x,bin.y,bin.width,bin.height);
05728 }
05729
05730 ctx.stroke();
05731 }
05732
05733
05734 JSROOT.TH2Painter.prototype.DrawBins = function() {
05735
05736 this.RecreateDrawG();
05737
05738 var w = Number(this.svg_frame(true).attr("width")),
05739 h = Number(this.svg_frame(true).attr("height"));
05740
05741 if (this.options.Color==2)
05742 return this.DrawSimpleCanvas(w,h);
05743
05744 if (this.options.Color==3)
05745 return this.DrawNormalCanvas(w,h);
05746
05747
05748
05749
05750
05751 var draw_markers = (this.options.Scat > 0 && this.histo['fMarkerStyle'] > 1);
05752 var normal_coordinates = (this.options.Color > 0) || draw_markers;
05753
05754 var tipkind = 0;
05755 if (JSROOT.gStyle.Tooltip) tipkind = draw_markers ? 2 : 1;
05756
05757 var local_bins = this.CreateDrawBins(w, h, normal_coordinates ? 0 : 1, tipkind);
05758
05759 if (draw_markers) {
05760
05761 var marker = JSROOT.Painter.createAttMarker(this.histo);
05762
05763 var markers =
05764 this.draw_g.selectAll(".marker")
05765 .data(local_bins)
05766 .enter().append("svg:path")
05767 .attr("class", "marker")
05768 .attr("transform", function(d) { return "translate(" + d.x.toFixed(1) + "," + d.y.toFixed(1) + ")" })
05769 .call(marker.func);
05770
05771 if (JSROOT.gStyle.Tooltip)
05772 markers.append("svg:title").text(function(d) { return d.tip; });
05773 } else {
05774 var drawn_bins = this.draw_g.selectAll(".bins")
05775 .data(local_bins).enter()
05776 .append("svg:rect")
05777 .attr("class", "bins")
05778 .attr("x", function(d) { return d.x.toFixed(1); })
05779 .attr("y", function(d) { return d.y.toFixed(1); })
05780 .attr("width", function(d) { return d.width.toFixed(1); })
05781 .attr("height", function(d) { return d.height.toFixed(1); })
05782 .style("stroke", function(d) { return d.stroke; })
05783 .style("fill", function(d) {
05784 this['f0'] = d.fill;
05785 this['f1'] = d.tipcolor;
05786 return d.fill;
05787 });
05788
05789 if (JSROOT.gStyle.Tooltip)
05790 drawn_bins
05791 .on('mouseover', function() {
05792 if (JSROOT.gStyle.Tooltip)
05793 d3.select(this).transition().duration(100).style("fill", this['f1']);
05794 })
05795 .on('mouseout', function() {
05796 d3.select(this).transition().duration(100).style("fill", this['f0']);
05797 })
05798 .append("svg:title").text(function(d) { return d.tip; });
05799 }
05800
05801 delete local_bins;
05802 }
05803
05804 JSROOT.TH2Painter.prototype.Draw2D = function() {
05805
05806 if (this.options.Lego>0) this.options.Lego = 0;
05807
05808 if (this['done2d']) return;
05809
05810
05811 if ((this.FindPalette() == null) && this.create_canvas && (this.options.Zscale > 0)) {
05812
05813 var shrink = this.CreatePalette(0.04);
05814 this.svg_frame()['frame_painter'].Shrink(0, shrink);
05815 this.svg_frame()['frame_painter'].Redraw();
05816 this.CreateXY();
05817 } else if (this.options.Zscale == 0) {
05818
05819 this.FindPalette(true);
05820 }
05821
05822
05823 if (JSROOT.gStyle.AutoStat && this.create_canvas)
05824 this.CreateStat();
05825
05826 this.DrawAxes();
05827
05828 this.DrawGrids();
05829
05830 this.DrawBins();
05831
05832 if (this.create_canvas) this.DrawTitle();
05833
05834 this.DrawFunctions();
05835
05836 this.AddInteractive();
05837
05838 this['done2d'] = true;
05839 }
05840
05841 JSROOT.TH2Painter.prototype.Draw3D = function() {
05842
05843 if (this.options.Lego<=0) this.options.Lego = 1;
05844 var painter = this;
05845
05846 JSROOT.AssertPrerequisites('3d', function() {
05847 JSROOT.Painter.real_drawHistogram2D(painter);
05848 });
05849 }
05850
05851 JSROOT.Painter.drawHistogram2D = function(divid, histo, opt) {
05852
05853
05854 var painter = new JSROOT.TH2Painter(histo);
05855
05856 painter.SetDivId(divid, 1);
05857
05858
05859 painter.options = painter.DecodeOptions(opt);
05860
05861 painter.CheckPadOptions();
05862
05863 painter.ScanContent();
05864
05865 painter.CreateXY();
05866
05867 if (painter.options.Lego > 0)
05868 painter.Draw3D();
05869 else
05870 painter.Draw2D();
05871
05872 return painter;
05873 }
05874
05875 JSROOT.Painter.drawHistogram3D = function(divid, obj, opt) {
05876 JSROOT.AssertPrerequisites('3d', function() {
05877 JSROOT.Painter.real_drawHistogram3D(divid, obj, opt);
05878 });
05879 }
05880
05881
05882
05883 JSROOT.THStackPainter = function(stack) {
05884 JSROOT.TObjectPainter.call(this, stack);
05885 this.stack = stack;
05886 this.nostack = false;
05887 this.firstpainter = null;
05888 this.painters = new Array;
05889 }
05890
05891 JSROOT.THStackPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
05892
05893 JSROOT.THStackPainter.prototype.GetObject = function() {
05894 return this.stack;
05895 }
05896
05897 JSROOT.THStackPainter.prototype.drawStack = function(opt) {
05898
05899 var pad = this.root_pad();
05900 var histos = this.stack['fHists'];
05901 var nhists = histos.arr.length;
05902
05903 if (opt == null) opt = "";
05904 else opt = opt.toLowerCase();
05905 var lsame = false;
05906 if (opt.indexOf("same") != -1) {
05907 lsame = true;
05908 opt.replace("same", "");
05909 }
05910
05911 var i, h;
05912 var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
05913 for (var i = 0; i < nhists; ++i) {
05914 h = histos.arr[i];
05915 if (i == 0 || h['fXaxis']['fXmin'] < xmin)
05916 xmin = h['fXaxis']['fXmin'];
05917 if (i == 0 || h['fXaxis']['fXmax'] > xmax)
05918 xmax = h['fXaxis']['fXmax'];
05919 if (i == 0 || h['fYaxis']['fXmin'] < ymin)
05920 ymin = h['fYaxis']['fXmin'];
05921 if (i == 0 || h['fYaxis']['fXmax'] > ymax)
05922 ymax = h['fYaxis']['fXmax'];
05923 }
05924 this.nostack = opt.indexOf("nostack") == -1 ? false : true;
05925 if (!this.nostack)
05926 this.stack.buildStack();
05927
05928 var themin, themax;
05929 if (this.stack['fMaximum'] == -1111) themax = this.stack.getMaximum(opt);
05930 else themax = this.stack['fMaximum'];
05931 if (this.stack['fMinimum'] == -1111) {
05932 themin = this.stack.getMinimum(opt);
05933 if (pad && pad['fLogy']) {
05934 if (themin > 0)
05935 themin *= .9;
05936 else
05937 themin = themax * 1.e-3;
05938 } else if (themin > 0)
05939 themin = 0;
05940 } else
05941 themin = this.stack['fMinimum'];
05942 if (!('fHistogram' in this.stack)) {
05943 h = this.stack['fHists'].arr[0];
05944 this.stack['fHistogram'] = JSROOT.Create("TH1I");
05945 this.stack['fHistogram']['fName'] = "unnamed";
05946 this.stack['fHistogram']['fXaxis'] = JSROOT.clone(h['fXaxis']);
05947 this.stack['fHistogram']['fYaxis'] = JSROOT.clone(h['fYaxis']);
05948 this.stack['fHistogram']['fXaxis']['fXmin'] = xmin;
05949 this.stack['fHistogram']['fXaxis']['fXmax'] = xmax;
05950 this.stack['fHistogram']['fYaxis']['fXmin'] = ymin;
05951 this.stack['fHistogram']['fYaxis']['fXmax'] = ymax;
05952 }
05953 this.stack['fHistogram']['fTitle'] = this.stack['fTitle'];
05954
05955 var histo = this.stack['fHistogram'];
05956 if (!histo.TestBit(JSROOT.TH1StatusBits.kIsZoomed)) {
05957 if (this.nostack && this.stack['fMaximum'] != -1111)
05958 histo['fMaximum'] = this.stack['fMaximum'];
05959 else {
05960 if (pad && pad['fLogy'])
05961 histo['fMaximum'] = themax * (1 + 0.2 * JSROOT.Math.log10(themax / themin));
05962 else
05963 histo['fMaximum'] = 1.05 * themax;
05964 }
05965 if (this.nostack && this.stack['fMinimum'] != -1111)
05966 histo['fMinimum'] = this.stack['fMinimum'];
05967 else {
05968 if (pad && pad['fLogy'])
05969 histo['fMinimum'] = themin / (1 + 0.5 * JSROOT.Math.log10(themax / themin));
05970 else
05971 histo['fMinimum'] = themin;
05972 }
05973 }
05974 if (!lsame) {
05975
05976 var hopt = histo['fOption'];
05977 if ((opt != "") && (hopt.indexOf(opt) == -1))
05978 hopt += opt;
05979
05980 if (histo['_typename'].match(/^TH1/))
05981 this.firstpainter = JSROOT.Painter.drawHistogram1D(this.divid, histo, hopt);
05982 else
05983 if (histo['_typename'].match(/^TH2/))
05984 this.firstpainter = JSROOT.Painter.drawHistogram2D(this.divid, histo, hopt);
05985
05986 }
05987 for (var i = 0; i < nhists; ++i) {
05988 if (this.nostack)
05989 h = histos.arr[i];
05990 else
05991 h = this.stack['fStack'].arr[nhists - i - 1];
05992
05993 var hopt = h['fOption'];
05994 if ((opt != "") && (hopt.indexOf(opt) == -1)) hopt += opt;
05995 hopt += "same";
05996
05997 if (h['_typename'].match(/^TH1/)) {
05998 var subpainter = JSROOT.Painter.drawHistogram1D(this.divid, h, hopt);
05999 this.painters.push(subpainter);
06000 }
06001 }
06002 }
06003
06004 JSROOT.THStackPainter.prototype.UpdateObject = function(obj) {
06005 var isany = false;
06006 if (this.firstpainter)
06007 if (this.firstpainter.UpdateObject(obj['fHistogram'])) isany = true;
06008
06009 var histos = obj['fHists'];
06010 var nhists = histos.arr.length;
06011
06012 for (var i = 0; i < nhists; ++i) {
06013 var h = null;
06014
06015 if (this.nostack)
06016 h = histos.arr[i];
06017 else
06018 h = obj['fStack'].arr[nhists - i - 1];
06019
06020 if (this.painters[i].UpdateObject(h)) isany = true;
06021 }
06022
06023 return isany;
06024 }
06025
06026
06027 JSROOT.Painter.drawHStack = function(divid, stack, opt) {
06028
06029
06030
06031
06032
06033 if (!'fHists' in stack) return;
06034 if (stack['fHists'].arr.length == 0) return;
06035
06036 var painter = new JSROOT.THStackPainter(stack);
06037 painter.SetDivId(divid);
06038
06039 painter.drawStack(opt);
06040
06041 return painter
06042 }
06043
06044
06045
06046 JSROOT.TLegendPainter = function(legend) {
06047 JSROOT.TObjectPainter.call(this, legend);
06048 this.legend = legend;
06049 }
06050
06051 JSROOT.TLegendPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
06052
06053 JSROOT.TLegendPainter.prototype.GetObject = function() {
06054 return this.legend;
06055 }
06056
06057 JSROOT.TLegendPainter.prototype.drawLegend = function() {
06058 this.RecreateDrawG(true, ".text_layer");
06059
06060 var svg = this.svg_pad(true);
06061 var pave = this.legend;
06062
06063 var x = 0, y = 0, w = 0, h = 0;
06064 if (pave['fInit'] == 0) {
06065 x = pave['fX1'] * Number(svg.attr("width"));
06066 y = Number(svg.attr("height")) - pave['fY1']
06067 * Number(svg.attr("height"));
06068 w = (pave['fX2'] - pave['fX1']) * Number(svg.attr("width"));
06069 h = (pave['fY2'] - pave['fY1']) * Number(svg.attr("height"));
06070 } else {
06071 x = pave['fX1NDC'] * Number(svg.attr("width"));
06072 y = Number(svg.attr("height")) - pave['fY1NDC']
06073 * Number(svg.attr("height"));
06074 w = (pave['fX2NDC'] - pave['fX1NDC']) * Number(svg.attr("width"));
06075 h = (pave['fY2NDC'] - pave['fY1NDC']) * Number(svg.attr("height"));
06076 }
06077 y -= h;
06078 var lwidth = pave['fBorderSize'] ? pave['fBorderSize'] : 0;
06079 var fill = this.createAttFill(pave);
06080 var lcolor = JSROOT.Painter.createAttLine(pave, lwidth);
06081
06082 var p = this.draw_g
06083 .attr("x", x)
06084 .attr("y", y)
06085 .attr("width", w)
06086 .attr("height", h)
06087 .attr("transform", "translate(" + x + "," + y + ")");
06088
06089 p.append("svg:rect")
06090 .attr("x", 0)
06091 .attr("y", 0)
06092 .attr("width", w)
06093 .attr("height", h)
06094 .call(fill.func)
06095 .style("stroke-width", lwidth ? 1 : 0)
06096 .style("stroke", lcolor.color);
06097
06098 var tcolor = JSROOT.Painter.root_colors[pave['fTextColor']];
06099 var tpos_x = pave['fMargin'] * w;
06100 var nlines = pave.fPrimitives.arr.length;
06101 var font = JSROOT.Painter.getFontDetails(pave['fTextFont'], h / (nlines * 1.5));
06102
06103 var max_len = 0, mul = 1.4;
06104 for (var j = 0; j < nlines; ++j) {
06105 var line = JSROOT.Painter.translateLaTeX(pave.fPrimitives.arr[j]['fLabel']);
06106 var lw = tpos_x + font.stringWidth(svg, line);
06107 if (lw > max_len) max_len = lw;
06108 }
06109 if (max_len > w) {
06110 font.size = Math.floor(font.size * 0.95 * (w / max_len));
06111 mul *= 0.95 * (max_len / w);
06112 }
06113 var x1 = pave['fX1NDC'];
06114 var x2 = pave['fX2NDC'];
06115 var y1 = pave['fY1NDC'];
06116 var y2 = pave['fY2NDC'];
06117 var margin = pave['fMargin'] * (x2 - x1) / pave['fNColumns'];
06118 var yspace = (y2 - y1) / nlines;
06119 var ytext = y2 + 0.5 * yspace;
06120 var boxw = margin * 0.35;
06121
06122 for (var i = 0; i < nlines; ++i) {
06123 var leg = pave.fPrimitives.arr[i];
06124 var lopt = leg['fOption'].toLowerCase();
06125
06126 var string = leg['fLabel'];
06127
06128 var pos_y = ((i + 1) * (font.size * mul)) - (font.size / 3);
06129 var tpos_y = (i + 1) * (font.size * mul);
06130 if (nlines == 1) {
06131 var pos_y = (h * 0.75) - (font.size / 3);
06132 var tpos_y = h * 0.75;
06133 }
06134
06135 var attfill = leg;
06136 var attmarker = leg;
06137 var attline = leg;
06138
06139 var mo = leg['fObject'];
06140
06141 if ((mo != null) && (typeof mo == 'object')) {
06142 if ('fLineColor' in mo) attline = mo;
06143 if ('fFillColor' in mo) attfill = mo;
06144 if ('fMarkerColor' in mo) attmarker = mo;
06145 }
06146
06147 var fill = this.createAttFill(attfill);
06148 var llll = JSROOT.Painter.createAttLine(attline);
06149
06150 p.append("text")
06151 .attr("class", "text")
06152 .attr("text-anchor", "start")
06153 .attr("x", tpos_x)
06154 .attr("y", tpos_y)
06155 .call(font.func)
06156 .attr("fill", tcolor)
06157 .text(string);
06158
06159
06160 if (lopt.indexOf('f') != -1) {
06161
06162
06163 var xsym = margin / 2;
06164 var ysym = ytext;
06165 var xf = new Array(4), yf = new Array(4);
06166 xf[0] = xsym - boxw;
06167 yf[0] = ysym - yspace * 0.35;
06168 xf[1] = xsym + boxw;
06169 yf[1] = yf[0];
06170 xf[2] = xf[1];
06171 yf[2] = ysym + yspace * 0.35;
06172 xf[3] = xf[0];
06173 yf[3] = yf[2];
06174 for (var j = 0; j < 4; j++) {
06175 xf[j] = xf[j] * Number(svg.attr("width"));
06176 yf[j] = yf[j] * Number(svg.attr("height"));
06177 }
06178 var ww = xf[1] - xf[0];
06179 var hh = yf[2] - yf[0];
06180 pos_y = pos_y - (hh / 2);
06181 var pos_x = (tpos_x / 2) - (ww / 2);
06182
06183 p.append("svg:rect")
06184 .attr("x", pos_x)
06185 .attr("y", pos_y)
06186 .attr("width", ww)
06187 .attr("height", hh)
06188 .call(llll.func)
06189 .call(fill.func);
06190 }
06191
06192 if (lopt.indexOf('l') != -1) {
06193
06194
06195 var line_length = (0.7 * pave['fMargin']) * w;
06196 var pos_x = (tpos_x - line_length) / 2;
06197 p.append("svg:line")
06198 .attr("x1", pos_x)
06199 .attr("y1", pos_y)
06200 .attr("x2", pos_x + line_length)
06201 .attr("y2", pos_y)
06202 .call(llll.func);
06203 }
06204
06205 if (lopt.indexOf('e') != -1 && (lopt.indexOf('l') == -1 || lopt.indexOf('f') != -1)) {
06206 }
06207
06208 if (lopt.indexOf('p') != -1) {
06209
06210 var line_length = (0.7 * pave['fMargin']) * w;
06211 var pos_x = tpos_x / 2;
06212
06213 var marker = JSROOT.Painter.createAttMarker(attmarker);
06214 p.append("svg:path")
06215 .attr("transform", function(d) { return "translate(" + pos_x + "," + pos_y + ")"; })
06216 .call(marker.func);
06217 }
06218 }
06219 if (lwidth && lwidth > 1) {
06220 p.append("svg:line")
06221 .attr("x1", w + (lwidth / 2))
06222 .attr("y1", lwidth + 1)
06223 .attr("x2", w + (lwidth / 2))
06224 .attr("y2", h + lwidth - 1)
06225 .call(lcolor.func);
06226 p.append("svg:line")
06227 .attr("x1", lwidth + 1)
06228 .attr("y1", h + (lwidth / 2))
06229 .attr("x2", w + lwidth - 1)
06230 .attr("y2", h + (lwidth / 2))
06231 .style("stroke", lcolor)
06232 .call(lcolor.func);
06233 }
06234
06235 var pthis = this;
06236
06237 this.AddDrag('leg', this.draw_g, {
06238 move : function(x, y, dx, dy) {
06239 pthis.draw_g.attr("transform", "translate(" + x + "," + y + ")");
06240
06241 pave['fX1NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
06242 pave['fX2NDC'] += dx / Number(pthis.svg_pad(true).attr("width"));
06243 pave['fY1NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
06244 pave['fY2NDC'] -= dy / Number(pthis.svg_pad(true).attr("height"));
06245 },
06246 resize : function(width, height) {
06247 pave['fX2NDC'] = pave['fX1NDC'] + width / Number(pthis.svg_pad(true).attr("width"));
06248 pave['fY1NDC'] = pave['fY2NDC'] - height / Number(pthis.svg_pad(true).attr("height"));
06249
06250 pthis.drawLegend();
06251 }
06252 });
06253 }
06254
06255 JSROOT.TLegendPainter.prototype.Redraw = function() {
06256 this.drawLegend();
06257 }
06258
06259 JSROOT.Painter.drawLegend = function(divid, obj, opt) {
06260 var painter = new JSROOT.TLegendPainter(obj);
06261 painter.SetDivId(divid);
06262 painter.Redraw();
06263 return painter;
06264 }
06265
06266
06267
06268 JSROOT.TMultiGraphPainter = function(mgraph) {
06269 JSROOT.TObjectPainter.call(this, mgraph);
06270 this.mgraph = mgraph;
06271 this.firstpainter = null;
06272 this.painters = new Array;
06273 }
06274
06275 JSROOT.TMultiGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
06276
06277 JSROOT.TMultiGraphPainter.prototype.GetObject = function() {
06278 return this.mgraph;
06279 }
06280
06281 JSROOT.TMultiGraphPainter.prototype.UpdateObject = function(obj) {
06282
06283 if ((obj==null) || (obj['_typename'] != 'TMultiGraph')) return false;
06284
06285 var histo = obj['fHistogram'];
06286 var graphs = obj['fGraphs'];
06287
06288 var isany = false;
06289 if (this.firstpainter && histo)
06290 if (this.firstpainter.UpdateObject(histo)) isany = true;
06291
06292 for (var i in graphs.arr) {
06293 if (i>=this.painters.length) break;
06294 if (this.painters[i].UpdateObject(graphs.arr[i])) isany = true;
06295 }
06296
06297 return isany;
06298 }
06299
06300 JSROOT.TMultiGraphPainter.prototype.drawMultiGraph = function(opt) {
06301 var maximum, minimum, rwxmin = 0, rwxmax = 0, rwymin = 0, rwymax = 0, uxmin = 0, uxmax = 0, dx, dy;
06302 var histo = this.mgraph['fHistogram'];
06303 var graphs = this.mgraph['fGraphs'];
06304 var scalex = 1, scaley = 1;
06305 var logx = false, logy = false, logz = false, gridx = false, gridy = false;
06306 var draw_all = true;
06307
06308 var pad = this.root_pad();
06309
06310 if (pad!=null) {
06311 rwxmin = pad.fUxmin;
06312 rwxmax = pad.fUxmax;
06313 rwymin = pad.fUymin;
06314 rwymax = pad.fUymax;
06315 logx = pad['fLogx'];
06316 logy = pad['fLogy'];
06317 logz = pad['fLogz'];
06318 gridx = pad['fGridx'];
06319 gridy = pad['fGridy'];
06320 }
06321 if (histo!=null) {
06322 minimum = histo['fYaxis']['fXmin'];
06323 maximum = histo['fYaxis']['fXmax'];
06324 if (pad) {
06325 uxmin = JSROOT.Painter.padtoX(pad, rwxmin);
06326 uxmax = JSROOT.Painter.padtoX(pad, rwxmax);
06327 }
06328 } else {
06329 for (var i = 0; i < graphs.arr.length; ++i) {
06330 var r = graphs.arr[i].ComputeRange();
06331 if ((i==0) || (r.xmin < rwxmin)) rwxmin = r.xmin;
06332 if ((i==0) || (r.ymin < rwymin)) rwymin = r.ymin;
06333 if ((i==0) || (r.xmax > rwxmax)) rwxmax = r.xmax;
06334 if ((i==0) || (r.ymax > rwymax)) rwymax = r.ymax;
06335 }
06336 if (rwxmin == rwxmax)
06337 rwxmax += 1.;
06338 if (rwymin == rwymax)
06339 rwymax += 1.;
06340 dx = 0.05 * (rwxmax - rwxmin);
06341 dy = 0.05 * (rwymax - rwymin);
06342 uxmin = rwxmin - dx;
06343 uxmax = rwxmax + dx;
06344 if (logy) {
06345 if (rwymin <= 0)
06346 rwymin = 0.001 * rwymax;
06347 minimum = rwymin / (1 + 0.5 * JSROOT.Math.log10(rwymax / rwymin));
06348 maximum = rwymax * (1 + 0.2 * JSROOT.Math.log10(rwymax / rwymin));
06349 } else {
06350 minimum = rwymin - dy;
06351 maximum = rwymax + dy;
06352 }
06353 if (minimum < 0 && rwymin >= 0)
06354 minimum = 0;
06355 if (maximum > 0 && rwymax <= 0)
06356 maximum = 0;
06357 }
06358 if (this.mgraph['fMinimum'] != -1111)
06359 rwymin = minimum = this.mgraph['fMinimum'];
06360 if (this.mgraph['fMaximum'] != -1111)
06361 rwymax = maximum = this.mgraph['fMaximum'];
06362 if (uxmin < 0 && rwxmin >= 0) {
06363 if (logx) uxmin = 0.9 * rwxmin;
06364
06365 }
06366 if (uxmax > 0 && rwxmax <= 0) {
06367 if (logx) uxmax = 1.1 * rwxmax;
06368 }
06369 if (minimum < 0 && rwymin >= 0) {
06370 if (logy) minimum = 0.9 * rwymin;
06371 }
06372 if (maximum > 0 && rwymax <= 0) {
06373 if (logy) maximum = 1.1 * rwymax;
06374 }
06375 if (minimum <= 0 && logy)
06376 minimum = 0.001 * maximum;
06377 if (uxmin <= 0 && logx) {
06378 if (uxmax > 1000)
06379 uxmin = 1;
06380 else
06381 uxmin = 0.001 * uxmax;
06382 }
06383 rwymin = minimum;
06384 rwymax = maximum;
06385 if (histo!=null) {
06386 histo['fYaxis']['fXmin'] = rwymin;
06387 histo['fYaxis']['fXmax'] = rwymax;
06388 }
06389
06390
06391 if (!histo) {
06392 histo = JSROOT.Create("TH1I");
06393 histo['fXaxis']['fXmin'] = rwxmin;
06394 histo['fXaxis']['fXmax'] = rwxmax;
06395 histo['fYaxis']['fXmin'] = rwymin;
06396 histo['fYaxis']['fXmax'] = rwymax;
06397 }
06398
06399
06400
06401 this.firstpainter = JSROOT.Painter.drawHistogram1D(this.divid, histo);
06402
06403 for ( var i in graphs.arr) {
06404 var subpainter = JSROOT.Painter.drawGraph(this.divid, graphs.arr[i]);
06405 this.painters.push(subpainter);
06406 }
06407 }
06408
06409 JSROOT.Painter.drawMultiGraph = function(divid, mgraph, opt) {
06410 var painter = new JSROOT.TMultiGraphPainter(mgraph);
06411 painter.SetDivId(divid);
06412 painter.drawMultiGraph(opt);
06413 return painter;
06414 }
06415
06416
06417
06418 JSROOT.TTextPainter = function(text) {
06419 JSROOT.TObjectPainter.call(this, text);
06420 this.text = text;
06421 }
06422
06423 JSROOT.TTextPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
06424
06425 JSROOT.TTextPainter.prototype.GetObject = function() {
06426 return this.text;
06427 }
06428
06429 JSROOT.TTextPainter.prototype.drawPaveLabel = function() {
06430
06431 this.RecreateDrawG(true, ".text_layer");
06432
06433 var pavelabel = this.text;
06434
06435 var w = Number(this.svg_pad(true).attr("width")),
06436 h = Number(this.svg_pad(true).attr("height"));
06437
06438 var pos_x = pavelabel['fX1NDC'] * w;
06439 var pos_y = (1.0 - pavelabel['fY1NDC']) * h;
06440 var width = Math.abs(pavelabel['fX2NDC'] - pavelabel['fX1NDC']) * w;
06441 var height = Math.abs(pavelabel['fY2NDC'] - pavelabel['fY1NDC']) * h;
06442 pos_y -= height;
06443 var fcolor = this.createAttFill(pavelabel);
06444 var tcolor = JSROOT.Painter.root_colors[pavelabel['fTextColor']];
06445 var scolor = JSROOT.Painter.root_colors[pavelabel['fShadowColor']];
06446
06447
06448
06449
06450 var align = 'start', halign = Math.round(pavelabel['fTextAlign'] / 10);
06451 var baseline = 'bottom', valign = pavelabel['fTextAlign'] % 10;
06452 if (halign == 1) align = 'start';
06453 else if (halign == 2) align = 'middle';
06454 else if (halign == 3) align = 'end';
06455 if (valign == 1) baseline = 'bottom';
06456 else if (valign == 2) baseline = 'middle';
06457 else if (valign == 3) baseline = 'top';
06458 var lmargin = 0;
06459 switch (halign) {
06460 case 1: lmargin = pavelabel['fMargin'] * width; break;
06461 case 2: lmargin = width / 2; break;
06462 case 3: lmargin = width - (pavelabel['fMargin'] * width); break;
06463 }
06464 var lwidth = pavelabel['fBorderSize'] ? pavelabel['fBorderSize'] : 0;
06465 var font = JSROOT.Painter.getFontDetails(pavelabel['fTextFont'], height / 1.9);
06466
06467 var lcolor = JSROOT.Painter.createAttLine(pavelabel, lwidth);
06468
06469 var pave = this.draw_g
06470 .attr("width", width)
06471 .attr("height", height)
06472 .attr("transform", "translate(" + pos_x + "," + pos_y + ")");
06473
06474 pave.append("svg:rect")
06475 .attr("x", 0)
06476 .attr("y", 0)
06477 .attr("width", width)
06478 .attr("height", height)
06479 .call(fcolor.func)
06480 .style("stroke-width", lwidth ? 1 : 0)
06481 .style("stroke", lcolor.color);
06482
06483 var line = JSROOT.Painter.translateLaTeX(pavelabel['fLabel']);
06484
06485 var lw = font.stringWidth(this.svg_pad(true), line);
06486 if (lw > width) font.size = Math.floor(font.size * (width / lw));
06487
06488 pave.append("text")
06489 .attr("class", "text")
06490 .attr("text-anchor", align)
06491 .attr("x", lmargin)
06492 .attr("y", (height / 2) + (font.size / 3))
06493 .call(font.func)
06494 .attr("fill", tcolor)
06495 .text(line);
06496
06497 if (lwidth && lwidth > 1) {
06498 pave.append("svg:line")
06499 .attr("x1", width + (lwidth / 2))
06500 .attr("y1", lwidth + 1)
06501 .attr("x2", width + (lwidth / 2))
06502 .attr("y2", height + lwidth - 1)
06503 .call(lcolor.func);
06504 pave.append("svg:line")
06505 .attr("x1", lwidth + 1)
06506 .attr("y1", height + (lwidth / 2))
06507 .attr("x2", width + lwidth - 1)
06508 .attr("y2", height + (lwidth / 2))
06509 .style("stroke", lcolor)
06510 .call(lcolor.func);
06511 }
06512 }
06513
06514 JSROOT.TTextPainter.prototype.drawText = function() {
06515 this.RecreateDrawG(true, ".text_layer");
06516
06517 var kTextNDC = JSROOT.BIT(14);
06518
06519 var w = Number(this.svg_pad(true).attr("width")),
06520 h = Number(this.svg_pad(true).attr("height"));
06521 var align = 'start', halign = Math.round(this.text['fTextAlign'] / 10);
06522 var baseline = 'bottom', valign = this.text['fTextAlign'] % 10;
06523 if (halign == 1) align = 'start';
06524 else if (halign == 2) align = 'middle';
06525 else if (halign == 3) align = 'end';
06526 if (valign == 1) baseline = 'bottom';
06527 else if (valign == 2) baseline = 'middle';
06528 else if (valign == 3) baseline = 'top';
06529 var lmargin = 0;
06530 switch (halign) {
06531 case 1: lmargin = this.text['fMargin'] * w; break;
06532 case 2: lmargin = w / 2; break;
06533 case 3: lmargin = w - (this.text['fMargin'] * w); break;
06534 }
06535 var pos_x = this.text['fX'], pos_y = this.text['fY'];
06536 if (this.text.TestBit(kTextNDC)) {
06537 pos_x = pos_x * w;
06538 pos_y = (1 - pos_y) * h;
06539 } else
06540 if (this.main_painter()!=null) {
06541 pos_x = this.main_painter().x(pos_x);
06542 pos_y = this.main_painter().y(pos_y);
06543 } else
06544 if (this.root_pad()!=null) {
06545 var pad = this.root_pad();
06546 if (pad['fLogx'])
06547 pos_x = (pos_x > 0) ? JSROOT.Math.log10(pos_x) : pad['fUxmin'];
06548 if (pad['fLogy'])
06549 pos_y = (pos_y > 0) ? JSROOT.Math.log10(pos_y) : pad['fUymin'];
06550
06551 pos_x = ((Math.abs(pad['fX1']) + pos_x) / (pad['fX2'] - pad['fX1'])) * w;
06552 pos_y = (1 - ((Math.abs(pad['fY1']) + pos_y) / (pad['fY2'] - pad['fY1']))) * h;
06553 } else {
06554 alert("Cannot draw text at x/y coordinates without real TPad object");
06555 pos_x = w/2;
06556 pos_y = h/2;
06557 }
06558
06559 var tcolor = JSROOT.Painter.root_colors[this.text['fTextColor']];
06560 var font = JSROOT.Painter.getFontDetails(this.text['fTextFont'], this.text['fTextSize'] * Math.min(w,h));
06561
06562 var string = this.text['fTitle'];
06563
06564 if (this.text['_typename'] == 'TLatex')
06565 string = JSROOT.Painter.translateLaTeX(string);
06566
06567 this.draw_g.append("text")
06568 .attr("class", "text")
06569 .attr("x", pos_x.toFixed(1))
06570 .attr("y", pos_y.toFixed(1))
06571 .call(font.func)
06572 .attr("text-anchor", align)
06573 .attr("fill", tcolor)
06574 .text(string);
06575 }
06576
06577 JSROOT.TTextPainter.prototype.UpdateObject = function(obj) {
06578 if (this.text['_typename'] != obj['_typename']) return false;
06579 if (this.text['_typename'] == 'TPaveLabel') {
06580 this.text['fLabel'] = obj['fLabel'];
06581 } else {
06582 this.text['fTitle'] = obj['fTitle'];
06583 }
06584
06585 return true;
06586 }
06587
06588
06589 JSROOT.TTextPainter.prototype.Redraw = function() {
06590 if (this.text['_typename'] == 'TPaveLabel')
06591 this.drawPaveLabel();
06592 else
06593 this.drawText();
06594 }
06595
06596 JSROOT.Painter.drawText = function(divid, text) {
06597 var painter = new JSROOT.TTextPainter(text);
06598 painter.SetDivId(divid);
06599 painter.Redraw();
06600 return painter;
06601 }
06602
06603 JSROOT.Painter.drawStreamerInfo = function(divid, obj) {
06604 $("#" + divid).css({ overflow : 'auto' });
06605 var painter = new JSROOT.HierarchyPainter('sinfo', divid, true);
06606 painter.ShowStreamerInfo(obj);
06607 return painter;
06608 }
06609
06610
06611
06612 JSROOT.HList = [];
06613
06614 JSROOT.DelHList = function(_name) {
06615 for ( var i in JSROOT.HList)
06616 if (JSROOT.HList[i].name == _name) {
06617 var old = JSROOT.HList[i];
06618 JSROOT.HList.splice(i, 1);
06619 delete old;
06620 return true;
06621 }
06622 }
06623
06624 JSROOT.AddHList = function(_name, _h) {
06625 JSROOT.DelHList(_name);
06626 JSROOT.HList.push({
06627 name : _name,
06628 h : _h
06629 });
06630 }
06631
06632 JSROOT.H = function(name) {
06633 for ( var i in JSROOT.HList)
06634 if (JSROOT.HList[i].name == name)
06635 return JSROOT.HList[i].h;
06636 return null;
06637 }
06638
06639 JSROOT.HierarchyPainter = function(name, frameid, local) {
06640 JSROOT.TBasePainter.call(this);
06641 this.name = name;
06642 this.frameid = frameid;
06643 this.h = null;
06644 this.local = local;
06645 if (!this.local) JSROOT.AddHList(name, this);
06646 }
06647
06648 JSROOT.HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
06649
06650 JSROOT.HierarchyPainter.prototype.Cleanup = function() {
06651 if (!this.local) JSROOT.DelHList(this.name);
06652 }
06653
06654 JSROOT.HierarchyPainter.prototype.GlobalName = function(suffix) {
06655 var res = "JSROOT.H(\'" + this.name + "\')";
06656 if (suffix != null) res += suffix;
06657 return res;
06658 }
06659
06660 JSROOT.HierarchyPainter.prototype.ListHierarchy = function(folder, lst) {
06661 folder['_childs'] = [];
06662 for ( var i in lst.arr) {
06663 var obj = lst.arr[i];
06664 var item = {
06665 _name : obj['fName'],
06666 _kind : "ROOT." + obj['_typename'],
06667 _readobj : obj
06668 };
06669 folder._childs.push(item);
06670 }
06671 }
06672
06673 JSROOT.HierarchyPainter.prototype.StreamerInfoHierarchy = function(folder, lst) {
06674 folder['_childs'] = [];
06675
06676 for ( var i in lst.arr) {
06677 var entry = lst.arr[i]
06678
06679 if (typeof (entry['fName']) == 'undefined') {
06680 console.log("strange element in StreamerInfo with name " + entry['fName']);
06681 continue;
06682 }
06683
06684 var item = {
06685 _name : entry['fName'],
06686 _kind : "",
06687 _childs : []
06688 };
06689
06690 folder._childs.push(item);
06691
06692 item._childs.push({ _name : 'Checksum: ' + entry['fCheckSum'] });
06693 item._childs.push({ _name : 'Class version: ' + entry['fClassVersion'] });
06694 if (entry['fTitle'] != '') item._childs.push({ _name : 'Title: ' + entry['fTitle'] });
06695 if (typeof entry['fElements'] == 'undefined') continue;
06696 for ( var l in entry['fElements']['arr']) {
06697 var elem = entry['fElements']['arr'][l];
06698 if ((elem == null) || (typeof (elem['fName']) == 'undefined')) continue;
06699 var info = elem['fTypeName'] + " " + elem['fName'] + ";";
06700 if (elem['fTitle'] != '') info += " // " + elem['fTitle'];
06701 item._childs.push({ _name : info });
06702 }
06703 }
06704 }
06705
06706 JSROOT.HierarchyPainter.prototype.TreeHierarchy = function(node, obj) {
06707 node._childs = [];
06708
06709 for ( var i in obj['fBranches'].arr) {
06710 var branch = obj['fBranches'].arr[i];
06711 var nb_leaves = branch['fLeaves'].arr.length;
06712
06713
06714 if (nb_leaves == 1 && branch['fLeaves'].arr[0]['fName'] == branch['fName']) nb_leaves = 0;
06715
06716 var subitem = {
06717 _name : branch['fName'],
06718 _kind : nb_leaves > 0 ? "ROOT.TBranch" : "ROOT.TLeafF"
06719 }
06720
06721 node._childs.push(subitem);
06722
06723 if (nb_leaves > 0) {
06724 subitem._childs = [];
06725 for (var j = 0; j < nb_leaves; ++j) {
06726 var leafitem = {
06727 _name : branch['fLeaves'].arr[j]['fName'],
06728 _kind : "ROOT.TLeafF"
06729 }
06730 subitem._childs.push(leafitem);
06731 }
06732 }
06733 }
06734 }
06735
06736 JSROOT.HierarchyPainter.prototype.KeysHierarchy = function(folder, keys, file) {
06737 folder['_childs'] = [];
06738
06739 var painter = this;
06740 for (var i in keys) {
06741 var key = keys[i];
06742
06743 var item = {
06744 _name : key['fName'] + ";" + key['fCycle'],
06745 _kind : "ROOT." + key['fClassName'],
06746 _title : key['fTitle'],
06747 _keyname : key['fName'],
06748 _readobj : null
06749 };
06750
06751 if ('fRealName' in key)
06752 item['_realname'] = key['fRealName'] + ";" + key['fCycle'];
06753
06754 if ((key['fClassName'] == 'TTree' || key['fClassName'] == 'TNtuple')) {
06755 item["_more"] = true;
06756
06757 item['_expand'] = function(node, obj) {
06758 painter.TreeHierarchy(node, obj);
06759 return true;
06760 }
06761 } else if (key['fClassName'] == 'TDirectory' || key['fClassName'] == 'TDirectoryFile') {
06762 item["_more"] = true;
06763 item["_isdir"] = true;
06764 item['_expand'] = function(node, obj) {
06765 painter.KeysHierarchy(node, obj.fKeys);
06766 return true;
06767 }
06768 } else if ((key['fClassName'] == 'TList') && (key['fName'] == 'StreamerInfo') && (file != null)) {
06769 item['_name'] = 'StreamerInfo';
06770 item['_kind'] = "ROOT.TStreamerInfoList";
06771 item['_title'] = "List of streamer infos for binary I/O";
06772 item['_readobj'] = file.fStreamerInfos;
06773 item['_expand'] = function(node, obj) {
06774 painter.StreamerInfoHierarchy(node, obj);
06775 return true;
06776 }
06777
06778 } else if (key['fClassName'] == 'TList'
06779 || key['fClassName'] == 'TObjArray'
06780 || key['fClassName'] == 'TClonesArray') {
06781 item["_more"] = true;
06782 item['_expand'] = function(node, obj) {
06783 painter.ListHierarchy(node, obj);
06784 return true;
06785 }
06786 }
06787
06788 folder._childs.push(item);
06789 }
06790 }
06791
06792 JSROOT.HierarchyPainter.prototype.FileHierarchy = function(file) {
06793 var painter = this;
06794
06795 var folder = {
06796 _name : file.fFileName,
06797 _kind : "ROOT.TFile",
06798 _file : file,
06799
06800 _get : function(item, callback) {
06801 if ((this._file == null) || (item._readobj != null)) {
06802 if (typeof callback == 'function')
06803 callback(item, item._readobj);
06804 return;
06805 }
06806
06807 var fullname = painter.itemFullName(item, this);
06808
06809
06810
06811 this._file.ReadObject(fullname, function(obj) {
06812 item._readobj = obj;
06813 if ('_expand' in item)
06814 item._name = item._keyname;
06815
06816 if (typeof callback == 'function')
06817 callback(item, obj);
06818 });
06819 },
06820
06821
06822 _getdirect : function(itemname, callback) {
06823 this._file.ReadObject(itemname, function(obj) {
06824 if (typeof callback == 'function')
06825 callback(itemname, obj);
06826 });
06827 }
06828 };
06829
06830 this.KeysHierarchy(folder, file.fKeys, file);
06831
06832 return folder;
06833 }
06834
06835 JSROOT.HierarchyPainter.prototype.Find = function(itemname, force) {
06836
06837 function find_in_hierarchy(top, fullname) {
06838
06839 if (!fullname || fullname.length == 0) return top;
06840
06841 var pos = -1;
06842
06843 function process_child(child) {
06844
06845 child['_parent'] = top;
06846 if ((pos + 1 == fullname.length) || (pos < 0)) return child;
06847
06848 return find_in_hierarchy(child, fullname.substr(pos + 1));
06849 }
06850
06851 do {
06852
06853 pos = fullname.indexOf("/", pos + 1);
06854
06855 var localname = (pos < 0) ? fullname : fullname.substr(0, pos);
06856
06857 for (var i in top._childs)
06858 if (top._childs[i]._name == localname)
06859 return process_child(top._childs[i]);
06860
06861 if (force) {
06862
06863 if (! ('_childs' in top)) top['_childs'] = [];
06864 var child = { _name: localname };
06865 top['_childs'].push(child);
06866 return process_child(child);
06867 }
06868 } while (pos > 0);
06869
06870 return null;
06871 }
06872
06873 return find_in_hierarchy(this.h, itemname);
06874 }
06875
06876 JSROOT.HierarchyPainter.prototype.itemFullName = function(node, uptoparent) {
06877 var res = "";
06878
06879 while ('_parent' in node) {
06880 if (res.length > 0) res = "/" + res;
06881 res = node._name + res;
06882 node = node._parent;
06883 if ((uptoparent != null) && (node == uptoparent)) break;
06884 }
06885
06886 return res;
06887 }
06888
06889 JSROOT.HierarchyPainter.prototype.CheckCanDo = function(node) {
06890 var cando = { expand : false, display : false, scan : true, open : false,
06891 img1 : "", img2 : "", html : "", ctxt : false };
06892
06893 var kind = node["_kind"];
06894 if (kind == null) kind = "";
06895
06896 cando.expand = ('_more' in node);
06897
06898 if (node == this.h) {
06899 cando.ctxt = true;
06900 } else if (kind == "ROOT.Session") {
06901 cando.img1 = "img_globe";
06902 } else if (kind.match(/^ROOT.TH1/)) {
06903 cando.img1 = "img_histo1d";
06904 cando.scan = false;
06905 cando.display = true;
06906 } else if (kind.match(/^ROOT.TH2/)) {
06907 cando.img1 = "img_histo2d";
06908 cando.scan = false;
06909 cando.display = true;
06910 } else if (kind.match(/^ROOT.TH3/)) {
06911 cando.img1 = "img_histo3d";
06912 cando.scan = false;
06913 cando.display = true;
06914 } else if (kind == "ROOT.TCanvas") {
06915 cando.img1 = "img_canvas";
06916 cando.display = true;
06917 } else if (kind == "ROOT.TProfile") {
06918 cando.img1 = "img_profile";
06919 cando.display = true;
06920 } else if (kind.match(/^ROOT.TGraph/) || (kind=="TCutG")) {
06921 cando.img1 = "img_graph";
06922 cando.display = true;
06923 } else if (kind == "ROOT.TF1") {
06924 cando.img1 = "img_graph";
06925 cando.display = true;
06926 } else if (kind == "ROOT.TTree") {
06927 cando.img1 = "img_tree";
06928 } else if (kind == "ROOT.TFolder") {
06929 cando.img1 = "img_folder";
06930 cando.img2 = "img_folderopen";
06931 } else if (kind == "ROOT.TNtuple")
06932 cando.img1 = "img_tree";
06933 else if (kind == "ROOT.TBranch")
06934 cando.img1 = "img_branch";
06935 else if (kind.match(/^ROOT.TLeaf/))
06936 cando.img1 = "img_leaf";
06937 else if (kind == "ROOT.TStreamerInfoList") {
06938 cando.img1 = 'img_question';
06939 cando.expand = false;
06940 cando.display = true;
06941 } else if ((kind.indexOf("ROOT.") == 0) && JSROOT.canDraw(kind.slice(5))) {
06942 cando.img1 = "img_histo1d";
06943 cando.scan = false;
06944 cando.display = true;
06945 }
06946
06947 return cando;
06948 }
06949
06950 JSROOT.HierarchyPainter.prototype.RefreshHtml = function(force) {
06951 if (this.frameid == null) return;
06952 var elem = $("#" + this.frameid);
06953 if (elem.length == 0) return;
06954
06955 if (this.h == null) return elem.html("<h2>null</h2>");
06956
06957 this['html'] = "<p>";
06958
06959 this['html'] += "<a href='#open_all'>open all</a>";
06960 this['html'] += "| <a href='#close_all'>close all</a>";
06961 if ('_online' in this.h)
06962 this['html'] += "| <a href='#reload'>reload</a>";
06963 else
06964 this['html'] += "<a/>"
06965
06966 if ('disp_kind' in this)
06967 this['html'] += "| <a href='#clear'>clear</a>";
06968 else
06969 this['html'] += "<a/>"
06970
06971 this['html'] += "</p>";
06972
06973 this['html'] += '<div class="h_tree">'
06974 this.addItemHtml(this.h, null);
06975 this['html'] += '</div>';
06976
06977 var h = this;
06978
06979 var items = elem.html(this['html'])
06980 .find(".h_item")
06981 .click(function() { h.tree_click($(this)); });
06982
06983 if ('disp_kind' in h) {
06984 if (JSROOT.gStyle.DragAndDrop)
06985 items.draggable({ revert: "invalid", appendTo: "body", helper: "clone" });
06986
06987 if (JSROOT.gStyle.ContextMenu)
06988 items.on('contextmenu', function(e) { h.tree_contextmenu($(this), e); })
06989 }
06990
06991 elem.find(".plus_minus").click(function() { h.tree_click($(this),true); });
06992
06993 elem.find("a").first().click(function() { h.toggle(true); return false; })
06994 .next().click(function() { h.toggle(false); return false; })
06995 .next().click(function() { h.reload(); return false; })
06996 .next().click(function() { h.clear(); return false; });
06997 }
06998
06999 JSROOT.HierarchyPainter.prototype.isLastSibling = function(hitem) {
07000 return hitem && hitem._parent && hitem._parent._childs &&
07001 (hitem._parent._childs.indexOf(hitem) == hitem._parent._childs.length-1);
07002 }
07003
07004 JSROOT.HierarchyPainter.prototype.addItemHtml = function(hitem, parent) {
07005 var isroot = (parent == null);
07006 var has_childs = '_childs' in hitem;
07007 var cando = this.CheckCanDo(hitem);
07008
07009 if (!isroot) hitem._parent = parent;
07010
07011 var can_click = false;
07012
07013 if (!has_childs || !cando.scan) {
07014 if (cando.expand) {
07015 can_click = true;
07016 if (cando.img1.length == 0) {
07017 cando.img1 = 'img_folder';
07018 cando.img2 = 'img_folderopen';
07019 }
07020 } else
07021 if (cando.display) {
07022 can_click = true;
07023 } else
07024 if (cando.html.length > 0) can_click = true;
07025 }
07026
07027 if (!('_icon' in hitem)) hitem['_icon'] = cando.img1;
07028 if (!('_icon2' in hitem)) hitem['_icon2'] = cando.img2;
07029 if (hitem['_icon2']=="") hitem['_icon2'] = hitem['_icon'];
07030
07031
07032
07033 if (!hitem['_icon'])
07034 hitem['_icon'] = has_childs ? "img_folder" : "img_page";
07035
07036 if (!hitem['_icon2'])
07037 hitem['_icon2'] = has_childs ? "img_folderopen" : "img_page";
07038
07039 if (isroot)
07040 hitem['_icon'] = hitem['_icon2'] = "img_base";
07041
07042 var itemname = this.itemFullName(hitem);
07043
07044 this['html'] += '<div item="' + itemname + '">';
07045
07046
07047 var sindent = "";
07048 var prnt = isroot ? null : hitem._parent;
07049 while ((prnt != null) && (prnt != this.h)) {
07050 sindent = '<div class="' + (this.isLastSibling(prnt) ? "img_empty" : "img_line") + '"/>' + sindent;
07051 prnt = prnt._parent;
07052 }
07053 this['html'] += sindent;
07054
07055 var icon_class = "", plusminus = false;
07056
07057 if (isroot) {
07058
07059 } else
07060 if (has_childs) {
07061 icon_class = hitem._isopen ? "img_minus" : "img_plus";
07062 plusminus = true;
07063 } else {
07064 icon_class = "img_join";
07065 }
07066
07067 if (icon_class.length > 0) {
07068 this['html'] += '<div class="' + icon_class;
07069 if (this.isLastSibling(hitem)) this['html'] += "bottom";
07070 if (plusminus) this['html'] += ' plus_minus" style="cursor:pointer';
07071 this['html'] += '"/>';
07072 }
07073
07074
07075
07076 var icon_name = hitem._isopen ? hitem._icon2 : hitem._icon;
07077
07078 if (icon_name.indexOf("img_")==0)
07079 this['html'] += '<div class="' + icon_name + '"/>';
07080 else
07081 this['html'] += '<img src="' + icon_name + '" alt=""/>';
07082
07083 this['html'] += '<a';
07084 if (can_click || has_childs) this['html'] +=' class="h_item"';
07085
07086 var element_name = hitem._name;
07087
07088 if ('_realname' in hitem)
07089 element_name = hitem._realname;
07090
07091 var element_title = "";
07092 if ('_title' in hitem) element_title = hitem._title;
07093
07094 if ('_fullname' in hitem)
07095 element_title += " fullname: " + hitem['_fullname'];
07096
07097 if (element_title.length == 0) element_title = element_name;
07098
07099 this['html'] += ' title="' + element_title + '"';
07100 this['html'] += '>' + element_name + '</a>';
07101
07102 if (has_childs && (isroot || hitem._isopen)) {
07103 this['html'] += '<div class="h_childs">';
07104 for (var i in hitem._childs)
07105 this.addItemHtml(hitem._childs[i], hitem);
07106 this['html'] += '</div>';
07107 }
07108
07109 this['html'] += '</div>';
07110 }
07111
07112 JSROOT.HierarchyPainter.prototype.tree_click = function(node, plusminus) {
07113
07114 var itemname = node.parent().attr('item');
07115
07116 if (itemname==null) return;
07117
07118 var hitem = this.Find(itemname);
07119 if (hitem==null) return;
07120
07121 if (!plusminus) {
07122 var cando = this.CheckCanDo(hitem);
07123
07124 if (cando.open && (cando.html.length>0))
07125 return window.open(cando.html);
07126
07127 if (cando.expand && (hitem['_childs'] == null))
07128 return this.expand(itemname, hitem, node.parent());
07129
07130 if (cando.display)
07131 return this.display(itemname);
07132
07133 if (!('_childs' in hitem) || (hitem === this.h)) return;
07134 }
07135
07136 if (hitem._isopen)
07137 delete hitem._isopen;
07138 else
07139 hitem._isopen = true;
07140
07141 this.UpdateTreeNode(node.parent(), hitem);
07142 }
07143
07144 JSROOT.HierarchyPainter.prototype.open = function(itemname) {
07145 console.log("open() no longer available");
07146 }
07147
07148 JSROOT.HierarchyPainter.prototype.UpdateTreeNode = function(node, hitem) {
07149 var has_childs = '_childs' in hitem;
07150
07151 var newname = hitem._isopen ? hitem._icon2 : hitem._icon;
07152 var oldname = hitem._isopen ? hitem._icon : hitem._icon2;
07153
07154 var img = node.find("a").first().prev();
07155
07156 if (newname.indexOf("img_")<0) {
07157 img.attr("src", newname);
07158 } else {
07159 if (newname!=oldname)
07160 img.switchClass(oldname, newname);
07161 }
07162
07163 img = img.prev();
07164
07165 var h = this;
07166
07167 var new_class = hitem._isopen ? "img_minus" : "img_plus";
07168 if (this.isLastSibling(hitem)) new_class += "bottom";
07169
07170 if (img.hasClass("plus_minus")) {
07171 img.attr('class', new_class + " plus_minus");
07172 } else
07173 if (has_childs) {
07174 img.attr('class', new_class + " plus_minus");
07175 img.css('cursor', 'pointer');
07176 img.click(function() { h.tree_click($(this), true); });
07177 }
07178
07179 var childs = node.children().last();
07180 if (childs.hasClass("h_childs")) childs.remove();
07181
07182 var display_childs = has_childs && hitem._isopen;
07183 if (!display_childs) return;
07184
07185 this['html'] = '<div class="h_childs">';
07186 for (var i in hitem._childs)
07187 this.addItemHtml(hitem._childs[i], hitem);
07188 this['html'] += '</div>';
07189 node.append(this['html']);
07190 childs = node.children().last();
07191
07192 var items = childs.find(".h_item")
07193 .click(function() { h.tree_click($(this)); });
07194
07195 if ('disp_kind' in h) {
07196 if (JSROOT.gStyle.DragAndDrop)
07197 items.draggable({ revert: "invalid", appendTo: "body", helper: "clone" });
07198
07199 if (JSROOT.gStyle.ContextMenu)
07200 items.on('contextmenu', function(e) { h.tree_contextmenu($(this), e); })
07201 }
07202
07203 childs.find(".plus_minus").click(function() { h.tree_click($(this), true); });
07204 }
07205
07206 JSROOT.HierarchyPainter.prototype.toggle = function(status) {
07207 var painter = this;
07208
07209 var toggleItem = function(hitem) {
07210
07211 if (hitem != painter.h)
07212 if (status)
07213 hitem._isopen = true;
07214 else
07215 delete hitem._isopen;
07216
07217 if ('_childs' in hitem)
07218 for ( var i in hitem._childs)
07219 toggleItem(hitem._childs[i]);
07220 }
07221
07222 toggleItem(this.h);
07223
07224 this.RefreshHtml();
07225 }
07226
07227 JSROOT.HierarchyPainter.prototype.get = function(itemname, callback, options) {
07228 var item = this.Find(itemname);
07229
07230
07231 if ((item == null) && ('_getdirect' in this.h))
07232 return this.h._getdirect(itemname, callback);
07233
07234
07235 var curr = item;
07236 while (curr != null) {
07237 if (('_get' in curr) && (typeof (curr._get) == 'function'))
07238 return curr._get(item, callback);
07239 curr = ('_parent' in curr) ? curr['_parent'] : null;
07240 }
07241
07242 if (typeof callback == 'function')
07243 callback(item, null);
07244 }
07245
07246 JSROOT.HierarchyPainter.prototype.draw = function(divid, obj, drawopt) {
07247
07248 return JSROOT.draw(divid, obj, drawopt);
07249 }
07250
07251 JSROOT.HierarchyPainter.prototype.display = function(itemname, drawopt, call_back) {
07252
07253 function do_call_back(res) {
07254 if (typeof call_back=='function') call_back(res);
07255 }
07256
07257 if (!this.CreateDisplay()) return do_call_back(null);
07258
07259 var h = this;
07260
07261 var mdi = h['disp'];
07262
07263 var updating = drawopt=="update";
07264
07265 if (updating) {
07266 var item = h.Find(itemname);
07267 if ((item==null) || ('_doing_update' in item)) return do_call_back(null);
07268 item['_doing_update'] = true;
07269 }
07270
07271 h.get(itemname, function(item, obj) {
07272
07273 if (updating) delete item['_doing_update'];
07274 if (obj==null) return do_call_back(null);
07275
07276 var painter = null;
07277
07278 var pos = drawopt ? drawopt.indexOf("divid:") : -1;
07279 if (pos>=0) {
07280 var divid = drawopt.slice(pos+6);
07281 drawopt = drawopt.slice(0, pos);
07282 painter = h.draw(divid, obj, drawopt);
07283 } else
07284 mdi.ForEachPainter(function(p, frame) {
07285 if (p['_hitemname'] != itemname) return;
07286 painter = p;
07287 mdi.ActivateFrame(frame);
07288 painter.RedrawObject(obj);
07289 });
07290
07291 if (painter==null) {
07292 if (updating) {
07293 console.log("something went wrong - did not found painter when doing update of " + itemname);
07294 } else {
07295 var frame = mdi.FindFrame(itemname, true);
07296 if (JSROOT.gStyle.DragAndDrop)
07297 frame.addClass("ui-state-default");
07298 painter = h.draw(frame.attr("id"), obj, drawopt);
07299
07300 mdi.ActivateFrame(frame);
07301
07302 if (JSROOT.gStyle.DragAndDrop)
07303 frame.droppable({
07304 hoverClass : "ui-state-active",
07305 accept: function(ui) {
07306 var dropname = ui.parent().attr('item');
07307 if (dropname == itemname) return false;
07308
07309 var ditem = h.Find(dropname);
07310 if (ditem==null) return false;
07311
07312 return ditem._kind.indexOf("ROOT.")==0;
07313 },
07314 drop: function(event, ui) {
07315 var dropname = ui.draggable.parent().attr('item');
07316 return h.dropitem(dropname, frame.attr("id"));
07317 }
07318 });
07319 }
07320 }
07321
07322 if (painter) painter['_hitemname'] = itemname;
07323
07324 do_call_back(painter);
07325 });
07326 }
07327
07328 JSROOT.HierarchyPainter.prototype.dropitem = function(itemname, divid) {
07329 var h = this;
07330 var mdi = h['disp'];
07331
07332 h.get(itemname, function(item, obj) {
07333 if (obj==null) return;
07334 var painter = h.draw(divid, obj, "same");
07335 if (painter) painter['_hitemname'] = itemname;
07336 });
07337
07338 return true;
07339 }
07340
07341
07342 JSROOT.HierarchyPainter.prototype.updateAll = function() {
07343
07344
07345 var mdi = this['disp'];
07346 if (mdi == null) return;
07347
07348 var allitems = [];
07349
07350
07351 mdi.ForEachPainter(function(p) {
07352 if (('_hitemname' in p) && (allitems.indexOf(p['_hitemname'])<0)) allitems.push(p['_hitemname']);
07353 }, true);
07354
07355
07356 for (var cnt in allitems)
07357 this.display(allitems[cnt], "update");
07358 }
07359
07360 JSROOT.HierarchyPainter.prototype.displayAll = function(items, options) {
07361 if ((items == null) || (items.length == 0)) return;
07362 if (!this.CreateDisplay()) return;
07363 if (options == null) options = [];
07364 while (options.length < items.length)
07365 options.push("");
07366
07367 var mdi = this['disp'];
07368
07369 var dropitems = new Array(items.length);
07370
07371
07372 for (var i in items) {
07373 if (this.Find(items[i])) continue;
07374 if (this.Find(items[i] + ";1")) { items[i] += ";1"; continue; }
07375
07376 var pos = items[i].indexOf("+");
07377 if ((pos>0) && this.Find(items[i].slice(0,pos))) {
07378 dropitems[i] = items[i].slice(pos+1);
07379 items[i] = items[i].slice(0,pos);
07380 }
07381 }
07382
07383
07384 for (var i in items)
07385 mdi.CreateFrame(items[i]);
07386
07387 var h = this;
07388
07389
07390 for (var i in items)
07391 this.display(items[i], options[i], function(painter) {
07392 if ((painter==0) || (dropitems[i]==null)) return;
07393 h.dropitem(dropitems[i], painter.divid);
07394 });
07395 }
07396
07397 JSROOT.HierarchyPainter.prototype.reload = function() {
07398 if ('_online' in this.h)
07399 this.OpenOnline(this.h['_online']);
07400 }
07401
07402 JSROOT.HierarchyPainter.prototype.expand = function(itemname, item0, node) {
07403 var painter = this;
07404
07405 if (node==null)
07406 node = $("#" + this.frameid).find("[item='" + itemname + "']");
07407
07408 if (node.length==0)
07409 return console.log("Did not found node with item = " + itemname);
07410
07411 if (item0==null) item0 = this.Find(itemname);
07412 if (item0==null) return;
07413 item0['_doing_expand'] = true;
07414
07415 this.get(itemname, function(item, obj) {
07416 delete item0['_doing_expand'];
07417 if ((item == null) || (obj == null)) return;
07418
07419 var curr = item;
07420 while (curr != null) {
07421 if (('_expand' in curr) && (typeof (curr['_expand']) == 'function')) {
07422 if (curr['_expand'](item, obj)) {
07423 var itemname = painter.itemFullName(item);
07424 node.attr('item', itemname);
07425 node.find("a").text(item._name);
07426 item._isopen = true;
07427 painter.UpdateTreeNode(node, item);
07428 }
07429 return;
07430 }
07431 curr = ('_parent' in curr) ? curr['_parent'] : null;
07432 }
07433 });
07434 }
07435
07436 JSROOT.HierarchyPainter.prototype.OpenRootFile = function(filepath, andThan) {
07437 var pthis = this;
07438
07439 var f = new JSROOT.TFile(filepath, function(file) {
07440 if (file == null) return;
07441
07442 pthis.h = pthis.FileHierarchy(file);
07443
07444 pthis.RefreshHtml();
07445
07446 if (typeof andThan == 'function') andThan();
07447 });
07448 }
07449
07450 JSROOT.HierarchyPainter.prototype.GetFileProp = function(itemname) {
07451 var item = this.Find(itemname);
07452 if (item == null) return null;
07453
07454 var subname = item._name;
07455 while (item._parent != null) {
07456 item = item._parent;
07457 if ('_file' in item) {
07458 return {
07459 fileurl : item._file.fURL,
07460 itemname : subname
07461 };
07462 }
07463 subname = item._name + "/" + subname;
07464 }
07465
07466 return null;
07467 }
07468
07469 JSROOT.HierarchyPainter.prototype.CompleteOnline = function(ready_callback) {
07470
07471
07472
07473 ready_callback();
07474 }
07475
07476 JSROOT.HierarchyPainter.prototype.OpenOnline = function(server_address, user_callback) {
07477 if (!server_address) server_address = "";
07478
07479 var painter = this;
07480
07481 var req = JSROOT.NewHttpRequest(server_address + "h.json?compact=3", 'object', function(result) {
07482 painter.h = result;
07483 if (painter.h == null) return;
07484
07485
07486 painter.h['_online'] = server_address;
07487
07488 painter.h['_get'] = function(item, callback) {
07489
07490 var url = painter.itemFullName(item);
07491 if (url.length > 0) url += "/";
07492 var h_get = ('_more' in item) || ('_doing_expand' in item);
07493 url += h_get ? 'h.json?compact=3' : 'root.json.gz?compact=3';
07494
07495 var itemreq = JSROOT.NewHttpRequest(url, 'object', function(obj) {
07496 if ((obj != null) && !h_get && (item._name === "StreamerInfo")
07497 && (obj['_typename'] === 'TList'))
07498 obj['_typename'] = 'TStreamerInfoList';
07499
07500 if (typeof callback == 'function')
07501 callback(item, obj);
07502 });
07503
07504 itemreq.send(null);
07505 }
07506
07507 painter.h['_expand'] = function(node, obj) {
07508
07509
07510 if ((obj != null) && (node != null) && ('_childs' in obj)) {
07511 node._childs = obj._childs;
07512 obj._childs = null;
07513 return true;
07514 }
07515 return false;
07516 }
07517
07518 painter.CompleteOnline(function() {
07519 if (painter.h != null)
07520 painter.RefreshHtml(true);
07521
07522 if (typeof user_callback == 'function')
07523 user_callback(painter);
07524 });
07525 });
07526
07527 req.send(null);
07528 }
07529
07530 JSROOT.HierarchyPainter.prototype.GetOnlineProp = function(itemname) {
07531 var item = this.Find(itemname);
07532 if (item == null) return null;
07533
07534 var subname = item._name;
07535 while (item._parent != null) {
07536 item = item._parent;
07537
07538 if ('_online' in item) {
07539 return {
07540 server : item['_online'],
07541 itemname : subname
07542 };
07543 }
07544 subname = item._name + "/" + subname;
07545 }
07546
07547 return null;
07548 }
07549
07550 JSROOT.HierarchyPainter.prototype.FillOnlineMenu = function(menu, onlineprop, itemname) {
07551
07552 var painter = this;
07553
07554 var node = this.Find(itemname);
07555 var cando = this.CheckCanDo(node);
07556
07557 if (cando.display)
07558 JSROOT.Painter.menuitem(menu, "Draw", function() { painter.display(itemname); });
07559
07560 if (cando.expand || cando.display)
07561 JSROOT.Painter.menuitem(menu, "Expand", function() { painter.expand(itemname); });
07562
07563 var drawurl = onlineprop.server + onlineprop.itemname + "/draw.htm";
07564 if (this.IsMonitoring())
07565 drawurl += "?monitoring=" + this.MonitoringInterval();
07566
07567 if (cando.display)
07568 JSROOT.Painter.menuitem(menu, "Draw in new window", function() { window.open(drawurl); });
07569
07570 if (cando.display)
07571 JSROOT.Painter.menuitem(menu, "Draw as png", function() {
07572 window.open(onlineprop.server + onlineprop.itemname + "/root.png?w=400&h=300&opt=");
07573 });
07574 }
07575
07576 JSROOT.HierarchyPainter.prototype.ShowStreamerInfo = function(sinfo) {
07577 this.h = { _name : "StreamerInfo" };
07578 this.StreamerInfoHierarchy(this.h, sinfo);
07579 this.RefreshHtml();
07580 }
07581
07582 JSROOT.HierarchyPainter.prototype.Adopt = function(h) {
07583 this.h = h;
07584 this.RefreshHtml();
07585 }
07586
07587 JSROOT.HierarchyPainter.prototype.MonitoringInterval = function() {
07588
07589 var monitor = this['_monitoring_interval'];
07590 if (monitor == null) {
07591 monitor = JSROOT.GetUrlOption("monitoring");
07592 if ((monitor == "") || (monitor==null)) monitor = 3000;
07593 else monitor = parseInt(monitor);
07594 if ((monitor == NaN) || (monitor<=0)) monitor = 3000;
07595 this['_monitoring_interval'] = monitor;
07596 }
07597 return monitor;
07598 }
07599
07600 JSROOT.HierarchyPainter.prototype.EnableMonitoring = function(on) {
07601 this['_monitoring_on'] = on;
07602 }
07603
07604 JSROOT.HierarchyPainter.prototype.IsMonitoring = function() {
07605 return this['_monitoring_on'];
07606 }
07607
07608 JSROOT.HierarchyPainter.prototype.tree_contextmenu = function(node, event) {
07609 event.preventDefault();
07610
07611 var itemname = node.parent().attr('item');
07612
07613 var hitem = this.Find(itemname);
07614 if (hitem==null) return;
07615
07616 var cando = this.CheckCanDo(hitem);
07617
07618 if (!cando.display && !cando.ctxt && (itemname!="")) return;
07619
07620 var onlineprop = this.GetOnlineProp(itemname);
07621 var fileprop = this.GetFileProp(itemname);
07622
07623 var menu = JSROOT.Painter.createmenu(event);
07624
07625 function qualifyURL(url) {
07626 function escapeHTML(s) {
07627 return s.split('&').join('&').split('<').join('<').split('"').join('"');
07628 }
07629 var el = document.createElement('div');
07630 el.innerHTML = '<a href="' + escapeHTML(url) + '">x</a>';
07631 return el.firstChild.href;
07632 }
07633
07634 var painter = this;
07635
07636 if (itemname == "") {
07637 var addr = "";
07638 if ('_online' in this.h) {
07639 addr = "/?";
07640 if (this.IsMonitoring())
07641 addr += "monitoring=" + this.MonitoringInterval();
07642 } else if ('_file' in this.h) {
07643 addr = JSROOT.source_dir + "index.htm?";
07644 addr += "file=" + this.h['_file'].fURL;
07645 }
07646
07647 if (this['disp_kind']) {
07648 if (addr.length > 2) addr += "&";
07649 addr += "layout=" + this['disp_kind'].replace(/ /g, "");
07650 }
07651
07652 var items = [];
07653
07654 if (this['disp'] != null)
07655 this['disp'].ForEachPainter(function(painter) {
07656 if ('_hitemname' in painter)
07657 items.push(painter['_hitemname']);
07658 });
07659
07660 if (items.length == 1) {
07661 if (addr.length > 2) addr += "&";
07662 addr += "item=" + items[0];
07663 } else if (items.length > 1) {
07664 if (addr.length > 2) addr += "&";
07665 addr += "items=" + JSON.stringify(items);
07666 }
07667
07668 JSROOT.Painter.menuitem(menu, "Direct link", function() { window.open(addr); });
07669 JSROOT.Painter.menuitem(menu, "Only items", function() { window.open(addr + "&nobrowser"); });
07670 } else
07671 if (onlineprop != null) {
07672 this.FillOnlineMenu(menu, onlineprop, itemname);
07673 } else
07674 if (fileprop != null) {
07675 JSROOT.Painter.menuitem(menu, "Draw", function() { painter.display(itemname); });
07676 var filepath = qualifyURL(fileprop.fileurl);
07677 if (filepath.indexOf(JSROOT.source_dir) == 0)
07678 filepath = filepath.slice(JSROOT.source_dir.length);
07679 JSROOT.Painter.menuitem(menu, "Draw in new window", function() {
07680 window.open(JSROOT.source_dir + "index.htm?nobrowser&file=" + filepath + "&item=" + fileprop.itemname);
07681 });
07682 }
07683
07684 JSROOT.Painter.menuitem(menu, "Close", function() {});
07685
07686 return false;
07687 }
07688
07689 JSROOT.HierarchyPainter.prototype.SetDisplay = function(kind, frameid) {
07690 this['disp_kind'] = kind;
07691 this['disp_frameid'] = frameid;
07692 }
07693
07694 JSROOT.HierarchyPainter.prototype.clear = function() {
07695 if ('disp' in this)
07696 this['disp'].Reset();
07697 }
07698
07699 JSROOT.HierarchyPainter.prototype.CreateDisplay = function(force) {
07700 if ('disp' in this) {
07701 if (!force && this['disp'].NumDraw() > 0) return true;
07702 this['disp'].Reset();
07703 delete this['disp'];
07704 }
07705
07706
07707 if (document.getElementById(this['disp_frameid']) == null) return false;
07708
07709 if (this['disp_kind'] == "tabs")
07710 this['disp'] = new JSROOT.TabsDisplay(this['disp_frameid']);
07711 else
07712 if (this['disp_kind'].search("grid") == 0)
07713 this['disp'] = new JSROOT.GridDisplay(this['disp_frameid'], this['disp_kind']);
07714 else
07715 this['disp'] = new JSROOT.CollapsibleDisplay(this['disp_frameid']);
07716
07717 return true;
07718 }
07719
07720 JSROOT.HierarchyPainter.prototype.CheckResize = function(force) {
07721 if ('disp' in this)
07722 this['disp'].CheckResize();
07723 }
07724
07725
07726
07727
07728
07729 JSROOT.MDIDisplay = function(frameid) {
07730 this.frameid = frameid;
07731 }
07732
07733 JSROOT.MDIDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
07734
07735
07736
07737 alert("ForEachFrame not implemented");
07738 }
07739
07740 JSROOT.MDIDisplay.prototype.ForEachPainter = function(userfunc, only_visible) {
07741
07742
07743
07744 this.ForEachFrame(function(frame) {
07745 var dummy = new JSROOT.TObjectPainter();
07746 dummy.SetDivId($(frame).attr('id'), -1);
07747 dummy.ForEachPainter(function(painter) { userfunc(painter, frame); });
07748 }, only_visible);
07749 }
07750
07751 JSROOT.MDIDisplay.prototype.NumDraw = function() {
07752 var cnt = 0;
07753 this.ForEachFrame(function() { cnt++; });
07754 return cnt;
07755 }
07756
07757 JSROOT.MDIDisplay.prototype.FindFrame = function(searchtitle, force) {
07758 var found_frame = null;
07759
07760 this.ForEachFrame(function(frame) {
07761 if (frame.prop('title') == searchtitle)
07762 found_frame = frame;
07763 });
07764
07765 if ((found_frame == null) && force)
07766 found_frame = this.CreateFrame(searchtitle);
07767
07768 return found_frame;
07769 }
07770
07771 JSROOT.MDIDisplay.prototype.FindPainter = function(title) {
07772 var res = null;
07773 this.ForEachPainter(function(p,f) {
07774 if ((res==null) && (f.prop('title')==title)) res = p;
07775 });
07776 return res;
07777 }
07778
07779 JSROOT.MDIDisplay.prototype.ActivateFrame = function(frame) {
07780
07781 }
07782
07783 JSROOT.MDIDisplay.prototype.CheckResize = function() {
07784 this.ForEachPainter(function(painter) {
07785 if (('_hitemname' in painter) && (typeof painter['CheckResize'] == 'function'))
07786 painter.CheckResize();
07787 });
07788 }
07789
07790 JSROOT.MDIDisplay.prototype.Reset = function() {
07791 this.ForEachPainter(function(painter) {
07792 if (('_hitemname' in painter) && (typeof painter['Clenaup'] == 'function'))
07793 painter.Clenaup();
07794 });
07795
07796 document.getElementById(this.frameid).innerHTML = '';
07797 }
07798
07799 JSROOT.MDIDisplay.prototype.Draw = function(title, obj, drawopt) {
07800
07801 if (!obj) return;
07802
07803 var painter = this.FindPainter(title);
07804 var frame = this.FindFrame(title);
07805
07806 if (painter!=null) {
07807 this.ActivateFrame(frame);
07808 painter.RedrawObject(obj);
07809 return painter;
07810 }
07811
07812 if (!JSROOT.canDraw(obj['_typename'], drawopt)) return;
07813
07814 if (frame == null)
07815 frame = this.CreateFrame(title);
07816
07817 this.ActivateFrame(frame);
07818
07819 return JSROOT.draw($(frame).attr("id"), obj, drawopt);
07820 }
07821
07822
07823
07824 JSROOT.CloseCollapsible = function(e, el) {
07825 var sel = $(el)[0].textContent;
07826 if (typeof (sel) == 'undefined')
07827 return;
07828 sel.replace(' x', '');
07829 sel.replace(';', '');
07830 sel.replace(' ', '');
07831 $(el).next().andSelf().remove();
07832 e.stopPropagation();
07833 };
07834
07835 JSROOT.CollapsibleDisplay = function(frameid) {
07836 JSROOT.MDIDisplay.call(this, frameid);
07837 this.cnt = 0;
07838 }
07839
07840 JSROOT.CollapsibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
07841
07842 JSROOT.CollapsibleDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
07843 var topid = this.frameid + '_collapsible';
07844
07845 if (document.getElementById(topid) == null) return;
07846
07847 if (typeof userfunc != 'function') return;
07848
07849 $('#' + topid + ' .collapsible_draw').each(function() {
07850
07851
07852 if (only_visible && $(this).is(":hidden")) return;
07853
07854 userfunc($(this));
07855 });
07856 }
07857
07858 JSROOT.CollapsibleDisplay.prototype.ActivateFrame = function(frame) {
07859 if ($(frame).is(":hidden")) {
07860 $(frame).prev().toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
07861 .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s").end()
07862 .next().toggleClass("ui-accordion-content-active").slideDown(0);
07863 }
07864 $(frame).prev()[0].scrollIntoView();
07865 }
07866
07867 JSROOT.CollapsibleDisplay.prototype.CreateFrame = function(title) {
07868
07869 var topid = this.frameid + '_collapsible';
07870
07871 if (document.getElementById(topid) == null)
07872 $("#right-div").append('<div id="'+ topid + '" class="ui-accordion ui-accordion-icons ui-widget ui-helper-reset" style="overflow:auto; overflow-y:scroll; height:100%"></div>');
07873
07874 var hid = topid + "_sub" + this.cnt++;
07875 var uid = hid + "h";
07876
07877 var entryInfo = "<h5 id=\"" + uid + "\"><a> " + title + "</a> </h5>\n";
07878 entryInfo += "<div class='collapsible_draw' id='" + hid + "'></div>\n";
07879 $("#" + topid).append(entryInfo);
07880
07881 $('#' + uid)
07882 .addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom")
07883 .hover(function() { $(this).toggleClass("ui-state-hover"); })
07884 .prepend('<span class="ui-icon ui-icon-triangle-1-e"></span>')
07885 .append('<button type="button" class="closeButton" title="close canvas" onclick="JSROOT.CloseCollapsible(event, \'#'
07886 + uid + '\')"><img class="img_remove" src="" alt=""/></button>')
07887 .click( function() {
07888 $(this).toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
07889 .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s")
07890 .end().next().toggleClass("ui-accordion-content-active").slideToggle(0);
07891 return false;
07892 })
07893 .next()
07894 .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom")
07895 .hide();
07896
07897 $('#' + uid)
07898 .toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
07899 .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s").end().next()
07900 .toggleClass("ui-accordion-content-active").slideToggle(0);
07901
07902 // $('#'+uid)[0].scrollIntoView();
07903
07904 $("#" + hid).prop('title', title);
07905
07906 return $("#" + hid);
07907 }
07908
07909 // ================================================
07910
07911 JSROOT.TabsDisplay = function(frameid) {
07912 JSROOT.MDIDisplay.call(this, frameid);
07913 this.cnt = 0;
07914 }
07915
07916 JSROOT.TabsDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
07917
07918 JSROOT.TabsDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
07919 var topid = this.frameid + '_tabs';
07920
07921 if (document.getElementById(topid) == null) return;
07922
07923 if (typeof userfunc != 'function') return;
07924
07925 var cnt = -1;
07926 var active = $('#' + topid).tabs("option", "active");
07927
07928 $('#' + topid + ' .tabs_draw').each(function() {
07929 // check if only_visible specified
07930 if (only_visible && (cnt++ != active)) return;
07931
07932 userfunc($(this));
07933 });
07934 }
07935
07936 JSROOT.TabsDisplay.prototype.ActivateFrame = function(frame) {
07937 var cnt = 0, id = -1;
07938 this.ForEachFrame(function(fr) {
07939 if ($(fr).attr('id') == frame.attr('id')) id = cnt;
07940 cnt++;
07941 });
07942
07943 $('#' + this.frameid + "_tabs").tabs("option", "active", id);
07944 }
07945
07946 JSROOT.TabsDisplay.prototype.CreateFrame = function(title) {
07947 var topid = this.frameid + '_tabs';
07948
07949 var hid = topid + "_sub" + this.cnt++;
07950
07951 var li = '<li><a href="#' + hid + '">' + title
07952 + '</a><span class="ui-icon ui-icon-close" role="presentation">Remove Tab</span></li>';
07953 var cont = '<div class="tabs_draw" id="' + hid + '"></div>';
07954
07955 if (document.getElementById(topid) == null) {
07956 $("#" + this.frameid).append('<div id="' + topid + '">' + ' <ul>' + li + ' </ul>' + cont + '</div>');
07957
07958 var tabs = $("#" + topid).tabs({ heightStyle : "fill" });
07959
07960 tabs.delegate("span.ui-icon-close", "click", function() {
07961 var panelId = $(this).closest("li").remove().attr("aria-controls");
07962 $("#" + panelId).remove();
07963 tabs.tabs("refresh");
07964 });
07965 } else {
07966
07967 // var tabs = $("#tabs").tabs();
07968
07969 $("#" + topid).find(".ui-tabs-nav").append(li);
07970 $("#" + topid).append(cont);
07971 $("#" + topid).tabs("refresh");
07972 $("#" + topid).tabs("option", "active", -1);
07973 }
07974 $('#' + hid).empty();
07975 $('#' + hid).prop('title', title);
07976 return $('#' + hid);
07977 }
07978
07979 // ================================================
07980
07981 JSROOT.GridDisplay = function(frameid, sizex, sizey) {
07982 // create grid display object
07983 // one could use followinf arguments
07984 // new JSROOT.GridDisplay('yourframeid','4x4');
07985 // new JSROOT.GridDisplay('yourframeid','3x2');
07986 // new JSROOT.GridDisplay('yourframeid', 3, 4);
07987
07988 JSROOT.MDIDisplay.call(this, frameid);
07989 this.cnt = 0;
07990 if (typeof sizex == "string") {
07991 if (sizex.search("grid") == 0)
07992 sizex = sizex.slice(4).trim();
07993
07994 var separ = sizex.search("x");
07995
07996 if (separ > 0) {
07997 sizey = parseInt(sizex.slice(separ + 1));
07998 sizex = parseInt(sizex.slice(0, separ));
07999 } else {
08000 sizex = parseInt(sizex);
08001 sizey = sizex;
08002 }
08003
08004 if (sizex == NaN)
08005 sizex = 3;
08006 if (sizey == NaN)
08007 sizey = 3;
08008 }
08009
08010 if (!sizex)
08011 sizex = 3;
08012 if (!sizey)
08013 sizey = sizex;
08014 this.sizex = sizex;
08015 this.sizey = sizey;
08016 }
08017
08018 JSROOT.GridDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
08019
08020 JSROOT.GridDisplay.prototype.IsSingle = function() {
08021 return (this.sizex <= 1) && (this.sizey <= 1);
08022 }
08023
08024 JSROOT.GridDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
08025 if (typeof userfunc != 'function') return;
08026
08027 if (this.IsSingle()) {
08028 var elem = $("#"+this.frameid);
08029 if (elem.prop('title')!=null)
08030 userfunc(elem);
08031 return;
08032 }
08033
08034 var topid = this.frameid + '_grid';
08035
08036 if (document.getElementById(topid) == null) return;
08037
08038 for (var cnt = 0; cnt < this.sizex * this.sizey; cnt++) {
08039
08040 var elem = $( "#" + topid + "_" + cnt);
08041
08042 if (elem.prop('title')!="")
08043 userfunc(elem);
08044 }
08045 }
08046
08047 JSROOT.GridDisplay.prototype.CreateFrame = function(title) {
08048
08049 var hid = this.frameid;
08050
08051 if (!this.IsSingle()) {
08052 var topid = this.frameid + '_grid';
08053 if (document.getElementById(topid) == null) {
08054
08055 var main = $("#" + this.frameid);
08056
08057 var h = Math.floor(main.height() / this.sizey);
08058 var w = Math.floor(main.width() / this.sizex);
08059
08060 var content = "<table id='" + topid + "' style='width:100%; height:100%; table-layout:fixed'>";
08061 var cnt = 0;
08062 for (var i = 0; i < this.sizey; i++) {
08063 content += "<tr>";
08064 for (var j = 0; j < this.sizex; j++)
08065 content += "<td><div id='" + topid + "_" + cnt++ + "'></div></td>";
08066 content += "</tr>";
08067 }
08068 content += "</table>";
08069
08070 main.empty();
08071 main.append(content);
08072
08073 main.find("[id^=" + this.frameid + "_grid_]").width(w).height(h);
08074 // .droppable({ accepted: ".h_item", drop: function(event, ui) { console.log("drop!"); } });
08075 }
08076
08077 hid = topid + "_" + this.cnt;
08078 if (++this.cnt >= this.sizex * this.sizey) this.cnt = 0;
08079 }
08080
08081 $("#" + hid).empty();
08082 $("#" + hid).prop('title', title);
08083
08084 return $('#' + hid);
08085 }
08086
08087 JSROOT.GridDisplay.prototype.Reset = function() {
08088 JSROOT.MDIDisplay.prototype.Reset.call(this);
08089 if (this.IsSingle())
08090 $("#" + this.frameid).prop('title', null);
08091 this.cnt = 0;
08092 }
08093
08094 JSROOT.GridDisplay.prototype.CheckResize = function() {
08095
08096 var main = $("#" + this.frameid);
08097
08098 var h = Math.floor(main.height() / this.sizey);
08099 var w = Math.floor(main.width() / this.sizex);
08100
08101 // console.log("big width = " + main.width() + " height = " + main.height());
08102
08103 // set height for all table cells, it is not done automatically by browser
08104 // for (var cnt=0;cnt<this.sizex*this.sizey;cnt++)
08105 // $("#" + this.frameid + "_grid_"+cnt).height(h);
08106
08107 // $("[id^=" + this.frameid + "_grid_]").height(h).width(w);
08108
08109 main.find("[id^=" + this.frameid + "_grid_]").height(h).width(w);
08110
08111 JSROOT.MDIDisplay.prototype.CheckResize.call(this);
08112 }
08113
08114 JSROOT.RegisterForResize = function(handle, delay) {
08115 // function used to react on browser window resize event
08116 // While many resize events could come in short time,
08117 // resize will be handled with delay after last resize event
08118 // handle can be function or object with CheckResize function
08119 // one could specify delay after which resize event will be handled
08120
08121 var myInterval = null;
08122 var myCounter = -1;
08123 var myPeriod = delay ? delay / 2.5 : 100;
08124 if (myPeriod < 20) myPeriod = 20;
08125
08126 function ResizeTimer() {
08127 if (myCounter < 0) return;
08128 myCounter += 1;
08129 if (myCounter < 3) return;
08130
08131 if (myInterval != null) {
08132 clearInterval(myInterval);
08133 myInterval = null;
08134 }
08135 myCounter = -1;
08136
08137 document.body.style.cursor = 'wait';
08138
08139 if (typeof handle == 'function') handle();
08140 else if ((typeof handle == 'object') && (typeof handle['CheckResize'] == 'function'))
08141 handle.CheckResize();
08142
08143 document.body.style.cursor = 'auto';
08144 }
08145
08146 function ProcessResize() {
08147 if (myInterval == null) {
08148 myInterval = setInterval(ResizeTimer, myPeriod);
08149 }
08150 myCounter = 0;
08151 }
08152
08153 window.addEventListener('resize', ProcessResize);
08154 }
08155
08156 JSROOT.addDrawFunc("TCanvas", JSROOT.Painter.drawCanvas);
08157 JSROOT.addDrawFunc("TPad", JSROOT.Painter.drawPad);
08158 JSROOT.addDrawFunc("TFrame", JSROOT.Painter.drawFrame);
08159 JSROOT.addDrawFunc("TLegend", JSROOT.Painter.drawLegend);
08160 JSROOT.addDrawFunc("TPaveText", JSROOT.Painter.drawPaveText);
08161 JSROOT.addDrawFunc("TPaveStats", JSROOT.Painter.drawPaveText);
08162 JSROOT.addDrawFunc("TLatex", JSROOT.Painter.drawText);
08163 JSROOT.addDrawFunc("TText", JSROOT.Painter.drawText);
08164 JSROOT.addDrawFunc("TPaveLabel", JSROOT.Painter.drawText);
08165 JSROOT.addDrawFunc(/^TH1/, JSROOT.Painter.drawHistogram1D);
08166 JSROOT.addDrawFunc("TProfile", JSROOT.Painter.drawHistogram1D);
08167 JSROOT.addDrawFunc(/^TH2/, JSROOT.Painter.drawHistogram2D);
08168 JSROOT.addDrawFunc(/^TH3/, JSROOT.Painter.drawHistogram3D);
08169 JSROOT.addDrawFunc("THStack", JSROOT.Painter.drawHStack);
08170 JSROOT.addDrawFunc("TF1", JSROOT.Painter.drawFunction);
08171 JSROOT.addDrawFunc(/^TGraph/, JSROOT.Painter.drawGraph);
08172 JSROOT.addDrawFunc("TCutG", JSROOT.Painter.drawGraph);
08173 JSROOT.addDrawFunc(/^RooHist/, JSROOT.Painter.drawGraph);
08174 JSROOT.addDrawFunc(/^RooCurve/, JSROOT.Painter.drawGraph);
08175 JSROOT.addDrawFunc("TMultiGraph", JSROOT.Painter.drawMultiGraph);
08176 JSROOT.addDrawFunc("TStreamerInfoList", JSROOT.Painter.drawStreamerInfo);
08177
08178 JSROOT.getDrawFunc = function(classname) {
08179 if (typeof classname != 'string') return null;
08180
08181 for (var i in JSROOT.fDrawFunc) {
08182 if ((typeof JSROOT.fDrawFunc[i].name) === "string") {
08183 if (JSROOT.fDrawFunc[i].name == classname) return JSROOT.fDrawFunc[i].func;
08184 } else {
08185 if (classname.match(JSROOT.fDrawFunc[i].name)) return JSROOT.fDrawFunc[i].func;
08186 }
08187 }
08188 return null;
08189 }
08190
08191 JSROOT.canDraw = function(classname) {
08192 return JSROOT.getDrawFunc(classname) != null;
08193 }
08194
08198 JSROOT.draw = function(divid, obj, opt) {
08199 if ((typeof obj != 'object') || (!('_typename' in obj))) return null;
08200
08201 var draw_func = JSROOT.getDrawFunc(obj['_typename']);
08202
08203 if (draw_func==null) return null;
08204
08205 return draw_func(divid, obj, opt);
08206 }
08207
08213 JSROOT.redraw = function(divid, obj, opt) {
08214 if (obj==null) return;
08215
08216 var can = d3.select("#" + divid + " .root_canvas");
08217 var can_painter = can.node() ? can.node()['pad_painter'] : null;
08218
08219 if (can_painter != null) {
08220 if (obj._typename=="TCanvas") {
08221 can_painter.RedrawObject(obj);
08222 return can_painter;
08223 }
08224
08225 for (var i in can_painter.painters) {
08226 var obj0 = can_painter.painters[i].GetObject();
08227
08228 if ((obj0 != null) && (obj0._typename == obj._typename))
08229 if (can_painter.painters[i].UpdateObject(obj)) {
08230 can_painter.RedrawPad();
08231 return can_painter.painters[i];
08232 }
08233 }
08234 }
08235
08236 if (can_painter)
08237 console.log("Cannot find painter to update object of type " + obj._typename);
08238
08239 $("#"+divid).empty();
08240 return JSROOT.draw(divid, obj, opt);
08241 }
08242
08243 })();
08244
08245 // JSRootPainter.js ends
08246
08247 // example of user code for streamer and painter
08248
08249 /*
08250
08251 (function(){
08252
08253 Amore_String_Streamer = function(buf, obj, prop, streamer) {
08254 console.log("read property " + prop + " of typename " + streamer[prop]['typename']);
08255 obj[prop] = buf.ReadTString();
08256 }
08257
08258 Amore_Draw = function(divid, obj, opt) { // custom draw function.
08259 return JSROOT.draw(divid, obj['fVal'], opt);
08260 }
08261
08262 JSROOT.addUserStreamer("amore::core::String_t", Amore_String_Streamer);
08263
08264 JSROOT.addDrawFunc("amore::core::MonitorObjectHisto<TH1F>", Amore_Draw);
08265
08266 })();
08267
08268 */
08269