5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootCore',
'd3',
'JSRootPainter'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 factory(require(
"./JSRootCore.js"), require(
"d3"), require(
"./JSRootPainter.js"));
10 if (typeof d3 !=
'object')
11 throw new Error(
'This extension requires d3.js',
'JSRootPainter.hierarchy.js');
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootPainter.hierarchy.js');
14 if (typeof JSROOT.Painter !=
'object')
15 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.hierarchy.js');
18 } (
function(JSROOT, d3) {
22 JSROOT.sources.push(
"hierarchy");
27 function drawList(divid, lst, opt, callback) {
28 if (!lst || !lst.arr)
return JSROOT.CallBack(callback);
36 draw_next:
function() {
37 while (++this.indx < this.lst.arr.length) {
38 var handle = { func: this.draw_bind },
39 item = this.lst.arr[this.indx],
40 opt = (this.lst.opt && this.lst.opt[this.indx]) ? this.lst.opt[
this.indx] :
this.opt;
42 JSROOT.draw(this.divid, item, opt, handle);
43 if (!handle.completed)
return;
46 return JSROOT.CallBack(this.callback);
50 obj.draw_bind = obj.draw_next.bind(obj);
57 function FolderHierarchy(item, obj) {
59 if (!obj || !(
'fFolders' in obj) || (obj.fFolders===null))
return false;
61 if (obj.fFolders.arr.length===0) { item._more =
false;
return true; }
65 for ( var i = 0; i < obj.fFolders.arr.length; ++i) {
66 var chld = obj.fFolders.arr[i];
69 _kind :
"ROOT." + chld._typename,
76 function TaskHierarchy(item, obj) {
80 if (!obj || !(
'fTasks' in obj) || (obj.fTasks === null))
return false;
82 ObjectHierarchy(item, obj, { exclude: [
'fTasks',
'fName'] } );
84 if ((obj.fTasks.arr.length===0) && (item._childs.length==0)) { item._more =
false;
return true; }
88 for ( var i = 0; i < obj.fTasks.arr.length; ++i) {
89 var chld = obj.fTasks.arr[i];
92 _kind :
"ROOT." + chld._typename,
99 function ListHierarchy(folder, lst) {
100 if (!JSROOT.IsRootCollection(lst))
return false;
102 if ((lst.arr === undefined) || (lst.arr.length === 0)) {
103 folder._more =
false;
107 var do_context =
false, prnt = folder;
109 if (prnt._do_context) do_context =
true;
114 var ismap = (lst._typename ==
'TMap'), names = [], cnt = [], cycle = [];
116 for (var i = 0; i < lst.arr.length; ++i) {
117 var obj = ismap ? lst.arr[i].first : lst.arr[i];
119 var objname = obj.fName || obj.name;
120 if (!objname)
continue;
121 var indx = names.indexOf(objname);
125 cnt[names.length] = cycle[names.length] = 1;
131 for ( var i = 0; i < lst.arr.length; ++i) {
132 var obj = ismap ? lst.arr[i].first : lst.arr[i];
136 if (!obj || !obj._typename) {
146 _name: obj.fName || obj.name,
147 _kind:
"ROOT." + obj._typename,
148 _title: (obj.fTitle ||
"") +
" type:" + obj._typename,
152 switch(obj._typename) {
153 case 'TColor': item._value = JSROOT.Painter.MakeColorRGB(obj);
break;
154 case 'TText': item._value = obj.fTitle;
break;
155 case 'TLatex': item._value = obj.fTitle;
break;
156 case 'TObjString': item._value = obj.fString;
break;
157 default:
if (lst.opt && lst.opt[i] && lst.opt[i].length) item._value = lst.opt[i];
160 if (do_context && JSROOT.canDraw(obj._typename)) item._direct_context =
true;
163 if (!item._name || (!isNaN(parseInt(item._name)) && (parseInt(item._name)!==i))
164 || (lst.arr.indexOf(obj)<i)) {
165 item._name = i.toString();
168 var indx = names.indexOf(obj.fName);
169 if ((indx>=0) && (cnt[indx]>1)) {
170 item._cycle = cycle[indx]++;
171 item._keyname = item._name;
172 item._name = item._keyname +
";" + item._cycle;
177 folder._childs.push(item);
182 function KeysHierarchy(folder, keys, file, dirname) {
184 if (keys === undefined)
return false;
188 for (var i = 0; i < keys.length; ++i) {
192 _name : key.fName +
";" + key.fCycle,
194 _kind :
"ROOT." + key.fClassName,
196 _keyname : key.fName,
201 if (key.fObjlen > 1e5) item._title +=
' (size: ' + (key.fObjlen/1e6).toFixed(1) +
'MB)';
203 if (
'fRealName' in key)
204 item._realname = key.fRealName +
";" + key.fCycle;
206 if (key.fClassName ==
'TDirectory' || key.fClassName ==
'TDirectoryFile') {
208 if ((dirname!=null) && (file!=null)) dir = file.GetDir(dirname + key.fName);
211 item._expand =
function(node, obj) {
213 return KeysHierarchy(node, obj.fKeys);
217 item._name = key.fName;
218 KeysHierarchy(item, dir.fKeys, file, dirname + key.fName +
"/");
221 if ((key.fClassName ==
'TList') && (key.fName ==
'StreamerInfo')) {
222 item._name =
'StreamerInfo';
223 item._kind =
"ROOT.TStreamerInfoList";
224 item._title =
"List of streamer infos for binary I/O";
225 item._readobj = file.fStreamerInfos;
228 folder._childs.push(item);
234 function ObjectHierarchy(top, obj, args) {
235 if (!top || (obj===null))
return false;
239 var proto = Object.prototype.toString.apply(obj);
241 if (proto ===
'[object DataView]') {
246 _value: obj.byteLength.toString(),
247 _vclass:
'h_value_num'
250 top._childs.push(item);
251 var namelen = (obj.byteLength < 10) ? 1 : JSROOT.log10(obj.byteLength);
253 for (var k=0;k<obj.byteLength;++k) {
259 _vclass:
'h_value_num'
261 while (item._name.length < namelen) item._name =
"0" + item._name;
262 top._childs.push(item);
265 var val = obj.getUint8(k).toString(16);
266 while (val.length<2) val =
"0"+val;
267 if (item._value.length>0)
268 item._value += (k%4===0) ?
" | " :
" ";
276 var nosimple =
true, do_context =
false, prnt = top;
278 if (prnt._do_context) do_context =
true;
279 if (
'_nosimple' in prnt) { nosimple = prnt._nosimple;
break; }
283 var isarray = (proto.lastIndexOf(
'Array]') == proto.length-6) && (proto.indexOf(
'[object')==0) && !isNaN(obj.length),
284 compress = isarray && (obj.length > JSROOT.gStyle.HierarchyLimit), arrcompress =
false;
286 if (isarray && (top._name===
"Object") && !top._parent) top._name =
"Array";
290 for (var k=0;k<obj.length;++k) {
291 var typ = typeof obj[k];
292 if ((typ ===
'number') || (typ ===
'boolean') || (typ==
'string' && (obj[k].length<16)))
continue;
293 arrcompress =
false;
break;
297 if (!(
'_obj' in top))
300 if (top._obj !== obj) alert(
'object missmatch');
304 top._title =
"ROOT." + obj._typename;
306 if (isarray) top._title =
"Array len: " + obj.length;
310 for (var k=0;k<obj.length;) {
312 var nextk = Math.min(k+10,obj.length), allsame =
true, prevk = k;
316 for (var d=prevk;d<nextk;++d)
317 if (obj[k]!==obj[d]) allsame =
false;
320 if (nextk===obj.length)
break;
322 nextk = Math.min(nextk+10,obj.length);
332 var item = { _parent: top, _name: k+
".."+(nextk-1), _vclass:
'h_value_num' };
335 item._value = obj[k].toString();
338 for (var d=k;d<nextk;++d)
339 item._value += ((d===k) ?
"[ " :
", ") + obj[d].toString();
343 top._childs.push(item);
350 var lastitem, lastkey, lastfield, cnt;
352 for (var key in obj) {
353 if ((key ==
'_typename') || (key[0]==
'$'))
continue;
355 if (typeof fld ==
'function')
continue;
356 if (args && args.exclude && (args.exclude.indexOf(key)>=0))
continue;
358 if (compress && lastitem) {
359 if (lastfield===fld) { ++cnt; lastkey = key;
continue; }
360 if (cnt>0) lastitem._name +=
".." + lastkey;
363 var item = { _parent: top, _name: key };
365 if (compress) { lastitem = item; lastkey = key; lastfield = fld; cnt = 0; }
368 item._value = item._title =
"null";
369 if (!nosimple) top._childs.push(item);
375 if (typeof fld ==
'object') {
377 proto = Object.prototype.toString.apply(fld);
379 if ((proto.lastIndexOf(
'Array]') == proto.length-6) && (proto.indexOf(
'[object')==0)) {
380 item._title =
"array len=" + fld.length;
381 simple = (proto !=
'[object Array]');
382 if (fld.length === 0) {
386 item._value =
"[...]";
388 item._expand = ObjectHierarchy;
392 if (proto ===
"[object DataView]") {
393 item._title =
'DataView len=' + fld.byteLength;
394 item._value =
"[...]";
396 item._expand = ObjectHierarchy;
399 if (proto ===
"[object Date]") {
401 item._title =
'Date';
402 item._value = fld.toString();
403 item._vclass =
'h_value_num';
406 if (fld.$kind || fld._typename)
407 item._kind = item._title =
"ROOT." + (fld.$kind || fld._typename);
410 item._title = fld._typename;
411 if (do_context && JSROOT.canDraw(fld._typename)) item._direct_context =
true;
415 var curr = top, inparent =
false;
416 while (curr && !inparent) {
417 inparent = (curr._obj === fld);
422 item._value =
"{ prnt }";
423 item._vclass =
'h_value_num';
430 switch(fld._typename) {
431 case 'TColor': item._value = JSROOT.Painter.MakeColorRGB(fld);
break;
432 case 'TText': item._value = fld.fTitle;
break;
433 case 'TLatex': item._value = fld.fTitle;
break;
434 case 'TObjString': item._value = fld.fString;
break;
436 if (JSROOT.IsRootCollection(fld) && (typeof fld.arr ===
"object")) {
437 item._value = fld.arr.length ?
"[...]" :
"[]";
438 item._title +=
", size:" + fld.arr.length;
439 if (fld.arr.length>0) item._more =
true;
448 if ((typeof fld ===
'number') || (typeof fld ===
'boolean')) {
451 item._value =
"0x" + fld.toString(16);
453 item._value = fld.toString();
454 item._vclass =
'h_value_num';
456 if (typeof fld ===
'string') {
458 item._value =
'"' + fld.replace(/\&/g,
'&').replace(/\
"/g, '"').replace(/</g, '<').replace(/>/g, '>') + '"';
459 item._vclass = 'h_value_str';
461 if (typeof fld === 'undefined') {
463 item._value = "undefined
";
464 item._vclass = 'h_value_num';
467 alert('miss ' + key + ' ' + typeof fld);
470 if (!simple || !nosimple)
471 top._childs.push(item);
474 if (compress && lastitem && (cnt>0)) lastitem._name += "..
" + lastkey;
479 // =================================================================================================
483 function BrowserLayout(id, hpainter, objpainter) {
485 this.hpainter = hpainter; // painter for brwoser area (if any)
486 this.objpainter = objpainter; // painter for object area (if any)
487 this.browser_kind = null; // should be 'float' or 'fix'
490 BrowserLayout.prototype.main = function() {
491 return d3.select("#
" + this.gui_div);
494 BrowserLayout.prototype.drawing_divid = function() {
495 return this.gui_div + "_drawing
";
498 BrowserLayout.prototype.CheckResize = function() {
499 if (this.hpainter && (typeof this.hpainter.CheckResize == 'function'))
500 this.hpainter.CheckResize();
501 else if (this.objpainter && (typeof this.objpainter.CheckResize == 'function')) {
502 this.objpainter.CheckResize(true);
508 BrowserLayout.prototype.Create = function(with_browser) {
509 var main = this.main();
511 main.append("div
").attr("id", this.drawing_divid())
512 .classed("jsroot_draw_area
", true)
513 .style('position',"absolute
").style('left',0).style('top',0).style('bottom',0).style('right',0);
515 if (with_browser) main.append("div
").classed("jsroot_browser
", true);
518 BrowserLayout.prototype.CreateBrowserBtns = function() {
519 var br = this.main().select(".jsroot_browser
");
520 if (br.empty()) return;
521 var btns = br.append("div
").classed("jsroot_browser_btns
", true).classed("jsroot
", true);
522 btns.style('position',"absolute
").style("left
","7px
").style("top
","7px
");
523 if (JSROOT.touches) btns.style('opacity','0.2'); // on touch devices should be always visible
527 BrowserLayout.prototype.RemoveBrowserBtns = function() {
528 this.main().select(".jsroot_browser
").select(".jsroot_browser_btns
").remove();
531 BrowserLayout.prototype.SetBrowserContent = function(guiCode) {
532 var main = d3.select("#
" + this.gui_div + " .jsroot_browser
");
533 if (main.empty()) return;
535 main.insert('div', ".jsroot_browser_btns
").classed('jsroot_browser_area', true)
536 .style('position',"absolute
").style('left',0).style('top',0).style('bottom',0).style('width','250px')
537 .style('padding-left','5px')
538 .style('display','flex').style('flex-direction', 'column') /* use the flex model */
539 .html("<p
class=
'jsroot_browser_title'>title</p>
" + guiCode);
542 BrowserLayout.prototype.HasContent = function() {
543 var main = d3.select("#
" + this.gui_div + " .jsroot_browser
");
544 if (main.empty()) return false;
545 return !main.select(".jsroot_browser_area
").empty();
548 BrowserLayout.prototype.DeleteContent = function() {
549 var main = d3.select("#
" + this.gui_div + " .jsroot_browser
");
550 if (main.empty()) return;
552 main.selectAll("*
").remove();
553 delete this.browser_visible;
556 BrowserLayout.prototype.HasStatus = function() {
557 var main = d3.select("#
"+this.gui_div+" .jsroot_browser
");
558 if (main.empty()) return false;
560 var id = this.gui_div + "_status
",
561 line = d3.select("#
"+id);
563 return !line.empty();
566 BrowserLayout.prototype.CreateStatusLine = function(height, mode) {
567 if (!this.gui_div) return '';
569 JSROOT.AssertPrerequisites('jq2d', function() {
570 pthis.CreateStatusLine(height, mode);
572 return this.gui_div + "_status
";
575 // =========== painter of hierarchical structures =================================
577 JSROOT.hpainter = null; // global pointer
581 function HierarchyPainter(name, frameid, backgr) {
582 JSROOT.TBasePainter.call(this);
584 this.h = null; // hierarchy
585 this.with_icons = true;
586 this.background = backgr;
587 this.files_monitoring = (frameid == null); // by default files monitored when nobrowser option specified
588 this.nobrowser = (frameid === null);
589 if (!this.nobrowser) this.SetDivId(frameid); // this is required to be able cleanup painter
591 // remember only very first instance
592 if (!JSROOT.hpainter)
593 JSROOT.hpainter = this;
596 HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype);
598 HierarchyPainter.prototype.Cleanup = function() {
599 // clear drawing and browser
602 JSROOT.TBasePainter.prototype.Cleanup.call(this);
604 if (JSROOT.hpainter === this)
605 JSROOT.hpainter = null;
608 HierarchyPainter.prototype.FileHierarchy = function(file) {
612 _name : file.fFileName,
613 _title : (file.fTitle ? (file.fTitle + ", path
") : "") + file.fFullURL,
614 _kind : "ROOT.TFile
",
616 _fullurl : file.fFullURL,
617 _localfile : file.fLocalFile,
618 _had_direct_read : false,
619 // this is central get method, item or itemname can be used
620 _get : function(item, itemname, callback) {
622 var fff = this; // file item
624 if (item && item._readobj)
625 return JSROOT.CallBack(callback, item, item._readobj);
627 if (item!=null) itemname = painter.itemFullName(item, fff);
629 function ReadFileObject(file) {
630 if (!fff._file) fff._file = file;
632 if (file == null) return JSROOT.CallBack(callback, item, null);
634 file.ReadObject(itemname, function(obj) {
636 // if object was read even when item did not exist try to reconstruct new hierarchy
638 // first try to found last read directory
639 var d = painter.Find({name:itemname, top:fff, last_exists:true, check_keys:true });
640 if ((d!=null) && ('last' in d) && (d.last!=fff)) {
641 // reconstruct only subdir hierarchy
642 var dir = file.GetDir(painter.itemFullName(d.last, fff));
644 d.last._name = d.last._keyname;
645 var dirname = painter.itemFullName(d.last, fff);
646 KeysHierarchy(d.last, dir.fKeys, file, dirname + "/
");
649 // reconstruct full file hierarchy
650 KeysHierarchy(fff, file.fKeys, file, "");
652 item = painter.Find({name:itemname, top: fff});
657 // remove cycle number for objects supporting expand
658 if ('_expand' in item) item._name = item._keyname;
661 JSROOT.CallBack(callback, item, obj);
665 if (fff._file) ReadFileObject(fff._file); else
666 if (fff._localfile) new JSROOT.TLocalFile(fff._localfile, ReadFileObject); else
667 if (fff._fullurl) new JSROOT.TFile(fff._fullurl, ReadFileObject);
671 KeysHierarchy(folder, file.fKeys, file, "");
682 HierarchyPainter.prototype.ForEach = function(callback, top) {
684 if (!top) top = this.h;
685 if (!top || (typeof callback != 'function')) return;
686 function each_item(item) {
688 if ('_childs' in item)
689 for (var n = 0; n < item._childs.length; ++n) {
690 item._childs[n]._parent = item;
691 each_item(item._childs[n]);
708 HierarchyPainter.prototype.Find = function(arg) {
710 function find_in_hierarchy(top, fullname) {
712 if (!fullname || (fullname.length == 0) || !top) return top;
714 var pos = fullname.length;
716 if (!top._parent && (top._kind !== 'TopFolder') && (fullname.indexOf(top._name)===0)) {
717 // it is allowed to provide item name, which includes top-parent like file.root/folder/item
718 // but one could skip top-item name, if there are no other items
719 if (fullname === top._name) return top;
721 var len = top._name.length;
722 if (fullname[len] == "/
") {
723 fullname = fullname.substr(len+1);
724 pos = fullname.length;
728 function process_child(child, ignore_prnt) {
729 // set parent pointer when searching child
730 if (!ignore_prnt) child._parent = top;
732 if ((pos >= fullname.length-1) || (pos < 0)) return child;
734 return find_in_hierarchy(child, fullname.substr(pos + 1));
738 // we try to find element with slashes inside - start from full name
739 var localname = (pos >= fullname.length) ? fullname : fullname.substr(0, pos);
742 // first try to find direct matched item
743 for (var i = 0; i < top._childs.length; ++i)
744 if (top._childs[i]._name == localname)
745 return process_child(top._childs[i]);
747 // if first child online, check its elements
748 if ((top._kind === 'TopFolder') && (top._childs[0]._online!==undefined))
749 for (var i = 0; i < top._childs[0]._childs.length; ++i)
750 if (top._childs[0]._childs[i]._name == localname)
751 return process_child(top._childs[0]._childs[i], true);
753 // if allowed, try to found item with key
754 if (arg.check_keys) {
756 for (var i = 0; i < top._childs.length; ++i) {
757 if (top._childs[i]._keyname === localname) {
758 if (!newest || (newest._cycle < top._childs[i]._cycle)) newest = top._childs[i];
761 if (newest) return process_child(newest);
764 var allow_index = arg.allow_index;
765 if ((localname[0] === '[') && (localname[localname.length-1] === ']') &&
766 !isNaN(parseInt(localname.substr(1,localname.length-2)))) {
768 localname = localname.substr(1,localname.length-2);
771 // when search for the elements it could be allowed to check index
773 var indx = parseInt(localname);
774 if (!isNaN(indx) && (indx>=0) && (indx<top._childs.length))
775 return process_child(top._childs[indx]);
779 pos = fullname.lastIndexOf("/
", pos - 1);
783 // if did not found element with given name we just generate it
784 if (top._childs === undefined) top._childs = [];
785 pos = fullname.indexOf("/
");
786 var child = { _name: ((pos < 0) ? fullname : fullname.substr(0, pos)) };
787 top._childs.push(child);
788 return process_child(child);
791 return (arg.last_exists && top) ? { last: top, rest: fullname } : null;
794 var top = this.h, itemname = "";
796 if (arg === null) return null; else
797 if (typeof arg == 'string') { itemname = arg; arg = {}; } else
798 if (typeof arg == 'object') { itemname = arg.name; if ('top' in arg) top = arg.top; } else
801 if (itemname === "__top_folder__
") return top;
803 if ((typeof itemname == 'string') && (itemname.indexOf("img:
")==0)) return null;
805 return find_in_hierarchy(top, itemname);
808 HierarchyPainter.prototype.itemFullName = function(node, uptoparent, compact) {
810 if (node && node._kind ==='TopFolder') return "__top_folder__
";
815 // online items never includes top-level folder
816 if ((node._online!==undefined) && !uptoparent) return res;
818 if ((node === uptoparent) || (node._kind==='TopFolder')) break;
819 if (compact && !node._parent) break; // in compact form top-parent is not included
820 if (res.length > 0) res = "/
" + res;
821 res = node._name + res;
828 HierarchyPainter.prototype.ExecuteCommand = function(itemname, callback) {
829 // execute item marked as 'Command'
830 // If command requires additional arguments, they could be specified as extra arguments
831 // Or they will be requested interactive
833 var hitem = this.Find(itemname),
834 url = this.GetOnlineItemUrl(hitem) + "/cmd.json
",
836 d3node = d3.select((typeof callback == 'function') ? undefined : callback);
838 if ('_numargs' in hitem)
839 for (var n = 0; n < hitem._numargs; ++n) {
840 var argname = "arg
" + (n+1), argvalue = null;
841 if (n+2<arguments.length) argvalue = arguments[n+2];
842 if (!argvalue && (typeof callback == 'object'))
843 argvalue = prompt("Input argument
" + argname + " for command
" + hitem._name, "");
844 if (!argvalue) return;
845 url += ((n==0) ? "?
" : "&
") + argname + "=
" + argvalue;
848 if (!d3node.empty()) {
849 d3node.style('background','yellow');
850 if (hitem && hitem._title) d3node.attr('title', "Executing
" + hitem._title);
853 JSROOT.NewHttpRequest(url, 'text', function(res) {
854 if (typeof callback == 'function') return callback(res);
855 if (d3node.empty()) return;
856 var col = ((res!=null) && (res!='false')) ? 'green' : 'red';
857 if (hitem && hitem._title) d3node.attr('title', hitem._title + " lastres=
" + res);
858 d3node.style('background', col);
859 setTimeout(function() { d3node.style('background', ''); }, 2000);
860 if ((col == 'green') && ('_hreload' in hitem)) pthis.reload();
861 if ((col == 'green') && ('_update_item' in hitem)) pthis.updateItems(hitem._update_item.split(";
"));
865 HierarchyPainter.prototype.RefreshHtml = function(callback) {
866 if (!this.divid) return JSROOT.CallBack(callback);
868 JSROOT.AssertPrerequisites('jq2d', function() {
869 hpainter.RefreshHtml(callback);
873 HierarchyPainter.prototype.get = function(arg, call_back, options) {
874 // get object item with specified name
875 // depending from provided option, same item can generate different object types
877 if (arg===null) return JSROOT.CallBack(call_back, null, null);
879 var itemname, item, hpainter = this;
881 if (typeof arg === 'string') {
883 } else if (typeof arg === 'object') {
884 if ((arg._parent!==undefined) && (arg._name!==undefined) && (arg._kind!==undefined)) item = arg; else
885 if (arg.name!==undefined) itemname = arg.name; else
886 if (arg.arg!==undefined) itemname = arg.arg; else
887 if (arg.item!==undefined) item = arg.item;
890 if ((typeof itemname == 'string') && (itemname.indexOf("img:
")==0))
891 return JSROOT.CallBack(call_back, null, {
892 _typename: "TJSImage
", // artificial class, can be created by users
893 fName: itemname.substr(4)
896 if (item) itemname = this.itemFullName(item);
897 else item = this.Find( { name: itemname, allow_index: true, check_keys: true } );
899 // if item not found, try to find nearest parent which could allow us to get inside
900 var d = (item!=null) ? null : this.Find({ name: itemname, last_exists: true, check_keys: true, allow_index: true });
902 // if item not found, try to expand hierarchy central function
903 // implements not process get in central method of hierarchy item (if exists)
904 // if last_parent found, try to expand it
905 if ((d !== null) && ('last' in d) && (d.last !== null)) {
906 var parentname = this.itemFullName(d.last);
908 // this is indication that expand does not give us better path to searched item
909 if ((typeof arg == 'object') && ('rest' in arg))
910 if ((arg.rest == d.rest) || (arg.rest.length <= d.rest.length))
911 return JSROOT.CallBack(call_back);
913 return this.expand(parentname, function(res) {
914 if (!res) JSROOT.CallBack(call_back);
915 var newparentname = hpainter.itemFullName(d.last);
916 if (newparentname.length>0) newparentname+="/
";
917 hpainter.get( { name: newparentname + d.rest, rest: d.rest }, call_back, options);
921 if ((item !== null) && (typeof item._obj == 'object'))
922 return JSROOT.CallBack(call_back, item, item._obj);
924 // normally search _get method in the parent items
927 if (('_get' in curr) && (typeof curr._get == 'function'))
928 return curr._get(item, null, call_back, options);
929 curr = ('_parent' in curr) ? curr._parent : null;
932 JSROOT.CallBack(call_back, item, null);
935 HierarchyPainter.prototype.draw = function(divid, obj, drawopt) {
936 // just envelope, one should be able to redefine it for sub-classes
937 return JSROOT.draw(divid, obj, drawopt);
940 HierarchyPainter.prototype.redraw = function(divid, obj, drawopt) {
941 // just envelope, one should be able to redefine it for sub-classes
942 return JSROOT.redraw(divid, obj, drawopt);
945 HierarchyPainter.prototype.player = function(itemname, option, call_back) {
946 var item = this.Find(itemname);
948 if (!item || !item._player) return JSROOT.CallBack(call_back, null);
952 JSROOT.AssertPrerequisites(item._prereq || '', function() {
954 var player_func = JSROOT.findFunction(item._player);
955 if (!player_func) return JSROOT.CallBack(call_back, null);
957 hpainter.CreateDisplay(function(mdi) {
958 var res = mdi ? player_func(hpainter, itemname, option) : null;
959 JSROOT.CallBack(call_back, res);
964 HierarchyPainter.prototype.canDisplay = function(item, drawopt) {
965 if (!item) return false;
966 if (item._player) return true;
967 if (item._can_draw !== undefined) return item._can_draw;
968 if (drawopt == 'inspect') return true;
969 var handle = JSROOT.getDrawHandle(item._kind, drawopt);
970 return handle && (('func' in handle) || ('draw_field' in handle));
973 HierarchyPainter.prototype.isItemDisplayed = function(itemname) {
974 var mdi = this.GetDisplay();
975 if (!mdi) return false;
977 return mdi.FindFrame(itemname) !== null;
980 HierarchyPainter.prototype.display = function(itemname, drawopt, call_back) {
985 display_itemname = itemname,
986 frame_name = itemname,
987 marker = "::_display_on_frame_::
",
988 p = drawopt ? drawopt.indexOf(marker) : -1;
991 frame_name = drawopt.substr(p + marker.length);
992 drawopt = drawopt.substr(0, p);
995 function display_callback(respainter) {
996 if (!updating) JSROOT.progress();
998 if (respainter && (typeof respainter === 'object') && (typeof respainter.SetItemName === 'function')) {
999 respainter.SetItemName(display_itemname, updating ? null : drawopt, h); // mark painter as created from hierarchy
1000 if (item && !item._painter) item._painter = respainter;
1002 JSROOT.CallBack(call_back, respainter || painter, display_itemname);
1005 h.CreateDisplay(function(mdi) {
1007 if (!mdi) return display_callback();
1009 item = h.Find(display_itemname);
1011 if (item && ('_player' in item))
1012 return h.player(display_itemname, drawopt, display_callback);
1014 updating = (typeof(drawopt)=='string') && (drawopt.indexOf("update:
")==0);
1017 drawopt = drawopt.substr(7);
1018 if (!item || item._doing_update) return display_callback();
1019 item._doing_update = true;
1022 if (item && !h.canDisplay(item, drawopt)) return display_callback();
1025 if ((typeof(drawopt)=='string') && (drawopt.indexOf("divid:
")>=0)) {
1026 var pos = drawopt.indexOf("divid:
");
1027 divid = drawopt.slice(pos+6);
1028 drawopt = drawopt.slice(0, pos);
1031 if (!updating) JSROOT.progress("Loading
" + display_itemname);
1033 h.get(display_itemname, function(resitem, obj) {
1035 if (!updating) JSROOT.progress();
1037 if (!item) item = resitem;
1039 if (updating && item) delete item._doing_update;
1040 if (!obj) return display_callback();
1042 if (!updating) JSROOT.progress("Drawing
" + display_itemname);
1044 if (divid.length > 0)
1045 return (updating ? JSROOT.redraw : JSROOT.draw)(divid, obj, drawopt, display_callback);
1047 mdi.ForEachPainter(function(p, frame) {
1048 if (p.GetItemName() != display_itemname) return;
1049 // verify that object was drawn with same option as specified now (if any)
1050 if (!updating && (drawopt!=null) && (p.GetItemDrawOpt()!=drawopt)) return;
1051 mdi.ActivateFrame(frame);
1054 if (obj._typename) handle = JSROOT.getDrawHandle("ROOT.
" + obj._typename);
1055 if (handle && handle.draw_field && obj[handle.draw_field])
1056 obj = obj[handle.draw_field];
1058 if (p.RedrawObject(obj)) painter = p;
1061 if (painter) return display_callback();
1064 JSROOT.console("something went wrong - did not found painter when doing update of
" + display_itemname);
1065 return display_callback();
1068 var frame = mdi.FindFrame(frame_name, true);
1069 d3.select(frame).html("");
1070 mdi.ActivateFrame(frame);
1072 JSROOT.draw(d3.select(frame).attr("id"), obj, drawopt, display_callback);
1074 if (JSROOT.gStyle.DragAndDrop)
1075 h.enable_dropping(frame, display_itemname);
1081 HierarchyPainter.prototype.enable_dragging = function(element, itemname) {
1082 // here is not defined - implemented with jquery
1085 HierarchyPainter.prototype.enable_dropping = function(frame, itemname) {
1086 // here is not defined - implemented with jquery
1089 HierarchyPainter.prototype.dropitem = function(itemname, divid, opt, call_back) {
1092 if (opt && typeof opt === 'function') { call_back = opt; opt = ""; }
1093 if (opt===undefined) opt = "";
1095 function drop_callback(drop_painter) {
1096 if (drop_painter && (typeof drop_painter === 'object')) drop_painter.SetItemName(itemname, null, h);
1097 JSROOT.CallBack(call_back);
1100 if (itemname == "$legend
")
1101 return JSROOT.AssertPrerequisites("v6;hist
", function() {
1102 var res = JSROOT.Painter.produceLegend(divid, opt);
1103 JSROOT.CallBack(drop_callback, res);
1106 h.get(itemname, function(item, obj) {
1108 if (!obj) return JSROOT.CallBack(call_back);
1110 var main_painter = JSROOT.GetMainPainter(divid);
1112 if (main_painter && (typeof main_painter.PerformDrop === 'function'))
1113 return main_painter.PerformDrop(obj, itemname, item, opt, drop_callback);
1115 if (main_painter && main_painter.accept_drops)
1116 return JSROOT.draw(divid, obj, "same
" + opt, drop_callback);
1118 h.CleanupFrame(divid);
1119 return JSROOT.draw(divid, obj, opt, drop_callback);
1127 HierarchyPainter.prototype.updateItems = function(items) {
1129 if (!this.disp || !items) return;
1131 var draw_items = [], draw_options = [];
1133 this.disp.ForEachPainter(function(p) {
1134 var itemname = p.GetItemName();
1135 if (!itemname || (draw_items.indexOf(itemname)>=0)) return;
1136 if (typeof items == 'array') {
1137 if (items.indexOf(itemname) < 0) return;
1139 if (items != itemname) return;
1141 draw_items.push(itemname);
1142 draw_options.push("update:
" + p.GetItemDrawOpt());
1143 }, true); // only visible panels are considered
1145 if (draw_items.length > 0)
1146 this.displayAll(draw_items, draw_options);
1152 HierarchyPainter.prototype.updateAll = function(only_auto_items, only_items) {
1154 if (!this.disp) return;
1156 if (only_auto_items === "monitoring
") only_auto_items = !this._monitoring_on;
1158 var allitems = [], options = [], hpainter = this;
1160 // first collect items
1161 this.disp.ForEachPainter(function(p) {
1162 var itemname = p.GetItemName(),
1163 drawopt = p.GetItemDrawOpt();
1164 if ((typeof itemname != 'string') || (allitems.indexOf(itemname)>=0)) return;
1166 var item = hpainter.Find(itemname), forced = false;
1167 if (!item || ('_not_monitor' in item) || ('_player' in item)) return;
1169 if ('_always_monitor' in item) {
1172 var handle = JSROOT.getDrawHandle(item._kind);
1173 if (handle && ('monitor' in handle)) {
1174 if ((handle.monitor===false) || (handle.monitor=='never')) return;
1175 if (handle.monitor==='always') forced = true;
1179 if (forced || !only_auto_items) {
1180 allitems.push(itemname);
1181 options.push("update:
" + drawopt);
1183 }, true); // only visible panels are considered
1187 // force all files to read again (normally in non-browser mode)
1188 if (this.files_monitoring && !only_auto_items)
1189 this.ForEachRootFile(function(item) {
1190 painter.ForEach(function(fitem) { delete fitem._readobj; }, item);
1194 if (allitems.length > 0)
1195 this.displayAll(allitems, options);
1198 HierarchyPainter.prototype.displayAll = function(items, options, call_back) {
1200 if (!items || (items.length == 0)) return JSROOT.CallBack(call_back);
1204 if (!options) options = [];
1205 while (options.length < items.length)
1208 if ((options.length == 1) && (options[0] == "iotest
")) {
1210 d3.select("#
" + h.disp_frameid).html("<h2>Start I/O test</h2>
")
1212 var tm0 = new Date();
1213 return h.get(items[0], function(item, obj) {
1214 var tm1 = new Date();
1215 d3.select("#
" + h.disp_frameid).append("h2
").html("Item
" + items[0] + " reading time =
" + (tm1.getTime() - tm0.getTime()) + "ms
");
1216 return JSROOT.CallBack(call_back);
1220 var dropitems = new Array(items.length), dropopts = new Array(items.length), images = new Array(items.length);
1222 // First of all check that items are exists, look for cycle extension and plus sign
1223 for (var i = 0; i < items.length; ++i) {
1224 dropitems[i] = dropopts[i] = null;
1226 var item = items[i], can_split = true;
1228 if (item && item.indexOf("img:
")==0) { images[i] = true; continue; }
1230 if (item && (item.length>1) && (item[0]=='\'') && (item[item.length-1]=='\'')) {
1231 items[i] = item.substr(1, item.length-2);
1235 var elem = h.Find({ name: items[i], check_keys: true });
1236 if (elem) { items[i] = h.itemFullName(elem); continue; }
1238 if (can_split && (items[i][0]=='[') && (items[i][items[i].length-1]==']')) {
1239 dropitems[i] = JSROOT.ParseAsArray(items[i]);
1240 items[i] = dropitems[i].shift();
1242 if (can_split && (items[i].indexOf("+
") > 0)) {
1243 dropitems[i] = items[i].split("+
");
1244 items[i] = dropitems[i].shift();
1247 if (dropitems[i] && dropitems[i].length > 0) {
1248 // allow to specify _same_ item in different file
1249 for (var j = 0; j < dropitems[i].length; ++j) {
1250 var pos = dropitems[i][j].indexOf("_same_
");
1251 if ((pos>0) && (h.Find(dropitems[i][j])===null))
1252 dropitems[i][j] = dropitems[i][j].substr(0,pos) + items[i].substr(pos);
1254 elem = h.Find({ name: dropitems[i][j], check_keys: true });
1255 if (elem) dropitems[i][j] = h.itemFullName(elem);
1258 if ((options[i][0] == "[
") && (options[i][options[i].length-1] == "]
")) {
1259 dropopts[i] = JSROOT.ParseAsArray(options[i]);
1260 options[i] = dropopts[i].shift();
1262 if (options[i].indexOf("+
") > 0) {
1263 dropopts[i] = options[i].split("+
");
1264 options[i] = dropopts[i].shift();
1269 while (dropopts[i].length < dropitems[i].length) dropopts[i].push("");
1272 // also check if subsequent items has _same_, than use name from first item
1273 var pos = items[i].indexOf("_same_
");
1274 if ((pos>0) && !h.Find(items[i]) && (i>0))
1275 items[i] = items[i].substr(0,pos) + items[0].substr(pos);
1277 elem = h.Find({ name: items[i], check_keys: true });
1278 if (elem) items[i] = h.itemFullName(elem);
1281 // now check that items can be displayed
1282 for (var n = items.length-1; n>=0; --n) {
1283 if (images[n]) continue;
1284 var hitem = h.Find(items[n]);
1285 if (!hitem || h.canDisplay(hitem, options[n])) continue;
1286 // try to expand specified item
1287 h.expand(items[n], null, null, true);
1289 options.splice(n, 1);
1290 dropitems.splice(n, 1);
1293 if (items.length == 0) return JSROOT.CallBack(call_back);
1295 var frame_names = new Array(items.length), items_wait = new Array(items.length);
1296 for (var n=0; n < items.length;++n) {
1298 var fname = items[n], k = 0;
1299 if (items.indexOf(fname) < n) items_wait[n] = true; // if same item specified, one should wait first drawing before start next
1300 var p = options[n].indexOf("frameid:
");
1302 fname = options[n].substr(p+8);
1303 options[n] = options[n].substr(0,p);
1305 while (frame_names.indexOf(fname)>=0)
1306 fname = items[n] + "_
" + k++;
1308 frame_names[n] = fname;
1311 // now check if several same items present - select only one for the drawing
1312 // if draw option includes 'main', such item will be drawn first
1313 for (var n=0; n<items.length;++n) {
1314 if (items_wait[n] !== 0) continue;
1316 for (var k=0; k<items.length;++k)
1317 if ((items[n]===items[k]) && (options[k].indexOf('main')>=0)) found_main = k;
1318 for (var k=0; k<items.length;++k)
1319 if (items[n]===items[k]) items_wait[k] = (found_main != k);
1322 h.CreateDisplay(function(mdi) {
1323 if (!mdi) return JSROOT.CallBack(call_back);
1325 // Than create empty frames for each item
1326 for (var i = 0; i < items.length; ++i)
1327 if (options[i].indexOf('update:')!==0) {
1328 mdi.CreateFrame(frame_names[i]);
1329 options[i] += "::_display_on_frame_::
"+frame_names[i];
1332 function DropNextItem(indx, painter) {
1333 if (painter && dropitems[indx] && (dropitems[indx].length>0))
1334 return h.dropitem(dropitems[indx].shift(), painter.divid, dropopts[indx].shift(), DropNextItem.bind(h, indx, painter));
1336 dropitems[indx] = null; // mark that all drop items are processed
1337 items[indx] = null; // mark item as ready
1341 for (var cnt = 0; cnt < items.length; ++cnt) {
1342 if (dropitems[cnt]) isany = true;
1343 if (items[cnt]===null) continue; // ignore completed item
1345 if (items_wait[cnt] && items.indexOf(items[cnt])===cnt) {
1346 items_wait[cnt] = false;
1347 h.display(items[cnt], options[cnt], DropNextItem.bind(h,cnt));
1351 // only when items drawn and all sub-items dropped, one could perform call-back
1352 if (!isany && call_back) {
1353 JSROOT.CallBack(call_back);
1358 // We start display of all items parallel, but only if they are not the same
1359 for (var i = 0; i < items.length; ++i)
1361 h.display(items[i], options[i], DropNextItem.bind(h,i));
1365 HierarchyPainter.prototype.reload = function() {
1366 var hpainter = this;
1367 if ('_online' in this.h)
1368 this.OpenOnline(this.h._online, function() {
1369 hpainter.RefreshHtml();
1373 HierarchyPainter.prototype.UpdateTreeNode = function() {
1374 // dummy function, will be redefined when jquery part loaded
1377 HierarchyPainter.prototype.activate = function(items, force) {
1378 // activate (select) specified item
1379 // if force specified, all required sub-levels will be opened
1381 if (typeof items == 'string') items = [ items ];
1383 var active = [], // array of elements to activate
1384 painter = this, // painter itself
1385 update = []; // array of elements to update
1386 this.ForEach(function(item) { if (item._background) { active.push(item); delete item._background; } });
1388 function mark_active() {
1389 if (typeof painter.UpdateBackground !== 'function') return;
1391 for (var n=update.length-1;n>=0;--n)
1392 painter.UpdateTreeNode(update[n]);
1394 for (var n=0;n<active.length;++n)
1395 painter.UpdateBackground(active[n], force);
1398 function find_next(itemname, prev_found) {
1399 if (itemname === undefined) {
1400 // extract next element
1401 if (items.length == 0) return mark_active();
1402 itemname = items.shift();
1405 var hitem = painter.Find(itemname);
1408 var d = painter.Find({ name: itemname, last_exists: true, check_keys: true, allow_index: true });
1409 if (!d || !d.last) return find_next();
1410 d.now_found = painter.itemFullName(d.last);
1414 // if after last expand no better solution found - skip it
1415 if ((prev_found!==undefined) && (d.now_found === prev_found)) return find_next();
1417 return painter.expand(d.now_found, function(res) {
1418 if (!res) return find_next();
1419 var newname = painter.itemFullName(d.last);
1420 if (newname.length>0) newname+="/
";
1421 find_next(newname + d.rest, d.now_found);
1428 // check that item is visible (opened), otherwise should enable parent
1430 var prnt = hitem._parent;
1432 if (!prnt._isopen) {
1434 prnt._isopen = true;
1435 if (update.indexOf(prnt)<0) update.push(prnt);
1437 hitem = prnt; break;
1440 prnt = prnt._parent;
1443 hitem._background = 'grey';
1444 if (active.indexOf(hitem)<0) active.push(hitem);
1450 if (force && this.brlayout) {
1451 if (!this.brlayout.browser_kind) return this.CreateBrowser('float', true, find_next);
1452 if (!this.brlayout.browser_visible) this.brlayout.ToggleBrowserVisisbility();
1459 HierarchyPainter.prototype.expand = function(itemname, call_back, d3cont, silent) {
1460 var hpainter = this, hitem = this.Find(itemname);
1462 if (!hitem && d3cont) return JSROOT.CallBack(call_back);
1464 function DoExpandItem(_item, _obj, _name) {
1465 if (!_name) _name = hpainter.itemFullName(_item);
1467 var handle = _item._expand ? null : JSROOT.getDrawHandle(_item._kind, "::expand
");
1469 if (_obj && handle && handle.expand_item) {
1470 _obj = _obj[handle.expand_item]; // just take specified field from the object
1471 if (_obj && _obj._typename)
1472 handle = JSROOT.getDrawHandle("ROOT.
"+_obj._typename, "::expand
");
1475 if (handle && handle.expand) {
1476 JSROOT.AssertPrerequisites(handle.prereq, function() {
1477 _item._expand = JSROOT.findFunction(handle.expand);
1478 if (_item._expand) return DoExpandItem(_item, _obj, _name);
1479 JSROOT.CallBack(call_back);
1484 // try to use expand function
1485 if (_obj && _item && (typeof _item._expand === 'function')) {
1486 if (_item._expand(_item, _obj)) {
1487 _item._isopen = true;
1488 if (_item._parent && !_item._parent._isopen) {
1489 _item._parent._isopen = true; // also show parent
1490 if (!silent) hpainter.UpdateTreeNode(_item._parent);
1492 if (!silent) hpainter.UpdateTreeNode(_item, d3cont);
1494 JSROOT.CallBack(call_back, _item);
1499 if (_obj && ObjectHierarchy(_item, _obj)) {
1500 _item._isopen = true;
1501 if (_item._parent && !_item._parent._isopen) {
1502 _item._parent._isopen = true; // also show parent
1503 if (!silent) hpainter.UpdateTreeNode(_item._parent);
1505 if (!silent) hpainter.UpdateTreeNode(_item, d3cont);
1507 JSROOT.CallBack(call_back, _item);
1515 // item marked as it cannot be expanded, also top item cannot be changed
1516 if ((hitem._more === false) || (!hitem._parent && hitem._childs)) return JSROOT.CallBack(call_back);
1518 if (hitem._childs && hitem._isopen) {
1519 hitem._isopen = false;
1520 if (!silent) hpainter.UpdateTreeNode(hitem, d3cont);
1521 return JSROOT.CallBack(call_back);
1524 if (hitem._obj && DoExpandItem(hitem, hitem._obj, itemname)) return;
1527 JSROOT.progress("Loading
" + itemname);
1529 this.get(itemname, function(item, obj) {
1533 if (obj && DoExpandItem(item, obj)) return;
1535 JSROOT.CallBack(call_back);
1536 }, "hierarchy_expand
" ); // indicate that we getting element for expand, can handle it differently
1540 HierarchyPainter.prototype.GetTopOnlineItem = function(item) {
1542 while (item && (!('_online' in item))) item = item._parent;
1546 if (!this.h) return null;
1547 if ('_online' in this.h) return this.h;
1548 if (this.h._childs && ('_online' in this.h._childs[0])) return this.h._childs[0];
1553 HierarchyPainter.prototype.ForEachJsonFile = function(call_back) {
1554 if (!this.h) return;
1555 if ('_jsonfile' in this.h)
1556 return JSROOT.CallBack(call_back, this.h);
1559 for (var n = 0; n < this.h._childs.length; ++n) {
1560 var item = this.h._childs[n];
1561 if ('_jsonfile' in item) JSROOT.CallBack(call_back, item);
1565 HierarchyPainter.prototype.OpenJsonFile = function(filepath, call_back) {
1566 var isfileopened = false;
1567 this.ForEachJsonFile(function(item) { if (item._jsonfile==filepath) isfileopened = true; });
1568 if (isfileopened) return JSROOT.CallBack(call_back);
1571 JSROOT.NewHttpRequest(filepath, 'object', function(res) {
1572 if (!res) return JSROOT.CallBack(call_back);
1573 var h1 = { _jsonfile: filepath, _kind: "ROOT.
" + res._typename, _jsontmp: res, _name: filepath.split("/
").pop() };
1574 if (res.fTitle) h1._title = res.fTitle;
1575 h1._get = function(item,itemname,callback) {
1577 return JSROOT.CallBack(callback, item, item._jsontmp);
1578 JSROOT.NewHttpRequest(item._jsonfile, 'object', function(res) {
1579 item._jsontmp = res;
1580 JSROOT.CallBack(callback, item, item._jsontmp);
1583 if (pthis.h == null) pthis.h = h1; else
1584 if (pthis.h._kind == 'TopFolder') pthis.h._childs.push(h1); else {
1585 var h0 = pthis.h, topname = ('_jsonfile' in h0) ? "Files
" : "Items
";
1586 pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1] };
1589 pthis.RefreshHtml(call_back);
1593 HierarchyPainter.prototype.ForEachRootFile = function(call_back) {
1594 if (!this.h) return;
1595 if ((this.h._kind == "ROOT.TFile
") && this.h._file)
1596 return JSROOT.CallBack(call_back, this.h);
1599 for (var n = 0; n < this.h._childs.length; ++n) {
1600 var item = this.h._childs[n];
1601 if ((item._kind == 'ROOT.TFile') && ('_fullurl' in item))
1602 JSROOT.CallBack(call_back, item);
1606 HierarchyPainter.prototype.OpenRootFile = function(filepath, call_back) {
1607 // first check that file with such URL already opened
1609 var isfileopened = false;
1610 this.ForEachRootFile(function(item) { if (item._fullurl===filepath) isfileopened = true; });
1611 if (isfileopened) return JSROOT.CallBack(call_back);
1615 JSROOT.progress("Opening
" + filepath + " ...
");
1616 JSROOT.OpenFile(filepath, function(file) {
1619 // make CORS warning
1620 if (!d3.select("#gui_fileCORS
").style("background
","red
").empty())
1621 setTimeout(function() { d3.select("#gui_fileCORS
").style("background
",''); }, 5000);
1622 return JSROOT.CallBack(call_back, false);
1625 var h1 = pthis.FileHierarchy(file);
1627 if (pthis.h == null) {
1629 if (pthis._topname) h1._name = pthis._topname;
1631 if (pthis.h._kind == 'TopFolder') {
1632 pthis.h._childs.push(h1);
1634 var h0 = pthis.h, topname = (h0._kind == "ROOT.TFile
") ? "Files
" : "Items
";
1635 pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1], _isopen: true };
1638 pthis.RefreshHtml(call_back);
1642 HierarchyPainter.prototype.ApplyStyle = function(style, call_back) {
1644 return JSROOT.CallBack(call_back);
1646 if (typeof style === 'object') {
1647 if (style._typename === "TStyle
")
1648 JSROOT.extend(JSROOT.gStyle, style);
1649 return JSROOT.CallBack(call_back);
1652 if (typeof style === 'string') {
1654 var hpainter = this,
1655 item = this.Find( { name: style, allow_index: true, check_keys: true } );
1658 return this.get(item, function(item2, obj) { hpainter.ApplyStyle(obj, call_back); });
1660 if (style.indexOf('.json') > 0)
1661 return JSROOT.NewHttpRequest(style, 'object', function(res) {
1662 hpainter.ApplyStyle(res, call_back);
1666 return JSROOT.CallBack(call_back);
1669 HierarchyPainter.prototype.GetFileProp = function(itemname) {
1670 var item = this.Find(itemname);
1671 if (item == null) return null;
1673 var subname = item._name;
1674 while (item._parent) {
1675 item = item._parent;
1676 if ('_file' in item)
1677 return { kind: "file
", fileurl: item._file.fURL, itemname: subname, localfile: !!item._file.fLocalFile };
1679 if ('_jsonfile' in item)
1680 return { kind: "json
", fileurl: item._jsonfile, itemname: subname };
1682 subname = item._name + "/
" + subname;
1688 JSROOT.MarkAsStreamerInfo = function(h,item,obj) {
1689 // this function used on THttpServer to mark streamer infos list
1690 // as fictional TStreamerInfoList class, which has special draw function
1691 if (obj && (obj._typename=='TList'))
1692 obj._typename = 'TStreamerInfoList';
1695 HierarchyPainter.prototype.GetOnlineItemUrl = function(item) {
1696 // returns URL, which could be used to request item from the online server
1697 if (typeof item == "string") item = this.Find(item);
1699 while (prnt && (prnt._online===undefined)) prnt = prnt._parent;
1700 return prnt ? (prnt._online + this.itemFullName(item, prnt)) : null;
1703 HierarchyPainter.prototype.isOnlineItem = function(item) {
1704 return this.GetOnlineItemUrl(item)!==null;
1707 HierarchyPainter.prototype.GetOnlineItem = function(item, itemname, callback, option) {
1708 // method used to request object from the http server
1710 var url = itemname, h_get = false, req = "", req_kind = "object", pthis = this, draw_handle = null;
1712 if (option === 'hierarchy_expand') { h_get = true; option = undefined; }
1715 url = this.GetOnlineItemUrl(item);
1717 if ('_kind' in item) draw_handle = JSROOT.getDrawHandle(item._kind);
1720 req = 'h.json?compact=3';
1721 item._expand = JSROOT.Painter.OnlineHierarchy; // use proper expand function
1723 if ('_make_request' in item) {
1724 func = JSROOT.findFunction(item._make_request);
1726 if ((draw_handle!=null) && ('make_request' in draw_handle)) {
1727 func = draw_handle.make_request;
1730 if (typeof func == 'function') {
1731 // ask to make request
1732 var dreq = func(pthis, item, url, option);
1733 // result can be simple string or object with req and kind fields
1735 if (typeof dreq == 'string') req = dreq; else {
1736 if ('req' in dreq) req = dreq.req;
1737 if ('kind' in dreq) req_kind = dreq.kind;
1741 if ((req.length==0) && (item._kind.indexOf("ROOT.
")!=0))
1742 req = 'item.json.gz?compact=3';
1745 if (!itemname && item && ('_cached_draw_object' in this) && (req.length == 0)) {
1746 // special handling for drawGUI when cashed
1747 var obj = this._cached_draw_object;
1748 delete this._cached_draw_object;
1749 return JSROOT.CallBack(callback, item, obj);
1752 if (req.length == 0) req = 'root.json.gz?compact=23';
1754 if (url.length > 0) url += "/
";
1757 var itemreq = JSROOT.NewHttpRequest(url, req_kind, function(obj) {
1761 if (!h_get && item && ('_after_request' in item)) {
1762 func = JSROOT.findFunction(item._after_request);
1763 } else if (draw_handle && ('after_request' in draw_handle))
1764 func = draw_handle.after_request;
1766 if (typeof func == 'function') {
1767 var res = func(pthis, item, obj, option, itemreq);
1768 if ((res!=null) && (typeof res == "object")) obj = res;
1771 JSROOT.CallBack(callback, item, obj);
1777 JSROOT.Painter.OnlineHierarchy = function(node, obj) {
1778 // central function for expand of all online items
1780 if (obj && node && ('_childs' in obj)) {
1782 for (var n=0;n<obj._childs.length;++n)
1783 if (obj._childs[n]._more || obj._childs[n]._childs)
1784 obj._childs[n]._expand = JSROOT.Painter.OnlineHierarchy;
1786 node._childs = obj._childs;
1794 HierarchyPainter.prototype.OpenOnline = function(server_address, user_callback) {
1797 function AdoptHierarchy(result) {
1799 if (painter.h == null) return;
1801 if (('_title' in painter.h) && (painter.h._title!='')) document.title = painter.h._title;
1803 result._isopen = true;
1805 // mark top hierarchy as online data and
1806 painter.h._online = server_address;
1808 painter.h._get = function(item, itemname, callback, option) {
1809 painter.GetOnlineItem(item, itemname, callback, option);
1812 painter.h._expand = JSROOT.Painter.OnlineHierarchy;
1814 var scripts = "", modules = "";
1815 painter.ForEach(function(item) {
1816 if ('_childs' in item) item._expand = JSROOT.Painter.OnlineHierarchy;
1818 if ('_autoload' in item) {
1819 var arr = item._autoload.split(";
");
1820 for (var n = 0; n < arr.length; ++n)
1821 if ((arr[n].length>3) &&
1822 ((arr[n].lastIndexOf(".js
")==arr[n].length-3) ||
1823 (arr[n].lastIndexOf(".css
")==arr[n].length-4))) {
1824 if (scripts.indexOf(arr[n])<0) scripts+=arr[n]+";
";
1826 if (modules.indexOf(arr[n])<0) modules+=arr[n]+";
";
1831 if (scripts.length > 0) scripts = "user:
" + scripts;
1833 // use AssertPrerequisites, while it protect us from race conditions
1834 JSROOT.AssertPrerequisites(modules + scripts, function() {
1836 painter.ForEach(function(item) {
1837 if (!('_drawfunc' in item) || !('_kind' in item)) return;
1838 var typename = "kind:
" + item._kind;
1839 if (item._kind.indexOf('ROOT.')==0) typename = item._kind.slice(5);
1840 var drawopt = item._drawopt;
1841 if (!JSROOT.canDraw(typename) || (drawopt!=null))
1842 JSROOT.addDrawFunc({ name: typename, func: item._drawfunc, script: item._drawscript, opt: drawopt });
1845 JSROOT.CallBack(user_callback, painter);
1849 if (!server_address) server_address = "";
1851 if (typeof server_address == 'object') {
1852 var h = server_address;
1853 server_address = "";
1854 return AdoptHierarchy(h);
1857 JSROOT.NewHttpRequest(server_address + "h.json?compact=3
", 'object', AdoptHierarchy).send(null);
1860 HierarchyPainter.prototype.GetOnlineProp = function(itemname) {
1861 var item = this.Find(itemname);
1862 if (!item) return null;
1864 var subname = item._name;
1865 while (item._parent) {
1866 item = item._parent;
1868 if ('_online' in item) {
1870 server : item._online,
1874 subname = item._name + "/
" + subname;
1880 HierarchyPainter.prototype.FillOnlineMenu = function(menu, onlineprop, itemname) {
1883 node = this.Find(itemname),
1884 sett = JSROOT.getDrawSettings(node._kind, 'nosame;noinspect'),
1885 handle = JSROOT.getDrawHandle(node._kind),
1886 root_type = (typeof node._kind == 'string') ? node._kind.indexOf("ROOT.
") == 0 : false;
1888 if (sett.opts && (node._can_draw !== false)) {
1889 sett.opts.push('inspect');
1890 menu.addDrawMenu("Draw
", sett.opts, function(arg) { painter.display(itemname, arg); });
1893 if (!node._childs && (node._more !== false) && (node._more || root_type || sett.expand))
1894 menu.add("Expand
", function() { painter.expand(itemname); });
1896 if (handle && ('execute' in handle))
1897 menu.add("Execute
", function() { painter.ExecuteCommand(itemname, menu.tree_node); });
1899 var drawurl = onlineprop.server + onlineprop.itemname + "/draw.htm
", separ = "?
";
1900 if (this.IsMonitoring()) {
1901 drawurl += separ + "monitoring=
" + this.MonitoringInterval();
1905 if (sett.opts && (node._can_draw !== false))
1906 menu.addDrawMenu("Draw in
new window
", sett.opts, function(arg) { window.open(drawurl+separ+"opt=
" +arg); });
1908 if (sett.opts && (sett.opts.length > 0) && root_type && (node._can_draw !== false))
1909 menu.addDrawMenu("Draw as png
", sett.opts, function(arg) {
1910 window.open(onlineprop.server + onlineprop.itemname + "/root.png?w=400&h=300&opt=
" + arg);
1913 if ('_player' in node)
1914 menu.add("Player
", function() { painter.player(itemname); });
1917 HierarchyPainter.prototype.Adopt = function(h) {
1926 HierarchyPainter.prototype.SetMonitoring = function(interval, monitor_on) {
1928 this._runMonitoring("cleanup
");
1931 interval = parseInt(interval);
1932 if (!isNaN(interval) && (interval > 0)) {
1933 this._monitoring_interval = Math.max(100,interval);
1936 this._monitoring_interval = 3000;
1940 this._monitoring_on = monitor_on;
1942 if (this.IsMonitoring())
1943 this._runMonitoring();
1947 HierarchyPainter.prototype._runMonitoring = function(arg) {
1948 if ((arg == "cleanup
") || !this.IsMonitoring()) {
1949 if (this._monitoring_handle) {
1950 clearTimeout(this._monitoring_handle);
1951 delete this._monitoring_handle;
1954 if (this._monitoring_frame) {
1955 cancelAnimationFrame(this._monitoring_frame);
1956 delete this._monitoring_frame;
1961 if (arg == "frame
") {
1962 // process of timeout, request animation frame
1963 delete this._monitoring_handle;
1964 this._monitoring_frame = requestAnimationFrame(this._runMonitoring.bind(this,"draw
"));
1968 if (arg == "draw
") {
1969 delete this._monitoring_frame;
1970 this.updateAll("monitoring
");
1973 this._monitoring_handle = setTimeout(this._runMonitoring.bind(this,"frame
"), this.MonitoringInterval());
1977 HierarchyPainter.prototype.MonitoringInterval = function(val) {
1978 return this._monitoring_interval || 3000;
1982 HierarchyPainter.prototype.EnableMonitoring = function(on) {
1983 this.SetMonitoring(undefined, on);
1987 HierarchyPainter.prototype.IsMonitoring = function() {
1988 return this._monitoring_on;
1991 HierarchyPainter.prototype.SetDisplay = function(layout, frameid) {
1992 if (!frameid && (typeof layout == 'object')) {
1994 this.disp_kind = 'custom';
1995 this.disp_frameid = null;
1997 this.disp_kind = layout;
1998 this.disp_frameid = frameid;
2001 if (!this.register_resize) {
2002 this.register_resize = true;
2003 JSROOT.RegisterForResize(this);
2007 HierarchyPainter.prototype.GetLayout = function() {
2008 return this.disp_kind;
2011 HierarchyPainter.prototype.ClearPainter = function(obj_painter) {
2012 this.ForEach(function(item) {
2013 if (item._painter === obj_painter) delete item._painter;
2017 HierarchyPainter.prototype.clear = function(withbrowser) {
2025 this.ForEach(function(item) {
2026 delete item._painter; // remove reference on the painter
2027 // when only display cleared, try to clear all browser items
2028 if (!withbrowser && (typeof item.clear=='function')) item.clear();
2029 if (withbrowser) plainarr.push(item);
2033 // cleanup all monitoring loops
2034 this.EnableMonitoring(false);
2035 // simplify work for javascript and delete all (ok, most of) cross-references
2036 this.select_main().html("");
2037 plainarr.forEach(function(d) { delete d._parent; delete d._childs; delete d._obj; delete d._d3cont; });
2042 HierarchyPainter.prototype.GetDisplay = function() {
2043 return ('disp' in this) ? this.disp : null;
2046 HierarchyPainter.prototype.CleanupFrame = function(divid) {
2047 // hook to perform extra actions when frame is cleaned
2049 var lst = JSROOT.cleanup(divid);
2051 // we remove all painters references from items
2052 if (lst && (lst.length>0))
2053 this.ForEach(function(item) {
2054 if (item._painter && lst.indexOf(item._painter)>=0) delete item._painter;
2062 HierarchyPainter.prototype.CreateDisplay = function(callback) {
2064 if ('disp' in this) {
2065 if ((this.disp.NumDraw() > 0) || (this.disp_kind == "custom
")) return JSROOT.CallBack(callback, this.disp);
2070 // check that we can found frame where drawing should be done
2071 if (document.getElementById(this.disp_frameid) == null)
2072 return JSROOT.CallBack(callback, null);
2074 if ((this.disp_kind == "simple
") ||
2075 ((this.disp_kind.indexOf("grid
") == 0) && (this.disp_kind.indexOf("gridi
") < 0)))
2076 this.disp = new GridDisplay(this.disp_frameid, this.disp_kind);
2078 return JSROOT.AssertPrerequisites('jq2d', this.CreateDisplay.bind(this, callback));
2081 this.disp.CleanupFrame = this.CleanupFrame.bind(this);
2083 JSROOT.CallBack(callback, this.disp);
2092 HierarchyPainter.prototype.CreateCustomDisplay = function(itemname, custom_kind, callback) {
2094 if (this.disp_kind != "simple
")
2095 return this.CreateDisplay(callback);
2097 this.disp_kind = custom_kind;
2099 // check if display can be erased
2101 var num = this.disp.NumDraw();
2102 if ((num>1) || ((num==1) && !this.disp.FindFrame(itemname)))
2103 return this.CreateDisplay(callback);
2108 this.CreateDisplay(callback);
2111 HierarchyPainter.prototype.updateOnOtherFrames = function(painter, obj) {
2112 // function should update object drawings for other painters
2113 var mdi = this.disp, handle = null, isany = false;
2114 if (!mdi) return false;
2116 if (obj._typename) handle = JSROOT.getDrawHandle("ROOT.
" + obj._typename);
2117 if (handle && handle.draw_field && obj[handle.draw_field])
2118 obj = obj[handle.draw_field];
2120 mdi.ForEachPainter(function(p, frame) {
2121 if ((p===painter) || (p.GetItemName() != painter.GetItemName())) return;
2122 mdi.ActivateFrame(frame);
2123 if (p.RedrawObject(obj)) isany = true;
2128 HierarchyPainter.prototype.CheckResize = function(size) {
2129 if (this.disp) this.disp.CheckMDIResize(null, size);
2132 HierarchyPainter.prototype.StartGUI = function(gui_div, gui_call_back, url) {
2134 function GetOption(opt) {
2135 var res = JSROOT.GetUrlOption(opt, url);
2136 if (!res && gui_div && !gui_div.empty() && gui_div.node().hasAttribute(opt)) res = gui_div.attr(opt);
2140 function GetOptionAsArray(opt) {
2141 var res = JSROOT.GetUrlOptionAsArray(opt, url);
2142 if (res.length>0 || !gui_div || gui_div.empty()) return res;
2143 while (opt.length>0) {
2144 var separ = opt.indexOf(";
");
2145 var part = separ>0 ? opt.substr(0, separ) : opt;
2146 if (separ>0) opt = opt.substr(separ+1); else opt = "";
2148 var canarray = true;
2149 if (part[0]=='#') { part = part.substr(1); canarray = false; }
2150 if (part==='files') continue; // special case for normal UI
2152 if (!gui_div.node().hasAttribute(part)) continue;
2154 var val = gui_div.attr(part);
2156 if (canarray) res = res.concat(JSROOT.ParseAsArray(val));
2157 else if (val!==null) res.push(val);
2162 var hpainter = this,
2163 prereq = GetOption('prereq') || "",
2164 filesdir = JSROOT.GetUrlOption("path
", url) || "", // path used in normal gui
2165 filesarr = GetOptionAsArray("#file;files
"),
2166 localfile = GetOption("localfile
"),
2167 jsonarr = GetOptionAsArray("#json;jsons
"),
2168 expanditems = GetOptionAsArray("expand
"),
2169 itemsarr = GetOptionAsArray("#item;items
"),
2170 optionsarr = GetOptionAsArray("#opt;opts
"),
2171 monitor = GetOption("monitoring
"),
2172 layout = GetOption("layout
"),
2173 style = GetOptionAsArray("#style
"),
2174 statush = 0, status = GetOption("status
"),
2175 browser_kind = GetOption("browser
"),
2176 browser_configured = !!browser_kind,
2177 title = GetOption("title
");
2179 if (GetOption("float")!==null) { browser_kind = 'float'; browser_configured = true; } else
2180 if (GetOption("fix
")!==null) { browser_kind = 'fix'; browser_configured = true; }
2182 this.no_select = GetOption("noselect
");
2184 if (GetOption('files_monitoring')!==null) this.files_monitoring = true;
2186 if (title) document.title = title;
2188 var load = GetOption("load
");
2189 if (load) prereq += ";io;2d;load:
" + load;
2191 if (expanditems.length==0 && (GetOption("expand
")==="")) expanditems.push("");
2194 for (var i=0;i<filesarr.length;++i) filesarr[i] = filesdir + filesarr[i];
2195 for (var i=0;i<jsonarr.length;++i) jsonarr[i] = filesdir + jsonarr[i];
2198 if ((itemsarr.length==0) && GetOption("item
")==="") itemsarr.push("");
2200 if ((jsonarr.length==1) && (itemsarr.length==0) && (expanditems.length==0)) itemsarr.push("");
2202 if (!this.disp_kind) {
2203 if ((typeof layout == "string") && (layout.length > 0))
2204 this.disp_kind = layout;
2206 switch (itemsarr.length) {
2208 case 1: this.disp_kind = 'simple'; break;
2209 case 2: this.disp_kind = 'vert2'; break;
2210 case 3: this.disp_kind = 'vert21'; break;
2211 case 4: this.disp_kind = 'vert22'; break;
2212 case 5: this.disp_kind = 'vert32'; break;
2213 case 6: this.disp_kind = 'vert222'; break;
2214 case 7: this.disp_kind = 'vert322'; break;
2215 case 8: this.disp_kind = 'vert332'; break;
2216 case 9: this.disp_kind = 'vert333'; break;
2217 default: this.disp_kind = 'flex';
2221 if (status==="no
") status = null; else
2222 if (status==="off
") { this.status_disabled = true; status = null; } else
2223 if (status==="on
") status = true; else
2224 if (status!==null) { statush = parseInt(status); if (isNaN(statush) || (statush<5)) statush = 0; status = true; }
2225 if (this.no_select==="") this.no_select = true;
2227 if (!browser_kind) browser_kind = "fix
"; else
2228 if (browser_kind==="no
") browser_kind = ""; else
2229 if (browser_kind==="off
") { browser_kind = ""; status = null; this.exclude_browser = true; }
2230 if (GetOption("nofloat
")!==null) this.float_browser_disabled = true;
2232 if (this.start_without_browser) browser_kind = "";
2234 if (status || browser_kind) prereq = "jq2d;
" + prereq;
2236 this._topname = GetOption("topname
");
2238 function OpenAllFiles(res) {
2239 if (browser_kind) { hpainter.CreateBrowser(browser_kind); browser_kind = ""; }
2240 if (status!==null) { hpainter.CreateStatusLine(statush, status); status = null; }
2241 if (jsonarr.length>0)
2242 hpainter.OpenJsonFile(jsonarr.shift(), OpenAllFiles);
2243 else if (filesarr.length>0)
2244 hpainter.OpenRootFile(filesarr.shift(), OpenAllFiles);
2245 else if ((localfile!==null) && (typeof hpainter.SelectLocalFile == 'function')) {
2246 localfile = null; hpainter.SelectLocalFile(OpenAllFiles);
2247 } else if (expanditems.length>0)
2248 hpainter.expand(expanditems.shift(), OpenAllFiles);
2249 else if (style.length>0)
2250 hpainter.ApplyStyle(style.shift(), OpenAllFiles);
2252 hpainter.displayAll(itemsarr, optionsarr, function() {
2253 hpainter.RefreshHtml();
2254 hpainter.SetMonitoring(monitor);
2255 JSROOT.CallBack(gui_call_back);
2259 function AfterOnlineOpened() {
2260 // check if server enables monitoring
2262 if (!hpainter.exclude_browser && !browser_configured && ('_browser' in hpainter.h)) {
2263 browser_kind = hpainter.h._browser;
2264 if (browser_kind==="no
") browser_kind = ""; else
2265 if (browser_kind==="off
") { browser_kind = ""; status = null; hpainter.exclude_browser = true; }
2268 if (('_monitoring' in hpainter.h) && !monitor)
2269 monitor = hpainter.h._monitoring;
2271 if (('_loadfile' in hpainter.h) && (filesarr.length==0))
2272 filesarr = JSROOT.ParseAsArray(hpainter.h._loadfile);
2274 if (('_drawitem' in hpainter.h) && (itemsarr.length==0)) {
2275 itemsarr = JSROOT.ParseAsArray(hpainter.h._drawitem);
2276 optionsarr = JSROOT.ParseAsArray(hpainter.h._drawopt);
2279 if (('_layout' in hpainter.h) && !layout && ((hpainter.is_online != "draw
") || (itemsarr.length > 1)))
2280 hpainter.disp_kind = hpainter.h._layout;
2282 if (('_toptitle' in hpainter.h) && hpainter.exclude_browser && document)
2283 document.title = hpainter.h._toptitle;
2286 hpainter.PrepareGuiDiv(gui_div, hpainter.disp_kind);
2292 if (this.is_online) {
2293 if (typeof GetCachedHierarchy == 'function') h0 = GetCachedHierarchy();
2294 if (typeof h0 !== 'object') h0 = "";
2298 return this.OpenOnline(h0, AfterOnlineOpened);
2301 this.PrepareGuiDiv(gui_div, this.disp_kind);
2303 if (prereq.length>0) JSROOT.AssertPrerequisites(prereq, OpenAllFiles);
2304 else OpenAllFiles();
2307 HierarchyPainter.prototype.PrepareGuiDiv = function(myDiv, layout) {
2309 this.gui_div = myDiv.attr('id');
2311 this.brlayout = new BrowserLayout(this.gui_div, this);
2313 this.brlayout.Create(!this.exclude_browser);
2315 if (!this.exclude_browser) {
2316 var btns = this.brlayout.CreateBrowserBtns();
2318 JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.diamand, 15, "toggle fix-pos browser
")
2319 .style("margin
","3px
").on("click
", this.CreateBrowser.bind(this, "fix
", true));
2321 if (!this.float_browser_disabled)
2322 JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.circle, 15, "toggle
float browser
")
2323 .style("margin
","3px
").on("click
", this.CreateBrowser.bind(this, "float", true));
2325 if (!this.status_disabled)
2326 JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.three_circles, 15, "toggle status line
")
2327 .style("margin
","3px
").on("click
", this.CreateStatusLine.bind(this, 0, "toggle
"));
2330 this.SetDisplay(layout, this.brlayout.drawing_divid());
2333 HierarchyPainter.prototype.CreateStatusLine = function(height, mode) {
2334 if (this.status_disabled || !this.gui_div || !this.brlayout) return '';
2335 return this.brlayout.CreateStatusLine(height, mode);
2338 HierarchyPainter.prototype.CreateBrowser = function(browser_kind, update_html, call_back) {
2339 if (!this.gui_div) return;
2341 var hpainter = this;
2342 JSROOT.AssertPrerequisites('jq2d', function() {
2343 hpainter.CreateBrowser(browser_kind, update_html, call_back);
2347 // ======================================================================================
2349 JSROOT.BuildNobrowserGUI = function() {
2350 var myDiv = d3.select('#simpleGUI'),
2351 online = false, drawing = false;
2353 if (myDiv.empty()) {
2355 myDiv = d3.select('#onlineGUI');
2356 if (myDiv.empty()) { myDiv = d3.select('#drawGUI'); drawing = true; }
2357 if (myDiv.empty()) return alert('no div for simple nobrowser gui found');
2360 if (myDiv.attr("ignoreurl
") === "true")
2361 JSROOT.gStyle.IgnoreUrlOptions = true;
2363 JSROOT.Painter.readStyleFromURL();
2365 var guisize = JSROOT.GetUrlOption("divsize
");
2367 guisize = guisize.split("x
");
2368 if (guisize.length != 2) guisize = null;
2372 myDiv.style('position',"relative
").style('width', guisize[0] + "px
").style('height', guisize[1] + "px
");
2374 d3.select('html').style('height','100%');
2375 d3.select('body').style('min-height','100%').style('margin',0).style('overflow',"hidden
");
2376 myDiv.style('position',"absolute
").style('left',0).style('top',0).style('bottom',0).style('right',0).style('padding',1);
2379 var hpainter = new JSROOT.HierarchyPainter('root', null);
2381 if (online) hpainter.is_online = drawing ? "draw
" : "online
";
2382 if (drawing) hpainter.exclude_browser = true;
2384 hpainter.start_without_browser = true; // indicate that browser not required at the beginning
2386 hpainter.StartGUI(myDiv, function() {
2387 if (!drawing) return;
2389 var func = JSROOT.findFunction('GetCachedObject');
2390 var obj = (typeof func == 'function') ? JSROOT.JSONR_unref(func()) : null;
2391 if (obj) hpainter._cached_draw_object = obj;
2392 var opt = JSROOT.GetUrlOption("opt
") || "";
2394 if (JSROOT.GetUrlOption("websocket
")!==null) opt+=";websocket
";
2396 hpainter.display("", opt);
2400 JSROOT.Painter.drawStreamerInfo = function(divid, lst) {
2401 var painter = new JSROOT.HierarchyPainter('sinfo', divid, 'white');
2403 painter.h = { _name : "StreamerInfo
", _childs : [] };
2405 for ( var i = 0; i < lst.arr.length; ++i) {
2406 var entry = lst.arr[i]
2408 if (entry._typename == "TList
") continue;
2410 if (typeof (entry.fName) == 'undefined') {
2411 JSROOT.console("strange element in StreamerInfo with type
" + entry._typename);
2416 _name : entry.fName + ";
" + entry.fClassVersion,
2417 _kind : "class " + entry.fName,
2418 _title : "class:
" + entry.fName + ' version:' + entry.fClassVersion + ' checksum:' + entry.fCheckSum,
2423 if (entry.fTitle != '') item._title += ' ' + entry.fTitle;
2425 painter.h._childs.push(item);
2427 if (typeof entry.fElements == 'undefined') continue;
2428 for ( var l = 0; l < entry.fElements.arr.length; ++l) {
2429 var elem = entry.fElements.arr[l];
2430 if (!elem || !elem.fName) continue;
2431 var info = elem.fTypeName + " " + elem.fName,
2432 title = elem.fTypeName + " type:
" + elem.fType;
2433 if (elem.fArrayDim===1)
2434 info += "[
" + elem.fArrayLength + "]
";
2436 for (var dim=0;dim<elem.fArrayDim;++dim)
2437 info+="[
" + elem.fMaxIndex[dim] + "]
";
2438 if (elem.fBaseVersion===4294967295) info += ":-1
"; else
2439 if (elem.fBaseVersion!==undefined) info += ":
" + elem.fBaseVersion;
2441 if (elem.fTitle != '') info += "
2443 item._childs.push({ _name : info, _title: title, _kind: elem.fTypeName, _icon: (elem.fTypeName ==
'BASE') ?
"img_class" :
"img_member" });
2445 if (item._childs.length == 0)
delete item._childs;
2450 painter.RefreshHtml(
function() {
2451 painter.SetDivId(divid);
2452 painter.DrawingReady();
2460 JSROOT.Painter.drawInspector =
function(divid, obj) {
2462 JSROOT.cleanup(divid);
2464 var painter =
new JSROOT.HierarchyPainter(
'inspector', divid,
'white');
2465 painter.default_by_click =
"expand";
2466 painter.with_icons =
false;
2467 painter.h = { _name:
"Object", _title:
"", _click_action:
"expand", _nosimple:
false, _do_context:
true };
2468 if ((typeof obj.fTitle ===
'string') && (obj.fTitle.length>0))
2469 painter.h._title = obj.fTitle;
2471 if (painter.select_main().classed(
"jsroot_inspector"))
2472 painter.removeInspector =
function() {
2473 this.select_main().remove();
2477 painter.h._title +=
" type:" + obj._typename;
2479 if ((typeof obj.fName ===
'string') && (obj.fName.length > 0))
2480 painter.h._name = obj.fName;
2484 painter.fill_context =
function(menu, hitem) {
2485 var sett = JSROOT.getDrawSettings(hitem._kind,
'nosame');
2487 menu.addDrawMenu(
"nosub:Draw", sett.opts,
function(arg) {
2488 if (!hitem || !hitem._obj)
return;
2489 var obj = hitem._obj, divid =
this.divid;
2490 if (this.removeInspector) {
2491 divid = this.select_main().node().parentNode;
2492 this.removeInspector();
2493 if (arg ==
"inspect")
2494 return this.ShowInspector(obj);
2496 JSROOT.cleanup(divid);
2497 JSROOT.draw(divid, obj, arg);
2501 if (JSROOT.IsRootCollection(obj)) {
2502 painter.h._name = obj.name || obj._typename;
2503 ListHierarchy(painter.h, obj);
2505 ObjectHierarchy(painter.h, obj);
2507 painter.RefreshHtml(
function() {
2508 painter.SetDivId(divid);
2509 painter.DrawingReady();
2519 function MDIDisplay(frameid) {
2520 JSROOT.TBasePainter.call(
this);
2521 this.frameid = frameid;
2522 this.SetDivId(frameid);
2523 this.select_main().property(
'mdi',
this);
2524 this.CleanupFrame = JSROOT.cleanup;
2525 this.active_frame_title =
"";
2528 MDIDisplay.prototype = Object.create(JSROOT.TBasePainter.prototype);
2530 MDIDisplay.prototype.BeforeCreateFrame =
function(title) {
2531 this.active_frame_title = title;
2534 MDIDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
2538 console.warn(
"ForEachFrame not implemented in MDIDisplay");
2541 MDIDisplay.prototype.ForEachPainter =
function(userfunc, only_visible) {
2545 this.ForEachFrame(
function(frame) {
2546 var dummy =
new JSROOT.TObjectPainter();
2547 dummy.SetDivId(frame, -1);
2548 dummy.ForEachPainter(
function(painter) { userfunc(painter, frame); });
2552 MDIDisplay.prototype.NumDraw =
function() {
2554 this.ForEachFrame(
function() { ++cnt; });
2558 MDIDisplay.prototype.FindFrame =
function(searchtitle, force) {
2559 var found_frame = null;
2561 this.ForEachFrame(
function(frame) {
2562 if (d3.select(frame).attr(
'frame_title') == searchtitle)
2563 found_frame = frame;
2566 if ((found_frame == null) && force)
2567 found_frame = this.CreateFrame(searchtitle);
2572 MDIDisplay.prototype.ActivateFrame =
function(frame) {
2573 this.active_frame_title = d3.select(frame).attr(
'frame_title');
2576 MDIDisplay.prototype.GetActiveFrame =
function() {
2577 return this.FindFrame(this.active_frame_title);
2580 MDIDisplay.prototype.CheckMDIResize =
function(only_frame_id, size) {
2582 var resized_frame = null;
2584 this.ForEachPainter(
function(painter, frame) {
2586 if (only_frame_id && (d3.select(frame).attr(
'id') != only_frame_id))
return;
2588 if ((painter.GetItemName()!==null) && (typeof painter.CheckResize ==
'function')) {
2590 if (resized_frame === frame)
return;
2591 painter.CheckResize(size);
2592 resized_frame = frame;
2597 MDIDisplay.prototype.Reset =
function() {
2599 this.active_frame_title =
"";
2601 this.ForEachFrame(this.CleanupFrame);
2603 this.select_main().html(
"").property(
'mdi', null);
2606 MDIDisplay.prototype.Draw =
function(title, obj, drawopt) {
2610 if (!JSROOT.canDraw(obj._typename, drawopt))
return;
2612 var frame = this.FindFrame(title,
true);
2614 this.ActivateFrame(frame);
2616 return JSROOT.redraw(frame, obj, drawopt);
2622 function CustomDisplay() {
2623 JSROOT.MDIDisplay.call(
this,
"dummy");
2627 CustomDisplay.prototype = Object.create(MDIDisplay.prototype);
2629 CustomDisplay.prototype.AddFrame =
function(divid, itemname) {
2630 if (!(divid in this.frames)) this.frames[divid] =
"";
2632 this.frames[divid] += (itemname +
";");
2635 CustomDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
2636 var ks = Object.keys(this.frames);
2637 for (var k = 0; k < ks.length; ++k) {
2638 var node = d3.select(
"#"+ks[k]);
2640 JSROOT.CallBack(userfunc, node.node());
2644 CustomDisplay.prototype.CreateFrame =
function(title) {
2646 this.BeforeCreateFrame(title);
2648 var ks = Object.keys(this.frames);
2649 for (var k = 0; k < ks.length; ++k) {
2650 var items = this.frames[ks[k]];
2651 if (items.indexOf(title+
";")>=0)
2652 return d3.select(
"#"+ks[k]).node();
2657 CustomDisplay.prototype.Reset =
function() {
2658 MDIDisplay.prototype.Reset.call(
this);
2659 this.ForEachFrame(
function(frame) {
2660 d3.select(frame).html(
"");
2666 function GridDisplay(frameid, kind, kind2) {
2677 JSROOT.MDIDisplay.call(
this, frameid);
2682 this.vertical = kind && (kind[0] ==
'v');
2683 this.use_separarators = !kind || (kind.indexOf(
"x")<0);
2684 this.simple_layout =
false;
2686 this.select_main().style(
'overflow',
'hidden');
2688 if (kind ===
"simple") {
2689 this.simple_layout =
true;
2690 this.use_separarators =
false;
2695 var num = 2, arr = undefined, sizes = undefined;
2697 if ((kind.indexOf(
"grid") == 0) || kind2) {
2698 if (kind2) kind = kind +
"x" + kind2;
2699 else kind = kind.substr(4).trim();
2700 this.use_separarators =
false;
2701 if (kind[0]===
"i") {
2702 this.use_separarators =
true;
2703 kind = kind.substr(1);
2706 var separ = kind.indexOf(
"x"), sizex = 3, sizey = 3;
2709 sizey = parseInt(kind.substr(separ + 1));
2710 sizex = parseInt(kind.substr(0, separ));
2712 sizex = sizey = parseInt(kind);
2715 if (isNaN(sizex)) sizex = 3;
2716 if (isNaN(sizey)) sizey = 3;
2719 this.vertical =
true;
2722 arr =
new Array(num);
2723 for (var k=0;k<num;++k) arr[k] = sizex;
2727 this.vertical =
false;
2730 this.simple_layout =
true;
2731 this.use_separarators =
false;
2738 if (kind && kind.indexOf(
"_")>0) {
2739 var arg = parseInt(kind.substr(kind.indexOf(
"_")+1), 10);
2740 if (!isNaN(arg) && (arg>10)) {
2741 kind = kind.substr(0, kind.indexOf(
"_"));
2744 sizes.unshift(Math.max(arg % 10, 1));
2745 arg = Math.round((arg-sizes[0])/10);
2746 if (sizes[0]===0) sizes[0]=1;
2751 kind = kind ? parseInt(kind.replace( /^\D+/g,
''), 10) : 0;
2752 if (kind && (kind>1)) {
2758 arr.unshift(kind % 10);
2759 kind = Math.round((kind-arr[0])/10);
2760 if (arr[0]==0) arr[0]=1;
2766 if (sizes && (sizes.length!==num)) sizes = undefined;
2768 if (!this.simple_layout)
2769 this.CreateGroup(
this, this.select_main(), num, arr, sizes);
2772 GridDisplay.prototype = Object.create(MDIDisplay.prototype);
2774 GridDisplay.prototype.CreateGroup =
function(handle, main, num, childs, sizes) {
2776 if (!sizes) sizes =
new Array(num);
2777 var sum1 = 0, sum2 = 0;
2778 for (var n=0;n<num;++n) sum1 += (sizes[n] || 1);
2779 for (var n=0;n<num;++n) {
2780 sizes[n] = Math.round(100 * (sizes[n] || 1) / sum1);
2782 if (n==num-1) sizes[n] += (100-sum2);
2785 for (var cnt = 0; cnt<num; ++cnt) {
2786 var group = {
id: cnt, drawid: -1, position: 0, size: sizes[cnt] };
2787 if (cnt>0) group.position = handle.groups[cnt-1].position + handle.groups[cnt-1].size;
2788 group.position0 = group.position;
2790 if (!childs || !childs[cnt] || childs[cnt]<2) group.drawid = this.framecnt++;
2792 handle.groups.push(group);
2794 var elem = main.append(
"div").attr(
'groupid', group.id);
2796 if (handle.vertical)
2797 elem.style(
'float',
'bottom').style(
'height',group.size+
'%').style(
'width',
'100%');
2799 elem.style(
'float',
'left').style(
'width',group.size+
'%').style(
'height',
'100%');
2801 if (group.drawid>=0) {
2802 elem.classed(
'jsroot_newgrid',
true);
2803 if (typeof this.frameid ===
'string')
2804 elem.attr(
'id', this.frameid +
"_" + group.drawid);
2806 elem.style(
'display',
'flex').style(
'flex-direction', handle.vertical ?
"row" :
"column");
2809 if (childs && (childs[cnt]>1)) {
2810 group.vertical = !handle.vertical;
2812 elem.style(
'overflow',
'hidden');
2813 this.CreateGroup(group, elem, childs[cnt]);
2817 if (this.use_separarators && this.CreateSeparator)
2818 for (var cnt=1;cnt<num;++cnt)
2819 this.CreateSeparator(handle, main, handle.groups[cnt]);
2822 GridDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
2823 if (this.simple_layout)
2824 userfunc(this.GetFrame());
2826 this.select_main().selectAll(
'.jsroot_newgrid').each(
function() {
2827 userfunc(d3.select(
this).node());
2831 GridDisplay.prototype.GetActiveFrame =
function() {
2832 if (this.simple_layout)
return this.GetFrame();
2834 var found = MDIDisplay.prototype.GetActiveFrame.call(
this);
2835 if (found)
return found;
2837 this.ForEachFrame(
function(frame) {
2838 if (!found) found = frame;
2844 GridDisplay.prototype.ActivateFrame =
function(frame) {
2845 this.active_frame_title = d3.select(frame).attr(
'frame_title');
2848 GridDisplay.prototype.GetFrame =
function(id) {
2849 if (this.simple_layout)
2850 return this.select_main(
'origin').node();
2852 this.select_main().selectAll(
'.jsroot_newgrid').each(
function() {
2853 if (
id-- === 0) res =
this;
2858 GridDisplay.prototype.NumGridFrames =
function() {
2859 return this.framecnt;
2862 GridDisplay.prototype.CreateFrame =
function(title) {
2863 this.BeforeCreateFrame(title);
2865 var frame = null, maxloop = this.framecnt || 2;
2867 while (!frame && maxloop--) {
2868 frame = this.GetFrame(this.getcnt);
2869 if (!this.simple_layout && this.framecnt)
2870 this.getcnt = (this.getcnt+1) % this.framecnt;
2872 if (d3.select(frame).classed(
"jsroot_fixed_frame")) frame = null;
2876 this.CleanupFrame(frame);
2877 d3.select(frame).attr(
'frame_title', title);
2886 JSROOT.Painter.drawList = drawList;
2888 JSROOT.Painter.FolderHierarchy = FolderHierarchy;
2889 JSROOT.Painter.ObjectHierarchy = ObjectHierarchy;
2890 JSROOT.Painter.TaskHierarchy = TaskHierarchy;
2891 JSROOT.Painter.ListHierarchy = ListHierarchy;
2892 JSROOT.Painter.KeysHierarchy = KeysHierarchy;
2894 JSROOT.BrowserLayout = BrowserLayout;
2895 JSROOT.HierarchyPainter = HierarchyPainter;
2897 JSROOT.MDIDisplay = MDIDisplay;
2898 JSROOT.CustomDisplay = CustomDisplay;
2899 JSROOT.GridDisplay = GridDisplay;