00001
00002
00003
00004 (function( factory ) {
00005 if ( typeof define === "function" && define.amd ) {
00006
00007 define( ['JSRootCore', 'd3'], factory );
00008 } else {
00009
00010 if (typeof JSROOT == 'undefined')
00011 throw new Error('JSROOT is not defined', 'JSRootPainter.js');
00012
00013 if (typeof d3 != 'object')
00014 throw new Error('d3 is not defined', 'JSRootPainter.js');
00015
00016 if (typeof JSROOT.Painter == 'object')
00017 throw new Error('JSROOT.Painter already defined', 'JSRootPainter.js');
00018
00019 factory(JSROOT, d3);
00020 }
00021 } (function(JSROOT, d3) {
00022
00023
00024 if ( typeof define === "function" && define.amd )
00025 JSROOT.loadScript('$$$style/JSRootPainter.css');
00026
00027
00028 JSROOT.DrawFuncs = {lst:[], cache:{}};
00029
00030
00031
00032
00033 JSROOT.addDrawFunc = function(_name, _func, _opt) {
00034 if ((arguments.length == 1) && (typeof arguments[0] == 'object')) {
00035 JSROOT.DrawFuncs.lst.push(arguments[0]);
00036 return arguments[0];
00037 }
00038 var handle = { name:_name, func:_func, opt:_opt };
00039 JSROOT.DrawFuncs.lst.push(handle);
00040 return handle;
00041 }
00042
00043
00044
00045 JSROOT.ToolbarIcons = {
00046 camera: { path: 'M 152.00,304.00c0.00,57.438, 46.562,104.00, 104.00,104.00s 104.00-46.562, 104.00-104.00s-46.562-104.00-104.00-104.00S 152.00,246.562, 152.00,304.00z M 480.00,128.00L 368.00,128.00 c-8.00-32.00-16.00-64.00-48.00-64.00L 192.00,64.00 c-32.00,0.00-40.00,32.00-48.00,64.00L 32.00,128.00 c-17.60,0.00-32.00,14.40-32.00,32.00l0.00,288.00 c0.00,17.60, 14.40,32.00, 32.00,32.00l 448.00,0.00 c 17.60,0.00, 32.00-14.40, 32.00-32.00L 512.00,160.00 C 512.00,142.40, 497.60,128.00, 480.00,128.00z M 256.00,446.00c-78.425,0.00-142.00-63.574-142.00-142.00c0.00-78.425, 63.575-142.00, 142.00-142.00c 78.426,0.00, 142.00,63.575, 142.00,142.00 C 398.00,382.426, 334.427,446.00, 256.00,446.00z M 480.00,224.00l-64.00,0.00 l0.00-32.00 l 64.00,0.00 L 480.00,224.00 z' },
00047 disk: { path: 'M384,0H128H32C14.336,0,0,14.336,0,32v448c0,17.656,14.336,32,32,32h448c17.656,0,32-14.344,32-32V96L416,0H384z M352,160 V32h32v128c0,17.664-14.344,32-32,32H160c-17.664,0-32-14.336-32-32V32h128v128H352z M96,288c0-17.656,14.336-32,32-32h256 c17.656,0,32,14.344,32,32v192H96V288z' },
00048 question: { path: 'M256,512c141.375,0,256-114.625,256-256S397.375,0,256,0S0,114.625,0,256S114.625,512,256,512z M256,64 c63.719,0,128,36.484,128,118.016c0,47.453-23.531,84.516-69.891,110.016C300.672,299.422,288,314.047,288,320 c0,17.656-14.344,32-32,32c-17.664,0-32-14.344-32-32c0-40.609,37.25-71.938,59.266-84.031 C315.625,218.109,320,198.656,320,182.016C320,135.008,279.906,128,256,128c-30.812,0-64,20.227-64,64.672 c0,17.664-14.336,32-32,32s-32-14.336-32-32C128,109.086,193.953,64,256,64z M256,449.406c-18.211,0-32.961-14.75-32.961-32.969 c0-18.188,14.75-32.953,32.961-32.953c18.219,0,32.969,14.766,32.969,32.953C288.969,434.656,274.219,449.406,256,449.406z' },
00049 undo: { path: 'M450.159,48.042c8.791,9.032,16.983,18.898,24.59,29.604c7.594,10.706,14.146,22.207,19.668,34.489 c5.509,12.296,9.82,25.269,12.92,38.938c3.113,13.669,4.663,27.834,4.663,42.499c0,14.256-1.511,28.863-4.532,43.822 c-3.009,14.952-7.997,30.217-14.953,45.795c-6.955,15.577-16.202,31.52-27.755,47.826s-25.88,32.9-42.942,49.807 c-5.51,5.444-11.787,11.67-18.834,18.651c-7.033,6.98-14.496,14.366-22.39,22.168c-7.88,7.802-15.955,15.825-24.187,24.069 c-8.258,8.231-16.333,16.203-24.252,23.888c-18.3,18.13-37.354,37.016-57.191,56.65l-56.84-57.445 c19.596-19.472,38.54-38.279,56.84-56.41c7.75-7.685,15.772-15.604,24.108-23.757s16.438-16.163,24.33-24.057 c7.894-7.893,15.356-15.33,22.402-22.312c7.034-6.98,13.312-13.193,18.821-18.651c22.351-22.402,39.165-44.648,50.471-66.738 c11.279-22.09,16.932-43.567,16.932-64.446c0-15.785-3.217-31.005-9.638-45.671c-6.422-14.665-16.229-28.504-29.437-41.529 c-3.282-3.282-7.358-6.395-12.217-9.325c-4.871-2.938-10.381-5.503-16.516-7.697c-6.121-2.201-12.815-3.992-20.058-5.373 c-7.242-1.374-14.9-2.064-23.002-2.064c-8.218,0-16.802,0.834-25.788,2.507c-8.961,1.674-18.053,4.429-27.222,8.271 c-9.189,3.842-18.456,8.869-27.808,15.089c-9.358,6.219-18.521,13.819-27.502,22.793l-59.92,60.271l93.797,94.058H0V40.91 l93.27,91.597l60.181-60.532c13.376-15.018,27.222-27.248,41.536-36.697c14.308-9.443,28.608-16.776,42.89-21.992 c14.288-5.223,28.505-8.74,42.623-10.557C294.645,0.905,308.189,0,321.162,0c13.429,0,26.389,1.185,38.84,3.562 c12.478,2.377,24.2,5.718,35.192,10.029c11.006,4.311,21.126,9.404,30.374,15.265C434.79,34.724,442.995,41.119,450.159,48.042z' },
00050 arrow_right : { path : 'M30.796,226.318h377.533L294.938,339.682c-11.899,11.906-11.899,31.184,0,43.084c11.887,11.899,31.19,11.893,43.077,0 l165.393-165.386c5.725-5.712,8.924-13.453,8.924-21.539c0-8.092-3.213-15.84-8.924-21.551L338.016,8.925 C332.065,2.975,324.278,0,316.478,0c-7.802,0-15.603,2.968-21.539,8.918c-11.899,11.906-11.899,31.184,0,43.084l113.391,113.384 H30.796c-16.822,0-30.463,13.645-30.463,30.463C0.333,212.674,13.974,226.318,30.796,226.318z' },
00051 arrow_up : { path : 'M295.505,629.446V135.957l148.193,148.206c15.555,15.559,40.753,15.559,56.308,0c15.555-15.538,15.546-40.767,0-56.304 L283.83,11.662C276.372,4.204,266.236,0,255.68,0c-10.568,0-20.705,4.204-28.172,11.662L11.333,227.859 c-7.777,7.777-11.666,17.965-11.666,28.158c0,10.192,3.88,20.385,11.657,28.158c15.563,15.555,40.762,15.555,56.317,0 l148.201-148.219v493.489c0,21.993,17.837,39.82,39.82,39.82C277.669,669.267,295.505,651.439,295.505,629.446z' },
00052 arrow_diag : { path : 'M279.875,511.994c-1.292,0-2.607-0.102-3.924-0.312c-10.944-1.771-19.333-10.676-20.457-21.71L233.97,278.348 L22.345,256.823c-11.029-1.119-19.928-9.51-21.698-20.461c-1.776-10.944,4.031-21.716,14.145-26.262L477.792,2.149 c9.282-4.163,20.167-2.165,27.355,5.024c7.201,7.189,9.199,18.086,5.024,27.356L302.22,497.527 C298.224,506.426,289.397,511.994,279.875,511.994z M118.277,217.332l140.534,14.294c11.567,1.178,20.718,10.335,21.878,21.896 l14.294,140.519l144.09-320.792L118.277,217.332z' },
00053 auto_zoom: { path : 'M505.441,242.47l-78.303-78.291c-9.18-9.177-24.048-9.171-33.216,0c-9.169,9.172-9.169,24.045,0.006,33.217l38.193,38.188 H280.088V80.194l38.188,38.199c4.587,4.584,10.596,6.881,16.605,6.881c6.003,0,12.018-2.297,16.605-6.875 c9.174-9.172,9.174-24.039,0.011-33.217L273.219,6.881C268.803,2.471,262.834,0,256.596,0c-6.229,0-12.202,2.471-16.605,6.881 l-78.296,78.302c-9.178,9.172-9.178,24.045,0,33.217c9.177,9.171,24.051,9.171,33.21,0l38.205-38.205v155.4H80.521l38.2-38.188 c9.177-9.171,9.177-24.039,0.005-33.216c-9.171-9.172-24.039-9.178-33.216,0L7.208,242.464c-4.404,4.403-6.881,10.381-6.881,16.611 c0,6.227,2.477,12.207,6.881,16.61l78.302,78.291c4.587,4.581,10.599,6.875,16.605,6.875c6.006,0,12.023-2.294,16.61-6.881 c9.172-9.174,9.172-24.036-0.005-33.211l-38.205-38.199h152.593v152.063l-38.199-38.211c-9.171-9.18-24.039-9.18-33.216-0.022 c-9.178,9.18-9.178,24.059-0.006,33.222l78.284,78.302c4.41,4.404,10.382,6.881,16.611,6.881c6.233,0,12.208-2.477,16.611-6.881 l78.302-78.296c9.181-9.18,9.181-24.048,0-33.205c-9.174-9.174-24.054-9.174-33.21,0l-38.199,38.188v-152.04h152.051l-38.205,38.199 c-9.18,9.175-9.18,24.037-0.005,33.211c4.587,4.587,10.596,6.881,16.604,6.881c6.01,0,12.024-2.294,16.605-6.875l78.303-78.285 c4.403-4.403,6.887-10.378,6.887-16.611C512.328,252.851,509.845,246.873,505.441,242.47z' },
00054 statbox : {
00055 path : 'M28.782,56.902H483.88c15.707,0,28.451-12.74,28.451-28.451C512.331,12.741,499.599,0,483.885,0H28.782 C13.074,0,0.331,12.741,0.331,28.451C0.331,44.162,13.074,56.902,28.782,56.902z' +
00056 'M483.885,136.845H28.782c-15.708,0-28.451,12.741-28.451,28.451c0,15.711,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.74,28.451-28.451C512.331,149.586,499.599,136.845,483.885,136.845z' +
00057 'M483.885,273.275H28.782c-15.708,0-28.451,12.731-28.451,28.452c0,15.707,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.744,28.451-28.451C512.337,286.007,499.599,273.275,483.885,273.275z' +
00058 'M256.065,409.704H30.492c-15.708,0-28.451,12.731-28.451,28.451c0,15.707,12.744,28.451,28.451,28.451h225.585 c15.707,0,28.451-12.744,28.451-28.451C284.516,422.436,271.785,409.704,256.065,409.704z'
00059 }
00060 };
00061
00062 JSROOT.Toolbar = function(container, buttons) {
00063 if ((container !== undefined) && (typeof container.append == 'function')) {
00064 this.element = container.append("div").attr('class','jsroot');
00065 this.addButtons(buttons);
00066 }
00067 }
00068
00069 JSROOT.Toolbar.prototype.addButtons = function(buttons) {
00070 var pthis = this;
00071
00072 this.buttonsNames = [];
00073 buttons.forEach(function(buttonGroup) {
00074 var group = pthis.element.append('div').attr('class', 'toolbar-group');
00075
00076 buttonGroup.forEach(function(buttonConfig) {
00077 var buttonName = buttonConfig.name;
00078 if (!buttonName) {
00079 throw new Error('must provide button \'name\' in button config');
00080 }
00081 if (pthis.buttonsNames.indexOf(buttonName) !== -1) {
00082 throw new Error('button name \'' + buttonName + '\' is taken');
00083 }
00084 pthis.buttonsNames.push(buttonName);
00085
00086 pthis.createButton(group, buttonConfig);
00087 });
00088 });
00089 };
00090
00091
00092 JSROOT.Toolbar.prototype.createButton = function(group, config) {
00093
00094 var title = config.title;
00095 if (title === undefined) title = config.name;
00096
00097 if (typeof config.click !== 'function')
00098 throw new Error('must provide button \'click\' function in button config');
00099
00100 var button = group.append('a')
00101 .attr('class','toolbar-btn')
00102 .attr('rel', 'tooltip')
00103 .attr('data-title', title)
00104 .on('click', config.click);
00105
00106 this.createIcon(button, config.icon || JSROOT.ToolbarIcons.question);
00107 };
00108
00109 JSROOT.Toolbar.prototype.createIcon = function(button, thisIcon) {
00110 var size = thisIcon.size || 512;
00111 var scale = thisIcon.scale || 1;
00112
00113 var svg = button.append("svg:svg")
00114 .attr('height', '1em')
00115 .attr('width', '1em')
00116 .attr('viewBox', [0, 0, size, size].join(' '))
00117
00118 if ('recs' in thisIcon) {
00119 var rec = {};
00120 for (var n=0;n<thisIcon.recs.length;++n) {
00121 JSROOT.extend(rec, thisIcon.recs[n]);
00122 svg.append('rect').attr("x", rec.x).attr("y", rec.y)
00123 .attr("width", rec.w).attr("height", rec.h)
00124 .attr("fill", rec.f);
00125 }
00126 } else {
00127 var elem = svg.append('svg:path').attr('d',thisIcon.path);
00128 if (scale !== 1)
00129 elem.attr('transform', 'scale(' + scale + ' ' + scale +')');
00130 }
00131 };
00132
00133 JSROOT.Toolbar.prototype.removeAllButtons = function() {
00134 this.element.remove();
00135 };
00136
00140 JSROOT.Painter = {};
00141
00142 JSROOT.Painter.createMenu = function(maincallback, menuname) {
00143
00144 document.body.style.cursor = 'wait';
00145 JSROOT.AssertPrerequisites('jq2d', function() {
00146 document.body.style.cursor = 'auto';
00147 JSROOT.Painter.createMenu(maincallback, menuname);
00148 });
00149 }
00150
00151 JSROOT.Painter.closeMenu = function(menuname) {
00152 if (!menuname) menuname = 'root_ctx_menu';
00153 var x = document.getElementById(menuname);
00154 if (x) x.parentNode.removeChild(x);
00155 }
00156
00157 JSROOT.Painter.readStyleFromURL = function(url) {
00158 var optimize = JSROOT.GetUrlOption("optimize", url);
00159 if (optimize=="") JSROOT.gStyle.OptimizeDraw = 2; else
00160 if (optimize!==null) {
00161 JSROOT.gStyle.OptimizeDraw = parseInt(optimize);
00162 if (isNaN(JSROOT.gStyle.OptimizeDraw)) JSROOT.gStyle.OptimizeDraw = 2;
00163 }
00164
00165 var inter = JSROOT.GetUrlOption("interactive", url);
00166 if ((inter=="") || (inter=="1")) inter = "11111"; else
00167 if (inter=="0") inter = "00000";
00168 if ((inter!==null) && (inter.length==5)) {
00169 JSROOT.gStyle.Tooltip = parseInt(inter.charAt(0));
00170 JSROOT.gStyle.ContextMenu = (inter.charAt(1) != '0');
00171 JSROOT.gStyle.Zooming = (inter.charAt(2) != '0');
00172 JSROOT.gStyle.MoveResize = (inter.charAt(3) != '0');
00173 JSROOT.gStyle.DragAndDrop = (inter.charAt(4) != '0');
00174 }
00175
00176 var tt = JSROOT.GetUrlOption("tooltip", url);
00177 if (tt !== null) JSROOT.gStyle.Tooltip = parseInt(tt);
00178
00179 var mathjax = JSROOT.GetUrlOption("mathjax", url);
00180 if ((mathjax!==null) && (mathjax!="0")) JSROOT.gStyle.MathJax = 1;
00181
00182 if (JSROOT.GetUrlOption("nomenu", url)!=null) JSROOT.gStyle.ContextMenu = false;
00183 if (JSROOT.GetUrlOption("noprogress", url)!=null) JSROOT.gStyle.ProgressBox = false;
00184 if (JSROOT.GetUrlOption("notouch", url)!=null) JSROOT.touches = false;
00185
00186 JSROOT.gStyle.OptStat = JSROOT.GetUrlOption("optstat", url, JSROOT.gStyle.OptStat);
00187 JSROOT.gStyle.OptFit = JSROOT.GetUrlOption("optfit", url, JSROOT.gStyle.OptFit);
00188 JSROOT.gStyle.StatFormat = JSROOT.GetUrlOption("statfmt", url, JSROOT.gStyle.StatFormat);
00189 JSROOT.gStyle.FitFormat = JSROOT.GetUrlOption("fitfmt", url, JSROOT.gStyle.FitFormat);
00190
00191 var toolbar = JSROOT.GetUrlOption("toolbar", url);
00192 if (toolbar !== null)
00193 JSROOT.gStyle.ToolBar = (toolbar !== "0") && (toolbar !== "false");
00194
00195 var palette = JSROOT.GetUrlOption("palette", url);
00196 if (palette!==null) {
00197 palette = parseInt(palette);
00198 if (!isNaN(palette) && (palette>0) && (palette<113)) JSROOT.gStyle.Palette = palette;
00199 }
00200
00201 var embed3d = JSROOT.GetUrlOption("embed3d", url);
00202 if (embed3d !== null) JSROOT.gStyle.Embed3DinSVG = parseInt(embed3d);
00203
00204 var webgl = JSROOT.GetUrlOption("webgl", url);
00205 if ((webgl === "0") || (webgl === "false")) JSROOT.gStyle.NoWebGL = false; else
00206 if (webgl === "ie") JSROOT.gStyle.NoWebGL = !JSROOT.browser.isIE;
00207 }
00208
00209 JSROOT.Painter.Coord = {
00210 kCARTESIAN : 1,
00211 kPOLAR : 2,
00212 kCYLINDRICAL : 3,
00213 kSPHERICAL : 4,
00214 kRAPIDITY : 5
00215 }
00216
00218 JSROOT.Painter.root_colors = function() {
00219 var colorMap = ['white','black','red','green','blue','yellow','magenta','cyan','rgb(89,212,84)','rgb(89,84,217)', 'white'];
00220 colorMap[110] = 'white';
00221
00222 var moreCol = [
00223 {col:11,str:'c1b7ad4d4d4d6666668080809a9a9ab3b3b3cdcdcde6e6e6f3f3f3cdc8accdc8acc3c0a9bbb6a4b3a697b8a49cae9a8d9c8f83886657b1cfc885c3a48aa9a1839f8daebdc87b8f9a768a926983976e7b857d9ad280809caca6c0d4cf88dfbb88bd9f83c89a7dc08378cf5f61ac8f94a6787b946971d45a549300ff7b00ff6300ff4b00ff3300ff1b00ff0300ff0014ff002cff0044ff005cff0074ff008cff00a4ff00bcff00d4ff00ecff00fffd00ffe500ffcd00ffb500ff9d00ff8500ff6d00ff5500ff3d00ff2600ff0e0aff0022ff003aff0052ff006aff0082ff009aff00b1ff00c9ff00e1ff00f9ff00ffef00ffd700ffbf00ffa700ff8f00ff7700ff6000ff4800ff3000ff1800ff0000'},
00224 {col:201,str:'5c5c5c7b7b7bb8b8b8d7d7d78a0f0fb81414ec4848f176760f8a0f14b81448ec4876f1760f0f8a1414b84848ec7676f18a8a0fb8b814ecec48f1f1768a0f8ab814b8ec48ecf176f10f8a8a14b8b848ecec76f1f1'},
00225 {col:390,str:'ffffcdffff9acdcd9affff66cdcd669a9a66ffff33cdcd339a9a33666633ffff00cdcd009a9a00666600333300'},
00226 {col:406,str:'cdffcd9aff9a9acd9a66ff6666cd66669a6633ff3333cd33339a3333663300ff0000cd00009a00006600003300'},
00227 {col:422,str:'cdffff9affff9acdcd66ffff66cdcd669a9a33ffff33cdcd339a9a33666600ffff00cdcd009a9a006666003333'},
00228 {col:590,str:'cdcdff9a9aff9a9acd6666ff6666cd66669a3333ff3333cd33339a3333660000ff0000cd00009a000066000033'},
00229 {col:606,str:'ffcdffff9affcd9acdff66ffcd66cd9a669aff33ffcd33cd9a339a663366ff00ffcd00cd9a009a660066330033'},
00230 {col:622,str:'ffcdcdff9a9acd9a9aff6666cd66669a6666ff3333cd33339a3333663333ff0000cd00009a0000660000330000'},
00231 {col:791,str:'ffcd9acd9a669a66339a6600cd9a33ffcd66ff9a00ffcd33cd9a00ffcd00ff9a33cd66006633009a3300cd6633ff9a66ff6600ff6633cd3300ff33009aff3366cd00336600339a0066cd339aff6666ff0066ff3333cd0033ff00cdff9a9acd66669a33669a009acd33cdff669aff00cdff339acd00cdff009affcd66cd9a339a66009a6633cd9a66ffcd00ff6633ffcd00cd9a00ffcd33ff9a00cd66006633009a3333cd6666ff9a00ff9a33ff6600cd3300ff339acdff669acd33669a00339a3366cd669aff0066ff3366ff0033cd0033ff339aff0066cd00336600669a339acd66cdff009aff33cdff009acd00cdffcd9aff9a66cd66339a66009a9a33cdcd66ff9a00ffcd33ff9a00cdcd00ff9a33ff6600cd33006633009a6633cd9a66ff6600ff6633ff3300cd3300ffff339acd00666600339a0033cd3366ff669aff0066ff3366cd0033ff0033ff9acdcd669a9a33669a0066cd339aff66cdff009acd009aff33cdff009a'},
00232 {col:920,str:'cdcdcd9a9a9a666666333333'}];
00233
00234 for (var indx = 0; indx < moreCol.length; ++indx) {
00235 var entry = moreCol[indx];
00236 for (var n=0; n < entry.str.length; n+=6) {
00237 var num = parseInt(entry.col) + parseInt(n/6);
00238 colorMap[num] = 'rgb(' + parseInt("0x" +entry.str.slice(n,n+2)) + "," + parseInt("0x" + entry.str.slice(n+2,n+4)) + "," + parseInt("0x" + entry.str.slice(n+4,n+6)) + ")";
00239 }
00240 }
00241
00242 return colorMap;
00243 }();
00244
00245 JSROOT.Painter.MakeColorRGB = function(col) {
00246 if ((col==null) || (col._typename != 'TColor')) return null;
00247 var rgb = Math.round(col.fRed*255) + "," + Math.round(col.fGreen*255) + "," + Math.round(col.fBlue*255);
00248 if ((col.fAlpha === undefined) || (col.fAlpha == 1.))
00249 rgb = "rgb(" + rgb + ")";
00250 else
00251 rgb = "rgba(" + rgb + "," + col.fAlpha.toFixed(3) + ")";
00252
00253 switch (rgb) {
00254 case 'rgb(255,255,255)' : rgb = 'white'; break;
00255 case 'rgb(0,0,0)' : rgb = 'black'; break;
00256 case 'rgb(255,0,0)' : rgb = 'red'; break;
00257 case 'rgb(0,255,0)' : rgb = 'green'; break;
00258 case 'rgb(0,0,255)' : rgb = 'blue'; break;
00259 case 'rgb(255,255,0)' : rgb = 'yellow'; break;
00260 case 'rgb(255,0,255)' : rgb = 'magenta'; break;
00261 case 'rgb(0,255,255)' : rgb = 'cyan'; break;
00262 }
00263 return rgb;
00264 }
00265
00266 JSROOT.Painter.adoptRootColors = function(objarr) {
00267 if (!objarr || !objarr.arr) return;
00268
00269 for (var n = 0; n < objarr.arr.length; ++n) {
00270 var col = objarr.arr[n];
00271 if ((col==null) || (col._typename != 'TColor')) continue;
00272
00273 var num = col.fNumber;
00274 if ((num<0) || (num>4096)) continue;
00275
00276 var rgb = JSROOT.Painter.MakeColorRGB(col);
00277 if (rgb == null) continue;
00278
00279 if (JSROOT.Painter.root_colors[num] != rgb)
00280 JSROOT.Painter.root_colors[num] = rgb;
00281 }
00282 }
00283
00284 JSROOT.Painter.root_line_styles = new Array("", "", "3,3", "1,2",
00285 "3,4,1,4", "5,3,1,3", "5,3,1,3,1,3,1,3", "5,5",
00286 "5,3,1,3,1,3", "20,5", "20,10,1,10", "1,3");
00287
00288
00289 JSROOT.Painter.root_markers = new Array(
00290 0, 100, 8, 7, 0,
00291 9, 100, 100, 100, 100,
00292 100, 100, 100, 100, 100,
00293 100, 100, 100, 100, 100,
00294 100, 103, 105, 104, 0,
00295 3, 4, 2, 1, 106,
00296 6, 7, 5, 102, 101);
00297
00299 JSROOT.Painter.createAttMarker = function(attmarker, style) {
00300
00301 var marker_color = JSROOT.Painter.root_colors[attmarker.fMarkerColor];
00302
00303 if ((style===null) || (style===undefined)) style = attmarker.fMarkerStyle;
00304
00305 var res = { x0: 0, y0: 0, color: marker_color, style: style, size: 8, stroke: true, fill: true, marker: "", ndig: 0, used: true };
00306
00307 res.Change = function(color, style, size) {
00308
00309 if (color!==undefined) this.color = color;
00310 if (style!==undefined) this.style = style;
00311 if (size!==undefined) this.size = size; else size = this.size;
00312
00313 this.x0 = this.y0 = 0;
00314
00315 this.reset_pos = function() {
00316 this.lastx = this.lasty = null;
00317 }
00318
00319 if ((this.style === 1) || (this.style === 777)) {
00320 this.fill = false;
00321 this.marker = "h1";
00322 this.size = 1;
00323
00324
00325 this.create = function(x,y) {
00326 var xx = Math.round(x), yy = Math.round(y), m1 = "M"+xx+","+yy+"h1";
00327 var m2 = (this.lastx===null) ? m1 : ("m"+(xx-this.lastx)+","+(yy-this.lasty)+"h1");
00328 this.lastx = xx+1; this.lasty = yy;
00329 return (m2.length < m1.length) ? m2 : m1;
00330 }
00331
00332 this.reset_pos();
00333 return true;
00334 }
00335
00336 var marker_kind = ((this.style>0) && (this.style<JSROOT.Painter.root_markers.length)) ? JSROOT.Painter.root_markers[this.style] : 100;
00337 var shape = marker_kind % 100;
00338
00339 this.fill = (marker_kind>=100);
00340
00341 switch(this.style) {
00342 case 1: size = this.size = 1; break;
00343 case 6: size = this.size = 2; break;
00344 case 7: size = this.size = 3; break;
00345 default: this.size = size; size*=8;
00346 }
00347
00348 this.ndig = (size>7) ? 0 : ((size>2) ? 1 : 2);
00349 if (shape == 6) this.ndig++;
00350 var half = (size/2).toFixed(this.ndig), full = size.toFixed(this.ndig);
00351
00352 switch(shape) {
00353 case 0:
00354 this.x0 = -size/2;
00355 this.marker = "a"+half+","+half+" 0 1,0 "+full+",0a"+half+","+half+" 0 1,0 -"+full+",0z";
00356 break;
00357 case 1:
00358 var d = (size/3).toFixed(res.ndig);
00359 this.x0 = this.y0 = size/6;
00360 this.marker = "h"+d+"v-"+d+"h-"+d+"v-"+d+"h-"+d+"v"+d+"h-"+d+"v"+d+"h"+d+"v"+d+"h"+d+"z";
00361 break;
00362 case 2:
00363 this.x0 = -size/2;
00364 this.marker = "l"+half+",-"+half+"l"+half+","+half+"l-"+half+","+half + "z";
00365 break;
00366 case 3:
00367 this.x0 = this.y0 = -size/2;
00368 this.marker = "v"+full+"h"+full+"v-"+full+"z";
00369 break;
00370 case 4:
00371 this.y0 = size/2;
00372 this.marker = "l-"+ half+",-"+full+"h"+full+"z";
00373 break;
00374 case 5:
00375 this.y0 = -size/2;
00376 this.marker = "l-"+ half+","+full+"h"+full+"z";
00377 break;
00378 case 6:
00379 this.y0 = -size/2;
00380 this.marker = "l" + (size/3).toFixed(res.ndig)+","+full +
00381 "l-"+ (5/6*size).toFixed(res.ndig) + ",-" + (5/8*size).toFixed(res.ndig) +
00382 "h" + full +
00383 "l-" + (5/6*size).toFixed(res.ndig) + "," + (5/8*size).toFixed(res.ndig) + "z";
00384 break;
00385 case 7:
00386 this.x0 = this.y0 = -size/2;
00387 this.marker = "l"+full+","+full +
00388 "m0,-"+full+"l-"+full+","+full+
00389 "m0,-"+half+"h"+full+"m-"+half+",-"+half+"v"+full;
00390 break;
00391 case 8:
00392 this.y0 = -size/2;
00393 this.marker = "v"+full+"m-"+half+",-"+half+"h"+full;
00394 break;
00395 case 9:
00396 this.x0 = this.y0 = -size/2;
00397 this.marker = "l"+full+","+full + "m0,-"+full+"l-"+full+","+full;
00398 break;
00399 default:
00400 this.x0 = -size/2;
00401 this.marker = "l"+half+",-"+half+"l"+half+","+half+"l-"+half+","+half + "z";
00402 break;
00403 }
00404
00405 this.create = function(x,y) {
00406 return "M" + (x+this.x0).toFixed(this.ndig)+ "," + (y+this.y0).toFixed(this.ndig) + this.marker;
00407 }
00408
00409 return true;
00410 }
00411
00412 res.Apply = function(selection) {
00413 selection.style('stroke', this.stroke ? this.color : "none");
00414 selection.style('fill', this.fill ? this.color : "none");
00415 }
00416
00417 res.func = res.Apply.bind(res);
00418
00419 res.Change(marker_color, style, attmarker.fMarkerSize);
00420
00421 return res;
00422 }
00423
00424 JSROOT.Painter.createAttLine = function(attline, borderw, can_excl) {
00425
00426 var color = 0, _width = 0, style = 0;
00427 if (typeof attline == 'string') {
00428 if (attline=='black') { color = 1; _width = 1; } else
00429 if (attline=='none') { _width = 0; }
00430 } else
00431 if (typeof attline == 'object') {
00432 if ('fLineColor' in attline) color = attline.fLineColor;
00433 if ('fLineWidth' in attline) _width = attline.fLineWidth;
00434 if ('fLineStyle' in attline) style = attline.fLineStyle;
00435 } else
00436 if ((attline!==undefined) && !isNaN(attline)) {
00437 color = attline;
00438 }
00439
00440 if (borderw!==undefined) _width = borderw;
00441
00442 var line = {
00443 used: true,
00444 color: JSROOT.Painter.root_colors[color],
00445 width: _width,
00446 dash: JSROOT.Painter.root_line_styles[style]
00447 };
00448
00449 if ((_width==0) || (color==0)) line.color = 'none';
00450
00451 if (can_excl) {
00452 line.excl_side = 0;
00453 line.excl_width = 0;
00454 if (Math.abs(line.width) > 99) {
00455
00456 line.excl_side = (line.width < 0) ? -1 : 1;
00457 line.excl_width = Math.floor(line.width / 100) * 5;
00458 line.width = line.width % 100;
00459 }
00460 }
00461
00462
00463 if ((line.color === undefined) && (color>0))
00464 line.color = 'lightgrey';
00465
00466 line.Apply = function(selection) {
00467 this.used = true;
00468 if (this.color=='none') {
00469 selection.style('stroke', null);
00470 selection.style('stroke-width', null);
00471 selection.style('stroke-dasharray', null);
00472 } else {
00473 selection.style('stroke', this.color);
00474 selection.style('stroke-width', this.width);
00475 if (this.dash && (this.dash.length>0))
00476 selection.style('stroke-dasharray', this.dash);
00477 }
00478 }
00479 line.func = line.Apply.bind(line);
00480
00481 return line;
00482 }
00483
00484 JSROOT.Painter.clearCuts = function(chopt) {
00485
00486 var left = chopt.indexOf('[');
00487 var right = chopt.indexOf(']');
00488 if ((left>=0) && (right>=0) && (left<right))
00489 for (var i = left; i <= right; ++i) chopt[i] = ' ';
00490 return chopt;
00491 }
00492
00493 JSROOT.Painter.root_fonts = new Array('Arial', 'Times New Roman',
00494 'bTimes New Roman', 'biTimes New Roman', 'Arial',
00495 'oArial', 'bArial', 'boArial', 'Courier New',
00496 'oCourier New', 'bCourier New', 'boCourier New',
00497 'Symbol', 'Times New Roman', 'Wingdings', 'Symbol', 'Verdana');
00498
00499 JSROOT.Painter.getFontDetails = function(fontIndex, size) {
00500
00501 var fontName = JSROOT.Painter.root_fonts[Math.floor(fontIndex / 10)];
00502
00503 var res = { name: "Arial", size: 11, weight: null, style: null };
00504
00505 if (size != undefined) res.size = Math.round(size);
00506
00507 if (typeof fontName != 'string') fontName = "";
00508
00509 while (fontName.length > 0) {
00510 if (fontName.charAt(0)==='b') res.weight = "bold"; else
00511 if (fontName.charAt(0)==='i') res.style = "italic"; else
00512 if (fontName.charAt(0)==='o') res.style = "oblique"; else break;
00513 fontName = fontName.substr(1);
00514 }
00515
00516 if (fontName == 'Symbol') {
00517 res.weight = null;
00518 res.style = null;
00519 }
00520
00521 res.name = fontName;
00522
00523 res.SetFont = function(selection) {
00524 selection.attr("font-family", this.name)
00525 .attr("font-size", this.size)
00526 .attr("xml:space","preserve");
00527 if (this.weight!=null)
00528 selection.attr("font-weight", this.weight);
00529 if (this.style!=null)
00530 selection.attr("font-style", this.style);
00531 }
00532
00533 res.asStyle = function(sz) {
00534 return ((sz!=null) ? sz : this.size) + "px " + this.name;
00535 }
00536
00537 res.stringWidth = function(svg, line) {
00538
00539 var text = svg.append("svg:text")
00540 .attr("xml:space","preserve")
00541 .style("opacity", 0)
00542 .text(line);
00543 this.SetFont(text);
00544 var w = text.node().getBBox().width;
00545 text.remove();
00546 return w;
00547 }
00548
00549 res.func = res.SetFont.bind(res);
00550
00551 return res;
00552 }
00553
00554 JSROOT.Painter.chooseTimeFormat = function(awidth, ticks) {
00555 if (awidth < .5) return ticks ? "%S.%L" : "%M:%S.%L";
00556 if (awidth < 30) return ticks ? "%Mm%S" : "%H:%M:%S";
00557 awidth /= 60; if (awidth < 30) return ticks ? "%Hh%M" : "%d/%m %H:%M";
00558 awidth /= 60; if (awidth < 12) return ticks ? "%d-%Hh" : "%d/%m/%y %Hh";
00559 awidth /= 24; if (awidth < 15.218425) return ticks ? "%d/%m" : "%d/%m/%y";
00560 awidth /= 30.43685; if (awidth < 6) return "%d/%m/%y";
00561 awidth /= 12; if (awidth < 2) return ticks ? "%m/%y" : "%d/%m/%y";
00562 return "%Y";
00563 }
00564
00565 JSROOT.Painter.getTimeFormat = function(axis) {
00566 var idF = axis.fTimeFormat.indexOf('%F');
00567 if (idF >= 0) return axis.fTimeFormat.substr(0, idF);
00568 return axis.fTimeFormat;
00569 }
00570
00571 JSROOT.Painter.getTimeOffset = function(axis) {
00572 var idF = axis.fTimeFormat.indexOf('%F');
00573 if (idF < 0) return JSROOT.gStyle.TimeOffset;
00574 var sof = axis.fTimeFormat.substr(idF + 2);
00575 if (sof == '1995-01-01 00:00:00s0') return 788918400000;
00576
00577 if ((sof == "0") || (sof == "")) return 0;
00578
00579
00580 var dt = new Date(0);
00581 var pos = sof.indexOf("-"); dt.setFullYear(sof.substr(0,pos)); sof = sof.substr(pos+1);
00582 pos = sof.indexOf("-"); dt.setMonth(parseInt(sof.substr(0,pos))-1); sof = sof.substr(pos+1);
00583 pos = sof.indexOf(" "); dt.setDate(sof.substr(0,pos)); sof = sof.substr(pos+1);
00584 pos = sof.indexOf(":"); dt.setHours(sof.substr(0,pos)); sof = sof.substr(pos+1);
00585 pos = sof.indexOf(":"); dt.setMinutes(sof.substr(0,pos)); sof = sof.substr(pos+1);
00586 pos = sof.indexOf("s"); dt.setSeconds(sof.substr(0,pos));
00587 if (pos>0) { sof = sof.substr(pos+1); dt.setMilliseconds(sof); }
00588 return dt.getTime();
00589 }
00590
00591 JSROOT.Painter.formatExp = function(label) {
00592 var str = label;
00593 if (parseFloat(str) == 1.0) return '1';
00594 if (parseFloat(str) == 10.0) return '10';
00595 var str = str.replace('e+', 'x10@');
00596 var str = str.replace('e-', 'x10@-');
00597 var _val = str.substring(0, str.indexOf('@'));
00598 var _exp = str.substr(str.indexOf('@'));
00599 _val = _val.replace('@', '');
00600 _exp = _exp.replace('@', '');
00601 var u, size = _exp.length;
00602 for (var j = 0; j < size; ++j) {
00603 var u, c = _exp.charAt(j);
00604 if (c == '+') u = '\u207A'; else
00605 if (c == '-') u = '\u207B'; else {
00606 var e = parseInt(c);
00607 if (e == 1) u = String.fromCharCode(0xB9); else
00608 if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e); else
00609 u = String.fromCharCode(0x2070 + e);
00610 }
00611 _exp = _exp.replace(c, u);
00612 }
00613 _val = _val.replace('1x', '');
00614 return _val + _exp;
00615 };
00616
00617 JSROOT.Painter.translateExp = function(str) {
00618 var lstr = str.match(/\^{[0-9]*}/gi);
00619 if (lstr != null) {
00620 var symbol = '';
00621 for (var i = 0; i < lstr.length; ++i) {
00622 symbol = lstr[i].replace(' ', '');
00623 symbol = symbol.replace('^{', '');
00624 symbol = symbol.replace('}', '');
00625 var size = symbol.length;
00626 for (var j = 0; j < size; ++j) {
00627 var c = symbol.charAt(j);
00628 var u, e = parseInt(c);
00629 if (e == 1) u = String.fromCharCode(0xB9);
00630 else if (e > 1 && e < 4) u = String.fromCharCode(0xB0 + e);
00631 else u = String.fromCharCode(0x2070 + e);
00632 symbol = symbol.replace(c, u);
00633 }
00634 str = str.replace(lstr[i], symbol);
00635 }
00636 }
00637 return str;
00638 };
00639
00640 JSROOT.Painter.symbols_map = {
00641
00642 '#alpha' : '\u03B1',
00643 '#beta' : '\u03B2',
00644 '#chi' : '\u03C7',
00645 '#delta' : '\u03B4',
00646 '#varepsilon' : '\u03B5',
00647 '#phi' : '\u03C6',
00648 '#gamma' : '\u03B3',
00649 '#eta' : '\u03B7',
00650 '#iota' : '\u03B9',
00651 '#varphi' : '\u03C6',
00652 '#kappa' : '\u03BA',
00653 '#lambda' : '\u03BB',
00654 '#mu' : '\u03BC',
00655 '#nu' : '\u03BD',
00656 '#omicron' : '\u03BF',
00657 '#pi' : '\u03C0',
00658 '#theta' : '\u03B8',
00659 '#rho' : '\u03C1',
00660 '#sigma' : '\u03C3',
00661 '#tau' : '\u03C4',
00662 '#upsilon' : '\u03C5',
00663 '#varomega' : '\u03D6',
00664 '#omega' : '\u03C9',
00665 '#xi' : '\u03BE',
00666 '#psi' : '\u03C8',
00667 '#zeta' : '\u03B6',
00668 '#Alpha' : '\u0391',
00669 '#Beta' : '\u0392',
00670 '#Chi' : '\u03A7',
00671 '#Delta' : '\u0394',
00672 '#Epsilon' : '\u0395',
00673 '#Phi' : '\u03A6',
00674 '#Gamma' : '\u0393',
00675 '#Eta' : '\u0397',
00676 '#Iota' : '\u0399',
00677 '#vartheta' : '\u03D1',
00678 '#Kappa' : '\u039A',
00679 '#Lambda' : '\u039B',
00680 '#Mu' : '\u039C',
00681 '#Nu' : '\u039D',
00682 '#Omicron' : '\u039F',
00683 '#Pi' : '\u03A0',
00684 '#Theta' : '\u0398',
00685 '#Rho' : '\u03A1',
00686 '#Sigma' : '\u03A3',
00687 '#Tau' : '\u03A4',
00688 '#Upsilon' : '\u03A5',
00689 '#varsigma' : '\u03C2',
00690 '#Omega' : '\u03A9',
00691 '#Xi' : '\u039E',
00692 '#Psi' : '\u03A8',
00693 '#Zeta' : '\u0396',
00694 '#varUpsilon' : '\u03D2',
00695 '#epsilon' : '\u03B5',
00696
00697
00698 '#sqrt' : '\u221A',
00699
00700
00701 '#leq' : '\u2264',
00702 '#/' : '\u2044',
00703 '#infty' : '\u221E',
00704 '#voidb' : '\u0192',
00705 '#club' : '\u2663',
00706 '#diamond' : '\u2666',
00707 '#heart' : '\u2665',
00708 '#spade' : '\u2660',
00709 '#leftrightarrow' : '\u2194',
00710 '#leftarrow' : '\u2190',
00711 '#uparrow' : '\u2191',
00712 '#rightarrow' : '\u2192',
00713 '#downarrow' : '\u2193',
00714 '#circ' : '\u02C6',
00715 '#pm' : '\xB1',
00716 '#doublequote' : '\u2033',
00717 '#geq' : '\u2265',
00718 '#times' : '\xD7',
00719 '#propto' : '\u221D',
00720 '#partial' : '\u2202',
00721 '#bullet' : '\u2022',
00722 '#divide' : '\xF7',
00723 '#neq' : '\u2260',
00724 '#equiv' : '\u2261',
00725 '#approx' : '\u2248',
00726 '#3dots' : '\u2026',
00727 '#cbar' : '\u007C',
00728 '#topbar' : '\xAF',
00729 '#downleftarrow' : '\u21B5',
00730 '#aleph' : '\u2135',
00731 '#Jgothic' : '\u2111',
00732 '#Rgothic' : '\u211C',
00733 '#voidn' : '\u2118',
00734 '#otimes' : '\u2297',
00735 '#oplus' : '\u2295',
00736 '#oslash' : '\u2205',
00737 '#cap' : '\u2229',
00738 '#cup' : '\u222A',
00739 '#supseteq' : '\u2287',
00740 '#supset' : '\u2283',
00741 '#notsubset' : '\u2284',
00742 '#subseteq' : '\u2286',
00743 '#subset' : '\u2282',
00744 '#int' : '\u222B',
00745 '#in' : '\u2208',
00746 '#notin' : '\u2209',
00747 '#angle' : '\u2220',
00748 '#nabla' : '\u2207',
00749 '#oright' : '\xAE',
00750 '#ocopyright' : '\xA9',
00751 '#trademark' : '\u2122',
00752 '#prod' : '\u220F',
00753 '#surd' : '\u221A',
00754 '#upoint' : '\u22C5',
00755 '#corner' : '\xAC',
00756 '#wedge' : '\u2227',
00757 '#vee' : '\u2228',
00758 '#Leftrightarrow' : '\u21D4',
00759 '#Leftarrow' : '\u21D0',
00760 '#Uparrow' : '\u21D1',
00761 '#Rightarrow' : '\u21D2',
00762 '#Downarrow' : '\u21D3',
00763 '#LT' : '\x3C',
00764 '#void1' : '\xAE',
00765 '#copyright' : '\xA9',
00766 '#void3' : '\u2122',
00767 '#sum' : '\u2211',
00768 '#arctop' : '',
00769 '#lbar' : '',
00770 '#arcbottom' : '',
00771 '#void8' : '',
00772 '#bottombar' : '\u230A',
00773 '#arcbar' : '',
00774 '#ltbar' : '',
00775 '#AA' : '\u212B',
00776 '#aa' : '\u00E5',
00777 '#void06' : '',
00778 '#GT' : '\x3E',
00779 '#forall' : '\u2200',
00780 '#exists' : '\u2203',
00781 '#bar' : '',
00782 '#vec' : '',
00783 '#dot' : '\u22C5',
00784 '#hat' : '\xB7',
00785 '#ddot' : '',
00786 '#acute' : '\acute',
00787 '#grave' : '',
00788 '#check' : '\u2713',
00789 '#tilde' : '\u02DC',
00790 '#slash' : '\u2044',
00791 '#hbar' : '\u0127',
00792 '#box' : '',
00793 '#Box' : '',
00794 '#parallel' : '',
00795 '#perp' : '\u22A5',
00796 '#odot' : '',
00797 '#left' : '',
00798 '#right' : ''
00799 };
00800
00801 JSROOT.Painter.translateLaTeX = function(string) {
00802 var str = string;
00803 str = this.translateExp(str);
00804 while (str.indexOf('^{o}') != -1)
00805 str = str.replace('^{o}', '\xBA');
00806 var lstr = str.match(/\#sqrt{(.*?)}/gi);
00807 if (lstr != null)
00808 for (var i = 0; i < lstr.length; ++i) {
00809 var symbol = lstr[i].replace(' ', '');
00810 symbol = symbol.replace('#sqrt{', '#sqrt');
00811 symbol = symbol.replace('}', '');
00812 str = str.replace(lstr[i], symbol);
00813 }
00814 lstr = str.match(/\_{(.*?)}/gi);
00815 if (lstr != null)
00816 for (var i = 0; i < lstr.length; ++i) {
00817 var symbol = lstr[i].replace(' ', '');
00818 symbol = symbol.replace('_{', '');
00819 symbol = symbol.replace('}', '');
00820 str = str.replace(lstr[i], symbol);
00821 }
00822 lstr = str.match(/\^{(.*?)}/gi);
00823 if (lstr != null)
00824 for (i = 0; i < lstr.length; ++i) {
00825 var symbol = lstr[i].replace(' ', '');
00826 symbol = symbol.replace('^{', '');
00827 symbol = symbol.replace('}', '');
00828 str = str.replace(lstr[i], symbol);
00829 }
00830 while (str.indexOf('#/') != -1)
00831 str = str.replace('#/', JSROOT.Painter.symbols_map['#/']);
00832 for ( var x in JSROOT.Painter.symbols_map) {
00833 while (str.indexOf(x) != -1)
00834 str = str.replace(x, JSROOT.Painter.symbols_map[x]);
00835 }
00836
00837
00838 if ((str.indexOf("#splitline{")==0) && (str.charAt(str.length-1)=="}")) {
00839 var pos = str.indexOf("}{");
00840 if ((pos>0) && (pos == str.lastIndexOf("}{"))) {
00841 str = str.replace("}{", "\n");
00842 str = str.slice(11, str.length-1);
00843 }
00844 }
00845 return str;
00846 }
00847
00848 JSROOT.Painter.isAnyLatex = function(str) {
00849 return (str.indexOf("#")>=0) || (str.indexOf("\\")>=0) || (str.indexOf("{")>=0);
00850 }
00851
00852 JSROOT.Painter.translateMath = function(str, kind, color) {
00853
00854
00855 if (kind!=2) {
00856 str = str.replace(/#LT/g, "\\langle");
00857 str = str.replace(/#GT/g, "\\rangle");
00858 str = str.replace(/#club/g, "\\clubsuit");
00859 str = str.replace(/#spade/g, "\\spadesuit");
00860 str = str.replace(/#heart/g, "\\heartsuit");
00861 str = str.replace(/#diamond/g, "\\diamondsuit");
00862 str = str.replace(/#voidn/g, "\\wp");
00863 str = str.replace(/#voidb/g, "f");
00864 str = str.replace(/#copyright/g, "(c)");
00865 str = str.replace(/#ocopyright/g, "(c)");
00866 str = str.replace(/#trademark/g, "TM");
00867 str = str.replace(/#void3/g, "TM");
00868 str = str.replace(/#oright/g, "R");
00869 str = str.replace(/#void1/g, "R");
00870 str = str.replace(/#3dots/g, "\\ldots");
00871 str = str.replace(/#lbar/g, "\\mid");
00872 str = str.replace(/#void8/g, "\\mid");
00873 str = str.replace(/#divide/g, "\\div");
00874 str = str.replace(/#Jgothic/g, "\\Im");
00875 str = str.replace(/#Rgothic/g, "\\Re");
00876 str = str.replace(/#doublequote/g, "\"");
00877 str = str.replace(/#plus/g, "+");
00878
00879 str = str.replace(/#diamond/g, "\\diamondsuit");
00880 str = str.replace(/#voidn/g, "\\wp");
00881 str = str.replace(/#voidb/g, "f");
00882 str = str.replace(/#copyright/g, "(c)");
00883 str = str.replace(/#ocopyright/g, "(c)");
00884 str = str.replace(/#trademark/g, "TM");
00885 str = str.replace(/#void3/g, "TM");
00886 str = str.replace(/#oright/g, "R");
00887 str = str.replace(/#void1/g, "R");
00888 str = str.replace(/#3dots/g, "\\ldots");
00889 str = str.replace(/#lbar/g, "\\mid");
00890 str = str.replace(/#void8/g, "\\mid");
00891 str = str.replace(/#divide/g, "\\div");
00892 str = str.replace(/#Jgothic/g, "\\Im");
00893 str = str.replace(/#Rgothic/g, "\\Re");
00894 str = str.replace(/#doublequote/g, "\"");
00895 str = str.replace(/#plus/g, "+");
00896 str = str.replace(/#minus/g, "-");
00897 str = str.replace(/#\
00898 str = str.replace(/#upoint/g, ".");
00899 str = str.replace(/#aa/g, "\\mathring{a}");
00900 str = str.replace(/#AA/g, "\\mathring{A}");
00901
00902 str = str.replace(/#omicron/g, "o");
00903 str = str.replace(/#Alpha/g, "A");
00904 str = str.replace(/#Beta/g, "B");
00905 str = str.replace(/#Epsilon/g, "E");
00906 str = str.replace(/#Zeta/g, "Z");
00907 str = str.replace(/#Eta/g, "H");
00908 str = str.replace(/#Iota/g, "I");
00909 str = str.replace(/#Kappa/g, "K");
00910 str = str.replace(/#Mu/g, "M");
00911 str = str.replace(/#Nu/g, "N");
00912 str = str.replace(/#Omicron/g, "O");
00913 str = str.replace(/#Rho/g, "P");
00914 str = str.replace(/#Tau/g, "T");
00915 str = str.replace(/#Chi/g, "X");
00916 str = str.replace(/#varomega/g, "\\varpi");
00917
00918 str = str.replace(/#corner/g, "?");
00919 str = str.replace(/#ltbar/g, "?");
00920 str = str.replace(/#bottombar/g, "?");
00921 str = str.replace(/#notsubset/g, "?");
00922 str = str.replace(/#arcbottom/g, "?");
00923 str = str.replace(/#cbar/g, "?");
00924 str = str.replace(/#arctop/g, "?");
00925 str = str.replace(/#topbar/g, "?");
00926 str = str.replace(/#arcbar/g, "?");
00927 str = str.replace(/#downleftarrow/g, "?");
00928 str = str.replace(/#splitline/g, "\\genfrac{}{}{0pt}{}");
00929 str = str.replace(/#it/g, "\\textit");
00930 str = str.replace(/#bf/g, "\\textbf");
00931
00932 str = str.replace(/#frac/g, "\\frac");
00933
00934
00935 str = str.replace(/#left{/g, "\\lbrace");
00936 str = str.replace(/#right}/g, "\\rbrace");
00937 str = str.replace(/#left\[/g, "\\lbrack");
00938 str = str.replace(/#right\]/g, "\\rbrack");
00939
00940
00941
00942 str = str.replace(/#\[\]{/g, "\\lbrack");
00943 str = str.replace(/ } /g, "\\rbrack");
00944
00945
00946 str = str.replace(/#\[/g, "\\lbrack");
00947 str = str.replace(/#\]/g, "\\rbrack");
00948 str = str.replace(/#{/g, "\\lbrace");
00949 str = str.replace(/#}/g, "\\rbrace");
00950 str = str.replace(/ /g, "\\;");
00951
00952 for (var x in JSROOT.Painter.symbols_map) {
00953 var y = "\\" + x.substr(1);
00954 str = str.replace(new RegExp(x,'g'), y);
00955 }
00956 } else {
00957 str = str.replace(/\\\^/g, "\\hat");
00958 }
00959
00960 if (typeof color != 'string') return "\\(" + str + "\\)";
00961
00962 if (color.indexOf("rgb(")>=0)
00963 color = color.replace(/rgb/g, "[RGB]")
00964 .replace(/\(/g, '{')
00965 .replace(/\)/g, '}');
00966 return "\\(\\color{" + color + '}' + str + "\\)";
00967 }
00968
00969
00970
00971 JSROOT.TBasePainter = function() {
00972 this.divid = null;
00973 }
00974
00975 JSROOT.TBasePainter.prototype.Cleanup = function() {
00976
00977 }
00978
00979 JSROOT.TBasePainter.prototype.DrawingReady = function() {
00980
00981 this['_ready_called_'] = true;
00982 if ('_ready_callback_' in this) {
00983 JSROOT.CallBack(this['_ready_callback_'], this);
00984 delete this['_ready_callback_'];
00985 this['_ready_callback_'] = null;
00986 }
00987 return this;
00988 }
00989
00990 JSROOT.TBasePainter.prototype.WhenReady = function(callback) {
00991
00992 if ('_ready_called_' in this) return JSROOT.CallBack(callback, this);
00993 this['_ready_callback_'] = callback;
00994 }
00995
00996 JSROOT.TBasePainter.prototype.GetObject = function() {
00997 return null;
00998 }
00999
01000 JSROOT.TBasePainter.prototype.MatchObjectType = function(typ) {
01001 return false;
01002 }
01003
01004 JSROOT.TBasePainter.prototype.UpdateObject = function(obj) {
01005 return false;
01006 }
01007
01008 JSROOT.TBasePainter.prototype.RedrawPad = function(resize) {
01009 }
01010
01011 JSROOT.TBasePainter.prototype.RedrawObject = function(obj) {
01012 if (this.UpdateObject(obj)) {
01013 var current = document.body.style.cursor;
01014 document.body.style.cursor = 'wait';
01015 this.RedrawPad();
01016 document.body.style.cursor = current;
01017 }
01018 }
01019
01020 JSROOT.TBasePainter.prototype.CheckResize = function(arg) {
01021 return false;
01022 }
01023
01024 JSROOT.TBasePainter.prototype.select_main = function() {
01025
01026 if ((this.divid === null) || (this.divid === undefined)) return d3.select(null);
01027 if ((typeof this.divid == "string") &&
01028 (this.divid.charAt(0) != "#")) return d3.select("#" + this.divid);
01029 return d3.select(this.divid);
01030 }
01031
01032 JSROOT.TBasePainter.prototype.main_visible_rect = function() {
01033
01034
01035 var render_to = this.select_main();
01036
01037 var rect = render_to.node().getBoundingClientRect();
01038
01039 var res = {};
01040
01041
01042 res.width = Math.round(rect.width - this.GetStyleValue(render_to, 'padding-left') - this.GetStyleValue(render_to, 'padding-right'));
01043 res.height = Math.round(rect.height - this.GetStyleValue(render_to, 'padding-top') - this.GetStyleValue(render_to, 'padding-bottom'));
01044
01045 return res;
01046 }
01047
01048 JSROOT.TBasePainter.prototype.SetDivId = function(divid) {
01049
01050
01051 if (arguments.length > 0)
01052 this.divid = divid;
01053 var main = this.select_main();
01054 var chld = main.node() ? main.node().firstChild : null;
01055 if (chld) chld.painter = this;
01056 }
01057
01058 JSROOT.TBasePainter.prototype.SetItemName = function(name, opt) {
01059 if (typeof name === 'string') this._hitemname = name;
01060 else delete this._hitemname;
01061
01062 if (typeof opt === 'string') this._hdrawopt = opt;
01063 }
01064
01065 JSROOT.TBasePainter.prototype.GetItemName = function() {
01066 return ('_hitemname' in this) ? this._hitemname : null;
01067 }
01068
01069 JSROOT.TBasePainter.prototype.GetItemDrawOpt = function() {
01070 return ('_hdrawopt' in this) ? this._hdrawopt : "";
01071 }
01072
01073 JSROOT.TBasePainter.prototype.CanZoomIn = function(axis,left,right) {
01074
01075 return false;
01076 }
01077
01078 JSROOT.TBasePainter.prototype.GetStyleValue = function(select, name) {
01079 var value = select.style(name);
01080 if (!value) return 0;
01081 value = parseFloat(value.replace("px",""));
01082 return isNaN(value) ? 0 : value;
01083 }
01084
01085
01086
01087 JSROOT.TObjectPainter = function(obj) {
01088 JSROOT.TBasePainter.call(this);
01089 this.draw_g = null;
01090 this.pad_name = "";
01091 this.main = null;
01092 this.draw_object = ((obj!==undefined) && (typeof obj == 'object')) ? obj : null;
01093 }
01094
01095 JSROOT.TObjectPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
01096
01097 JSROOT.TObjectPainter.prototype.GetObject = function() {
01098 return this.draw_object;
01099 }
01100
01101 JSROOT.TObjectPainter.prototype.MatchObjectType = function(arg) {
01102 if ((arg === undefined) || (arg === null) || (this.draw_object===null)) return false;
01103 if (typeof arg === 'string') return this.draw_object._typename === arg;
01104 return (typeof arg === 'object') && (this.draw_object._typename === arg._typename);
01105 }
01106
01107 JSROOT.TObjectPainter.prototype.SetItemName = function(name, opt) {
01108 JSROOT.TBasePainter.prototype.SetItemName.call(this, name, opt);
01109 if (name=="") return;
01110 var can = this.svg_canvas();
01111 if (!can.empty()) can.select("title").text(name);
01112 else this.select_main().attr("title", name);
01113 }
01114
01115 JSROOT.TObjectPainter.prototype.UpdateObject = function(obj) {
01116
01117
01118 if (!this.MatchObjectType(obj)) return false;
01119 JSROOT.extend(this.GetObject(), obj);
01120 return true;
01121 }
01122
01123 JSROOT.TObjectPainter.prototype.GetTipName = function(append) {
01124 var res = this.GetItemName();
01125 if (res===null) res = "";
01126 if ((res.length === 0) && ('fName' in this.GetObject()))
01127 res = this.GetObject().fName;
01128 if (res.lenght > 20) res = res.substr(0,17)+"...";
01129 if ((res.length > 0) && (append!==undefined)) res += append;
01130 return res;
01131 }
01132
01133 JSROOT.TObjectPainter.prototype.pad_painter = function(active_pad) {
01134 var can = active_pad ? this.svg_pad() : this.svg_canvas();
01135 return can.empty() ? null : can.property('pad_painter');
01136 }
01137
01138 JSROOT.TObjectPainter.prototype.CheckResize = function(arg) {
01139
01140 var pad_painter = this.pad_painter();
01141 if (pad_painter)
01142 return pad_painter.CheckCanvasResize(arg, false);
01143 return false;
01144 }
01145
01146 JSROOT.TObjectPainter.prototype.RemoveDrawG = function() {
01147
01148 if (this.draw_g != null) {
01149 this.draw_g.remove();
01150 this.draw_g = null;
01151 }
01152 }
01153
01157 JSROOT.TObjectPainter.prototype.RecreateDrawG = function(take_pad, layer) {
01158 if (this.draw_g) {
01159
01160 d3.selectAll(this.draw_g.node().childNodes).remove();
01161 } else
01162 if (take_pad) {
01163 if (typeof layer != 'string') layer = "text_layer";
01164 if (layer.charAt(0) == ".") layer = layer.substr(1);
01165 this.draw_g = this.svg_layer(layer).append("svg:g");
01166 } else {
01167 if (typeof layer != 'string') layer = ".main_layer";
01168 if (layer.charAt(0) != ".") layer = "." + layer;
01169 this.draw_g = this.svg_frame().select(layer).append("svg:g");
01170 }
01171
01172
01173 if (this.draw_object!==null) {
01174 this.draw_g.attr('objname', this.draw_object.fName);
01175 this.draw_g.attr('objtype', this.draw_object._typename);
01176 }
01177
01178 return this.draw_g;
01179 }
01180
01182 JSROOT.TObjectPainter.prototype.svg_canvas = function() {
01183 return this.select_main().select(".root_canvas");
01184 }
01185
01187 JSROOT.TObjectPainter.prototype.svg_pad = function(pad_name) {
01188 var c = this.svg_canvas();
01189 if (pad_name === undefined) pad_name = this.pad_name;
01190 if ((pad_name.length > 0) && !c.empty())
01191 c = c.select(".subpads_layer").select("[pad=" + pad_name + ']');
01192 return c;
01193 }
01194
01196 JSROOT.TObjectPainter.prototype.svg_layer = function(name, pad_name) {
01197 var svg = this.svg_pad(pad_name);
01198 if (svg.empty()) return svg;
01199
01200 var node = svg.node().firstChild;
01201
01202 while (node!==null) {
01203 var elem = d3.select(node);
01204 if (elem.classed(name)) return elem;
01205 node = node.nextSibling;
01206 }
01207
01208 return d3.select(null);
01209 }
01210
01211 JSROOT.TObjectPainter.prototype.root_pad = function() {
01212 var pad_painter = this.pad_painter(true);
01213 return pad_painter ? pad_painter.pad : null;
01214 }
01215
01217 JSROOT.TObjectPainter.prototype.ConvertToNDC = function(axis, value, isndc) {
01218 var pad = this.root_pad();
01219 if (isndc == null) isndc = false;
01220
01221 if (isndc || (pad==null)) return value;
01222
01223 if (axis=="y") {
01224 if (pad.fLogy)
01225 value = (value>0) ? JSROOT.log10(value) : pad.fUymin;
01226 return (value - pad.fY1) / (pad.fY2 - pad.fY1);
01227 }
01228 if (pad.fLogx)
01229 value = (value>0) ? JSROOT.log10(value) : pad.fUxmin;
01230 return (value - pad.fX1) / (pad.fX2 - pad.fX1);
01231 }
01232
01236 JSROOT.TObjectPainter.prototype.AxisToSvg = function(axis, value, ndc) {
01237 var main = this.main_painter();
01238 if ((main!=null) && !ndc)
01239 return axis=="y" ? main.gry(value) : main.grx(value);
01240 if (!ndc) value = this.ConvertToNDC(axis, value);
01241 if (axis=="y") return (1-value)*this.pad_height();
01242 return value*this.pad_width();
01243 }
01244
01245 JSROOT.TObjectPainter.prototype.PadToSvg = function(axis, value, ndc) {
01246 return this.AxisToSvg(axis,value,ndc);
01247 }
01248
01250 JSROOT.TObjectPainter.prototype.svg_frame = function() {
01251 return this.svg_pad().select(".root_frame");
01252 }
01253
01254 JSROOT.TObjectPainter.prototype.frame_painter = function() {
01255 var res = this.svg_frame().property('frame_painter');
01256 return (res===undefined) ? null : res;
01257 }
01258
01259 JSROOT.TObjectPainter.prototype.pad_width = function(pad_name) {
01260 var res = this.svg_pad(pad_name).property("draw_width");
01261 return isNaN(res) ? 0 : res;
01262 }
01263
01264 JSROOT.TObjectPainter.prototype.pad_height = function(pad_name) {
01265 var res = this.svg_pad(pad_name).property("draw_height");
01266 return isNaN(res) ? 0 : res;
01267 }
01268
01269 JSROOT.TObjectPainter.prototype.frame_x = function() {
01270 var res = parseInt(this.svg_frame().attr("x"));
01271 return isNaN(res) ? 0 : res;
01272 }
01273
01274 JSROOT.TObjectPainter.prototype.frame_y = function() {
01275 var res = parseInt(this.svg_frame().attr("y"));
01276 return isNaN(res) ? 0 : res;
01277 }
01278
01279 JSROOT.TObjectPainter.prototype.frame_width = function() {
01280 var res = parseInt(this.svg_frame().attr("width"));
01281 return isNaN(res) ? 0 : res;
01282 }
01283
01284 JSROOT.TObjectPainter.prototype.frame_height = function() {
01285 var res = parseInt(this.svg_frame().attr("height"));
01286 return isNaN(res) ? 0 : res;
01287 }
01288
01289 JSROOT.TObjectPainter.prototype.embed_3d = function() {
01290
01291
01292
01293
01294
01295 if (JSROOT.gStyle.Embed3DinSVG < 2) return JSROOT.gStyle.Embed3DinSVG;
01296 if (JSROOT.browser.isFirefox )
01297 return JSROOT.gStyle.Embed3DinSVG;
01298 return 1;
01299 }
01300
01301 JSROOT.TObjectPainter.prototype.size_for_3d = function(can3d) {
01302
01303
01304 if (can3d === undefined) can3d = this.embed_3d();
01305
01306 var pad = this.svg_pad();
01307
01308 var clname = this.pad_name;
01309 if (clname == '') clname = 'canvas';
01310 clname = "draw3d_" + clname;
01311
01312 if (pad.empty()) {
01313
01314
01315 var rect = this.main_visible_rect();
01316
01317 if ((rect.height<10) && (rect.width>10)) {
01318 rect.height = Math.round(0.66*rect.width);
01319 this.select_main().style('height', rect.height + "px");
01320 }
01321 rect.x = 0; rect.y = 0; rect.clname = clname; rect.can3d = -1;
01322 return rect;
01323 }
01324
01325 var elem = pad;
01326 if (can3d == 0) elem = this.svg_canvas();
01327
01328 var size = { x: 0, y: 0, width: 100, height:100, clname: clname, can3d: can3d };
01329
01330 if (this.frame_painter()!==null) {
01331 elem = this.svg_frame();
01332 size.x = elem.property("draw_x");
01333 size.y = elem.property("draw_y");
01334 }
01335
01336 size.width = elem.property("draw_width");
01337 size.height = elem.property("draw_height");
01338
01339 if ((this.frame_painter()===null) && (can3d > 0)) {
01340 size.x = Math.round(size.x + size.width*0.1);
01341 size.y = Math.round(size.y + size.height*0.1);
01342 size.width = Math.round(size.width*0.8);
01343 size.height = Math.round(size.height*0.8);
01344 }
01345
01346 if (can3d === 1)
01347 this.CalcAbsolutePosition(this.svg_pad(), size);
01348
01349 return size;
01350 }
01351
01352 JSROOT.TObjectPainter.prototype.clear_3d_canvas = function() {
01353 var can3d = this.svg_pad().property('can3d');
01354 if (can3d === null) return;
01355
01356 this.svg_pad().property('can3d', null);
01357
01358 var size = this.size_for_3d(can3d);
01359
01360 if (size.can3d === 0) {
01361 d3.select(this.svg_canvas().node().nextSibling).remove();
01362 this.svg_canvas().style('display', null);
01363 } else {
01364 if (this.svg_pad().empty()) return;
01365
01366 this.apply_3d_size(size).remove();
01367
01368 this.svg_frame().style('display', null);
01369 }
01370 }
01371
01372 JSROOT.TObjectPainter.prototype.add_3d_canvas = function(size, canv) {
01373
01374 if ((canv == null) || (size.can3d < -1)) return;
01375
01376 if (size.can3d === -1) {
01377
01378
01379 var main = this.select_main().node();
01380 if (main !== null) {
01381 main.appendChild(canv);
01382 canv['painter'] = this;
01383 }
01384
01385 return;
01386 }
01387
01388 this.svg_pad().property('can3d', size.can3d);
01389
01390 if (size.can3d === 0) {
01391 this.svg_canvas().style('display', 'none');
01392
01393 this.svg_canvas().node().parentNode.appendChild(canv);
01394 } else {
01395 if (this.svg_pad().empty()) return;
01396
01397
01398 this.svg_frame().style('display', 'none');
01399
01400 var elem = this.apply_3d_size(size);
01401
01402 elem.attr('title','').node().appendChild(canv);
01403 }
01404 }
01405
01406 JSROOT.TObjectPainter.prototype.apply_3d_size = function(size, onlyget) {
01407
01408 if (size.can3d < 0) return d3.select(null);
01409
01410 var elem;
01411
01412 if (size.can3d > 1) {
01413
01414 var layer = this.svg_layer("special_layer");
01415
01416 elem = layer.select("." + size.clname);
01417 if (onlyget) return elem;
01418
01419 if (elem.empty())
01420 elem = layer.append("foreignObject").attr("class", size.clname);
01421
01422 elem.attr('x', size.x)
01423 .attr('y', size.y)
01424 .attr('width', size.width)
01425 .attr('height', size.height)
01426 .attr('viewBox', "0 0 " + size.width + " " + size.height)
01427 .attr('preserveAspectRatio','xMidYMid');
01428
01429 } else {
01430 elem = d3.select(this.svg_canvas().node().parentNode).select("." + size.clname);
01431 if (onlyget) return elem;
01432
01433
01434 this.svg_canvas().property('redraw_by_resize', true);
01435
01436 if (elem.empty()) {
01437 elem = d3.select(this.svg_canvas().node().parentNode)
01438 .append('div').attr("class", size.clname);
01439 }
01440
01441 elem.style('position','absolute')
01442 .style('left', size.x + 'px')
01443 .style('top', size.y + 'px')
01444 .style('width', size.width + 'px')
01445 .style('height', size.height + 'px');
01446 }
01447
01448 return elem;
01449 }
01450
01451
01453 JSROOT.TObjectPainter.prototype.main_painter = function() {
01454 if (this.main === null) {
01455 var svg_p = this.svg_pad();
01456 if (!svg_p.empty()) {
01457 this.main = svg_p.property('mainpainter');
01458 if (this.main === undefined) this.main = null;
01459 }
01460 }
01461 return this.main;
01462 }
01463
01464 JSROOT.TObjectPainter.prototype.is_main_painter = function() {
01465 return this === this.main_painter();
01466 }
01467
01468 JSROOT.TObjectPainter.prototype.SetDivId = function(divid, is_main) {
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 if (divid !== undefined)
01481 this.divid = divid;
01482
01483 if ((is_main === null) || (is_main === undefined)) is_main = 0;
01484
01485 this.create_canvas = false;
01486
01487
01488 var svg_c = this.svg_canvas();
01489
01490 if (svg_c.empty() && (is_main > 0) && (is_main!==5)) {
01491 JSROOT.Painter.drawCanvas(divid, null, ((is_main == 2) || (is_main == 4)) ? "noframe" : "");
01492 svg_c = this.svg_canvas();
01493 this.create_canvas = true;
01494 }
01495
01496 if (svg_c.empty()) {
01497 if ((is_main < 0) || (is_main===5) || this.iscan) return;
01498 var main = this.select_main();
01499 if (main.node() && main.node().firstChild)
01500 main.node().firstChild.painter = this;
01501 return;
01502 }
01503
01504
01505 this.pad_name = svg_c.property('current_pad');
01506
01507 if (is_main < 0) return;
01508
01509
01510 if (this.svg_frame().select(".main_layer").empty() && ((is_main == 1) || (is_main == 3))) {
01511 JSROOT.Painter.drawFrame(divid, null);
01512 if (this.svg_frame().empty()) return alert("Fail to draw dummy TFrame");
01513 }
01514
01515 var svg_p = this.svg_pad();
01516 if (svg_p.empty()) return;
01517
01518 if (svg_p.property('pad_painter') !== this)
01519 svg_p.property('pad_painter').painters.push(this);
01520
01521 if (((is_main === 1) || (is_main === 4) || (is_main === 5)) && (svg_p.property('mainpainter') == null))
01522
01523 svg_p.property('mainpainter', this);
01524 }
01525
01526 JSROOT.TObjectPainter.prototype.CalcAbsolutePosition = function(sel, pos) {
01527 while (!sel.empty() && !sel.classed('root_canvas')) {
01528 if (sel.classed('root_frame') || sel.classed('root_pad')) {
01529 pos.x += sel.property("draw_x");
01530 pos.y += sel.property("draw_y");
01531 }
01532 sel = d3.select(sel.node().parentNode);
01533 }
01534 return pos;
01535 }
01536
01537
01538 JSROOT.TObjectPainter.prototype.createAttFill = function(attfill, pattern, color, kind) {
01539
01540
01541
01542
01543
01544 var fill = { color: "none", colorindx: 0, pattern: 0, used: true, kind: 2 };
01545
01546 if (kind!==undefined) fill.kind = kind;
01547
01548 fill.Apply = function(selection) {
01549 this.used = true;
01550
01551 selection.style('fill', this.color);
01552
01553 if ('opacity' in this)
01554 selection.style('opacity', this.opacity);
01555
01556 if ('antialias' in this)
01557 selection.style('antialias', this.antialias);
01558 }
01559 fill.func = fill.Apply.bind(fill);
01560
01561 fill.Change = function(color, pattern, svg) {
01562 if ((color !== undefined) && !isNaN(color))
01563 this.colorindx = color;
01564
01565 if ((pattern !== undefined) && !isNaN(pattern)) {
01566 this.pattern = pattern;
01567 delete this.opacity;
01568 delete this.antialias;
01569 }
01570
01571 if (this.pattern < 1001) {
01572 this.color = 'none';
01573 return true;
01574 }
01575
01576 if ((this.pattern === 1001) && (this.colorindx===0) && (this.kind===1)) {
01577 this.color = 'none';
01578 return true;
01579 }
01580
01581 this.color = JSROOT.Painter.root_colors[this.colorindx];
01582 if (typeof this.color != 'string') this.color = "none";
01583
01584 if (this.pattern === 1001) return true;
01585
01586 if ((this.pattern >= 4000) && (this.pattern <= 4100)) {
01587
01588 this.opacity = (this.pattern - 4000)/100;
01589 return true;
01590 }
01591
01592 if ((svg===undefined) || svg.empty() || (this.pattern < 3000) || (this.pattern > 3025)) return false;
01593
01594 var id = "pat_" + this.pattern + "_" + this.colorindx;
01595
01596 var defs = svg.select('defs');
01597 if (defs.empty())
01598 defs = svg.insert("svg:defs",":first-child");
01599
01600 var line_color = this.color;
01601 this.color = "url(#" + id + ")";
01602 this.antialias = false;
01603
01604 if (!defs.select("."+id).empty()) return true;
01605
01606 var patt = defs.append('svg:pattern').attr("id", id).attr("class",id).attr("patternUnits","userSpaceOnUse");
01607
01608 switch (this.pattern) {
01609 case 3001:
01610 patt.attr("width", 2).attr("height", 2);
01611 patt.append('svg:rect').attr("x", 0).attr("y", 0).attr("width", 1).attr("height", 1);
01612 patt.append('svg:rect').attr("x", 1).attr("y", 1).attr("width", 1).attr("height", 1);
01613 break;
01614 case 3002:
01615 patt.attr("width", 4).attr("height", 2);
01616 patt.append('svg:rect').attr("x", 1).attr("y", 0).attr("width", 1).attr("height", 1);
01617 patt.append('svg:rect').attr("x", 3).attr("y", 1).attr("width", 1).attr("height", 1);
01618 break;
01619 case 3003:
01620 patt.attr("width", 4).attr("height", 4);
01621 patt.append('svg:rect').attr("x", 2).attr("y", 1).attr("width", 1).attr("height", 1);
01622 patt.append('svg:rect').attr("x", 0).attr("y", 3).attr("width", 1).attr("height", 1);
01623 break;
01624 case 3005:
01625 patt.attr("width", 8).attr("height", 8);
01626 patt.append("svg:line").attr("x1", 0).attr("y1", 0).attr("x2", 8).attr("y2", 8);
01627 break;
01628 case 3006:
01629 patt.attr("width", 4).attr("height", 4);
01630 patt.append("svg:line").attr("x1", 1).attr("y1", 0).attr("x2", 1).attr("y2", 3);
01631 break;
01632 case 3007:
01633 patt.attr("width", 4).attr("height", 4);
01634 patt.append("svg:line").attr("x1", 0).attr("y1", 1).attr("x2", 3).attr("y2", 1);
01635 break;
01636 case 3010:
01637 patt.attr("width", 10).attr("height", 10);
01638 patt.append("svg:line").attr("x1", 0).attr("y1", 2).attr("x2", 10).attr("y2", 2);
01639 patt.append("svg:line").attr("x1", 0).attr("y1", 7).attr("x2", 10).attr("y2", 7);
01640 patt.append("svg:line").attr("x1", 2).attr("y1", 0).attr("x2", 2).attr("y2", 2);
01641 patt.append("svg:line").attr("x1", 7).attr("y1", 2).attr("x2", 7).attr("y2", 7);
01642 patt.append("svg:line").attr("x1", 2).attr("y1", 7).attr("x2", 2).attr("y2", 10);
01643 break;
01644 case 3021:
01645 case 3022:
01646 patt.attr("width", 10).attr("height", 10);
01647 patt.append("svg:line").attr("x1", 0).attr("y1", 5).attr("x2", 5).attr("y2", 5);
01648 patt.append("svg:line").attr("x1", 5).attr("y1", 5).attr("x2", 5).attr("y2", 0);
01649 patt.append("svg:line").attr("x1", 5).attr("y1", 10).attr("x2", 10).attr("y2", 10);
01650 patt.append("svg:line").attr("x1", 10).attr("y1", 10).attr("x2", 10).attr("y2", 5);
01651 break;
01652 default:
01653 patt.attr("width", 8).attr("height", 8);
01654 patt.append("svg:line").attr("x1", 8).attr("y1", 0).attr("x2", 0).attr("y2", 8);
01655 break;
01656 }
01657
01658 patt.selectAll('line').style("stroke",line_color).style("stroke-width", 1);
01659 patt.selectAll('rect').style("fill",line_color);
01660
01661 return true;
01662 }
01663
01664 if ((attfill!==null) && (typeof attfill == 'object')) {
01665 if ('fFillStyle' in attfill) pattern = attfill.fFillStyle;
01666 if ('fFillColor' in attfill) color = attfill.fFillColor;
01667 }
01668
01669 fill.Change(color, pattern, this.svg_canvas());
01670
01671 return fill;
01672 }
01673
01674 JSROOT.TObjectPainter.prototype.ForEachPainter = function(userfunc) {
01675
01676
01677 var main = this.select_main();
01678 var painter = (main.node() && main.node().firstChild) ? main.node().firstChild['painter'] : null;
01679 if (painter!=null) return userfunc(painter);
01680
01681 var pad_painter = this.pad_painter(true);
01682 if (pad_painter == null) return;
01683
01684 userfunc(pad_painter);
01685 if ('painters' in pad_painter)
01686 for (var k = 0; k < pad_painter.painters.length; ++k)
01687 userfunc(pad_painter.painters[k]);
01688 }
01689
01690 JSROOT.TObjectPainter.prototype.Cleanup = function() {
01691
01692 this.select_main().html("");
01693 }
01694
01695 JSROOT.TObjectPainter.prototype.RedrawPad = function() {
01696
01697
01698 var pad_painter = this.pad_painter(true);
01699 if (pad_painter) pad_painter.Redraw();
01700 }
01701
01702 JSROOT.TObjectPainter.prototype.SwitchTooltip = function(on) {
01703 var fp = this.frame_painter();
01704 if (fp) fp.ProcessTooltipEvent(null, on);
01705 }
01706
01707 JSROOT.TObjectPainter.prototype.AddDrag = function(callback) {
01708 if (!JSROOT.gStyle.MoveResize) return;
01709
01710 var pthis = this;
01711
01712 var rect_width = function() { return Number(pthis.draw_g.attr("width")); }
01713 var rect_height = function() { return Number(pthis.draw_g.attr("height")); }
01714
01715 var acc_x = 0, acc_y = 0, pad_w = 1, pad_h = 1, drag_tm = null;
01716
01717 function detectRightButton(event) {
01718 if ('buttons' in event) return event.buttons === 2;
01719 else if ('which' in event) return event.which === 3;
01720 else if ('button' in event) return event.button === 2;
01721 return false;
01722 }
01723
01724 var resize_corner1 = this.draw_g.select('.resize_corner1');
01725 if (resize_corner1.empty())
01726 resize_corner1 = this.draw_g
01727 .append("path")
01728 .attr('class','resize_corner1')
01729 .attr("d","M2,2 h15 v-5 h-20 v20 h5 Z");
01730
01731 var resize_corner2 = this.draw_g.select('.resize_corner2');
01732 if (resize_corner2.empty())
01733 resize_corner2 = this.draw_g
01734 .append("path")
01735 .attr('class','resize_corner2')
01736 .attr("d","M-2,-2 h-15 v5 h20 v-20 h-5 Z");
01737
01738 resize_corner1.style("opacity", "0")
01739 .style("cursor", "nw-resize");
01740
01741 resize_corner2.style("opacity", "0")
01742 .style("cursor", "se-resize")
01743 .attr("transform", "translate(" + rect_width() + "," + rect_height() + ")");
01744
01745 var drag_rect = null;
01746
01747 function complete_drag() {
01748 drag_rect.style("cursor", "auto");
01749
01750 var oldx = Number(pthis.draw_g.attr("x")),
01751 oldy = Number(pthis.draw_g.attr("y")),
01752 newx = Number(drag_rect.attr("x")),
01753 newy = Number(drag_rect.attr("y")),
01754 newwidth = Number(drag_rect.attr("width")),
01755 newheight = Number(drag_rect.attr("height"));
01756
01757 var change_size = (newwidth !== rect_width()) || (newheight !== rect_height());
01758 var change_pos = (newx !== oldx) || (newy !== oldy);
01759
01760 pthis.draw_g.attr('x', newx).attr('y', newy)
01761 .attr("transform", "translate(" + newx + "," + newy + ")")
01762 .attr('width', newwidth).attr('height', newheight);
01763
01764 drag_rect.remove();
01765 drag_rect = null;
01766
01767 pthis.SwitchTooltip(true);
01768
01769 resize_corner2.attr("transform", "translate(" + newwidth + "," + newheight + ")");
01770
01771 if (change_size || change_pos) {
01772 if (change_size && ('resize' in callback)) callback.resize(newwidth, newheight);
01773 if (change_pos && ('move' in callback)) callback.move(newx, newy, newx - oldxx, newy-oldy);
01774
01775 if (change_size || change_pos) {
01776 if ('obj' in callback) {
01777 callback.obj.fX1NDC = newx / pthis.pad_width();
01778 callback.obj.fX2NDC = (newx + newwidth) / pthis.pad_width();
01779 callback.obj.fY1NDC = 1 - (newy + newheight) / pthis.pad_height();
01780 callback.obj.fY2NDC = 1 - newy / pthis.pad_height();
01781 }
01782 if ('redraw' in callback) callback.redraw();
01783 }
01784 }
01785
01786 return change_size || change_pos;
01787 }
01788
01789 var drag_move = d3.behavior.drag().origin(Object)
01790 .on("dragstart", function() {
01791 if (detectRightButton(d3.event.sourceEvent)) return;
01792
01793 JSROOT.Painter.closeMenu();
01794
01795 pthis.SwitchTooltip(false);
01796
01797 d3.event.sourceEvent.preventDefault();
01798 d3.event.sourceEvent.stopPropagation();
01799
01800 acc_x = 0; acc_y = 0;
01801 pad_w = pthis.pad_width() - rect_width();
01802 pad_h = pthis.pad_height() - rect_height();
01803
01804 drag_tm = new Date();
01805
01806 drag_rect = d3.select(pthis.draw_g.node().parentNode).append("rect")
01807 .classed("zoom", true)
01808 .attr("x", pthis.draw_g.attr("x"))
01809 .attr("y", pthis.draw_g.attr("y"))
01810 .attr("width", rect_width())
01811 .attr("height", rect_height())
01812 .style("cursor", "move")
01813 .style("pointer-events","none");
01814 }).on("drag", function() {
01815 if (drag_rect == null) return;
01816
01817 d3.event.sourceEvent.preventDefault();
01818
01819 var x = Number(drag_rect.attr("x")), y = Number(drag_rect.attr("y"));
01820 var dx = d3.event.dx, dy = d3.event.dy;
01821
01822 if ((acc_x<0) && (dx>0)) { acc_x+=dx; dx=0; if (acc_x>0) { dx=acc_x; acc_x=0; }}
01823 if ((acc_x>0) && (dx<0)) { acc_x+=dx; dx=0; if (acc_x<0) { dx=acc_x; acc_x=0; }}
01824 if ((acc_y<0) && (dy>0)) { acc_y+=dy; dy=0; if (acc_y>0) { dy=acc_y; acc_y=0; }}
01825 if ((acc_y>0) && (dy<0)) { acc_y+=dy; dy=0; if (acc_y<0) { dy=acc_y; acc_y=0; }}
01826
01827 if (x+dx<0) { acc_x+=(x+dx); x=0; } else
01828 if (x+dx>pad_w) { acc_x+=(x+dx-pad_w); x=pad_w; } else x+=dx;
01829
01830 if (y+dy<0) { acc_y+=(y+dy); y = 0; } else
01831 if (y+dy>pad_h) { acc_y+=(y+dy-pad_h); y=pad_h; } else y+=dy;
01832
01833 drag_rect.attr("x", x).attr("y", y);
01834
01835 d3.event.sourceEvent.stopPropagation();
01836 }).on("dragend", function() {
01837 if (drag_rect==null) return;
01838
01839 d3.event.sourceEvent.preventDefault();
01840
01841 if (complete_drag() === false)
01842 if(callback['ctxmenu'] && ((new Date()).getTime() - drag_tm.getTime() > 600)) {
01843 var rrr = resize_corner2.node().getBoundingClientRect();
01844 pthis.ShowContextMenu('main', { clientX: rrr.left, clientY: rrr.top } );
01845 }
01846 });
01847
01848 var drag_resize = d3.behavior.drag().origin(Object)
01849 .on( "dragstart", function() {
01850 if (detectRightButton(d3.event.sourceEvent)) return;
01851
01852 d3.event.sourceEvent.stopPropagation();
01853 d3.event.sourceEvent.preventDefault();
01854
01855 pthis.SwitchTooltip(false);
01856
01857 acc_x = 0; acc_y = 0;
01858 pad_w = pthis.pad_width();
01859 pad_h = pthis.pad_height();
01860 drag_rect = d3.select(pthis.draw_g.node().parentNode).append("rect")
01861 .classed("zoom", true)
01862 .attr("x", pthis.draw_g.attr("x"))
01863 .attr("y", pthis.draw_g.attr("y"))
01864 .attr("width", rect_width())
01865 .attr("height", rect_height())
01866 .style("cursor", d3.select(this).style("cursor"));
01867 }).on("drag", function() {
01868 if (drag_rect == null) return;
01869
01870 d3.event.sourceEvent.preventDefault();
01871
01872 var w = Number(drag_rect.attr("width")), h = Number(drag_rect.attr("height")),
01873 x = Number(drag_rect.attr("x")), y = Number(drag_rect.attr("y"));
01874 var dx = d3.event.dx, dy = d3.event.dy;
01875 if ((acc_x<0) && (dx>0)) { acc_x+=dx; dx=0; if (acc_x>0) { dx=acc_x; acc_x=0; }}
01876 if ((acc_x>0) && (dx<0)) { acc_x+=dx; dx=0; if (acc_x<0) { dx=acc_x; acc_x=0; }}
01877 if ((acc_y<0) && (dy>0)) { acc_y+=dy; dy=0; if (acc_y>0) { dy=acc_y; acc_y=0; }}
01878 if ((acc_y>0) && (dy<0)) { acc_y+=dy; dy=0; if (acc_y<0) { dy=acc_y; acc_y=0; }}
01879
01880 if (d3.select(this).classed('resize_corner1')) {
01881 if (x+dx < 0) { acc_x += (x+dx); w += x; x = 0; } else
01882 if (w-dx < 0) { acc_x -= (w-dx); x += w; w = 0; } else { x+=dx; w-=dx; }
01883 if (y+dy < 0) { acc_y += (y+dy); h += y; y = 0; } else
01884 if (h-dy < 0) { acc_y -= (h-dy); y += h; h = 0; } else { y+=dy; h-=dy; }
01885 } else {
01886 if (x+w+dx > pad_w) { acc_x += (x+w+dx-pad_w); w = pad_w-x; } else
01887 if (w+dx < 0) { acc_x += (w+dx); w = 0; } else w += dx;
01888 if (y+h+dy > pad_h) { acc_y += (y+h+dy-pad_h); h = pad_h-y; } else
01889 if (h+dy < 0) { acc_y += (h+dy); h=0; } else h += dy;
01890 }
01891
01892 drag_rect.attr("x", x).attr("y", y).attr("width", w).attr("height", h);
01893
01894 d3.event.sourceEvent.stopPropagation();
01895 }).on( "dragend", function() {
01896 if (drag_rect == null) return;
01897
01898 d3.event.sourceEvent.preventDefault();
01899
01900 complete_drag();
01901 });
01902
01903 if (!('only_resize' in callback)) {
01904 this.draw_g.style("cursor", "move").call(drag_move);
01905 }
01906
01907 resize_corner1.call(drag_resize);
01908 resize_corner2.call(drag_resize);
01909 }
01910
01911 JSROOT.TObjectPainter.prototype.startTouchMenu = function(kind) {
01912
01913
01914 var arr = d3.touches(this.svg_frame().node());
01915 if (arr.length != 1) return;
01916
01917 if (!kind || (kind=="")) kind = "main";
01918 var fld = "touch_" + kind;
01919
01920 d3.event.preventDefault();
01921 d3.event.stopPropagation();
01922
01923 this[fld] = { dt: new Date(), pos: arr[0] };
01924
01925 this.svg_frame().on("touchcancel", this.endTouchMenu.bind(this, kind))
01926 .on("touchend", this.endTouchMenu.bind(this, kind));
01927 }
01928
01929 JSROOT.TObjectPainter.prototype.endTouchMenu = function(kind) {
01930 var fld = "touch_" + kind;
01931
01932 if (! (fld in this)) return;
01933
01934 d3.event.preventDefault();
01935 d3.event.stopPropagation();
01936
01937 var diff = new Date().getTime() - this[fld].dt.getTime();
01938
01939 this.svg_frame().on("touchcancel", null)
01940 .on("touchend", null);
01941
01942 if (diff>500) {
01943 var rect = this.svg_frame().node().getBoundingClientRect();
01944 this.ShowContextMenu(kind, { clientX: rect.left + this[fld].pos[0],
01945 clientY: rect.top + this[fld].pos[1] } );
01946 }
01947
01948 delete this[fld];
01949 }
01950
01951 JSROOT.TObjectPainter.prototype.AddColorMenuEntry = function(menu, name, value, set_func, fill_kind) {
01952 if (value === undefined) return;
01953 menu.add("sub:"+name, function() {
01954
01955 var useid = (typeof value !== 'string');
01956 var col = prompt("Enter color " + (useid ? "(only id number)" : "(name or id)"), value);
01957 if (col == null) return;
01958 var id = parseInt(col);
01959 if (!isNaN(id) && (JSROOT.Painter.root_colors[id] !== undefined)) {
01960 col = JSROOT.Painter.root_colors[id];
01961 } else {
01962 if (useid) return;
01963 }
01964 set_func.bind(this)(useid ? id : col);
01965 });
01966 var useid = (typeof value !== 'string');
01967 for (var n=-1;n<11;++n) {
01968 if ((n<0) && useid) continue;
01969 if ((n==10) && (fill_kind!==1)) continue;
01970 var col = (n<0) ? 'none' : JSROOT.Painter.root_colors[n];
01971 if ((n==0) && (fill_kind==1)) col = 'none';
01972 var svg = "<svg width='100' height='18' style='margin:0px;background-color:" + col + "'><text x='4' y='12' style='font-size:12px' fill='" + (n==1 ? "white" : "black") + "'>"+col+"</text></svg>";
01973 menu.addchk((value == (useid ? n : col)), svg, (useid ? n : col), set_func);
01974 }
01975 menu.add("endsub:");
01976 }
01977
01978 JSROOT.TObjectPainter.prototype.AddSizeMenuEntry = function(menu, name, min, max, step, value, set_func) {
01979 if (value === undefined) return;
01980
01981 menu.add("sub:"+name, function() {
01982
01983 var entry = value.toFixed(4);
01984 if (step>=0.1) entry = value.toFixed(2);
01985 if (step>=1) entry = value.toFixed(0);
01986 var val = prompt("Enter value of " + name, entry);
01987 if (val==null) return;
01988 var val = parseFloat(val);
01989 if (!isNaN(val)) set_func.bind(this)((step>=1) ? Math.round(val) : val);
01990 });
01991 for (var val=min;val<=max;val+=step) {
01992 var entry = val.toFixed(2);
01993 if (step>=0.1) entry = val.toFixed(1);
01994 if (step>=1) entry = val.toFixed(0);
01995 menu.addchk((Math.abs(value - val) < step/2), entry, val, set_func);
01996 }
01997 menu.add("endsub:");
01998 }
01999
02000
02001 JSROOT.TObjectPainter.prototype.FillAttContextMenu = function(menu, preffix) {
02002
02003
02004
02005
02006 if (!preffix) preffix = "";
02007
02008 if (this.lineatt && this.lineatt.used) {
02009 menu.add("sub:"+preffix+"Line att");
02010 this.AddSizeMenuEntry(menu, "width", 1, 10, 1, this.lineatt.width,
02011 function(arg) { this.lineatt.width = parseInt(arg); this.Redraw(); }.bind(this));
02012 this.AddColorMenuEntry(menu, "color", this.lineatt.color,
02013 function(arg) { this.lineatt.color = arg; this.Redraw(); }.bind(this));
02014 menu.add("sub:style", function() {
02015 var id = prompt("Enter line style id (1-solid)", 1);
02016 if (id == null) return;
02017 id = parseInt(id);
02018 if (isNaN(id) || (JSROOT.Painter.root_line_styles[id] === undefined)) return;
02019 this.lineatt.dash = JSROOT.Painter.root_line_styles[id];
02020 this.Redraw();
02021 }.bind(this));
02022 for (var n=1;n<11;++n) {
02023 var style = JSROOT.Painter.root_line_styles[n];
02024
02025 var svg = "<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + n + "</text><line x1='30' y1='8' x2='100' y2='8' stroke='black' stroke-width='3' stroke-dasharray='" + style + "'></line></svg>";
02026
02027 menu.addchk((this.lineatt.dash==style), svg, style, function(arg) { this.lineatt.dash = arg; this.Redraw(); }.bind(this));
02028 }
02029 menu.add("endsub:");
02030 menu.add("endsub:");
02031
02032 if (('excl_side' in this.lineatt) && (this.lineatt.excl_side!==0)) {
02033 menu.add("sub:Exclusion");
02034 menu.add("sub:side");
02035 for (var side=-1;side<=1;++side)
02036 menu.addchk((this.lineatt.excl_side==side), side, side, function(arg) {
02037 this.lineatt.excl_side = parseInt(arg);
02038 if ((this.lineatt.excl_width===0) && (this.lineatt.excl_side!=0)) this.lineatt.excl_width = 20;
02039 this.Redraw();
02040 }.bind(this));
02041 menu.add("endsub:");
02042
02043 this.AddSizeMenuEntry(menu, "width", 10, 100, 10, this.lineatt.excl_width,
02044 function(arg) { this.lineatt.excl_width = parseInt(arg); this.Redraw(); }.bind(this));
02045
02046 menu.add("endsub:");
02047 }
02048 }
02049
02050 if (this.fillatt && this.fillatt.used) {
02051 menu.add("sub:"+preffix+"Fill att");
02052 this.AddColorMenuEntry(menu, "color", this.fillatt.colorindx,
02053 function(arg) { this.fillatt.Change(parseInt(arg), undefined, this.svg_canvas()); this.Redraw(); }.bind(this), this.fillatt.kind);
02054 menu.add("sub:style", function() {
02055 var id = prompt("Enter fill style id (1001-solid, 3000..3010)", this.fillatt.pattern);
02056 if (id == null) return;
02057 id = parseInt(id);
02058 if (isNaN(id)) return;
02059 this.fillatt.Change(undefined, id, this.svg_canvas());
02060 this.Redraw();
02061 }.bind(this));
02062
02063 var supported = [1, 1001, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3010, 3021, 3022];
02064
02065 var clone = JSROOT.clone(this.fillatt);
02066 if (clone.colorindx<=0) clone.colorindx = 1;
02067
02068 for (var n=0; n<supported.length; ++n) {
02069
02070 clone.Change(undefined, supported[n], this.svg_canvas());
02071
02072 var svg = "<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() + "</text><rect x='40' y='0' width='60' height='18' stroke='none' fill='" + clone.color + "'></rect></svg>";
02073
02074 menu.addchk(this.fillatt.pattern == supported[n], svg, supported[n], function(arg) {
02075 this.fillatt.Change(undefined, parseInt(arg), this.svg_canvas());
02076 this.Redraw();
02077 }.bind(this));
02078 }
02079 menu.add("endsub:");
02080 menu.add("endsub:");
02081 }
02082
02083 if (this.markeratt && this.markeratt.used) {
02084 menu.add("sub:"+preffix+"Marker att");
02085 this.AddColorMenuEntry(menu, "color", this.markeratt.color,
02086 function(arg) { this.markeratt.Change(arg); this.Redraw(); }.bind(this));
02087 this.AddSizeMenuEntry(menu, "size", 0.5, 6, 0.5, this.markeratt.size,
02088 function(arg) { this.markeratt.Change(undefined, undefined, parseFloat(arg)); this.Redraw(); }.bind(this));
02089
02090 menu.add("sub:style");
02091 var supported = [1,2,3,4,5,6,7,8,21,22,23,24,25,26,27,28,29,30,31,32,33,34];
02092
02093 var clone = JSROOT.clone(this.markeratt);
02094 for (var n=0; n<supported.length; ++n) {
02095 clone.Change(undefined, supported[n], 1.7);
02096 clone.reset_pos();
02097 var svg = "<svg width='60' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() + "</text><path stroke='black' fill='" + (clone.fill ? "black" : "none") + "' d='" + clone.create(40,8) + "'></path></svg>";
02098
02099 menu.addchk(this.markeratt.style == supported[n], svg, supported[n],
02100 function(arg) { this.markeratt.Change(undefined, parseInt(arg)); this.Redraw(); }.bind(this));
02101 }
02102 menu.add("endsub:");
02103 menu.add("endsub:");
02104 }
02105 }
02106
02107 JSROOT.TObjectPainter.prototype.TextAttContextMenu = function(menu, prefix) {
02108
02109
02110 var obj = this.GetObject();
02111 if (!obj || !('fTextColor' in obj)) return;
02112
02113 menu.add("sub:" + (prefix ? prefix : "Text"));
02114 this.AddColorMenuEntry(menu, "color", obj.fTextColor,
02115 function(arg) { this.GetObject().fTextColor = parseInt(arg); this.Redraw(); }.bind(this));
02116
02117 var align = [11, 12, 13, 21, 22, 23, 31, 32, 33],
02118 hnames = ['left', 'centered' , 'right'],
02119 vnames = ['bottom', 'centered', 'top'];
02120
02121 menu.add("sub:align");
02122 for (var n=0; n<align.length; ++n) {
02123 menu.addchk(align[n] == obj.fTextAlign,
02124 align[n], align[n],
02125
02126 function(arg) { this.GetObject().fTextAlign = parseInt(arg); this.Redraw(); }.bind(this));
02127 }
02128 menu.add("endsub:");
02129
02130 menu.add("sub:font");
02131 for (var n=1; n<16; ++n) {
02132 menu.addchk(n == Math.floor(obj.fTextFont/10), n, n,
02133 function(arg) { this.GetObject().fTextFont = parseInt(arg)*10+2; this.Redraw(); }.bind(this));
02134 }
02135 menu.add("endsub:");
02136
02137 menu.add("endsub:");
02138 }
02139
02140
02141 JSROOT.TObjectPainter.prototype.FillContextMenu = function(menu) {
02142
02143 var title = this.GetTipName();
02144 if (this.GetObject() && ('_typename' in this.GetObject()))
02145 title = this.GetObject()._typename + "::" + title;
02146
02147 menu.add("header:"+ title);
02148
02149 this.FillAttContextMenu(menu);
02150
02151 return menu.size() > 0;
02152 }
02153
02154
02155 JSROOT.TObjectPainter.prototype.FindInPrimitives = function(objname) {
02156
02157
02158
02159 var painter = this.pad_painter(true);
02160 if ((painter === null) || (painter.pad === null)) return null;
02161
02162 if (painter.pad.fPrimitives !== null)
02163 for (var n=0;n<painter.pad.fPrimitives.arr.length;++n) {
02164 var prim = painter.pad.fPrimitives.arr[n];
02165 if (('fName' in prim) && (prim.fName === objname)) return prim;
02166 }
02167
02168 return null;
02169 }
02170
02171 JSROOT.TObjectPainter.prototype.FindPainterFor = function(selobj,selname) {
02172
02173
02174
02175
02176 var painter = this.pad_painter(true);
02177 var painters = (painter === null) ? null : painter.painters;
02178 if (painters === null) return null;
02179
02180 for (var n = 0; n < painters.length; ++n) {
02181 var pobj = painters[n].GetObject();
02182 if (pobj===null) continue;
02183
02184 if (selobj && (pobj === selobj)) return painters[n];
02185
02186 if (selname && ('fName' in pobj) && (pobj.fName == selname)) return painters[n];
02187 }
02188
02189 return null;
02190 }
02191
02192 JSROOT.TObjectPainter.prototype.ConfigureUserTooltipCallback = function(call_back, user_timeout) {
02193
02194
02195
02196
02197 if ((call_back === undefined) || (typeof call_back !== 'function')) {
02198 delete this.UserTooltipCallback;
02199 return;
02200 }
02201
02202 if (user_timeout===undefined) user_timeout = 500;
02203
02204 this.UserTooltipCallback = call_back;
02205 this.UserTooltipTimeout = user_timeout;
02206 }
02207
02208 JSROOT.TObjectPainter.prototype.IsUserTooltipCallback = function() {
02209 return typeof this.UserTooltipCallback == 'function';
02210 }
02211
02212 JSROOT.TObjectPainter.prototype.ProvideUserTooltip = function(data) {
02213
02214 if (!this.IsUserTooltipCallback()) return;
02215
02216 if (this.UserTooltipTimeout <= 0)
02217 return this.UserTooltipCallback(data);
02218
02219 if (typeof this.UserTooltipTHandle != 'undefined') {
02220 clearTimeout(this.UserTooltipTHandle);
02221 delete this.UserTooltipTHandle;
02222 }
02223
02224 if (data==null)
02225 return this.UserTooltipCallback(data);
02226
02227 this.UserTooltipTHandle = setTimeout(function(d) {
02228
02229 delete this.UserTooltipTHandle;
02230 this.UserTooltipCallback(d);
02231 }.bind(this, data), this.UserTooltipTimeout);
02232 }
02233
02234 JSROOT.TObjectPainter.prototype.Redraw = function() {
02235
02236
02237
02238 }
02239
02240 JSROOT.TObjectPainter.prototype.StartTextDrawing = function(font_face, font_size, draw_g) {
02241
02242
02243 if (!draw_g) draw_g = this.draw_g;
02244
02245 var font = JSROOT.Painter.getFontDetails(font_face, font_size);
02246
02247 draw_g.call(font.func);
02248
02249 draw_g.property('text_font', font);
02250 draw_g.property('mathjax_use', false);
02251 draw_g.property('text_factor', 0.);
02252 draw_g.property('max_text_width', 0);
02253 }
02254
02255 JSROOT.TObjectPainter.prototype.TextScaleFactor = function(value, draw_g) {
02256
02257 if (!draw_g) draw_g = this.draw_g;
02258 if (value && (value > draw_g.property('text_factor'))) draw_g.property('text_factor', value);
02259 }
02260
02261 JSROOT.TObjectPainter.prototype.GetBoundarySizes = function(elem) {
02262
02263
02264
02265
02266 if (elem===null) { console.warn('empty node in GetBoundarySizes'); return { width:0, height:0 }; }
02267 var box = elem.getBoundingClientRect();
02268 if (parseInt(box.width) > 0) box = elem.getBBox();
02269 var res = { width : parseInt(box.width), height : parseInt(box.height) };
02270 if ('left' in box) { res.x = parseInt(box.left); res.y = parseInt(box.right); } else
02271 if ('x' in box) { res.x = parseInt(box.x); res.y = parseInt(box.y); }
02272 return res;
02273 }
02274
02275 JSROOT.TObjectPainter.prototype.FinishTextDrawing = function(draw_g, call_ready) {
02276 if (!draw_g) draw_g = this.draw_g;
02277 var pthis = this;
02278
02279 var svgs = null;
02280
02281 if (draw_g.property('mathjax_use')) {
02282 draw_g.property('mathjax_use', false);
02283
02284 var missing = false;
02285 svgs = draw_g.selectAll(".math_svg");
02286
02287 svgs.each(function() {
02288 var fo_g = d3.select(this);
02289 if (fo_g.node().parentNode !== draw_g.node()) return;
02290 var entry = fo_g.property('_element');
02291 if (d3.select(entry).select("svg").empty()) missing = true;
02292 });
02293
02294
02295 if (missing) {
02296 JSROOT.AssertPrerequisites('mathjax', function() {
02297 if (typeof MathJax == 'object')
02298 MathJax.Hub.Queue(["FinishTextDrawing", pthis, draw_g, call_ready]);
02299 });
02300 return null;
02301 }
02302 }
02303
02304 if (svgs==null) svgs = draw_g.selectAll(".math_svg");
02305
02306 var painter = this, svg_factor = 0.;
02307
02308
02309 var f = draw_g.property('text_factor');
02310 if ((f>0) && ((f<0.9) || (f>1.))) {
02311 var font = draw_g.property('text_font');
02312 font.size = Math.floor(font.size/f);
02313 draw_g.call(font.func);
02314 }
02315
02316
02317 svgs.each(function() {
02318 var fo_g = d3.select(this);
02319 if (fo_g.node().parentNode !== draw_g.node()) return;
02320 var entry = fo_g.property('_element'),
02321 rotate = fo_g.property('_rotate');
02322
02323 fo_g.property('_element', null);
02324
02325 var vvv = d3.select(entry).select("svg");
02326 if (vvv.empty()) {
02327 JSROOT.console('MathJax SVG ouptut error');
02328 return;
02329 }
02330
02331 vvv.remove();
02332 document.body.removeChild(entry);
02333
02334 fo_g.append(function() { return vvv.node(); });
02335
02336 if (fo_g.property('_scale')) {
02337 var box = painter.GetBoundarySizes(fo_g.node());
02338 svg_factor = Math.max(svg_factor, 1.05*box.width / fo_g.property('_width'),
02339 1.05*box.height / fo_g.property('_height'));
02340 }
02341 });
02342
02343 svgs.each(function() {
02344 var fo_g = d3.select(this);
02345
02346 if (fo_g.node().parentNode !== draw_g.node()) return;
02347
02348 if (svg_factor > 0.) {
02349 var m = fo_g.select("svg");
02350 var mw = m.attr("width"), mh = m.attr("height");
02351 if ((typeof mw == 'string') && (typeof mh == 'string') && (mw.indexOf("ex") > 0) && (mh.indexOf("ex") > 0)) {
02352 mw = parseFloat(mw.substr(0,mw.length-2));
02353 mh = parseFloat(mh.substr(0,mh.length-2));
02354 if ((mw>0) && (mh>0)) {
02355 m.attr("width", (mw/svg_factor).toFixed(2)+"ex");
02356 m.attr("height", (mh/svg_factor).toFixed(2)+"ex");
02357 }
02358 } else {
02359 JSROOT.console('Fail to downscale MathJax output');
02360 }
02361 }
02362
02363 var box = painter.GetBoundarySizes(fo_g.node()),
02364 align = fo_g.property('_align'),
02365 rotate = fo_g.property('_rotate'),
02366 fo_w = fo_g.property('_width'),
02367 fo_h = fo_g.property('_height'),
02368 tr = { x: fo_g.property('_x'), y: fo_g.property('_y') };
02369
02370 var sign = { x:1, y:1 }, nx = "x", ny = "y";
02371 if (rotate == 180) { sign.x = sign.y = -1; } else
02372 if ((rotate == 270) || (rotate == 90)) {
02373 sign.x = (rotate===270) ? -1 : 1;
02374 sign.y = -sign.x;
02375 nx = "y"; ny = "x";
02376 }
02377
02378 if (!fo_g.property('_scale')) fo_w = fo_h = 0;
02379
02380 if (align[0] == 'middle') tr[nx] += sign.x*(fo_w - box.width)/2; else
02381 if (align[0] == 'end') tr[nx] += sign.x*(fo_w - box.width);
02382
02383 if (align[1] == 'middle') tr[ny] += sign.y*(fo_h - box.height)/2; else
02384 if (align[1] == 'bottom') tr[ny] += sign.y*(fo_h - box.height);
02385
02386 var trans = "translate("+tr.x+","+tr.y+")";
02387 if (rotate!==0) trans += " rotate("+rotate+",0,0)";
02388
02389 fo_g.attr('transform', trans).attr('visibility', null);
02390 });
02391
02392
02393 draw_g.selectAll('.hidden_text').attr('opacity', '1').classed('hidden_text',false);
02394
02395
02396 JSROOT.CallBack(call_ready);
02397
02398 return draw_g.property('max_text_width');
02399 }
02400
02401 JSROOT.TObjectPainter.prototype.DrawText = function(align_arg, x, y, w, h, label, tcolor, latex_kind, draw_g) {
02402
02403 if (!draw_g) draw_g = this.draw_g;
02404 var align;
02405
02406 if (typeof align_arg == 'string') {
02407 align = align_arg.split(";");
02408 if (align.length==1) align.push('middle');
02409 } else {
02410 align = ['start', 'middle'];
02411 if ((align_arg / 10) >= 3) align[0] = 'end'; else
02412 if ((align_arg / 10) >= 2) align[0] = 'middle';
02413 if ((align_arg % 10) == 0) align[1] = 'bottom'; else
02414 if ((align_arg % 10) == 1) align[1] = 'bottom'; else
02415 if ((align_arg % 10) == 3) align[1] = 'top';
02416 }
02417
02418 var scale = (w>0) && (h>0);
02419
02420 if (latex_kind==null) latex_kind = 1;
02421 if (latex_kind<2)
02422 if (!JSROOT.Painter.isAnyLatex(label)) latex_kind = 0;
02423
02424 var use_normal_text = ((JSROOT.gStyle.MathJax<1) && (latex_kind!==2)) || (latex_kind<1);
02425
02426
02427
02428
02429 if (use_normal_text) {
02430 if (latex_kind>0) label = JSROOT.Painter.translateLaTeX(label);
02431
02432 var pos_x = x.toFixed(1), pos_y = y.toFixed(1), pos_dy = null, middleline = false;
02433
02434 if (w>0) {
02435
02436 if (align[0]=="middle") pos_x = (x+w*0.5).toFixed(1); else
02437 if (align[0]=="end") pos_x = (x+w).toFixed(1);
02438 }
02439
02440 if (h>0) {
02441 if (align[1] == 'bottom') pos_y = (y + h).toFixed(1); else
02442 if (align[1] == 'top') pos_dy = ".8em"; else {
02443 pos_y = (y + h/2).toFixed(1);
02444 if (JSROOT.browser.isIE) pos_dy = ".4em"; else middleline = true;
02445 }
02446 } else {
02447 if (align[1] == 'top') pos_dy = ".8em"; else
02448 if (align[1] == 'middle') {
02449 if (JSROOT.browser.isIE) pos_dy = ".4em"; else middleline = true;
02450 }
02451 }
02452
02453
02454 var trans = "translate("+pos_x+","+pos_y+")";
02455 if (!scale && (h<0)) trans += " rotate("+(-h)+",0,0)";
02456
02457 var txt = draw_g.append("text")
02458 .attr("text-anchor", align[0])
02459 .attr("x", 0)
02460 .attr("y", 0)
02461 .attr("fill", tcolor ? tcolor : null)
02462 .attr("transform", trans)
02463 .text(label)
02464 if (pos_dy!=null) txt.attr("dy", pos_dy);
02465 if (middleline) txt.attr("dominant-baseline", "middle");
02466
02467 var box = this.GetBoundarySizes(txt.node());
02468
02469 if (scale) txt.classed('hidden_text',true).attr('opacity','0');
02470
02471 if (box.width > draw_g.property('max_text_width')) draw_g.property('max_text_width', box.width);
02472 if ((w>0) && scale) this.TextScaleFactor(1.05*box.width / w, draw_g);
02473 if ((h>0) && scale) this.TextScaleFactor(1.*box.height / h, draw_g);
02474
02475 return box.width;
02476 }
02477
02478 w = Math.round(w); h = Math.round(h);
02479 x = Math.round(x); y = Math.round(y);
02480
02481 var rotate = 0;
02482
02483 if (!scale && h<0) { rotate = Math.abs(h); h = 0; }
02484
02485 var fo_g = draw_g.append("svg:g")
02486 .attr('class', 'math_svg')
02487 .attr('visibility','hidden')
02488 .property('_x',x)
02489 .property('_y',y)
02490 .property('_width',w)
02491 .property('_height',h)
02492 .property('_scale', scale)
02493 .property('_rotate', rotate)
02494 .property('_align', align);
02495
02496 var element = document.createElement("div");
02497 d3.select(element).style("visibility", "hidden")
02498 .style("overflow", "hidden")
02499 .style("position", "absolute")
02500 .html(JSROOT.Painter.translateMath(label, latex_kind, tcolor));
02501 document.body.appendChild(element);
02502
02503 draw_g.property('mathjax_use', true);
02504 fo_g.property('_element', element);
02505
02506 JSROOT.AssertPrerequisites('mathjax', function() {
02507 if (typeof MathJax == 'object')
02508 MathJax.Hub.Queue(["Typeset", MathJax.Hub, element]);
02509 });
02510
02511 return 0;
02512 }
02513
02514
02515
02516 JSROOT.TFramePainter = function(tframe) {
02517 JSROOT.TObjectPainter.call(this, tframe);
02518 this.tooltip_enabled = true;
02519 }
02520
02521 JSROOT.TFramePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
02522
02523 JSROOT.TFramePainter.prototype.Shrink = function(shrink_left, shrink_right) {
02524 this.fX1NDC += shrink_left;
02525 this.fX2NDC -= shrink_right;
02526 }
02527
02528 JSROOT.TFramePainter.prototype.Redraw = function() {
02529
02530 var width = this.pad_width(),
02531 height = this.pad_height(),
02532 tframe = this.GetObject(),
02533 root_pad = this.root_pad(),
02534 framecolor = this.createAttFill(null, 1001, 0),
02535 lineatt = JSROOT.Painter.createAttLine('black'),
02536 bordermode = 0, bordersize = 0,
02537 has_ndc = ('fX1NDC' in this);
02538
02539 if (!has_ndc) {
02540 if (root_pad === null)
02541 JSROOT.extend(this, JSROOT.gStyle.FrameNDC);
02542 else
02543 JSROOT.extend(this, {
02544 fX1NDC: root_pad.fLeftMargin,
02545 fX2NDC: 1 - root_pad.fRightMargin,
02546 fY1NDC: root_pad.fTopMargin,
02547 fY2NDC: 1 - root_pad.fBottomMargin
02548 });
02549 }
02550
02551 if (tframe !== null) {
02552 bordermode = tframe.fBorderMode;
02553 bordersize = tframe.fBorderSize;
02554 lineatt = JSROOT.Painter.createAttLine(tframe);
02555 framecolor = this.createAttFill(tframe);
02556 if (!has_ndc && (root_pad !== null)) {
02557 var xspan = width / Math.abs(root_pad.fX2 - root_pad.fX1),
02558 yspan = height / Math.abs(root_pad.fY2 - root_pad.fY1),
02559 px1 = (tframe.fX1 - root_pad.fX1) * xspan,
02560 py1 = (tframe.fY1 - root_pad.fY1) * yspan,
02561 px2 = (tframe.fX2 - root_pad.fX1) * xspan,
02562 py2 = (tframe.fY2 - root_pad.fY1) * yspan,
02563 pxl, pxt, pyl, pyt;
02564 if (px1 < px2) { pxl = px1; pxt = px2; }
02565 else { pxl = px2; pxt = px1; }
02566 if (py1 < py2) { pyl = py1; pyt = py2; }
02567 else { pyl = py2; pyt = py1; }
02568 this.fX1NDC = pxl / width;
02569 this.fY1NDC = pyl / height;
02570 this.fX2NDC = pxt / width;
02571 this.fY2NDC = pyt / height;
02572 }
02573 } else {
02574 if (root_pad)
02575 framecolor = this.createAttFill(null, root_pad.fFrameFillStyle, root_pad.fFrameFillColor);
02576 }
02577
02578
02579 if (framecolor.color == 'none') framecolor.color = 'white';
02580
02581 if (this.fillatt === undefined) this.fillatt = framecolor;
02582 if (this.lineatt === undefined) this.lineatt = lineatt;
02583
02584 var lm = Math.round(width * this.fX1NDC),
02585 w = Math.round(width * (this.fX2NDC - this.fX1NDC)),
02586 tm = Math.round(height * (1 - this.fY2NDC)),
02587 h = Math.round(height * (this.fY2NDC - this.fY1NDC));
02588
02589
02590
02591 this.draw_g = this.svg_frame();
02592 if (this.draw_g.empty())
02593 return console.error('did not found frame layer');
02594
02595 var top_rect = this.draw_g.select("rect"),
02596 main_svg = this.draw_g.select(".main_layer");
02597
02598 if (main_svg.empty()) {
02599 this.draw_g.append("svg:title").text("");
02600
02601 top_rect = this.draw_g.append("svg:rect");
02602
02603
02604 this.draw_g.append('svg:g').attr('class','grid_layer');
02605
02606 main_svg = this.draw_g.append('svg:svg')
02607 .attr('class','main_layer')
02608 .attr("x", 0)
02609 .attr("y", 0)
02610 .attr('overflow', 'hidden');
02611
02612 this.draw_g.append('svg:g').attr('class','axis_layer');
02613 this.draw_g.append('svg:g').attr('class','upper_layer');
02614 }
02615
02616
02617 this.draw_g.property('frame_painter', this);
02618
02619 this.draw_g.attr("x", lm)
02620 .attr("y", tm)
02621 .attr("width", w)
02622 .attr("height", h)
02623 .property('draw_x', lm)
02624 .property('draw_y', tm)
02625 .property('draw_width', w)
02626 .property('draw_height', h)
02627 .attr("transform", "translate(" + lm + "," + tm + ")");
02628
02629 top_rect.attr("x", 0)
02630 .attr("y", 0)
02631 .attr("width", w)
02632 .attr("height", h)
02633 .call(this.fillatt.func)
02634 .call(this.lineatt.func);
02635
02636 main_svg.attr("width", w)
02637 .attr("height", h)
02638 .attr("viewBox", "0 0 " + w + " " + h);
02639
02640 this.AddDrag({ obj: this, only_resize: true, redraw: this.RedrawPad.bind(this) });
02641
02642 var tooltip_rect = this.draw_g.select(".interactive_rect");
02643
02644 if (JSROOT.gStyle.Tooltip === 0)
02645 return tooltip_rect.remove();
02646
02647 var painter = this;
02648
02649 function MouseMoveEvent() {
02650 var pnt = d3.mouse(tooltip_rect.node());
02651 painter.ProcessTooltipEvent({ x: pnt[0], y: pnt[1], touch: false });
02652 }
02653
02654 function MouseCloseEvent() {
02655 painter.ProcessTooltipEvent(null);
02656 }
02657
02658 function TouchMoveEvent() {
02659 var pnt = d3.touches(tooltip_rect.node());
02660 if (!pnt || pnt.length !== 1) return painter.ProcessTooltipEvent(null);
02661 painter.ProcessTooltipEvent({ x: pnt[0][0], y: pnt[0][1], touch: true });
02662 }
02663
02664 function TouchCloseEvent() {
02665 painter.ProcessTooltipEvent(null);
02666 }
02667
02668 if (tooltip_rect.empty()) {
02669 tooltip_rect =
02670 this.draw_g
02671 .append("rect")
02672 .attr("class","interactive_rect")
02673 .style("opacity","0")
02674 .style("fill","none")
02675 .style("pointer-events", "visibleFill")
02676 .on('mouseenter', MouseMoveEvent)
02677 .on('mousemove', MouseMoveEvent)
02678 .on('mouseleave', MouseCloseEvent);
02679
02680 if (JSROOT.touches)
02681 tooltip_rect.on("touchstart", TouchMoveEvent)
02682 .on("touchmove", TouchMoveEvent)
02683 .on("touchend", TouchCloseEvent)
02684 .on("touchcancel", TouchCloseEvent);
02685 }
02686
02687 tooltip_rect.attr("x", 0)
02688 .attr("y", 0)
02689 .attr("width", w)
02690 .attr("height", h);
02691
02692 var hintsg = this.svg_layer("stat_layer").select(".objects_hints");
02693
02694 if (!hintsg.empty() && (JSROOT.gStyle.Tooltip > 0))
02695 setTimeout(this.ProcessTooltipEvent.bind(this, hintsg.property('last_point')), 10);
02696 }
02697
02698
02699 JSROOT.TFramePainter.prototype.FillContextMenu = function(menu) {
02700
02701
02702
02703 var main = this.main_painter(), alone = menu.size()==0;
02704
02705 if (alone)
02706 menu.add("header:Frame");
02707 else
02708 menu.add("separator");
02709
02710 if (main) {
02711 if (main.zoom_xmin !== main.zoom_xmax)
02712 menu.add("Unzoom X", main.Unzoom.bind(main,"x"));
02713 if (main.zoom_ymin !== main.zoom_ymax)
02714 menu.add("Unzoom Y", main.Unzoom.bind(main,"y"));
02715 if (main.zoom_zmin !== main.zoom_zmax)
02716 menu.add("Unzoom Z", main.Unzoom.bind(main,"z"));
02717 menu.add("Unzoom all", main.Unzoom.bind(main,"xyz"));
02718
02719 if (main.options) {
02720 menu.addchk(main.options.Logx, "SetLogx", main.ToggleLog.bind(main,"x"));
02721
02722 menu.addchk(main.options.Logy, "SetLogy", main.ToggleLog.bind(main,"y"));
02723
02724 if (main.Dimension() == 2)
02725 menu.addchk(main.options.Logz, "SetLogz", main.ToggleLog.bind(main,"z"));
02726 }
02727 menu.add("separator");
02728 }
02729
02730 menu.addchk(this.tooltip_enabled, "Show tooltips", function() {
02731 this.tooltip_enabled = !this.tooltip_enabled;
02732 }.bind(this));
02733 this.FillAttContextMenu(menu,alone ? "" : "Frame ");
02734 menu.add("separator");
02735 menu.add("Save as frame.png", function(arg) {
02736 var top = this.svg_frame();
02737 if (!top.empty())
02738 JSROOT.AssertPrerequisites("savepng", function() {
02739 saveSvgAsPng(top.node(), "frame.png");
02740 });
02741 }.bind(this));
02742
02743 return true;
02744 }
02745
02746
02747 JSROOT.TFramePainter.prototype.IsTooltipShown = function() {
02748
02749 if (JSROOT.gStyle.Tooltip < 1) return false;
02750 return ! (this.svg_layer("stat_layer").select(".objects_hints").empty());
02751 }
02752
02753 JSROOT.TFramePainter.prototype.ProcessTooltipEvent = function(pnt, enabled) {
02754
02755 if (enabled !== undefined) this.tooltip_enabled = enabled;
02756
02757 if ((pnt === undefined) || (JSROOT.gStyle.Tooltip < 1) || !this.tooltip_enabled) pnt = null;
02758
02759 var hints = [], nhints = 0, maxlen = 0, lastcolor1 = 0, usecolor1 = false,
02760 textheight = 11, hmargin = 3, wmargin = 3, hstep = 1.2,
02761 height = this.frame_height(),
02762 width = this.frame_width(),
02763 pp = this.pad_painter(true);
02764
02765
02766 if (pp!==null) hints = pp.GetTooltips(pnt);
02767
02768 if (pnt && pnt.touch) textheight = 15;
02769
02770 hints.forEach(function(hint) {
02771 if (hint === null) return;
02772
02773 nhints++;
02774
02775 for (var l=0;l<hint.lines.length;++l)
02776 maxlen = Math.max(maxlen, hint.lines[l].length);
02777
02778 hint.height = hint.lines.length*textheight*hstep + 2*hmargin - textheight*(hstep-1);
02779
02780 if ((hint.color1!== undefined) && (hint.color1!=='none')) {
02781 if ((lastcolor1!==0) && (lastcolor1 !== hint.color1)) usecolor1 = true;
02782 lastcolor1 = hint.color1;
02783 }
02784 });
02785
02786 var layer = this.svg_layer("stat_layer"),
02787 hintsg = layer.select(".objects_hints");
02788
02789
02790 if ((pnt === null) || (hints.length===0) || (maxlen===0)) {
02791 hintsg.remove();
02792 return;
02793 }
02794
02795
02796
02797
02798 if (hintsg.empty())
02799 hintsg = layer.append("svg:g")
02800 .attr("class", "objects_hints")
02801 .style("pointer-events","none");
02802
02803
02804 hintsg.attr("transform", this.draw_g.attr("transform"));
02805
02806 hintsg.property("last_point", pnt);
02807
02808 var viewmode = hintsg.property('viewmode');
02809 if (viewmode === undefined) viewmode = "";
02810
02811 var actualw = 0, posx = pnt.x + 15;
02812
02813 if (nhints > 1) {
02814
02815
02816 var bleft = 0.5, bright = 0.5;
02817
02818 if (viewmode=="left") bright = 0.7; else
02819 if (viewmode=="right") bleft = 0.3;
02820
02821 if (pnt.x <= bleft*width) {
02822 viewmode = "left";
02823 posx = 20;
02824 } else
02825 if (pnt.x >= bright*width) {
02826 viewmode = "right";
02827 posx = width - 100;
02828 } else {
02829 posx = hintsg.property('startx');
02830 }
02831 } else {
02832 viewmode = "single";
02833 }
02834
02835 if (viewmode !== hintsg.property('viewmode')) {
02836 hintsg.property('viewmode', viewmode);
02837 hintsg.selectAll("*").remove();
02838 }
02839
02840 var font = JSROOT.Painter.getFontDetails(160, textheight);
02841
02842 var curry = 10;
02843
02844 for (var n=0; n < hints.length; ++n) {
02845 var hint = hints[n];
02846 var group = hintsg.select(".painter_hint_"+n);
02847 if (hint===null) {
02848 group.remove();
02849 continue;
02850 }
02851
02852 var was_empty = group.empty();
02853
02854 if (was_empty)
02855 group = hintsg.append("svg:svg")
02856 .attr("class", "painter_hint_"+n)
02857 .style('overflow','hidden')
02858 .attr("opacity","0")
02859 .style("pointer-events","none");
02860
02861 if (viewmode == "single")
02862 curry = pnt.touch ? pnt.y - hints[n].height - 5 : pnt.y + 15;
02863
02864 group.attr("x", posx)
02865 .attr("y", curry);
02866
02867 curry += hints[n].height + 5;
02868
02869 if (!was_empty)
02870 group.selectAll("*").remove();
02871
02872 group.attr("width", 100)
02873 .attr("height", hint.height);
02874
02875 var r = group.append("rect")
02876 .attr("x",0)
02877 .attr("y",0)
02878 .attr("width", 100)
02879 .attr("height", hint.height)
02880 .attr("fill","lightgrey")
02881 .style("pointer-events","none");
02882
02883 if (nhints > 1) {
02884 var col = usecolor1 ? hint.color1 : hint.color2;
02885 if ((col !== undefined) && (col!=='none'))
02886 r.attr("stroke", col).attr("stroke-width", hint.exact ? 3 : 1);
02887 }
02888
02889 if (hint.lines != null) {
02890 for (var l=0;l<hint.lines.length;l++)
02891 if (hint.lines[l]!==null) {
02892 var txt = group.append("svg:text")
02893 .attr("text-anchor", "start")
02894 .attr("x", wmargin)
02895 .attr("y", hmargin + l*textheight*hstep)
02896 .attr("dy", ".8em")
02897 .attr("fill","black")
02898 .style("pointer-events","none")
02899 .call(font.func)
02900 .text(hint.lines[l]);
02901
02902 var box = this.GetBoundarySizes(txt.node());
02903
02904 actualw = Math.max(actualw, box.width);
02905 }
02906 }
02907
02908 function translateFn() {
02909
02910
02911 return function(d, i, a) {
02912 return function(t) {
02913 return t < 0.8 ? "0" : (t-0.8)*5;
02914 };
02915 };
02916 }
02917
02918 if (was_empty)
02919 group.transition().duration(500).attrTween("opacity", translateFn());
02920 }
02921
02922 actualw += 2*wmargin;
02923
02924 if ((viewmode == "right") && (posx + actualw > width)) {
02925 posx = width - actualw - 20;
02926 hintsg.selectAll("svg").attr("x", posx);
02927 }
02928
02929 if (actualw > 10)
02930 hintsg.selectAll("svg").attr("width", actualw)
02931 .select('rect').attr("width", actualw);
02932
02933 hintsg.property('startx', posx);
02934 }
02935
02936 JSROOT.Painter.drawFrame = function(divid, obj) {
02937 var p = new JSROOT.TFramePainter(obj);
02938 p.SetDivId(divid, 2);
02939 p.Redraw();
02940 return p.DrawingReady();
02941 }
02942
02943
02944
02945
02946 JSROOT.TPavePainter = function(pave) {
02947 JSROOT.TObjectPainter.call(this, pave);
02948 this.Enabled = true;
02949 this.UseContextMenu = true;
02950 this.UseTextColor = false;
02951 }
02952
02953 JSROOT.TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
02954
02955 JSROOT.TPavePainter.prototype.DrawPave = function(refill) {
02956
02957
02958 this.UseTextColor = false;
02959
02960 if (!this.Enabled)
02961 return this.RemoveDrawG();
02962
02963 var pt = this.GetObject();
02964
02965 if (pt.fInit===0) {
02966 pt.fInit = 1;
02967 var pad = this.root_pad();
02968 if (pt.fOption.indexOf("NDC")>=0) {
02969 pt.fX1NDC = pt.fX1; pt.fX2NDC = pt.fX2;
02970 pt.fY1NDC = pt.fY1; pt.fY2NDC = pt.fY2;
02971 } else
02972 if (pad !== null) {
02973 if (pad.fLogx) {
02974 if (pt.fX1 > 0) pt.fX1 = JSROOT.log10(pt.fX1);
02975 if (pt.fX2 > 0) pt.fX2 = JSROOT.log10(pt.fX2);
02976 }
02977 if (pad.fLogy) {
02978 if (pt.fY1 > 0) pt.fY1 = JSROOT.log10(pt.fY1);
02979 if (pt.fY2 > 0) pt.fY2 = JSROOT.log10(pt.fY2);
02980 }
02981 pt.fX1NDC = (pt.fX1-pad.fX1) / (pad.fX2 - pad.fX1);
02982 pt.fY1NDC = (pt.fY1-pad.fY1) / (pad.fY2 - pad.fY1);
02983 pt.fX2NDC = (pt.fX2-pad.fX1) / (pad.fX2 - pad.fX1);
02984 pt.fY2NDC = (pt.fY2-pad.fY1) / (pad.fY2 - pad.fY1);
02985 } else {
02986 pt.fX1NDC = pt.fY1NDC = 0.1;
02987 pt.fX2NDC = pt.fY2NDC = 0.9;
02988 }
02989 }
02990
02991 var pos_x = Math.round(pt.fX1NDC * this.pad_width()),
02992 pos_y = Math.round((1.0 - pt.fY2NDC) * this.pad_height()),
02993 width = Math.round((pt.fX2NDC - pt.fX1NDC) * this.pad_width()),
02994 height = Math.round((pt.fY2NDC - pt.fY1NDC) * this.pad_height()),
02995 lwidth = pt.fBorderSize;
02996
02997
02998 this.RecreateDrawG(true, this.IsStats() ? "stat_layer" : "text_layer");
02999
03000
03001 this.draw_g
03002 .attr("x", pos_x)
03003 .attr("y", pos_y)
03004 .attr("width", width)
03005 .attr("height", height)
03006 .attr("transform", "translate(" + pos_x + "," + pos_y + ")");
03007
03008
03009 if ((lwidth > 1) && (pt.fShadowColor > 0))
03010 this.draw_g.append("svg:path")
03011 .attr("d","M" + width + "," + height +
03012 " v" + (-height + lwidth) + " h" + lwidth +
03013 " v" + height + " h" + (-width) +
03014 " v" + (-lwidth) + " Z")
03015 .style("fill", JSROOT.Painter.root_colors[pt.fShadowColor])
03016 .style("stroke", JSROOT.Painter.root_colors[pt.fShadowColor])
03017 .style("stroke-width", "1px");
03018
03019 if (this.lineatt === undefined)
03020 this.lineatt = JSROOT.Painter.createAttLine(pt, lwidth>0 ? 1 : 0);
03021 if (this.fillatt === undefined)
03022 this.fillatt = this.createAttFill(pt);
03023
03024 this.draw_g.append("rect")
03025 .attr("x", 0)
03026 .attr("y", 0)
03027 .attr("width", width)
03028 .attr("height", height)
03029 .style("pointer-events", "visibleFill")
03030 .call(this.fillatt.func)
03031 .call(this.lineatt.func);
03032
03033 if ('PaveDrawFunc' in this)
03034 this.PaveDrawFunc(width, height, refill);
03035
03036 this.AddDrag({ obj: pt, redraw: this.DrawPave.bind(this), ctxmenu: JSROOT.touches && JSROOT.gStyle.ContextMenu && this.UseContextMenu });
03037
03038 if (this.UseContextMenu && JSROOT.gStyle.ContextMenu)
03039 this.draw_g.on("contextmenu", this.ShowContextMenu.bind(this) );
03040 }
03041
03042 JSROOT.TPavePainter.prototype.DrawPaveLabel = function(width, height) {
03043 this.UseTextColor = true;
03044
03045 var pave = this.GetObject();
03046
03047 this.StartTextDrawing(pave.fTextFont, height/1.2);
03048
03049 this.DrawText(pave.fTextAlign, 0, 0, width, height, pave.fLabel, JSROOT.Painter.root_colors[pave.fTextColor]);
03050
03051 this.FinishTextDrawing();
03052 }
03053
03054 JSROOT.TPavePainter.prototype.DrawPaveText = function(width, height, refill) {
03055
03056 if (refill && this.IsStats()) this.FillStatistic();
03057
03058 var pt = this.GetObject(),
03059 tcolor = JSROOT.Painter.root_colors[pt.fTextColor],
03060 lwidth = pt.fBorderSize,
03061 first_stat = 0,
03062 num_cols = 0,
03063 nlines = pt.fLines.arr.length,
03064 lines = [],
03065 maxlen = 0;
03066
03067
03068 for (var j = 0; j < nlines; ++j) {
03069 var line = pt.fLines.arr[j].fTitle;
03070 lines.push(line);
03071 if (j>0) maxlen = Math.max(maxlen, line.length);
03072 if (!this.IsStats() || (j == 0) || (line.indexOf('|') < 0)) continue;
03073 if (first_stat === 0) first_stat = j;
03074 var parts = line.split("|");
03075 if (parts.length > num_cols)
03076 num_cols = parts.length;
03077 }
03078
03079
03080 var stepy = height / nlines, has_head = false, margin_x = pt.fMargin * width;
03081
03082 this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2));
03083
03084 if (nlines == 1) {
03085 this.DrawText(pt.fTextAlign, 0, 0, width, height, lines[0], tcolor);
03086 this.UseTextColor = true;
03087 } else {
03088 for (var j = 0; j < nlines; ++j) {
03089 var posy = j*stepy,
03090 jcolor = JSROOT.Painter.root_colors[pt.fLines.arr[j].fTextColor];
03091 if ((pt.fLines.arr[j].fTextColor == 0) || (jcolor===undefined)) {
03092 jcolor = tcolor;
03093 this.UseTextColor = true;
03094 }
03095
03096 if (this.IsStats()) {
03097 if ((first_stat > 0) && (j >= first_stat)) {
03098 var parts = lines[j].split("|");
03099 for (var n = 0; n < parts.length; ++n)
03100 this.DrawText("middle",
03101 width * n / num_cols, posy,
03102 width/num_cols, stepy, parts[n], jcolor);
03103 } else if (lines[j].indexOf('=') < 0) {
03104 if (j==0) {
03105 has_head = true;
03106 if (lines[j].length > maxlen + 5)
03107 lines[j] = lines[j].substr(0,maxlen+2) + "...";
03108 }
03109 this.DrawText((j == 0) ? "middle" : "start",
03110 margin_x, posy, width-2*margin_x, stepy, lines[j], jcolor);
03111 } else {
03112 var parts = lines[j].split("="), sumw = 0;
03113 for (var n = 0; n < 2; ++n)
03114 sumw += this.DrawText((n == 0) ? "start" : "end",
03115 margin_x, posy, width-2*margin_x, stepy, parts[n], jcolor);
03116 this.TextScaleFactor(1.05*sumw/(width-2*margin_x), this.draw_g);
03117 }
03118 } else {
03119 this.DrawText(pt.fTextAlign, margin_x, posy, width-2*margin_x, stepy, lines[j], jcolor);
03120 }
03121 }
03122 }
03123
03124 var maxtw = this.FinishTextDrawing();
03125
03126 if ((lwidth > 0) && has_head) {
03127 this.draw_g.append("svg:line")
03128 .attr("x1", 0)
03129 .attr("y1", stepy.toFixed(1))
03130 .attr("x2", width)
03131 .attr("y2", stepy.toFixed(1))
03132 .call(this.lineatt.func);
03133 }
03134
03135 if ((first_stat > 0) && (num_cols > 1)) {
03136 for (var nrow = first_stat; nrow < nlines; ++nrow)
03137 this.draw_g.append("svg:line")
03138 .attr("x1", 0)
03139 .attr("y1", (nrow * stepy).toFixed(1))
03140 .attr("x2", width)
03141 .attr("y2", (nrow * stepy).toFixed(1))
03142 .call(this.lineatt.func);
03143
03144 for (var ncol = 0; ncol < num_cols - 1; ++ncol)
03145 this.draw_g.append("svg:line")
03146 .attr("x1", (width / num_cols * (ncol + 1)).toFixed(1))
03147 .attr("y1", (first_stat * stepy).toFixed(1))
03148 .attr("x2", (width / num_cols * (ncol + 1)).toFixed(1))
03149 .attr("y2", height)
03150 .call(this.lineatt.func);
03151 }
03152
03153 if ((pt.fLabel.length>0) && !this.IsStats()) {
03154 var x = Math.round(width*0.25),
03155 y = Math.round(-height*0.02),
03156 w = Math.round(width*0.5),
03157 h = Math.round(height*0.04);
03158
03159 var lbl_g = this.draw_g.append("svg:g");
03160
03161 lbl_g.append("rect")
03162 .attr("x", x)
03163 .attr("y", y)
03164 .attr("width", w)
03165 .attr("height", h)
03166 .call(this.fillatt.func)
03167 .call(this.lineatt.func);
03168
03169 this.StartTextDrawing(pt.fTextFont, h/1.5, lbl_g);
03170
03171 this.DrawText(22, x, y, w, h, pt.fLabel, tcolor, 1, lbl_g);
03172
03173 this.FinishTextDrawing(lbl_g);
03174
03175 this.UseTextColor = true;
03176 }
03177 }
03178
03179 JSROOT.TPavePainter.prototype.Format = function(value, fmt) {
03180
03181
03182 if (!fmt) fmt = "stat";
03183
03184 var pave = this.GetObject();
03185
03186 if (fmt=="stat") {
03187 fmt = pave.fStatFormat;
03188 if (!fmt) fmt = JSROOT.gStyle.StatFormat;
03189 } else
03190 if (fmt=="fit") {
03191 fmt = pave.fFitFormat;
03192 if (!fmt) fmt = JSROOT.gStyle.FitFormat;
03193 } else
03194 if (fmt=="entries") {
03195 if (value < 1e9) return value.toFixed(0);
03196 fmt = "14.7g";
03197 } else
03198 if (fmt=="last") {
03199 fmt = this['lastformat'];
03200 }
03201
03202 delete this['lastformat'];
03203
03204 if (!fmt) fmt = "6.4g";
03205
03206 var res = JSROOT.FFormat(value, fmt);
03207
03208 this['lastformat'] = JSROOT.lastFFormat;
03209
03210 return res;
03211 }
03212
03213 JSROOT.TPavePainter.prototype.ShowContextMenu = function(evnt) {
03214 if (!evnt) {
03215 d3.event.stopPropagation();
03216 d3.event.preventDefault();
03217
03218
03219 evnt = d3.event;
03220 }
03221
03222 var pthis = this, pave = this.GetObject();
03223
03224 JSROOT.Painter.createMenu(function(menu) {
03225 menu.painter = pthis;
03226 menu.add("header: " + pave._typename + "::" + pave.fName);
03227 if (pthis.IsStats()) {
03228
03229 menu.add("SetStatFormat", function() {
03230 var fmt = prompt("Enter StatFormat", pave.fStatFormat);
03231 if (fmt!=null) {
03232 pave.fStatFormat = fmt;
03233 pthis.Redraw();
03234 }
03235 });
03236 menu.add("SetFitFormat", function() {
03237 var fmt = prompt("Enter FitFormat", pave.fFitFormat);
03238 if (fmt!=null) {
03239 pave.fFitFormat = fmt;
03240 pthis.Redraw();
03241 }
03242 });
03243 menu.add("separator");
03244 menu.add("sub:SetOptStat", function() {
03245
03246 var fmt = prompt("Enter OptStat", pave.fOptStat);
03247 if (fmt!=null) { pave.fOptStat = parseInt(fmt); pthis.Redraw(); }
03248 });
03249 function AddStatOpt(pos, name) {
03250 var opt = (pos<10) ? pave.fOptStat : pave.fOptFit;
03251 opt = parseInt(parseInt(opt) / parseInt(Math.pow(10,pos % 10))) % 10;
03252 menu.addchk(opt, name, opt * 100 + pos, function(arg) {
03253 var newopt = (arg % 100 < 10) ? pave.fOptStat : pave.fOptFit;
03254 var oldopt = parseInt(arg / 100);
03255 newopt -= (oldopt>0 ? oldopt : -1) * parseInt(Math.pow(10, arg % 10));
03256 if (arg % 100 < 10) pave.fOptStat = newopt;
03257 else pave.fOptFit = newopt;
03258 pthis.Redraw();
03259 });
03260 }
03261
03262 AddStatOpt(0, "Histogram name");
03263 AddStatOpt(1, "Entries");
03264 AddStatOpt(2, "Mean");
03265 AddStatOpt(3, "Std Dev");
03266 AddStatOpt(4, "Underflow");
03267 AddStatOpt(5, "Overflow");
03268 AddStatOpt(6, "Integral");
03269 AddStatOpt(7, "Skewness");
03270 AddStatOpt(8, "Kurtosis");
03271 menu.add("endsub:");
03272
03273 menu.add("sub:SetOptFit", function() {
03274
03275 var fmt = prompt("Enter OptStat", pave.fOptFit);
03276 if (fmt!=null) { pave.fOptFit = parseInt(fmt); pthis.Redraw(); }
03277 });
03278 AddStatOpt(10, "Fit parameters");
03279 AddStatOpt(11, "Par errors");
03280 AddStatOpt(12, "Chi square / NDF");
03281 AddStatOpt(13, "Probability");
03282 menu.add("endsub:");
03283
03284 menu.add("separator");
03285 }
03286
03287 if (pthis.UseTextColor)
03288 pthis.TextAttContextMenu(menu);
03289
03290 pthis.FillAttContextMenu(menu);
03291
03292 menu.show(evnt);
03293 });
03294 }
03295
03296 JSROOT.TPavePainter.prototype.IsStats = function() {
03297 return this.MatchObjectType('TPaveStats');
03298 }
03299
03300 JSROOT.TPavePainter.prototype.FillStatistic = function() {
03301 var pave = this.GetObject(), main = this.main_painter();
03302
03303 if (pave.fName !== "stats") return false;
03304 if ((main===null) || !('FillStatistic' in main)) return false;
03305
03306
03307 if (main.IsDummyHisto()) return true;
03308
03309 var dostat = new Number(pave.fOptStat);
03310 var dofit = new Number(pave.fOptFit);
03311 if (!dostat) dostat = JSROOT.gStyle.OptStat;
03312 if (!dofit) dofit = JSROOT.gStyle.OptFit;
03313
03314
03315 pave.Clear();
03316
03317
03318 main.FillStatistic(this, dostat, dofit);
03319
03320 return true;
03321 }
03322
03323 JSROOT.TPavePainter.prototype.UpdateObject = function(obj) {
03324 if (!this.MatchObjectType(obj)) return false;
03325
03326 var pave = this.GetObject();
03327
03328 if (obj._typename === 'TPaveText') {
03329 pave.fLines = JSROOT.clone(obj.fLines);
03330 return true;
03331 } else
03332 if (obj._typename === 'TPaveLabel') {
03333 pave.fLabel = obj.fLabel;
03334 return true;
03335 }
03336
03337 return false;
03338 }
03339
03340 JSROOT.TPavePainter.prototype.Redraw = function() {
03341
03342
03343 this.DrawPave(true);
03344 }
03345
03346 JSROOT.Painter.drawPaveText = function(divid, pave, opt) {
03347
03348 var painter = new JSROOT.TPavePainter(pave);
03349 painter.SetDivId(divid, 2);
03350
03351 if ((typeof opt == 'string') && (opt.indexOf("onpad:")==0))
03352 painter.pad_name = opt.substr(6);
03353
03354 switch (pave._typename) {
03355 case "TPaveLabel":
03356 painter.PaveDrawFunc = painter.DrawPaveLabel;
03357 break;
03358 case "TPaveStats":
03359 case "TPaveText":
03360 painter.PaveDrawFunc = painter.DrawPaveText;
03361 break;
03362 }
03363
03364 painter.Redraw();
03365
03366 return painter.DrawingReady();
03367 }
03368
03369
03370
03371 JSROOT.TPadPainter = function(pad, iscan) {
03372 JSROOT.TObjectPainter.call(this, pad);
03373 this.pad = pad;
03374 this.iscan = iscan;
03375 this.this_pad_name = "";
03376 if (!this.iscan && (pad !== null) && ('fName' in pad))
03377 this.this_pad_name = pad.fName.replace(" ", "_");
03378 this.painters = new Array;
03379 this.has_canvas = true;
03380 }
03381
03382 JSROOT.TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
03383
03384 JSROOT.TPadPainter.prototype.ButtonSize = function(fact) {
03385 return Math.round((!fact ? 1 : fact) * (this.iscan || !this.has_canvas ? 16 : 12));
03386 }
03387
03388 JSROOT.TPadPainter.prototype.CreateCanvasSvg = function(check_resize, new_size) {
03389
03390 var render_to = this.select_main();
03391
03392 var rect = this.main_visible_rect();
03393
03394
03395 var w = rect.width, h = rect.height;
03396
03397 if ((typeof new_size == 'object') && (new_size!==null) && ('width' in new_size) && ('height' in new_size)) {
03398 w = new_size.width;
03399 h = new_size.height;
03400 }
03401
03402 var factor = null, svg = null;
03403
03404 if (check_resize > 0) {
03405
03406 svg = this.svg_canvas();
03407
03408 var oldw = svg.property('draw_width'), oldh = svg.property('draw_height');
03409
03410 if ((w<=0) && (h<=0)) {
03411 svg.attr("visibility", "hidden");
03412 return false;
03413 } else {
03414 svg.attr("visibility", "visible");
03415 svg.select(".canvas_fillrect")
03416 .call(this.fillatt.func);
03417 }
03418
03419 if (check_resize == 1) {
03420 if ((oldw == w) && (oldh == h)) return false;
03421 }
03422
03423 factor = svg.property('height_factor');
03424
03425 if (factor != null) {
03426
03427 h = Math.round(w * factor);
03428 render_to.style('height', h+'px');
03429 }
03430
03431 if ((check_resize==1) && (oldw>0) && (oldh>0) && !svg.property('redraw_by_resize'))
03432 if ((w/oldw>0.66) && (w/oldw<1.5) && (h/oldh>0.66) && (h/oldh<1.5)) {
03433
03434
03435 return false;
03436 }
03437
03438 } else {
03439
03440 if ((h < 10) && (w > 0)) {
03441
03442
03443 factor = 0.66;
03444
03445
03446 if ((this.pad!==null) && ('fCw' in this.pad) && ('fCh' in this.pad) && (this.pad.fCw > 0)) {
03447 factor = this.pad.fCh / this.pad.fCw;
03448 if ((factor < 0.1) || (factor > 10))
03449 factor = 0.66;
03450 }
03451
03452 h = Math.round(w * factor);
03453
03454 render_to.style('height', h+'px');
03455 }
03456
03457 svg = this.select_main()
03458 .append("svg")
03459 .attr("class", "jsroot root_canvas")
03460 .property('pad_painter', this)
03461 .property('mainpainter', null)
03462 .property('current_pad', "")
03463 .property('redraw_by_resize', false);
03464
03465 svg.append("svg:title").text("ROOT canvas");
03466 svg.append("svg:rect").attr("class","canvas_fillrect").attr("x",0).attr("y",0);
03467 svg.append("svg:g").attr("class","root_frame");
03468 svg.append("svg:g").attr("class","subpads_layer");
03469 svg.append("svg:g").attr("class","special_layer");
03470 svg.append("svg:g").attr("class","text_layer");
03471 svg.append("svg:g").attr("class","stat_layer");
03472 svg.append("svg:g").attr("class","btns_layer");
03473
03474 this.fillatt = this.createAttFill(this.pad, 1001, 0);
03475
03476 if (JSROOT.gStyle.ContextMenu)
03477 svg.select(".canvas_fillrect").on("contextmenu", this.ShowContextMenu.bind(this));
03478 }
03479
03480 if ((w<=0) || (h<=0)) {
03481 svg.attr("visibility", "hidden");
03482 w = 200; h = 100;
03483 } else {
03484 svg.attr("visibility", "visible");
03485 }
03486
03487 svg.attr("x", 0)
03488 .attr("y", 0)
03489 .attr("width", "100%")
03490 .attr("height", "100%")
03491 .attr("viewBox", "0 0 " + w + " " + h)
03492 .attr("preserveAspectRatio", "none")
03493 .property('height_factor', factor)
03494 .property('draw_x', 0)
03495 .property('draw_y', 0)
03496 .property('draw_width', w)
03497 .property('draw_height', h);
03498
03499 svg.select(".canvas_fillrect")
03500 .attr("width",w)
03501 .attr("height",h)
03502 .call(this.fillatt.func);
03503
03504 this.svg_layer("btns_layer").attr("transform","translate(2," + (h-this.ButtonSize(1.25)) + ")");
03505
03506 return true;
03507 }
03508
03509 JSROOT.TPadPainter.prototype.CreatePadSvg = function(only_resize) {
03510 if (!this.has_canvas)
03511 return this.CreateCanvasSvg(only_resize ? 2 : 0);
03512
03513 var width = this.svg_canvas().property("draw_width"),
03514 height = this.svg_canvas().property("draw_height"),
03515 w = Math.round(this.pad.fAbsWNDC * width),
03516 h = Math.round(this.pad.fAbsHNDC * height),
03517 x = Math.round(this.pad.fAbsXlowNDC * width),
03518 y = Math.round(height - this.pad.fAbsYlowNDC * height) - h;
03519
03520 var svg_pad = null, svg_rect = null, btns = null;
03521
03522 if (only_resize) {
03523 svg_pad = this.svg_pad(this.this_pad_name);
03524 svg_rect = svg_pad.select(".root_pad_border");
03525 btns = this.svg_layer("btns_layer", this.this_pad_name);
03526 } else {
03527 svg_pad = this.svg_canvas().select(".subpads_layer")
03528 .append("g")
03529 .attr("class", "root_pad")
03530 .attr("pad", this.this_pad_name)
03531 .property('pad_painter', this)
03532 .property('mainpainter', null);
03533 svg_rect = svg_pad.append("svg:rect").attr("class", "root_pad_border");
03534 svg_pad.append("svg:g").attr("class","root_frame");
03535 svg_pad.append("svg:g").attr("class","special_layer");
03536 svg_pad.append("svg:g").attr("class","text_layer");
03537 svg_pad.append("svg:g").attr("class","stat_layer");
03538 btns = svg_pad.append("svg:g").attr("class","btns_layer").property('nextx', 0);
03539
03540 if (JSROOT.gStyle.ContextMenu)
03541 svg_pad.select(".root_pad_border").on("contextmenu", this.ShowContextMenu.bind(this));
03542
03543 this.fillatt = this.createAttFill(this.pad, 1001, 0);
03544 this.lineatt = JSROOT.Painter.createAttLine(this.pad)
03545 if (this.pad.fBorderMode == 0) this.lineatt.color = 'none';
03546 }
03547
03548 svg_pad.attr("transform", "translate(" + x + "," + y + ")")
03549 .property('draw_x', x)
03550 .property('draw_y', y)
03551 .property('draw_width', w)
03552 .property('draw_height', h);
03553
03554 svg_rect.attr("x", 0)
03555 .attr("y", 0)
03556 .attr("width", w)
03557 .attr("height", h)
03558 .call(this.fillatt.func)
03559 .call(this.lineatt.func);
03560
03561 btns.attr("transform","translate("+ (w- btns.property('nextx') - this.ButtonSize(0.25)) + "," + (h-this.ButtonSize(1.25)) + ")");
03562 }
03563
03564 JSROOT.TPadPainter.prototype.CheckColors = function(can) {
03565 if (can==null) return;
03566 for (var i = 0; i < can.fPrimitives.arr.length; ++i) {
03567 var obj = can.fPrimitives.arr[i];
03568 if (obj==null) continue;
03569 if ((obj._typename=="TObjArray") && (obj.name == "ListOfColors")) {
03570 JSROOT.Painter.adoptRootColors(obj);
03571 can.fPrimitives.arr.splice(i,1);
03572 can.fPrimitives.opt.splice(i,1);
03573 return;
03574 }
03575 }
03576 }
03577
03578 JSROOT.TPadPainter.prototype.RemovePrimitive = function(obj) {
03579 if ((this.pad===null) || (this.pad.fPrimitives === null)) return;
03580 var indx = this.pad.fPrimitives.arr.indexOf(obj);
03581 if (indx>=0) this.pad.fPrimitives.RemoveAt(indx);
03582 }
03583
03584 JSROOT.TPadPainter.prototype.FindPrimitive = function(exact_obj, classname, name) {
03585 if ((this.pad===null) || (this.pad.fPrimitives === null)) return null;
03586
03587 for (var i=0; i < this.pad.fPrimitives.arr.length; i++) {
03588 var obj = this.pad.fPrimitives.arr[i];
03589
03590 if ((exact_obj!==null) && (obj !== exact_obj)) continue;
03591
03592 if ((classname !== undefined) && (classname !== null))
03593 if (obj._typename !== classname) continue;
03594
03595 if ((name !== undefined) && (name !== null))
03596 if (obj.fName !== name) continue;
03597
03598 return obj;
03599 }
03600
03601 return null;
03602 }
03603
03604 JSROOT.TPadPainter.prototype.HasObjectsToDraw = function() {
03605
03606
03607 if ((this.pad===null) || !this.pad.fPrimitives || (this.pad.fPrimitives.arr.length==0)) return false;
03608
03609 for (var n=0;n<this.pad.fPrimitives.arr.length;++n)
03610 if (this.pad.fPrimitives.arr[n] && this.pad.fPrimitives.arr[n]._typename != "TPad") return true;
03611
03612 return false;
03613 }
03614
03615 JSROOT.TPadPainter.prototype.DrawPrimitive = function(indx, callback) {
03616 if ((this.pad===null) || (indx >= this.pad.fPrimitives.arr.length))
03617 return JSROOT.CallBack(callback);
03618
03619 var pp = JSROOT.draw(this.divid, this.pad.fPrimitives.arr[indx], this.pad.fPrimitives.opt[indx]);
03620
03621 if (pp === null) return this.DrawPrimitive(indx+1, callback);
03622
03623 pp._primitive = true;
03624 pp.WhenReady(this.DrawPrimitive.bind(this, indx+1, callback));
03625 }
03626
03627
03628 JSROOT.TPadPainter.prototype.GetTooltips = function(pnt) {
03629 var painters = [], hints = [];
03630
03631
03632 if (this.painters !== null)
03633 this.painters.forEach(function(obj) {
03634 if ('ProcessTooltip' in obj) painters.push(obj);
03635 });
03636
03637 if (pnt) pnt.nproc = painters.length;
03638
03639 painters.forEach(function(obj) {
03640 var hint = obj.ProcessTooltip(pnt);
03641 hints.push(hint);
03642 if (hint && pnt.painters) hint.painter = obj;
03643 });
03644
03645 return hints;
03646 }
03647
03648 JSROOT.TPadPainter.prototype.ShowContextMenu = function(evnt) {
03649 if (!evnt) {
03650
03651
03652 var pos = d3.mouse(this.svg_pad(this.this_pad_name).node());
03653 if (pos && (pos.length==2) && (pos[0]>0) && (pos[0]<10) && (pos[1]>0) && pos[1]<10) return;
03654
03655 d3.event.stopPropagation();
03656 d3.event.preventDefault();
03657
03658
03659 evnt = d3.event;
03660 }
03661
03662 var pthis = this;
03663
03664 JSROOT.Painter.createMenu(function(menu) {
03665 menu.painter = pthis;
03666 if (pthis.pad)
03667 menu.add("header: " + pthis.pad._typename + "::" + pthis.pad.fName);
03668 else
03669 menu.add("header: Canvas");
03670
03671 if (pthis.iscan)
03672 menu.addchk((JSROOT.gStyle.Tooltip > 0), "Show tooltips", function() {
03673 JSROOT.gStyle.Tooltip = (JSROOT.gStyle.Tooltip === 0) ? 1 : -JSROOT.gStyle.Tooltip;
03674 });
03675
03676 pthis.FillAttContextMenu(menu);
03677
03678 menu.add("separator");
03679
03680 var file_name = "canvas.png";
03681 if (!pthis.iscan) file_name = pthis.this_pad_name + ".png";
03682
03683 menu.add("Save as "+file_name, file_name, function(arg) {
03684
03685 var top = this.svg_pad(this.this_pad_name);
03686 if (!top.empty())
03687 JSROOT.AssertPrerequisites("savepng", function() {
03688 console.log('create', arg);
03689 top.selectAll(".btns_layer").style("display","none");
03690 saveSvgAsPng(top.node(), arg);
03691 top.selectAll(".btns_layer").style("display","");
03692 });
03693 });
03694
03695 menu.show(evnt);
03696 });
03697 }
03698
03699 JSROOT.TPadPainter.prototype.Redraw = function(resize) {
03700 if (this.iscan)
03701 this.CreateCanvasSvg(2);
03702 else
03703 this.CreatePadSvg(true);
03704
03705
03706 for (var i = 0; i < this.painters.length; ++i)
03707 this.painters[i].Redraw(resize);
03708 }
03709
03710 JSROOT.TPadPainter.prototype.NumDrawnSubpads = function() {
03711 if (this.painters === undefined) return 0;
03712
03713 var num = 0;
03714
03715 for (var i = 0; i < this.painters.length; ++i) {
03716 var obj = this.painters[i].GetObject();
03717 if ((obj!==null) && (obj._typename === "TPad")) num++;
03718 }
03719
03720 return num;
03721 }
03722
03723 JSROOT.TPadPainter.prototype.CheckCanvasResize = function(size, force) {
03724 if (!this.iscan) return false;
03725
03726 if ((size !== null) && (typeof size === 'object') && size.force) force = true;
03727
03728 var changed = this.CreateCanvasSvg(force ? 2 : 1, size);
03729
03730
03731 if (changed)
03732 for (var i = 0; i < this.painters.length; ++i)
03733 this.painters[i].Redraw(true);
03734
03735 return changed;
03736 }
03737
03738 JSROOT.TPadPainter.prototype.UpdateObject = function(obj) {
03739
03740 if ((obj == null) || !('fPrimitives' in obj)) return false;
03741
03742 if (this.iscan) this.CheckColors(obj);
03743
03744 if (obj.fPrimitives.arr.length !== this.pad.fPrimitives.arr.length) return false;
03745
03746 var isany = false, p = 0;
03747 for (var n = 0; n < obj.fPrimitives.arr.length; ++n) {
03748 while (p < this.painters.length) {
03749 var pp = this.painters[p++];
03750 if (!('_primitive' in pp)) continue;
03751 if (pp.UpdateObject(obj.fPrimitives.arr[n])) isany = true;
03752 break;
03753 }
03754 }
03755
03756 return isany;
03757 }
03758
03759 JSROOT.TPadPainter.prototype.ItemContextMenu = function(name) {
03760 var rrr = this.svg_pad(this.this_pad_name).node().getBoundingClientRect();
03761 var evnt = { clientX: rrr.left+10, clientY: rrr.top + 10 };
03762
03763
03764 if (name=="pad")
03765 return setTimeout(this.ShowContextMenu.bind(this, evnt), 50);
03766
03767 var selp = null, selkind;
03768
03769 switch(name) {
03770 case "xaxis": selp = this.main_painter(); selkind = "x"; break;
03771 case "yaxis": selp = this.main_painter(); selkind = "y"; break;
03772 case "frame": selp = this.frame_painter(); break;
03773 default: {
03774 var indx = parseInt(name);
03775 if (!isNaN(indx)) selp = this.painters[indx];
03776 }
03777 }
03778
03779 if (!selp || (typeof selp.FillContextMenu !== 'function')) return;
03780
03781 JSROOT.Painter.createMenu(function(menu) {
03782 menu.painter = selp;
03783 if (selp.FillContextMenu(menu,selkind))
03784 setTimeout(menu.show.bind(menu, evnt), 50);
03785 });
03786
03787 }
03788
03789 JSROOT.TPadPainter.prototype.PadButtonClick = function(funcname) {
03790
03791 var elem = null, filename = "";
03792
03793 if (funcname == "CanvasSnapShot") {
03794 elem = this.svg_canvas();
03795 filename = (this.pad ? this.pad.fName : "jsroot_canvas") + ".png";
03796 } else
03797 if (funcname == "PadSnapShot") {
03798 elem = this.svg_pad(this.this_pad_name);
03799 filename = this.this_pad_name + ".png";
03800 }
03801 if ((elem!==null) && !elem.empty()) {
03802 var main = elem.property('mainpainter');
03803
03804 if ((elem.property('can3d') === 1) && (main!==undefined) && (main.renderer!==undefined)) {
03805 var dataUrl = main.renderer.domElement.toDataURL("image/png");
03806 dataUrl.replace("image/png", "image/octet-stream");
03807 var link = document.createElement('a');
03808 if (typeof link.download === 'string') {
03809 document.body.appendChild(link);
03810 link.download = filename;
03811 link.href = dataUrl;
03812 link.click();
03813 document.body.removeChild(link);
03814 }
03815 } else {
03816 JSROOT.AssertPrerequisites("savepng", function() {
03817 elem.selectAll(".btns_layer").style("display","none");
03818 saveSvgAsPng(elem.node(), filename);
03819 elem.selectAll(".btns_layer").style("display","");
03820 });
03821 }
03822 return;
03823 }
03824
03825 if (funcname == "PadContextMenus") {
03826
03827 var pthis = this, evnt = d3.event;
03828
03829 d3.event.preventDefault();
03830 d3.event.stopPropagation();
03831
03832 JSROOT.Painter.createMenu(function(menu) {
03833 menu.painter = pthis;
03834 menu.add("header:Menus");
03835
03836 if (pthis.iscan)
03837 menu.add("Canvas", "pad", pthis.ItemContextMenu);
03838 else
03839 menu.add("Pad", "pad", pthis.ItemContextMenu);
03840
03841 if (pthis.frame_painter())
03842 menu.add("Frame", "frame", pthis.ItemContextMenu);
03843
03844 if (pthis.main_painter()) {
03845 menu.add("X axis", "xaxis", pthis.ItemContextMenu);
03846 menu.add("Y axis", "yaxis", pthis.ItemContextMenu);
03847 }
03848
03849 if (pthis.painters && (pthis.painters.length>0)) {
03850 menu.add("separator");
03851 var shown = [];
03852 for (var n=0;n<pthis.painters.length;++n) {
03853 var pp = pthis.painters[n];
03854 var obj = pp ? pp.GetObject() : null;
03855 if (!obj || (shown.indexOf(obj)>=0)) continue;
03856
03857 var name = ('_typename' in obj) ? (obj._typename + "::") : "";
03858 if ('fName' in obj) name += obj.fName;
03859 if (name.length==0) name = "item" + n;
03860 menu.add(name, n, pthis.ItemContextMenu);
03861 }
03862 }
03863
03864 menu.show(evnt);
03865 });
03866
03867 return;
03868 }
03869
03870
03871
03872 var done = false;
03873
03874 for (var i = 0; i < this.painters.length; ++i) {
03875 var pp = this.painters[i];
03876
03877 if (typeof pp.PadButtonClick == 'function')
03878 pp.PadButtonClick(funcname);
03879
03880 if (!done && (typeof pp.ButtonClick == 'function'))
03881 done = pp.ButtonClick(funcname);
03882 }
03883 }
03884
03885 JSROOT.TPadPainter.prototype.AddButton = function(btn, tooltip, funcname) {
03886
03887
03888 if (!JSROOT.gStyle.ToolBar) return;
03889
03890 var group = this.svg_layer("btns_layer", this.this_pad_name);
03891 if (group.empty()) return;
03892
03893
03894 if (!group.select("[name=" + funcname + ']').empty()) return;
03895
03896 var x = group.property("nextx");
03897 if (x===undefined) x = 0;
03898
03899 var iscan = this.iscan || !this.has_canvas;
03900
03901 var svg = group.append("svg:svg")
03902 .attr("class", "svg_toolbar_btn")
03903 .attr("name", funcname)
03904 .attr("x", x)
03905 .attr("y", 0)
03906 .attr("width",this.ButtonSize()+"px")
03907 .attr("height",this.ButtonSize()+"px")
03908 .attr("viewBox", "0 0 512 512")
03909 .style("overflow","hidden");
03910
03911 svg.append("svg:title").text(tooltip + (iscan ? "" : (" on pad " + this.this_pad_name)));
03912
03913 if ('recs' in btn) {
03914 var rec = {};
03915 for (var n=0;n<btn.recs.length;++n) {
03916 JSROOT.extend(rec, btn.recs[n]);
03917 svg.append('rect').attr("x", rec.x).attr("y", rec.y)
03918 .attr("width", rec.w).attr("height", rec.h)
03919 .attr("fill", rec.f);
03920 }
03921 } else {
03922 svg.append('svg:path').attr('d',btn.path);
03923 }
03924
03925
03926 svg.append("svg:rect").attr("x",0).attr("y",0).attr("width",512).attr("height",512)
03927 .style("opacity","0").style("fill","none").style("pointer-events", "visibleFill");
03928
03929 svg.on("click", this.PadButtonClick.bind(this, funcname));
03930
03931 group.property("nextx", x+this.ButtonSize(1.25));
03932
03933 if (!iscan)
03934 group.attr("transform","translate("+ (this.pad_width(this.this_pad_name) - group.property('nextx')-this.ButtonSize(0.25)) + "," + (this.pad_height(this.this_pad_name)-this.ButtonSize(1.25)) + ")");
03935
03936 if (!iscan && (funcname.indexOf("Pad")!=0) && (this.pad_painter()!==this))
03937 this.pad_painter().AddButton(btn, tooltip, funcname);
03938 }
03939
03940 JSROOT.Painter.drawCanvas = function(divid, can, opt) {
03941 var painter = new JSROOT.TPadPainter(can, true);
03942 if (can && opt && (opt.indexOf("white")>=0)) can.fFillColor = 0;
03943
03944 painter.SetDivId(divid, -1);
03945 painter.CheckColors(can);
03946 painter.CreateCanvasSvg(0);
03947 painter.SetDivId(divid);
03948
03949 painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot");
03950 painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus");
03951
03952 if (can==null) {
03953 if (opt.indexOf("noframe") < 0)
03954 JSROOT.Painter.drawFrame(divid, null);
03955 return painter.DrawingReady();
03956 }
03957
03958 painter.DrawPrimitive(0, function() { painter.DrawingReady(); });
03959 return painter;
03960 }
03961
03962 JSROOT.Painter.drawPad = function(divid, pad, opt) {
03963 var painter = new JSROOT.TPadPainter(pad, false);
03964
03965 if (pad && opt && (opt.indexOf("white")>=0)) pad.fFillColor = 0;
03966
03967 painter.SetDivId(divid);
03968
03969 if (painter.svg_canvas().empty()) {
03970 painter.has_canvas = false;
03971 painter.this_pad_name = "";
03972 }
03973
03974 painter.CreatePadSvg();
03975
03976 if (painter.MatchObjectType("TPad") && (!painter.has_canvas || painter.HasObjectsToDraw())) {
03977 painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "PadSnapShot");
03978 painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus");
03979 }
03980
03981 var prev_name = "";
03982
03983 if (painter.has_canvas) {
03984
03985 prev_name = painter.svg_canvas().property('current_pad');
03986 painter.svg_canvas().property('current_pad', pad.fName);
03987 }
03988
03989 painter.DrawPrimitive(0, function() {
03990
03991 painter.svg_canvas().property('current_pad', prev_name);
03992 painter.DrawingReady();
03993 });
03994
03995 return painter;
03996 }
03997
03998
03999
04000 JSROOT.TAxisPainter = function(axis, embedded) {
04001 JSROOT.TObjectPainter.call(this, axis);
04002
04003 this.embedded = embedded;
04004
04005 this.name = "yaxis";
04006 this.kind = "normal";
04007 this.func = null;
04008 this.order = 0;
04009
04010 this.full_min = 0;
04011 this.full_max = 1;
04012 this.scale_min = 0;
04013 this.scale_max = 1;
04014 this.ticks = [];
04015 }
04016
04017 JSROOT.TAxisPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
04018
04019 JSROOT.TAxisPainter.prototype.SetAxisConfig = function(name, kind, func, min, max, smin, smax) {
04020 this.name = name;
04021 this.kind = kind;
04022 this.func = func;
04023
04024 this.full_min = min;
04025 this.full_max = max;
04026 this.scale_min = smin;
04027 this.scale_max = smax;
04028 }
04029
04030 JSROOT.TAxisPainter.prototype.CreateFormatFuncs = function() {
04031
04032 var axis = this.GetObject(),
04033 is_gaxis = (axis && axis._typename === 'TGaxis');
04034
04035 delete this.format;
04036
04037 var ndiv = 508;
04038 if (axis !== null)
04039 ndiv = Math.max(is_gaxis ? axis.fNdiv : axis.fNdivisions, 4) ;
04040
04041 this.nticks = ndiv % 100;
04042 this.nticks2 = (ndiv % 10000 - this.nticks) / 100;
04043 this.nticks3 = Math.floor(ndiv/10000);
04044
04045 if (axis && !is_gaxis && (this.nticks > 7)) this.nticks = 7;
04046
04047 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
04048 if (gr_range<=0) gr_range = 100;
04049
04050 if (this.kind == 'time') {
04051 if (this.nticks > 8) this.nticks = 8;
04052
04053 var scale_range = this.scale_max - this.scale_min;
04054
04055 var tf1 = JSROOT.Painter.getTimeFormat(axis);
04056 if ((tf1.length == 0) || (scale_range < 0.1 * (this.full_max - this.full_min)))
04057 tf1 = JSROOT.Painter.chooseTimeFormat(scale_range / this.nticks, true);
04058 var tf2 = JSROOT.Painter.chooseTimeFormat(scale_range / gr_range, false);
04059
04060 this.tfunc1 = this.tfunc2 = d3.time.format(tf1);
04061 if (tf2!==tf1)
04062 this.tfunc2 = d3.time.format(tf2);
04063
04064 this.format = function(d, asticks) {
04065 return asticks ? this.tfunc1(d) : this.tfunc2(d);
04066 }
04067
04068 } else
04069 if (this.kind == 'log') {
04070 this.nticks2 = 1;
04071 this.noexp = axis ? axis.TestBit(JSROOT.EAxisBits.kNoExponent) : false;
04072 if ((this.scale_max < 300) && (this.scale_min > 0.3)) this.noexp = true;
04073 this.moreloglabels = axis ? axis.TestBit(JSROOT.EAxisBits.kMoreLogLabels) : false;
04074
04075 this.format = function(d, asticks, notickexp) {
04076
04077 var val = parseFloat(d);
04078
04079 if (!asticks) {
04080 var rnd = Math.round(val);
04081 return ((rnd === val) && (Math.abs(rnd)<1e9)) ? rnd.toString() : val.toExponential(4);
04082 }
04083
04084 if (val <= 0) return null;
04085 var vlog = JSROOT.log10(val);
04086 if (this.moreloglabels || (Math.abs(vlog - Math.round(vlog))<0.001)) {
04087 if (!this.noexp && !notickexp)
04088 return JSROOT.Painter.formatExp(val.toExponential(0));
04089 else
04090 if (vlog<0)
04091 return val.toFixed(Math.round(-vlog+0.5));
04092 else
04093 return val.toFixed(0);
04094 }
04095 return null;
04096 }
04097 } else
04098 if (this.kind == 'labels') {
04099 this.nticks = 50;
04100 var scale_range = this.scale_max - this.scale_min;
04101 if (this.nticks > scale_range)
04102 this.nticks = Math.round(scale_range);
04103 this.nticks2 = 1;
04104
04105 this.axis = axis;
04106
04107 this.format = function(d) {
04108 var indx = Math.round(parseInt(d)) + 1;
04109 if ((indx<1) || (indx>this.axis.fNbins)) return null;
04110 for (var i = 0; i < this.axis.fLabels.arr.length; ++i) {
04111 var tstr = this.axis.fLabels.arr[i];
04112 if (tstr.fUniqueID == indx) return tstr.fString;
04113 }
04114 return null;
04115 }
04116 } else {
04117
04118 this.range = Math.abs(this.scale_max - this.scale_min);
04119 if (this.range <= 0)
04120 this.ndig = -3;
04121 else
04122 this.ndig = Math.round(JSROOT.log10(this.nticks / this.range) + 0.7);
04123
04124 this.format = function(d, asticks) {
04125 var val = parseFloat(d), rnd = Math.round(val);
04126 if (asticks) {
04127 if (this.order===0) {
04128 if (val === rnd) return rnd.toString();
04129 if (Math.abs(val) < 1e-10 * this.range) return 0;
04130 val = val.toFixed(this.ndig > 0 ? this.ndig : 0);
04131 if ((typeof d == 'string') && (d.length <= val.length+1)) return d;
04132 return val;
04133 }
04134 val = val / Math.pow(10, this.order);
04135 rnd = Math.round(val);
04136 if (val === rnd) return rnd.toString();
04137 return val.toFixed(this.ndig + this.order > 0 ? this.ndig + this.order : 0 );
04138 }
04139
04140 if (val === rnd)
04141 return (Math.abs(rnd)<1e9) ? rnd.toString() : val.toExponential(4);
04142 return val.toFixed(this.ndig+2 > 0 ? this.ndig+2 : 0);
04143 }
04144 }
04145 }
04146
04147 JSROOT.TAxisPainter.prototype.CreateTicks = function() {
04148
04149
04150 var handle = { nminor: 0, nmiddle: 0, nmajor: 0, func: this.func };
04151
04152 handle.minor = handle.middle = handle.major = this.func.ticks(this.nticks);
04153
04154 if (this.nticks2 > 1) {
04155 handle.minor = handle.middle = this.func.ticks(handle.major.length * this.nticks2);
04156
04157 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
04158
04159
04160 if ((handle.middle.length <= handle.major.length) || (handle.middle.length > gr_range/3.5)) {
04161 handle.minor = handle.middle = handle.major;
04162 } else
04163 if ((this.nticks3 > 1) && (this.kind !== 'log')) {
04164 handle.minor = this.func.ticks(handle.middle.length * this.nticks3);
04165 if ((handle.minor.length <= handle.middle.length) || (handle.minor.length > gr_range/1.7)) handle.minor = handle.middle;
04166 }
04167 }
04168
04169 handle.reset = function() {
04170 this.nminor = this.nmiddle = this.nmajor = 0;
04171 }
04172
04173 handle.next = function(doround) {
04174 if (this.nminor >= this.minor.length) return false;
04175
04176 this.tick = this.minor[this.nminor++];
04177 this.grpos = this.func(this.tick);
04178 if (doround) this.grpos = Math.round(this.grpos);
04179 this.kind = 3;
04180
04181 if ((this.nmiddle < this.middle.length) && (Math.abs(this.grpos - this.func(this.middle[this.nmiddle])) < 1)) {
04182 this.nmiddle++;
04183 this.kind = 2;
04184 }
04185
04186 if ((this.nmajor < this.major.length) && (Math.abs(this.grpos - this.func(this.major[this.nmajor])) < 1) ) {
04187 this.nmajor++;
04188 this.kind = 1;
04189 }
04190 return true;
04191 }
04192
04193 handle.last_major = function() {
04194 return (this.kind !== 1) ? false : this.nmajor == this.major.length;
04195 }
04196
04197 return handle;
04198 }
04199
04200 JSROOT.TAxisPainter.prototype.DrawAxis = function(layer, w, h, transform, reverse) {
04201
04202
04203
04204 var axis = this.GetObject(),
04205 is_gaxis = (axis && axis._typename === 'TGaxis'),
04206 vertical = (this.name !== "xaxis"),
04207 side = (this.name === "zaxis") ? -1 : 1, both_sides = 0,
04208 axis_g = layer, tickSize = 10, scaling_size = 100, text_scaling_size = 100;
04209
04210 if (is_gaxis) {
04211 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(axis);
04212 scaling_size = (vertical ? this.pad_width() : this.pad_height());
04213 text_scaling_size = Math.min(this.pad_width(), this.pad_height());
04214 tickSize = Math.round(axis.fTickSize * scaling_size);
04215 } else {
04216 if (!this.lineatt) this.lineatt = JSROOT.Painter.createAttLine(axis.fAxisColor, 1);
04217 scaling_size = (vertical ? w : h);
04218 tickSize = Math.round(axis.fTickLength * scaling_size);
04219 text_scaling_size = Math.min(w,h);
04220 }
04221
04222 if (!is_gaxis || (this.name === "zaxis")) {
04223 axis_g = layer.select("." + this.name + "_container");
04224 if (axis_g.empty())
04225 axis_g = layer.append("svg:g").attr("class",this.name+"_container");
04226 else
04227 axis_g.selectAll("*").remove();
04228 } else {
04229
04230 if ((axis.fChopt.indexOf("-")>=0) && (axis.fChopt.indexOf("+")<0)) side = -1; else
04231 if (vertical && axis.fChopt=="+L") side = -1; else
04232 if ((axis.fChopt.indexOf("-")>=0) && (axis.fChopt.indexOf("+")>=0)) { side = 1; both_sides = 1; }
04233
04234 axis_g.append("svg:line")
04235 .attr("x1",0).attr("y1",0)
04236 .attr("x1",vertical ? 0 : w)
04237 .attr("y1", vertical ? h : 0)
04238 .call(this.lineatt.func);
04239 }
04240
04241 if (transform!== undefined)
04242 axis_g.attr("transform", transform);
04243
04244 this.CreateFormatFuncs();
04245
04246 var center = (this.kind == 'labels') ||
04247 (this.kind !== 'log' && axis.TestBit(JSROOT.EAxisBits.kCenterLabels));
04248
04249 var res = "", lastpos = 0, lasth = 0, textscale = 1;
04250
04251
04252
04253 this.ticks = [];
04254
04255 var handle = this.CreateTicks();
04256
04257 while (handle.next(true)) {
04258 var h1 = Math.round(tickSize/4), h2 = 0;
04259
04260 if (handle.kind < 3)
04261 h1 = Math.round(tickSize/2);
04262
04263 if (handle.kind == 1) {
04264
04265 if (!('format' in this) || (this.format(handle.tick,true)!==null)) h1 = tickSize;
04266 this.ticks.push(handle.grpos);
04267 }
04268
04269 if (both_sides > 0) h2 = -h1; else
04270 if (side < 0) { h2 = -h1; h1 = 0; } else { h2 = 0; }
04271
04272 if (res.length == 0) {
04273 res += vertical ? ("M"+h1+","+handle.grpos) : ("M"+handle.grpos+","+-h1);
04274 } else {
04275 res += vertical ? ("m"+(h1-lasth)+","+(handle.grpos-lastpos)) : ("m"+(handle.grpos-lastpos)+","+(lasth-h1));
04276 }
04277
04278 res += vertical ? ("h"+ (h2-h1)) : ("v"+ (h1-h2));
04279
04280 lastpos = handle.grpos;
04281 lasth = h2;
04282 }
04283
04284 if (res.length > 0)
04285 axis_g.append("svg:path").attr("d", res).call(this.lineatt.func);
04286
04287 var last = vertical ? h : 0,
04288 labelfont = JSROOT.Painter.getFontDetails(axis.fLabelFont, Math.round(axis.fLabelSize * (is_gaxis ? this.pad_height() : h))),
04289 label_color = JSROOT.Painter.root_colors[axis.fLabelColor],
04290 labeloffset = 3 + Math.round(axis.fLabelOffset * scaling_size),
04291 label_g = axis_g.append("svg:g")
04292 .attr("class","axis_labels")
04293 .call(labelfont.func);
04294
04295 this.order = 0;
04296 if ((this.kind=="normal") && vertical && !axis.TestBit(JSROOT.EAxisBits.kNoExponent)) {
04297 var maxtick = Math.max(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1]));
04298 for(var order=18;order>-18;order-=3) {
04299 if (order===0) continue;
04300 if ((order<0) && ((this.range>=0.1) || (maxtick>=1.))) break;
04301 var mult = Math.pow(10, order);
04302 if ((this.range > mult * 9.99999) || ((maxtick > mult*50) && (this.range > mult * 0.05))) {
04303 this.order = order;
04304 break;
04305 }
04306 }
04307 }
04308
04309 for (var nmajor=0;nmajor<handle.major.length;++nmajor) {
04310 var pos = Math.round(this.func(handle.major[nmajor]));
04311 var lbl = this.format(handle.major[nmajor], true);
04312 if (lbl === null) continue;
04313
04314 var t = label_g.append("svg:text").attr("fill", label_color).text(lbl);
04315
04316 if (vertical)
04317 t.attr("x", -labeloffset*side)
04318 .attr("y", pos)
04319 .style("text-anchor", (side > 0) ? "end" : "start")
04320 .style("dominant-baseline", "middle");
04321 else
04322 t.attr("x", pos)
04323 .attr("y", 2+labeloffset*side + both_sides*tickSize)
04324 .attr("dy", (side > 0) ? ".7em" : "-.3em")
04325 .style("text-anchor", "middle");
04326
04327 var tsize = this.GetBoundarySizes(t.node());
04328 var space_before = (nmajor > 0) ? (pos - last) : (vertical ? h/2 : w/2);
04329 var space_after = (nmajor < handle.major.length-1) ? (Math.round(this.func(handle.major[nmajor+1])) - pos) : space_before;
04330 var space = Math.min(Math.abs(space_before), Math.abs(space_after));
04331
04332 if (vertical) {
04333
04334 if ((space > 0) && (tsize.height > 5) && (this.kind !== 'log'))
04335 textscale = Math.min(textscale, space / tsize.height);
04336
04337 if (center) {
04338
04339 if (pos + space_after/2 - textscale*tsize.height/2 < -10)
04340 t.remove();
04341 else
04342 t.attr("y", Math.round(pos + space_after/2));
04343 }
04344
04345 } else {
04346
04347
04348 if ((space > 0) && (tsize.width > 10) && (this.kind !== 'log'))
04349 textscale = Math.min(textscale, space / tsize.width);
04350
04351 if (center) {
04352
04353 if (pos + space_after/2 - textscale*tsize.width/2 > w - 10)
04354 t.remove();
04355 else
04356 t.attr("x", Math.round(pos + space_after/2));
04357 }
04358 }
04359
04360 last = pos;
04361 }
04362
04363 if (this.order!==0) {
04364 var val = Math.pow(10,this.order).toExponential(0);
04365
04366 var t = label_g.append("svg:text").attr("fill", label_color).text('\xD7' + JSROOT.Painter.formatExp(val));
04367
04368 if (vertical)
04369 t.attr("x", labeloffset)
04370 .attr("y", 0)
04371 .style("text-anchor", "start")
04372 .style("dominant-baseline", "middle")
04373 .attr("dy", "-.5em");
04374 }
04375
04376
04377 if ((textscale>0) && (textscale<1.)) {
04378
04379 if ((textscale < 0.7) && !vertical && (side>0)) {
04380 label_g.selectAll("text").each(function() {
04381 var txt = d3.select(this), x = txt.attr("x"), y = txt.attr("y") - 5;
04382
04383 txt.attr("transform", "translate(" + x + "," + y + ") rotate(25)")
04384 .style("text-anchor", "start")
04385 .attr("x",null).attr("y",null);
04386 });
04387 textscale *= 3.5;
04388 }
04389
04390 labelfont.size = Math.floor(labelfont.size * textscale + 0.7);
04391 label_g.call(labelfont.func);
04392 }
04393
04394 if (axis.fTitle.length > 0) {
04395 var title_g = axis_g.append("svg:g").attr("class", "axis_title"),
04396 title_fontsize = Math.round(axis.fTitleSize * text_scaling_size),
04397 center = axis.TestBit(JSROOT.EAxisBits.kCenterTitle),
04398 rotate = axis.TestBit(JSROOT.EAxisBits.kRotateTitle) ? -1 : 1,
04399 title_color = JSROOT.Painter.root_colors[axis.fTitleColor];
04400
04401 this.StartTextDrawing(axis.fTitleFont, title_fontsize, title_g);
04402
04403 var myxor = ((rotate<0) && !reverse) || ((rotate>=0) && reverse);
04404
04405 if (vertical) {
04406 var xoffset = -side*Math.round(labeloffset + (2-side/10) * axis.fTitleOffset*title_fontsize);
04407
04408 if ((this.name == "zaxis") && is_gaxis && ('getBoundingClientRect' in axis_g.node())) {
04409
04410 var rect = axis_g.node().getBoundingClientRect();
04411 if (xoffset < rect.width - tickSize) xoffset = Math.round(rect.width - tickSize);
04412 }
04413
04414 this.DrawText((center ? "middle" : (myxor ? "begin" : "end" ))+ ";middle",
04415 xoffset,
04416 Math.round(center ? h/2 : (reverse ? h : 0)),
04417 0, (rotate<0 ? -90 : -270),
04418 axis.fTitle, title_color, 1, title_g);
04419 } else {
04420 this.DrawText((center ? 'middle' : (myxor ? 'begin' : 'end')) + ";middle",
04421 Math.round(center ? w/2 : (reverse ? 0 : w)),
04422 Math.round(side*(labeloffset + 1.9*title_fontsize*axis.fTitleOffset)),
04423 0, (rotate<0 ? -180 : 0),
04424 axis.fTitle, title_color, 1, title_g);
04425 }
04426
04427 this.FinishTextDrawing(title_g);
04428 }
04429
04430
04431 if (JSROOT.gStyle.Zooming) {
04432 var r = axis_g.append("svg:rect")
04433 .attr("class", "axis_zoom")
04434 .style("opacity", "0")
04435 .style("cursor", "crosshair");
04436
04437 if (vertical)
04438 r.attr("x", (side >0) ? (-2*labelfont.size - 3) : 3)
04439 .attr("y", 0)
04440 .attr("width", 2*labelfont.size + 3)
04441 .attr("height", h)
04442 else
04443 r.attr("x", 0).attr("y", 0)
04444 .attr("width", w).attr("height", labelfont.size + 3);
04445 }
04446
04447 this.position = 0;
04448
04449 if ('getBoundingClientRect' in axis_g.node()) {
04450 var rect1 = axis_g.node().getBoundingClientRect(),
04451 rect2 = this.svg_pad().node().getBoundingClientRect();
04452
04453 this.position = rect1.left - rect2.left;
04454 }
04455 }
04456
04457 JSROOT.TAxisPainter.prototype.Redraw = function() {
04458
04459 var gaxis = this.GetObject(),
04460 x1 = Math.round(this.AxisToSvg("x", gaxis.fX1)),
04461 y1 = Math.round(this.AxisToSvg("y", gaxis.fY1)),
04462 x2 = Math.round(this.AxisToSvg("x", gaxis.fX2)),
04463 y2 = Math.round(this.AxisToSvg("y", gaxis.fY2)),
04464 w = x2 - x1, h = y1 - y2;
04465
04466 var name = w<5 ? "yaxis" : "xaxis",
04467 kind = "normal",
04468 func = null,
04469 min = gaxis.fWmin,
04470 max = gaxis.fWmax,
04471 reverse = false;
04472
04473 if (gaxis.fChopt.indexOf("G")>=0) {
04474 func = d3.scale.log();
04475 kind = "log";
04476 } else {
04477 func = d3.scale.linear();
04478 }
04479
04480 func.domain([min, max]);
04481
04482 if (name == "yaxis") {
04483 if (h > 0) {
04484 func.range([h,0]);
04485 } else {
04486 var d = y1; y1 = y2; y2 = d;
04487 h = -h; reverse = true;
04488 func.range([0,h]);
04489 }
04490 } else {
04491 if (w > 0) {
04492 func.range([0,w]);
04493 } else {
04494 var d = x1; x1 = x2; x2 = d;
04495 w = -w; reverse = true;
04496 func.range([w,0]);
04497 }
04498 }
04499
04500 this.SetAxisConfig(name, kind, func, min, max, min, max);
04501
04502 this.RecreateDrawG(true, "text_layer");
04503
04504 this.DrawAxis(this.draw_g, w, h, "translate(" + x1 + "," + y2 +")", reverse);
04505 }
04506
04507
04508 JSROOT.drawGaxis = function(divid, obj, opt) {
04509 var painter = new JSROOT.TAxisPainter(obj, false);
04510
04511 painter.SetDivId(divid);
04512
04513 painter.Redraw();
04514
04515 return painter.DrawingReady();
04516 }
04517
04518
04519
04520
04521 JSROOT.THistPainter = function(histo) {
04522 JSROOT.TObjectPainter.call(this, histo);
04523 this.histo = histo;
04524 this.shrink_frame_left = 0.;
04525 this.draw_content = true;
04526 this.nbinsx = 0;
04527 this.nbinsy = 0;
04528 this.x_kind = 'normal';
04529 this.y_kind = 'normal';
04530 }
04531
04532 JSROOT.THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
04533
04534 JSROOT.THistPainter.prototype.IsDummyHisto = function() {
04535 return (this.histo==null) || !this.draw_content || (this.options.Axis>0);
04536 }
04537
04538 JSROOT.THistPainter.prototype.IsTProfile = function() {
04539 return this.MatchObjectType('TProfile');
04540 }
04541
04542 JSROOT.THistPainter.prototype.IsTH2Poly = function() {
04543 return this.histo && this.histo._typename.match(/^TH2Poly/);
04544 }
04545
04546 JSROOT.THistPainter.prototype.Dimension = function() {
04547 if (!this.histo) return 0;
04548 if (this.histo._typename.indexOf("TH2")==0) return 2;
04549 if (this.histo._typename.indexOf("TH3")==0) return 3;
04550 return 1;
04551 }
04552
04553 JSROOT.THistPainter.prototype.DecodeOptions = function(opt) {
04554
04555 if ((opt == null) || (opt == "")) opt = this.histo['fOption'];
04556
04557
04558 var hdim = this.Dimension();
04559 var option = {
04560 Axis: 0, Bar: 0, Curve: 0, Error: 0, Hist: 0, Line: 0,
04561 Mark: 0, Fill: 0, Same: 0, Scat: 0, Func: 0, Star: 0,
04562 Arrow: 0, Box: 0, Text: 0, Char: 0, Color: 0, Contour: 0,
04563 Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0,
04564 Spec: 0, Pie: 0, List: 0, Zscale: 0, FrontBox: 1, BackBox: 1,
04565 System: JSROOT.Painter.Coord.kCARTESIAN,
04566 AutoColor : 0, NoStat : 0, AutoZoom : false,
04567 HighRes: 0, Zero: 0, Logx: 0, Logy: 0, Logz: 0, Gridx: 0, Gridy: 0,
04568 Palette:0, Optimize:JSROOT.gStyle.OptimizeDraw
04569 };
04570
04571 var chopt = opt.toUpperCase();
04572 chopt = JSROOT.Painter.clearCuts(chopt);
04573
04574
04575
04576
04577 if ((hdim===1) && (this.histo.fSumw2.length > 0))
04578 for (var n=0;n<this.histo.fSumw2.length;++n)
04579 if (this.histo.fSumw2[n] > 0) { option.Error = 2; break; }
04580
04581 if (this.histo.fFunctions !== null) option.Func = 1;
04582
04583 var i = chopt.indexOf('PAL');
04584 if (i>=0) {
04585 var i2 = i+3;
04586 while ((i2<chopt.length) && (chopt.charCodeAt(i2)>=48) && (chopt.charCodeAt(i2)<58)) ++i2;
04587 if (i2>i+3) {
04588 option.Palette = parseInt(chopt.substring(i+3,i2));
04589 chopt = chopt.replace(chopt.substring(i,i2),"");
04590 }
04591 }
04592
04593 if (chopt.indexOf('NOOPTIMIZE') != -1) {
04594 option.Optimize = 0;
04595 chopt = chopt.replace('NOOPTIMIZE', '');
04596 }
04597
04598 if (chopt.indexOf('OPTIMIZE') != -1) {
04599 option.Optimize = 2;
04600 chopt = chopt.replace('OPTIMIZE', '');
04601 }
04602
04603 if (chopt.indexOf('AUTOCOL') != -1) {
04604 option.AutoColor = 1;
04605 option.Hist = 1;
04606 chopt = chopt.replace('AUTOCOL', '');
04607 }
04608 if (chopt.indexOf('AUTOZOOM') != -1) {
04609 option.AutoZoom = 1;
04610 option.Hist = 1;
04611 chopt = chopt.replace('AUTOZOOM', '');
04612 }
04613 if (chopt.indexOf('NOSTAT') != -1) {
04614 option.NoStat = 1;
04615 chopt = chopt.replace('NOSTAT', '');
04616 }
04617 if (chopt.indexOf('LOGX') != -1) {
04618 option.Logx = 1;
04619 chopt = chopt.replace('LOGX', '');
04620 }
04621 if (chopt.indexOf('LOGY') != -1) {
04622 option.Logy = 1;
04623 chopt = chopt.replace('LOGY', '');
04624 }
04625 if (chopt.indexOf('LOGZ') != -1) {
04626 option.Logz = 1;
04627 chopt = chopt.replace('LOGZ', '');
04628 }
04629
04630 chopt = chopt.trim();
04631 while ((chopt.length>0) && (chopt[0]==',' || chopt[0]==';')) chopt = chopt.substr(1);
04632
04633 var nch = chopt.length;
04634 if (!nch) option.Hist = 1;
04635
04636 var l = chopt.indexOf('SPEC');
04637 if (l != -1) {
04638 option.Scat = 0;
04639 chopt = chopt.replace('SPEC', ' ');
04640 var bs = 0;
04641 l = chopt.indexOf('BF(');
04642 if (l != -1) bs = parseInt(chopt)
04643 option.Spec = Math.max(1600, bs);
04644 return option;
04645 }
04646 if (chopt.indexOf('GL') != -1) chopt = chopt.replace('GL', ' ');
04647 if (chopt.indexOf('X+') != -1) {
04648 option.AxisPos = 10;
04649 chopt = chopt.replace('X+', ' ');
04650 }
04651 if (chopt.indexOf('Y+') != -1) {
04652 option.AxisPos += 1;
04653 chopt = chopt.replace('Y+', ' ');
04654 }
04655 if ((option.AxisPos == 10 || option.AxisPos == 1) && (nch == 2))
04656 option.Hist = 1;
04657 if (option.AxisPos == 11 && nch == 4)
04658 option.Hist = 1;
04659 if (chopt.indexOf('SAMES') != -1) {
04660 if (nch == 5) option.Hist = 1;
04661 option.Same = 2;
04662 chopt = chopt.replace('SAMES', ' ');
04663 }
04664 if (chopt.indexOf('SAME') != -1) {
04665 if (nch == 4) option.Hist = 1;
04666 option.Same = 1;
04667 chopt = chopt.replace('SAME', ' ');
04668 }
04669 if (chopt.indexOf('PIE') != -1) {
04670 option.Pie = 1;
04671 chopt = chopt.replace('PIE', ' ');
04672 }
04673 l = chopt.indexOf('LEGO');
04674 if (l != -1) {
04675 option.Scat = 0;
04676 option.Lego = 1;
04677 chopt = chopt.replace('LEGO', ' ');
04678 if (chopt[l + 4] == '1') {
04679 option.Lego = 11;
04680 chopt[l + 4] = ' ';
04681 }
04682 if (chopt[l + 4] == '2') {
04683 option.Lego = 12;
04684 chopt[l + 4] = ' ';
04685 }
04686 if (chopt[l + 4] == '3') {
04687 option.Lego = 13;
04688 chopt[l + 4] = ' ';
04689 }
04690 l = chopt.indexOf('FB');
04691 if (l != -1) {
04692 option.FrontBox = 0;
04693 chopt = chopt.replace('FB', ' ');
04694 }
04695 l = chopt.indexOf('BB');
04696 if (l != -1) {
04697 option.BackBox = 0;
04698 chopt = chopt.replace('BB', ' ');
04699 }
04700 l = chopt.indexOf('0');
04701 if (l != -1) {
04702 option.Zero = 1;
04703 chopt = chopt.replace('0', ' ');
04704 }
04705 }
04706 l = chopt.indexOf('SURF');
04707 if (l != -1) {
04708 option.Scat = 0;
04709 option.Surf = 1;
04710 chopt = chopt.replace('SURF', ' ');
04711 if (chopt[l + 4] == '1') {
04712 option.Surf = 11;
04713 chopt[l + 4] = ' ';
04714 }
04715 if (chopt[l + 4] == '2') {
04716 option.Surf = 12;
04717 chopt[l + 4] = ' ';
04718 }
04719 if (chopt[l + 4] == '3') {
04720 option.Surf = 13;
04721 chopt[l + 4] = ' ';
04722 }
04723 if (chopt[l + 4] == '4') {
04724 option.Surf = 14;
04725 chopt[l + 4] = ' ';
04726 }
04727 if (chopt[l + 4] == '5') {
04728 option.Surf = 15;
04729 chopt[l + 4] = ' ';
04730 }
04731 if (chopt[l + 4] == '6') {
04732 option.Surf = 16;
04733 chopt[l + 4] = ' ';
04734 }
04735 if (chopt[l + 4] == '7') {
04736 option.Surf = 17;
04737 chopt[l + 4] = ' ';
04738 }
04739 l = chopt.indexOf('FB');
04740 if (l != -1) {
04741 option.FrontBox = 0;
04742 chopt = chopt.replace('FB', ' ');
04743 }
04744 l = chopt.indexOf('BB');
04745 if (l != -1) {
04746 option.BackBox = 0;
04747 chopt = chopt.replace('BB', ' ');
04748 }
04749 }
04750 l = chopt.indexOf('TF3');
04751 if (l != -1) {
04752 l = chopt.indexOf('FB');
04753 if (l != -1) {
04754 option.FrontBox = 0;
04755 chopt = chopt.replace('FB', ' ');
04756 }
04757 l = chopt.indexOf('BB');
04758 if (l != -1) {
04759 option.BackBox = 0;
04760 chopt = chopt.replace('BB', ' ');
04761 }
04762 }
04763 l = chopt.indexOf('ISO');
04764 if (l != -1) {
04765 l = chopt.indexOf('FB');
04766 if (l != -1) {
04767 option.FrontBox = 0;
04768 chopt = chopt.replace('FB', ' ');
04769 }
04770 l = chopt.indexOf('BB');
04771 if (l != -1) {
04772 option.BackBox = 0;
04773 chopt = chopt.replace('BB', ' ');
04774 }
04775 }
04776 l = chopt.indexOf('LIST');
04777 if (l != -1) {
04778 option.List = 1;
04779 chopt = chopt.replace('LIST', ' ');
04780 }
04781 l = chopt.indexOf('CONT');
04782 if (l != -1) {
04783 chopt = chopt.replace('CONT', ' ');
04784 if (hdim > 1) {
04785 option.Scat = 0;
04786 option.Contour = 1;
04787 if (chopt[l + 4] == '1') {
04788 option.Contour = 11;
04789 chopt[l + 4] = ' ';
04790 }
04791 if (chopt[l + 4] == '2') {
04792 option.Contour = 12;
04793 chopt[l + 4] = ' ';
04794 }
04795 if (chopt[l + 4] == '3') {
04796 option.Contour = 13;
04797 chopt[l + 4] = ' ';
04798 }
04799 if (chopt[l + 4] == '4') {
04800 option.Contour = 14;
04801 chopt[l + 4] = ' ';
04802 }
04803 if (chopt[l + 4] == '5') {
04804 option.Contour = 15;
04805 chopt[l + 4] = ' ';
04806 }
04807 } else {
04808 option.Hist = 1;
04809 }
04810 }
04811 l = chopt.indexOf('HBAR');
04812 if (l != -1) {
04813 option.Hist = 0;
04814 option.Bar = 20;
04815 chopt = chopt.replace('HBAR', ' ');
04816 if (chopt[l + 4] == '1') {
04817 option.Bar = 21;
04818 chopt[l + 4] = ' ';
04819 }
04820 if (chopt[l + 4] == '2') {
04821 option.Bar = 22;
04822 chopt[l + 4] = ' ';
04823 }
04824 if (chopt[l + 4] == '3') {
04825 option.Bar = 23;
04826 chopt[l + 4] = ' ';
04827 }
04828 if (chopt[l + 4] == '4') {
04829 option.Bar = 24;
04830 chopt[l + 4] = ' ';
04831 }
04832 }
04833 l = chopt.indexOf('BAR');
04834 if (l != -1) {
04835 option.Hist = 0;
04836 option.Bar = 10;
04837 chopt = chopt.replace('BAR', ' ');
04838 if (chopt[l + 3] == '1') {
04839 option.Bar = 11;
04840 chopt[l + 3] = ' ';
04841 }
04842 if (chopt[l + 3] == '2') {
04843 option.Bar = 12;
04844 chopt[l + 3] = ' ';
04845 }
04846 if (chopt[l + 3] == '3') {
04847 option.Bar = 13;
04848 chopt[l + 3] = ' ';
04849 }
04850 if (chopt[l + 3] == '4') {
04851 option.Bar = 14;
04852 chopt[l + 3] = ' ';
04853 }
04854 }
04855 l = chopt.indexOf('ARR');
04856 if (l != -1) {
04857 chopt = chopt.replace('ARR', ' ');
04858 if (hdim > 1) {
04859 option.Arrow = 1;
04860 option.Scat = 0;
04861 } else {
04862 option.Hist = 1;
04863 }
04864 }
04865 l = chopt.indexOf('BOX');
04866 if (l != -1) {
04867 chopt = chopt.replace('BOX', ' ');
04868 if (hdim > 1) {
04869 option.Scat = 0;
04870 option.Box = 1;
04871 if (chopt[l + 3] == '1') {
04872 option.Box = 11;
04873 chopt[l + 3] = ' ';
04874 }
04875 } else {
04876 option.Hist = 1;
04877 }
04878 }
04879
04880 l = chopt.indexOf('COL');
04881 if (l!=-1) {
04882 var name = 'COL';
04883
04884 if (chopt.charAt(l+3)=='0') { option.Color = 111; name += "0"; ++l; } else
04885 if (chopt.charAt(l+3)=='1') { option.Color = 1; name += "1"; ++l; } else
04886 if (chopt.charAt(l+3)=='2') { option.Color = 2; name += "2"; ++l; } else
04887 if (chopt.charAt(l+3)=='3') { option.Color = 3; name += "3"; ++l; } else
04888 option.Color = 1;
04889
04890 if (chopt.charAt(l+4)=='Z') { option.Zscale = 1; name += 'Z'; }
04891 chopt = chopt.replace(name, '');
04892 if (hdim == 1) {
04893 option.Hist = 1;
04894 } else {
04895 option.Scat = 0;
04896 }
04897 }
04898
04899 if (chopt.indexOf('CHAR') != -1) {
04900 option.Char = 1;
04901 chopt = chopt.replace('CHAR', ' ');
04902 option.Scat = 0;
04903 }
04904 l = chopt.indexOf('FUNC');
04905 if (l != -1) {
04906 option.Func = 2;
04907 chopt = chopt.replace('FUNC', ' ');
04908 option.Hist = 0;
04909 }
04910 l = chopt.indexOf('HIST');
04911 if (l != -1) {
04912 option.Hist = 2;
04913 chopt = chopt.replace('HIST', ' ');
04914 option.Func = 0;
04915 option.Error = 0;
04916 }
04917 if (chopt.indexOf('AXIS') != -1) {
04918 option.Axis = 1;
04919 chopt = chopt.replace('AXIS', ' ');
04920 }
04921 if (chopt.indexOf('AXIG') != -1) {
04922 option.Axis = 2;
04923 chopt = chopt.replace('AXIG', ' ');
04924 }
04925 if (chopt.indexOf('TEXT') != -1) {
04926 var angle = parseInt(chopt);
04927 if (!isNaN(angle)) {
04928 if (angle < 0)
04929 angle = 0;
04930 if (angle > 90)
04931 angle = 90;
04932 option.Text = 1000 + angle;
04933 } else {
04934 option.Text = 1;
04935 }
04936 chopt = chopt.replace('TEXT', ' ');
04937 l = chopt.indexOf('N');
04938 if (l != -1 && this.IsTH2Poly())
04939 option.Text += 3000;
04940 option.Scat = 0;
04941 }
04942 if (chopt.indexOf('SCAT') != -1) {
04943 option.Scat = 1;
04944 chopt = chopt.replace('SCAT', ' ');
04945 }
04946 if (chopt.indexOf('POL') != -1) {
04947 option.System = JSROOT.Painter.Coord.kPOLAR;
04948 chopt = chopt.replace('POL', ' ');
04949 }
04950 if (chopt.indexOf('CYL') != -1) {
04951 option.System = JSROOT.Painter.Coord.kCYLINDRICAL;
04952 chopt = chopt.replace('CYL', ' ');
04953 }
04954 if (chopt.indexOf('SPH') != -1) {
04955 option.System = JSROOT.Painter.Coord.kSPHERICAL;
04956 chopt = chopt.replace('SPH', ' ');
04957 }
04958 l = chopt.indexOf('PSR');
04959 if (l != -1) {
04960 option.System = JSROOT.Painter.Coord.kRAPIDITY;
04961 chopt = chopt.replace('PSR', ' ');
04962 }
04963 l = chopt.indexOf('TRI');
04964 if (l != -1) {
04965 option.Scat = 0;
04966 option.Color = 0;
04967 option.Tri = 1;
04968 chopt = chopt.replace('TRI', ' ');
04969 l = chopt.indexOf('FB');
04970 if (l != -1) {
04971 option.FrontBox = 0;
04972 chopt = chopt.replace('FB', ' ');
04973 }
04974 l = chopt.indexOf('BB');
04975 if (l != -1) {
04976 option.BackBox = 0;
04977 chopt = chopt.replace('BB', ' ');
04978 }
04979 l = chopt.indexOf('ERR');
04980 if (l != -1)
04981 chopt = chopt.replace('ERR', ' ');
04982 }
04983 l = chopt.indexOf('AITOFF');
04984 if (l != -1) {
04985 option.Proj = 1;
04986 chopt = chopt.replace('AITOFF', ' ');
04987 }
04988 l = chopt.indexOf('MERCATOR');
04989 if (l != -1) {
04990 option.Proj = 2;
04991 chopt = chopt.replace('MERCATOR', ' ');
04992 }
04993 l = chopt.indexOf('SINUSOIDAL');
04994 if (l != -1) {
04995 option.Proj = 3;
04996 chopt = chopt.replace('SINUSOIDAL', ' ');
04997 }
04998 l = chopt.indexOf('PARABOLIC');
04999 if (l != -1) {
05000 option.Proj = 4;
05001 chopt = chopt.replace('PARABOLIC', ' ');
05002 }
05003 if (option.Proj > 0) {
05004 option.Scat = 0;
05005 option.Contour = 14;
05006 }
05007 if (chopt.indexOf('A') != -1)
05008 option.Axis = -1;
05009 if (chopt.indexOf('B') != -1)
05010 option.Bar = 1;
05011 if (chopt.indexOf('C') != -1) {
05012 option.Curve = 1;
05013 option.Hist = -1;
05014 }
05015 if (chopt.indexOf('F') != -1)
05016 option.Fill = 1;
05017 if (chopt.indexOf('][') != -1) {
05018 option.Off = 1;
05019 option.Hist = 1;
05020 }
05021 if (chopt.indexOf('F2') != -1) option.Fill = 2;
05022 if (chopt.indexOf('L') != -1) {
05023 option.Line = 1;
05024 option.Hist = -1;
05025 }
05026
05027 if (chopt.indexOf('P') != -1) {
05028 option.Mark = 1;
05029 option.Hist = -1;
05030 if (chopt.indexOf('P0') != -1) option.Mark = 10;
05031 }
05032 if (chopt.indexOf('Z') != -1) option.Zscale = 1;
05033 if (chopt.indexOf('*') != -1) option.Star = 1;
05034 if (chopt.indexOf('H') != -1) option.Hist = 2;
05035 if (this.IsTH2Poly()) {
05036 if (option.Fill + option.Line + option.Mark != 0) option.Scat = 0;
05037 }
05038
05039 if (chopt.indexOf('E') != -1) {
05040 if (hdim == 1) {
05041 option.Error = 1;
05042 if (chopt.indexOf('E0') != -1) option.Error = 10;
05043 if (chopt.indexOf('E1') != -1) option.Error = 11;
05044 if (chopt.indexOf('E2') != -1) option.Error = 12;
05045 if (chopt.indexOf('E3') != -1) option.Error = 13;
05046 if (chopt.indexOf('E4') != -1) option.Error = 14;
05047 if (chopt.indexOf('E5') != -1) option.Error = 15;
05048 if (chopt.indexOf('E6') != -1) option.Error = 16;
05049 if (chopt.indexOf('X0') != -1) {
05050 if (option.Error == 1) option.Error += 20;
05051 option.Error += 10;
05052 }
05053 if (option.Text && this.IsTProfile()) {
05054 option.Text += 2000;
05055 option.Error = 0;
05056 }
05057 } else {
05058 if (option.Error == 0) {
05059 option.Error = 100;
05060 option.Scat = 0;
05061 }
05062 if (option.Text) {
05063 option.Text += 2000;
05064 option.Error = 0;
05065 }
05066 }
05067 }
05068 if (chopt.indexOf('9') != -1) option.HighRes = 1;
05069 if (option.Surf == 15) {
05070 if (option.System == JSROOT.Painter.Coord.kPOLAR
05071 || option.System == JSROOT.Painter.Coord.kCARTESIAN) {
05072 option.Surf = 13;
05073
05074
05075 }
05076 }
05077
05078
05079 if (option.Bar == 1) option.Hist = -1;
05080
05081 return option;
05082 }
05083
05084 JSROOT.THistPainter.prototype.GetAutoColor = function(col) {
05085 if (this.options.AutoColor<=0) return col;
05086
05087 var id = this.options.AutoColor;
05088 this.options.AutoColor = id % 8 + 1;
05089 return JSROOT.Painter.root_colors[id];
05090 }
05091
05092 JSROOT.THistPainter.prototype.ScanContent = function() {
05093
05094
05095
05096
05097 alert("HistPainter.prototype.ScanContent not implemented");
05098 }
05099
05100 JSROOT.THistPainter.prototype.CheckPadOptions = function() {
05101
05102 this.fillatt = this.createAttFill(this.histo, undefined, undefined, 1);
05103
05104 this.lineatt = JSROOT.Painter.createAttLine(this.histo);
05105 var main = this.main_painter();
05106 if (main!==null) this.lineatt.color = main.GetAutoColor(this.lineatt.color);
05107
05108 var pad = this.root_pad();
05109
05110 if (pad!=null) {
05111
05112 this.options.Logx = pad.fLogx;
05113 this.options.Logy = pad.fLogy;
05114 this.options.Logz = pad.fLogz;
05115 this.options.Gridx = pad.fGridx;
05116 this.options.Gridy = pad.fGridy;
05117 }
05118
05119 if (this.main_painter() !== this) return;
05120
05121 this.zoom_xmin = this.zoom_xmax = 0;
05122 this.zoom_ymin = this.zoom_ymax = 0;
05123 this.zoom_zmin = this.zoom_zmax = 0;
05124
05125 if ((pad==null) || !('fUxmin' in pad) || this.create_canvas) return;
05126
05127 var min = pad.fUxmin, max = pad.fUxmax;
05128
05129
05130 if ((this.Dimension() < 3) && ((min !== 0) || (max !== 1))) {
05131 if (pad.fLogx > 0) {
05132 min = Math.exp(min * Math.log(10));
05133 max = Math.exp(max * Math.log(10));
05134 }
05135
05136 if (min !== this.histo.fXaxis.fXmin || max !== this.histo.fXaxis.fXmax)
05137 if (min >= this.histo.fXaxis.fXmin && max <= this.histo.fXaxis.fXmax) {
05138
05139 this.zoom_xmin = min;
05140 this.zoom_xmax = max;
05141 }
05142 }
05143
05144 min = pad.fUymin; max = pad.fUymax;
05145
05146 if ((this.Dimension() == 2) && ((min !== 0) || (max !== 1))) {
05147 if (pad.fLogy > 0) {
05148 min = Math.exp(min * Math.log(10));
05149 max = Math.exp(max * Math.log(10));
05150 }
05151
05152 if (min !== this.histo.fYaxis.fXmin || max !== this.histo.fYaxis.fXmax)
05153 if (min >= this.histo.fYaxis.fXmin && max <= this.histo.fYaxis.fXmax) {
05154
05155 this.zoom_ymin = min;
05156 this.zoom_ymax = max;
05157 }
05158 }
05159 }
05160
05161 JSROOT.THistPainter.prototype.UpdateObject = function(obj) {
05162 if (!this.MatchObjectType(obj)) {
05163 alert("JSROOT.THistPainter.UpdateObject - wrong class " + obj._typename + " expected " + this.histo._typename);
05164 return false;
05165 }
05166
05167
05168
05169
05170
05171
05172
05173
05174 var histo = this.GetObject();
05175
05176 histo.fEntries = obj.fEntries;
05177 histo.fTsumw = obj.fTsumw;
05178 histo.fTsumwx = obj.fTsumwx;
05179 histo.fTsumwx2 = obj.fTsumwx2;
05180 if (this.Dimension() == 2) {
05181 histo.fTsumwy = obj.fTsumwy;
05182 histo.fTsumwy2 = obj.fTsumwy2;
05183 histo.fTsumwxy = obj.fTsumwxy;
05184 }
05185 histo.fArray = obj.fArray;
05186 histo.fNcells = obj.fNcells;
05187 histo.fTitle = obj.fTitle;
05188 histo.fMinimum = obj.fMinimum;
05189 histo.fMaximum = obj.fMaximum;
05190 histo.fXaxis.fNbins = obj.fXaxis.fNbins;
05191 histo.fXaxis.fXmin = obj.fXaxis.fXmin;
05192 histo.fXaxis.fXmax = obj.fXaxis.fXmax;
05193 histo.fYaxis.fXmin = obj.fYaxis.fXmin;
05194 histo.fYaxis.fXmax = obj.fYaxis.fXmax;
05195 histo.fSumw2 = obj.fSumw2;
05196
05197 if (this.IsTProfile()) {
05198 histo.fBinEntries = obj.fBinEntries;
05199 }
05200
05201 this.ScanContent();
05202
05203 return true;
05204 }
05205
05206 JSROOT.THistPainter.prototype.CreateAxisFuncs = function(with_y_axis, with_z_axis) {
05207
05208
05209
05210 this.xmin = this.histo.fXaxis.fXmin;
05211 this.xmax = this.histo.fXaxis.fXmax;
05212
05213 if (this.histo.fXaxis.fXbins.length == this.nbinsx+1) {
05214 this.regularx = false;
05215 this.GetBinX = function(bin) {
05216 var indx = Math.round(bin);
05217 if (indx <= 0) return this.xmin;
05218 if (indx > this.nbinsx) this.xmax;
05219 if (indx==bin) return this.histo.fXaxis.fXbins[indx];
05220 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
05221 return this.histo.fXaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fXaxis.fXbins[indx2] * Math.abs(bin-indx);
05222 };
05223 this.GetIndexX = function(x,add) {
05224 for (var k = 1; k < this.histo.fXaxis.fXbins.length; ++k)
05225 if (x < this.histo.fXaxis.fXbins[k]) return Math.floor(k-1+add);
05226 return this.nbinsx;
05227 };
05228 } else {
05229 this.regularx = true;
05230 this.binwidthx = (this.xmax - this.xmin);
05231 if (this.nbinsx > 0)
05232 this.binwidthx = this.binwidthx / this.nbinsx;
05233
05234 this.GetBinX = function(bin) { return this.xmin + bin*this.binwidthx; };
05235 this.GetIndexX = function(x,add) { return Math.floor((x - this.xmin) / this.binwidthx + add); };
05236 }
05237
05238 this.ymin = this.histo.fYaxis.fXmin;
05239 this.ymax = this.histo.fYaxis.fXmax;
05240
05241 if (!with_y_axis || (this.nbinsy==0)) return;
05242
05243 if (this.histo.fYaxis.fXbins.length == this.nbinsy+1) {
05244 this.regulary = false;
05245 this.GetBinY = function(bin) {
05246 var indx = Math.round(bin);
05247 if (indx <= 0) return this.ymin;
05248 if (indx > this.nbinsy) this.ymax;
05249 if (indx==bin) return this.histo.fYaxis.fXbins[indx];
05250 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
05251 return this.histo.fYaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fYaxis.fXbins[indx2] * Math.abs(bin-indx);
05252 };
05253 this.GetIndexY = function(y,add) {
05254 for (var k = 1; k < this.histo.fYaxis.fXbins.length; ++k)
05255 if (y < this.histo.fYaxis.fXbins[k]) return Math.floor(k-1+add);
05256 return this.nbinsy;
05257 };
05258 } else {
05259 this.regulary = true;
05260 this.binwidthy = (this.ymax - this.ymin);
05261 if (this.nbinsy > 0)
05262 this.binwidthy = this.binwidthy / this.nbinsy;
05263
05264 this.GetBinY = function(bin) { return this.ymin+bin*this.binwidthy; };
05265 this.GetIndexY = function(y,add) { return Math.floor((y - this.ymin) / this.binwidthy + add); };
05266 }
05267
05268 if (!with_z_axis || (this.nbinsz==0)) return;
05269
05270 if (this.histo.fZaxis.fXbins.length == this.nbinsz+1) {
05271 this.regularz = false;
05272 this.GetBinZ = function(bin) {
05273 var indx = Math.round(bin);
05274 if (indx <= 0) return this.zmin;
05275 if (indx > this.nbinsz) this.zmax;
05276 if (indx==bin) return this.histo.fZaxis.fXbins[indx];
05277 var indx2 = (bin < indx) ? indx - 1 : indx + 1;
05278 return this.histo.fZaxis.fXbins[indx] * Math.abs(bin-indx2) + this.histo.fZaxis.fXbins[indx2] * Math.abs(bin-indx);
05279 };
05280 this.GetIndexZ = function(z,add) {
05281 for (var k = 1; k < this.histo.fZaxis.fXbins.length; ++k)
05282 if (z < this.histo.fZaxis.fXbins[k]) return Math.floor(k-1+add);
05283 return this.nbinsz;
05284 };
05285 } else {
05286 this.regularz = true;
05287 this.binwidthz = (this.zmax - this.zmin);
05288 if (this.nbinsz > 0)
05289 this.binwidthz = this.binwidthz / this.nbinsz;
05290
05291 this.GetBinZ = function(bin) { return this.zmin+bin*this.binwidthz; };
05292 this.GetIndexZ = function(z,add) { return Math.floor((z - this.zmin) / this.binwidthz + add); };
05293 }
05294 }
05295
05296
05297 JSROOT.THistPainter.prototype.CreateXY = function() {
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307 if (!this.is_main_painter()) {
05308 this.x = this.main_painter().x;
05309 this.y = this.main_painter().y;
05310 return;
05311 }
05312
05313 var w = this.frame_width(), h = this.frame_height();
05314
05315 if (this.histo.fXaxis.fTimeDisplay) {
05316 this.x_kind = 'time';
05317 this.timeoffsetx = JSROOT.Painter.getTimeOffset(this.histo.fXaxis);
05318 this.ConvertX = function(x) { return new Date(this.timeoffsetx + x*1000); };
05319 this.RevertX = function(grx) { return (this.x.invert(grx) - this.timeoffsetx) / 1000; };
05320 } else {
05321 this.x_kind = (this.histo.fXaxis.fLabels==null) ? 'normal' : 'labels';
05322 this.ConvertX = function(x) { return x; };
05323 this.RevertX = function(grx) { return this.x.invert(grx); };
05324 }
05325
05326 this.scale_xmin = this.xmin;
05327 this.scale_xmax = this.xmax;
05328 if (this.zoom_xmin != this.zoom_xmax) {
05329 this.scale_xmin = this.zoom_xmin;
05330 this.scale_xmax = this.zoom_xmax;
05331 }
05332 if (this.x_kind == 'time') {
05333 this.x = d3.time.scale();
05334 } else
05335 if (this.options.Logx) {
05336 if (this.scale_xmax <= 0) this.scale_xmax = 0;
05337
05338 if ((this.scale_xmin <= 0) && (this.nbinsx>0))
05339 for (var i=0;i<this.nbinsx;++i) {
05340 this.scale_xmin = Math.max(this.scale_xmin, this.GetBinX(i));
05341 if (this.scale_xmin>0) break;
05342 }
05343
05344 if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) {
05345 this.scale_xmin = this.scale_xmax * 0.0001;
05346 }
05347
05348 this.x = d3.scale.log();
05349 } else {
05350 this.x = d3.scale.linear();
05351 }
05352
05353 this.x.domain([this.ConvertX(this.scale_xmin), this.ConvertX(this.scale_xmax)]).range([ 0, w ]);
05354
05355 if (this.x_kind == 'time') {
05356
05357 this.grx = function(val) { return this.x(this.ConvertX(val)); }
05358 } else
05359 if (this.options.Logx) {
05360 this.grx = function(val) { return (val < this.scale_xmin) ? -5 : this.x(val); }
05361 } else {
05362 this.grx = this.x;
05363 }
05364
05365 this.scale_ymin = this.ymin;
05366 this.scale_ymax = this.ymax;
05367 if (this.zoom_ymin != this.zoom_ymax) {
05368 this.scale_ymin = this.zoom_ymin;
05369 this.scale_ymax = this.zoom_ymax;
05370 }
05371
05372 if (this.histo.fYaxis.fTimeDisplay) {
05373 this.y_kind = 'time';
05374 this.timeoffsety = JSROOT.Painter.getTimeOffset(this.histo.fYaxis);
05375 this.ConvertY = function(y) { return new Date(this.timeoffsety + y*1000); };
05376 this.RevertY = function(gry) { return (this.y.invert(gry) - this.timeoffsety) / 1000; };
05377 } else {
05378 this.y_kind = ((this.Dimension()==2) && (this.histo.fYaxis.fLabels!=null)) ? 'labels' : 'normal';
05379 this.ConvertY = function(y) { return y; };
05380 this.RevertY = function(gry) { return this.y.invert(gry); };
05381 }
05382
05383 if (this.options.Logy) {
05384 if (this.scale_ymax <= 0)
05385 this.scale_ymax = 1;
05386 else
05387 if ((this.zoom_ymin === this.zoom_ymax) && (this.Dimension()==1))
05388 this.scale_ymax*=1.8;
05389
05390 if ((this.scale_ymin <= 0) && (this.nbinsy>0))
05391 for (var i=0;i<this.nbinsy;++i) {
05392 this.scale_ymin = Math.max(this.scale_ymin, this.GetBinY(i));
05393 if (this.scale_ymin>0) break;
05394 }
05395
05396 if ((this.scale_ymin <= 0) && ('ymin_nz' in this) && (this.ymin_nz > 0))
05397 this.scale_ymin = 0.3*this.ymin_nz;
05398
05399 if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax))
05400 this.scale_ymin = 0.000001 * this.scale_ymax;
05401 this.y = d3.scale.log();
05402 } else
05403 if (this.y_kind=='time') {
05404 this.y = d3.time.scale();
05405 } else {
05406 this.y = d3.scale.linear()
05407 }
05408
05409 this.y.domain([ this.ConvertY(this.scale_ymin), this.ConvertY(this.scale_ymax) ]).range([ h, 0 ]);
05410
05411 if (this.y_kind=='time') {
05412
05413 this.gry = function(val) { return this.y(this.ConvertY(val)); }
05414 } else
05415 if (this.options.Logy) {
05416
05417 this.gry = function(val) { return (val < this.scale_ymin) ? h+5 : this.y(val); }
05418 } else {
05419 this.gry = this.y;
05420 }
05421 }
05422
05423 JSROOT.THistPainter.prototype.DrawGrids = function() {
05424
05425 if (!this.is_main_painter()) return;
05426
05427 var layer = this.svg_frame().select(".grid_layer");
05428
05429 layer.selectAll(".xgrid").remove();
05430 layer.selectAll(".ygrid").remove();
05431
05432
05433
05434 if (this.options.Gridx && this.x_handle) {
05435
05436 var h = this.frame_height();
05437
05438 layer.selectAll(".xgrid")
05439 .data(this.x_handle.ticks).enter()
05440 .append("svg:line")
05441 .attr("class", "xgrid")
05442 .attr("x1", function(d) { return d; })
05443 .attr("y1", h)
05444 .attr("x2", function(d) { return d; })
05445 .attr("y2",0)
05446 .style("stroke", "black")
05447 .style("stroke-width", 1)
05448 .style("stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
05449 }
05450
05451
05452 if (this.options.Gridy && this.y_handle) {
05453 var w = this.frame_width();
05454
05455 layer.selectAll('.ygrid')
05456 .data(this.y_handle.ticks).enter()
05457 .append("svg:line")
05458 .attr("class", "ygrid")
05459 .attr("x1", 0)
05460 .attr("y1", function(d) { return d; })
05461 .attr("x2", w)
05462 .attr("y2", function(d) { return d; })
05463 .style("stroke", "black")
05464 .style("stroke-width", 1)
05465 .style("stroke-dasharray", JSROOT.Painter.root_line_styles[11]);
05466 }
05467 }
05468
05469 JSROOT.THistPainter.prototype.DrawBins = function() {
05470 alert("HistPainter.DrawBins not implemented");
05471 }
05472
05473 JSROOT.THistPainter.prototype.AxisAsText = function(axis, value) {
05474 if (axis == "x") {
05475 if (this.x_kind == 'time')
05476 value = this.ConvertX(value);
05477
05478 if (this.x_handle!==null)
05479 if ('format' in this.x_handle)
05480 return this.x_handle.format(value);
05481
05482 return value.toPrecision(4);
05483 }
05484
05485 if (axis == "y") {
05486 if (this.y_kind == 'time')
05487 value = this.ConvertY(value);
05488
05489 if (this.y_handle!==null)
05490 if ('format' in this.y_handle)
05491 return this.y_handle.format(value);
05492
05493 return value.toPrecision(4);
05494 }
05495
05496 return value.toPrecision(4);
05497 }
05498
05499 JSROOT.THistPainter.prototype.DrawAxes = function(shrink_forbidden) {
05500
05501
05502 if (!this.is_main_painter()) return;
05503
05504 var layer = this.svg_frame().select(".axis_layer"),
05505 w = this.frame_width(),
05506 h = this.frame_height();
05507
05508 this.x_handle = new JSROOT.TAxisPainter(this.histo.fXaxis, true);
05509 this.x_handle.SetDivId(this.divid, -1);
05510
05511 this.x_handle.SetAxisConfig("xaxis",
05512 (this.options.Logx && this.x_kind !== "time") ? "log" : this.x_kind,
05513 this.x, this.xmin, this.xmax, this.scale_xmin, this.scale_xmax);
05514
05515 this.x_handle.DrawAxis(layer, w, h, "translate(0," + h + ")");
05516
05517 this.y_handle = new JSROOT.TAxisPainter(this.histo.fYaxis, true);
05518 this.y_handle.SetDivId(this.divid, -1);
05519
05520 this.y_handle.SetAxisConfig("yaxis",
05521 (this.options.Logy && this.y_kind !== "time") ? "log" : this.y_kind,
05522 this.y, this.ymin, this.ymax, this.scale_ymin, this.scale_ymax);
05523
05524 this.y_handle.DrawAxis(layer, w, h);
05525
05526 if (shrink_forbidden) return;
05527
05528 var shrink = 0., ypos = this.y_handle.position;
05529
05530 if (ypos < 0) {
05531 shrink = -ypos/w + 0.001;
05532 this.shrink_frame_left += shrink;
05533 } else
05534 if ((this.shrink_frame_left > 0) && (ypos/w > this.shrink_frame_left)) {
05535 shrink = -this.shrink_frame_left;
05536 this.shrink_frame_left = 0.;
05537 }
05538
05539 if (shrink != 0) {
05540 this.frame_painter().Shrink(shrink, 0);
05541 this.frame_painter().Redraw();
05542 this.CreateXY();
05543 this.DrawAxes(true);
05544 }
05545 }
05546
05547 JSROOT.THistPainter.prototype.DrawTitle = function() {
05548
05549
05550 if (!this.is_main_painter()) return;
05551
05552 var tpainter = this.FindPainterFor(null, "title");
05553 var pavetext = (tpainter !== null) ? tpainter.GetObject() : null;
05554 if (pavetext === null) pavetext = this.FindInPrimitives("title");
05555 if ((pavetext !== null) && (pavetext._typename !== "TPaveText")) pavetext = null;
05556
05557 var draw_title = !this.histo.TestBit(JSROOT.TH1StatusBits.kNoTitle);
05558
05559 if (pavetext !== null) {
05560 pavetext.Clear();
05561 if (draw_title)
05562 pavetext.AddText(this.histo.fTitle);
05563 } else
05564 if (draw_title && (tpainter === null)) {
05565 pavetext = JSROOT.Create("TPaveText");
05566
05567 JSROOT.extend(pavetext, { fName: "title", fX1NDC: 0.28, fY1NDC: 0.94, fX2NDC: 0.72, fY2NDC: 0.99 } );
05568 pavetext.AddText(this.histo.fTitle);
05569
05570 JSROOT.Painter.drawPaveText(this.divid, pavetext);
05571 }
05572 }
05573
05574 JSROOT.THistPainter.prototype.ToggleStat = function(arg) {
05575
05576 var stat = this.FindStat(), statpainter = null;
05577
05578 if (stat == null) {
05579 if (arg=='only-check') return false;
05580
05581 stat = this.CreateStat();
05582 } else {
05583 statpainter = this.FindPainterFor(stat);
05584 }
05585
05586 if (arg=='only-check') return statpainter ? statpainter.Enabled : false;
05587
05588 if (statpainter) {
05589 statpainter.Enabled = !statpainter.Enabled;
05590
05591
05592 statpainter.Redraw();
05593 return statpainter.Enabled;
05594 }
05595
05596 JSROOT.draw(this.divid, stat, "onpad:" + this.pad_name);
05597
05598 return true;
05599 }
05600
05601 JSROOT.THistPainter.prototype.IsAxisZoomed = function(axis) {
05602 var obj = this.main_painter();
05603 if (obj == null) obj = this;
05604 if (axis === "x") return obj.zoom_xmin != obj.zoom_xmax;
05605 if (axis === "y") return obj.zoom_ymin != obj.zoom_ymax;
05606 return false;
05607 }
05608
05609 JSROOT.THistPainter.prototype.GetSelectIndex = function(axis, size, add) {
05610
05611 var indx = 0, obj = this.main_painter();
05612 if (obj == null) obj = this;
05613 var nbin = this['nbins'+axis];
05614 if (!nbin) nbin = 0;
05615 if (!add) add = 0;
05616
05617 var func = 'GetIndex' + axis.toUpperCase(),
05618 min = obj['zoom_' + axis + 'min'],
05619 max = obj['zoom_' + axis + 'max'];
05620
05621 if ((min != max) && (func in this)) {
05622 if (size == "left") {
05623 indx = this[func](min, add);
05624 } else {
05625 indx = this[func](max, add + 0.5);
05626 }
05627 } else {
05628 indx = (size == "left") ? 0 : nbin;
05629 }
05630
05631 var taxis;
05632 if (this.histo) taxis = this.histo["f" + axis.toUpperCase() + "axis"];
05633 if (taxis) {
05634 if ((taxis.fFirst === taxis.fLast) || !taxis.TestBit(JSROOT.EAxisBits.kAxisRange) ||
05635 ((taxis.fFirst<=1) && (taxis.fLast>=nbin))) taxis = undefined;
05636 }
05637
05638 if (size == "left") {
05639 if (indx < 0) indx = 0;
05640 if (taxis && taxis.fFirst>1 && (indx<taxis.fFirst)) indx = taxis.fFirst-1;
05641 } else {
05642 if (indx > nbin) indx = nbin;
05643 if (taxis && (taxis.fLast <= nbin) && (indx>taxis.fLast)) indx = taxis.fLast;
05644 }
05645
05646 return indx;
05647 }
05648
05649 JSROOT.THistPainter.prototype.FindStat = function() {
05650 if (this.histo.fFunctions !== null)
05651 for (var i = 0; i < this.histo.fFunctions.arr.length; ++i) {
05652 var func = this.histo.fFunctions.arr[i];
05653
05654 if ((func._typename == 'TPaveStats') &&
05655 (func.fName == 'stats')) return func;
05656 }
05657
05658 return null;
05659 }
05660
05661 JSROOT.THistPainter.prototype.CreateStat = function() {
05662
05663 if (!this.draw_content) return null;
05664
05665 var stats = this.FindStat();
05666 if (stats != null) return stats;
05667
05668 stats = JSROOT.Create('TPaveStats');
05669 JSROOT.extend(stats, { fName : 'stats',
05670 fOptStat: JSROOT.gStyle.OptStat,
05671 fOptFit: JSROOT.gStyle.OptFit,
05672 fBorderSize : 1} );
05673 JSROOT.extend(stats, JSROOT.gStyle.StatNDC);
05674 JSROOT.extend(stats, JSROOT.gStyle.StatText);
05675 JSROOT.extend(stats, JSROOT.gStyle.StatFill);
05676
05677 if (this.histo._typename.match(/^TProfile/) || this.histo._typename.match(/^TH2/))
05678 stats.fY1NDC = 0.67;
05679
05680 stats.AddText(this.histo.fName);
05681
05682 if (this.histo.fFunctions === null)
05683 this.histo.fFunctions = JSROOT.Create("TList");
05684
05685 this.histo.fFunctions.Add(stats,"");
05686
05687 return stats;
05688 }
05689
05690 JSROOT.THistPainter.prototype.FindF1 = function() {
05691
05692 if (this.histo.fFunctions == null) return null;
05693 for (var i = 0; i < this.histo.fFunctions.arr.length; ++i) {
05694 var func = this.histo.fFunctions.arr[i];
05695 if (func._typename == 'TF1') return func;
05696 }
05697 return null;
05698 }
05699
05700 JSROOT.THistPainter.prototype.DrawNextFunction = function(indx, callback) {
05701
05702
05703 if (this.options.Same || (this.histo.fFunctions === null) || (indx >= this.histo.fFunctions.arr.length))
05704 return JSROOT.CallBack(callback);
05705
05706 var func = this.histo.fFunctions.arr[indx],
05707 opt = this.histo.fFunctions.opt[indx],
05708 do_draw = false,
05709 func_painter = this.FindPainterFor(func);
05710
05711
05712
05713 if (func_painter === null) {
05714 if (func._typename == 'TPaveText' || func._typename == 'TPaveStats') {
05715 do_draw = !this.histo.TestBit(JSROOT.TH1StatusBits.kNoStats) && (this.options.NoStat!=1);
05716 } else
05717 if (func._typename == 'TF1') {
05718 do_draw = !func.TestBit(JSROOT.BIT(9));
05719 } else
05720 do_draw = true;
05721 } else
05722 if (('CompleteDraw' in func_painter) && (typeof func_painter.CompleteDraw == 'function'))
05723 func_painter.CompleteDraw();
05724
05725 if (do_draw) {
05726 var painter = JSROOT.draw(this.divid, func, opt);
05727 if (painter) return painter.WhenReady(this.DrawNextFunction.bind(this, indx+1, callback));
05728 }
05729
05730 this.DrawNextFunction(indx+1, callback);
05731 }
05732
05733 JSROOT.THistPainter.prototype.UnzoomUserRange = function(dox, doy, doz) {
05734
05735 if (!this.histo) return false;
05736
05737 function UnzoomTAxis(obj) {
05738 if (!obj) return false;
05739 if (!obj.TestBit(JSROOT.EAxisBits.kAxisRange)) return false;
05740 if (obj.fFirst === obj.fLast) return false;
05741 if ((obj.fFirst <= 1) && (obj.fLast >= obj.fNbins)) return false;
05742 obj.InvertBit(JSROOT.EAxisBits.kAxisRange);
05743 return true;
05744 }
05745
05746 var res = false;
05747
05748 if (dox) res |= UnzoomTAxis(this.histo.fXaxis);
05749 if (doy) res |= UnzoomTAxis(this.histo.fYaxis);
05750 if (doz) res |= UnzoomTAxis(this.histo.fZaxis);
05751
05752 return res;
05753 }
05754
05755 JSROOT.THistPainter.prototype.ToggleLog = function(axis) {
05756 var obj = this.main_painter();
05757 if (!obj) obj = this;
05758
05759 var curr = obj.options["Log" + axis];
05760
05761 if (!curr && (this[axis+"_kind"] == "labels")) return;
05762 obj.options["Log" + axis] = curr ? 0 : 1;
05763 obj.RedrawPad();
05764 }
05765
05766 JSROOT.THistPainter.prototype.Zoom = function(xmin, xmax, ymin, ymax, zmin, zmax) {
05767
05768
05769
05770 var main = this.main_painter(),
05771 zoom_x = (xmin !== xmax), zoom_y = (ymin !== ymax), zoom_z = (zmin !== zmax),
05772 unzoom_x = false, unzoom_y = false, unzoom_z = false;
05773
05774 if (zoom_x) {
05775 var cnt = 0;
05776 if (xmin <= main.xmin) { xmin = main.xmin; cnt++; }
05777 if (xmax >= main.xmax) { xmax = main.xmax; cnt++; }
05778 if (cnt === 2) { zoom_x = false; unzoom_x = true; }
05779 } else {
05780 unzoom_x = (xmin === xmax) && (xmin === 0);
05781 }
05782
05783 if (zoom_y) {
05784 var cnt = 0;
05785 if (ymin <= main.ymin) { ymin = main.ymin; cnt++; }
05786 if (ymax >= main.ymax) { ymax = main.ymax; cnt++; }
05787 if (cnt === 2) { zoom_y = false; unzoom_y = true; }
05788 } else {
05789 unzoom_y = (ymin === ymax) && (ymin === 0);
05790 }
05791
05792 if (zoom_z) {
05793 var cnt = 0;
05794 if (zmin <= main.zmin) { zmin = main.zmin; cnt++; }
05795 if (zmax >= main.zmax) { zmax = main.zmax; cnt++; }
05796 if (cnt === 2) { zoom_z = false; unzoom_z = true; }
05797 } else {
05798 unzoom_z = (zmin === zmax) && (zmin === 0);
05799 }
05800
05801 var changed = false;
05802
05803
05804 if (zoom_x || zoom_y || zoom_z)
05805 main.ForEachPainter(function(obj) {
05806 if (zoom_x && obj.CanZoomIn("x", xmin, xmax)) {
05807 main.zoom_xmin = xmin;
05808 main.zoom_xmax = xmax;
05809 changed = true;
05810 zoom_x = false;
05811 }
05812 if (zoom_y && obj.CanZoomIn("y", ymin, ymax)) {
05813 main.zoom_ymin = ymin;
05814 main.zoom_ymax = ymax;
05815 changed = true;
05816 zoom_y = false;
05817 }
05818 if (zoom_z && obj.CanZoomIn("z", zmin, zmax)) {
05819 main.zoom_zmin = zmin;
05820 main.zoom_zmax = zmax;
05821 changed = true;
05822 zoom_z = false;
05823 }
05824 });
05825
05826
05827 if (unzoom_x || unzoom_y || unzoom_z) {
05828 if (unzoom_x) {
05829 if (main.zoom_xmin !== main.zoom_xmax) changed = true;
05830 main.zoom_xmin = main.zoom_xmax = 0;
05831 }
05832 if (unzoom_y) {
05833 if (main.zoom_ymin !== main.zoom_ymax) changed = true;
05834 main.zoom_ymin = main.zoom_ymax = 0;
05835 }
05836 if (unzoom_z) {
05837 if (main.zoom_zmin !== main.zoom_zmax) changed = true;
05838 main.zoom_zmin = main.zoom_zmax = 0;
05839 }
05840
05841
05842 if (!changed) {
05843 changed = main.UnzoomUserRange(unzoom_x, unzoom_y, unzoom_z);
05844
05845
05846 var pp = this.pad_painter(true);
05847 if (pp && pp.painters)
05848 pp.painters.forEach(function(paint){
05849 if (paint && (paint!==main) && (typeof paint.UnzoomUserRange == 'function'))
05850 if (paint.UnzoomUserRange(unzoom_x, unzoom_y, unzoom_z)) changed = true;
05851 });
05852 }
05853 }
05854
05855 if (changed) this.RedrawPad();
05856
05857 return changed;
05858 }
05859
05860 JSROOT.THistPainter.prototype.Unzoom = function(dox, doy, doz) {
05861 if (typeof dox === 'undefined') { dox = true; doy = true; doz = true; } else
05862 if (typeof dox === 'string') { doz = dox.indexOf("z")>=0; doy = dox.indexOf("y")>=0; dox = dox.indexOf("x")>=0; }
05863
05864 return this.Zoom(dox ? 0 : undefined, dox ? 0 : undefined,
05865 doy ? 0 : undefined, doy ? 0 : undefined,
05866 doz ? 0 : undefined, doz ? 0 : undefined);
05867 }
05868
05869 JSROOT.THistPainter.prototype.clearInteractiveElements = function() {
05870 JSROOT.Painter.closeMenu();
05871 if (this.zoom_rect != null) { this.zoom_rect.remove(); this.zoom_rect = null; }
05872 this.zoom_kind = 0;
05873
05874
05875 this.SwitchTooltip(true);
05876 }
05877
05878 JSROOT.THistPainter.prototype.mouseDoubleClick = function() {
05879 d3.event.preventDefault();
05880 var m = d3.mouse(this.svg_frame().node());
05881 this.clearInteractiveElements();
05882 var kind = "xyz";
05883 if (m[0] < 0) kind = "y"; else
05884 if (m[1] > this.frame_height()) kind = "x";
05885 this.Unzoom(kind);
05886 }
05887
05888 JSROOT.THistPainter.prototype.startRectSel = function() {
05889
05890
05891 if (this.zoom_kind > 100) return;
05892
05893
05894 if ((d3.event.which || d3.event.button) !== 1) return;
05895
05896 d3.event.preventDefault();
05897
05898 this.clearInteractiveElements();
05899 this.zoom_origin = d3.mouse(this.svg_frame().node());
05900
05901 this.zoom_curr = [ Math.max(0, Math.min(this.frame_width(), this.zoom_origin[0])),
05902 Math.max(0, Math.min(this.frame_height(), this.zoom_origin[1])) ];
05903
05904 if (this.zoom_origin[0] < 0) {
05905 this.zoom_kind = 3;
05906 this.zoom_origin[0] = 0;
05907 this.zoom_origin[1] = this.zoom_curr[1];
05908 this.zoom_curr[0] = this.frame_width();
05909 this.zoom_curr[1] += 1;
05910 } else if (this.zoom_origin[1] > this.frame_height()) {
05911 this.zoom_kind = 2;
05912 this.zoom_origin[0] = this.zoom_curr[0];
05913 this.zoom_origin[1] = 0;
05914 this.zoom_curr[0] += 1;
05915 this.zoom_curr[1] = this.frame_height();
05916 } else {
05917 this.zoom_kind = 1;
05918 this.zoom_origin[0] = this.zoom_curr[0];
05919 this.zoom_origin[1] = this.zoom_curr[1];
05920 }
05921
05922 d3.select(window).on("mousemove.zoomRect", this.moveRectSel.bind(this))
05923 .on("mouseup.zoomRect", this.endRectSel.bind(this), true);
05924
05925 this.zoom_rect = null;
05926
05927
05928 this.SwitchTooltip(false);
05929
05930 d3.event.stopPropagation();
05931 }
05932
05933 JSROOT.THistPainter.prototype.moveRectSel = function() {
05934
05935 if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return;
05936
05937 d3.event.preventDefault();
05938 var m = d3.mouse(this.svg_frame().node());
05939
05940 m[0] = Math.max(0, Math.min(this.frame_width(), m[0]));
05941 m[1] = Math.max(0, Math.min(this.frame_height(), m[1]));
05942
05943 switch (this.zoom_kind) {
05944 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break;
05945 case 2: this.zoom_curr[0] = m[0]; break;
05946 case 3: this.zoom_curr[1] = m[1]; break;
05947 }
05948
05949 if (this.zoom_rect===null)
05950 this.zoom_rect = this.svg_frame()
05951 .append("rect")
05952 .attr("class", "zoom")
05953 .attr("pointer-events","none");
05954
05955 this.zoom_rect.attr("x", Math.min(this.zoom_origin[0], this.zoom_curr[0]))
05956 .attr("y", Math.min(this.zoom_origin[1], this.zoom_curr[1]))
05957 .attr("width", Math.abs(this.zoom_curr[0] - this.zoom_origin[0]))
05958 .attr("height", Math.abs(this.zoom_curr[1] - this.zoom_origin[1]));
05959 }
05960
05961 JSROOT.THistPainter.prototype.endRectSel = function() {
05962 if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return;
05963
05964 d3.event.preventDefault();
05965
05966 d3.select(window).on("mousemove.zoomRect", null)
05967 .on("mouseup.zoomRect", null);
05968
05969 var m = d3.mouse(this.svg_frame().node());
05970
05971 m[0] = Math.max(0, Math.min(this.frame_width(), m[0]));
05972 m[1] = Math.max(0, Math.min(this.frame_height(), m[1]));
05973
05974 switch (this.zoom_kind) {
05975 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break;
05976 case 2: this.zoom_curr[0] = m[0]; break;
05977 case 3: this.zoom_curr[1] = m[1]; break;
05978 }
05979
05980 var xmin, xmax, ymin, ymax, isany = false;
05981
05982 if ((this.zoom_kind != 3) && (Math.abs(this.zoom_curr[0] - this.zoom_origin[0]) > 10)) {
05983 xmin = Math.min(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
05984 xmax = Math.max(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
05985 isany = true;
05986 }
05987
05988 if ((this.zoom_kind != 2) && (Math.abs(this.zoom_curr[1] - this.zoom_origin[1]) > 10)) {
05989 ymin = Math.min(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
05990 ymax = Math.max(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
05991 isany = true;
05992 }
05993
05994 this.clearInteractiveElements();
05995
05996 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
05997 }
05998
05999 JSROOT.THistPainter.prototype.startTouchZoom = function() {
06000
06001 if (this.zoom_kind != 0) {
06002 d3.event.preventDefault();
06003 d3.event.stopPropagation();
06004 return;
06005 }
06006
06007 var arr = d3.touches(this.svg_frame().node());
06008 this.touch_cnt+=1;
06009
06010
06011
06012 if (arr.length == 1) {
06013
06014
06015 var now = new Date();
06016 var diff = now.getTime() - this.last_touch.getTime();
06017 this.last_touch = now;
06018
06019 if ((diff < 300) && (this.zoom_curr != null)
06020 && (Math.abs(this.zoom_curr[0] - arr[0][0]) < 30)
06021 && (Math.abs(this.zoom_curr[1] - arr[0][1]) < 30)) {
06022
06023 d3.event.preventDefault();
06024 d3.event.stopPropagation();
06025
06026 this.clearInteractiveElements();
06027 this.Unzoom("xyz");
06028
06029 this.last_touch = new Date(0);
06030
06031 this.svg_frame().on("touchcancel", null)
06032 .on("touchend", null, true);
06033 } else
06034 if (JSROOT.gStyle.ContextMenu) {
06035 this.zoom_curr = arr[0];
06036 this.svg_frame().on("touchcancel", this.endTouchSel.bind(this))
06037 .on("touchend", this.endTouchSel.bind(this));
06038 d3.event.preventDefault();
06039 d3.event.stopPropagation();
06040 }
06041 }
06042
06043 if (arr.length != 2) return;
06044
06045 d3.event.preventDefault();
06046 d3.event.stopPropagation();
06047
06048 this.clearInteractiveElements();
06049
06050 this.svg_frame().on("touchcancel", null)
06051 .on("touchend", null);
06052
06053 var pnt1 = arr[0], pnt2 = arr[1];
06054
06055 this.zoom_curr = [ Math.min(pnt1[0], pnt2[0]), Math.min(pnt1[1], pnt2[1]) ];
06056 this.zoom_origin = [ Math.max(pnt1[0], pnt2[0]), Math.max(pnt1[1], pnt2[1]) ];
06057
06058 if (this.zoom_curr[0] < 0) {
06059 this.zoom_kind = 103;
06060 this.zoom_curr[0] = 0;
06061 this.zoom_origin[0] = this.frame_width();
06062 } else if (this.zoom_origin[1] > this.frame_height()) {
06063 this.zoom_kind = 102;
06064 this.zoom_curr[1] = 0;
06065 this.zoom_origin[1] = this.frame_height();
06066 } else {
06067 this.zoom_kind = 101;
06068 }
06069
06070 this.SwitchTooltip(false);
06071
06072 this.zoom_rect = this.svg_frame().append("rect")
06073 .attr("class", "zoom")
06074 .attr("id", "zoomRect")
06075 .attr("x", this.zoom_curr[0])
06076 .attr("y", this.zoom_curr[1])
06077 .attr("width", this.zoom_origin[0] - this.zoom_curr[0])
06078 .attr("height", this.zoom_origin[1] - this.zoom_curr[1]);
06079
06080 d3.select(window).on("touchmove.zoomRect", this.moveTouchSel.bind(this))
06081 .on("touchcancel.zoomRect", this.endTouchSel.bind(this))
06082 .on("touchend.zoomRect", this.endTouchSel.bind(this));
06083 }
06084
06085 JSROOT.THistPainter.prototype.moveTouchSel = function() {
06086 if (this.zoom_kind < 100) return;
06087
06088 d3.event.preventDefault();
06089
06090 var arr = d3.touches(this.svg_frame().node());
06091
06092 if (arr.length != 2)
06093 return this.clearInteractiveElements();
06094
06095 var pnt1 = arr[0], pnt2 = arr[1];
06096
06097 if (this.zoom_kind != 103) {
06098 this.zoom_curr[0] = Math.min(pnt1[0], pnt2[0]);
06099 this.zoom_origin[0] = Math.max(pnt1[0], pnt2[0]);
06100 }
06101 if (this.zoom_kind != 102) {
06102 this.zoom_curr[1] = Math.min(pnt1[1], pnt2[1]);
06103 this.zoom_origin[1] = Math.max(pnt1[1], pnt2[1]);
06104 }
06105
06106 this.zoom_rect.attr("x", this.zoom_curr[0])
06107 .attr("y", this.zoom_curr[1])
06108 .attr("width", this.zoom_origin[0] - this.zoom_curr[0])
06109 .attr("height", this.zoom_origin[1] - this.zoom_curr[1]);
06110
06111 if ((this.zoom_origin[0] - this.zoom_curr[0] > 10)
06112 || (this.zoom_origin[1] - this.zoom_curr[1] > 10))
06113 this.SwitchTooltip(false);
06114
06115 d3.event.stopPropagation();
06116 }
06117
06118 JSROOT.THistPainter.prototype.endTouchSel = function() {
06119
06120 this.svg_frame().on("touchcancel", null)
06121 .on("touchend", null);
06122
06123 if (this.zoom_kind === 0) {
06124
06125
06126 d3.event.preventDefault();
06127
06128 var now = new Date();
06129
06130 var diff = now.getTime() - this.last_touch.getTime();
06131
06132 if ((diff > 500) && (diff<2000) && !this.frame_painter().IsTooltipShown()) {
06133 this.ShowContextMenu('main', { clientX: this.zoom_curr[0], clientY: this.zoom_curr[1] });
06134 this.last_touch = new Date(0);
06135 } else {
06136 this.clearInteractiveElements();
06137 }
06138 }
06139
06140 if (this.zoom_kind < 100) return;
06141
06142 d3.event.preventDefault();
06143 d3.select(window).on("touchmove.zoomRect", null)
06144 .on("touchend.zoomRect", null)
06145 .on("touchcancel.zoomRect", null);
06146
06147 var xmin, xmax, ymin, ymax, isany = false;
06148
06149 if ((this.zoom_kind != 103) && (Math.abs(this.zoom_curr[0] - this.zoom_origin[0]) > 10)) {
06150 xmin = Math.min(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
06151 xmax = Math.max(this.RevertX(this.zoom_origin[0]), this.RevertX(this.zoom_curr[0]));
06152 isany = true;
06153 }
06154
06155 if ((this.zoom_kind != 102) && (Math.abs(this.zoom_curr[1] - this.zoom_origin[1]) > 10)) {
06156 ymin = Math.min(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
06157 ymax = Math.max(this.RevertY(this.zoom_origin[1]), this.RevertY(this.zoom_curr[1]));
06158 isany = true;
06159 }
06160
06161 this.clearInteractiveElements();
06162 this.last_touch = new Date(0);
06163
06164 if (isany) this.Zoom(xmin, xmax, ymin, ymax);
06165
06166 d3.event.stopPropagation();
06167 }
06168
06169 JSROOT.THistPainter.prototype.mouseWheel = function() {
06170 d3.event.stopPropagation();
06171
06172 var delta = 0;
06173 switch (d3.event.deltaMode) {
06174 case 0: delta = d3.event.deltaY / this.pad_height() * 2; break;
06175 case 1: delta = d3.event.deltaY / this.pad_height() * 40; break;
06176 case 2: delta = d3.event.deltaY / this.pad_height() * 200; break;
06177 }
06178 if (delta===0) return;
06179
06180 d3.event.preventDefault();
06181
06182 this.clearInteractiveElements();
06183
06184 if (delta < -0.2) delta = -0.2; else if (delta>0.2) delta = 0.2;
06185
06186 var xmin = this.scale_xmin, xmax = this.scale_xmax, ymin = undefined, ymax = undefined;
06187
06188 if ((xmin === xmax) && (delta<0)) { xmin = this.xmin; xmax = this.xmax; }
06189
06190 var cur = d3.mouse(this.svg_frame().node());
06191
06192 if (xmin < xmax) {
06193 var dmin = cur[0] / this.frame_width();
06194 if ((dmin>0) && (dmin<1)) {
06195 if (this.options.Logx) {
06196 var factor = (xmin>0) ? JSROOT.log10(xmax/xmin) : 2;
06197 if (factor>10) factor = 10; else if (factor<1.5) factor = 1.5;
06198 xmin = xmin / Math.pow(factor, delta*dmin);
06199 xmax = xmax * Math.pow(factor, delta*(1-dmin));
06200 } else {
06201 var rx = (xmax - xmin);
06202 if (delta>0) rx = 1.001 * rx / (1-delta);
06203 xmin += -delta*dmin*rx;
06204 xmax -= -delta*(1-dmin)*rx;
06205 }
06206 if (xmin >= xmax) xmin = xmax = undefined;
06207 } else {
06208 xmin = xmax = undefined;
06209 }
06210 }
06211
06212 if ((this.Dimension() > 1) || (cur[0] < 0)) {
06213 ymin = this.scale_ymin; ymax = this.scale_ymax;
06214
06215 if ((ymin === ymax) && (delta<0)) { ymin = this.ymin; ymax = this.ymax; }
06216
06217 var dmin = 1 - cur[1] / this.frame_height();
06218
06219 if ((ymin < ymax) && (dmin>0) && (dmin<1)) {
06220 if (this.options.Logy) {
06221 var factor = (ymin>0) ? JSROOT.log10(ymax/ymin) : 2;
06222 if (factor>10) factor = 10; else if (factor<1.5) factor = 1.5;
06223 ymin = ymin / Math.pow(factor, delta*dmin);
06224 ymax = ymax * Math.pow(factor, delta*(1-dmin));
06225 } else {
06226 var ry = (ymax - ymin);
06227 if (delta>0) ry = 1.001 * ry / (1-delta);
06228 ymin += -delta*dmin*ry;
06229 ymax -= -delta*(1-dmin)*ry;
06230 }
06231 if (ymin >= ymax) ymin = ymax = undefined;
06232 } else {
06233 ymin = ymax = undefined;
06234 }
06235 }
06236
06237 this.Zoom(xmin,xmax,ymin,ymax);
06238 }
06239
06240 JSROOT.THistPainter.prototype.AddInteractive = function() {
06241
06242
06243 if ((!JSROOT.gStyle.Zooming && !JSROOT.gStyle.ContextMenu) || !this.is_main_painter()) return;
06244
06245 this.last_touch = new Date(0);
06246 this.zoom_kind = 0;
06247 this.zoom_rect = null;
06248 this.zoom_origin = null;
06249 this.zoom_curr = null;
06250 this.touch_cnt = 0;
06251
06252 if (JSROOT.gStyle.Zooming) {
06253 this.svg_frame().on("mousedown", this.startRectSel.bind(this) );
06254 this.svg_frame().on("dblclick", this.mouseDoubleClick.bind(this) );
06255 this.svg_frame().on("wheel", this.mouseWheel.bind(this) );
06256 }
06257
06258 if (JSROOT.touches && (JSROOT.gStyle.Zooming || JSROOT.gStyle.ContextMenu))
06259 this.svg_frame().on("touchstart", this.startTouchZoom.bind(this) );
06260
06261 if (JSROOT.gStyle.ContextMenu) {
06262 if (JSROOT.touches) {
06263 this.svg_frame().selectAll(".xaxis_container")
06264 .on("touchstart", this.startTouchMenu.bind(this,"x") );
06265 this.svg_frame().selectAll(".yaxis_container")
06266 .on("touchstart", this.startTouchMenu.bind(this,"y") );
06267 }
06268 this.svg_frame().on("contextmenu", this.ShowContextMenu.bind(this) );
06269 this.svg_frame().selectAll(".xaxis_container")
06270 .on("contextmenu", this.ShowContextMenu.bind(this,"x"));
06271 this.svg_frame().selectAll(".yaxis_container")
06272 .on("contextmenu", this.ShowContextMenu.bind(this,"y"));
06273 }
06274 }
06275
06276 JSROOT.THistPainter.prototype.ShowContextMenu = function(kind, evnt, obj) {
06277
06278 if (('zoom_kind' in this) && (this.zoom_kind > 100)) return;
06279
06280
06281
06282
06283
06284
06285
06286
06287 var menu_painter = this, frame_corner = false;
06288
06289 if (!evnt) {
06290 d3.event.preventDefault();
06291 d3.event.stopPropagation();
06292 evnt = d3.event;
06293
06294 if (kind === undefined) {
06295 var ms = d3.mouse(this.svg_frame().node());
06296 var tch = d3.touches(this.svg_frame().node());
06297 var pnt = null, pp = this.pad_painter(true), fp = this.frame_painter(), sel = null;
06298
06299 if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch: true }; else
06300 if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch: false };
06301
06302 if ((pnt !== null) && (pp !== null)) {
06303 pnt.painters = true;
06304 var hints = pp.GetTooltips(pnt);
06305
06306 var bestdist = 1000;
06307 for (var n=0;n<hints.length;++n)
06308 if (hints[n] && hints[n].menu) {
06309 var dist = ('menu_dist' in hints[n]) ? hints[n].menu_dist : 7;
06310 if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; }
06311 }
06312 }
06313
06314 if (sel!==null) menu_painter = sel; else
06315 if (fp!==null) kind = "frame";
06316
06317 if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20);
06318 }
06319 }
06320
06321
06322 menu_painter.ctx_menu_evnt = evnt;
06323
06324 JSROOT.Painter.createMenu(function(menu) {
06325 menu.painter = this;
06326 var domenu = this.FillContextMenu(menu, kind, obj);
06327
06328
06329 if (fp && (!domenu || (frame_corner && (kind!=="frame"))))
06330 domenu = fp.FillContextMenu(menu);
06331
06332 if (domenu) {
06333
06334 this.SwitchTooltip(false);
06335 menu.show(this.ctx_menu_evnt, this.SwitchTooltip.bind(this, true) );
06336 }
06337
06338
06339 delete this.ctx_menu_evnt;
06340 }.bind(menu_painter) );
06341 }
06342
06343
06344 JSROOT.THistPainter.prototype.ChangeUserRange = function(arg) {
06345 var taxis = this.histo['f'+arg+"axis"];
06346 if (!taxis) return;
06347
06348 var curr = "[1," + taxis.fNbins+"]";
06349 if (taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
06350 curr = "[" +taxis.fFirst+"," + taxis.fLast+"]";
06351
06352 var res = prompt("Enter user range for axis " + arg + " like [1," + taxis.fNbins + "]", curr);
06353 if (res==null) return;
06354 res = JSON.parse(res);
06355
06356 if (!res || (res.length!=2) || isNaN(res[0]) || isNaN(res[1])) return;
06357 taxis.fFirst = parseInt(res[0]);
06358 taxis.fLast = parseInt(res[1]);
06359
06360 var newflag = (taxis.fFirst < taxis.fLast) && (taxis.fFirst >= 1) && (taxis.fLast<=taxis.fNbins);
06361 if (newflag != taxis.TestBit(JSROOT.EAxisBits.kAxisRange))
06362 taxis.InvertBit(JSROOT.EAxisBits.kAxisRange);
06363
06364 this.Redraw();
06365 }
06366
06367 JSROOT.THistPainter.prototype.FillContextMenu = function(menu, kind, obj) {
06368
06369
06370 this.clearInteractiveElements();
06371
06372 if ((kind=="x") || (kind=="y") || (kind=="z")) {
06373 var faxis = this.histo.fXaxis;
06374 if (kind=="y") faxis = this.histo.fYaxis; else
06375 if (kind=="z") faxis = obj ? obj : this.histo.fZaxis;
06376 menu.add("header: " + kind.toUpperCase() + " axis");
06377 menu.add("Unzoom", this.Unzoom.bind(this, kind));
06378 menu.addchk(this.options["Log" + kind], "SetLog"+kind, this.ToggleLog.bind(this, kind) );
06379 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kMoreLogLabels), "More log",
06380 function() { faxis.InvertBit(JSROOT.EAxisBits.kMoreLogLabels); this.RedrawPad(); });
06381 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kNoExponent), "No exponent",
06382 function() { faxis.InvertBit(JSROOT.EAxisBits.kNoExponent); this.RedrawPad(); });
06383 if (faxis != null) {
06384 menu.add("sub:Labels");
06385 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterLabels), "Center",
06386 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterLabels); this.RedrawPad(); });
06387 this.AddColorMenuEntry(menu, "Color", faxis.fLabelColor,
06388 function(arg) { faxis.fLabelColor = parseInt(arg); this.RedrawPad(); });
06389 this.AddSizeMenuEntry(menu,"Offset", 0, 0.1, 0.01, faxis.fLabelOffset,
06390 function(arg) { faxis.fLabelOffset = parseFloat(arg); this.RedrawPad(); } );
06391 this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fLabelSize,
06392 function(arg) { faxis.fLabelSize = parseFloat(arg); this.RedrawPad(); } );
06393 menu.add("endsub:");
06394 menu.add("sub:Title");
06395 menu.add("SetTitle", function() {
06396 var t = prompt("Enter axis title", faxis.fTitle);
06397 if (t!==null) { faxis.fTitle = t; this.RedrawPad(); }
06398 });
06399 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterTitle), "Center",
06400 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); this.RedrawPad(); });
06401 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kRotateTitle), "Rotate",
06402 function() { faxis.InvertBit(JSROOT.EAxisBits.kRotateTitle); this.RedrawPad(); });
06403 this.AddColorMenuEntry(menu, "Color", faxis.fTitleColor,
06404 function(arg) { faxis.fTitleColor = parseInt(arg); this.RedrawPad(); });
06405 this.AddSizeMenuEntry(menu,"Offset", 0, 3, 0.2, faxis.fTitleOffset,
06406 function(arg) { faxis.fTitleOffset = parseFloat(arg); this.RedrawPad(); } );
06407 this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fTitleSize,
06408 function(arg) { faxis.fTitleSize = parseFloat(arg); this.RedrawPad(); } );
06409 menu.add("endsub:");
06410 }
06411 menu.add("sub:Ticks");
06412 this.AddColorMenuEntry(menu, "Color", faxis.fLineColor,
06413 function(arg) { faxis.fLineColor = parseInt(arg); this.RedrawPad(); });
06414 this.AddColorMenuEntry(menu, "Color", faxis.fAxisColor,
06415 function(arg) { faxis.fAxisColor = parseInt(arg); this.RedrawPad(); });
06416 this.AddSizeMenuEntry(menu,"Size", -0.05, 0.055, 0.01, faxis.fTickLength,
06417 function(arg) { faxis.fTickLength = parseFloat(arg); this.RedrawPad(); } );
06418 menu.add("endsub:");
06419 return true;
06420 }
06421
06422 if (kind == "frame") {
06423 var fp = this.frame_painter();
06424 if (fp) return fp.FillContextMenu(menu);
06425 }
06426
06427 menu.add("header:"+ this.histo._typename + "::" + this.histo.fName);
06428
06429 if (this.draw_content) {
06430 menu.addchk(this.ToggleStat('only-check'), "Show statbox", function() { this.ToggleStat(); });
06431 if (this.Dimension() == 1) {
06432 menu.add("User range X", "X", this.ChangeUserRange);
06433 } else {
06434 menu.add("sub:User ranges");
06435 menu.add("X", "X", this.ChangeUserRange);
06436 menu.add("Y", "Y", this.ChangeUserRange);
06437 if (this.Dimension() > 2)
06438 menu.add("Z", "Z", this.ChangeUserRange);
06439 menu.add("endsub:")
06440 }
06441 }
06442
06443 if ('FillHistContextMenu' in this)
06444 this.FillHistContextMenu(menu);
06445
06446 this.FillAttContextMenu(menu);
06447
06448 return true;
06449 }
06450
06451 JSROOT.THistPainter.prototype.ButtonClick = function(funcname) {
06452 if (!this.is_main_painter()) return false;
06453 switch(funcname) {
06454 case "ToggleZoom":
06455 if ((this.zoom_xmin !== this.zoom_xmax) || (this.zoom_ymin !== this.zoom_ymax) || (this.zoom_zmin !== this.zoom_zmax)) {
06456 this.Unzoom();
06457 return true;
06458 }
06459 if (this.draw_content && ('AutoZoom' in this) && (this.Dimension() < 3)) {
06460 this.AutoZoom();
06461 return true;
06462 }
06463 break;
06464 case "ToggleLogX": this.ToggleLog("x"); break;
06465 case "ToggleLogY": this.ToggleLog("y"); break;
06466 case "ToggleLogZ": this.ToggleLog("z"); break;
06467 case "ToggleStatBox": this.ToggleStat(); return true; break;
06468 }
06469 return false;
06470 }
06471
06472 JSROOT.THistPainter.prototype.FillToolbar = function() {
06473 var pp = this.pad_painter(true);
06474 if (pp===null) return;
06475
06476 pp.AddButton(JSROOT.ToolbarIcons.auto_zoom, 'Toggle between unzoom and autozoom-in', 'ToggleZoom');
06477 pp.AddButton(JSROOT.ToolbarIcons.arrow_right, "Toggle log x", "ToggleLogX");
06478 pp.AddButton(JSROOT.ToolbarIcons.arrow_up, "Toggle log y", "ToggleLogY");
06479 if (this.Dimension() > 1)
06480 pp.AddButton(JSROOT.ToolbarIcons.arrow_diag, "Toggle log z", "ToggleLogZ");
06481 if (this.draw_content)
06482 pp.AddButton(JSROOT.ToolbarIcons.statbox, 'Toggle stat box', "ToggleStatBox");
06483 }
06484
06485
06486
06487 JSROOT.TH1Painter = function(histo) {
06488 JSROOT.THistPainter.call(this, histo);
06489 }
06490
06491 JSROOT.TH1Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
06492
06493 JSROOT.TH1Painter.prototype.ScanContent = function() {
06494
06495
06496
06497 var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0;
06498
06499 var profile = this.IsTProfile();
06500
06501 this.nbinsx = this.histo.fXaxis.fNbins;
06502 this.nbinsy = 0;
06503
06504 for (var i = 0; i < this.nbinsx; ++i) {
06505 var value = this.histo.getBinContent(i + 1), err = 0;
06506 hsum += profile ? this.histo.fBinEntries[i + 1] : value;
06507 if (value > 0)
06508 if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value;
06509 if (this.options.Error > 0) err = this.histo.getBinError(i + 1);
06510 if (i == 0) {
06511 hmin = value - err; hmax = value + err;
06512 } else {
06513 hmin = Math.min(hmin, value - err);
06514 hmax = Math.max(hmax, value + err);
06515 }
06516 }
06517
06518
06519 if (profile)
06520 hsum += this.histo.fBinEntries[0] + this.histo.fBinEntries[this.nbinsx + 1];
06521 else
06522 hsum += this.histo.getBinContent(0) + this.histo.getBinContent(this.nbinsx + 1);
06523
06524 this.stat_entries = hsum;
06525 if (this.histo.fEntries>1) this.stat_entries = this.histo.fEntries;
06526
06527 this.CreateAxisFuncs(false);
06528
06529 this.hmin = hmin;
06530 this.hmax = hmax;
06531
06532 this.ymin_nz = hmin_nz;
06533
06534 if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) {
06535 this.draw_content = false;
06536 hmin = this.ymin;
06537 hmax = this.ymax;
06538 } else {
06539 this.draw_content = true;
06540 }
06541
06542 if (hmin >= hmax) {
06543 if (hmin == 0) { this.ymin = 0; this.ymax = 1; } else
06544 if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; }
06545 else { this.ymin = 0; this.ymax = hmin * 2; }
06546 } else {
06547 var dy = (hmax - hmin) * 0.05;
06548 this.ymin = hmin - dy;
06549 if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0;
06550 this.ymax = hmax + dy;
06551 }
06552
06553 hmin = hmax = null;
06554 var set_zoom = false;
06555 if (this.histo.fMinimum != -1111) {
06556 hmin = this.histo.fMinimum;
06557 if (hmin < this.ymin)
06558 this.ymin = hmin;
06559 else
06560 set_zoom = true;
06561 }
06562 if (this.histo.fMaximum != -1111) {
06563 hmax = this.histo.fMaximum;
06564 if (hmax > this.ymax)
06565 this.ymax = hmax;
06566 else
06567 set_zoom = true;
06568 }
06569
06570 if (set_zoom) {
06571 this.zoom_ymin = (hmin == null) ? this.ymin : hmin;
06572 this.zoom_ymax = (hmax == null) ? this.ymax : hmax;
06573 }
06574
06575
06576 if (this.is_main_painter() && (this.zoom_xmin === this.zoom_xmax) &&
06577 this.histo.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange) &&
06578 (this.histo.fXaxis.fFirst !== this.histo.fXaxis.fLast) &&
06579 ((this.histo.fXaxis.fFirst>1) || (this.histo.fXaxis.fLast <= this.nbinsx))) {
06580 this.zoom_xmin = this.histo.fXaxis.fFirst > 1 ? this.GetBinX(this.histo.fXaxis.fFirst-1) : this.xmin;
06581 this.zoom_xmax = this.histo.fXaxis.fLast <= this.nbinsx ? this.GetBinX(this.histo.fXaxis.fLast) : this.xmax;
06582 }
06583
06584
06585 if (this.options.Bar == 0 && this.options.Hist == 0
06586 && this.options.Error == 0 && this.options.Same == 0) {
06587 this.draw_content = false;
06588 }
06589 if (this.options.Axis > 0) {
06590 this.draw_content = false;
06591 }
06592 }
06593
06594 JSROOT.TH1Painter.prototype.CountStat = function(cond) {
06595 var profile = this.IsTProfile();
06596
06597 var stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0;
06598
06599 var left = this.GetSelectIndex("x", "left");
06600 var right = this.GetSelectIndex("x", "right");
06601
06602 var xx = 0, w = 0, xmax = null, wmax = null;
06603
06604 for (var i = left; i < right; ++i) {
06605 xx = this.GetBinX(i+0.5);
06606
06607 if ((cond!=null) && !cond(xx)) continue;
06608
06609 if (profile) {
06610 w = this.histo.fBinEntries[i + 1];
06611 stat_sumwy += this.histo.fArray[i + 1];
06612 stat_sumwy2 += this.histo.fSumw2[i + 1];
06613 } else {
06614 w = this.histo.getBinContent(i + 1);
06615 }
06616
06617 if ((xmax==null) || (w>wmax)) { xmax = xx; wmax = w; }
06618
06619 stat_sumw += w;
06620 stat_sumwx += w * xx;
06621 stat_sumwx2 += w * xx * xx;
06622 }
06623
06624
06625 if (!this.IsAxisZoomed("x") && (this.histo.fTsumw>0)) {
06626 stat_sumw = this.histo.fTsumw;
06627 stat_sumwx = this.histo.fTsumwx;
06628 stat_sumwx2 = this.histo.fTsumwx2;
06629 }
06630
06631 var res = { meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: stat_sumw, entries: this.stat_entries, xmax:0, wmax:0 };
06632
06633 if (stat_sumw > 0) {
06634 res.meanx = stat_sumwx / stat_sumw;
06635 res.meany = stat_sumwy / stat_sumw;
06636 res.rmsx = Math.sqrt(stat_sumwx2 / stat_sumw - res.meanx * res.meanx);
06637 res.rmsy = Math.sqrt(stat_sumwy2 / stat_sumw - res.meany * res.meany);
06638 }
06639
06640 if (xmax!=null) {
06641 res.xmax = xmax;
06642 res.wmax = wmax;
06643 }
06644
06645 return res;
06646 }
06647
06648 JSROOT.TH1Painter.prototype.FillStatistic = function(stat, dostat, dofit) {
06649 if (!this.histo) return false;
06650
06651 var pave = stat.GetObject(),
06652 data = this.CountStat(),
06653 print_name = dostat % 10,
06654 print_entries = Math.floor(dostat / 10) % 10,
06655 print_mean = Math.floor(dostat / 100) % 10,
06656 print_rms = Math.floor(dostat / 1000) % 10,
06657 print_under = Math.floor(dostat / 10000) % 10,
06658 print_over = Math.floor(dostat / 100000) % 10,
06659 print_integral = Math.floor(dostat / 1000000) % 10,
06660 print_skew = Math.floor(dostat / 10000000) % 10,
06661 print_kurt = Math.floor(dostat / 100000000) % 10;
06662
06663 if (print_name > 0)
06664 pave.AddText(this.histo.fName);
06665
06666 if (this.IsTProfile()) {
06667
06668 if (print_entries > 0)
06669 pave.AddText("Entries = " + stat.Format(data.entries,"entries"));
06670
06671 if (print_mean > 0) {
06672 pave.AddText("Mean = " + stat.Format(data.meanx));
06673 pave.AddText("Mean y = " + stat.Format(data.meany));
06674 }
06675
06676 if (print_rms > 0) {
06677 pave.AddText("Std Dev = " + stat.Format(data.rmsx));
06678 pave.AddText("Std Dev y = " + stat.Format(data.rmsy));
06679 }
06680
06681 } else {
06682
06683 if (print_entries > 0)
06684 pave.AddText("Entries = " + stat.Format(data.entries,"entries"));
06685
06686 if (print_mean > 0) {
06687 pave.AddText("Mean = " + stat.Format(data.meanx));
06688 }
06689
06690 if (print_rms > 0) {
06691 pave.AddText("Std Dev = " + stat.Format(data.rmsx));
06692 }
06693
06694 if (print_under > 0) {
06695 var res = (this.histo.fArray.length > 0) ? this.histo.fArray[0] : 0;
06696 pave.AddText("Underflow = " + stat.Format(res));
06697 }
06698
06699 if (print_over > 0) {
06700 var res = (this.histo.fArray.length > 0) ? this.histo.fArray[this.histo.fArray.length - 1] : 0;
06701 pave.AddText("Overflow = " + stat.Format(res));
06702 }
06703
06704 if (print_integral > 0) {
06705 pave.AddText("Integral = " + stat.Format(data.integral,"entries"));
06706 }
06707
06708 if (print_skew > 0)
06709 pave.AddText("Skew = <not avail>");
06710
06711 if (print_kurt > 0)
06712 pave.AddText("Kurt = <not avail>");
06713 }
06714
06715 if (dofit!=0) {
06716 var f1 = this.FindF1();
06717 if (f1!=null) {
06718 var print_fval = dofit%10;
06719 var print_ferrors = Math.floor(dofit/10) % 10;
06720 var print_fchi2 = Math.floor(dofit/100) % 10;
06721 var print_fprob = Math.floor(dofit/1000) % 10;
06722
06723 if (print_fchi2 > 0)
06724 pave.AddText("#chi^2 / ndf = " + stat.Format(f1.fChisquare,"fit") + " / " + f1.fNDF);
06725 if (print_fprob > 0)
06726 pave.AddText("Prob = " + (('Math' in JSROOT) ? stat.Format(JSROOT.Math.Prob(f1.fChisquare, f1.fNDF)) : "<not avail>"));
06727 if (print_fval > 0) {
06728 for(var n=0;n<f1.fNpar;++n) {
06729 var parname = f1.GetParName(n);
06730 var parvalue = f1.GetParValue(n);
06731 if (parvalue != null) parvalue = stat.Format(Number(parvalue),"fit");
06732 else parvalue = "<not avail>";
06733 var parerr = "";
06734 if (f1.fParErrors!=null) {
06735 parerr = stat.Format(f1.fParErrors[n],"last");
06736 if ((Number(parerr)==0.0) && (f1.fParErrors[n]!=0.0)) parerr = stat.Format(f1.fParErrors[n],"4.2g");
06737 }
06738
06739 if ((print_ferrors > 0) && (parerr.length > 0))
06740 pave.AddText(parname + " = " + parvalue + " #pm " + parerr);
06741 else
06742 pave.AddText(parname + " = " + parvalue);
06743 }
06744 }
06745 }
06746 }
06747
06748
06749 var nlines = pave.fLines.arr.length,
06750 stath = nlines * JSROOT.gStyle.StatFontSize;
06751 if ((stath <= 0) || (JSROOT.gStyle.StatFont % 10 === 3)) {
06752 stath = 0.25 * nlines * JSROOT.gStyle.StatH;
06753 pave.fY1NDC = 0.93 - stath;
06754 pave.fY2NDC = 0.93;
06755 }
06756
06757 return true;
06758 }
06759
06760
06761 JSROOT.TH1Painter.prototype.DrawBins = function() {
06762
06763
06764
06765 var width = this.frame_width(), height = this.frame_height();
06766
06767 if (!this.draw_content || (width<=0) || (height<=0))
06768 return this.RemoveDrawG();
06769
06770 this.RecreateDrawG(false, "main_layer");
06771
06772 var left = this.GetSelectIndex("x", "left", -1),
06773 right = this.GetSelectIndex("x", "right", 2),
06774 pmain = this.main_painter(),
06775 pthis = this,
06776 res = "", lastbin = false,
06777 startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, besti,
06778 exclude_zero = (this.options.Error!==10) && (this.options.Mark!==10),
06779 show_errors = (this.options.Error > 0),
06780 show_markers = (this.options.Mark > 0),
06781 path_fill = null, path_err = null, path_marker = null,
06782 endx = "", endy = "", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, mpath = "";
06783
06784 if (show_errors && !show_markers && (this.histo.fMarkerStyle > 1))
06785 show_markers = true;
06786
06787 if (this.options.Error == 12) {
06788 if (this.fillatt.color=='none') show_markers = true;
06789 else path_fill = "";
06790 } else
06791 if (this.options.Error > 0) path_err = "";
06792
06793 if (show_markers) {
06794
06795 if (!this.markeratt)
06796 this.markeratt = JSROOT.Painter.createAttMarker(this.histo);
06797 if (this.markeratt.size > 0) {
06798
06799 path_marker = "";
06800 this.markeratt.reset_pos();
06801 } else {
06802 show_markers = false;
06803 }
06804 }
06805
06806
06807
06808 var use_minmax = ((right-left) > 3*width);
06809
06810 if (this.options.Error == 11) {
06811 var lw = this.lineatt.width + JSROOT.gStyle.EndErrorSize;
06812 endx = "m0," + lw + "v-" + 2*lw + "m0," + lw;
06813 endy = "m" + lw + ",0h-" + 2*lw + "m" + lw + ",0";
06814 dend = Math.floor((this.lineatt.width-1)/2);
06815 }
06816
06817 var draw_markers = show_errors || show_markers;
06818
06819 if (draw_markers) use_minmax = true;
06820
06821 for (i = left; i <= right; ++i) {
06822
06823 x = this.GetBinX(i);
06824
06825 if (this.options.Logx && (x <= 0)) continue;
06826
06827 grx = Math.round(pmain.grx(x));
06828
06829 lastbin = (i === right);
06830
06831 if (lastbin && (left<right)) {
06832 gry = curry;
06833 } else {
06834 y = this.histo.getBinContent(i+1);
06835 if (this.options.Logy && (y < this.scale_ymin))
06836 gry = height + 1;
06837 else
06838 gry = Math.round(pmain.gry(y));
06839 }
06840
06841 if (res.length === 0) {
06842 besti = i;
06843 prevx = startx = currx = grx;
06844 prevy = curry_min = curry_max = curry = gry;
06845 res = "M"+currx+","+curry;
06846 } else
06847 if (use_minmax) {
06848 if ((grx === currx) && !lastbin) {
06849 if (gry < curry_min) besti = i;
06850 curry_min = Math.min(curry_min, gry);
06851 curry_max = Math.max(curry_max, gry);
06852 curry = gry;
06853 } else {
06854
06855 if (draw_markers) {
06856 bincont = this.histo.getBinContent(besti+1);
06857 if (!exclude_zero || (bincont!==0)) {
06858
06859 mx1 = Math.round(pmain.grx(this.GetBinX(besti)));
06860 mx2 = Math.round(pmain.grx(this.GetBinX(besti+1)));
06861 my = Math.round(pmain.gry(bincont));
06862 yerr1 = yerr2 = 20;
06863 if (show_errors) {
06864 binerr = this.histo.getBinError(besti+1);
06865 yerr1 = Math.round(my - pmain.gry(bincont + binerr));
06866 yerr2 = Math.round(pmain.gry(bincont - binerr) - my);
06867 }
06868
06869 if ((my >= -yerr1) && (my <= height + yerr2)) {
06870 if (path_fill !== null)
06871 path_fill +="M" + mx1 +","+(my-yerr1) +
06872 "h" + (mx2-mx1) + "v" + (yerr1+yerr2+1) + "h-" + (mx2-mx1) + "z";
06873 if (path_err !== null)
06874 path_err +="M" + (mx1+dend) +","+ my + endx + "h" + (mx2-mx1-2*dend) + endx +
06875 "M" + Math.round((mx1+mx2)/2) +"," + (my-yerr1+dend) + endy + "v" + (yerr1+yerr2-2*dend) + endy;
06876 if (path_marker !== null)
06877 path_marker += this.markeratt.create((mx1+mx2)/2, my);
06878 }
06879 }
06880 }
06881
06882
06883 if (!draw_markers && ((curry_min !== curry_max) || (prevy !== curry_min))) {
06884
06885 if (prevx !== currx)
06886 res += "h"+(currx-prevx);
06887
06888 if (curry === curry_min) {
06889 if (curry_max !== prevy)
06890 res += "v" + (curry_max - prevy);
06891 if (curry_min !== curry_max)
06892 res += "v" + (curry_min - curry_max);
06893 } else {
06894 if (curry_min !== prevy)
06895 res += "v" + (curry_min - prevy);
06896 if (curry_max !== curry_min)
06897 res += "v" + (curry_max - curry_min);
06898 if (curry !== curry_max)
06899 res += "v" + (curry - curry_max);
06900 }
06901
06902 prevx = currx;
06903 prevy = curry;
06904 }
06905
06906 if (lastbin && (prevx !== grx))
06907 res += "h"+(grx-prevx);
06908
06909 besti = i;
06910 curry_min = curry_max = curry = gry;
06911 currx = grx;
06912 }
06913 } else
06914 if ((gry !== curry) || lastbin) {
06915 if (grx !== currx) res += "h"+(grx-currx);
06916 if (gry !== curry) res += "v"+(gry-curry);
06917 curry = gry;
06918 currx = grx;
06919 }
06920 }
06921
06922 if ((this.fillatt.color !== 'none') && (res.length>0)) {
06923 var h0 = (height+3);
06924 if ((this.hmin>=0) && (pmain.gry(0) < height)) h0 = Math.round(pmain.gry(0));
06925 res += "L"+currx+","+h0 + "L"+startx+","+h0 + "Z";
06926 }
06927
06928 if (draw_markers) {
06929
06930 if ((path_fill !== null) && (path_fill.length > 0))
06931 this.draw_g.append("svg:path")
06932 .attr("d", path_fill)
06933 .call(this.fillatt.func);
06934
06935 if ((path_err !== null) && (path_err.length > 0))
06936 this.draw_g.append("svg:path")
06937 .attr("d", path_err)
06938 .call(this.lineatt.func)
06939
06940 if ((path_marker !== null) && (path_marker.length > 0))
06941 this.draw_g.append("svg:path")
06942 .attr("d", path_marker)
06943 .call(this.markeratt.func);
06944
06945 } else
06946 if (res.length > 0) {
06947 this.draw_g.append("svg:path")
06948 .attr("d", res)
06949 .style("stroke-linejoin","miter")
06950 .call(this.lineatt.func)
06951 .call(this.fillatt.func);
06952 }
06953 }
06954
06955 JSROOT.TH1Painter.prototype.GetBinTips = function(bin,asstr) {
06956 var tips = [], name = this.GetTipName(), pmain = this.main_painter();
06957 if (name.length>0) tips.push(name);
06958
06959 var x1 = this.GetBinX(bin),
06960 x2 = this.GetBinX(bin+1),
06961 cont = this.histo.getBinContent(bin+1);
06962
06963 if ((this.options.Error > 0) || (this.options.Mark > 0)) {
06964 tips.push("x = " + pmain.AxisAsText("x", (x1+x2)/2));
06965 tips.push("y = " + pmain.AxisAsText("y", cont));
06966 if (this.options.Error > 0) {
06967 tips.push("error x = " + ((x2 - x1) / 2).toPrecision(4));
06968 tips.push("error y = " + this.histo.getBinError(bin + 1).toPrecision(4));
06969 }
06970 } else {
06971 tips.push("bin = " + (bin+1));
06972
06973 if (pmain.x_kind === 'labels')
06974 tips.push("x = " + pmain.AxisAsText("x", x1));
06975 else
06976 if (pmain.x_kind === 'time')
06977 tips.push("x = " + pmain.AxisAsText("x", (x1+x2)/2));
06978 else
06979 tips.push("x = [" + pmain.AxisAsText("x", x1) + ", " + pmain.AxisAsText("x", x2) + ")");
06980
06981 if (cont === Math.round(cont))
06982 tips.push("entries = " + cont);
06983 else
06984 tips.push("entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.StatFormat));
06985 }
06986
06987 if (!asstr) return tips;
06988
06989 var res = "";
06990 for (var n=0;n<tips.length;++n) res += (n>0 ? "\n" : "") + tips[n];
06991 return res;
06992 }
06993
06994 JSROOT.TH1Painter.prototype.ProcessTooltip = function(pnt) {
06995 if ((pnt === null) || !this.draw_content) {
06996 if (this.draw_g !== null)
06997 this.draw_g.select(".tooltip_bin").remove();
06998 this.ProvideUserTooltip(null);
06999 return null;
07000 }
07001
07002 var width = this.frame_width(),
07003 height = this.frame_height(),
07004 pmain = this.main_painter(),
07005 painter = this,
07006 findbin = null, show_rect = true,
07007 grx1, midx, grx2, gry1, midy, gry2,
07008 left = this.GetSelectIndex("x", "left", -1),
07009 right = this.GetSelectIndex("x", "right", 2),
07010 l = left, r = right;
07011
07012 function GetBinGrX(i) {
07013 var x1 = painter.GetBinX(i);
07014 if ((x1<0) && painter.options.Logx) return null;
07015 return pmain.grx(x1);
07016 }
07017
07018 function GetBinGrY(i) {
07019 var y = painter.histo.getBinContent(i + 1);
07020 if (painter.options.Logy && (y < painter.scale_ymin))
07021 return 10*height;
07022 return Math.round(pmain.gry(y));
07023 }
07024
07025 while (l < r-1) {
07026 var m = Math.round((l+r)*0.5);
07027
07028 var xx = GetBinGrX(m);
07029 if (xx === null) { l = m; continue; }
07030
07031 if (xx < pnt.x - 0.5) l = m; else
07032 if (xx > pnt.x + 0.5) r = m; else { l++; r--; }
07033 }
07034
07035 findbin = r = l;
07036 grx1 = GetBinGrX(findbin);
07037
07038 while ((l>left) && (GetBinGrX(l-1) > grx1 - 1.0)) --l;
07039 while ((r<right) && (GetBinGrX(r+1) < grx1 + 1.0)) ++r;
07040
07041 if (l < r) {
07042
07043
07044 var best = height;
07045 for (var m=l;m<=r;m++) {
07046 var dist = Math.abs(GetBinGrY(m) - pnt.y);
07047 if (dist < best) { best = dist; findbin = m; }
07048 }
07049
07050
07051 if (best > height/10)
07052 findbin = Math.round(l + (r-l) / height * pnt.y);
07053
07054 grx1 = GetBinGrX(findbin);
07055 }
07056
07057 grx1 = Math.round(grx1);
07058 grx2 = Math.round(GetBinGrX(findbin+1));
07059
07060 midx = Math.round((grx1+grx2)/2);
07061
07062 midy = gry1 = gry2 = GetBinGrY(findbin);
07063
07064
07065 if ((this.options.Error > 0) || (this.options.Mark > 0)) {
07066
07067 show_rect = true;
07068
07069 var msize = 3;
07070 if (this.markeratt) msize = Math.max(msize, 2+Math.round(this.markeratt.size * 4));
07071
07072
07073 if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; }
07074
07075 if (this.options.Error > 0) {
07076 var cont = this.histo.getBinContent(findbin+1);
07077 var binerr = this.histo.getBinError(findbin+1);
07078
07079 gry1 = Math.round(pmain.gry(cont + binerr));
07080 gry2 = Math.round(pmain.gry(cont - binerr));
07081 }
07082
07083 gry1 = Math.min(gry1, midy - msize);
07084 gry2 = Math.max(gry2, midy + msize);
07085
07086 if (!pnt.touch && (pnt.nproc === 1))
07087 if ((pnt.y<gry1) || (pnt.y>gry2)) findbin = null;
07088
07089 } else {
07090
07091
07092
07093 show_rect = (pnt.nproc === 1) && (right-left < width);
07094
07095 if (show_rect) {
07096
07097 if ((pnt.y < gry1) && !pnt.touch) findbin = null;
07098
07099 gry2 = height;
07100
07101 if ((this.fillatt.color !== 'none') && (this.hmin>=0)) {
07102 gry2 = Math.round(pmain.gry(0));
07103 if ((gry2 > height) || (gry2 <= gry1)) gry2 = height;
07104 }
07105 }
07106 }
07107
07108 if (findbin!==null) {
07109
07110 if ((findbin === left) && (grx1 > pnt.x + 2)) findbin = null; else
07111 if ((findbin === right-1) && (grx2 < pnt.x - 2)) findbin = null;
07112 }
07113
07114
07115 var ttrect = this.draw_g.select(".tooltip_bin");
07116
07117 if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) {
07118 ttrect.remove();
07119 this.ProvideUserTooltip(null);
07120 return null;
07121 }
07122
07123 var res = { x: midx, y: midy,
07124 color1: this.lineatt.color, color2: this.fillatt.color,
07125 lines: this.GetBinTips(findbin) };
07126
07127 if (show_rect) {
07128
07129 if (ttrect.empty())
07130 ttrect = this.draw_g.append("svg:rect")
07131 .attr("class","tooltip_bin h1bin")
07132 .style("pointer-events","none");
07133
07134 res.changed = ttrect.property("current_bin") !== findbin;
07135
07136 if (res.changed)
07137 ttrect.attr("x", grx1)
07138 .attr("width", grx2-grx1)
07139 .attr("y", gry1)
07140 .attr("height", gry2-gry1)
07141 .style("opacity", "0.3")
07142 .property("current_bin", findbin);
07143
07144 res.exact = (Math.abs(midy - pnt.y) <= 5) || ((pnt.y>=gry1) && (pnt.y<=gry2));
07145
07146 res.menu = true;
07147
07148 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
07149
07150 } else {
07151 var radius = this.lineatt.width + 3;
07152
07153 if (ttrect.empty())
07154 ttrect = this.draw_g.append("svg:circle")
07155 .attr("class","tooltip_bin")
07156 .style("pointer-events","none")
07157 .attr("r", radius)
07158 .call(this.lineatt.func)
07159 .call(this.fillatt.func);
07160
07161 res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius);
07162
07163 res.menu = res.exact;
07164 res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y));
07165
07166 res.changed = ttrect.property("current_bin") !== findbin;
07167
07168 if (res.changed)
07169 ttrect.attr("cx", midx)
07170 .attr("cy", midy)
07171 .property("current_bin", findbin);
07172 }
07173
07174 if (this.IsUserTooltipCallback() && res.changed) {
07175 this.ProvideUserTooltip({ obj: this.histo, name: this.histo.fName,
07176 bin: findbin, cont: this.histo.getBinContent(findbin+1),
07177 grx: midx, gry: midy });
07178 }
07179
07180 return res;
07181 }
07182
07183
07184 JSROOT.TH1Painter.prototype.FillHistContextMenu = function(menu) {
07185 if (!this.draw_content) return;
07186
07187 menu.add("Auto zoom-in", this.AutoZoom.bind(this));
07188 menu.addDrawMenu("Draw with", ["hist", "p", "e", "e1", "pe2"], function(arg) {
07189 this.options = this.DecodeOptions(arg);
07190 this.Redraw();
07191 });
07192 }
07193
07194 JSROOT.TH1Painter.prototype.AutoZoom = function() {
07195 var left = this.GetSelectIndex("x", "left", -1),
07196 right = this.GetSelectIndex("x", "right", 1),
07197 dist = right - left;
07198
07199 if (dist == 0) return;
07200
07201
07202 var min = this.histo.getBinContent(left + 1);
07203 for (var indx = left; indx < right; ++indx)
07204 if (this.histo.getBinContent(indx + 1) < min)
07205 min = this.histo.getBinContent(indx + 1);
07206 if (min>0) return;
07207
07208 while ((left < right) && (this.histo.getBinContent(left + 1) <= min)) ++left;
07209 while ((left < right) && (this.histo.getBinContent(right) <= min)) --right;
07210
07211 if ((right - left < dist) && (left < right))
07212 this.Zoom(this.GetBinX(left), this.GetBinX(right));
07213 }
07214
07215 JSROOT.TH1Painter.prototype.CanZoomIn = function(axis,min,max) {
07216 if ((axis=="x") && (this.GetIndexX(max,0.5) - this.GetIndexX(min,0) > 1)) return true;
07217
07218 if ((axis=="y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6)) return true;
07219
07220
07221 return false;
07222 }
07223
07224 JSROOT.TH1Painter.prototype.Redraw = function() {
07225 this.CreateXY();
07226 this.DrawAxes();
07227 this.DrawGrids();
07228 this.DrawBins();
07229 this.DrawTitle();
07230 }
07231
07232 JSROOT.Painter.drawHistogram1D = function(divid, histo, opt) {
07233
07234 var painter = new JSROOT.TH1Painter(histo);
07235
07236 painter.SetDivId(divid, 1);
07237
07238
07239 painter.options = painter.DecodeOptions(opt);
07240
07241 painter.CheckPadOptions();
07242
07243 painter.ScanContent();
07244
07245 painter.CreateXY();
07246
07247 painter.DrawAxes();
07248
07249 painter.DrawGrids();
07250
07251 painter.DrawBins();
07252
07253 painter.DrawTitle();
07254
07255 if (JSROOT.gStyle.AutoStat && painter.create_canvas)
07256 painter.CreateStat();
07257
07258 painter.DrawNextFunction(0, function() {
07259
07260 painter.AddInteractive();
07261
07262 painter.FillToolbar();
07263
07264 if (painter.options.AutoZoom) painter.AutoZoom();
07265
07266 painter.DrawingReady();
07267 });
07268
07269 return painter;
07270 }
07271
07272
07273
07274 JSROOT.Painter.drawText = function(divid, text) {
07275 var painter = new JSROOT.TObjectPainter(text);
07276 painter.SetDivId(divid, 2);
07277
07278 painter.Redraw = function() {
07279 var text = this.GetObject(),
07280 w = this.pad_width(), h = this.pad_height(),
07281 pos_x = text.fX, pos_y = text.fY,
07282 tcolor = JSROOT.Painter.root_colors[text.fTextColor],
07283 use_pad = true, latex_kind = 0, fact = 1.;
07284
07285 if (text.TestBit(JSROOT.BIT(14))) {
07286
07287 pos_x = pos_x * w;
07288 pos_y = (1 - pos_y) * h;
07289 } else
07290 if (this.main_painter() !== null) {
07291 w = this.frame_width(); h = this.frame_height(); use_pad = false;
07292 pos_x = this.main_painter().grx(pos_x);
07293 pos_y = this.main_painter().gry(pos_y);
07294 } else
07295 if (this.root_pad() !== null) {
07296 pos_x = this.ConvertToNDC("x", pos_x) * w;
07297 pos_y = (1 - this.ConvertToNDC("y", pos_y)) * h;
07298 } else {
07299 text.fTextAlign = 22;
07300 pos_x = w/2;
07301 pos_y = h/2;
07302 if (text.fTextSize === 0) text.fTextSize = 0.05;
07303 if (text.fTextColor === 0) text.fTextColor = 1;
07304 }
07305
07306 this.RecreateDrawG(use_pad, use_pad ? "text_layer" : "upper_layer");
07307
07308 if (text._typename == 'TLatex') { latex_kind = 1; fact = 0.9; } else
07309 if (text._typename == 'TMathText') { latex_kind = 2; fact = 0.8; }
07310
07311 this.StartTextDrawing(text.fTextFont, Math.round(text.fTextSize*Math.min(w,h)*fact));
07312
07313 this.DrawText(text.fTextAlign, Math.round(pos_x), Math.round(pos_y), 0, 0, text.fTitle, tcolor, latex_kind);
07314
07315 this.FinishTextDrawing();
07316 }
07317
07318 return painter.DrawingReady();
07319 }
07320
07321
07322
07323 JSROOT.RawTextPainter = function(txt) {
07324 JSROOT.TBasePainter.call(this);
07325 this.txt = txt;
07326 return this;
07327 }
07328
07329 JSROOT.RawTextPainter.prototype = Object.create( JSROOT.TBasePainter.prototype );
07330
07331 JSROOT.RawTextPainter.prototype.RedrawObject = function(obj) {
07332 this.txt = obj;
07333 this.Draw();
07334 return true;
07335 }
07336
07337 JSROOT.RawTextPainter.prototype.Draw = function() {
07338 var txt = this.txt.value;
07339 if (txt==null) txt = "<undefined>";
07340
07341 var mathjax = 'mathjax' in this.txt;
07342
07343 if (!mathjax && !('as_is' in this.txt)) {
07344 var arr = txt.split("\n"); txt = "";
07345 for (var i = 0; i < arr.length; ++i)
07346 txt += "<pre>" + arr[i] + "</pre>";
07347 }
07348
07349 var frame = this.select_main();
07350 var main = frame.select("div");
07351 if (main.empty())
07352 main = frame.append("div")
07353 .style('max-width','100%')
07354 .style('max-height','100%')
07355 .style('overflow','auto');
07356
07357 main.html(txt);
07358
07359
07360 this.SetDivId(this.divid);
07361
07362 if (mathjax) {
07363 if (this['loading_mathjax']) return;
07364 this['loading_mathjax'] = true;
07365 var painter = this;
07366 JSROOT.AssertPrerequisites('mathjax', function() {
07367 painter['loading_mathjax'] = false;
07368 if (typeof MathJax == 'object') {
07369 MathJax.Hub.Queue(["Typeset", MathJax.Hub, frame.node()]);
07370 }
07371 });
07372 }
07373 }
07374
07375 JSROOT.Painter.drawRawText = function(divid, txt, opt) {
07376 var painter = new JSROOT.RawTextPainter(txt);
07377 painter.SetDivId(divid);
07378 painter.Draw();
07379 return painter.DrawingReady();
07380 }
07381
07382
07383
07384 JSROOT.Painter.FolderHierarchy = function(item, obj) {
07385
07386 if ((obj==null) || !('fFolders' in obj) || (obj.fFolders==null)) return false;
07387
07388 if (obj.fFolders.arr.length===0) { item._more = false; return true; }
07389
07390 item._childs = [];
07391
07392 for ( var i = 0; i < obj.fFolders.arr.length; ++i) {
07393 var chld = obj.fFolders.arr[i];
07394 item._childs.push( {
07395 _name : chld.fName,
07396 _kind : "ROOT." + chld._typename,
07397 _obj : chld
07398 });
07399 }
07400 return true;
07401 }
07402
07403 JSROOT.Painter.TaskHierarchy = function(item, obj) {
07404
07405
07406
07407 if ((obj==null) || !('fTasks' in obj) || (obj.fTasks==null)) return false;
07408
07409 JSROOT.Painter.ObjectHierarchy(item, obj, { exclude: ['fTasks', 'fName'] } );
07410
07411 if ((obj.fTasks.arr.length===0) && (item._childs.length==0)) { item._more = false; return true; }
07412
07413
07414
07415 for ( var i = 0; i < obj.fTasks.arr.length; ++i) {
07416 var chld = obj.fTasks.arr[i];
07417 item._childs.push( {
07418 _name : chld.fName,
07419 _kind : "ROOT." + chld._typename,
07420 _obj : chld
07421 });
07422 }
07423 return true;
07424 }
07425
07426
07427 JSROOT.Painter.ListHierarchy = function(folder, lst) {
07428 if (lst._typename != 'TList' && lst._typename != 'TObjArray' && lst._typename != 'TClonesArray') return false;
07429
07430 if ((lst.arr === undefined) || (lst.arr.length === 0)) {
07431 folder._more = false;
07432 return true;
07433 }
07434
07435 folder._childs = [];
07436 for ( var i = 0; i < lst.arr.length; ++i) {
07437 var obj = lst.arr[i];
07438
07439 var item;
07440
07441 if (obj===null) {
07442 item = {
07443 _name: i.toString(),
07444 _kind: "ROOT.NULL",
07445 _title: "NULL",
07446 _obj: null
07447 }
07448 } else {
07449 item = {
07450 _name : obj.fName,
07451 _kind : "ROOT." + obj._typename,
07452 _title : obj.fTitle,
07453 _obj : obj
07454 };
07455
07456 if ((item._name === undefined) ||
07457 (!isNaN(parseInt(item._name)) && (parseInt(item._name)!==i))
07458 || (lst.arr.indexOf(obj)<i))
07459 item._name = i.toString();
07460
07461 if (item._title === undefined)
07462 item._title = obj._typename ? item._kind : item._name;
07463 }
07464
07465 folder._childs.push(item);
07466 }
07467 return true;
07468 }
07469
07470 JSROOT.Painter.TreeHierarchy = function(node, obj) {
07471 if (obj._typename != 'TTree' && obj._typename != 'TNtuple') return false;
07472
07473 node._childs = [];
07474
07475 for ( var i = 0; i < obj.fBranches.arr.length; ++i) {
07476 var branch = obj.fBranches.arr[i];
07477 var nb_leaves = branch.fLeaves.arr.length;
07478
07479
07480 if (nb_leaves == 1 && branch.fLeaves.arr[0].fName == branch.fName) nb_leaves = 0;
07481
07482 var subitem = {
07483 _name : branch.fName,
07484 _kind : nb_leaves > 0 ? "ROOT.TBranch" : "ROOT.TLeafF"
07485 }
07486
07487 node._childs.push(subitem);
07488
07489 if (nb_leaves > 0) {
07490 subitem._childs = [];
07491 for (var j = 0; j < nb_leaves; ++j) {
07492 var leafitem = {
07493 _name : branch.fLeaves.arr[j].fName,
07494 _kind : "ROOT.TLeafF"
07495 }
07496 subitem._childs.push(leafitem);
07497 }
07498 }
07499 }
07500
07501 return true;
07502 }
07503
07504 JSROOT.Painter.KeysHierarchy = function(folder, keys, file, dirname) {
07505
07506 if (keys === undefined) return false;
07507
07508 folder._childs = [];
07509
07510 for (var i = 0; i < keys.length; ++i) {
07511 var key = keys[i];
07512
07513 var item = {
07514 _name : key.fName + ";" + key.fCycle,
07515 _cycle : key.fCycle,
07516 _kind : "ROOT." + key.fClassName,
07517 _title : key.fTitle,
07518 _keyname : key.fName,
07519 _readobj : null,
07520 _parent : folder
07521 };
07522
07523 if ('fRealName' in key)
07524 item._realname = key.fRealName + ";" + key.fCycle;
07525
07526 if (key.fClassName == 'TDirectory' || key.fClassName == 'TDirectoryFile') {
07527 var dir = null;
07528 if ((dirname!=null) && (file!=null)) dir = file.GetDir(dirname + key.fName);
07529 if (dir == null) {
07530 item._more = true;
07531 item._expand = function(node, obj) {
07532
07533 return JSROOT.Painter.KeysHierarchy(node, obj.fKeys);
07534 }
07535 } else {
07536
07537 item._name = key.fName;
07538 JSROOT.Painter.KeysHierarchy(item, dir.fKeys, file, dirname + key.fName + "/");
07539 }
07540 } else
07541 if ((key.fClassName == 'TList') && (key.fName == 'StreamerInfo')) {
07542 item._name = 'StreamerInfo';
07543 item._kind = "ROOT.TStreamerInfoList";
07544 item._title = "List of streamer infos for binary I/O";
07545 item._readobj = file.fStreamerInfos;
07546 }
07547
07548 folder._childs.push(item);
07549 }
07550
07551 return true;
07552 }
07553
07554 JSROOT.Painter.ObjectHierarchy = function(top, obj, args) {
07555 if ((top==null) || (obj==null)) return false;
07556
07557
07558 var nosimple = true, prnt = top;
07559 while (prnt) {
07560 if ('_nosimple' in prnt) { nosimple = prnt._nosimple; break; }
07561 prnt = prnt._parent;
07562 }
07563
07564 top._childs = [];
07565 if (!('_obj' in top))
07566 top._obj = obj;
07567 else
07568 if (top._obj !== obj) alert('object missmatch');
07569
07570 if (!('_title' in top) && ('_typename' in obj))
07571 top._title = "ROOT." + obj._typename;
07572
07573 for (var key in obj) {
07574 if (key == '_typename') continue;
07575 var fld = obj[key];
07576 if (typeof fld == 'function') continue;
07577 if (args && args.exclude && (args.exclude.indexOf(key)>=0)) continue;
07578
07579 var item = {
07580 _parent : top,
07581 _name : key
07582 };
07583
07584 if (fld === null) {
07585 item._value = item._title = "null";
07586 if (!nosimple) top._childs.push(item);
07587 continue;
07588 }
07589
07590 var proto = Object.prototype.toString.apply(fld);
07591 var simple = false;
07592
07593 if ((proto.lastIndexOf('Array]') == proto.length-6) && (proto.indexOf('[object')==0)) {
07594 item._title = item._kind + " len=" + fld.length;
07595 simple = (proto != '[object Array]');
07596 if (fld.length === 0) {
07597 item._value = "[ ]";
07598 item._more = false;
07599 } else {
07600 item._value = "[...]";
07601 item._more = true;
07602 item._expand = JSROOT.Painter.ObjectHierarchy;
07603 item._obj = fld;
07604 }
07605 } else
07606 if (typeof fld == 'object') {
07607 if ('_typename' in fld)
07608 item._kind = item._title = "ROOT." + fld._typename;
07609
07610
07611 var curr = top, inparent = false;
07612 while (curr && !inparent) {
07613 inparent = (curr._obj === fld);
07614 curr = curr._parent;
07615 }
07616
07617 if (inparent) {
07618 item._value = "{ prnt }";
07619 simple = true;
07620 } else {
07621 item._obj = fld;
07622 item._value = "{ }";
07623 if (fld._typename == 'TColor') item._value = JSROOT.Painter.MakeColorRGB(fld);
07624 }
07625 } else
07626 if ((typeof fld == 'number') || (typeof fld == 'boolean')) {
07627 simple = true;
07628 if (key == 'fBits')
07629 item._value = "0x" + fld.toString(16);
07630 else
07631 item._value = fld.toString();
07632 item._vclass = 'h_value_num';
07633 } else
07634 if (typeof fld == 'string') {
07635 simple = true;
07636 item._value = '"' + fld + '"';
07637 item._vclass = 'h_value_str';
07638 } else {
07639 simple = true;
07640 alert('miss ' + key + ' ' + typeof fld);
07641 }
07642
07643 if (!simple || !nosimple)
07644 top._childs.push(item);
07645 }
07646 return true;
07647 }
07648
07649
07650
07651 JSROOT.hpainter = null;
07652
07653 JSROOT.HierarchyPainter = function(name, frameid, backgr) {
07654 JSROOT.TBasePainter.call(this);
07655 this.name = name;
07656 this.h = null;
07657 this.with_icons = true;
07658 this.background = backgr;
07659 this.files_monitoring = (frameid == null);
07660 if (frameid != null) this.SetDivId(frameid);
07661
07662
07663 if (JSROOT.hpainter == null)
07664 JSROOT.hpainter = this;
07665 }
07666
07667 JSROOT.HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
07668
07669 JSROOT.HierarchyPainter.prototype.Cleanup = function() {
07670
07671 this.clear(true);
07672 }
07673
07674 JSROOT.HierarchyPainter.prototype.FileHierarchy = function(file) {
07675 var painter = this;
07676
07677 var folder = {
07678 _name : file.fFileName,
07679 _kind : "ROOT.TFile",
07680 _file : file,
07681 _fullurl : file.fFullURL,
07682 _had_direct_read : false,
07683
07684 _get : function(item, itemname, callback) {
07685
07686 var fff = this;
07687
07688 if ((item!=null) && (item._readobj != null))
07689 return JSROOT.CallBack(callback, item, item._readobj);
07690
07691 if (item!=null) itemname = painter.itemFullName(item, fff);
07692
07693
07694
07695 function ReadFileObject(file) {
07696 if (fff._file==null) fff._file = file;
07697
07698 if (file == null) return JSROOT.CallBack(callback, item, null);
07699
07700 file.ReadObject(itemname, function(obj) {
07701
07702
07703 if ((item==null) && (obj!=null)) {
07704
07705 var d = painter.Find({name:itemname, top:fff, last_exists:true, check_keys:true });
07706 if ((d!=null) && ('last' in d) && (d.last!=fff)) {
07707
07708 var dir = file.GetDir(painter.itemFullName(d.last, fff));
07709 if (dir) {
07710 d.last._name = d.last._keyname;
07711 var dirname = painter.itemFullName(d.last, fff);
07712 JSROOT.Painter.KeysHierarchy(d.last, dir.fKeys, file, dirname + "/");
07713 }
07714 } else {
07715
07716 JSROOT.Painter.KeysHierarchy(fff, file.fKeys, file, "");
07717 }
07718 item = painter.Find({name:itemname, top: fff});
07719 }
07720
07721 if (item!=null) {
07722 item._readobj = obj;
07723
07724 if ('_expand' in item) item._name = item._keyname;
07725 }
07726
07727 JSROOT.CallBack(callback, item, obj);
07728 });
07729 }
07730
07731 if (fff._file != null) {
07732 ReadFileObject(fff._file);
07733 } else {
07734
07735 new JSROOT.TFile(fff._fullurl, ReadFileObject);
07736 }
07737 }
07738 };
07739
07740 JSROOT.Painter.KeysHierarchy(folder, file.fKeys, file, "");
07741
07742 return folder;
07743 }
07744
07745 JSROOT.HierarchyPainter.prototype.ForEach = function(callback, top) {
07746
07747 if (top==null) top = this.h;
07748 if ((top==null) || (typeof callback != 'function')) return;
07749 function each_item(item) {
07750 callback(item);
07751 if ('_childs' in item)
07752 for (var n = 0; n < item._childs.length; ++n) {
07753 item._childs[n]._parent = item;
07754 each_item(item._childs[n]);
07755 }
07756 }
07757
07758 each_item(top);
07759 }
07760
07761 JSROOT.HierarchyPainter.prototype.Find = function(arg) {
07762
07763
07764
07765
07766
07767
07768
07769 function find_in_hierarchy(top, fullname) {
07770
07771 if (!fullname || (fullname.length == 0) || (top==null)) return top;
07772
07773 var pos = -1;
07774
07775 function process_child(child) {
07776
07777 child._parent = top;
07778 if ((pos + 1 == fullname.length) || (pos < 0)) return child;
07779
07780 return find_in_hierarchy(child, fullname.substr(pos + 1));
07781 }
07782
07783 do {
07784
07785 pos = fullname.indexOf("/", pos + 1);
07786
07787 var localname = (pos < 0) ? fullname : fullname.substr(0, pos);
07788
07789
07790 if (typeof top._childs != 'undefined')
07791 for (var i = 0; i < top._childs.length; ++i)
07792 if (top._childs[i]._name == localname)
07793 return process_child(top._childs[i]);
07794
07795
07796 if (('check_keys' in arg) && (typeof top._childs != 'undefined'))
07797 for (var i = 0; i < top._childs.length; ++i) {
07798 if (top._childs[i]._name.indexOf(localname + ";")==0)
07799 return process_child(top._childs[i]);
07800 }
07801
07802 if ('force' in arg) {
07803
07804 if (! ('_childs' in top)) top._childs = [];
07805 var child = { _name: localname };
07806 top._childs.push(child);
07807 return process_child(child);
07808 }
07809
07810
07811 if (arg.allow_index && (typeof top._childs != 'undefined')) {
07812 var indx = parseInt(localname);
07813 if (!isNaN(indx) && (indx>=0) && (indx<top._childs.length))
07814 return process_child(top._childs[indx]);
07815 }
07816
07817 } while (pos > 0);
07818
07819 return ('last_exists' in arg) && (top!=null) ? { last : top, rest : fullname } : null;
07820 }
07821
07822 var top = this.h;
07823 var itemname = "";
07824
07825 if (typeof arg == 'string') { itemname = arg; arg = {}; } else
07826 if (typeof arg == 'object') { itemname = arg.name; if ('top' in arg) top = arg.top; } else
07827 return null;
07828
07829 return find_in_hierarchy(top, itemname);
07830 }
07831
07832 JSROOT.HierarchyPainter.prototype.itemFullName = function(node, uptoparent) {
07833 var res = "";
07834
07835 while (node && ('_parent' in node)) {
07836 if (res.length > 0) res = "/" + res;
07837 res = node._name + res;
07838 node = node._parent;
07839 if (uptoparent && (node === uptoparent)) break;
07840 }
07841
07842 return res;
07843 }
07844
07845 JSROOT.HierarchyPainter.prototype.ExecuteCommand = function(itemname, callback) {
07846
07847
07848
07849
07850 var hitem = this.Find(itemname);
07851 var url = itemname + "/cmd.json";
07852 var pthis = this;
07853 var d3node = d3.select((typeof callback == 'function') ? null : callback);
07854
07855 if ('_numargs' in hitem)
07856 for (var n = 0; n < hitem._numargs; ++n) {
07857 var argname = "arg" + (n+1);
07858 var argvalue = null;
07859 if (n+2<arguments.length) argvalue = arguments[n+2];
07860 if ((argvalue==null) && (typeof callback == 'object'))
07861 argvalue = prompt("Input argument " + argname + " for command " + hitem._name,"");
07862 if (argvalue==null) return;
07863 url += ((n==0) ? "?" : "&") + argname + "=" + argvalue;
07864 }
07865
07866 if (!d3node.empty()) {
07867 d3node.style('background','yellow');
07868 if (hitem && hitem._title) d3node.attr('title', "Executing " + hitem._title);
07869 }
07870
07871 JSROOT.NewHttpRequest(url, 'text', function(res) {
07872 if (typeof callback == 'function') return callback(res);
07873 if (d3node.empty()) return;
07874 var col = ((res!=null) && (res!='false')) ? 'green' : 'red';
07875 if (hitem && hitem._title) d3node.attr('title', hitem._title + " lastres=" + res);
07876 d3node.style('background', col).transition().duration(2000).each("end", function() { d3node.style('background', ''); });
07877 if ((col == 'green') && ('_hreload' in hitem)) pthis.reload();
07878 if ((col == 'green') && ('_update_item' in hitem)) pthis.updateItems(hitem._update_item.split(";"));
07879 }).send();
07880 }
07881
07882 JSROOT.HierarchyPainter.prototype.RefreshHtml = function(callback) {
07883 if (this.divid == null) return JSROOT.CallBack(callback);
07884 var hpainter = this;
07885 JSROOT.AssertPrerequisites('jq2d', function() {
07886 hpainter.RefreshHtml(callback);
07887 });
07888 }
07889
07890 JSROOT.HierarchyPainter.prototype.toggle = function(status, h) {
07891 var hitem = (h==null) ? this.h : h;
07892
07893 if (!('_childs' in hitem)) {
07894 if (!status || this.with_icons || ((typeof hitem._expand) !== 'function')) return;
07895 this.expand(this.itemFullName(hitem));
07896 if ('_childs' in hitem) hitem._isopen = true;
07897 return;
07898 }
07899
07900 if (hitem != this.h)
07901 if (status)
07902 hitem._isopen = true;
07903 else
07904 delete hitem._isopen;
07905
07906 for (var i=0; i < hitem._childs.length; ++i)
07907 this.toggle(status, hitem._childs[i]);
07908
07909 if (h==null) this.RefreshHtml();
07910 }
07911
07912 JSROOT.HierarchyPainter.prototype.get = function(arg, call_back, options) {
07913
07914
07915
07916 var itemname = (typeof arg == 'object') ? arg.arg : arg;
07917
07918 var item = this.Find( { name: itemname, allow_index: true } );
07919
07920
07921 var d = (item!=null) ? null : this.Find({ name: itemname, last_exists: true, check_keys: true, allow_index: true });
07922
07923
07924
07925
07926 if ((d !== null) && ('last' in d) && (d.last !== null)) {
07927 var hpainter = this;
07928 var parentname = this.itemFullName(d.last);
07929
07930
07931 if ((typeof arg == 'object') && ('rest' in arg))
07932 if ((arg.rest == d.rest) || (arg.rest.length <= d.rest.length))
07933 return JSROOT.CallBack(call_back);
07934
07935 return this.expand(parentname, function(res) {
07936 if (!res) JSROOT.CallBack(call_back);
07937 var newparentname = hpainter.itemFullName(d.last);
07938 hpainter.get( { arg: newparentname + "/" + d.rest, rest: d.rest }, call_back, options);
07939 });
07940 }
07941
07942
07943
07944 if ((item !== null) && (typeof item._obj == 'object'))
07945 return JSROOT.CallBack(call_back, item, item._obj);
07946
07947
07948 var curr = item;
07949 while (curr != null) {
07950 if (('_get' in curr) && (typeof curr._get == 'function'))
07951 return curr._get(item, null, call_back, options);
07952 curr = ('_parent' in curr) ? curr._parent : null;
07953 }
07954
07955 JSROOT.CallBack(call_back, item, null);
07956 }
07957
07958 JSROOT.HierarchyPainter.prototype.draw = function(divid, obj, drawopt) {
07959
07960 return JSROOT.draw(divid, obj, drawopt);
07961 }
07962
07963 JSROOT.HierarchyPainter.prototype.redraw = function(divid, obj, drawopt) {
07964
07965 return JSROOT.redraw(divid, obj, drawopt);
07966 }
07967
07968 JSROOT.HierarchyPainter.prototype.player = function(itemname, option, call_back) {
07969 var item = this.Find(itemname);
07970
07971 if (!item || !('_player' in item)) return JSROOT.CallBack(call_back, null);
07972
07973 var hpainter = this;
07974
07975 var prereq = ('_prereq' in item) ? item['_prereq'] : '';
07976
07977 JSROOT.AssertPrerequisites(prereq, function() {
07978
07979 var player_func = JSROOT.findFunction(item._player);
07980 if (player_func == null) return JSROOT.CallBack(call_back, null);
07981
07982 hpainter.CreateDisplay(function(mdi) {
07983 var res = null;
07984 if (mdi) res = player_func(hpainter, itemname, option);
07985 JSROOT.CallBack(call_back, res);
07986 });
07987 });
07988 }
07989
07990 JSROOT.HierarchyPainter.prototype.canDisplay = function(item, drawopt) {
07991 if (item == null) return false;
07992 if ('_player' in item) return true;
07993 if (drawopt == 'inspect') return true;
07994 var handle = JSROOT.getDrawHandle(item._kind, drawopt);
07995 return (handle!=null) && ('func' in handle);
07996 }
07997
07998 JSROOT.HierarchyPainter.prototype.display = function(itemname, drawopt, call_back) {
07999 var h = this, painter = null, updating = false;
08000
08001 function display_callback() {
08002 if (painter) painter.SetItemName(itemname, updating ? null : drawopt);
08003 JSROOT.CallBack(call_back, painter, itemname);
08004 }
08005
08006 h.CreateDisplay(function(mdi) {
08007
08008 if (!mdi) return display_callback();
08009
08010 var item = h.Find(itemname);
08011
08012 if ((item!=null) && ('_player' in item))
08013 return h.player(itemname, drawopt, display_callback);
08014
08015 updating = (typeof(drawopt)=='string') && (drawopt.indexOf("update:")==0);
08016
08017 if (updating) {
08018 drawopt = drawopt.substr(7);
08019 if ((item==null) || ('_doing_update' in item)) return display_callback();
08020 item._doing_update = true;
08021 }
08022
08023 if (item!=null) {
08024 if (!h.canDisplay(item, drawopt)) return display_callback();
08025 }
08026
08027 var divid = "";
08028 if ((typeof(drawopt)=='string') && (drawopt.indexOf("divid:")>=0)) {
08029 var pos = drawopt.indexOf("divid:");
08030 divid = drawopt.slice(pos+6);
08031 drawopt = drawopt.slice(0, pos);
08032 }
08033
08034 JSROOT.progress("Loading " + itemname);
08035
08036 h.get(itemname, function(item, obj) {
08037
08038 JSROOT.progress();
08039
08040 if (updating && item) delete item['_doing_update'];
08041 if (obj==null) return display_callback();
08042
08043 JSROOT.progress("Drawing " + itemname);
08044
08045 if (divid.length > 0) {
08046 painter = updating ? h.redraw(divid, obj, drawopt) : h.draw(divid, obj, drawopt);
08047 } else {
08048 mdi.ForEachPainter(function(p, frame) {
08049 if (p.GetItemName() != itemname) return;
08050
08051 if (!updating && (drawopt!=null) && (p.GetItemDrawOpt()!=drawopt)) return;
08052 painter = p;
08053 mdi.ActivateFrame(frame);
08054 painter.RedrawObject(obj);
08055 });
08056 }
08057
08058 if (painter==null) {
08059 if (updating) {
08060 JSROOT.console("something went wrong - did not found painter when doing update of " + itemname);
08061 } else {
08062 var frame = mdi.FindFrame(itemname, true);
08063 d3.select(frame).html("");
08064 mdi.ActivateFrame(frame);
08065 painter = h.draw(d3.select(frame).attr("id"), obj, drawopt);
08066 if (JSROOT.gStyle.DragAndDrop)
08067 h.enable_dropping(frame, itemname);
08068 }
08069 }
08070
08071 JSROOT.progress();
08072
08073 if (painter === null) return display_callback();
08074
08075 painter.WhenReady(display_callback);
08076
08077 }, drawopt);
08078 });
08079 }
08080
08081 JSROOT.HierarchyPainter.prototype.enable_dragging = function(element, itemname) {
08082
08083 }
08084
08085 JSROOT.HierarchyPainter.prototype.enable_dropping = function(frame, itemname) {
08086
08087 }
08088
08089 JSROOT.HierarchyPainter.prototype.dropitem = function(itemname, divid, call_back) {
08090 var h = this;
08091
08092 h.get(itemname, function(item, obj) {
08093 if (obj!=null) {
08094 var painter = h.draw(divid, obj, "same");
08095 if (painter) painter.WhenReady(function() { painter.SetItemName(itemname); });
08096 }
08097
08098 JSROOT.CallBack(call_back);
08099 });
08100
08101 return true;
08102 }
08103
08104 JSROOT.HierarchyPainter.prototype.updateItems = function(items) {
08105
08106
08107
08108 if ((this.disp == null) || (items==null)) return;
08109
08110 var draw_items = [], draw_options = [];
08111
08112 this.disp.ForEachPainter(function(p) {
08113 var itemname = p.GetItemName();
08114 if ((itemname==null) || (draw_items.indexOf(itemname)>=0)) return;
08115 if (typeof items == 'array') {
08116 if (items.indexOf(itemname) < 0) return;
08117 } else {
08118 if (items != itemname) return;
08119 }
08120 draw_items.push(itemname);
08121 draw_options.push("update:" + p.GetItemDrawOpt());
08122 }, true);
08123
08124 if (draw_items.length > 0)
08125 this.displayAll(draw_items, draw_options);
08126 }
08127
08128
08129 JSROOT.HierarchyPainter.prototype.updateAll = function(only_auto_items, only_items) {
08130
08131
08132
08133 if (this.disp == null) return;
08134
08135 var allitems = [], options = [], hpainter = this;
08136
08137
08138 this.disp.ForEachPainter(function(p) {
08139 var itemname = p.GetItemName();
08140 var drawopt = p.GetItemDrawOpt();
08141 if ((itemname==null) || (allitems.indexOf(itemname)>=0)) return;
08142
08143 var item = hpainter.Find(itemname);
08144 if ((item==null) || ('_not_monitor' in item) || ('_player' in item)) return;
08145 var forced = false;
08146
08147 if ('_always_monitor' in item) {
08148 forced = true;
08149 } else {
08150 var handle = JSROOT.getDrawHandle(item._kind);
08151 if (handle && ('monitor' in handle)) {
08152 if ((handle.monitor===false) || (handle.monitor=='never')) return;
08153 if (handle.monitor==='always') forced = true;
08154 }
08155 }
08156
08157 if (forced || !only_auto_items) {
08158 allitems.push(itemname);
08159 options.push("update:" + drawopt);
08160 }
08161 }, true);
08162
08163 var painter = this;
08164
08165
08166 if (this.files_monitoring)
08167 this.ForEachRootFile(function(item) {
08168 painter.ForEach(function(fitem) { delete fitem._readobj; }, item);
08169 delete item._file;
08170 });
08171
08172 this.displayAll(allitems, options);
08173 }
08174
08175 JSROOT.HierarchyPainter.prototype.displayAll = function(items, options, call_back) {
08176
08177 if ((items == null) || (items.length == 0)) return JSROOT.CallBack(call_back);
08178
08179 var h = this;
08180
08181 if (options == null) options = [];
08182 while (options.length < items.length)
08183 options.push("");
08184
08185 if ((options.length == 1) &&( options[0] == "iotest")) {
08186 h.clear();
08187 d3.select("#" + h['disp_frameid']).html("<h2>Start I/O test "+ ('IO' in JSROOT ? "Mode=" + JSROOT.IO.Mode : "") + "</h2>")
08188
08189 var tm0 = new Date();
08190 return h.get(items[0], function(item, obj) {
08191 var tm1 = new Date();
08192 d3.select("#" + h['disp_frameid']).append("h2").html("Item " + items[0] + " reading time = " + (tm1.getTime() - tm0.getTime()) + "ms");
08193 return JSROOT.CallBack(call_back);
08194 });
08195 }
08196
08197 var dropitems = new Array(items.length);
08198
08199
08200 for (var i = 0; i < items.length; ++i) {
08201 dropitems[i] = null;
08202 if (h.Find(items[i])) continue;
08203 if (h.Find(items[i] + ";1")) { items[i] += ";1"; continue; }
08204
08205 var pos = items[i].indexOf("+");
08206 if (pos>0) {
08207 dropitems[i] = items[i].split("+");
08208 items[i] = dropitems[i].shift();
08209
08210 for (var j = 0; j < dropitems[i].length; ++j) {
08211 var pos = dropitems[i][j].indexOf("_same_");
08212 if ((pos>0) && (h.Find(dropitems[i][j])==null))
08213 dropitems[i][j] = dropitems[i][j].substr(0,pos) + items[i].substr(pos);
08214 }
08215 }
08216
08217
08218 var pos = items[i].indexOf("_same_");
08219 if ((pos>0) && !h.Find(items[i]) && (i>0))
08220 items[i] = items[i].substr(0,pos) + items[0].substr(pos);
08221 }
08222
08223
08224 for (var n = items.length-1; n>=0; n--) {
08225 var hitem = h.Find(items[n]);
08226 if ((hitem==null) || h.canDisplay(hitem, options[n])) continue;
08227
08228 h.expand(items[n]);
08229 items.splice(n, 1);
08230 options.splice(n, 1);
08231 dropitems.splice(n,1);
08232 }
08233
08234 if (items.length == 0) return JSROOT.CallBack(call_back);
08235
08236 h.CreateDisplay(function(mdi) {
08237 if (!mdi) return JSROOT.CallBack(call_back);
08238
08239
08240 for (var i = 0; i < items.length; ++i)
08241 if (options[i].indexOf('update:')!=0)
08242 mdi.CreateFrame(items[i]);
08243
08244
08245 for (var i = 0; i < items.length; ++i)
08246 h.display(items[i], options[i], function(painter, itemname) {
08247
08248 var indx = items.indexOf(itemname);
08249 if (indx<0) return JSROOT.console('did not found item ' + itemname);
08250
08251 items[indx] = "---";
08252
08253 function DropNextItem() {
08254 if ((painter!=null) && (dropitems[indx]!=null) && (dropitems[indx].length>0))
08255 return h.dropitem(dropitems[indx].shift(), painter.divid, DropNextItem);
08256
08257 var isany = false;
08258 for (var cnt = 0; cnt < items.length; ++cnt)
08259 if (items[cnt]!='---') isany = true;
08260
08261
08262 if (!isany) JSROOT.CallBack(call_back);
08263 }
08264
08265 DropNextItem();
08266 });
08267 });
08268 }
08269
08270 JSROOT.HierarchyPainter.prototype.reload = function() {
08271 var hpainter = this;
08272 if ('_online' in this.h)
08273 this.OpenOnline(this.h['_online'], function() {
08274 hpainter.RefreshHtml();
08275 });
08276 }
08277
08278 JSROOT.HierarchyPainter.prototype.expand = function(itemname, call_back, d3cont) {
08279 var hpainter = this;
08280
08281 var hitem = this.Find(itemname);
08282
08283 if (!hitem && d3cont) return JSROOT.CallBack(call_back);
08284
08285 function DoExpandItem(_item, _obj, _name) {
08286 if (!_name) _name = hpainter.itemFullName(_item);
08287
08288
08289 if (_obj && _item && typeof _item._expand == 'function') {
08290 if (_item._expand(_item, _obj)) {
08291 _item._isopen = true;
08292 if (typeof hpainter.UpdateTreeNode == 'function')
08293 hpainter.UpdateTreeNode(_item, d3cont);
08294 JSROOT.CallBack(call_back, _item);
08295 return true;
08296 }
08297 }
08298
08299 if (!('_expand' in _item)) {
08300 var handle = JSROOT.getDrawHandle(_item._kind);
08301 if (handle && ('expand' in handle)) {
08302 JSROOT.AssertPrerequisites(handle.prereq, function() {
08303 _item._expand = JSROOT.findFunction(handle.expand);
08304 if (typeof _item._expand != 'function') { delete _item._expand; return; }
08305 hpainter.expand(_name, call_back, d3cont);
08306 });
08307 return true;
08308 }
08309 }
08310
08311 if (_obj && JSROOT.Painter.ObjectHierarchy(_item, _obj)) {
08312 _item._isopen = true;
08313 if (typeof hpainter.UpdateTreeNode == 'function')
08314 hpainter.UpdateTreeNode(_item, d3cont);
08315 JSROOT.CallBack(call_back, _item);
08316 return true;
08317 }
08318
08319 return false;
08320 }
08321
08322 if (hitem) {
08323
08324 if (('_more' in hitem) && !hitem._more) return JSROOT.CallBack(call_back);
08325
08326 if (DoExpandItem(hitem, hitem._obj, itemname)) return;
08327 }
08328
08329 JSROOT.progress("Loading " + itemname);
08330
08331 this.get(itemname, function(item, obj) {
08332
08333 JSROOT.progress();
08334
08335 if (obj && DoExpandItem(item, obj)) return;
08336
08337 JSROOT.CallBack(call_back);
08338 }, "hierarchy_expand" );
08339
08340 }
08341
08342 JSROOT.HierarchyPainter.prototype.GetTopOnlineItem = function(item) {
08343 if (item!=null) {
08344 while ((item!=null) && (!('_online' in item))) item = item._parent;
08345 return item;
08346 }
08347
08348 if (this.h==null) return null;
08349 if ('_online' in this.h) return this.h;
08350 if ((this.h._childs!=null) && ('_online' in this.h._childs[0])) return this.h._childs[0];
08351 return null;
08352 }
08353
08354
08355 JSROOT.HierarchyPainter.prototype.ForEachJsonFile = function(call_back) {
08356 if (this.h==null) return;
08357 if ('_jsonfile' in this.h)
08358 return JSROOT.CallBack(call_back, this.h);
08359
08360 if (this.h._childs!=null)
08361 for (var n = 0; n < this.h._childs.length; ++n) {
08362 var item = this.h._childs[n];
08363 if ('_jsonfile' in item) JSROOT.CallBack(call_back, item);
08364 }
08365 }
08366
08367 JSROOT.HierarchyPainter.prototype.OpenJsonFile = function(filepath, call_back) {
08368 var isfileopened = false;
08369 this.ForEachJsonFile(function(item) { if (item._jsonfile==filepath) isfileopened = true; });
08370 if (isfileopened) return JSROOT.CallBack(call_back);
08371
08372 var pthis = this;
08373 JSROOT.NewHttpRequest(filepath,'object', function(res) {
08374 if (res == null) return JSROOT.CallBack(call_back);
08375 var h1 = { _jsonfile : filepath, _kind : "ROOT." + res._typename, _jsontmp : res, _name: filepath.split("/").pop() };
08376 if ('fTitle' in res) h1._title = res.fTitle;
08377 h1._get = function(item,itemname,callback) {
08378 if ('_jsontmp' in item) {
08379 var res = item._jsontmp;
08380 delete item._jsontmp;
08381 return JSROOT.CallBack(callback, item, res);
08382 }
08383 JSROOT.NewHttpRequest(item._jsonfile, 'object', function(res) {
08384 return JSROOT.CallBack(callback, item, res);
08385 }).send(null);
08386 }
08387 if (pthis.h == null) pthis.h = h1; else
08388 if (pthis.h._kind == 'TopFolder') pthis.h._childs.push(h1); else {
08389 var h0 = pthis.h;
08390 var topname = ('_jsonfile' in h0) ? "Files" : "Items";
08391 pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1] };
08392 }
08393
08394 pthis.RefreshHtml(call_back);
08395 }).send(null);
08396 }
08397
08398 JSROOT.HierarchyPainter.prototype.ForEachRootFile = function(call_back) {
08399 if (this.h==null) return;
08400 if ((this.h._kind == "ROOT.TFile") && (this.h._file!=null))
08401 return JSROOT.CallBack(call_back, this.h);
08402
08403 if (this.h._childs != null)
08404 for (var n = 0; n < this.h._childs.length; ++n) {
08405 var item = this.h._childs[n];
08406 if ((item._kind == 'ROOT.TFile') && ('_fullurl' in item))
08407 JSROOT.CallBack(call_back, item);
08408 }
08409 }
08410
08411 JSROOT.HierarchyPainter.prototype.OpenRootFile = function(filepath, call_back) {
08412
08413
08414 var isfileopened = false;
08415 this.ForEachRootFile(function(item) { if (item._fullurl==filepath) isfileopened = true; });
08416 if (isfileopened) return JSROOT.CallBack(call_back);
08417
08418 var pthis = this;
08419
08420 JSROOT.OpenFile(filepath, function(file) {
08421 if (file == null) return JSROOT.CallBack(call_back);
08422 var h1 = pthis.FileHierarchy(file);
08423 h1._isopen = true;
08424 if (pthis.h == null) pthis.h = h1; else
08425 if (pthis.h._kind == 'TopFolder') pthis.h._childs.push(h1); else {
08426 var h0 = pthis.h;
08427 var topname = (h0._kind == "ROOT.TFile") ? "Files" : "Items";
08428 pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1] };
08429 }
08430
08431 pthis.RefreshHtml(call_back);
08432 });
08433 }
08434
08435 JSROOT.HierarchyPainter.prototype.GetFileProp = function(itemname) {
08436 var item = this.Find(itemname);
08437 if (item == null) return null;
08438
08439 var subname = item._name;
08440 while (item._parent != null) {
08441 item = item._parent;
08442 if ('_file' in item) {
08443 return {
08444 fileurl : item._file.fURL,
08445 itemname : subname
08446 };
08447 }
08448 subname = item._name + "/" + subname;
08449 }
08450
08451 return null;
08452 }
08453
08454 JSROOT.MarkAsStreamerInfo = function(h,item,obj) {
08455
08456
08457 if ((obj!=null) && (obj._typename=='TList'))
08458 obj._typename = 'TStreamerInfoList';
08459 }
08460
08461 JSROOT.HierarchyPainter.prototype.GetOnlineItemUrl = function(item) {
08462
08463 if ((item!=null) && (typeof item == "string")) item = this.Find(item);
08464 var top = this.GetTopOnlineItem(item);
08465 if (item==null) return null;
08466
08467 var urlpath = this.itemFullName(item, top);
08468 if (top && ('_online' in top) && (top._online!="")) urlpath = top._online + urlpath;
08469 return urlpath;
08470 }
08471
08472 JSROOT.HierarchyPainter.prototype.GetOnlineItem = function(item, itemname, callback, option) {
08473
08474
08475 var url = itemname, h_get = false, req = "", req_kind = "object", pthis = this, draw_handle = null;
08476
08477 if (option === 'hierarchy_expand') { h_get = true; option = undefined; }
08478
08479 if (item != null) {
08480 url = this.GetOnlineItemUrl(item);
08481 var func = null;
08482 if ('_kind' in item) draw_handle = JSROOT.getDrawHandle(item._kind);
08483
08484 if (h_get) {
08485 req = 'h.json?compact=3';
08486 item._expand = JSROOT.Painter.OnlineHierarchy;
08487 } else
08488 if ('_make_request' in item) {
08489 func = JSROOT.findFunction(item._make_request);
08490 } else
08491 if ((draw_handle!=null) && ('make_request' in draw_handle)) {
08492 func = draw_handle.make_request;
08493 }
08494
08495 if (typeof func == 'function') {
08496
08497 var dreq = func(pthis, item, url, option);
08498
08499 if (dreq!=null)
08500 if (typeof dreq == 'string') req = dreq; else {
08501 if ('req' in dreq) req = dreq.req;
08502 if ('kind' in dreq) req_kind = dreq.kind;
08503 }
08504 }
08505
08506 if ((req.length==0) && (item._kind.indexOf("ROOT.")!=0))
08507 req = 'item.json.gz?compact=3';
08508 }
08509
08510 if ((itemname==null) && (item!=null) && ('_cached_draw_object' in this) && (req.length == 0)) {
08511
08512 var obj = this._cached_draw_object;
08513 delete this._cached_draw_object;
08514 return JSROOT.CallBack(callback, item, obj);
08515 }
08516
08517 if (req.length == 0) req = 'root.json.gz?compact=3';
08518
08519 if (url.length > 0) url += "/";
08520 url += req;
08521
08522 var itemreq = JSROOT.NewHttpRequest(url, req_kind, function(obj) {
08523
08524 var func = null;
08525
08526 if (!h_get && (item!=null) && ('_after_request' in item)) {
08527 func = JSROOT.findFunction(item._after_request);
08528 } else
08529 if ((draw_handle!=null) && ('after_request' in draw_handle))
08530 func = draw_handle.after_request;
08531
08532 if (typeof func == 'function') {
08533 var res = func(pthis, item, obj, option, itemreq);
08534 if ((res!=null) && (typeof res == "object")) obj = res;
08535 }
08536
08537 JSROOT.CallBack(callback, item, obj);
08538 });
08539
08540 itemreq.send(null);
08541 }
08542
08543 JSROOT.Painter.OnlineHierarchy = function(node, obj) {
08544
08545
08546 if ((obj != null) && (node != null) && ('_childs' in obj)) {
08547
08548 for (var n=0;n<obj._childs.length;++n)
08549 if (obj._childs[n]._more || obj._childs[n]._childs)
08550 obj._childs[n]._expand = JSROOT.Painter.OnlineHierarchy;
08551
08552 node._childs = obj._childs;
08553 obj._childs = null;
08554 return true;
08555 }
08556
08557 return false;
08558 }
08559
08560 JSROOT.HierarchyPainter.prototype.OpenOnline = function(server_address, user_callback) {
08561 var painter = this;
08562
08563 function AdoptHierarchy(result) {
08564 painter.h = result;
08565 if (painter.h == null) return;
08566
08567 if (('_title' in painter.h) && (painter.h._title!='')) document.title = painter.h._title;
08568
08569 result._isopen = true;
08570
08571
08572 painter.h._online = server_address;
08573
08574 painter.h._get = function(item, itemname, callback, option) {
08575 painter.GetOnlineItem(item, itemname, callback, option);
08576 }
08577
08578 painter.h._expand = JSROOT.Painter.OnlineHierarchy;
08579
08580 var scripts = "", modules = "";
08581 painter.ForEach(function(item) {
08582 if ('_childs' in item) item._expand = JSROOT.Painter.OnlineHierarchy;
08583
08584 if ('_autoload' in item) {
08585 var arr = item._autoload.split(";");
08586 for (var n = 0; n < arr.length; ++n)
08587 if ((arr[n].length>3) &&
08588 ((arr[n].lastIndexOf(".js")==arr[n].length-3) ||
08589 (arr[n].lastIndexOf(".css")==arr[n].length-4))) {
08590 if (scripts.indexOf(arr[n])<0) scripts+=arr[n]+";";
08591 } else {
08592 if (modules.indexOf(arr[n])<0) modules+=arr[n]+";";
08593 }
08594 }
08595 });
08596
08597 if (scripts.length > 0) scripts = "user:" + scripts;
08598
08599
08600 JSROOT.AssertPrerequisites(modules + scripts, function() {
08601
08602 painter.ForEach(function(item) {
08603 if (!('_drawfunc' in item) || !('_kind' in item)) return;
08604 var typename = "kind:" + item._kind;
08605 if (item._kind.indexOf('ROOT.')==0) typename = item._kind.slice(5);
08606 var drawopt = item['_drawopt'];
08607 if (!JSROOT.canDraw(typename) || (drawopt!=null))
08608 JSROOT.addDrawFunc({ name: typename, func: item['_drawfunc'], script:item['_drawscript'], opt: drawopt});
08609 });
08610
08611 JSROOT.CallBack(user_callback, painter);
08612 });
08613 }
08614
08615 if (!server_address) server_address = "";
08616
08617 if (typeof server_address == 'object') {
08618 var h = server_address;
08619 server_address = "";
08620 return AdoptHierarchy(h);
08621 }
08622
08623 JSROOT.NewHttpRequest(server_address + "h.json?compact=3", 'object', AdoptHierarchy).send(null);
08624 }
08625
08626 JSROOT.HierarchyPainter.prototype.GetOnlineProp = function(itemname) {
08627 var item = this.Find(itemname);
08628 if (item == null) return null;
08629
08630 var subname = item._name;
08631 while (item._parent != null) {
08632 item = item._parent;
08633
08634 if ('_online' in item) {
08635 return {
08636 server : item._online,
08637 itemname : subname
08638 };
08639 }
08640 subname = item._name + "/" + subname;
08641 }
08642
08643 return null;
08644 }
08645
08646 JSROOT.HierarchyPainter.prototype.FillOnlineMenu = function(menu, onlineprop, itemname) {
08647
08648 var painter = this;
08649
08650 var node = this.Find(itemname);
08651 var opts = JSROOT.getDrawOptions(node._kind, 'nosame');
08652 var handle = JSROOT.getDrawHandle(node._kind);
08653 var root_type = ('_kind' in node) ? node._kind.indexOf("ROOT.") == 0 : false;
08654
08655 if (opts != null)
08656 menu.addDrawMenu("Draw", opts, function(arg) { painter.display(itemname, arg); });
08657
08658 if ((node['_childs'] == null) && (node['_more'] || root_type))
08659 menu.add("Expand", function() { painter.expand(itemname); });
08660
08661 if (handle && ('execute' in handle))
08662 menu.add("Execute", function() { painter.ExecuteCommand(itemname, menu.tree_node); });
08663
08664 var drawurl = onlineprop.server + onlineprop.itemname + "/draw.htm";
08665 var separ = "?";
08666 if (this.IsMonitoring()) {
08667 drawurl += separ + "monitoring=" + this.MonitoringInterval();
08668 separ = "&";
08669 }
08670
08671 if (opts != null)
08672 menu.addDrawMenu("Draw in new window", opts, function(arg) { window.open(drawurl+separ+"opt=" +arg); });
08673
08674 if ((opts!=null) && (opts.length > 0) && root_type)
08675 menu.addDrawMenu("Draw as png", opts, function(arg) {
08676 window.open(onlineprop.server + onlineprop.itemname + "/root.png?w=400&h=300&opt=" + arg);
08677 });
08678
08679 if ('_player' in node)
08680 menu.add("Player", function() { painter.player(itemname); });
08681 }
08682
08683 JSROOT.HierarchyPainter.prototype.Adopt = function(h) {
08684 this.h = h;
08685 this.RefreshHtml();
08686 }
08687
08688 JSROOT.HierarchyPainter.prototype.SetMonitoring = function(val) {
08689 this._monitoring_on = false;
08690 this._monitoring_interval = 3000;
08691
08692 val = (val === undefined) ? 0 : parseInt(val);
08693
08694 if (!isNaN(val) && (val>0)) {
08695 this._monitoring_on = true;
08696 this._monitoring_interval = Math.max(100,val);
08697 }
08698 }
08699
08700 JSROOT.HierarchyPainter.prototype.MonitoringInterval = function(val) {
08701
08702 return ('_monitoring_interval' in this) ? this._monitoring_interval : 3000;
08703 }
08704
08705 JSROOT.HierarchyPainter.prototype.EnableMonitoring = function(on) {
08706 this._monitoring_on = on;
08707 }
08708
08709 JSROOT.HierarchyPainter.prototype.IsMonitoring = function() {
08710 return this._monitoring_on;
08711 }
08712
08713 JSROOT.HierarchyPainter.prototype.SetDisplay = function(layout, frameid) {
08714 if ((frameid==null) && (typeof layout == 'object')) {
08715 this.disp = layout;
08716 this.disp_kind = 'custom';
08717 this.disp_frameid = null;
08718 } else {
08719 this.disp_kind = layout;
08720 this.disp_frameid = frameid;
08721 }
08722 }
08723
08724 JSROOT.HierarchyPainter.prototype.GetLayout = function() {
08725 return this.disp_kind;
08726 }
08727
08728 JSROOT.HierarchyPainter.prototype.clear = function(withbrowser) {
08729 if ('disp' in this) {
08730 this.disp.Reset();
08731 delete this.disp;
08732 }
08733
08734 if (withbrowser) {
08735 this.select_main().html("");
08736 delete this.h;
08737 } else {
08738
08739 this.ForEach(function(item) {
08740 if (('clear' in item) && (typeof item.clear=='function')) item.clear();
08741 });
08742 }
08743 }
08744
08745 JSROOT.HierarchyPainter.prototype.GetDisplay = function() {
08746 return ('disp' in this) ? this.disp : null;
08747 }
08748
08749 JSROOT.HierarchyPainter.prototype.CreateDisplay = function(callback) {
08750
08751 var h = this;
08752
08753 if ('disp' in this) {
08754 if ((h.disp.NumDraw() > 0) || (h.disp_kind == "custom")) return JSROOT.CallBack(callback, h.disp);
08755 h.disp.Reset();
08756 delete h.disp;
08757 }
08758
08759
08760 if (document.getElementById(this.disp_frameid) == null)
08761 return JSROOT.CallBack(callback, null);
08762
08763 if (h.disp_kind == "simple")
08764 h.disp = new JSROOT.SimpleDisplay(h.disp_frameid);
08765 else
08766 if (h.disp_kind.search("grid") == 0)
08767 h.disp = new JSROOT.GridDisplay(h.disp_frameid, h.disp_kind);
08768 else
08769 return JSROOT.AssertPrerequisites('jq2d', function() { h.CreateDisplay(callback); });
08770
08771 JSROOT.CallBack(callback, h.disp);
08772 }
08773
08774 JSROOT.HierarchyPainter.prototype.updateOnOtherFrames = function(painter, obj) {
08775
08776 var mdi = this.disp;
08777 if (mdi==null) return false;
08778
08779 var isany = false;
08780 mdi.ForEachPainter(function(p, frame) {
08781 if ((p===painter) || (p.GetItemName() != painter.GetItemName())) return;
08782 mdi.ActivateFrame(frame);
08783 p.RedrawObject(obj);
08784 isany = true;
08785 });
08786 return isany;
08787 }
08788
08789 JSROOT.HierarchyPainter.prototype.CheckResize = function(size) {
08790 if ('disp' in this)
08791 this.disp.CheckMDIResize(null, size);
08792 }
08793
08794 JSROOT.HierarchyPainter.prototype.StartGUI = function(h0, call_back) {
08795 var hpainter = this;
08796 var filesarr = JSROOT.GetUrlOptionAsArray("file;files");
08797 var jsonarr = JSROOT.GetUrlOptionAsArray("json");
08798 var filesdir = JSROOT.GetUrlOption("path");
08799 var expanditems = JSROOT.GetUrlOptionAsArray("expand");
08800 if (expanditems.length==0 && (JSROOT.GetUrlOption("expand")=="")) expanditems.push("");
08801
08802 if (filesdir!=null) {
08803 for (var i=0;i<filesarr.length;++i) filesarr[i] = filesdir + filesarr[i];
08804 for (var i=0;i<jsonarr.length;++i) jsonarr[i] = filesdir + jsonarr[i];
08805 }
08806
08807 var itemsarr = JSROOT.GetUrlOptionAsArray("item;items");
08808 if ((itemsarr.length==0) && JSROOT.GetUrlOption("item")=="") itemsarr.push("");
08809
08810 var optionsarr = JSROOT.GetUrlOptionAsArray("opt;opts");
08811
08812 var monitor = JSROOT.GetUrlOption("monitoring");
08813
08814 if ((jsonarr.length==1) && (itemsarr.length==0) && (expanditems.length==0)) itemsarr.push("");
08815
08816 if (!this.disp_kind) {
08817 var layout = JSROOT.GetUrlOption("layout");
08818 if ((typeof layout == "string") && (layout.length>0))
08819 this.disp_kind = layout;
08820 else
08821 switch (itemsarr.length) {
08822 case 0:
08823 case 1: this.disp_kind = 'simple'; break;
08824 case 2: this.disp_kind = 'grid 1x2'; break;
08825 default: this.disp_kind = 'flex';
08826 }
08827 }
08828
08829 if (JSROOT.GetUrlOption('files_monitoring')!=null) this.files_monitoring = true;
08830
08831
08832
08833 this.SetMonitoring(monitor);
08834
08835 function OpenAllFiles() {
08836 if (jsonarr.length>0)
08837 hpainter.OpenJsonFile(jsonarr.shift(), OpenAllFiles);
08838 else if (filesarr.length>0)
08839 hpainter.OpenRootFile(filesarr.shift(), OpenAllFiles);
08840 else if (expanditems.length>0)
08841 hpainter.expand(expanditems.shift(), OpenAllFiles);
08842 else
08843 hpainter.displayAll(itemsarr, optionsarr, function() {
08844 hpainter.RefreshHtml();
08845
08846 JSROOT.RegisterForResize(hpainter);
08847
08848 setInterval(function() { hpainter.updateAll(!hpainter.IsMonitoring()); }, hpainter.MonitoringInterval());
08849
08850 JSROOT.CallBack(call_back);
08851 });
08852 }
08853
08854 function AfterOnlineOpened() {
08855
08856 if (('_monitoring' in hpainter.h) && (monitor==null)) {
08857 hpainter.SetMonitoring(hpainter.h._monitoring);
08858 }
08859
08860 if (('_layout' in hpainter.h) && (layout==null)) {
08861 hpainter.disp_kind = hpainter.h._layout;
08862 }
08863
08864 if (('_loadfile' in hpainter.h) && (filesarr.length==0)) {
08865 filesarr = JSROOT.ParseAsArray(hpainter.h._loadfile);
08866 }
08867
08868 if (('_drawitem' in hpainter.h) && (itemsarr.length==0)) {
08869 itemsarr = JSROOT.ParseAsArray(hpainter.h._drawitem);
08870 optionsarr = JSROOT.ParseAsArray(hpainter.h['_drawopt']);
08871 }
08872
08873 OpenAllFiles();
08874 }
08875
08876 if (h0!=null) hpainter.OpenOnline(h0, AfterOnlineOpened);
08877 else OpenAllFiles();
08878 }
08879
08880 JSROOT.BuildNobrowserGUI = function() {
08881 var myDiv = d3.select('#simpleGUI');
08882 var online = false, drawing = false;
08883
08884 if (myDiv.empty()) {
08885 online = true;
08886 myDiv = d3.select('#onlineGUI');
08887 if (myDiv.empty()) { myDiv = d3.select('#drawGUI'); drawing = true; }
08888 if (myDiv.empty()) return alert('no div for simple nobrowser gui found');
08889 }
08890
08891 JSROOT.Painter.readStyleFromURL();
08892
08893 d3.select('html').style('height','100%');
08894 d3.select('body').style({ 'min-height':'100%', 'margin':'0px', "overflow": "hidden"});
08895
08896 myDiv.style({"position":"absolute", "left":"1px", "top" :"1px", "bottom" :"1px", "right": "1px"});
08897
08898 var hpainter = new JSROOT.HierarchyPainter('root', null);
08899 hpainter.SetDisplay(JSROOT.GetUrlOption("layout", null, "simple"), myDiv.attr('id'));
08900
08901 var h0 = null;
08902 if (online) {
08903 var func = JSROOT.findFunction('GetCachedHierarchy');
08904 if (typeof func == 'function') h0 = func();
08905 if (typeof h0 != 'object') h0 = "";
08906 }
08907
08908 hpainter.StartGUI(h0, function() {
08909 if (!drawing) return;
08910 var func = JSROOT.findFunction('GetCachedObject');
08911 var obj = (typeof func == 'function') ? JSROOT.JSONR_unref(func()) : null;
08912 if (obj!=null) hpainter['_cached_draw_object'] = obj;
08913 var opt = JSROOT.GetUrlOption("opt");
08914 hpainter.display("", opt);
08915 });
08916 }
08917
08918 JSROOT.Painter.drawStreamerInfo = function(divid, lst) {
08919 var painter = new JSROOT.HierarchyPainter('sinfo', divid, 'white');
08920
08921 painter.h = { _name : "StreamerInfo", _childs : [] };
08922
08923 for ( var i = 0; i < lst.arr.length; ++i) {
08924 var entry = lst.arr[i]
08925
08926 if (entry._typename == "TList") continue;
08927
08928 if (typeof (entry.fName) == 'undefined') {
08929 JSROOT.console("strange element in StreamerInfo with type " + entry._typename);
08930 continue;
08931 }
08932
08933 var item = {
08934 _name : entry.fName + ";" + entry.fClassVersion,
08935 _kind : "class " + entry.fName,
08936 _title : "class:" + entry.fName + ' version:' + entry.fClassVersion + ' checksum:' + entry.fCheckSum,
08937 _icon: "img_class",
08938 _childs : []
08939 };
08940
08941 if (entry.fTitle != '') item._title += ' ' + entry.fTitle;
08942
08943 painter.h._childs.push(item);
08944
08945 if (typeof entry.fElements == 'undefined') continue;
08946 for ( var l = 0; l < entry.fElements.arr.length; ++l) {
08947 var elem = entry.fElements.arr[l];
08948 if ((elem == null) || (typeof (elem.fName) == 'undefined')) continue;
08949 var info = elem.fTypeName + " " + elem.fName + ";";
08950 if (elem.fTitle != '') info += " // " + elem.fTitle;
08951 item._childs.push({ _name : info, _title: elem.fTypeName, _kind:elem.fTypeName, _icon: (elem.fTypeName == 'BASE') ? "img_class" : "img_member" });
08952 }
08953 if (item._childs.length == 0) delete item._childs;
08954 }
08955
08956
08957 painter.RefreshHtml(function() {
08958 painter.SetDivId(divid);
08959 painter.DrawingReady();
08960 });
08961
08962 return painter;
08963 }
08964
08965 JSROOT.Painter.drawInspector = function(divid, obj) {
08966 var painter = new JSROOT.HierarchyPainter('inspector', divid, 'white');
08967 painter.default_by_click = "expand";
08968 painter.with_icons = false;
08969 painter.h = { _name: "Object", _title: "ROOT." + obj._typename, _click_action: "expand", _nosimple: false };
08970 if ((typeof obj.fName === 'string') && (obj.fName.length>0))
08971 painter.h._name = obj.fName;
08972
08973 JSROOT.Painter.ObjectHierarchy(painter.h, obj);
08974 painter.RefreshHtml(function() {
08975 painter.SetDivId(divid);
08976 painter.DrawingReady();
08977 });
08978
08979 return painter;
08980 }
08981
08982
08983
08984
08985
08986 JSROOT.MDIDisplay = function(frameid) {
08987 this.frameid = frameid;
08988 d3.select("#"+this.frameid).property('mdi', this);
08989 }
08990
08991 JSROOT.MDIDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
08992
08993
08994
08995 console.warn("ForEachFrame not implemented in MDIDisplay");
08996 }
08997
08998 JSROOT.MDIDisplay.prototype.ForEachPainter = function(userfunc, only_visible) {
08999
09000
09001
09002 this.ForEachFrame(function(frame) {
09003 var dummy = new JSROOT.TObjectPainter();
09004 dummy.SetDivId(d3.select(frame).attr('id'), -1);
09005 dummy.ForEachPainter(function(painter) { userfunc(painter, frame); });
09006 }, only_visible);
09007 }
09008
09009 JSROOT.MDIDisplay.prototype.NumDraw = function() {
09010 var cnt = 0;
09011 this.ForEachFrame(function() { ++cnt; });
09012 return cnt;
09013 }
09014
09015 JSROOT.MDIDisplay.prototype.FindFrame = function(searchtitle, force) {
09016 var found_frame = null;
09017
09018 this.ForEachFrame(function(frame) {
09019 if (d3.select(frame).attr('frame_title') == searchtitle)
09020 found_frame = frame;
09021 });
09022
09023 if ((found_frame == null) && force)
09024 found_frame = this.CreateFrame(searchtitle);
09025
09026 return found_frame;
09027 }
09028
09029 JSROOT.MDIDisplay.prototype.ActivateFrame = function(frame) {
09030
09031 }
09032
09033 JSROOT.MDIDisplay.prototype.CheckMDIResize = function(only_frame_id, size) {
09034
09035 var resized_frame = null;
09036
09037 this.ForEachPainter(function(painter, frame) {
09038
09039 if ((only_frame_id !== null) && (d3.select(frame).attr('id') != only_frame_id)) return;
09040
09041 if ((painter.GetItemName()!==null) && (typeof painter.CheckResize == 'function')) {
09042
09043 if (resized_frame === frame) return;
09044 painter.CheckResize(size);
09045 resized_frame = frame;
09046 }
09047 });
09048 }
09049
09050 JSROOT.MDIDisplay.prototype.Reset = function() {
09051
09052 this.ForEachFrame(function(frame) {
09053 JSROOT.cleanup(frame);
09054 });
09055
09056 d3.select("#"+this.frameid).html("").property('mdi', null);
09057 }
09058
09059 JSROOT.MDIDisplay.prototype.Draw = function(title, obj, drawopt) {
09060
09061 if (!obj) return;
09062
09063 if (!JSROOT.canDraw(obj._typename, drawopt)) return;
09064
09065 var frame = this.FindFrame(title, true);
09066
09067 this.ActivateFrame(frame);
09068
09069 return JSROOT.redraw(d3.select(frame).attr("id"), obj, drawopt);
09070 }
09071
09072
09073
09074
09075 JSROOT.CustomDisplay = function() {
09076 JSROOT.MDIDisplay.call(this, "dummy");
09077 this.frames = {};
09078 }
09079
09080 JSROOT.CustomDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
09081
09082 JSROOT.CustomDisplay.prototype.AddFrame = function(divid, itemname) {
09083 if (!(divid in this.frames)) this.frames[divid] = "";
09084
09085 this.frames[divid] += (itemname + ";");
09086 }
09087
09088 JSROOT.CustomDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
09089 var ks = Object.keys(this.frames);
09090 for (var k = 0; k < ks.length; ++k) {
09091 var node = d3.select("#"+ks[k]);
09092 if (!node.empty())
09093 JSROOT.CallBack(userfunc, node.node());
09094 }
09095 }
09096
09097 JSROOT.CustomDisplay.prototype.CreateFrame = function(title) {
09098 var ks = Object.keys(this.frames);
09099 for (var k = 0; k < ks.length; ++k) {
09100 var items = this.frames[ks[k]];
09101 if (items.indexOf(title+";")>=0)
09102 return d3.select("#"+ks[k]).node();
09103 }
09104 return null;
09105 }
09106
09107 JSROOT.CustomDisplay.prototype.Reset = function() {
09108 JSROOT.MDIDisplay.prototype.Reset.call(this);
09109 this.ForEachFrame(function(frame) {
09110 d3.select(frame).html("");
09111 });
09112 }
09113
09114
09115
09116 JSROOT.SimpleDisplay = function(frameid) {
09117 JSROOT.MDIDisplay.call(this, frameid);
09118 }
09119
09120 JSROOT.SimpleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
09121
09122 JSROOT.SimpleDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
09123 var node = d3.select("#"+this.frameid + "_simple_display");
09124 if (!node.empty())
09125 JSROOT.CallBack(userfunc, node.node());
09126 }
09127
09128 JSROOT.SimpleDisplay.prototype.CreateFrame = function(title) {
09129
09130 JSROOT.cleanup(this.frameid+"_simple_display");
09131
09132 return d3.select("#"+this.frameid)
09133 .html("")
09134 .append("div")
09135 .attr("id", this.frameid + "_simple_display")
09136 .style("width", "100%")
09137 .style("height", "100%")
09138 .style("overflow" ,"hidden")
09139 .attr("frame_title", title)
09140 .node();
09141 }
09142
09143 JSROOT.SimpleDisplay.prototype.Reset = function() {
09144 JSROOT.MDIDisplay.prototype.Reset.call(this);
09145
09146 d3.select("#"+this.frameid).html("");
09147 }
09148
09149
09150
09151 JSROOT.GridDisplay = function(frameid, sizex, sizey) {
09152
09153
09154
09155
09156
09157
09158 JSROOT.MDIDisplay.call(this, frameid);
09159 this.cnt = 0;
09160 if (typeof sizex == "string") {
09161 if (sizex.search("grid") == 0)
09162 sizex = sizex.slice(4).trim();
09163
09164 var separ = sizex.search("x");
09165
09166 if (separ > 0) {
09167 sizey = parseInt(sizex.slice(separ + 1));
09168 sizex = parseInt(sizex.slice(0, separ));
09169 } else {
09170 sizex = parseInt(sizex);
09171 sizey = sizex;
09172 }
09173
09174 if (isNaN(sizex)) sizex = 3;
09175 if (isNaN(sizey)) sizey = 3;
09176 }
09177
09178 if (!sizex) sizex = 3;
09179 if (!sizey) sizey = sizex;
09180 this.sizex = sizex;
09181 this.sizey = sizey;
09182 }
09183
09184 JSROOT.GridDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
09185
09186 JSROOT.GridDisplay.prototype.NumGridFrames = function() {
09187 return this.sizex*this.sizey;
09188 }
09189
09190 JSROOT.GridDisplay.prototype.IsSingle = function() {
09191 return (this.sizex == 1) && (this.sizey == 1);
09192 }
09193
09194 JSROOT.GridDisplay.prototype.ForEachFrame = function(userfunc, only_visible) {
09195 for (var cnt = 0; cnt < this.sizex * this.sizey; ++cnt) {
09196 var elem = this.IsSingle() ? d3.select("#"+this.frameid) : d3.select("#" + this.frameid + "_grid_" + cnt);
09197
09198 if (!elem.empty() && elem.attr('frame_title') != '')
09199 JSROOT.CallBack(userfunc, elem.node());
09200 }
09201 }
09202
09203 JSROOT.GridDisplay.prototype.CreateFrame = function(title) {
09204
09205 var main = d3.select("#" + this.frameid);
09206 if (main.empty()) return null;
09207
09208 var drawid = this.frameid;
09209
09210 if (!this.IsSingle()) {
09211 var topid = this.frameid + '_grid';
09212 if (d3.select("#" + topid).empty()) {
09213 var rect = main.node().getBoundingClientRect();
09214 var h = Math.floor(rect.height / this.sizey) - 1;
09215 var w = Math.floor(rect.width / this.sizex) - 1;
09216
09217 var content = "<div style='width:100%; height:100%; margin:0; padding:0; border:0; overflow:hidden'>"+
09218 "<table id='" + topid + "' style='width:100%; height:100%; table-layout:fixed; border-collapse: collapse;'>";
09219 var cnt = 0;
09220 for (var i = 0; i < this.sizey; ++i) {
09221 content += "<tr>";
09222 for (var j = 0; j < this.sizex; ++j)
09223 content += "<td><div id='" + topid + "_" + cnt++ + "' class='grid_cell'></div></td>";
09224 content += "</tr>";
09225 }
09226 content += "</table></div>";
09227
09228 main.html(content);
09229 main.selectAll('.grid_cell').style({ 'width': w + 'px', 'height': h + 'px', 'overflow' : 'hidden'});
09230 }
09231
09232 drawid = topid + "_" + this.cnt;
09233 if (++this.cnt >= this.sizex * this.sizey) this.cnt = 0;
09234 }
09235
09236 JSROOT.cleanup(drawid);
09237
09238 return d3.select("#" + drawid).html("").attr('frame_title', title).node();
09239 }
09240
09241 JSROOT.GridDisplay.prototype.Reset = function() {
09242 JSROOT.MDIDisplay.prototype.Reset.call(this);
09243 if (this.IsSingle())
09244 d3.select("#" + this.frameid).attr('frame_title', null);
09245 this.cnt = 0;
09246 }
09247
09248 JSROOT.GridDisplay.prototype.CheckMDIResize = function(frame_id, size) {
09249
09250 if (!this.IsSingle()) {
09251 var main = d3.select("#" + this.frameid);
09252 var rect = main.node().getBoundingClientRect();
09253 var h = Math.floor(rect.height / this.sizey) - 1;
09254 var w = Math.floor(rect.width / this.sizex) - 1;
09255 main.selectAll('.grid_cell').style({ 'width': w + 'px', 'height': h + 'px'});
09256 }
09257
09258 JSROOT.MDIDisplay.prototype.CheckMDIResize.call(this, frame_id, size);
09259 }
09260
09261
09262
09263 JSROOT.RegisterForResize = function(handle, delay) {
09264
09265
09266
09267
09268
09269
09270 if ((handle===null) || (handle === undefined)) return;
09271
09272 var myInterval = null, myDelay = delay ? delay : 300;
09273
09274 if (myDelay < 20) myDelay = 20;
09275
09276 function ResizeTimer() {
09277 myInterval = null;
09278
09279 document.body.style.cursor = 'wait';
09280 if (typeof handle == 'function') handle(); else
09281 if ((typeof handle == 'object') && (typeof handle.CheckResize == 'function')) handle.CheckResize(); else
09282 if (typeof handle == 'string') {
09283 var node = d3.select('#'+handle);
09284 if (!node.empty()) {
09285 var mdi = node.property('mdi');
09286 if (mdi) {
09287 mdi.CheckMDIResize();
09288 } else {
09289 JSROOT.resize(node.node());
09290 }
09291 }
09292 }
09293 document.body.style.cursor = 'auto';
09294 }
09295
09296 function ProcessResize() {
09297 if (myInterval !== null) clearTimeout(myInterval);
09298 myInterval = setTimeout(ResizeTimer, myDelay);
09299 }
09300
09301 window.addEventListener('resize', ProcessResize);
09302 }
09303
09304 JSROOT.addDrawFunc({ name: "TCanvas", icon: "img_canvas", func: JSROOT.Painter.drawCanvas });
09305 JSROOT.addDrawFunc({ name: "TPad", icon: "img_canvas", func: JSROOT.Painter.drawPad });
09306 JSROOT.addDrawFunc({ name: "TSlider", icon: "img_canvas", func: JSROOT.Painter.drawPad });
09307 JSROOT.addDrawFunc({ name: "TFrame", icon: "img_frame", func: JSROOT.Painter.drawFrame });
09308 JSROOT.addDrawFunc({ name: "TPaveText", icon: "img_pavetext", func: JSROOT.Painter.drawPaveText });
09309 JSROOT.addDrawFunc({ name: "TPaveStats", icon: "img_pavetext", func: JSROOT.Painter.drawPaveText });
09310 JSROOT.addDrawFunc({ name: "TPaveLabel", icon: "img_pavelabel", func: JSROOT.Painter.drawPaveText });
09311 JSROOT.addDrawFunc({ name: "TLatex", icon:"img_text", func: JSROOT.Painter.drawText });
09312 JSROOT.addDrawFunc({ name: "TMathText", icon:"img_text", func: JSROOT.Painter.drawText });
09313 JSROOT.addDrawFunc({ name: "TText", icon:"img_text", func: JSROOT.Painter.drawText });
09314 JSROOT.addDrawFunc({ name: /^TH1/, icon: "img_histo1d", func: JSROOT.Painter.drawHistogram1D, opt:";hist;P;P0;E;E1;E2;same"});
09315 JSROOT.addDrawFunc({ name: "TProfile", icon: "img_profile", func: JSROOT.Painter.drawHistogram1D, opt:";E0;E1;E2;p;hist"});
09316 JSROOT.addDrawFunc({ name: /^TH2/, icon: "img_histo2d", prereq: "more2d", func: "JSROOT.Painter.drawHistogram2D", opt:";COL;COLZ;COL0Z;BOX;SCAT;TEXT;LEGO;same" });
09317 JSROOT.addDrawFunc({ name: /^TH3/, icon: 'img_histo3d', prereq: "3d", func: "JSROOT.Painter.drawHistogram3D" });
09318 JSROOT.addDrawFunc({ name: "THStack", prereq: "more2d", func: "JSROOT.Painter.drawHStack" });
09319 JSROOT.addDrawFunc({ name: "TPolyMarker3D", icon: 'img_histo3d', prereq: "3d", func: "JSROOT.Painter.drawPolyMarker3D" });
09320 JSROOT.addDrawFunc({ name: "TGraphPolargram" });
09321 JSROOT.addDrawFunc({ name: /^TGraph/, icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraph", opt:";L;P"});
09322 JSROOT.addDrawFunc({ name: "TCutG", icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraph", opt:";L;P"});
09323 JSROOT.addDrawFunc({ name: /^RooHist/, icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraph", opt:";L;P" });
09324 JSROOT.addDrawFunc({ name: /^RooCurve/, icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraph", opt:";L;P" });
09325 JSROOT.addDrawFunc({ name: "TMultiGraph", icon:"img_mgraph", prereq: "more2d", func: "JSROOT.Painter.drawMultiGraph" });
09326 JSROOT.addDrawFunc({ name: "TStreamerInfoList", icon:'img_question', func: JSROOT.Painter.drawStreamerInfo });
09327 JSROOT.addDrawFunc({ name: "TPaletteAxis", icon: "img_colz", prereq: "more2d", func: "JSROOT.Painter.drawPaletteAxis" });
09328 JSROOT.addDrawFunc({ name: "kind:Text", icon:"img_text", func: JSROOT.Painter.drawRawText });
09329 JSROOT.addDrawFunc({ name: "TF1", icon: "img_graph", prereq: "math;more2d", func: "JSROOT.Painter.drawFunction" });
09330 JSROOT.addDrawFunc({ name: "TEllipse", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawEllipse" });
09331 JSROOT.addDrawFunc({ name: "TLine", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawLine" });
09332 JSROOT.addDrawFunc({ name: "TArrow", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawArrow" });
09333 JSROOT.addDrawFunc({ name: "TGaxis", icon: "img_graph", func: JSROOT.drawGaxis });
09334 JSROOT.addDrawFunc({ name: "TLegend", icon: "img_pavelabel", prereq: "more2d", func: "JSROOT.Painter.drawLegend" });
09335 JSROOT.addDrawFunc({ name: "TBox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox" });
09336 JSROOT.addDrawFunc({ name: "TWbox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox" });
09337 JSROOT.addDrawFunc({ name: "TSliderBox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox" });
09338 JSROOT.addDrawFunc({ name: "TGeoVolume", icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeometry", expand: "JSROOT.expandGeoVolume", opt:"all;count;limit;maxlvl2;" });
09339 JSROOT.addDrawFunc({ name: "TEveGeoShapeExtract", icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeometry", opt: ";count;limit;maxlvl2" });
09340 JSROOT.addDrawFunc({ name: "TGeoManager", icon: 'img_histo3d', prereq: "geom", expand: "JSROOT.expandGeoManagerHierarchy" });
09341 JSROOT.addDrawFunc({ name: /^TGeo/, icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeoObject", opt: "all" });
09342
09343 JSROOT.addDrawFunc({ name: "kind:Command", icon: "img_execute", execute: true });
09344 JSROOT.addDrawFunc({ name: "TFolder", icon: "img_folder", icon2: "img_folderopen", noinspect: true, expand: JSROOT.Painter.FolderHierarchy });
09345 JSROOT.addDrawFunc({ name: "TTask", icon: "img_task", expand: JSROOT.Painter.TaskHierarchy, for_derived: true });
09346 JSROOT.addDrawFunc({ name: "TTree", icon: "img_tree", noinspect:true, expand: JSROOT.Painter.TreeHierarchy });
09347 JSROOT.addDrawFunc({ name: "TNtuple", icon: "img_tree", noinspect:true, expand: JSROOT.Painter.TreeHierarchy });
09348 JSROOT.addDrawFunc({ name: "TBranch", icon: "img_branch", noinspect:true });
09349 JSROOT.addDrawFunc({ name: /^TLeaf/, icon: "img_leaf" });
09350 JSROOT.addDrawFunc({ name: "TList", icon: "img_list", noinspect:true, expand: JSROOT.Painter.ListHierarchy });
09351 JSROOT.addDrawFunc({ name: "TObjArray", icon: "img_list", noinspect:true, expand: JSROOT.Painter.ListHierarchy });
09352 JSROOT.addDrawFunc({ name: "TClonesArray", icon: "img_list", noinspect:true, expand: JSROOT.Painter.ListHierarchy });
09353 JSROOT.addDrawFunc({ name: "TColor", icon: "img_color" });
09354 JSROOT.addDrawFunc({ name: "TFile", icon: "img_file", noinspect:true });
09355 JSROOT.addDrawFunc({ name: "TMemFile", icon: "img_file", noinspect:true });
09356 JSROOT.addDrawFunc({ name: "Session", icon: "img_globe" });
09357 JSROOT.addDrawFunc({ name: "kind:TopFolder", icon: "img_base" });
09358 JSROOT.addDrawFunc({ name: "kind:Folder", icon: "img_folder", icon2: "img_folderopen", noinspect:true });
09359
09360 JSROOT.getDrawHandle = function(kind, selector) {
09361
09362
09363
09364
09365
09366
09367 if (typeof kind != 'string') return null;
09368 if (selector === "") selector = null;
09369
09370 var first = null;
09371
09372 if ((selector === null) && (kind in JSROOT.DrawFuncs.cache))
09373 return JSROOT.DrawFuncs.cache[kind];
09374
09375 var search = (kind.indexOf("ROOT.")==0) ? kind.substr(5) : "kind:"+kind;
09376
09377 var counter = 0;
09378 for (var i=0; i < JSROOT.DrawFuncs.lst.length; ++i) {
09379 var h = JSROOT.DrawFuncs.lst[i];
09380 if (typeof h.name == "string") {
09381 if (h.name != search) continue;
09382 } else {
09383 if (!search.match(h.name)) continue;
09384 }
09385
09386 if (selector==null) {
09387
09388 if (!(kind in JSROOT.DrawFuncs.cache)) JSROOT.DrawFuncs.cache[kind] = h;
09389 return h;
09390 } else
09391 if (typeof selector=='string') {
09392 if (first == null) first = h;
09393
09394 if ('opt' in h) {
09395 var opts = h.opt.split(';');
09396 for (var j=0; j < opts.length; ++j) opts[j] = opts[j].toLowerCase();
09397 if (opts.indexOf(selector.toLowerCase())>=0) return h;
09398 }
09399 } else {
09400 if (selector === counter) return h;
09401 }
09402 ++counter;
09403 }
09404
09405 return first;
09406 }
09407
09408 JSROOT.addStreamerInfos = function(lst) {
09409 if (lst === null) return;
09410
09411 function CheckBaseClasses(si, lvl) {
09412 if (si.fElements == null) return null;
09413 if (lvl>10) return null;
09414
09415 for (var j=0; j<si.fElements.arr.length; ++j) {
09416
09417 var element = si.fElements.arr[j];
09418 if (element.fTypeName !== 'BASE') continue;
09419
09420 var handle = JSROOT.getDrawHandle("ROOT." + element.fName);
09421 if (handle && !handle.for_derived) handle = null;
09422
09423
09424 if (handle === null)
09425 for (var k=0;k<lst.arr.length; ++k)
09426 if (lst.arr[k].fName === element.fName) {
09427 handle = CheckBaseClasses(lst.arr[k], lvl+1);
09428 break;
09429 }
09430
09431 if (handle && handle.for_derived) return handle;
09432 }
09433 return null;
09434 }
09435
09436 for (var n=0;n<lst.arr.length;++n) {
09437 var si = lst.arr[n];
09438 if (JSROOT.getDrawHandle("ROOT." + si.fName) !== null) continue;
09439
09440 var handle = CheckBaseClasses(si, 0);
09441
09442 if (!handle) continue;
09443
09444
09445
09446 var newhandle = JSROOT.extend({}, handle);
09447
09448 newhandle.name = si.fName;
09449 JSROOT.DrawFuncs.lst.push(newhandle);
09450 }
09451 }
09452
09453
09454 JSROOT.getDrawOptions = function(kind, selector) {
09455 if (typeof kind != 'string') return null;
09456 var allopts = null, isany = false, noinspect = false;
09457 for (var cnt=0;cnt<1000;++cnt) {
09458 var h = JSROOT.getDrawHandle(kind, cnt);
09459 if (h==null) break;
09460 if (h.noinspect) noinspect = true;
09461 if (!('func' in h)) break;
09462 isany = true;
09463 if (! ('opt' in h)) continue;
09464 var opts = h.opt.split(';');
09465 for (var i = 0; i < opts.length; ++i) {
09466 opts[i] = opts[i].toLowerCase();
09467 if ((selector=='nosame') && (opts[i].indexOf('same')==0)) continue;
09468
09469 if (allopts===null) allopts = [];
09470 if (allopts.indexOf(opts[i])<0) allopts.push(opts[i]);
09471 }
09472 }
09473
09474 if (isany && (allopts===null)) allopts = [""];
09475
09476
09477 if (!isany && kind.indexOf("ROOT.")==0) allopts = [];
09478
09479 if (!noinspect && allopts)
09480 allopts.push("inspect");
09481
09482 return allopts;
09483 }
09484
09485 JSROOT.canDraw = function(classname) {
09486 return JSROOT.getDrawOptions("ROOT." + classname) !== null;
09487 }
09488
09492 JSROOT.draw = function(divid, obj, opt) {
09493 if ((obj===null) || (typeof obj !== 'object')) return null;
09494
09495 if (opt == 'inspect')
09496 return JSROOT.Painter.drawInspector(divid, obj);
09497
09498 var handle = null, painter = null;
09499 if ('_typename' in obj) handle = JSROOT.getDrawHandle("ROOT." + obj._typename, opt);
09500 else if ('_kind' in obj) handle = JSROOT.getDrawHandle(obj._kind, opt);
09501
09502 if ((handle==null) || !('func' in handle)) return null;
09503
09504 function performDraw() {
09505 if ((painter===null) && ('painter_kind' in handle))
09506 painter = (handle.painter_kind == "base") ? new JSROOT.TBasePainter() : new JSROOT.TObjectPainter(obj);
09507
09508 if (painter==null) return handle.func(divid, obj, opt);
09509
09510 return handle.func.bind(painter)(divid, obj, opt, painter);
09511 }
09512
09513 if (typeof handle.func == 'function') return performDraw();
09514
09515 var funcname = "", prereq = "";
09516 if (typeof handle.func == 'object') {
09517 if ('func' in handle.func) funcname = handle.func.func;
09518 if ('script' in handle.func) prereq = "user:" + handle.func.script;
09519 } else
09520 if (typeof handle.func == 'string') {
09521 funcname = handle.func;
09522 if (('prereq' in handle) && (typeof handle.prereq == 'string')) prereq = handle.prereq;
09523 if (('script' in handle) && (typeof handle.script == 'string')) prereq += ";user:" + handle.script;
09524 }
09525
09526 if (funcname.length==0) return null;
09527
09528 if (prereq.length > 0) {
09529
09530
09531
09532 if (!('painter_kind' in handle))
09533 handle.painter_kind = (funcname.indexOf("JSROOT.Painter")==0) ? "object" : "base";
09534
09535 painter = (handle.painter_kind == "base") ? new JSROOT.TBasePainter() : new JSROOT.TObjectPainter(obj);
09536
09537 JSROOT.AssertPrerequisites(prereq, function() {
09538 var func = JSROOT.findFunction(funcname);
09539 if (func==null) {
09540 alert('Fail to find function ' + funcname + ' after loading ' + prereq);
09541 return null;
09542 }
09543
09544 handle.func = func;
09545 var ppp = performDraw();
09546
09547 if (ppp !== painter)
09548 alert('Painter function ' + funcname + ' do not follow rules of dynamicaly loaded painters');
09549 });
09550
09551 return painter;
09552 }
09553
09554 var func = JSROOT.findFunction(funcname);
09555 if (func == null) return null;
09556
09557 handle.func = func;
09558 return performDraw();
09559 }
09560
09566 JSROOT.redraw = function(divid, obj, opt) {
09567 if (obj==null) return;
09568
09569 var dummy = new JSROOT.TObjectPainter();
09570 dummy.SetDivId(divid, -1);
09571 var can_painter = dummy.pad_painter();
09572
09573 if (can_painter !== null) {
09574 if (obj._typename === "TCanvas") {
09575 can_painter.RedrawObject(obj);
09576 return can_painter;
09577 }
09578
09579 for (var i = 0; i < can_painter.painters.length; ++i) {
09580 var painter = can_painter.painters[i];
09581 if (painter.MatchObjectType(obj._typename))
09582 if (painter.UpdateObject(obj)) {
09583 can_painter.RedrawPad();
09584 return painter;
09585 }
09586 }
09587 }
09588
09589 if (can_painter)
09590 JSROOT.console("Cannot find painter to update object of type " + obj._typename);
09591
09592 JSROOT.cleanup(divid);
09593
09594 return JSROOT.draw(divid, obj, opt);
09595 }
09596
09597
09598
09599
09600
09601
09602
09603 JSROOT.resize = function(divid, arg) {
09604 if (arg === true) arg = { force: true }; else
09605 if (typeof arg !== 'object') arg = null;
09606
09607 var dummy = new JSROOT.TObjectPainter(), done = false;
09608 dummy.SetDivId(divid, -1);
09609 dummy.ForEachPainter(function(painter) {
09610 if (!done && typeof painter['CheckResize'] == 'function')
09611 done = painter.CheckResize(arg);
09612 });
09613 }
09614
09615
09616 JSROOT.CheckElementResize = JSROOT.resize;
09617
09618
09619 JSROOT.cleanup = function(divid) {
09620 var dummy = new JSROOT.TObjectPainter();
09621 dummy.SetDivId(divid, -1);
09622 dummy.ForEachPainter(function(painter) {
09623 if (typeof painter['Cleanup'] === 'function')
09624 painter.Cleanup();
09625 });
09626 dummy.select_main().html("");
09627 }
09628
09629
09630
09631
09632 JSROOT.progress = function(msg) {
09633 var id = "jsroot_progressbox";
09634 var box = d3.select("#"+id);
09635
09636 if (!JSROOT.gStyle.ProgressBox) return box.remove();
09637
09638 if ((arguments.length == 0) || (msg === undefined) || (msg === null))
09639 return box.remove();
09640
09641 if (box.empty()) {
09642 box = d3.select(document.body)
09643 .append("div")
09644 .attr("id", id);
09645 box.append("p");
09646 }
09647
09648 box.select("p").html(msg);
09649 }
09650
09651 return JSROOT;
09652
09653 }));