5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootCore',
'JSRootIOEvolution',
'JSRootMath'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 factory(require(
"./JSRootCore.js"), require(
"./JSRootIOEvolution.js"), require(
"./JSRootMath.js"));
10 if (typeof JSROOT ==
'undefined')
11 throw new Error(
'JSROOT is not defined',
'JSRootTree.js');
12 if (typeof JSROOT.IO !=
'object')
13 throw new Error(
'JSROOT.IO not defined',
'JSRootTree.js');
20 JSROOT.sources.push(
"tree");
22 JSROOT.BranchType = { kLeafNode: 0, kBaseClassNode: 1, kObjectNode: 2, kClonesNode: 3,
23 kSTLNode: 4, kClonesMemberNode: 31, kSTLMemberNode: 41 };
25 JSROOT.IO.BranchBits = {
26 kDoNotProcess: JSROOT.BIT(10),
27 kIsClone: JSROOT.BIT(11),
28 kBranchObject: JSROOT.BIT(12),
29 kBranchAny: JSROOT.BIT(17),
30 kAutoDelete: JSROOT.BIT(15),
31 kDoNotUseBufferMap: JSROOT.BIT(22)
41 function TSelector() {
45 this.break_execution = 0;
58 TSelector.prototype.AddBranch =
function(branch, name, direct) {
60 name = (typeof branch ===
'string') ? branch : (
"br" + this.branches.length);
61 this.branches.push(branch);
62 this.names.push(name);
63 this.directs.push(direct);
64 return this.branches.length-1;
67 TSelector.prototype.indexOfBranch =
function(branch) {
68 return this.branches.indexOf(branch);
71 TSelector.prototype.nameOfBranch =
function(indx) {
72 return this.names[indx];
75 TSelector.prototype.ShowProgress =
function(value) {
80 TSelector.prototype.Abort =
function() {
81 this.break_execution = -1111;
88 TSelector.prototype.Begin =
function(tree) {
95 TSelector.prototype.Process =
function(entry) {
102 TSelector.prototype.Terminate =
function(res) {
107 JSROOT.CheckArrayPrototype =
function(arr, check_content) {
111 if (typeof arr !==
'object')
return 0;
112 var proto = Object.prototype.toString.apply(arr);
113 if (proto.indexOf(
'[object')!==0)
return 0;
114 var pos = proto.indexOf(
'Array]');
115 if (pos < 0)
return 0;
116 if (pos > 8)
return 2;
118 if (!check_content)
return 1;
119 var typ, plain =
true;
120 for (var k=0;k<arr.length;++k) {
121 var sub = typeof arr[k];
123 if (sub!==typ) { plain =
false;
break; }
124 if ((sub==
"object") && JSROOT.CheckArrayPrototype(arr[k])) { plain =
false;
break; }
127 return plain ? 2 : 1;
130 function ArrayIterator(arr, select, tgtobj) {
138 this.tgtobj = tgtobj;
140 if (typeof select ===
'object')
141 this.select = select;
146 ArrayIterator.prototype.next =
function() {
147 var obj, typ, cnt = this.cnt, seltyp;
151 if (++this.fastindx < this.fastlimit) {
152 this.value = this.fastarr[this.fastindx];
157 if ((this.select[cnt]===undefined) && (++this.indx[cnt] < this.arr[cnt].length))
break;
159 if (cnt < 0)
return false;
164 obj = (cnt < 0) ? this.
object : (this.arr[cnt])[this.indx[cnt]];
166 typ = obj ? typeof obj :
"any";
168 if (typ ===
"object") {
169 if (obj._typename !== undefined) {
170 if (JSROOT.IsRootCollection(obj)) { obj = obj.arr; typ =
"array"; }
172 }
else if (!isNaN(obj.length) && (JSROOT.CheckArrayPrototype(obj)>0)) {
179 if (this.select[cnt+1]==
"$self$") {
181 this.fastindx = this.fastlimit = 0;
186 if ((typ==
"any") && (typeof this.select[cnt+1] ===
"string")) {
188 this.arr[++cnt] = obj;
189 this.indx[cnt] = this.select[cnt];
193 if ((typ ===
"array") && ((obj.length > 0) || (this.select[cnt+1]===
"$size$"))) {
194 this.arr[++cnt] = obj;
195 switch (this.select[cnt]) {
196 case undefined: this.indx[cnt] = 0;
break;
197 case "$last$": this.indx[cnt] = obj.length-1;
break;
199 this.value = obj.length;
200 this.fastindx = this.fastlimit = 0;
205 if (!isNaN(this.select[cnt])) {
206 this.indx[cnt] = this.select[cnt];
207 if (this.indx[cnt] < 0) this.indx[cnt] = obj.length-1;
210 this.select[cnt].Produce(this.tgtobj);
211 this.indx[cnt] = Math.round(this.select[cnt].
get(0));
216 if (cnt<0)
return false;
219 if (this.select[cnt]===undefined) {
220 this.fastarr = this.arr[cnt];
221 this.fastindx = this.indx[cnt];
222 this.fastlimit = this.fastarr.length;
224 this.fastindx = this.fastlimit = 0;
236 ArrayIterator.prototype.reset =
function() {
246 function TDrawVariable(globals) {
248 this.globals = globals;
256 this.kind = undefined;
260 TDrawVariable.prototype.Parse =
function(tree,selector,code,only_branch,branch_mode) {
263 function is_start_symbol(symb) {
264 if ((symb >=
"A") && (symb <=
"Z"))
return true;
265 if ((symb >=
"a") && (symb <=
"z"))
return true;
266 return (symb ===
"_");
269 function is_next_symbol(symb) {
270 if (is_start_symbol(symb))
return true;
271 if ((symb >=
"0") && (symb <=
"9"))
return true;
275 if (!code) code =
"";
277 this.code = (only_branch ? only_branch.fName :
"") + code;
279 var pos = 0, pos2 = 0, br = null;
280 while ((pos < code.length) || only_branch) {
286 only_branch = undefined;
289 while ((pos < code.length) && !is_start_symbol(code[pos])) pos++;
291 while ((pos2 < code.length) && (is_next_symbol(code[pos2]) || code[pos2]===
".")) pos2++;
292 if (code[pos2]==
"$") {
294 switch (code.substr(pos, pos2-pos)) {
296 case "Entry": repl =
"arg.$globals.entry";
break;
297 case "Entries": repl =
"arg.$globals.entries";
break;
300 code = code.substr(0, pos) + repl + code.substr(pos2+1);
301 pos = pos + repl.length;
306 br = tree.FindBranch(code.substr(pos, pos2-pos),
true);
307 if (!br) { pos = pos2+1;
continue; }
310 if (br.branch && (br.rest!==undefined)) {
311 pos2 -= br.rest.length;
312 branch_mode = br.read_mode;
318 if ((pos2>=code.length-1) && (code[code.length-1]===
".")) {
319 arriter.push(
"$self$");
325 while (pos2 < code.length) {
327 if ((code[pos2]===
"@") && (code.substr(pos2,5)==
"@size") && (arriter.length==0)) {
333 if (code[pos2] ===
".") {
337 if ((code[prev]===
"@") && (code.substr(prev,5)===
"@size")) {
338 arriter.push(
"$size$");
343 if (!is_start_symbol(code[prev])) {
344 arriter.push(
"$self$");
348 while ((pos2 < code.length) && is_next_symbol(code[pos2])) pos2++;
351 if (code[pos2]==
"(") { pos2 = prev-1;
break; }
354 if ((arriter.length===0) && br) {
356 if ((br.fType === JSROOT.BranchType.kClonesNode) || (br.fType === JSROOT.BranchType.kSTLNode)) {
357 arriter.push(undefined);
359 var objclass = JSROOT.IO.GetBranchObjectClass(br, tree,
false,
true);
360 if (objclass && JSROOT.IsRootCollection(null, objclass)) arriter.push(undefined);
363 arriter.push(code.substr(prev, pos2-prev));
367 if (code[pos2]!==
"[")
break;
370 if (code[pos2+1]==
"]") { arriter.push(undefined); pos2+=2;
continue; }
372 var prev = pos2++, cnt = 0;
373 while ((pos2 < code.length) && ((code[pos2]!=
"]") || (cnt>0))) {
374 if (code[pos2]==
'[') cnt++;
else if (code[pos2]==
']') cnt--;
377 var sub = code.substr(prev+1, pos2-prev-1);
380 case "$all$": arriter.push(undefined);
break;
381 case "$last$": arriter.push(
"$last$");
break;
382 case "$size$": arriter.push(
"$size$");
break;
383 case "$first$": arriter.push(0);
break;
385 if (!isNaN(parseInt(sub))) {
386 arriter.push(parseInt(sub));
389 var subvar =
new TDrawVariable(this.globals);
390 if (!subvar.Parse(tree,selector, sub))
return false;
391 arriter.push(subvar);
397 if (arriter.length===0) arriter = undefined;
else
398 if ((arriter.length===1) && (arriter[0]===undefined)) arriter =
true;
400 var indx = selector.indexOfBranch(br);
401 if (indx<0) indx = selector.AddBranch(br, undefined, branch_mode);
403 branch_mode = undefined;
405 this.brindex.push(indx);
406 this.branches.push(selector.nameOfBranch(indx));
407 this.brarray.push(arriter);
410 if ((pos===0) && (pos2 === code.length) && (
this.branches.length===1)) {
411 this.direct_branch =
true;
415 var replace =
"arg.var" + (this.branches.length-1);
417 code = code.substr(0, pos) + replace + code.substr(pos2);
419 pos = pos + replace.length;
423 code = code.replace(/TMath::Exp\(/g,
'Math.exp(')
424 .replace(/TMath::Abs\(/g,
'Math.abs(')
425 .replace(/TMath::Prob\(/g,
'arg.$math.Prob(')
426 .replace(/TMath::Gaus\(/g,
'arg.$math.Gaus(');
428 this.func =
new Function(
"arg",
"return (" + code +
")");
433 TDrawVariable.prototype.is_dummy =
function() {
434 return (this.branches.length === 0) && !this.func;
437 TDrawVariable.prototype.Produce =
function(obj) {
441 this.isarray =
false;
443 if (this.is_dummy()) {
445 this.kind =
"number";
449 var arg = { $globals: this.globals, $math: JSROOT.Math }, usearrlen = -1, arrs = [];
450 for (var n=0;n<this.branches.length;++n) {
451 var name =
"var" + n;
452 arg[name] = obj[this.branches[n]];
455 if (this.brarray[n]===undefined)
456 this.brarray[n] = (JSROOT.CheckArrayPrototype(arg[name]) > 0) || JSROOT.IsRootCollection(arg[name]);
459 if (this.brarray[n]===
false)
continue;
462 if ((this.brarray[n]===
true) && (JSROOT.CheckArrayPrototype(arg[name],
true) === 2)) {
466 var iter =
new ArrayIterator(arg[name], this.brarray[n], obj);
468 while (iter.next()) arrs[n].push(iter.value);
470 if ((usearrlen < 0) || (usearrlen < arrs[n].length)) usearrlen = arrs[n].length;
474 this.value = this.direct_branch ? arg.var0 : this.func(arg);
475 if (!this.kind) this.kind = typeof this.value;
479 if (usearrlen == 0) {
486 this.length = usearrlen;
489 if (this.direct_branch) {
490 this.value = arrs[0];
492 this.value =
new Array(usearrlen);
494 for (var k=0;k<usearrlen;++k) {
495 for (var n=0;n<this.branches.length;++n) {
496 if (arrs[n]) arg[
"var"+n] = arrs[n][k];
498 this.value[k] = this.func(arg);
502 if (!this.kind) this.kind = typeof this.value[0];
505 TDrawVariable.prototype.get =
function(indx) {
506 return this.isarray ? this.value[indx] : this.value;
509 TDrawVariable.prototype.AppendArray =
function(tgtarr) {
512 this.buf = this.buf.concat(tgtarr[this.branches[0]]);
524 function TDrawSelector(callback) {
525 TSelector.call(
this);
531 this.histo_callback = callback;
532 this.histo_drawopt =
"";
533 this.hist_name =
"$htemp";
534 this.hist_title =
"Result of TTree::Draw";
537 this.arr_limit = 1000;
541 this.last_progress = 0;
545 TDrawSelector.prototype = Object.create(TSelector.prototype);
547 TDrawSelector.prototype.ParseParameters =
function(tree, args, expr) {
549 if (!expr || (typeof expr !==
"string"))
return "";
552 var pos = expr.lastIndexOf(
";");
554 var parname = expr.substr(pos+1), parvalue = undefined;
555 expr = expr.substr(0,pos);
556 pos = expr.lastIndexOf(
";");
558 var separ = parname.indexOf(
":");
559 if (separ>0) { parvalue = parname.substr(separ+1); parname = parname.substr(0, separ); }
561 var intvalue = parseInt(parvalue);
562 if (!parvalue || isNaN(intvalue)) intvalue = undefined;
568 if (parvalue===
"all") args.numentries = tree.fEntries;
else
569 if (parvalue===
"half") args.numentries = Math.round(tree.fEntries/2);
else
570 if (intvalue !== undefined) args.numentries = intvalue;
573 if (intvalue !== undefined) args.firstentry = intvalue;
577 args.monitoring = (intvalue !== undefined) ? intvalue : 5000;
587 if (intvalue) tree.$file.fMaxRanges = intvalue;
590 if (intvalue) this.arr_limit = intvalue;
593 if (parvalue && (parvalue.length===1)) {
594 this.htype = parvalue.toUpperCase();
595 if ((this.htype!==
"C") && (this.htype!==
"S") && (this.htype!==
"I")
596 && (this.htype!==
"F") && (this.htype!==
"L") && (this.htype!==
"D")) this.htype =
"F";
600 this.hist_nbins = parseInt(parvalue);
601 if (isNaN(this.hist_nbins) || (this.hist_nbins<=3))
delete this.hist_nbins;
604 args.drawopt = parvalue;
607 args.graph = intvalue ||
true;
612 pos = expr.lastIndexOf(
">>");
614 var harg = expr.substr(pos+2).trim();
615 expr = expr.substr(0,pos).trim();
616 pos = harg.indexOf(
"(");
618 this.hist_name = harg.substr(0, pos);
619 harg = harg.substr(pos);
621 if (harg ===
"dump") {
623 }
else if (harg.indexOf(
"Graph") == 0) {
626 this.hist_name = harg;
627 }
else if ((harg[0]==
"(") && (harg[harg.length-1]==
")")) {
628 harg = harg.substr(1,harg.length-2).split(
",");
630 for (var n=0;n<harg.length;++n) {
631 harg[n] = (n%3===0) ? parseInt(harg[n]) : parseFloat(harg[n]);
632 if (isNaN(harg[n])) isok =
false;
634 if (isok) this.hist_args = harg;
639 this.dump_values =
true;
640 args.reallocate_objects =
true;
641 if (args.numentries===undefined) args.numentries = 10;
647 TDrawSelector.prototype.ParseDrawExpression =
function(tree, args) {
650 var expr = this.ParseParameters(tree, args, args.expr), cut =
"";
653 this.hist_title =
"drawing '" + expr +
"' from " + tree.fName;
659 pos = expr.replace(/TMath::/g,
'TMath__').lastIndexOf(
"::");
661 cut = expr.substr(pos+2).trim();
662 expr = expr.substr(0,pos).trim();
666 args.parse_expr = expr;
667 args.parse_cut = cut;
670 var names = [], nbr1 = 0, nbr2 = 0, prev = 0;
671 for (pos=0; pos < expr.length; ++pos) {
673 case "(" : nbr1++;
break;
674 case ")" : nbr1--;
break;
675 case "[" : nbr2++;
break;
676 case "]" : nbr2--;
break;
678 if (expr[pos+1]==
":") { pos++;
continue; }
679 if (!nbr1 && !nbr2 && (pos>prev)) names.push(expr.substr(prev,pos-prev));
684 if (!nbr1 && !nbr2 && (pos>prev)) names.push(expr.substr(prev,pos-prev));
686 if ((names.length < 1) || (names.length > 3))
return false;
688 this.ndim = names.length;
690 var is_direct = !cut;
692 for (var n=0;n<this.ndim;++n) {
693 this.vars[n] =
new TDrawVariable(this.globals);
694 if (!this.vars[n].Parse(tree,
this, names[n]))
return false;
695 if (!this.vars[n].direct_branch) is_direct =
false;
698 this.cut =
new TDrawVariable(this.globals);
700 if (!this.cut.Parse(tree,
this, cut))
return false;
702 if (!this.branches.length) {
703 console.warn(
'no any branch is selected');
707 if (is_direct) this.ProcessArrays = this.ProcessArraysFunc;
709 this.monitoring = args.monitoring;
711 this.graph = args.graph;
713 if (args.drawopt !== undefined)
714 this.histo_drawopt = args.drawopt;
716 this.histo_drawopt = (this.ndim===2) ?
"col" :
"";
721 TDrawSelector.prototype.DrawOnlyBranch =
function(tree, branch, expr, args) {
724 if (expr.indexOf(
"dump")==0) expr =
";" + expr;
726 expr = this.ParseParameters(tree, args, expr);
728 this.monitoring = args.monitoring;
731 this.dump_values =
true;
732 args.reallocate_objects =
true;
735 if (this.dump_values) {
739 this.leaf = args.leaf;
742 this.copy_fields = ((args.branch.fLeaves && (args.branch.fLeaves.arr.length > 1)) ||
743 (args.branch.fBranches && (args.branch.fBranches.arr.length > 0))) && !args.leaf;
745 this.AddBranch(branch,
"br0", args.direct_branch);
747 this.Process = this.ProcessDump;
752 this.vars[0] =
new TDrawVariable(this.globals);
753 if (!this.vars[0].Parse(tree,
this, expr, branch, args.direct_branch))
return false;
754 this.hist_title =
"drawing branch '" + branch.fName + (expr ?
"' expr:'" + expr :
"") +
"' from " + tree.fName;
756 this.cut =
new TDrawVariable(this.globals);
758 if (this.vars[0].direct_branch) this.ProcessArrays = this.ProcessArraysFunc;
763 TDrawSelector.prototype.Begin =
function(tree) {
764 this.globals.entries = tree.fEntries;
767 this.lasttm =
new Date().getTime();
770 TDrawSelector.prototype.ShowProgress =
function(value) {
773 if (typeof document ==
'undefined' || !JSROOT.progress)
return;
775 if ((value===undefined) || isNaN(value))
return JSROOT.progress();
777 if (this.last_progress !== value) {
778 var diff = value - this.last_progress;
779 if (!this.aver_diff) this.aver_diff = diff;
780 this.aver_diff = diff*0.3 + this.aver_diff*0.7;
784 if (this.aver_diff <= 0) ndig = 0;
else
785 if (this.aver_diff < 0.0001) ndig = 3;
else
786 if (this.aver_diff < 0.001) ndig = 2;
else
787 if (this.aver_diff < 0.01) ndig = 1;
789 var main_box = document.createElement(
"p"),
790 text_node = document.createTextNode(
"TTree draw " + (value*100).toFixed(ndig) +
" % "),
793 main_box.appendChild(text_node);
794 main_box.title =
"Click on element to break drawing";
796 main_box.onclick =
function() {
797 if (++selector.break_execution<3) {
798 main_box.title =
"Tree draw will break after next I/O operation";
799 return text_node.nodeValue =
"Breaking ... ";
805 JSROOT.progress(main_box);
806 this.last_progress = value;
809 TDrawSelector.prototype.GetBitsBins =
function(nbits, res) {
810 res.nbins = res.max = nbits;
811 res.fLabels = JSROOT.Create(
"THashList");
812 for (var k=0;k<nbits;++k) {
813 var s = JSROOT.Create(
"TObjString");
814 s.fString = k.toString();
821 TDrawSelector.prototype.GetMinMaxBins =
function(axisid, nbins) {
823 var res = { min: 0, max: 0, nbins: nbins, k: 1., fLabels: null, title:
"" };
825 if (axisid >= this.ndim)
return res;
827 var arr = this.vars[axisid].buf;
829 res.title = this.vars[axisid].code ||
"";
831 if (this.vars[axisid].kind ===
"object") {
833 var
typename, similar =
true, maxbits = 8;
834 for (var k=0;k<arr.length;++k) {
835 if (!arr[k])
continue;
836 if (!
typename)
typename = arr[k]._typename;
837 if (
typename !== arr[k]._typename) similar =
false;
838 if (arr[k].fNbits) maxbits = Math.max(maxbits, arr[k].fNbits+1);
841 if (
typename && similar) {
842 if ((
typename===
"TBits") && (axisid===0)) {
843 this.Fill1DHistogram = this.FillTBitsHistogram;
844 if (maxbits % 8) maxbits = (maxbits & 0xfff0) + 8;
846 if ((this.hist_name ===
"bits") && (this.hist_args.length == 1) && this.hist_args[0])
847 maxbits = this.hist_args[0];
849 return this.GetBitsBins(maxbits, res);
854 if (this.vars[axisid].kind ===
"string") {
857 for (var k=0;k<arr.length;++k)
858 if (res.lbls.indexOf(arr[k])<0)
859 res.lbls.push(arr[k]);
862 res.max = res.nbins = res.lbls.length;
864 res.fLabels = JSROOT.Create(
"THashList");
865 for (var k=0;k<res.lbls.length;++k) {
866 var s = JSROOT.Create(
"TObjString");
867 s.fString = res.lbls[k];
869 if (s.fString ===
"") s.fString =
"<empty>";
872 }
else if ((axisid === 0) && (this.hist_name ===
"bits") && (this.hist_args.length <= 1)) {
873 this.Fill1DHistogram = this.FillBitsHistogram;
874 return this.GetBitsBins(this.hist_args[0] || 32, res);
875 }
else if (axisid*3 + 2 < this.hist_args.length) {
876 res.nbins = this.hist_args[axisid*3];
877 res.min = this.hist_args[axisid*3+1];
878 res.max = this.hist_args[axisid*3+2];
883 res.min = Math.min.apply(null, arr);
884 res.max = Math.max.apply(null, arr);
887 nbins = res.nbins = this.hist_nbins;
889 res.isinteger = (Math.round(res.min)===res.min) && (Math.round(res.max)===res.max);
891 for (var k=0;k<arr.length;++k)
892 if (arr[k]!==Math.round(arr[k])) { res.isinteger =
false;
break; }
895 res.min = Math.round(res.min);
896 res.max = Math.round(res.max);
897 if (res.max-res.min < nbins*5) {
900 res.nbins = Math.round(res.max - res.min);
902 var range = (res.max - res.min + 2), step = Math.floor(range / nbins);
903 while (step*nbins < range) step++;
904 res.max = res.min + nbins*step;
907 if (res.min >= res.max) {
909 if (Math.abs(res.min)<100) { res.min-=1; res.max+=1; }
else
910 if (res.min>0) { res.min*=0.9; res.max*=1.1; }
else { res.min*=1.1; res.max*=0.9; }
912 res.max += (res.max-res.min)/res.nbins;
916 res.k = res.nbins/(res.max-res.min);
918 res.GetBin =
function(value) {
919 var bin = this.lbls ? this.lbls.indexOf(value) : Math.floor((value-this.min)*this.k);
920 return (bin<0) ? 0 : ((bin>this.nbins) ? this.nbins+1 : bin+1);
926 TDrawSelector.prototype.CreateHistogram =
function() {
927 if (this.hist || !this.vars[0].buf)
return;
929 if (this.dump_values) {
934 this.Fill1DHistogram = this.Fill2DHistogram = this.Fill3DHistogram = this.DumpValue;
935 }
else if (this.graph) {
936 var N = this.vars[0].buf.length;
940 this.hist = JSROOT.CreateTGraph(N, Array.from(Array(N).keys()), this.vars[0].buf);
941 }
else if(this.ndim == 2) {
942 this.hist = JSROOT.CreateTGraph(N,this.vars[0].buf, this.vars[1].buf);
943 delete this.vars[1].buf;
946 this.hist.fTitle = this.hist_title;
947 this.hist.fName =
"Graph";
951 this.x = this.GetMinMaxBins(0, (this.ndim > 1) ? 50 : 200);
953 this.y = this.GetMinMaxBins(1, 50);
955 this.z = this.GetMinMaxBins(2, 50);
958 case 1: this.hist = JSROOT.CreateHistogram(
"TH1"+this.htype, this.x.nbins);
break;
959 case 2: this.hist = JSROOT.CreateHistogram(
"TH2"+this.htype, this.x.nbins,
this.y.nbins);
break;
960 case 3: this.hist = JSROOT.CreateHistogram(
"TH3"+this.htype, this.x.nbins,
this.y.nbins,
this.z.nbins);
break;
963 this.hist.fXaxis.fTitle = this.x.title;
964 this.hist.fXaxis.fXmin = this.x.min;
965 this.hist.fXaxis.fXmax = this.x.max;
966 this.hist.fXaxis.fLabels = this.x.fLabels;
968 if (this.ndim > 1) this.hist.fYaxis.fTitle = this.y.title;
969 this.hist.fYaxis.fXmin = this.y.min;
970 this.hist.fYaxis.fXmax = this.y.max;
971 this.hist.fYaxis.fLabels = this.y.fLabels;
973 if (this.ndim > 2) this.hist.fZaxis.fTitle = this.z.title;
974 this.hist.fZaxis.fXmin = this.z.min;
975 this.hist.fZaxis.fXmax = this.z.max;
976 this.hist.fZaxis.fLabels = this.z.fLabels;
978 this.hist.fName = this.hist_name;
979 this.hist.fTitle = this.hist_title;
980 this.hist.$custom_stat = (this.hist_name ==
"$htemp") ? 111110 : 111111;
983 var var0 = this.vars[0].buf, cut = this.cut.buf, len = var0.length;
988 for (var n=0;n<len;++n)
989 this.Fill1DHistogram(var0[n], cut ? cut[n] : 1.);
992 var var1 = this.vars[1].buf;
993 for (var n=0;n<len;++n)
994 this.Fill2DHistogram(var0[n], var1[n], cut ? cut[n] : 1.);
995 delete this.vars[1].buf;
998 var var1 = this.vars[1].buf, var2 = this.vars[2].buf;
999 for (var n=0;n<len;++n)
1000 this.Fill3DHistogram(var0[n], var1[n], var2[n], cut ? cut[n] : 1.);
1001 delete this.vars[1].buf;
1002 delete this.vars[2].buf;
1007 delete this.vars[0].buf;
1008 delete this.cut.buf;
1011 TDrawSelector.prototype.FillTBitsHistogram =
function(xvalue, weight) {
1012 if (!weight || !xvalue || !xvalue.fNbits || !xvalue.fAllBits)
return;
1014 var sz = Math.min(xvalue.fNbits+1, xvalue.fNbytes*8);
1016 for (var bit=0,mask=1,b=0;bit<sz;++bit) {
1017 if (xvalue.fAllBits[b] && mask) {
1018 if (bit <= this.x.nbins)
1019 this.hist.fArray[bit+1] += weight;
1021 this.hist.fArray[this.x.nbins+1] += weight;
1025 if (mask>=0x100) { mask = 1; ++b; }
1029 TDrawSelector.prototype.FillBitsHistogram =
function(xvalue, weight) {
1030 if (!weight)
return;
1032 for (var bit=0,mask=1;bit<this.x.nbins;++bit) {
1033 if (xvalue & mask) this.hist.fArray[bit+1] += weight;
1038 TDrawSelector.prototype.Fill1DHistogram =
function(xvalue, weight) {
1039 var bin = this.x.GetBin(xvalue);
1040 this.hist.fArray[bin] += weight;
1043 this.hist.fTsumw += weight;
1044 this.hist.fTsumwx += weight*xvalue;
1045 this.hist.fTsumwx2 += weight*xvalue*xvalue;
1049 TDrawSelector.prototype.Fill2DHistogram =
function(xvalue, yvalue, weight) {
1050 var xbin = this.x.GetBin(xvalue),
1051 ybin = this.y.GetBin(yvalue);
1053 this.hist.fArray[xbin+(this.x.nbins+2)*ybin] += weight;
1054 if (!this.x.lbls && !
this.y.lbls) {
1055 this.hist.fTsumw += weight;
1056 this.hist.fTsumwx += weight*xvalue;
1057 this.hist.fTsumwy += weight*yvalue;
1058 this.hist.fTsumwx2 += weight*xvalue*xvalue;
1059 this.hist.fTsumwxy += weight*xvalue*yvalue;
1060 this.hist.fTsumwy2 += weight*yvalue*yvalue;
1064 TDrawSelector.prototype.Fill3DHistogram =
function(xvalue, yvalue, zvalue, weight) {
1065 var xbin = this.x.GetBin(xvalue),
1066 ybin = this.y.GetBin(yvalue),
1067 zbin = this.z.GetBin(zvalue);
1069 this.hist.fArray[xbin + (this.x.nbins+2) * (ybin + (this.y.nbins+2)*zbin) ] += weight;
1070 if (!this.x.lbls && !
this.y.lbls && !
this.z.lbls) {
1071 this.hist.fTsumw += weight;
1072 this.hist.fTsumwx += weight*xvalue;
1073 this.hist.fTsumwy += weight*yvalue;
1074 this.hist.fTsumwz += weight*zvalue;
1075 this.hist.fTsumwx2 += weight*xvalue*xvalue;
1076 this.hist.fTsumwy2 += weight*yvalue*yvalue;
1077 this.hist.fTsumwz2 += weight*zvalue*zvalue;
1078 this.hist.fTsumwxy += weight*xvalue*yvalue;
1079 this.hist.fTsumwxz += weight*xvalue*zvalue;
1080 this.hist.fTsumwyz += weight*yvalue*zvalue;
1084 TDrawSelector.prototype.DumpValue =
function(v1, v2, v3, v4) {
1086 switch (this.ndim) {
1087 case 1: obj = { x: v1, weight: v2 };
break;
1088 case 2: obj = { x: v1, y: v2, weight: v3 };
break;
1089 case 3: obj = { x: v1, y: v2, z: v3, weight: v4 };
break;
1092 if (this.cut.is_dummy()) {
1093 if (this.ndim===1) obj = v1;
else delete obj.weight;
1096 this.hist.push(obj);
1099 TDrawSelector.prototype.ProcessArraysFunc =
function(entry) {
1103 if (this.arr_limit || this.graph) {
1104 var var0 = this.vars[0], len = this.tgtarr.br0.length,
1105 var1 = this.vars[1], var2 = this.vars[2];
1106 if ((var0.buf.length===0) && (len>=this.arr_limit) && !this.graph) {
1108 var0.buf = this.tgtarr.br0;
1109 if (var1) var1.buf = this.tgtarr.br1;
1110 if (var2) var2.buf = this.tgtarr.br2;
1112 for (var k=0;k<len;++k) {
1113 var0.buf.push(this.tgtarr.br0[k]);
1114 if (var1) var1.buf.push(this.tgtarr.br1[k]);
1115 if (var2) var2.buf.push(this.tgtarr.br2[k]);
1117 var0.kind =
"number";
1118 if (var1) var1.kind =
"number";
1119 if (var2) var2.kind =
"number";
1120 this.cut.buf = null;
1121 if (!this.graph && (var0.buf.length >=
this.arr_limit)) {
1122 this.CreateHistogram();
1126 var br0 = this.tgtarr.br0, len = br0.length;
1129 for (var k=0;k<len;++k)
1130 this.Fill1DHistogram(br0[k], 1.);
1133 var br1 = this.tgtarr.br1;
1134 for (var k=0;k<len;++k)
1135 this.Fill2DHistogram(br0[k], br1[k], 1.);
1138 var br1 = this.tgtarr.br1, br2 = this.tgtarr.br2;
1139 for (var k=0;k<len;++k)
1140 this.Fill3DHistogram(br0[k], br1[k], br2[k], 1.);
1146 TDrawSelector.prototype.ProcessDump =
function(entry) {
1149 var res = this.leaf ? this.tgtobj.br0[this.leaf] : this.tgtobj.br0;
1151 if (res && this.copy_fields) {
1152 if (JSROOT.CheckArrayPrototype(res)===0) {
1153 this.hist.push(JSROOT.extend({}, res));
1155 this.hist.push(res);
1158 this.hist.push(res);
1162 TDrawSelector.prototype.Process =
function(entry) {
1164 this.globals.entry = entry;
1166 this.cut.Produce(this.tgtobj);
1167 if (!this.dump_values && !this.cut.value)
return;
1169 for (var n=0;n<this.ndim;++n)
1170 this.vars[n].Produce(this.tgtobj);
1172 var var0 = this.vars[0], var1 = this.vars[1], var2 = this.vars[2], cut = this.cut;
1174 if (this.graph || this.arr_limit) {
1177 for (var n0=0;n0<var0.length;++n0) {
1178 var0.buf.push(var0.get(n0));
1179 cut.buf.push(cut.value);
1183 for (var n0=0;n0<var0.length;++n0)
1184 for (var n1=0;n1<var1.length;++n1) {
1185 var0.buf.push(var0.get(n0));
1186 var1.buf.push(var1.get(n1));
1187 cut.buf.push(cut.value);
1191 for (var n0=0;n0<var0.length;++n0)
1192 for (var n1=0;n1<var1.length;++n1)
1193 for (var n2=0;n2<var2.length;++n2) {
1194 var0.buf.push(var0.get(n0));
1195 var1.buf.push(var1.get(n1));
1196 var2.buf.push(var2.get(n2));
1197 cut.buf.push(cut.value);
1201 if (!this.graph && var0.buf.length >=
this.arr_limit) {
1202 this.CreateHistogram();
1205 }
else if (this.hist) {
1208 for (var n0=0;n0<var0.length;++n0)
1209 this.Fill1DHistogram(var0.get(n0), cut.value);
1212 for (var n0=0;n0<var0.length;++n0)
1213 for (var n1=0;n1<var1.length;++n1)
1214 this.Fill2DHistogram(var0.get(n0), var1.get(n1), cut.value);
1217 for (var n0=0;n0<var0.length;++n0)
1218 for (var n1=0;n1<var1.length;++n1)
1219 for (var n2=0;n2<var2.length;++n2)
1220 this.Fill3DHistogram(var0.get(n0), var1.get(n1), var2.get(n2), cut.value);
1225 if (this.monitoring && this.hist && !this.dump_values) {
1226 var now =
new Date().getTime();
1227 if (now - this.lasttm > this.monitoring) {
1229 JSROOT.CallBack(this.histo_callback, this.hist, this.histo_drawopt,
true);
1234 TDrawSelector.prototype.Terminate =
function(res) {
1235 if (res && !this.hist) this.CreateHistogram();
1237 this.ShowProgress();
1239 return JSROOT.CallBack(this.histo_callback, this.hist, this.dump_values ?
"inspect" : this.histo_drawopt);
1244 JSROOT.IO.FindBrachStreamerElement =
function(branch, file) {
1248 if (!branch || !file || (branch._typename!==
"TBranchElement") || (branch.fID<0) || (branch.fStreamerType<0))
return null;
1250 var s_i = file.FindStreamerInfo(branch.fClassName, branch.fClassVersion, branch.fCheckSum),
1251 arr = (s_i && s_i.fElements) ? s_i.fElements.arr : null;
1252 if (!arr)
return null;
1254 var match_name = branch.fName,
1255 pos = match_name.indexOf(
"[");
1256 if (pos>0) match_name = match_name.substr(0, pos);
1257 pos = match_name.lastIndexOf(
".");
1258 if (pos>0) match_name = match_name.substr(pos+1);
1260 function match_elem(elem) {
1261 if (!elem)
return false;
1262 if (elem.fName !== match_name)
return false;
1263 if (elem.fType === branch.fStreamerType)
return true;
1264 if ((elem.fType === JSROOT.IO.kBool) && (branch.fStreamerType === JSROOT.IO.kUChar))
return true;
1265 if (((branch.fStreamerType===JSROOT.IO.kSTL) || (branch.fStreamerType===JSROOT.IO.kSTL + JSROOT.IO.kOffsetL) ||
1266 (branch.fStreamerType===JSROOT.IO.kSTLp) || (branch.fStreamerType===JSROOT.IO.kSTLp + JSROOT.IO.kOffsetL))
1267 && (elem.fType === JSROOT.IO.kStreamer))
return true;
1268 console.warn(
'Should match element', elem.fType,
'with branch', branch.fStreamerType);
1273 if (match_elem(arr[branch.fID]))
return arr[branch.fID];
1277 for (var k=0;k<arr.length;++k)
1278 if ((k!==branch.fID) && match_elem(arr[k]))
return arr[k];
1280 console.error(
'Did not found/match element for branch', branch.fName,
'class', branch.fClassName);
1286 JSROOT.IO.DefineMemberTypeName =
function(file, parent_class, member_name) {
1289 var s_i = file.FindStreamerInfo(parent_class),
1290 arr = (s_i && s_i.fElements) ? s_i.fElements.arr : null,
1292 if (!arr)
return "";
1294 for (var k=0;k<arr.length;++k) {
1295 if (arr[k].fTypeName ===
"BASE") {
1296 var res = JSROOT.IO.DefineMemberTypeName(file, arr[k].fName, member_name);
1297 if (res)
return res;
1299 if (arr[k].fName === member_name) { elem = arr[k];
break; }
1302 if (!elem)
return "";
1304 var clname = elem.fTypeName;
1305 if (clname[clname.length-1]===
"*") clname = clname.substr(0, clname.length-1);
1310 JSROOT.IO.GetBranchObjectClass =
function(branch, tree, with_clones, with_leafs) {
1313 if (!branch || (branch._typename!==
"TBranchElement"))
return "";
1315 if ((branch.fType === JSROOT.BranchType.kLeafNode) && (branch.fID===-2) && (branch.fStreamerType===-1)) {
1317 return branch.fClassName;
1320 if (with_clones && branch.fClonesName && ((branch.fType === JSROOT.BranchType.kClonesNode) || (branch.fType === JSROOT.BranchType.kSTLNode)))
1321 return branch.fClonesName;
1323 var s_elem = JSROOT.IO.FindBrachStreamerElement(branch, tree.$file);
1325 if ((branch.fType === JSROOT.BranchType.kBaseClassNode) && s_elem && (s_elem.fTypeName===
"BASE"))
1326 return s_elem.fName;
1328 if (branch.fType === JSROOT.BranchType.kObjectNode) {
1329 if (s_elem && ((s_elem.fType === JSROOT.IO.kObject) || (s_elem.fType === JSROOT.IO.kAny)))
1330 return s_elem.fTypeName;
1334 if ((branch.fType === JSROOT.BranchType.kLeafNode) && s_elem && with_leafs) {
1335 if ((s_elem.fType === JSROOT.IO.kObject) || (s_elem.fType === JSROOT.IO.kAny))
return s_elem.fTypeName;
1336 if (s_elem.fType === JSROOT.IO.kObjectp)
return s_elem.fTypeName.substr(0, s_elem.fTypeName.length-1);
1342 JSROOT.IO.MakeMethodsList =
function(
typename) {
1345 var methods = JSROOT.getMethods(
typename);
1350 Create :
function() {
1352 for (var n=0;n<this.names.length;++n)
1353 obj[this.names[n]] = this.values[n];
1358 res.names.push(
"_typename"); res.values.push(
typename);
1359 for (var key in methods) {
1360 res.names.push(key);
1361 res.values.push(methods[key]);
1366 JSROOT.IO.DetectBranchMemberClass =
function(brlst, prefix, start) {
1369 for (var kk=(start || 0); kk<brlst.arr.length; ++kk)
1370 if ((brlst.arr[kk].fName.indexOf(prefix)===0) && brlst.arr[kk].fClassName) clname = brlst.arr[kk].fClassName;
1376 JSROOT.TreeMethods = {};
1381 JSROOT.TreeMethods.Process =
function(selector, args) {
1384 if (!args) args = {};
1386 if (!selector || !this.$file || !selector.branches) {
1387 console.error(
'required parameter missing for TTree::Process');
1388 if (selector) selector.Terminate(
false);
1401 process_arrays:
true
1406 function CreateLeafElem(leaf, name) {
1409 switch (leaf._typename) {
1410 case 'TLeafF': datakind = JSROOT.IO.kFloat;
break;
1411 case 'TLeafD': datakind = JSROOT.IO.kDouble;
break;
1412 case 'TLeafO': datakind = JSROOT.IO.kBool;
break;
1413 case 'TLeafB': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUChar : JSROOT.IO.kChar;
break;
1414 case 'TLeafS': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUShort : JSROOT.IO.kShort;
break;
1415 case 'TLeafI': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUInt : JSROOT.IO.kInt;
break;
1416 case 'TLeafL': datakind = leaf.fIsUnsigned ? JSROOT.IO.kULong64 : JSROOT.IO.kLong64;
break;
1417 case 'TLeafC': datakind = JSROOT.IO.kTString;
break;
1418 default:
return null;
1420 return JSROOT.IO.CreateStreamerElement(name || leaf.fName, datakind);
1423 function FindInHandle(branch) {
1424 for (var k=0;k<handle.arr.length;++k)
1425 if (handle.arr[k].branch === branch)
return handle.arr[k];
1429 function AddBranchForReading(branch, target_object, target_name, read_mode) {
1436 if (typeof branch ===
'string')
1437 branch = handle.tree.FindBranch(branch);
1439 if (!branch) { console.error(
'Did not found branch');
return null; }
1441 var item = FindInHandle(branch);
1444 console.error(
'Branch already configured for reading', branch.fName);
1445 if (item.tgt !== target_object) console.error(
'Target object differs');
1449 if (!branch.fEntries) {
1450 console.warn(
'Branch ', branch.fName,
' does not have entries');
1469 first_readentry: -1,
1471 numentries: branch.fEntries,
1472 numbaskets: branch.fWriteBasket,
1479 GetBasketEntry:
function(k) {
1480 if (!this.branch || (k > this.branch.fMaxBaskets))
return 0;
1481 var res = (k < this.branch.fMaxBaskets) ? this.branch.fBasketEntry[k] : 0;
1482 if (res)
return res;
1483 var bskt = (k>0) ? this.branch.fBaskets.arr[k-1] : null;
1484 return bskt ? (
this.branch.fBasketEntry[k-1] + bskt.fNevBuf) : 0;
1486 GetTarget:
function(tgtobj) {
1488 if (!this.tgt)
return tgtobj;
1489 for (var k=0;k<this.tgt.length;++k) {
1490 var sub = this.tgt[k];
1491 if (!tgtobj[sub.name]) tgtobj[sub.name] = sub.lst.Create();
1492 tgtobj = tgtobj[sub.name];
1496 GetEntry:
function(entry) {
1498 var shift = entry - this.first_entry, off;
1499 if (!this.branch.TestBit(JSROOT.IO.BranchBits.kDoNotUseBufferMap))
1500 this.raw.ClearObjectMap();
1501 if (this.basket.fEntryOffset) {
1502 off = this.basket.fEntryOffset[shift];
1503 if (this.basket.fDisplacement)
1504 this.raw.fDisplacement = this.basket.fDisplacement[shift];
1506 off = this.basket.fKeylen + this.basket.fNevBufSize * shift;
1508 this.raw.locate(off - this.raw.raw_shift);
1515 while (item.GetBasketEntry(item.numbaskets+1)) item.numbaskets++;
1518 var nb_branches = branch.fBranches ? branch.fBranches.arr.length : 0,
1519 nb_leaves = branch.fLeaves ? branch.fLeaves.arr.length : 0,
1520 leaf = (nb_leaves>0) ? branch.fLeaves.arr[0] : null,
1523 is_brelem = (branch._typename===
"TBranchElement"),
1525 item_cnt = null, item_cnt2 = null, object_class =
"";
1527 if (branch.fBranchCount) {
1529 item_cnt = FindInHandle(branch.fBranchCount);
1532 item_cnt = AddBranchForReading(branch.fBranchCount, target_object,
"$counter" + namecnt++,
true);
1534 if (!item_cnt) { console.error(
'Cannot add counter branch', branch.fBranchCount.fName);
return null; }
1536 var BranchCount2 = branch.fBranchCount2;
1538 if (!BranchCount2 && (branch.fBranchCount.fStreamerType===JSROOT.IO.kSTL) &&
1539 ((branch.fStreamerType === JSROOT.IO.kStreamLoop) || (branch.fStreamerType === JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop))) {
1541 var elemd = JSROOT.IO.FindBrachStreamerElement(branch, handle.file),
1542 arrd = branch.fBranchCount.fBranches.arr;
1544 if (elemd && elemd.fCountName && arrd)
1545 for(var k=0;k<arrd.length;++k)
1546 if (arrd[k].fName === branch.fBranchCount.fName +
"." + elemd.fCountName) {
1547 BranchCount2 = arrd[k];
1551 if (!BranchCount2) console.error(
'Did not found branch for second counter of kStreamLoop element');
1555 item_cnt2 = FindInHandle(BranchCount2);
1557 if (!item_cnt2) item_cnt2 = AddBranchForReading(BranchCount2, target_object,
"$counter" + namecnt++,
true);
1559 if (!item_cnt2) { console.error(
'Cannot add counter branch2', BranchCount2.fName);
return null; }
1562 if (nb_leaves===1 && leaf && leaf.fLeafCount) {
1563 var br_cnt = handle.tree.FindBranch(leaf.fLeafCount.fName);
1566 item_cnt = FindInHandle(br_cnt);
1568 if (!item_cnt) item_cnt = AddBranchForReading(br_cnt, target_object,
"$counter" + namecnt++,
true);
1570 if (!item_cnt) { console.error(
'Cannot add counter branch', br_cnt.fName);
return null; }
1574 function ScanBranches(lst, master_target, chld_kind) {
1575 if (!lst || !lst.arr.length)
return true;
1577 var match_prefix = branch.fName;
1578 if (match_prefix[match_prefix.length-1] ===
".") match_prefix = match_prefix.substr(0,match_prefix.length-1);
1579 if ((typeof read_mode===
"string") && (read_mode[0]==
".")) match_prefix += read_mode;
1582 for (var k=0;k<lst.arr.length;++k) {
1583 var br = lst.arr[k];
1584 if ((chld_kind>0) && (br.fType!==chld_kind))
continue;
1586 if (br.fType === JSROOT.BranchType.kBaseClassNode) {
1587 if (!ScanBranches(br.fBranches, master_target, chld_kind))
return false;
1591 var elem = JSROOT.IO.FindBrachStreamerElement(br, handle.file);
1592 if (elem && (elem.fTypeName===
"BASE")) {
1594 if (br.fTotBytes && !AddBranchForReading(br, target_object, target_name, read_mode))
return false;
1595 if (!ScanBranches(br.fBranches, master_target, chld_kind))
return false;
1599 var subname = br.fName, chld_direct = 1;
1601 if (br.fName.indexOf(match_prefix)===0) {
1602 subname = subname.substr(match_prefix.length);
1604 if (chld_kind>0)
continue;
1607 var p = subname.indexOf(
'[');
1608 if (p>0) subname = subname.substr(0,p);
1609 p = subname.indexOf(
'<');
1610 if (p>0) subname = subname.substr(0,p);
1612 if (chld_kind > 0) {
1613 chld_direct =
"$child$";
1614 var pp = subname.indexOf(
".");
1615 if (pp>0) chld_direct = JSROOT.IO.DetectBranchMemberClass(lst, branch.fName +
"." + subname.substr(0,pp+1), k) ||
"TObject";
1618 if (!AddBranchForReading(br, master_target, subname, chld_direct))
return false;
1624 if (branch._typename ===
"TBranchObject") {
1627 typename: branch.fClassName,
1628 virtual: leaf.fVirtual,
1629 func:
function(buf,obj) {
1630 var clname = this.
typename;
1631 if (this.
virtual) clname = buf.ReadFastString(buf.ntou1()+1);
1632 obj[this.name] = buf.ClassStreamer({}, clname);
1637 if ((branch.fType === JSROOT.BranchType.kClonesNode) || (branch.fType === JSROOT.BranchType.kSTLNode)) {
1639 elem = JSROOT.IO.CreateStreamerElement(target_name, JSROOT.IO.kInt);
1641 if (!read_mode || ((typeof read_mode===
"string") && (read_mode[0]===
".")) || (read_mode===1)) {
1642 handle.process_arrays =
false;
1646 conttype: branch.fClonesName ||
"TObject",
1647 reallocate: args.reallocate_objects,
1648 func:
function(buf,obj) {
1649 var size = buf.ntoi4(), n = 0;
1650 if (!obj[this.name] || this.reallocate) {
1651 obj[this.name] =
new Array(size);
1653 n = obj[this.name].length;
1654 obj[this.name].length = size;
1657 while (n<size) obj[this.name][n++] = this.methods.Create();
1661 if ((typeof read_mode===
"string") && (read_mode[0]===
".")) {
1662 member.conttype = JSROOT.IO.DetectBranchMemberClass(branch.fBranches, branch.fName+read_mode);
1663 if (!member.conttype) {
1664 console.error(
'Cannot select object', read_mode,
"in the branch", branch.fName);
1669 member.methods = JSROOT.IO.MakeMethodsList(member.conttype);
1671 child_scan = (branch.fType === JSROOT.BranchType.kClonesNode) ? JSROOT.BranchType.kClonesMemberNode : JSROOT.BranchType.kSTLMemberNode;
1675 if ((object_class = JSROOT.IO.GetBranchObjectClass(branch, handle.tree))) {
1677 if (read_mode ===
true) {
1678 console.warn(
'Object branch ' + object_class +
' can not have data to be read directly');
1682 handle.process_arrays =
false;
1684 var newtgt =
new Array(target_object ? (target_object.length + 1) : 1);
1685 for (var l=0;l<newtgt.length-1;++l) newtgt[l] = target_object[l];
1686 newtgt[newtgt.length-1] = { name: target_name, lst: JSROOT.IO.MakeMethodsList(object_class) };
1688 if (!ScanBranches(branch.fBranches, newtgt, 0))
return null;
1692 }
else if (is_brelem && (nb_leaves === 1) && (leaf.fName === branch.fName) && (branch.fID==-1)) {
1694 elem = JSROOT.IO.CreateStreamerElement(target_name, branch.fClassName);
1696 if (elem.fType === JSROOT.IO.kAny) {
1698 var streamer = handle.file.GetStreamer(branch.fClassName, { val: branch.fClassVersion, checksum: branch.fCheckSum });
1699 if (!streamer) { elem = null; console.warn(
'not found streamer!'); }
else
1702 typename: branch.fClassName,
1704 func:
function(buf,obj) {
1705 var res = { _typename: this.
typename };
1706 for (var n = 0; n < this.streamer.length; ++n)
1707 this.streamer[n].func(buf, res);
1708 obj[this.name] = res;
1717 }
else if (is_brelem && (nb_leaves <= 1)) {
1719 elem = JSROOT.IO.FindBrachStreamerElement(branch, handle.file);
1722 if (!elem && branch.fStreamerType && (branch.fStreamerType < 20))
1723 elem = JSROOT.IO.CreateStreamerElement(target_name, branch.fStreamerType);
1725 }
else if (nb_leaves === 1) {
1728 elem = CreateLeafElem(leaf, target_name);
1730 }
else if ((branch._typename ===
"TBranch") && (nb_leaves > 1)) {
1733 var arr =
new Array(nb_leaves), isok =
true;
1734 for (var l=0;l<nb_leaves;++l) {
1735 arr[l] = CreateLeafElem(branch.fLeaves.arr[l]);
1736 arr[l] = JSROOT.IO.CreateMember(arr[l], handle.file);
1737 if (!arr[l]) isok =
false;
1744 func:
function(buf, obj) {
1745 var tgt = obj[this.name], l = 0;
1746 if (!tgt) obj[this.name] = tgt = {};
1747 while (l<this.leaves.length)
1748 this.leaves[l++].func(buf,tgt);
1753 if (!elem && !member) {
1754 console.warn(
'Not supported branch kind', branch.fName, branch._typename);
1759 member = JSROOT.IO.CreateMember(elem, handle.file);
1761 if ((member.base !== undefined) && member.basename) {
1763 member.func =
function(buf, obj) {
1764 if (!obj[this.name]) obj[this.name] = { _typename: this.basename };
1765 buf.ClassStreamer(obj[this.name], this.basename);
1770 if (item_cnt && (typeof read_mode ===
"string")) {
1772 member.name0 = item_cnt.name;
1774 var snames = target_name.split(
".");
1776 if (snames.length === 1) {
1778 member.get =
function(arr,n) {
return arr[n]; }
1779 }
else if (read_mode ===
"$child$") {
1780 console.error(
'target name contains point, but suppose to be direct child', target_name);
1782 }
else if (snames.length === 2) {
1783 target_name = member.name = snames[1];
1784 member.name1 = snames[0];
1785 member.subtype1 = read_mode;
1786 member.methods1 = JSROOT.IO.MakeMethodsList(member.subtype1);
1787 member.get =
function(arr,n) {
1788 var obj1 = arr[n][this.name1];
1789 if (!obj1) obj1 = arr[n][this.name1] = this.methods1.Create();
1797 if (!branch.fParentName) {
1798 console.error(
'Not possible to provide more than 2 parts in the target name', target_name);
1802 target_name = member.name = snames.pop();
1803 member.snames = snames;
1804 member.smethods = [];
1806 var parent_class = branch.fParentName;
1808 for (var k=0;k<snames.length;++k) {
1809 var chld_class = JSROOT.IO.DefineMemberTypeName(handle.file, parent_class, snames[k]);
1810 member.smethods[k] = JSROOT.IO.MakeMethodsList(chld_class ||
"AbstractClass");
1811 parent_class = chld_class;
1813 member.get =
function(arr,n) {
1814 var obj1 = arr[n][this.snames[0]];
1815 if (!obj1) obj1 = arr[n][this.snames[0]] = this.smethods[0].Create();
1816 for (var k=1;k<this.snames.length;++k) {
1817 var obj2 = obj1[this.snames[k]];
1818 if (!obj2) obj2 = obj1[this.snames[k]] = this.smethods[k].Create();
1828 if (member.objs_branch_func) {
1830 member.func = member.objs_branch_func;
1832 member.func0 = member.func;
1834 member.func =
function(buf,obj) {
1835 var arr = obj[this.name0], n = 0;
1837 this.func0(buf,this.
get(arr,n++));
1841 }
else if (item_cnt) {
1843 handle.process_arrays =
false;
1845 if ((elem.fType === JSROOT.IO.kDouble32) || (elem.fType === JSROOT.IO.kFloat16)) {
1848 member.stl_size = item_cnt.name;
1849 member.func =
function(buf, obj) {
1850 obj[this.name] = this.readarr(buf, obj[this.stl_size]);
1854 if (((elem.fType === JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32) || (elem.fType === JSROOT.IO.kOffsetP+JSROOT.IO.kFloat16)) && branch.fBranchCount2) {
1857 member.stl_size = item_cnt.name;
1858 member.arr_size = item_cnt2.name;
1859 member.func =
function(buf, obj) {
1860 var sz0 = obj[this.stl_size], sz1 = obj[this.arr_size], arr =
new Array(sz0);
1861 for (var n=0;n<sz0;++n)
1862 arr[n] = (buf.ntou1() === 1) ? this.readarr(buf, sz1[n]) : [];
1863 obj[this.name] = arr;
1868 if (((elem.fType > 0) && (elem.fType < JSROOT.IO.kOffsetL)) || (elem.fType === JSROOT.IO.kTString) ||
1869 (((elem.fType > JSROOT.IO.kOffsetP) && (elem.fType < JSROOT.IO.kOffsetP + JSROOT.IO.kOffsetL)) && branch.fBranchCount2)) {
1873 stl_size: item_cnt.name,
1875 func:
function(buf, obj) {
1876 obj[this.name] = buf.ReadFastArray(obj[this.stl_size], this.type);
1880 if (branch.fBranchCount2) {
1881 member.type -= JSROOT.IO.kOffsetP;
1882 member.arr_size = item_cnt2.name;
1883 member.func =
function(buf, obj) {
1884 var sz0 = obj[this.stl_size], sz1 = obj[this.arr_size], arr =
new Array(sz0);
1885 for (var n=0;n<sz0;++n)
1886 arr[n] = (buf.ntou1() === 1) ? buf.ReadFastArray(sz1[n],
this.type) : [];
1887 obj[this.name] = arr;
1892 if ((elem.fType > JSROOT.IO.kOffsetP) && (elem.fType < JSROOT.IO.kOffsetP + JSROOT.IO.kOffsetL) && member.cntname) {
1894 member.cntname = item_cnt.name;
1896 if (elem.fType == JSROOT.IO.kStreamer) {
1900 throw new Error(
'Second branch counter not supported yet with JSROOT.IO.kStreamer');
1903 member.func = member.branch_func;
1904 member.stl_size = item_cnt.name;
1906 if ((elem.fType === JSROOT.IO.kStreamLoop) || (elem.fType === JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop)) {
1909 member.stl_size = item_cnt.name;
1910 member.cntname = item_cnt2.name;
1911 member.func = member.branch_func;
1913 member.cntname = item_cnt.name;
1917 member.name =
"$stl_member";
1922 if (member.cntname) {
1923 loop_size_name = item_cnt2.name;
1924 member.cntname =
"$loop_size";
1926 throw new Error(
'Second branch counter not used - very BAD');
1932 stl_size: item_cnt.name,
1933 loop_size: loop_size_name,
1935 func:
function(buf, obj) {
1936 var cnt = obj[this.stl_size], arr =
new Array(cnt), n = 0;
1937 for (var n=0;n<cnt;++n) {
1938 if (this.loop_size) obj.$loop_size = obj[this.loop_size][n];
1939 this.member0.func(buf, obj);
1940 arr[n] = obj.$stl_member;
1942 delete obj.$stl_member;
1943 delete obj.$loop_size;
1944 obj[this.name] = arr;
1953 member.name = target_name;
1955 item.member = member;
1956 if (elem) item.type = elem.fType;
1957 item.index = handle.arr.length;
1960 item.counters = [ item_cnt.index ];
1961 item_cnt.ascounter.push(item.index);
1964 item.counters.push(item_cnt2.index);
1965 item_cnt2.ascounter.push(item.index);
1969 handle.arr.push(item);
1973 if (!ScanBranches(branch.fBranches, target_object, child_scan))
return null;
1979 for (var nn=0; nn<selector.branches.length; ++nn) {
1981 var item = AddBranchForReading(selector.branches[nn], undefined, selector.names[nn], selector.directs[nn]);
1984 selector.Terminate(
false);
1991 for (var h=1; (h < handle.arr.length) && handle.simple_read; ++h) {
1993 var item = handle.arr[h], item0 = handle.arr[0];
1995 if ((item.numentries !== item0.numentries) || (item.numbaskets !== item0.numbaskets)) handle.simple_read =
false;
1996 for (var n=0;n<item.numbaskets;++n)
1997 if (item.GetBasketEntry(n) !== item0.GetBasketEntry(n)) handle.simple_read =
false;
2002 handle.firstentry = handle.lastentry = 0;
2003 for (var nn = 0; nn < handle.arr.length; ++nn) {
2004 var branch = handle.arr[nn].branch, e1 = branch.fFirstEntry;
2005 if (e1 === undefined) e1 = (branch.fBasketBytes[0] ? branch.fBasketEntry[0] : 0);
2006 handle.firstentry = Math.max(handle.firstentry, e1);
2007 handle.lastentry = (nn===0) ? (e1 + branch.fEntries) : Math.min(handle.lastentry, e1 + branch.fEntries);
2010 if (handle.firstentry >= handle.lastentry) {
2011 console.warn(
'No any common events for selected branches');
2012 selector.Terminate(
false);
2016 handle.process_min = handle.firstentry;
2017 handle.process_max = handle.lastentry;
2019 if (!isNaN(args.firstentry) && (args.firstentry>handle.firstentry) && (args.firstentry < handle.lastentry))
2020 handle.process_min = args.firstentry;
2022 handle.current_entry = handle.staged_now = handle.process_min;
2024 if (!isNaN(args.numentries) && (args.numentries>0)) {
2025 var max = handle.process_min + args.numentries;
2026 if (max<handle.process_max) handle.process_max = max;
2029 if ((typeof selector.ProcessArrays ===
'function') && handle.simple_read) {
2033 for (var k=0;k<handle.arr.length;++k) {
2034 var elem = handle.arr[k];
2035 if ((elem.type<=0) || (elem.type >= JSROOT.IO.kOffsetL) || (elem.type === JSROOT.IO.kCharStar)) handle.process_arrays =
false;
2038 if (handle.process_arrays) {
2041 selector.tgtarr = {};
2043 for(var nn=0;nn<handle.arr.length;++nn) {
2044 var item = handle.arr[nn],
2045 elem = JSROOT.IO.CreateStreamerElement(item.name, item.type);
2047 elem.fType = item.type + JSROOT.IO.kOffsetL;
2048 elem.fArrayLength = 10;
2050 elem.fMaxIndex[0] = 10;
2052 item.arrmember = JSROOT.IO.CreateMember(elem, handle.file);
2056 handle.process_arrays =
false;
2059 function ReadBaskets(bitems, baskets_call_back) {
2062 var places = [], filename =
"";
2064 function ExtractPlaces() {
2067 places = []; filename =
"";
2069 for (var n=0;n<bitems.length;++n) {
2070 if (bitems[n].done)
continue;
2072 var branch = bitems[n].branch;
2074 if (places.length===0)
2075 filename = branch.fFileName;
2077 if (filename !== branch.fFileName)
continue;
2079 bitems[n].selected =
true;
2081 places.push(branch.fBasketSeek[bitems[n].basket], branch.fBasketBytes[bitems[n].basket]);
2084 return places.length > 0;
2087 function ReadProgress(value) {
2089 if ((handle.staged_prev === handle.staged_now) ||
2090 (handle.process_max <= handle.process_min))
return;
2092 var tm =
new Date().getTime();
2094 if (tm - handle.progress_showtm < 500)
return;
2096 handle.progress_showtm = tm;
2098 var portion = (handle.staged_prev + value * (handle.staged_now - handle.staged_prev)) /
2099 (handle.process_max - handle.process_min);
2101 handle.selector.ShowProgress(portion);
2104 function ProcessBlobs(blobs) {
2105 if (!blobs || ((places.length>2) && (blobs.length*2 !== places.length)))
2106 return JSROOT.CallBack(baskets_call_back, null);
2108 var baskets = [], n = 0;
2110 for (var k=0;k<bitems.length;++k) {
2111 if (!bitems[k].selected)
continue;
2113 bitems[k].selected =
false;
2114 bitems[k].done =
true;
2116 var blob = (places.length > 2) ? blobs[n++] : blobs,
2117 buf = JSROOT.CreateTBuffer(blob, 0, handle.file),
2118 basket = buf.ClassStreamer({},
"TBasket");
2120 if (basket.fNbytes !== bitems[k].branch.fBasketBytes[bitems[k].basket])
2121 console.error(
'mismatch in read basket sizes', bitems[k].branch.fBasketBytes[bitems[k].basket]);
2125 bitems[k].bskt_obj = basket;
2127 if (basket.fKeylen + basket.fObjlen === basket.fNbytes) {
2132 var objblob = JSROOT.R__unzip(blob, basket.fObjlen,
false, buf.o);
2135 buf = JSROOT.CreateTBuffer(objblob, 0, handle.file);
2136 buf.raw_shift = basket.fKeylen;
2137 buf.fTagOffset = basket.fKeylen;
2139 throw new Error(
'FAIL TO UNPACK');
2143 bitems[k].raw = buf;
2145 if (bitems[k].branch.fEntryOffsetLen > 0)
2146 buf.ReadBasketEntryOffset(basket, buf.raw_shift);
2149 if (ExtractPlaces())
2150 handle.file.ReadBuffer(places, ProcessBlobs, filename, ReadProgress);
2152 JSROOT.CallBack(baskets_call_back, bitems);
2156 if (ExtractPlaces())
2157 handle.file.ReadBuffer(places, ProcessBlobs, filename, ReadProgress);
2159 JSROOT.CallBack(baskets_call_back, null);
2162 function ReadNextBaskets() {
2164 var totalsz = 0, bitems = [], isany =
true, is_direct =
false, min_staged = handle.process_max;
2166 while ((totalsz < 1e6) && isany) {
2170 for (var n=handle.arr.length-1; n>=0; --n) {
2171 var elem = handle.arr[n];
2173 while (elem.staged_basket < elem.numbaskets) {
2175 var k = elem.staged_basket++;
2178 if (elem.GetBasketEntry(k) >= handle.process_max)
break;
2181 if (elem.first_readentry < 0) {
2182 var lmt = elem.GetBasketEntry(k+1),
2183 not_needed = (lmt <= handle.process_min);
2190 if (not_needed)
continue;
2192 elem.curr_basket = k;
2194 elem.first_readentry = elem.GetBasketEntry(k);
2201 branch: elem.branch,
2206 var bskt = elem.branch.fBaskets.arr[k];
2208 bitem.raw = bskt.fBufferRef;
2210 bitem.raw.locate(0);
2212 bitem.raw = JSROOT.CreateTBuffer(null, 0, handle.file);
2213 bitem.raw.raw_shift = bskt.fKeylen;
2215 if (bskt.fBufferRef && (elem.branch.fEntryOffsetLen > 0))
2216 bitem.raw.ReadBasketEntryOffset(bskt, bitem.raw.raw_shift);
2218 bitem.bskt_obj = bskt;
2220 elem.baskets[k] = bitem;
2223 totalsz += elem.branch.fBasketBytes[k];
2227 elem.staged_entry = elem.GetBasketEntry(k+1);
2229 min_staged = Math.min(min_staged, elem.staged_entry);
2236 if ((totalsz === 0) && !is_direct)
2237 return handle.selector.Terminate(
true);
2239 handle.staged_prev = handle.staged_now;
2240 handle.staged_now = min_staged;
2243 if (handle.process_max > handle.process_min)
2244 portion = (handle.staged_prev - handle.process_min)/ (handle.process_max - handle.process_min);
2246 handle.selector.ShowProgress(portion);
2248 handle.progress_showtm =
new Date().getTime();
2250 if (totalsz > 0)
return ReadBaskets(bitems, ProcessBaskets);
2252 if (is_direct)
return ProcessBaskets([]);
2254 throw new Error(
"No any data is requested - never come here");
2257 function ProcessBaskets(bitems) {
2260 if ((handle.selector.break_execution !== 0) || (bitems===null))
2261 return handle.selector.Terminate(
false);
2264 for(var n=0;n<bitems.length;++n)
2265 handle.arr[bitems[n].id].baskets[bitems[n].basket] = bitems[n];
2269 var isanyprocessed =
false;
2273 var loopentries = 100000000, min_curr = handle.process_max, n, elem;
2276 for (n=0;n<handle.arr.length;++n) {
2278 elem = handle.arr[n];
2280 if (!elem.raw || !elem.basket || (elem.first_entry + elem.basket.fNevBuf <= handle.current_entry)) {
2284 if ((elem.curr_basket >= elem.numbaskets)) {
2285 if (n==0)
return handle.selector.Terminate(
true);
2290 var bitem = elem.baskets[elem.curr_basket];
2295 if (!isanyprocessed) {
2296 console.warn(
'no data?', elem.branch.fName, elem.curr_basket);
2297 return handle.selector.Terminate(
false);
2301 return ReadNextBaskets();
2304 elem.raw = bitem.raw;
2305 elem.basket = bitem.bskt_obj;
2307 elem.first_entry = elem.GetBasketEntry(bitem.basket);
2310 bitem.branch = null;
2311 bitem.bskt_obj = null;
2312 elem.baskets[elem.curr_basket++] = undefined;
2316 loopentries = Math.min(loopentries, elem.first_entry + elem.basket.fNevBuf - handle.current_entry);
2322 if (handle.current_entry + loopentries > handle.process_max)
2323 loopentries = handle.process_max - handle.current_entry;
2325 if (handle.process_arrays && (loopentries>1)) {
2328 for (n=0;n<handle.arr.length;++n) {
2329 elem = handle.arr[n];
2331 elem.GetEntry(handle.current_entry);
2333 elem.arrmember.arrlength = loopentries;
2334 elem.arrmember.func(elem.raw, handle.selector.tgtarr);
2339 handle.selector.ProcessArrays(handle.current_entry);
2341 handle.current_entry += loopentries;
2343 isanyprocessed =
true;
2347 while(loopentries--) {
2349 for (n=0;n<handle.arr.length;++n) {
2350 elem = handle.arr[n];
2353 elem.GetEntry(handle.current_entry);
2355 elem.member.func(elem.raw, elem.GetTarget(handle.selector.tgtobj));
2358 handle.selector.Process(handle.current_entry);
2360 handle.current_entry++;
2362 isanyprocessed =
true;
2365 if (handle.current_entry >= handle.process_max)
2366 return handle.selector.Terminate(
true);
2371 handle.selector.Begin(
this);
2381 JSROOT.TreeMethods.FindBranch =
function(name, complex, lst) {
2383 var top_search =
false, search = name, res = null;
2385 if (lst===undefined) {
2387 lst = this.fBranches;
2388 var pos = search.indexOf(
"[");
2389 if (pos>0) search = search.substr(0,pos);
2392 if (!lst || (lst.arr.length===0))
return null;
2394 for (var n=0;n<lst.arr.length;++n) {
2395 var brname = lst.arr[n].fName;
2396 if (brname[brname.length-1] ==
"]")
2397 brname = brname.substr(0, brname.indexOf(
"["));
2400 if ((search.indexOf(brname)!==0) && (brname.indexOf(
"<")>0)) {
2401 var p1 = brname.indexOf(
"<"), p2 = brname.lastIndexOf(
">");
2402 brname = brname.substr(0, p1) + brname.substr(p2+1);
2405 if (brname === search) { res = { branch: lst.arr[n], rest:
"" };
break; }
2407 if (search.indexOf(brname)!==0)
continue;
2412 var pnt = brname.length;
2413 if (brname[pnt-1] ===
'.') pnt--;
2414 if (search[pnt] !==
'.')
continue;
2416 res = this.FindBranch(search, complex, lst.arr[n].fBranches);
2417 if (!res) res = this.FindBranch(search.substr(pnt+1), complex, lst.arr[n].fBranches);
2419 if (!res) res = { branch: lst.arr[n], rest: search.substr(pnt) };
2424 if (!top_search || !res)
return res;
2426 if (name.length > search.length) res.rest += name.substr(search.length);
2428 if (!complex && (res.rest.length>0))
return null;
2430 return complex ? res : res.branch;
2444 JSROOT.TreeMethods.Draw =
function(args, result_callback) {
2446 if (typeof args ===
'string') args = { expr: args };
2448 if (!args.expr) args.expr =
"";
2451 if (args.expr ===
"testio")
2452 return this.IOTest(args, result_callback);
2454 var selector =
new TDrawSelector(result_callback);
2457 if (!selector.DrawOnlyBranch(
this, args.branch, args.expr, args)) selector = null;
2459 if (!selector.ParseDrawExpression(
this, args)) selector = null;
2463 return JSROOT.CallBack(result_callback, null);
2465 return this.Process(selector, args);
2468 JSROOT.TreeMethods.IOTest =
function(args, result_callback) {
2471 if (!args.names && !args.bracnhes) {
2478 function CollectBranches(obj, prntname) {
2479 if (!obj || !obj.fBranches)
return 0;
2483 for (var n=0;n<obj.fBranches.arr.length;++n) {
2484 var br = obj.fBranches.arr[n],
2485 name = (prntname ? prntname +
"/" :
"") + br.fName;
2486 args.branches.push(br);
2487 args.names.push(name);
2488 args.nchilds.push(0);
2489 var pos = args.nchilds.length-1;
2490 cnt += br.fLeaves ? br.fLeaves.arr.length : 0;
2491 var nchld = CollectBranches(br, name);
2494 args.nchilds[pos] = nchld;
2500 var numleaves = CollectBranches(
this);
2502 args.names.push(
"Total are " + args.branches.length +
" branches with " + numleaves +
" leaves");
2505 args.lasttm =
new Date().getTime();
2506 args.lastnbr = args.nbr;
2510 function TestNextBranch() {
2512 var selector =
new TSelector;
2514 selector.AddBranch(args.branches[args.nbr],
"br0");
2516 selector.Process =
function() {
2517 if (this.tgtobj.br0 === undefined)
2521 selector.Terminate =
function(res) {
2522 if (typeof res !==
'string')
2523 res = (!res || this.fails) ?
"FAIL" :
"ok";
2525 args.names[args.nbr] = res +
" " + args.names[args.nbr];
2528 if (args.nbr >= args.branches.length) {
2530 return JSROOT.CallBack(result_callback, args.names,
"inspect");
2533 var now =
new Date().getTime();
2535 if ((now - args.lasttm > 5000) || (args.nbr - args.lastnbr > 50))
2536 setTimeout(tree.IOTest.bind(tree,args,result_callback), 100);
2541 JSROOT.progress(
"br " + args.nbr +
"/" + args.branches.length +
" " + args.names[args.nbr]);
2543 var br = args.branches[args.nbr],
2544 object_class = JSROOT.IO.GetBranchObjectClass(br, tree),
2546 skip_branch = (!br.fLeaves || (br.fLeaves.arr.length === 0));
2548 if (object_class) skip_branch = (args.nchilds[args.nbr]>100);
2552 if (skip_branch || (num<=0)) {
2555 selector.Terminate(
"ignore");
2558 var drawargs = { numentries: 10 },
2559 first = br.fFirstEntry || 0,
2560 last = br.fEntryNumber || (first+num);
2562 if (num < drawargs.numentries) {
2563 drawargs.numentries = num;
2566 drawargs.firstentry = first + Math.round((last-first-drawargs.numentries)*Math.random());
2570 console.log(
'test branch', br.fName,
'first', (drawargs.firstentry || 0),
"num", drawargs.numentries);
2572 tree.Process(selector, drawargs);
2580 JSROOT.TSelector = TSelector;
2581 JSROOT.TDrawVariable = TDrawVariable;
2582 JSROOT.TDrawSelector = TDrawSelector;