5 if ( typeof define ===
"function" && define.amd ) {
7 define( [
'jquery',
'jquery-ui',
'd3',
'JSRootPainter'], factory );
10 if (typeof jQuery ==
'undefined')
11 throw new Error(
'jQuery not defined',
'JSRootPainter.jquery.js');
13 if (typeof jQuery.ui ==
'undefined')
14 throw new Error(
'jQuery-ui not defined',
'JSRootPainter.jquery.js');
16 if (typeof d3 !=
'object')
17 throw new Error(
'This extension requires d3.v3.js',
'JSRootPainter.jquery.js');
19 if (typeof JSROOT ==
'undefined')
20 throw new Error(
'JSROOT is not defined',
'JSRootPainter.jquery.js');
22 if (typeof JSROOT.Painter !=
'object')
23 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.jquery.js');
26 factory(jQuery, jQuery.ui, d3, JSROOT);
28 } (
function($, myui, d3, JSROOT) {
30 if ( typeof define ===
"function" && define.amd )
31 JSROOT.loadScript(
'$$$style/jquery-ui.css');
33 JSROOT.Painter.createMenu =
function(maincallback, menuname) {
34 if (!menuname || (typeof menuname !==
'string')) menuname =
'root_ctx_menu';
36 var menu = { element: null, code:
"", cnt: 1, funcs: {}, separ:
false };
38 menu.add =
function(name, arg, func) {
39 if (name ==
"separator") { this.code +=
"<li>-</li>"; this.separ =
true;
return; }
41 if (name.indexOf(
"header:")==0) {
42 this.code +=
"<li class='ui-widget-header' style='padding-left:5px'>"+name.substr(7)+
"</li>";
46 if (name==
"endsub:") { this.code +=
"</ul></li>";
return; }
47 var close_tag =
"</li>", style =
"padding-top:2px;padding-bottom:1px";
48 if (name.indexOf(
"sub:")==0) { name = name.substr(4); close_tag=
"<ul>"; style +=
";padding-right:2em"}
50 if (typeof arg ==
'function') { func = arg; arg = name; }
54 if (name.indexOf(
"chk:")==0) { name =
"<span class='ui-icon ui-icon-check' style='margin:1px'></span>" + name.substr(4); }
else
55 if (name.indexOf(
"unk:")==0) { name =
"<span class='ui-icon ui-icon-blank' style='margin:1px'></span>" + name.substr(4); }
58 if (($.ui.version.indexOf(
"1.10")==0) || ($.ui.version.indexOf(
"1.9")==0))
59 name =
'<a href="#">' + name +
'</a>';
61 this.code +=
"<li cnt='" + this.cnt +
"' arg='" + arg +
"' style='" + style +
"'>" + name + close_tag;
62 if (typeof func ==
'function') this.funcs[this.cnt] = func;
67 menu.addchk =
function(flag, name, arg, func) {
68 return this.add((flag ?
"chk:" :
"unk:") + name, arg, func);
71 menu.size =
function() {
return this.cnt-1; }
73 menu.addDrawMenu =
function(menu_name, opts, call_back) {
74 if (opts==null) opts =
new Array;
75 if (opts.length==0) opts.push(
"");
77 this.add((opts.length > 1) ? (
"sub:" + menu_name) : menu_name, opts[0], call_back);
78 if (opts.length<2)
return;
80 for (var i=0;i<opts.length;++i) {
82 if (name==
"") name =
'<dflt>';
83 this.add(name, opts[i], call_back);
88 menu.remove =
function() {
89 if (this.element!==null) {
90 this.element.remove();
91 if (this.close_callback) this.close_callback();
92 document.body.removeEventListener(
'click', this.remove_bind);
97 menu.remove_bind = menu.remove.bind(menu);
99 menu.show =
function(event, close_callback) {
102 if (typeof close_callback ==
'function') this.close_callback = close_callback;
104 document.body.addEventListener(
'click', this.remove_bind);
106 var oldmenu = document.getElementById(menuname);
107 if (oldmenu) oldmenu.parentNode.removeChild(oldmenu);
109 $(document.body).append(
'<ul class="jsroot_ctxmenu">' + this.code +
'</ul>');
111 this.element = $(
'.jsroot_ctxmenu');
116 .attr(
'id', menuname)
117 .css(
'left', event.clientX + window.pageXOffset)
118 .css(
'top', event.clientY + window.pageYOffset)
119 .css(
'font-size',
'80%')
120 .css(
'position',
'absolute')
122 items:
"> :not(.ui-widget-header)",
123 select:
function( event, ui ) {
124 var arg = ui.item.attr(
'arg');
125 var cnt = ui.item.attr(
'cnt');
126 var func = cnt ? pthis.funcs[cnt] : null;
128 if (typeof func ==
'function') {
129 if (
'painter' in menu)
130 func.bind(pthis.painter)(arg);
137 var newx = null, newy = null;
139 if (event.clientX +
this.element.width() > $(window).width()) newx = $(window).width() - this.element.width() - 20;
140 if (event.clientY +
this.element.height() > $(window).height()) newy = $(window).height() - this.element.height() - 20;
142 if (newx!==null) this.element.css(
'left', (newx>0 ? newx : 0) + window.pageXOffset);
143 if (newy!==null) this.element.css(
'top', (newy>0 ? newy : 0) + window.pageYOffset);
146 JSROOT.CallBack(maincallback, menu);
151 JSROOT.HierarchyPainter.prototype.isLastSibling =
function(hitem) {
152 if (!hitem || !hitem._parent || !hitem._parent._childs)
return false;
153 var chlds = hitem._parent._childs;
154 var indx = chlds.indexOf(hitem);
155 if (indx<0)
return false;
156 while (++indx < chlds.length)
157 if (!(
'_hidden' in chlds[indx]))
return false;
161 JSROOT.HierarchyPainter.prototype.addItemHtml =
function(hitem, d3prnt, doupdate) {
162 var isroot = !(
'_parent' in hitem);
163 var has_childs =
'_childs' in hitem;
165 if (
'_hidden' in hitem)
return;
167 var handle = JSROOT.getDrawHandle(hitem._kind),
168 img1 =
"", img2 =
"", can_click =
false;
170 if (handle !== null) {
171 if (
'icon' in handle) img1 = handle.icon;
172 if (
'icon2' in handle) img2 = handle.icon2;
173 if ((
'func' in handle) || (
'execute' in handle) || (
'aslink' in handle) ||
174 ((
'expand' in handle) && (hitem._more !==
false))) can_click =
true;
177 if (
'_icon' in hitem) img1 = hitem._icon;
178 if (
'_icon2' in hitem) img2 = hitem._icon2;
179 if ((img1.length==0) && (
'_online' in hitem))
180 hitem._icon = img1 =
"img_globe";
181 if ((img1.length==0) && isroot)
182 hitem._icon = img1 =
"img_base";
184 if (hitem._more || (
'_expand' in hitem) || (
'_player' in hitem))
187 var can_menu = can_click;
188 if (!can_menu && (typeof hitem._kind ==
'string') && (hitem._kind.indexOf(
"ROOT.")==0)) {
193 if (img2.length==0) img2 = img1;
194 if (img1.length==0) img1 = (has_childs || hitem._more) ?
"img_folder" :
"img_page";
195 if (img2.length==0) img2 = (has_childs || hitem._more) ?
"img_folderopen" :
"img_page";
197 var itemname = this.itemFullName(hitem);
202 d3prnt.selectAll(
"*").remove();
205 d3cont = d3prnt.append(
"div");
208 d3cont.attr(
"item", itemname);
211 var prnt = isroot ? null : hitem._parent;
212 while ((prnt != null) && (prnt != this.h)) {
213 d3cont.insert(
"div",
":first-child")
214 .attr(
"class", this.isLastSibling(prnt) ?
"img_empty" :
"img_line");
218 var icon_class =
"", plusminus =
false;
224 icon_class = hitem._isopen ?
"img_minus" :
"img_plus";
231 icon_class =
"img_join";
236 if (icon_class.length > 0) {
237 if (this.isLastSibling(hitem)) icon_class+=
"bottom";
238 var d3icon = d3cont.append(
"div").attr(
'class', icon_class);
239 if (plusminus) d3icon.style(
'cursor',
'pointer')
240 .on(
"click",
function() { h.tree_click(
this,
"plusminus"); });
245 if (this.with_icons) {
246 var icon_name = hitem._isopen ? img2 : img1;
247 var title = hitem._kind ? hitem._kind.replace(/</g,
'<').replace(/>/g,
'>') :
"";
251 if (icon_name.indexOf(
"img_")==0) {
252 d3img = d3cont.append(
"div")
253 .attr(
"class", icon_name)
254 .attr(
"title", title);
256 d3img = d3cont.append(
"img")
257 .attr(
"src", icon_name)
260 .style(
'vertical-align',
'top')
261 .style(
'width',
'18px')
262 .style(
'height',
'18px');
265 if (
'_icon_click' in hitem)
266 d3img.on(
"click",
function() { h.tree_click(
this,
"icon"); });
269 var d3a = d3cont.append(
"a");
270 if (can_click || has_childs)
271 d3a.attr(
"class",
"h_item")
272 .on(
"click",
function() { h.tree_click(
this); });
274 if (
'disp_kind' in h) {
275 if (JSROOT.gStyle.DragAndDrop && can_click)
276 this.enable_dragging(d3a.node(), itemname);
277 if (JSROOT.gStyle.ContextMenu && can_menu)
278 d3a.on(
'contextmenu',
function() { h.tree_contextmenu(
this); });
281 var element_name = hitem._name;
283 if (
'_realname' in hitem)
284 element_name = hitem._realname;
286 var element_title =
"";
287 if (
'_title' in hitem) element_title = hitem._title;
289 if (
'_fullname' in hitem)
290 element_title +=
" fullname: " + hitem._fullname;
292 if (element_title.length === 0)
293 element_title = element_name;
295 d3a.attr(
'title', element_title)
296 .text(element_name + (
'_value' in hitem ?
":" :
""));
298 if (
'_value' in hitem) {
299 var d3p = d3cont.append(
"p");
300 if (
'_vclass' in hitem) d3p.attr(
'class', hitem._vclass);
301 if (!hitem._isopen) d3p.html(hitem._value);
304 if (has_childs && (isroot || hitem._isopen)) {
305 var d3chlds = d3cont.append(
"div").attr(
"class",
"h_childs");
306 for (var i=0; i< hitem._childs.length;++i) {
307 var chld = hitem._childs[i];
308 chld._parent = hitem;
309 this.addItemHtml(chld, d3chlds);
314 JSROOT.HierarchyPainter.prototype.RefreshHtml =
function(callback) {
316 if (this.divid == null)
return JSROOT.CallBack(callback);
317 var d3elem = this.select_main();
321 if ((this.h == null) || d3elem.empty())
322 return JSROOT.CallBack(callback);
324 var h =
this, factcmds = [], status_item = null;
325 this.ForEach(
function(item) {
326 if ((
'_fastcmd' in item) && (item._kind ==
'Command')) factcmds.push(item);
327 if ((
'_status' in item) && (status_item==null)) status_item = item;
332 .attr(
"class",
"jsroot")
333 .style(
"background-color", this.background ? this.background :
"")
334 .style(
'overflow',
'auto')
335 .style(
'width',
'100%')
336 .style(
'height',
'100%')
337 .style(
'font-size', this.with_icons ?
"12px" :
"15px");
339 for (var n=0;n<factcmds.length;++n) {
341 maindiv.append(
"button")
343 .attr(
"class",
'fast_command')
344 .attr(
"item", this.itemFullName(factcmds[n]))
345 .attr(
"title", factcmds[n]._title)
346 .on(
"click",
function() { h.ExecuteCommand(d3.select(
this).attr(
"item"),
this); } );
349 if (
'_icon' in factcmds[n])
350 btn.append(
'img').attr(
"src", factcmds[n]._icon);
353 d3p = maindiv.append(
"p");
355 d3p.append(
"a").attr(
"href",
'#').text(
"open all").on(
"click",
function() { h.toggle(
true); d3.event.preventDefault(); });
356 d3p.append(
"text").text(
" | ");
357 d3p.append(
"a").attr(
"href",
'#').text(
"close all").on(
"click",
function() { h.toggle(
false); d3.event.preventDefault(); });
359 if (
'_online' in this.h) {
360 d3p.append(
"text").text(
" | ");
361 d3p.append(
"a").attr(
"href",
'#').text(
"reload").on(
"click",
function() { h.reload(); d3.event.preventDefault(); });
364 if (
'disp_kind' in
this) {
365 d3p.append(
"text").text(
" | ");
366 d3p.append(
"a").attr(
"href",
'#').text(
"clear").on(
"click",
function() { h.clear(
false); d3.event.preventDefault(); });
369 this.addItemHtml(this.h, maindiv.append(
"div").attr(
"class",
"h_tree"));
371 if ((status_item!=null) && (JSROOT.GetUrlOption(
'nostatus')==null)) {
372 var func = JSROOT.findFunction(status_item._status);
373 var hdiv = (typeof func ==
'function') ? JSROOT.Painter.ConfigureHSeparator(30) : null;
375 func(hdiv, this.itemFullName(status_item));
378 JSROOT.CallBack(callback);
381 JSROOT.HierarchyPainter.prototype.UpdateTreeNode =
function(hitem, d3cont) {
382 if ((d3cont===undefined) || d3cont.empty()) {
383 var name = this.itemFullName(hitem);
384 d3cont = this.select_main().select(
"[item='" + name +
"']");
386 if (d3cont.empty() && (
'_cycle' in hitem))
387 d3cont = this.select_main().select(
"[item='" + name +
";" + hitem._cycle +
"']");
388 if (d3cont.empty())
return;
391 this.addItemHtml(hitem, d3cont,
true);
394 JSROOT.HierarchyPainter.prototype.tree_click =
function(node, place) {
395 if (node===null)
return;
396 var d3cont = d3.select(node.parentNode);
397 var itemname = d3cont.attr(
'item');
398 if (itemname == null)
return;
400 var hitem = this.Find(itemname);
401 if (hitem == null)
return;
403 var prnt = hitem, dflt = undefined;
405 if ((dflt = prnt._click_action) !== undefined)
break;
409 if (!place || (place==
"")) place =
"item";
411 if (place ==
"icon") {
412 if ((
'_icon_click' in hitem) && (typeof hitem._icon_click ==
'function'))
413 if (hitem._icon_click(hitem))
414 this.UpdateTreeNode(hitem, d3cont);
419 if ((place==
"item") && (
'_expand' in hitem)) place =
"plusminus";
422 if (((place ==
"plusminus") && !(
'_childs' in hitem) && hitem._more) ||
423 ((place ==
"item") && (dflt ===
"expand")))
424 return this.expand(itemname, null, d3cont);
426 if (place ==
"item") {
427 if (
'_player' in hitem)
428 return this.player(itemname);
430 var handle = JSROOT.getDrawHandle(hitem._kind);
432 if (handle != null) {
433 if (
'aslink' in handle)
434 return window.open(itemname +
"/");
436 if (
'func' in handle)
437 return this.display(itemname);
439 if (
'execute' in handle)
440 return this.ExecuteCommand(itemname, node.parentNode);
442 if ((
'expand' in handle) && (hitem._childs == null))
443 return this.expand(itemname, null, d3cont);
446 if (!hitem._childs && (
this.default_by_click ===
"expand"))
447 return this.expand(itemname, null, d3cont);
450 if ((typeof hitem._kind ===
"string") && (hitem._kind.indexOf(
"ROOT.")===0))
451 return this.display(itemname,
"inspect");
453 if (!hitem._childs || (hitem ===
this.h))
return;
457 delete hitem._isopen;
459 hitem._isopen =
true;
461 this.UpdateTreeNode(hitem, d3cont);
464 JSROOT.HierarchyPainter.prototype.tree_contextmenu =
function(elem) {
465 d3.event.preventDefault();
467 var itemname = d3.select(elem.parentNode).attr(
'item');
469 var hitem = this.Find(itemname);
470 if (hitem==null)
return;
474 var onlineprop = painter.GetOnlineProp(itemname);
475 var fileprop = painter.GetFileProp(itemname);
477 function qualifyURL(url) {
478 function escapeHTML(s) {
479 return s.split(
'&').join(
'&').split(
'<').join(
'<').split(
'"').join(
'"');
481 var el = document.createElement(
'div');
482 el.innerHTML =
'<a href="' + escapeHTML(url) +
'">x</a>';
483 return el.firstChild.href;
486 JSROOT.Painter.createMenu(
function(menu) {
488 menu[
'painter'] = painter;
490 if ((itemname ==
"") && !(
'_jsonfile' in hitem)) {
491 var addr =
"", cnt = 0;
492 function separ() {
return cnt++ > 0 ?
"&" :
"?"; }
495 painter.ForEachRootFile(
function(item) { files.push(item._file.fFullURL); });
497 if (painter.GetTopOnlineItem()==null)
498 addr = JSROOT.source_dir +
"index.htm";
500 if (painter.IsMonitoring())
501 addr += separ() +
"monitoring=" + painter.MonitoringInterval();
504 addr += separ() +
"file=" + files[0];
507 addr += separ() +
"files=" + JSON.stringify(files);
509 if (painter[
'disp_kind'])
510 addr += separ() +
"layout=" + painter.disp_kind.replace(/ /g,
"");
514 if (painter[
'disp'] != null)
515 painter[
'disp'].ForEachPainter(
function(p) {
516 if (p.GetItemName()!=null)
517 items.push(p.GetItemName());
520 if (items.length == 1) {
521 addr += separ() +
"item=" + items[0];
522 }
else if (items.length > 1) {
523 addr += separ() +
"items=" + JSON.stringify(items);
526 menu.add(
"Direct link",
function() { window.open(addr); });
527 menu.add(
"Only items",
function() { window.open(addr +
"&nobrowser"); });
529 if (onlineprop != null) {
530 painter.FillOnlineMenu(menu, onlineprop, itemname);
532 var opts = JSROOT.getDrawOptions(hitem._kind,
'nosame');
535 menu.addDrawMenu(
"Draw", opts,
function(arg) { this.display(itemname, arg); });
537 if ((fileprop!=null) && (opts!=null)) {
538 var filepath = qualifyURL(fileprop.fileurl);
539 if (filepath.indexOf(JSROOT.source_dir) == 0)
540 filepath = filepath.slice(JSROOT.source_dir.length);
541 menu.addDrawMenu(
"Draw in new window", opts,
function(arg) {
542 window.open(JSROOT.source_dir +
"index.htm?nobrowser&file=" + filepath +
"&item=" + fileprop.itemname+
"&opt="+arg);
546 if (!(
'_childs' in hitem) && (hitem._more || !(
'_more' in hitem)))
547 menu.add(
"Expand",
function() { painter.expand(itemname); });
550 if ((
'_menu' in hitem) && (typeof hitem[
'_menu'] ==
'function'))
551 hitem[
'_menu'](menu, hitem, painter);
553 if (menu.size() > 0) {
554 menu.tree_node = elem.parentNode;
555 if (menu.separ) menu.add(
"separator");
565 JSROOT.HierarchyPainter.prototype.CreateDisplay =
function(callback) {
566 if (
'disp' in
this) {
567 if (this.disp.NumDraw() > 0)
return JSROOT.CallBack(callback,
this.disp);
573 if (document.getElementById(
this.disp_frameid) == null)
574 return JSROOT.CallBack(callback, null);
576 if (this.disp_kind ==
"tabs")
577 this.disp =
new JSROOT.TabsDisplay(this.disp_frameid);
579 if ((this.disp_kind ==
"flex") || (this.disp_kind ==
"flexible"))
580 this.disp =
new JSROOT.FlexibleDisplay(this.disp_frameid);
582 if (this.disp_kind.search(
"grid") == 0)
583 this.disp =
new JSROOT.GridDisplay(
this.disp_frameid,
this.disp_kind);
585 if (this.disp_kind ==
"simple")
586 this.disp =
new JSROOT.SimpleDisplay(this.disp_frameid);
588 this.disp =
new JSROOT.CollapsibleDisplay(this.disp_frameid);
590 JSROOT.CallBack(callback, this.disp);
593 JSROOT.HierarchyPainter.prototype.enable_dragging =
function(element, itemname) {
594 $(element).draggable({ revert:
"invalid", appendTo:
"body", helper:
"clone" });
597 JSROOT.HierarchyPainter.prototype.enable_dropping =
function(frame, itemname) {
600 hoverClass :
"ui-state-active",
601 accept:
function(ui) {
602 var dropname = ui.parent().attr(
'item');
603 if ((dropname == itemname) || (dropname==null))
return false;
605 var ditem = h.Find(dropname);
606 if ((ditem==null) || (!(
'_kind' in ditem)))
return false;
608 return ditem._kind.indexOf(
"ROOT.")==0;
610 drop:
function(event, ui) {
611 var dropname = ui.draggable.parent().attr(
'item');
612 if (dropname==null)
return false;
613 return h.dropitem(dropname, $(
this).attr(
"id"));
620 JSROOT.CollapsibleDisplay =
function(frameid) {
621 JSROOT.MDIDisplay.call(
this, frameid);
625 JSROOT.CollapsibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
627 JSROOT.CollapsibleDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
628 var topid = this.frameid +
'_collapsible';
630 if (document.getElementById(topid) == null)
return;
632 if (typeof userfunc !=
'function')
return;
634 $(
'#' + topid +
' .collapsible_draw').each(
function() {
637 if (only_visible && $(
this).is(
":hidden"))
return;
639 userfunc($(
this).
get(0));
643 JSROOT.CollapsibleDisplay.prototype.ActivateFrame =
function(frame) {
644 if ($(frame).is(
":hidden")) {
645 $(frame).prev().toggleClass(
"ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
646 .find(
"> .ui-icon").toggleClass(
"ui-icon-triangle-1-e ui-icon-triangle-1-s").end()
647 .next().toggleClass(
"ui-accordion-content-active").slideDown(0);
649 $(frame).prev()[0].scrollIntoView();
652 JSROOT.CollapsibleDisplay.prototype.CreateFrame =
function(title) {
654 var topid = this.frameid +
'_collapsible';
656 if (document.getElementById(topid) == null)
657 $(
"#"+this.frameid).append(
'<div id="'+ topid +
'" class="jsroot ui-accordion ui-accordion-icons ui-widget ui-helper-reset" style="overflow:auto; overflow-y:scroll; height:100%; padding-left: 2px; padding-right: 2px"></div>');
659 var hid = topid +
"_sub" + this.cnt++;
662 var entryInfo =
"<h5 id=\"" + uid +
"\">" +
663 "<span class='ui-icon ui-icon-triangle-1-e'></span>" +
664 "<a> " + title +
"</a> " +
665 "<button type='button' class='jsroot_collaps_closebtn' style='float:right; width:1.4em' title='close canvas'/>" +
667 entryInfo +=
"<div class='collapsible_draw' id='" + hid +
"'></div>\n";
668 $(
"#" + topid).append(entryInfo);
671 .addClass(
"ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom")
672 .hover(
function() { $(
this).toggleClass(
"ui-state-hover"); })
674 $(
this).toggleClass(
"ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
675 .find(
"> .ui-icon").toggleClass(
"ui-icon-triangle-1-e ui-icon-triangle-1-s")
676 .end().next().toggleClass(
"ui-accordion-content-active").slideToggle(0);
677 JSROOT.resize($(
this).next().attr(
'id'));
681 .addClass(
"ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom")
684 $(
'#' + uid).find(
" .jsroot_collaps_closebtn")
685 .button({ icons: { primary:
"ui-icon-close" }, text:
false })
687 JSROOT.cleanup($(
this).parent().next().attr(
'id'));
688 $(
this).parent().next().andSelf().remove();
692 .toggleClass(
"ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom")
693 .find(
"> .ui-icon").toggleClass(
"ui-icon-triangle-1-e ui-icon-triangle-1-s").end().next()
694 .toggleClass(
"ui-accordion-content-active").slideToggle(0);
696 return $(
"#" + hid).attr(
'frame_title', title).css(
'overflow',
'hidden').get(0);
701 JSROOT.TabsDisplay =
function(frameid) {
702 JSROOT.MDIDisplay.call(
this, frameid);
706 JSROOT.TabsDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
708 JSROOT.TabsDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
709 var topid = this.frameid +
'_tabs';
711 if (document.getElementById(topid) == null)
return;
713 if (typeof userfunc !=
'function')
return;
716 var active = $(
'#' + topid).tabs(
"option",
"active");
718 $(
'#' + topid +
'> .tabs_draw').each(
function() {
720 if (!only_visible || (cnt == active))
721 userfunc($(
this).get(0));
725 JSROOT.TabsDisplay.prototype.ActivateFrame =
function(frame) {
726 var cnt = 0,
id = -1;
727 this.ForEachFrame(
function(fr) {
728 if ($(fr).attr(
'id') == $(frame).attr(
'id'))
id = cnt;
731 $(
'#' + this.frameid +
"_tabs").tabs(
"option",
"active",
id);
734 JSROOT.TabsDisplay.prototype.CreateFrame =
function(title) {
735 var topid = this.frameid +
'_tabs';
737 var hid = topid +
"_sub" + this.cnt++;
739 var li =
'<li><a href="#' + hid +
'">' + title
740 +
'</a><span class="ui-icon ui-icon-close" style="float: left; margin: 0.4em 0.2em 0 0; cursor: pointer;" role="presentation">Remove Tab</span></li>';
741 var cont =
'<div class="tabs_draw" id="' + hid +
'"></div>';
743 if (document.getElementById(topid) == null) {
744 $(
"#" + this.frameid).append(
'<div id="' + topid +
'" class="jsroot">' +
' <ul>' + li +
' </ul>' + cont +
'</div>');
746 var tabs = $(
"#" + topid)
747 .css(
'overflow',
'hidden')
749 heightStyle :
"fill",
750 activate :
function (event,ui) {
751 $(ui.newPanel).css(
'overflow',
'hidden');
752 JSROOT.resize($(ui.newPanel).attr(
'id'));
756 tabs.delegate(
"span.ui-icon-close",
"click",
function() {
757 var panelId = $(
this).closest(
"li").remove().attr(
"aria-controls");
758 JSROOT.cleanup(panelId);
759 $(
"#" + panelId).
remove();
760 tabs.tabs(
"refresh");
761 if ($(
'#' + topid +
'> .tabs_draw').length == 0)
762 $(
"#" + topid).
remove();
766 $(
"#" + topid).find(
"> .ui-tabs-nav").append(li);
767 $(
"#" + topid).append(cont);
768 $(
"#" + topid).tabs(
"refresh");
769 $(
"#" + topid).tabs(
"option",
"active", -1);
773 .css(
'overflow',
'hidden')
774 .attr(
'frame_title', title);
776 return $(
'#' + hid).
get(0);
781 JSROOT.FlexibleDisplay =
function(frameid) {
782 JSROOT.MDIDisplay.call(
this, frameid);
786 JSROOT.FlexibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype);
788 JSROOT.FlexibleDisplay.prototype.ForEachFrame =
function(userfunc, only_visible) {
789 var topid = this.frameid +
'_flex';
791 if (document.getElementById(topid) == null)
return;
792 if (typeof userfunc !=
'function')
return;
794 $(
'#' + topid +
' .flex_draw').each(
function() {
798 userfunc($(
this).
get(0));
802 JSROOT.FlexibleDisplay.prototype.ActivateFrame =
function(frame) {
805 JSROOT.FlexibleDisplay.prototype.CreateFrame =
function(title) {
806 var topid = this.frameid +
'_flex';
808 if (document.getElementById(topid) == null)
809 $(
"#" + this.frameid).append(
'<div id="'+ topid +
'" class="jsroot" style="overflow:none; height:100%; width:100%"></div>');
811 var top = $(
"#" + topid);
813 var w = top.width(), h = top.height();
815 var subid = topid +
"_frame" + this.cnt;
817 var entry =
'<div id="' + subid +
'" class="flex_frame" style="position:absolute">' +
818 '<div class="ui-widget-header flex_header">'+
820 '<button type="button" style="float:right; width:1.4em"/>' +
821 '<button type="button" style="float:right; width:1.4em"/>' +
822 '<button type="button" style="float:right; width:1.4em"/>' +
824 '<div id="' + subid +
'_cont" class="flex_draw"></div>' +
829 function ChangeWindowState(main, state) {
830 var curr = main.prop(
'state');
831 if (!curr) curr =
"normal";
832 main.prop(
'state', state);
833 if (state==curr)
return;
835 if (curr ==
"normal") {
836 main.prop(
'original_height', main.height());
837 main.prop(
'original_width', main.width());
838 main.prop(
'original_top', main.css(
'top'));
839 main.prop(
'original_left', main.css(
'left'));
842 main.find(
".jsroot_minbutton").find(
'.ui-icon')
843 .toggleClass(
"ui-icon-carat-1-s", state!=
"minimal")
844 .toggleClass(
"ui-icon-carat-2-n-s", state==
"minimal");
846 main.find(
".jsroot_maxbutton").find(
'.ui-icon')
847 .toggleClass(
"ui-icon-carat-1-n", state!=
"maximal")
848 .toggleClass(
"ui-icon-carat-2-n-s", state==
"maximal");
852 main.height(main.find(
'.flex_header').height()).width(
"auto");
853 main.find(
".flex_draw").css(
"display",
"none");
854 main.find(
".ui-resizable-handle").css(
"display",
"none");
857 main.height(
"100%").width(
"100%").css(
'left',
'').css(
'top',
'');
858 main.find(
".flex_draw").css(
"display",
"");
859 main.find(
".ui-resizable-handle").css(
"display",
"none");
862 main.find(
".flex_draw").css(
"display",
"");
863 main.find(
".ui-resizable-handle").css(
"display",
"");
864 main.height(main.prop(
'original_height'))
865 .width(main.prop(
'original_width'));
867 main.css(
'left', main.prop(
'original_left'))
868 .css(
'top', main.prop(
'original_top'));
871 if (state !==
"minimal")
872 JSROOT.resize(main.find(
".flex_draw").get(0));
876 .css(
'left', parseInt(w * (this.cnt % 5)/10))
877 .css(
'top', parseInt(h * (this.cnt % 5)/10))
878 .width(Math.round(w * 0.58))
879 .height(Math.round(h * 0.58))
881 helper:
"jsroot-flex-resizable-helper",
882 start:
function(event, ui) {
884 $(
this).appendTo($(
this).parent());
886 stop:
function(event, ui) {
887 var rect = { width : ui.size.width-1, height : ui.size.height - $(
this).find(
".flex_header").height()-1 };
888 JSROOT.resize($(
this).find(
".flex_draw").
get(0), rect);
892 containment:
"parent",
893 start:
function(event, ui) {
895 $(
this).appendTo($(
this).parent());
896 var ddd = $(
this).find(
".flex_draw");
898 if (ddd.prop(
'flex_block_drag') ===
true) {
900 var elementMouseIsOver = document.elementFromPoint(event.clientX, event.clientY);
901 var isparent =
false;
902 $(elementMouseIsOver).parents().map(
function() {
if ($(
this).
get(0) === ddd.get(0)) isparent =
true; });
903 if (isparent)
return false;
907 .find(
'.flex_header')
910 var div = $(
this).parent();
911 div.appendTo(div.parent());
915 .attr(
'title',
'close canvas')
916 .button({ icons: { primary:
"ui-icon-close" }, text:
false })
918 var main = $(
this).parent().parent();
919 JSROOT.cleanup(main.find(
".flex_draw").get(0));
923 .attr(
'title',
'maximize canvas')
924 .addClass(
'jsroot_maxbutton')
925 .button({ icons: { primary:
"ui-icon-carat-1-n" }, text:
false })
927 var main = $(
this).parent().parent();
928 var maximize = $(
this).find(
'.ui-icon').hasClass(
"ui-icon-carat-1-n");
929 ChangeWindowState(main, maximize ?
"maximal" :
"normal");
932 .attr(
'title',
'minimize canvas')
933 .addClass(
'jsroot_minbutton')
934 .button({ icons: { primary:
"ui-icon-carat-1-s" }, text:
false })
936 var main = $(
this).parent().parent();
937 var minimize = $(
this).find(
'.ui-icon').hasClass(
"ui-icon-carat-1-s");
938 ChangeWindowState(main, minimize ?
"minimal" :
"normal");
942 $(
"#" + subid).find(
".ui-resizable-handle").css(
'z-index',
'');
949 return $(
"#" + subid +
"_cont").attr(
'frame_title', title).get(0);
954 JSROOT.TTreePlayer =
function(itemname, url, askey, root_version) {
955 JSROOT.TBasePainter.call(
this);
956 this.SetItemName(itemname);
958 this.root_version = root_version;
959 this.hist_painter = null;
964 JSROOT.TTreePlayer.prototype = Object.create( JSROOT.TBasePainter.prototype );
966 JSROOT.TTreePlayer.prototype.Show =
function(divid) {
967 this.drawid = divid +
"_draw";
970 .html(
"<div class='treedraw_buttons' style='padding-left:0.5em'>" +
971 "<button class='treedraw_exe'>Draw</button>" +
972 " Expr:<input class='treedraw_varexp' style='width:12em'></input> " +
973 "<button class='treedraw_more'>More</button>" +
975 "<div id='" + this.drawid +
"' style='width:100%'></div>");
979 $(
"#" + divid).find(
'.treedraw_exe').click(
function() { player.PerformDraw(); });
980 $(
"#" + divid).find(
'.treedraw_varexp')
983 if(e.keyCode == 13) player.PerformDraw();
986 $(
"#" + divid).find(
'.treedraw_more').click(
function() {
988 $(
"#" + divid).find(
".treedraw_buttons")
989 .append(
" Cut:<input class='treedraw_cut' style='width:8em'></input>"+
990 " Opt:<input class='treedraw_opt' style='width:5em'></input>"+
991 " Num:<input class='treedraw_number' style='width:7em'></input>" +
992 " First:<input class='treedraw_first' style='width:7em'></input>");
994 $(
"#" + divid +
" .treedraw_opt").val(
"");
995 $(
"#" + divid +
" .treedraw_number").val(
"").spinner({ numberFormat:
"n", min: 0, page: 1000});
996 $(
"#" + divid +
" .treedraw_first").val(
"").spinner({ numberFormat:
"n", min: 0, page: 1000});
1001 this.SetDivId(divid);
1004 JSROOT.TTreePlayer.prototype.PerformDraw =
function() {
1006 var frame = $(this.select_main().node());
1008 var url = this.url +
'/exe.json.gz?compact=3&method=Draw';
1009 var expr = frame.find(
'.treedraw_varexp').val();
1010 var hname =
"h_tree_draw";
1012 var pos = expr.indexOf(
">>");
1014 expr +=
">>" + hname;
1016 hname = expr.substr(pos+2);
1017 if (hname[0]==
'+') hname = hname.substr(1);
1018 var pos2 = hname.indexOf(
"(");
1019 if (pos2>0) hname = hname.substr(0, pos2);
1022 if (frame.find(
'.treedraw_more').length==0) {
1023 var cut = frame.find(
'.treedraw_cut').val();
1024 var option = frame.find(
'.treedraw_opt').val();
1025 var nentries = frame.find(
'.treedraw_number').val();
1026 var firstentry = frame.find(
'.treedraw_first').val();
1028 url +=
'&prototype="const char*,const char*,Option_t*,Long64_t,Long64_t"&varexp="' + expr +
'"&selection="' + cut +
'"';
1031 if ((option!=
"") || (nentries!=
"") || (firstentry!=
"")) {
1032 if (nentries==
"") nentries = (this.root_version >= 394499) ?
"TTree::kMaxEntries":
"1000000000";
1033 if (firstentry==
"") firstentry =
"0";
1034 url +=
'&option="' + option +
'"&nentries=' + nentries +
'&firstentry=' + firstentry;
1037 url +=
'&prototype="Option_t*"&opt="' + expr +
'"';
1039 url +=
'&_ret_object_=' + hname;
1043 function SubmitDrawRequest() {
1044 JSROOT.NewHttpRequest(url,
'object',
function(res) {
1045 if (res==null)
return;
1046 $(
"#"+player.drawid).empty();
1047 player.hist_painter = JSROOT.draw(player.drawid, res)
1054 JSROOT.NewHttpRequest(this.url +
"/root.json",
'text', SubmitDrawRequest).send();
1055 }
else SubmitDrawRequest();
1058 JSROOT.TTreePlayer.prototype.CheckResize =
function(force) {
1059 var main = $(this.select_main().node());
1061 $(
"#" + this.drawid).width(main.width());
1062 var h = main.height();
1063 var h0 = main.find(
".treedraw_buttons").height();
1064 if (h>h0+30) $(
"#" + this.drawid).height(h - 1 - h0);
1066 if (this.hist_painter) {
1067 this.hist_painter.CheckResize(force);
1071 JSROOT.drawTreePlayer =
function(hpainter, itemname, askey) {
1073 var url = hpainter.GetOnlineItemUrl(itemname);
1074 if (url == null)
return null;
1076 var top = hpainter.GetTopOnlineItem(hpainter.Find(itemname));
1077 if (top == null)
return null;
1078 var root_version = (
'_root_version' in top) ? top._root_version : 336417;
1080 var mdi = hpainter.GetDisplay();
1081 if (mdi == null)
return null;
1083 var frame = mdi.FindFrame(itemname,
true);
1084 if (frame==null)
return null;
1086 var divid = d3.select(frame).attr(
'id');
1088 var player =
new JSROOT.TTreePlayer(itemname, url, askey, root_version);
1093 JSROOT.drawTreePlayerKey =
function(hpainter, itemname) {
1096 return JSROOT.drawTreePlayer(hpainter, itemname,
true);
1102 JSROOT.Painter.separ = null;
1104 JSROOT.Painter.AdjustLayout =
function(left, height, firsttime) {
1105 if (this.separ == null)
return;
1108 var wdiff = $(
"#"+this.separ.left).outerWidth() - $(
"#"+this.separ.left).width();
1110 $(
"#"+this.separ.vertical).css(
'left', left +
"px").width(w).css(
'top',
'1px');
1111 $(
"#"+this.separ.left).width(left-wdiff-1).css(
'top',
'1px');
1112 $(
"#"+this.separ.right).css(
'left',left+w+
"px").css(
'top',
'1px');
1113 if (!this.separ.horizontal) {
1114 $(
"#"+this.separ.vertical).css(
'bottom',
'1px');
1115 $(
"#"+this.separ.left).css(
'bottom',
'1px');
1116 $(
"#"+this.separ.right).css(
'bottom',
'1px');
1120 if ((height!=null) && this.separ.horizontal) {
1121 var diff = $(
"#"+this.separ.bottom).outerHeight() - $(
"#"+this.separ.bottom).height();
1123 if (height<5) height = 5;
1124 var bot = height + diff;
1125 $(
'#'+this.separ.bottom).height(height);
1127 $(
"#"+this.separ.horizontal).css(
'bottom', bot +
'px').height(h);
1129 $(
"#"+this.separ.left).css(
'bottom', bot +
'px');
1132 if (this.separ.horizontal)
1133 if (this.separ.hpart) {
1134 var ww = $(
"#"+this.separ.left).outerWidth() - 2;
1135 $(
'#'+this.separ.bottom).width(ww);
1136 $(
"#"+this.separ.horizontal).width(ww);
1138 var bot = $(
"#"+this.separ.left).css(
'bottom');
1139 $(
"#"+this.separ.vertical).css(
'bottom', bot);
1140 $(
"#"+this.separ.right).css(
'bottom', bot);
1143 if (firsttime || (this.separ.handle==null))
return;
1145 if (typeof this.separ.handle ==
'function') this.separ.handle();
else
1146 if ((typeof this.separ.handle ==
'object') &&
1147 (typeof
this.separ.handle[
'CheckResize'] ==
'function')) this.separ.handle.CheckResize();
1150 JSROOT.Painter.ConfigureVSeparator =
function(handle) {
1152 JSROOT.Painter.separ = { handle: handle, left:
"left-div", right:
"right-div", vertical:
"separator-div",
1153 horizontal : null, bottom : null, hpart:
true };
1155 $(
"#separator-div").addClass(
"separator").draggable({
1156 axis:
"x" , zIndex: 100, cursor:
"ew-resize",
1157 helper :
function() {
return $(
"#separator-div").clone().attr(
'id',
'separator-clone').css(
'background-color',
'grey'); },
1158 stop:
function(event,ui) {
1159 event.stopPropagation();
1160 var left = ui.position.left;
1161 $(
"#separator-clone").
remove();
1162 JSROOT.Painter.AdjustLayout(left, null,
false);
1166 var w0 = Math.round($(window).width() * 0.2);
1167 if (w0<300) w0 = Math.min(300, Math.round($(window).width() * 0.5));
1169 JSROOT.Painter.AdjustLayout(w0, null,
true);
1172 JSROOT.Painter.ConfigureHSeparator =
function(height, onlyleft) {
1174 if ((JSROOT.Painter.separ == null) ||
1175 (JSROOT.Painter.separ.horizontal != null))
return null;
1177 JSROOT.Painter.separ[
'horizontal'] =
'horizontal-separator-div';
1178 JSROOT.Painter.separ[
'bottom'] =
'bottom-div';
1179 JSROOT.Painter.separ.hpart = (onlyleft ===
true);
1181 var prnt = $(
"#"+this.separ.left).parent();
1183 prnt.append(
'<div id="horizontal-separator-div" class="separator" style="left:1px; right:1px; height:4px; bottom:16px; cursor: ns-resize"></div>');
1184 prnt.append(
'<div id="bottom-div" class="column" style="left:1px; right:1px; height:15px; bottom:1px"></div>');
1186 $(
"#horizontal-separator-div").addClass(
"separator").draggable({
1187 axis:
"y" , zIndex: 100, cursor:
"ns-resize",
1188 helper :
function() {
return $(
"#horizontal-separator-div").clone().attr(
'id',
'horizontal-separator-clone').css(
'background-color',
'grey'); },
1189 stop:
function(event,ui) {
1190 event.stopPropagation();
1191 var top = $(window).height() - ui.position.top;
1192 $(
'#horizontal-separator-clone').
remove();
1193 JSROOT.Painter.AdjustLayout(null, top,
false);
1197 JSROOT.Painter.AdjustLayout(null, height,
false);
1199 return JSROOT.Painter.separ.bottom;
1202 return JSROOT.Painter;