5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootPainter',
'd3'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 factory(require(
"./JSRootCore.js"), require(
"d3"));
10 if (typeof d3 !=
'object')
11 throw new Error(
'This extension requires d3.js',
'JSRootPainter.v7.js');
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootPainter.v7.js');
14 if (typeof JSROOT.Painter !=
'object')
15 throw new Error(
'JSROOT.Painter not defined',
'JSRootPainter.v7.js');
18 } (
function(JSROOT, d3) {
22 JSROOT.sources.push(
"v7");
27 JSROOT.TObjectPainter.prototype.v7EvalAttr =
function(name, dflt) {
28 var obj = this.GetObject();
29 if (!obj)
return dflt;
31 if (obj.fAttr && obj.fAttr.m) {
32 var value = obj.fAttr.m[name];
33 if (value)
return value.v;
36 if (this.rstyle && this.rstyle.fBlocks) {
37 var blks = this.rstyle.fBlocks;
38 for (var k=0;k<blks.length;++k) {
41 var match = (this.csstype && (block.selector == this.csstype)) ||
42 (obj.fId && (block.selector == (
"#" + obj.fId))) ||
43 (obj.fCssClass && (block.selector == (
"." + obj.fCssClass)));
45 if (match && block.map && block.map.m) {
46 var value = block.map.m[name];
47 if (value)
return value.v;
56 JSROOT.TObjectPainter.prototype.v7EvalColor =
function(name, dflt) {
57 var rgb = this.v7EvalAttr(name +
"_rgb",
"");
60 return "#" + rgb + this.v7EvalAttr(name +
"_a",
"");
62 return this.v7EvalAttr(name +
"_name",
"") || dflt;
66 function TAxisPainter(axis, embedded) {
67 JSROOT.TObjectPainter.call(
this, axis);
69 this.embedded = embedded;
81 this.invert_side =
false;
82 this.lbls_both_sides =
false;
85 TAxisPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
87 TAxisPainter.prototype.Cleanup =
function() {
93 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
96 TAxisPainter.prototype.SetAxisConfig =
function(name, kind, func, min, max, smin, smax) {
103 this.scale_min = smin;
104 this.scale_max = smax;
107 TAxisPainter.prototype.format10Exp =
function(order, value) {
110 value = Math.round(value/Math.pow(10,order));
111 if ((value!=0) && (value!=1)) res = value.toString() + (JSROOT.gStyle.Latex ?
"#times" :
"x");
114 if (JSROOT.gStyle.Latex > 1)
return res +
"^{" + order +
"}";
115 var superscript_symbols = {
116 '0':
'\u2070',
'1':
'\xB9',
'2':
'\xB2',
'3':
'\xB3',
'4':
'\u2074',
'5':
'\u2075',
117 '6':
'\u2076',
'7':
'\u2077',
'8':
'\u2078',
'9':
'\u2079',
'-':
'\u207B'
119 var str = order.toString();
120 for (var n=0;n<str.length;++n) res += superscript_symbols[str[n]];
124 TAxisPainter.prototype.CreateFormatFuncs =
function() {
126 var axis = this.GetObject(),
127 is_gaxis = (axis && axis._typename ===
'TGaxis');
132 if (is_gaxis) ndiv = axis.fNdiv;
else
133 if (axis) ndiv = Math.max(axis.fNdivisions, 4);
135 this.nticks = ndiv % 100;
136 this.nticks2 = (ndiv % 10000 - this.nticks) / 100;
137 this.nticks3 = Math.floor(ndiv/10000);
139 if (axis && !is_gaxis && (this.nticks > 7)) this.nticks = 7;
141 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
142 if (gr_range<=0) gr_range = 100;
144 if (this.kind ==
'time') {
145 if (this.nticks > 8) this.nticks = 8;
147 var scale_range = this.scale_max - this.scale_min,
148 tf1 = JSROOT.Painter.getTimeFormat(axis),
149 tf2 = JSROOT.Painter.chooseTimeFormat(scale_range / gr_range,
false);
151 if ((tf1.length == 0) || (scale_range < 0.1 * (
this.full_max -
this.full_min)))
152 tf1 = JSROOT.Painter.chooseTimeFormat(scale_range / this.nticks,
true);
154 this.tfunc1 = this.tfunc2 = d3.timeFormat(tf1);
156 this.tfunc2 = d3.timeFormat(tf2);
158 this.format =
function(d, asticks) {
159 return asticks ? this.tfunc1(d) : this.tfunc2(d);
162 }
else if (this.kind ==
'log') {
163 if (this.nticks2 > 1) {
164 this.nticks *= this.nticks2;
167 this.noexp = axis ? axis.TestBit(JSROOT.EAxisBits.kNoExponent) :
false;
168 if ((this.scale_max < 300) && (this.scale_min > 0.3)) this.noexp =
true;
169 this.moreloglabels = axis ? axis.TestBit(JSROOT.EAxisBits.kMoreLogLabels) :
false;
171 this.format =
function(d, asticks, notickexp_fmt) {
172 var val = parseFloat(d), rnd = Math.round(val);
174 return ((rnd === val) && (Math.abs(rnd)<1e9)) ? rnd.toString() : JSROOT.FFormat(val, notickexp_fmt || JSROOT.gStyle.fStatFormat);
176 if (val <= 0)
return null;
177 var vlog = JSROOT.log10(val);
178 if (this.moreloglabels || (Math.abs(vlog - Math.round(vlog))<0.001)) {
179 if (!this.noexp && !notickexp_fmt)
180 return this.format10Exp(Math.floor(vlog+0.01), val);
182 return (vlog<0) ? val.toFixed(Math.round(-vlog+0.5)) : val.toFixed(0);
186 }
else if (this.kind ==
'labels') {
188 var scale_range = this.scale_max - this.scale_min;
189 if (this.nticks > scale_range)
190 this.nticks = Math.round(scale_range);
193 this.regular_labels =
true;
195 if (axis && axis.fNbins && axis.fLabels) {
196 if ((axis.fNbins != Math.round(axis.fXmax - axis.fXmin)) ||
197 (axis.fXmin != 0) || (axis.fXmax != axis.fNbins)) {
198 this.regular_labels =
false;
204 this.format =
function(d) {
205 var indx = parseFloat(d);
206 if (!this.regular_labels)
207 indx = (indx - this.axis.fXmin)/(this.axis.fXmax -
this.axis.fXmin) * this.axis.fNbins;
208 indx = Math.round(indx);
209 if ((indx<0) || (indx>=this.axis.fNbins))
return null;
210 for (var i = 0; i < this.axis.fLabels.arr.length; ++i) {
211 var tstr = this.axis.fLabels.arr[i];
212 if (tstr.fUniqueID === indx+1)
return tstr.fString;
221 this.format =
function(d, asticks, fmt) {
222 var val = parseFloat(d);
223 if (asticks && this.order) val = val / Math.pow(10, this.order);
225 if (val === Math.round(val))
226 return (Math.abs(val)<1e9) ? val.toFixed(0) : val.toExponential(4);
228 if (asticks)
return (this.ndig>10) ? val.toExponential(this.ndig-11) : val.toFixed(this.ndig);
230 return JSROOT.FFormat(val, fmt || JSROOT.gStyle.fStatFormat);
235 TAxisPainter.prototype.ProduceTicks =
function(ndiv, ndiv2) {
236 if (!this.noticksopt)
return this.func.ticks(ndiv * (ndiv2 || 1));
238 if (ndiv2) ndiv = (ndiv-1) * ndiv2;
239 var dom = this.func.domain(), ticks = [];
240 for (var n=0;n<=ndiv;++n)
241 ticks.push((dom[0]*(ndiv-n) + dom[1]*n)/ndiv);
245 TAxisPainter.prototype.CreateTicks =
function(only_major_as_array, optionNoexp, optionNoopt, optionInt) {
248 if (optionNoopt && this.nticks && (this.kind ==
"normal")) this.noticksopt =
true;
250 var handle = { nminor: 0, nmiddle: 0, nmajor: 0, func: this.func };
252 handle.minor = handle.middle = handle.major = this.ProduceTicks(this.nticks);
254 if (only_major_as_array) {
255 var res = handle.major, delta = (this.scale_max - this.scale_min)*1e-5;
256 if (res[0] > this.scale_min + delta) res.unshift(this.scale_min);
257 if (res[res.length-1] <
this.scale_max - delta) res.push(this.scale_max);
261 if ((this.kind ==
'labels') && !this.regular_labels) {
263 for (var n=0;n<this.axis.fNbins;++n) {
264 var x = this.axis.fXmin + n / this.axis.fNbins * (this.axis.fXmax - this.axis.fXmin);
265 if ((x >= this.scale_min) && (x < this.scale_max)) handle.lbl_pos.push(x);
269 if (this.nticks2 > 1) {
270 handle.minor = handle.middle = this.ProduceTicks(handle.major.length,
this.nticks2);
272 var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]);
275 if ((handle.middle.length <= handle.major.length) || (handle.middle.length > gr_range/3.5)) {
276 handle.minor = handle.middle = handle.major;
278 if ((this.nticks3 > 1) && (this.kind !==
'log')) {
279 handle.minor = this.ProduceTicks(handle.middle.length,
this.nticks3);
280 if ((handle.minor.length <= handle.middle.length) || (handle.minor.length > gr_range/1.7)) handle.minor = handle.middle;
284 handle.reset =
function() {
285 this.nminor = this.nmiddle = this.nmajor = 0;
288 handle.next =
function(doround) {
289 if (this.nminor >= this.minor.length)
return false;
291 this.tick = this.minor[this.nminor++];
292 this.grpos = this.func(this.tick);
293 if (doround) this.grpos = Math.round(this.grpos);
296 if ((this.nmiddle < this.middle.length) && (Math.abs(
this.grpos -
this.func(
this.middle[
this.nmiddle])) < 1)) {
301 if ((this.nmajor < this.major.length) && (Math.abs(this.grpos - this.func(this.major[this.nmajor])) < 1) ) {
308 handle.last_major =
function() {
309 return (this.kind !== 1) ?
false : this.nmajor == this.major.length;
312 handle.next_major_grpos =
function() {
313 if (this.nmajor >= this.major.length)
return null;
314 return this.func(this.major[this.nmajor]);
322 if ((this.kind ==
"normal") && (handle.major.length > 0)) {
324 var maxorder = 0, minorder = 0, exclorder3 =
false;
327 var maxtick = Math.max(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])),
328 mintick = Math.min(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])),
329 ord1 = (maxtick > 0) ? Math.round(JSROOT.log10(maxtick)/3)*3 : 0,
330 ord2 = (mintick > 0) ? Math.round(JSROOT.log10(mintick)/3)*3 : 0;
332 exclorder3 = (maxtick < 2e4);
334 if (maxtick || mintick) {
335 maxorder = Math.max(ord1,ord2) + 3;
336 minorder = Math.min(ord1,ord2) - 3;
342 var bestorder = 0, bestndig = this.ndig, bestlen = 1e10;
344 for (var order = minorder; order <= maxorder; order+=3) {
345 if (exclorder3 && (order===3))
continue;
348 var lbls = [], indx = 0, totallen = 0;
349 while (indx<handle.major.length) {
350 var lbl = this.format(handle.major[indx],
true);
351 if (lbls.indexOf(lbl)<0) {
353 totallen += lbl.length;
357 if (++this.ndig > 11)
break;
358 lbls = []; indx = 0; totallen = 0;
362 if (!order && (this.ndig<4)) totallen-=(handle.major.length*2+3);
364 if (totallen < bestlen) {
366 bestorder = this.order;
367 bestndig = this.ndig;
371 this.order = bestorder;
372 this.ndig = bestndig;
375 if (this.order) console.warn(
'Axis painter - integer labels are configured, but axis order ' + this.order +
' is preferable');
376 if (this.ndig) console.warn(
'Axis painter - integer labels are configured, but ' + this.ndig +
' decimal digits are required');
385 TAxisPainter.prototype.IsCenterLabels =
function() {
386 if (this.kind ===
'labels')
return true;
387 if (this.kind ===
'log')
return false;
388 var axis = this.GetObject();
389 return axis && axis.TestBit(JSROOT.EAxisBits.kCenterLabels);
392 TAxisPainter.prototype.AddTitleDrag =
function(title_g, vertical, offset_k, reverse, axis_length) {
393 if (!JSROOT.gStyle.MoveResize)
return;
395 var pthis =
this, drag_rect = null, prefix =
"", drag_move,
396 acc_x, acc_y, new_x, new_y, sign_0, center_0, alt_pos;
397 if (JSROOT._test_d3_ === 3) {
399 drag_move = d3.behavior.drag().origin(Object);
401 drag_move = d3.drag().subject(Object);
405 .on(prefix+
"start",
function() {
407 d3.event.sourceEvent.preventDefault();
408 d3.event.sourceEvent.stopPropagation();
410 var box = title_g.node().getBBox(),
411 axis = pthis.GetObject();
413 new_x = acc_x = title_g.property(
'shift_x');
414 new_y = acc_y = title_g.property(
'shift_y');
416 sign_0 = vertical ? (acc_x>0) : (acc_y>0);
418 if (axis.TestBit(JSROOT.EAxisBits.kCenterTitle))
419 alt_pos = (reverse === vertical) ? axis_length : 0;
421 alt_pos = Math.round(axis_length/2);
423 drag_rect = title_g.append(
"rect")
424 .classed(
"zoom",
true)
427 .attr(
"width", box.width)
428 .attr(
"height", box.height)
429 .style(
"cursor",
"move");
431 }).on(
"drag",
function() {
432 if (!drag_rect)
return;
434 d3.event.sourceEvent.preventDefault();
435 d3.event.sourceEvent.stopPropagation();
437 acc_x += d3.event.dx;
438 acc_y += d3.event.dy;
440 var set_x = title_g.property(
'shift_x'),
441 set_y = title_g.property(
'shift_y');
445 if (Math.abs(acc_y - set_y) > Math.abs(acc_y - alt_pos)) set_y = alt_pos;
448 if (Math.abs(acc_x - set_x) > Math.abs(acc_x - alt_pos)) set_x = alt_pos;
451 if (sign_0 === (vertical ? (set_x>0) : (set_y>0))) {
452 new_x = set_x; new_y = set_y;
453 title_g.attr(
'transform',
'translate(' + new_x +
',' + new_y +
')');
456 }).on(prefix+
"end",
function() {
457 if (!drag_rect)
return;
459 d3.event.sourceEvent.preventDefault();
460 d3.event.sourceEvent.stopPropagation();
462 title_g.property(
'shift_x', new_x)
463 .property(
'shift_y', new_y);
465 var axis = pthis.GetObject();
467 axis.fTitleOffset = (vertical ? new_x : new_y) / offset_k;
468 if ((vertical ? new_y : new_x) === alt_pos) axis.InvertBit(JSROOT.EAxisBits.kCenterTitle);
474 title_g.style(
"cursor",
"move").call(drag_move);
477 TAxisPainter.prototype.DrawAxis =
function(vertical, layer, w, h, transform, reverse, second_shift, disable_axis_drawing, max_text_width) {
480 var axis = this.GetObject(), chOpt =
"",
481 is_gaxis = (axis && axis._typename ===
'TGaxis'),
482 axis_g = layer, tickSize = 0.03,
483 scaling_size = 100, draw_lines =
true,
484 pad_w = this.pad_width() || 10,
485 pad_h = this.pad_height() || 10;
487 this.vertical = vertical;
489 function myXor(a,b) {
return ( a && !b ) || (!a && b); }
492 if (!second_shift) second_shift = 0;
else
493 if (this.invert_side) second_shift = -second_shift;
496 this.createAttLine({ attr: axis });
497 draw_lines = axis.fLineColor != 0;
499 tickSize = axis.fTickSize;
500 scaling_size = (vertical ? 1.7*h : 0.6*w);
502 this.createAttLine({ color: axis.fAxisColor, width: 1, style: 1 });
503 chOpt = myXor(vertical, this.invert_side) ?
"-S" :
"+S";
504 tickSize = axis.fTickLength;
505 scaling_size = (vertical ? pad_w : pad_h);
508 if (!is_gaxis || (this.name ===
"zaxis")) {
509 axis_g = layer.select(
"." + this.name +
"_container");
511 axis_g = layer.append(
"svg:g").attr(
"class",this.name +
"_container");
513 axis_g.selectAll(
"*").remove();
515 if (!disable_axis_drawing && draw_lines)
516 axis_g.append(
"svg:line")
517 .attr(
"x1",0).attr(
"y1",0)
518 .attr(
"x1",vertical ? 0 : w)
519 .attr(
"y1", vertical ? h : 0)
520 .call(this.lineatt.func);
523 axis_g.attr(
"transform", transform || null);
525 var side = 1, ticks_plusminus = 0,
526 text_scaling_size = Math.min(pad_w, pad_h),
527 optionPlus = (chOpt.indexOf(
"+")>=0),
528 optionMinus = (chOpt.indexOf(
"-")>=0),
529 optionSize = (chOpt.indexOf(
"S")>=0),
530 optionY = (chOpt.indexOf(
"Y")>=0),
531 optionUp = (chOpt.indexOf(
"0")>=0),
532 optionDown = (chOpt.indexOf(
"O")>=0),
533 optionUnlab = (chOpt.indexOf(
"U")>=0),
534 optionNoopt = (chOpt.indexOf(
"N")>=0),
535 optionInt = (chOpt.indexOf(
"I")>=0),
536 optionNoexp = axis.TestBit(JSROOT.EAxisBits.kNoExponent);
538 if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickPlus)) optionPlus =
true;
539 if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickMinus)) optionMinus =
true;
541 if (optionPlus && optionMinus) { side = 1; ticks_plusminus = 1; }
else
542 if (optionMinus) { side = myXor(reverse,vertical) ? 1 : -1; }
else
543 if (optionPlus) { side = myXor(reverse,vertical) ? -1 : 1; }
545 tickSize = Math.round((optionSize ? tickSize : 0.03) * scaling_size);
547 if (this.max_tick_size && (tickSize > this.max_tick_size)) tickSize = this.max_tick_size;
549 this.CreateFormatFuncs();
551 var res =
"", res2 =
"", lastpos = 0, lasth = 0;
557 var handle = this.CreateTicks(
false, optionNoexp, optionNoopt, optionInt);
559 while (handle.next(
true)) {
561 var h1 = Math.round(tickSize/4), h2 = 0;
564 h1 = Math.round(tickSize/2);
566 if (handle.kind == 1) {
568 if (!(
'format' in
this) || (this.format(handle.tick,
true)!==null)) h1 = tickSize;
569 this.ticks.push(handle.grpos);
572 if (ticks_plusminus > 0) h2 = -h1;
else
573 if (side < 0) { h2 = -h1; h1 = 0; }
else { h2 = 0; }
575 if (res.length == 0) {
576 res = vertical ? (
"M"+h1+
","+handle.grpos) : (
"M"+handle.grpos+
","+(-h1));
577 res2 = vertical ? (
"M"+(second_shift-h1)+
","+handle.grpos) : (
"M"+handle.grpos+
","+(second_shift+h1));
579 res += vertical ? (
"m"+(h1-lasth)+
","+(handle.grpos-lastpos)) : (
"m"+(handle.grpos-lastpos)+
","+(lasth-h1));
580 res2 += vertical ? (
"m"+(lasth-h1)+
","+(handle.grpos-lastpos)) : (
"m"+(handle.grpos-lastpos)+
","+(h1-lasth));
583 res += vertical ? (
"h"+ (h2-h1)) : (
"v"+ (h1-h2));
584 res2 += vertical ? (
"h"+ (h1-h2)) : (
"v"+ (h2-h1));
586 lastpos = handle.grpos;
590 if ((res.length > 0) && !disable_axis_drawing && draw_lines)
591 axis_g.append(
"svg:path").attr(
"d", res).call(this.lineatt.func);
593 if ((second_shift!==0) && (res2.length>0) && !disable_axis_drawing && draw_lines)
594 axis_g.append(
"svg:path").attr(
"d", res2).call(this.lineatt.func);
596 var labelsize = Math.round( (axis.fLabelSize < 1) ? axis.fLabelSize * text_scaling_size : axis.fLabelSize);
597 if ((labelsize <= 0) || (Math.abs(axis.fLabelOffset) > 1.1)) optionUnlab =
true;
600 if (!disable_axis_drawing && !optionUnlab) {
602 var label_color = this.get_color(axis.fLabelColor),
603 labeloffset = Math.round(axis.fLabelOffset*text_scaling_size ),
604 center_lbls = this.IsCenterLabels(),
605 rotate_lbls = axis.TestBit(JSROOT.EAxisBits.kLabelsVert),
606 textscale = 1, maxtextlen = 0, lbls_tilt =
false, labelfont = null,
607 label_g = [ axis_g.append(
"svg:g").attr(
"class",
"axis_labels") ],
608 lbl_pos = handle.lbl_pos || handle.major;
610 if (this.lbls_both_sides)
611 label_g.push(axis_g.append(
"svg:g").attr(
"class",
"axis_labels").attr(
"transform", vertical ?
"translate(" + w +
",0)" :
"translate(0," + (-h) +
")"));
613 for (var lcnt = 0; lcnt < label_g.length; ++lcnt) {
615 if (lcnt > 0) side = -side;
618 fix_coord = vertical ? -labeloffset*side : (labeloffset+2)*side + ticks_plusminus*tickSize;
620 labelfont = JSROOT.Painter.getFontDetails(axis.fLabelFont, labelsize);
622 this.StartTextDrawing(labelfont,
'font', label_g[lcnt]);
624 for (var nmajor=0;nmajor<lbl_pos.length;++nmajor) {
626 var lbl = this.format(lbl_pos[nmajor],
true);
627 if (lbl === null)
continue;
629 var pos = Math.round(this.func(lbl_pos[nmajor])),
630 gap_before = (nmajor>0) ? Math.abs(Math.round(pos -
this.func(lbl_pos[nmajor-1]))) : 0,
631 gap_after = (nmajor<lbl_pos.length-1) ? Math.abs(Math.round(
this.func(lbl_pos[nmajor+1])-pos)) : 0;
634 var gap = gap_after || gap_before;
635 pos = Math.round(pos - (vertical ? 0.5*gap : -0.5*gap));
636 if ((pos < -5) || (pos > (vertical ? h : w) + 5))
continue;
639 var arg = { text: lbl, color: label_color, latex: 1, draw_g: label_g[lcnt] };
641 maxtextlen = Math.max(maxtextlen, lbl.length);
646 arg.align = rotate_lbls ? ((side<0) ? 23 : 20) : ((side<0) ? 12 : 32);
650 arg.align = rotate_lbls ? ((side<0) ? 12 : 32) : ((side<0) ? 20 : 23);
653 if (rotate_lbls) arg.rotate = 270;
655 var textwidth = this.DrawText(arg);
657 if (textwidth && ((!vertical && !rotate_lbls) || (vertical && rotate_lbls)) && (this.kind !=
'log')) {
658 var maxwidth = gap_before*0.45 + gap_after*0.45;
659 if (!gap_before) maxwidth = 0.9*gap_after;
else
660 if (!gap_after) maxwidth = 0.9*gap_before;
661 textscale = Math.min(textscale, maxwidth / textwidth);
662 }
else if (vertical && max_text_width && !lcnt && (max_text_width - labeloffset > 20) && (textwidth > max_text_width - labeloffset)) {
663 textscale = Math.min(textscale, (max_text_width - labeloffset) / textwidth);
666 if (lastpos && (pos!=lastpos) && ((vertical && !rotate_lbls) || (!vertical && rotate_lbls))) {
667 var axis_step = Math.abs(pos-lastpos);
668 textscale = Math.min(textscale, 0.9*axis_step/labelsize);
675 this.DrawText({ color: label_color,
676 x: vertical ? side*5 : w+5,
677 y: this.has_obstacle ? fix_coord : (vertical ? -3 : -3*side),
678 align: vertical ? ((side<0) ? 30 : 10) : ( myXor(this.has_obstacle, (side<0)) ? 13 : 10 ),
680 text:
'#times' + this.format10Exp(this.order),
681 draw_g: label_g[lcnt]
686 if ((textscale > 0.01) && (textscale < 0.7) && !vertical && !rotate_lbls && (maxtextlen > 5) && !this.lbls_both_sides) {
691 for (var lcnt = 0; lcnt < label_g.length; ++lcnt) {
692 if ((textscale > 0.01) && (textscale < 1))
693 this.TextScaleFactor(1/textscale, label_g[lcnt]);
695 this.FinishTextDrawing(label_g[lcnt]);
697 label_g[lcnt].selectAll(
"text").each(
function() {
698 var txt = d3.select(
this), tr = txt.attr(
"transform");
699 txt.attr(
"transform", tr +
" rotate(25)").style(
"text-anchor",
"start");
703 if (label_g.length > 1) side = -side;
705 if (labelfont) labelsize = labelfont.size;
708 if (JSROOT.gStyle.Zooming && !
this.disable_zooming) {
709 var r = axis_g.append(
"svg:rect")
710 .attr(
"class",
"axis_zoom")
711 .style(
"opacity",
"0")
712 .style(
"cursor",
"crosshair");
715 r.attr(
"x", (side>0) ? (-2*labelsize - 3) : 3)
717 .attr(
"width", 2*labelsize + 3)
720 r.attr(
"x", 0).attr(
"y", (side>0) ? 0 : -labelsize-3)
721 .attr(
"width", w).attr(
"height", labelsize + 3);
724 if ((axis.fTitle.length > 0) && !disable_axis_drawing) {
725 var title_g = axis_g.append(
"svg:g").attr(
"class",
"axis_title"),
726 title_fontsize = (axis.fTitleSize >= 1) ? axis.fTitleSize : Math.round(axis.fTitleSize * text_scaling_size),
727 title_offest_k = 1.6*(axis.fTitleSize<1 ? axis.fTitleSize : axis.fTitleSize/(this.pad_height(
"") || 10)),
728 center = axis.TestBit(JSROOT.EAxisBits.kCenterTitle),
729 rotate = axis.TestBit(JSROOT.EAxisBits.kRotateTitle) ? -1 : 1,
730 title_color = this.get_color(axis.fTitleColor),
731 shift_x = 0, shift_y = 0;
733 this.StartTextDrawing(axis.fTitleFont, title_fontsize, title_g);
735 var myxor = ((rotate<0) && !reverse) || ((rotate>=0) && reverse);
738 title_offest_k *= -side*pad_w;
740 shift_x = Math.round(title_offest_k*axis.fTitleOffset);
742 if ((this.name ==
"zaxis") && is_gaxis && (
'getBoundingClientRect' in axis_g.node())) {
744 var rect = axis_g.node().getBoundingClientRect();
745 if (shift_x < rect.width - tickSize) shift_x = Math.round(rect.width - tickSize);
748 shift_y = Math.round(center ? h/2 : (reverse ? h : 0));
750 this.DrawText({ align: (center ?
"middle" : (myxor ?
"begin" :
"end" )) +
";middle",
751 rotate: (rotate<0) ? 90 : 270,
752 text: axis.fTitle, color: title_color, draw_g: title_g });
754 title_offest_k *= side*pad_h;
756 shift_x = Math.round(center ? w/2 : (reverse ? 0 : w));
757 shift_y = Math.round(title_offest_k*axis.fTitleOffset);
758 this.DrawText({ align: (center ?
'middle' : (myxor ?
'begin' :
'end')) +
";middle",
759 rotate: (rotate<0) ? 180 : 0,
760 text: axis.fTitle, color: title_color, draw_g: title_g });
763 var axis_rect = null;
764 if (vertical && (axis.fTitleOffset == 0) && (
'getBoundingClientRect' in axis_g.node()))
765 axis_rect = axis_g.node().getBoundingClientRect();
767 this.FinishTextDrawing(title_g,
function() {
769 var title_rect = title_g.node().getBoundingClientRect();
770 shift_x = (side>0) ? Math.round(axis_rect.left - title_rect.right - title_fontsize*0.3) :
771 Math.round(axis_rect.right - title_rect.left + title_fontsize*0.3);
774 title_g.attr(
'transform',
'translate(' + shift_x +
',' + shift_y +
')')
775 .property(
'shift_x', shift_x)
776 .property(
'shift_y', shift_y);
780 this.AddTitleDrag(title_g, vertical, title_offest_k, reverse, vertical ? h : w);
785 if (
'getBoundingClientRect' in axis_g.node()) {
786 var rect1 = axis_g.node().getBoundingClientRect(),
787 rect2 = this.svg_pad().node().getBoundingClientRect();
789 this.position = rect1.left - rect2.left;
793 TAxisPainter.prototype.Redraw =
function() {
795 var gaxis = this.GetObject(),
796 x1 = this.AxisToSvg(
"x", gaxis.fX1),
797 y1 = this.AxisToSvg(
"y", gaxis.fY1),
798 x2 = this.AxisToSvg(
"x", gaxis.fX2),
799 y2 = this.AxisToSvg(
"y", gaxis.fY2),
800 w = x2 - x1, h = y1 - y2,
801 vertical = Math.abs(w) < Math.abs(h),
802 func = null, reverse =
false, kind =
"normal",
803 min = gaxis.fWmin, max = gaxis.fWmax,
804 domain_min = min, domain_max = max;
806 if (gaxis.fChopt.indexOf(
"t")>=0) {
807 func = d3.scaleTime();
809 this.toffset = JSROOT.Painter.getTimeOffset(gaxis);
810 domain_min =
new Date(this.toffset + min*1000);
811 domain_max =
new Date(this.toffset + max*1000);
812 }
else if (gaxis.fChopt.indexOf(
"G")>=0) {
813 func = d3.scaleLog();
816 func = d3.scaleLinear();
820 func.domain([domain_min, domain_max]);
826 var d = y1; y1 = y2; y2 = d;
827 h = -h; reverse =
true;
834 var d = x1; x1 = x2; x2 = d;
835 w = -w; reverse =
true;
840 this.SetAxisConfig(vertical ?
"yaxis" :
"xaxis", kind, func, min, max, min, max);
844 this.DrawAxis(vertical, this.draw_g, w, h,
"translate(" + x1 +
"," + y2 +
")", reverse);
850 function TFramePainter(tframe) {
851 JSROOT.TooltipHandler.call(
this, tframe);
853 this.shrink_frame_left = 0.;
854 this.x_kind =
'normal';
855 this.y_kind =
'normal';
856 this.xmin = this.xmax = 0;
857 this.ymin = this.ymax = 0;
858 this.axes_drawn =
false;
859 this.keys_handler = null;
863 TFramePainter.prototype = Object.create(JSROOT.TooltipHandler.prototype);
865 TFramePainter.prototype.frame_painter =
function() {
871 TFramePainter.prototype.SetActive =
function(on) {
875 TFramePainter.prototype.GetTipName =
function(append) {
876 var res = JSROOT.TooltipHandler.prototype.GetTipName.call(
this) ||
"TFrame";
877 if (append) res+=append;
881 TFramePainter.prototype.Shrink =
function(shrink_left, shrink_right) {
882 this.fX1NDC += shrink_left;
883 this.fX2NDC -= shrink_right;
886 TFramePainter.prototype.SetLastEventPos =
function(pnt) {
888 this.fLastEventPnt = pnt;
891 TFramePainter.prototype.GetLastEventPos =
function() {
893 return this.fLastEventPnt;
896 TFramePainter.prototype.UpdateAttributes =
function(force) {
897 var tframe = this.GetObject();
899 if ((this.fX1NDC === undefined) || (force && !this.modified_NDC)) {
900 JSROOT.extend(
this, JSROOT.gStyle.FrameNDC);
902 if (tframe && tframe.fPos && tframe.fSize) {
903 this.fX1NDC = tframe.fPos.fHoriz.fNormal.fVal;
904 this.fX2NDC = this.fX1NDC + tframe.fSize.fHoriz.fNormal.fVal;
905 this.fY1NDC = tframe.fPos.fVert.fNormal.fVal;
906 this.fY2NDC = this.fY1NDC + tframe.fSize.fVert.fNormal.fVal;
910 if (this.fillatt === undefined) {
911 this.createAttFill({ pattern: 1001, color: 0 });
914 this.fillatt.SetSolidColor(
'white');
917 this.createAttLine({ color:
'black' });
920 TFramePainter.prototype.ProjectAitoff2xy =
function(l, b) {
921 var DegToRad = Math.PI/180,
922 alpha2 = (l/2)*DegToRad,
926 cdec = Math.cos(delta),
927 denom = Math.sqrt(1. + cdec*Math.cos(alpha2)),
929 x: cdec*Math.sin(alpha2)*2.*r2/denom/f/DegToRad,
930 y: Math.sin(delta)*r2/denom/f/DegToRad
936 TFramePainter.prototype.ProjectMercator2xy =
function(l, b) {
937 var aid = Math.tan((Math.PI/2 + b/180*Math.PI)/2);
938 return { x: l, y: Math.log(aid) };
941 TFramePainter.prototype.ProjectSinusoidal2xy =
function(l, b) {
942 return { x: l*Math.cos(b/180*Math.PI), y: b };
945 TFramePainter.prototype.ProjectParabolic2xy =
function(l, b) {
947 x: l*(2.*Math.cos(2*b/180*Math.PI/3) - 1),
948 y: 180*Math.sin(b/180*Math.PI/3)
952 TFramePainter.prototype.RecalculateRange =
function(Proj) {
960 pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymin));
961 pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymax));
962 pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymax));
963 pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymin));
964 if (this.scale_ymin<0 && this.scale_ymax>0) {
966 pnts.push(this.ProjectAitoff2xy(this.scale_xmin*0.9999, 0));
967 pnts.push(this.ProjectAitoff2xy(this.scale_xmax*0.9999, 0));
969 if (this.scale_xmin<0 && this.scale_xmax>0) {
970 pnts.push(this.ProjectAitoff2xy(0, this.scale_ymin));
971 pnts.push(this.ProjectAitoff2xy(0, this.scale_ymax));
973 }
else if (Proj == 2) {
974 if (this.scale_ymin <= -90 || this.scale_ymax >=90) {
975 console.warn(
"Mercator Projection",
"Latitude out of range", this.scale_ymin, this.scale_ymax);
976 this.options.Proj = 0;
979 pnts.push(this.ProjectMercator2xy(this.scale_xmin, this.scale_ymin));
980 pnts.push(this.ProjectMercator2xy(this.scale_xmax, this.scale_ymax));
982 }
else if (Proj == 3) {
983 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymin));
984 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymax));
985 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymax));
986 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymin));
987 if (this.scale_ymin<0 && this.scale_ymax>0) {
988 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, 0));
989 pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, 0));
991 if (this.scale_xmin<0 && this.scale_xmax>0) {
992 pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymin));
993 pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymax));
995 }
else if (Proj == 4) {
996 pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymin));
997 pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymax));
998 pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymax));
999 pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymin));
1000 if (this.scale_ymin<0 && this.scale_ymax>0) {
1001 pnts.push(this.ProjectParabolic2xy(this.scale_xmin, 0));
1002 pnts.push(this.ProjectParabolic2xy(this.scale_xmax, 0));
1004 if (this.scale_xmin<0 && this.scale_xmax>0) {
1005 pnts.push(this.ProjectParabolic2xy(0, this.scale_ymin));
1006 pnts.push(this.ProjectParabolic2xy(0, this.scale_ymax));
1010 this.original_xmin = this.scale_xmin;
1011 this.original_xmax = this.scale_xmax;
1012 this.original_ymin = this.scale_ymin;
1013 this.original_ymax = this.scale_ymax;
1015 this.scale_xmin = this.scale_xmax = pnts[0].x;
1016 this.scale_ymin = this.scale_ymax = pnts[0].y;
1018 for (var n=1;n<pnts.length;++n) {
1019 this.scale_xmin = Math.min(this.scale_xmin, pnts[n].x);
1020 this.scale_xmax = Math.max(this.scale_xmax, pnts[n].x);
1021 this.scale_ymin = Math.min(this.scale_ymin, pnts[n].y);
1022 this.scale_ymax = Math.max(this.scale_ymax, pnts[n].y);
1026 TFramePainter.prototype.DrawGrids =
function() {
1029 var layer = this.svg_frame().select(
".grid_layer");
1031 layer.selectAll(
".xgrid").remove();
1032 layer.selectAll(
".ygrid").remove();
1034 var h = this.frame_height(),
1035 w = this.frame_width(),
1036 grid, grid_style = JSROOT.gStyle.fGridStyle,
1037 grid_color = (JSROOT.gStyle.fGridColor > 0) ? this.get_color(JSROOT.gStyle.fGridColor) :
"black";
1039 if ((grid_style < 0) || (grid_style >= JSROOT.Painter.root_line_styles.length)) grid_style = 11;
1042 if (this.x_handle) {
1044 for (var n=0;n<this.x_handle.ticks.length;++n)
1046 grid +=
"M0,"+this.x_handle.ticks[n]+
"h"+w;
1048 grid +=
"M"+this.x_handle.ticks[n]+
",0v"+h;
1050 if (grid.length > 0)
1051 layer.append(
"svg:path")
1052 .attr(
"class",
"xgrid")
1054 .style(
'stroke',grid_color).style(
"stroke-width",JSROOT.gStyle.fGridWidth)
1055 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]);
1059 if (this.y_handle) {
1061 for (var n=0;n<this.y_handle.ticks.length;++n)
1063 grid +=
"M"+this.y_handle.ticks[n]+
",0v"+h;
1065 grid +=
"M0,"+this.y_handle.ticks[n]+
"h"+w;
1067 if (grid.length > 0)
1068 layer.append(
"svg:path")
1069 .attr(
"class",
"ygrid")
1071 .style(
'stroke',grid_color).style(
"stroke-width",JSROOT.gStyle.fGridWidth)
1072 .style(
"stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]);
1076 TFramePainter.prototype.AxisAsText =
function(axis, value) {
1078 if (this.x_kind ==
'time')
1079 value = this.ConvertX(value);
1080 if (this.x_handle && (
'format' in this.x_handle))
1081 return this.x_handle.format(value,
false, JSROOT.gStyle.XValuesFormat);
1082 }
else if (axis ==
"y") {
1083 if (this.y_kind ==
'time')
1084 value = this.ConvertY(value);
1085 if (this.y_handle && (
'format' in this.y_handle))
1086 return this.y_handle.format(value,
false, JSROOT.gStyle.YValuesFormat);
1088 if (this.z_handle && (
'format' in this.z_handle))
1089 return this.z_handle.format(value,
false, JSROOT.gStyle.ZValuesFormat);
1092 return value.toPrecision(4);
1095 TFramePainter.prototype.SetAxesRanges =
function(xmin, xmax, ymin, ymax) {
1096 if (this.axes_drawn)
return;
1098 if ((this.xmin == this.xmax) && (xmin!==xmax)) {
1102 if ((this.ymin == this.ymax) && (ymin!==ymax)) {
1108 TFramePainter.prototype.DrawAxes =
function(shrink_forbidden) {
1111 if (this.axes_drawn)
return true;
1113 if ((this.xmin==this.xmax) || (this.ymin==this.ymax))
return false;
1120 var layer = this.svg_frame().select(
".axis_layer"),
1121 w = this.frame_width(),
1122 h = this.frame_height(),
1123 axisx = JSROOT.Create(
"TAxis"),
1124 axisy = JSROOT.Create(
"TAxis");
1126 this.x_handle =
new JSROOT.TAxisPainter(axisx,
true);
1127 this.x_handle.SetDivId(this.divid, -1);
1128 this.x_handle.pad_name = this.pad_name;
1130 this.x_handle.SetAxisConfig(
"xaxis",
1131 (this.logx && (this.x_kind !==
"time")) ?
"log" : this.x_kind,
1132 this.x, this.xmin, this.xmax, this.scale_xmin, this.scale_xmax);
1133 this.x_handle.invert_side =
false;
1134 this.x_handle.lbls_both_sides =
false;
1135 this.x_handle.has_obstacle =
false;
1137 this.y_handle =
new JSROOT.TAxisPainter(axisy,
true);
1138 this.y_handle.SetDivId(this.divid, -1);
1139 this.y_handle.pad_name = this.pad_name;
1141 this.y_handle.SetAxisConfig(
"yaxis",
1142 (this.logy && this.y_kind !==
"time") ?
"log" : this.y_kind,
1143 this.y, this.ymin, this.ymax, this.scale_ymin, this.scale_ymax);
1144 this.y_handle.invert_side =
false;
1145 this.y_handle.lbls_both_sides =
false;
1147 var draw_horiz = this.swap_xy ? this.y_handle : this.x_handle,
1148 draw_vertical = this.swap_xy ? this.x_handle : this.y_handle,
1149 disable_axis_draw =
false, show_second_ticks =
false;
1151 if (!disable_axis_draw) {
1152 var pp = this.pad_painter();
1153 if (pp && pp._fast_drawing) disable_axis_draw =
true;
1156 if (!disable_axis_draw) {
1157 draw_horiz.DrawAxis(
false, layer, w, h,
1158 draw_horiz.invert_side ? undefined :
"translate(0," + h +
")",
1159 false, show_second_ticks ? -h : 0, disable_axis_draw);
1161 draw_vertical.DrawAxis(
true, layer, w, h,
1162 draw_vertical.invert_side ?
"translate(" + w +
",0)" : undefined,
1163 false, show_second_ticks ? w : 0, disable_axis_draw,
1164 draw_vertical.invert_side ? 0 :
this.frame_x());
1169 if (!shrink_forbidden && JSROOT.gStyle.CanAdjustFrame && !disable_axis_draw) {
1171 var shrink = 0., ypos = draw_vertical.position;
1173 if ((-0.2*w < ypos) && (ypos < 0)) {
1174 shrink = -ypos/w + 0.001;
1175 this.shrink_frame_left += shrink;
1176 }
else if ((ypos>0) && (ypos<0.3*w) && (this.shrink_frame_left > 0) && (ypos/w > this.shrink_frame_left)) {
1177 shrink = -this.shrink_frame_left;
1178 this.shrink_frame_left = 0.;
1182 this.Shrink(shrink, 0);
1184 this.DrawAxes(
true);
1188 this.axes_drawn =
true;
1193 TFramePainter.prototype.SizeChanged =
function() {
1211 TFramePainter.prototype.CleanXY =
function() {
1213 delete this.x;
delete this.grx;
1214 delete this.ConvertX;
delete this.RevertX;
1215 delete this.y;
delete this.gry;
1216 delete this.ConvertY;
delete this.RevertY;
1217 delete this.z;
delete this.grz;
1220 TFramePainter.prototype.CleanupAxes =
function() {
1222 if (this.x_handle) {
1223 this.x_handle.Cleanup();
1224 delete this.x_handle;
1227 if (this.y_handle) {
1228 this.y_handle.Cleanup();
1229 delete this.y_handle;
1232 if (this.z_handle) {
1233 this.z_handle.Cleanup();
1234 delete this.z_handle;
1237 this.draw_g.select(
".grid_layer").selectAll(
"*").remove();
1238 this.draw_g.select(
".axis_layer").selectAll(
"*").remove();
1240 this.axes_drawn =
false;
1244 TFramePainter.prototype.CleanFrameDrawings =
function() {
1246 if (typeof this.Create3DScene ===
'function')
1247 this.Create3DScene(-1);
1252 this.xmin = this.xmax = 0;
1253 this.ymin = this.ymax = 0;
1254 this.zmin = this.zmax = 0;
1256 this.zoom_xmin = this.zoom_xmax = 0;
1257 this.zoom_ymin = this.zoom_ymax = 0;
1258 this.zoom_zmin = this.zoom_zmax = 0;
1260 this.scale_xmin = this.scale_xmax = 0;
1261 this.scale_ymin = this.scale_ymax = 0;
1262 this.scale_zmin = this.scale_zmax = 0;
1265 this.draw_g.select(
".main_layer").selectAll(
"*").remove();
1266 this.draw_g.select(
".upper_layer").selectAll(
"*").remove();
1270 TFramePainter.prototype.Cleanup =
function() {
1272 this.CleanFrameDrawings();
1275 this.draw_g.selectAll(
"*").remove();
1276 this.draw_g.on(
"mousedown", null)
1277 .on(
"dblclick", null)
1279 .on(
"contextmenu", null)
1280 .property(
'interactive_set', null);
1283 if (this.keys_handler) {
1284 window.removeEventListener(
'keydown', this.keys_handler,
false);
1285 this.keys_handler = null;
1289 delete this._click_handler;
1290 delete this._dblclick_handler;
1292 JSROOT.TooltipHandler.prototype.Cleanup.call(
this);
1295 TFramePainter.prototype.Redraw =
function() {
1297 var pp = this.pad_painter();
1298 if (pp) pp.frame_painter_ref =
this;
1300 if (this.mode3d)
return;
1303 this.UpdateAttributes();
1305 var width = this.pad_width(),
1306 height = this.pad_height(),
1307 lm = Math.round(width * this.fX1NDC),
1308 w = Math.round(width * (this.fX2NDC - this.fX1NDC)),
1309 tm = Math.round(height * (1 - this.fY2NDC)),
1310 h = Math.round(height * (this.fY2NDC - this.fY1NDC)),
1311 rotate =
false, fixpos =
false;
1313 if (pp && pp.options) {
1314 if (pp.options.RotateFrame) rotate =
true;
1315 if (pp.options.FixFrame) fixpos =
true;
1319 this.draw_g = this.svg_layer(
"primitives_layer").select(
".root_frame");
1321 var top_rect, main_svg;
1323 if (this.draw_g.empty()) {
1325 var layer = this.svg_layer(
"primitives_layer");
1327 this.draw_g = layer.append(
"svg:g").attr(
"class",
"root_frame");
1329 this.draw_g.append(
"svg:title").text(
"");
1331 top_rect = this.draw_g.append(
"svg:rect");
1334 this.draw_g.append(
'svg:g').attr(
'class',
'grid_layer');
1336 main_svg = this.draw_g.append(
'svg:svg')
1337 .attr(
'class',
'main_layer')
1340 .attr(
'overflow',
'hidden');
1342 this.draw_g.append(
'svg:g').attr(
'class',
'axis_layer');
1343 this.draw_g.append(
'svg:g').attr(
'class',
'upper_layer');
1345 top_rect = this.draw_g.select(
"rect");
1346 main_svg = this.draw_g.select(
".main_layer");
1349 this.axes_drawn =
false;
1351 var trans =
"translate(" + lm +
"," + tm +
")";
1353 trans +=
" rotate(-90) " +
"translate(" + -h +
",0)";
1354 var d = w; w = h; h = d;
1359 this._frame_width = w;
1360 this._frame_height = h;
1362 this.draw_g.attr(
"transform", trans);
1364 top_rect.attr(
"x", 0)
1368 .call(this.fillatt.func)
1369 .call(this.lineatt.func);
1371 main_svg.attr(
"width", w)
1373 .attr(
"viewBox",
"0 0 " + w +
" " + h);
1377 if (JSROOT.BatchMode)
return;
1379 this.draw_g.attr(
"x", lm)
1384 if (!rotate && !fixpos)
1385 this.AddDrag({ obj:
this, only_resize:
true, minwidth: 20, minheight: 20,
1386 redraw: this.SizeChanged.bind(
this) });
1388 var tooltip_rect = main_svg;
1389 tooltip_rect.style(
"pointer-events",
"visibleFill")
1390 .property(
'handlers_set', 0);
1402 var handlers_set = (pp && pp._fast_drawing) ? 0 : 1;
1404 if (tooltip_rect.property(
'handlers_set') != handlers_set) {
1405 var close_handler = handlers_set ? this.ProcessTooltipEvent.bind(
this, null) : null,
1406 mouse_handler = handlers_set ? this.ProcessTooltipEvent.bind(
this, { handler:
true, touch:
false }) : null;
1408 tooltip_rect.property(
'handlers_set', handlers_set)
1409 .on(
'mouseenter', mouse_handler)
1410 .on(
'mousemove', mouse_handler)
1411 .on(
'mouseleave', close_handler);
1413 if (JSROOT.touches) {
1414 var touch_handler = handlers_set ? this.ProcessTooltipEvent.bind(
this, { handler:
true, touch:
true }) : null;
1416 tooltip_rect.on(
"touchstart", touch_handler)
1417 .on(
"touchmove", touch_handler)
1418 .on(
"touchend", close_handler)
1419 .on(
"touchcancel", close_handler);
1423 tooltip_rect.attr(
"x", 0)
1428 var hintsg = this.hints_layer().select(
".objects_hints");
1430 if (!hintsg.empty() && this.IsTooltipAllowed() && (hintsg.property(
"hints_pad") == this.pad_name))
1431 setTimeout(this.ProcessTooltipEvent.bind(
this, hintsg.property(
'last_point')), 10);
1435 TFramePainter.prototype.GetFrameRect =
function() {
1439 width: this.frame_width(),
1440 height: this.frame_height(),
1441 transform: this.draw_g ? this.draw_g.attr(
"transform") :
"",
1449 TFramePainter.prototype.ProcessFrameClick =
function(pnt, dblckick) {
1451 var pp = this.pad_painter();
1454 pnt.painters =
true;
1455 pnt.disabled =
true;
1458 var hints = pp.GetTooltips(pnt), exact = null;
1459 for (var k=0; (k<hints.length) && !exact; ++k)
1460 if (hints[k] && hints[k].exact) exact = hints[k];
1467 var handler = dblckick ? this._dblclick_handler : this._click_handler;
1468 if (handler) res = handler(exact.user_info, pnt);
1472 pp.SelectObjectPainter(exact ? exact.painter :
this,
1473 { x: pnt.x + (
this._frame_x || 0), y: pnt.y + (
this._frame_y || 0) });
1478 TFramePainter.prototype.ConfigureUserClickHandler =
function(handler) {
1479 this._click_handler = handler && (typeof handler ==
'function') ? handler : null;
1482 TFramePainter.prototype.ConfigureUserDblclickHandler =
function(handler) {
1483 this._dblclick_handler = handler && (typeof handler ==
'function') ? handler : null;
1486 TFramePainter.prototype.Zoom =
function(xmin, xmax, ymin, ymax, zmin, zmax) {
1491 if (this.options && this.options.Proj)
return false;
1493 if (xmin===
"x") { xmin = xmax; xmax = ymin; ymin = undefined; }
else
1494 if (xmin===
"y") { ymax = ymin; ymin = xmax; xmin = xmax = undefined; }
else
1495 if (xmin===
"z") { zmin = xmax; zmax = ymin; xmin = xmax = ymin = undefined; }
1497 var zoom_x = (xmin !== xmax), zoom_y = (ymin !== ymax), zoom_z = (zmin !== zmax),
1498 unzoom_x =
false, unzoom_y =
false, unzoom_z =
false;
1502 if (xmin <= this.xmin) { xmin = this.xmin; cnt++; }
1503 if (xmax >= this.xmax) { xmax = this.xmax; cnt++; }
1504 if (cnt === 2) { zoom_x =
false; unzoom_x =
true; }
1506 unzoom_x = (xmin === xmax) && (xmin === 0);
1511 if (ymin <= this.ymin) { ymin = this.ymin; cnt++; }
1512 if (ymax >= this.ymax) { ymax = this.ymax; cnt++; }
1513 if (cnt === 2) { zoom_y =
false; unzoom_y =
true; }
1515 unzoom_y = (ymin === ymax) && (ymin === 0);
1521 if (zmin <= this.zmin) { zmin = this.zmin; cnt++; }
1522 if (zmax >= this.zmax) { zmax = this.zmax; cnt++; }
1523 if (cnt === 2) { zoom_z =
false; unzoom_z =
true; }
1525 unzoom_z = (zmin === zmax) && (zmin === 0);
1528 var changed =
false, fp =
this;
1531 if (zoom_x || zoom_y || zoom_z)
1532 this.ForEachPainter(
function(obj) {
1533 if (zoom_x && obj.CanZoomIn(
"x", xmin, xmax)) {
1534 fp.zoom_xmin = xmin;
1535 fp.zoom_xmax = xmax;
1539 if (zoom_y && obj.CanZoomIn(
"y", ymin, ymax)) {
1540 fp.zoom_ymin = ymin;
1541 fp.zoom_ymax = ymax;
1545 if (zoom_z && obj.CanZoomIn(
"z", zmin, zmax)) {
1546 fp.zoom_zmin = zmin;
1547 fp.zoom_zmax = zmax;
1554 if (unzoom_x || unzoom_y || unzoom_z) {
1556 if (this.zoom_xmin !== this.zoom_xmax) changed =
true;
1557 this.zoom_xmin = this.zoom_xmax = 0;
1560 if (this.zoom_ymin !== this.zoom_ymax) changed =
true;
1561 this.zoom_ymin = this.zoom_ymax = 0;
1564 if (this.zoom_zmin !== this.zoom_zmax) changed =
true;
1565 this.zoom_zmin = this.zoom_zmax = 0;
1569 if (changed) this.RedrawPad();
1574 TFramePainter.prototype.IsAxisZoomed =
function(axis) {
1575 return this[
'zoom_'+axis+
'min'] !==
this[
'zoom_'+axis+
'max'];
1578 TFramePainter.prototype.Unzoom =
function(dox, doy, doz) {
1579 if (typeof dox ===
'undefined') { dox =
true; doy =
true; doz =
true; }
else
1580 if (typeof dox ===
'string') { doz = dox.indexOf(
"z")>=0; doy = dox.indexOf(
"y")>=0; dox = dox.indexOf(
"x")>=0; }
1582 var last = this.zoom_changed_interactive;
1584 if (dox || doy || doz) this.zoom_changed_interactive = 2;
1586 var changed = this.Zoom(dox ? 0 : undefined, dox ? 0 : undefined,
1587 doy ? 0 : undefined, doy ? 0 : undefined,
1588 doz ? 0 : undefined, doz ? 0 : undefined);
1591 if ((dox || doy || doz) && !changed)
1592 this.zoom_changed_interactive = (!isNaN(last) && (last>0)) ? last - 1 : 0;
1598 TFramePainter.prototype.clearInteractiveElements =
function() {
1599 JSROOT.Painter.closeMenu();
1600 if (this.zoom_rect) { this.zoom_rect.remove(); this.zoom_rect = null; }
1604 this.SwitchTooltip(
true);
1607 TFramePainter.prototype.mouseDoubleClick =
function() {
1608 d3.event.preventDefault();
1609 var m = d3.mouse(this.svg_frame().node());
1610 this.clearInteractiveElements();
1612 var valid_x = (m[0] >= 0) && (m[0] <= this.frame_width()),
1613 valid_y = (m[1] >= 0) && (m[1] <= this.frame_height());
1615 if (valid_x && valid_y && this._dblclick_handler)
1616 if (this.ProcessFrameClick({ x: m[0], y: m[1] },
true))
return;
1619 if (!valid_x) kind = this.swap_xy ?
"x" :
"y";
else
1620 if (!valid_y) kind = this.swap_xy ?
"y" :
"x";
1621 if (this.Unzoom(kind))
return;
1624 TFramePainter.prototype.startRectSel =
function() {
1627 if (this.zoom_kind > 100)
return;
1630 if ((d3.event.which || d3.event.button) !== 1)
return;
1632 d3.event.preventDefault();
1634 var pos = d3.mouse(this.svg_frame().node());
1636 this.clearInteractiveElements();
1637 this.zoom_origin = pos;
1639 var w = this.frame_width(), h = this.frame_height();
1641 this.zoom_curr = [ Math.max(0, Math.min(w,
this.zoom_origin[0])),
1642 Math.max(0, Math.min(h,
this.zoom_origin[1])) ];
1644 if ((this.zoom_origin[0] < 0) || (this.zoom_origin[0] > w)) {
1646 this.zoom_origin[0] = 0;
1647 this.zoom_origin[1] = this.zoom_curr[1];
1648 this.zoom_curr[0] = w;
1649 this.zoom_curr[1] += 1;
1650 }
else if ((this.zoom_origin[1] < 0) || (this.zoom_origin[1] > h)) {
1652 this.zoom_origin[0] = this.zoom_curr[0];
1653 this.zoom_origin[1] = 0;
1654 this.zoom_curr[0] += 1;
1655 this.zoom_curr[1] = h;
1658 this.zoom_origin[0] = this.zoom_curr[0];
1659 this.zoom_origin[1] = this.zoom_curr[1];
1662 d3.select(window).on(
"mousemove.zoomRect", this.moveRectSel.bind(
this))
1663 .on(
"mouseup.zoomRect", this.endRectSel.bind(
this),
true);
1665 this.zoom_rect = null;
1668 this.SwitchTooltip(
false);
1670 d3.event.stopPropagation();
1673 TFramePainter.prototype.moveRectSel =
function() {
1675 if ((this.zoom_kind == 0) || (this.zoom_kind > 100))
return;
1677 d3.event.preventDefault();
1678 var m = d3.mouse(this.svg_frame().node());
1680 m[0] = Math.max(0, Math.min(
this.frame_width(), m[0]));
1681 m[1] = Math.max(0, Math.min(
this.frame_height(), m[1]));
1683 switch (this.zoom_kind) {
1684 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1];
break;
1685 case 2: this.zoom_curr[0] = m[0];
break;
1686 case 3: this.zoom_curr[1] = m[1];
break;
1689 if (this.zoom_rect===null)
1690 this.zoom_rect = this.svg_frame()
1692 .attr(
"class",
"zoom")
1693 .attr(
"pointer-events",
"none");
1695 this.zoom_rect.attr(
"x", Math.min(
this.zoom_origin[0],
this.zoom_curr[0]))
1696 .attr(
"y", Math.min(
this.zoom_origin[1],
this.zoom_curr[1]))
1697 .attr(
"width", Math.abs(
this.zoom_curr[0] -
this.zoom_origin[0]))
1698 .attr(
"height", Math.abs(
this.zoom_curr[1] -
this.zoom_origin[1]));
1701 TFramePainter.prototype.endRectSel =
function() {
1702 if ((this.zoom_kind == 0) || (this.zoom_kind > 100))
return;
1704 d3.event.preventDefault();
1706 d3.select(window).on(
"mousemove.zoomRect", null)
1707 .on(
"mouseup.zoomRect", null);
1709 var m = d3.mouse(this.svg_frame().node()), changed = [
true,
true];
1710 m[0] = Math.max(0, Math.min(
this.frame_width(), m[0]));
1711 m[1] = Math.max(0, Math.min(
this.frame_height(), m[1]));
1713 switch (this.zoom_kind) {
1714 case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1];
break;
1715 case 2: this.zoom_curr[0] = m[0]; changed[1] =
false;
break;
1716 case 3: this.zoom_curr[1] = m[1]; changed[0] =
false;
break;
1719 var xmin, xmax, ymin, ymax, isany =
false,
1720 idx = this.swap_xy ? 1 : 0, idy = 1 - idx;
1722 if (changed[idx] && (Math.abs(
this.zoom_curr[idx] -
this.zoom_origin[idx]) > 10)) {
1723 xmin = Math.min(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx]));
1724 xmax = Math.max(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx]));
1728 if (changed[idy] && (Math.abs(
this.zoom_curr[idy] -
this.zoom_origin[idy]) > 10)) {
1729 ymin = Math.min(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy]));
1730 ymax = Math.max(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy]));
1734 var kind = this.zoom_kind, pnt = (kind===1) ? { x: this.zoom_origin[0], y: this.zoom_origin[1] } : null;
1736 this.clearInteractiveElements();
1739 this.zoom_changed_interactive = 2;
1740 this.Zoom(xmin, xmax, ymin, ymax);
1744 var fp = this.frame_painter();
1745 if (fp) fp.ProcessFrameClick(pnt);
1748 var pp = this.pad_painter();
1749 if (pp) pp.SelectObjectPainter(this.x_handle);
1752 var pp = this.pad_painter();
1753 if (pp) pp.SelectObjectPainter(this.y_handle);
1761 TFramePainter.prototype.startTouchZoom =
function() {
1763 if (this.zoom_kind != 0) {
1764 d3.event.preventDefault();
1765 d3.event.stopPropagation();
1769 var arr = d3.touches(this.svg_frame().node());
1774 if (arr.length == 1) {
1777 var now =
new Date(), diff = now.getTime() - this.last_touch.getTime();
1778 this.last_touch = now;
1780 if ((diff < 300) && this.zoom_curr
1781 && (Math.abs(
this.zoom_curr[0] - arr[0][0]) < 30)
1782 && (Math.abs(
this.zoom_curr[1] - arr[0][1]) < 30)) {
1784 d3.event.preventDefault();
1785 d3.event.stopPropagation();
1787 this.clearInteractiveElements();
1790 this.last_touch =
new Date(0);
1792 this.svg_frame().on(
"touchcancel", null)
1793 .on(
"touchend", null,
true);
1795 if (JSROOT.gStyle.ContextMenu) {
1796 this.zoom_curr = arr[0];
1797 this.svg_frame().on(
"touchcancel", this.endTouchSel.bind(
this))
1798 .on(
"touchend", this.endTouchSel.bind(
this));
1799 d3.event.preventDefault();
1800 d3.event.stopPropagation();
1804 if ((arr.length != 2) || !JSROOT.gStyle.Zooming || !JSROOT.gStyle.ZoomTouch)
return;
1806 d3.event.preventDefault();
1807 d3.event.stopPropagation();
1809 this.clearInteractiveElements();
1811 this.svg_frame().on(
"touchcancel", null)
1812 .on(
"touchend", null);
1814 var pnt1 = arr[0], pnt2 = arr[1], w = this.frame_width(), h = this.frame_height();
1816 this.zoom_curr = [ Math.min(pnt1[0], pnt2[0]), Math.min(pnt1[1], pnt2[1]) ];
1817 this.zoom_origin = [ Math.max(pnt1[0], pnt2[0]), Math.max(pnt1[1], pnt2[1]) ];
1819 if ((this.zoom_curr[0] < 0) || (this.zoom_curr[0] > w)) {
1820 this.zoom_kind = 103;
1821 this.zoom_curr[0] = 0;
1822 this.zoom_origin[0] = w;
1823 }
else if ((this.zoom_origin[1] > h) || (this.zoom_origin[1] < 0)) {
1824 this.zoom_kind = 102;
1825 this.zoom_curr[1] = 0;
1826 this.zoom_origin[1] = h;
1828 this.zoom_kind = 101;
1831 this.SwitchTooltip(
false);
1833 this.zoom_rect = this.svg_frame().append(
"rect")
1834 .attr(
"class",
"zoom")
1835 .attr(
"id",
"zoomRect")
1836 .attr(
"x", this.zoom_curr[0])
1837 .attr(
"y", this.zoom_curr[1])
1838 .attr(
"width", this.zoom_origin[0] - this.zoom_curr[0])
1839 .attr(
"height", this.zoom_origin[1] - this.zoom_curr[1]);
1841 d3.select(window).on(
"touchmove.zoomRect", this.moveTouchSel.bind(
this))
1842 .on(
"touchcancel.zoomRect", this.endTouchSel.bind(
this))
1843 .on(
"touchend.zoomRect", this.endTouchSel.bind(
this));
1846 TFramePainter.prototype.moveTouchSel =
function() {
1847 if (this.zoom_kind < 100)
return;
1849 d3.event.preventDefault();
1851 var arr = d3.touches(this.svg_frame().node());
1853 if (arr.length != 2)
1854 return this.clearInteractiveElements();
1856 var pnt1 = arr[0], pnt2 = arr[1];
1858 if (this.zoom_kind != 103) {
1859 this.zoom_curr[0] = Math.min(pnt1[0], pnt2[0]);
1860 this.zoom_origin[0] = Math.max(pnt1[0], pnt2[0]);
1862 if (this.zoom_kind != 102) {
1863 this.zoom_curr[1] = Math.min(pnt1[1], pnt2[1]);
1864 this.zoom_origin[1] = Math.max(pnt1[1], pnt2[1]);
1867 this.zoom_rect.attr(
"x", this.zoom_curr[0])
1868 .attr(
"y", this.zoom_curr[1])
1869 .attr(
"width", this.zoom_origin[0] - this.zoom_curr[0])
1870 .attr(
"height", this.zoom_origin[1] - this.zoom_curr[1]);
1872 if ((this.zoom_origin[0] - this.zoom_curr[0] > 10)
1873 || (this.zoom_origin[1] - this.zoom_curr[1] > 10))
1874 this.SwitchTooltip(
false);
1876 d3.event.stopPropagation();
1879 TFramePainter.prototype.endTouchSel =
function() {
1881 this.svg_frame().on(
"touchcancel", null)
1882 .on(
"touchend", null);
1884 if (this.zoom_kind === 0) {
1887 d3.event.preventDefault();
1889 var now =
new Date();
1891 var diff = now.getTime() - this.last_touch.getTime();
1893 if ((diff > 500) && (diff<2000) && !this.frame_painter().IsTooltipShown()) {
1894 this.ShowContextMenu(
'main', { clientX: this.zoom_curr[0], clientY: this.zoom_curr[1] });
1895 this.last_touch =
new Date(0);
1897 this.clearInteractiveElements();
1901 if (this.zoom_kind < 100)
return;
1903 d3.event.preventDefault();
1904 d3.select(window).on(
"touchmove.zoomRect", null)
1905 .on(
"touchend.zoomRect", null)
1906 .on(
"touchcancel.zoomRect", null);
1908 var xmin, xmax, ymin, ymax, isany =
false,
1909 xid = this.swap_xy ? 1 : 0, yid = 1 - xid,
1910 changed = [
true,
true];
1911 if (this.zoom_kind === 102) changed[1] =
false;
1912 if (this.zoom_kind === 103) changed[0] =
false;
1914 if (changed[xid] && (Math.abs(
this.zoom_curr[xid] -
this.zoom_origin[xid]) > 10)) {
1915 xmin = Math.min(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid]));
1916 xmax = Math.max(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid]));
1920 if (changed[yid] && (Math.abs(
this.zoom_curr[yid] -
this.zoom_origin[yid]) > 10)) {
1921 ymin = Math.min(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid]));
1922 ymax = Math.max(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid]));
1926 this.clearInteractiveElements();
1927 this.last_touch =
new Date(0);
1930 this.zoom_changed_interactive = 2;
1931 this.Zoom(xmin, xmax, ymin, ymax);
1934 d3.event.stopPropagation();
1937 TFramePainter.prototype.ShowContextMenu =
function(kind, evnt, obj) {
1939 if ((
'zoom_kind' in
this) && (this.zoom_kind > 100))
return;
1948 var menu_painter =
this, frame_corner =
false, fp =
this;
1951 d3.event.preventDefault();
1952 d3.event.stopPropagation();
1955 if (kind === undefined) {
1956 var ms = d3.mouse(this.svg_frame().node()),
1957 tch = d3.touches(this.svg_frame().node()),
1958 pp = this.pad_painter(),
1959 pnt = null, sel = null;
1961 if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch:
true };
else
1962 if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch:
false };
1964 if ((pnt !== null) && (pp !== null)) {
1965 pnt.painters =
true;
1966 var hints = pp.GetTooltips(pnt), bestdist = 1000;
1967 for (var n=0;n<hints.length;++n)
1968 if (hints[n] && hints[n].menu) {
1969 var dist = (
'menu_dist' in hints[n]) ? hints[n].menu_dist : 7;
1970 if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; }
1974 if (sel!==null) menu_painter = sel;
1976 if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20);
1978 this.SetLastEventPos(pnt);
1983 menu_painter.ctx_menu_evnt = evnt;
1985 JSROOT.Painter.createMenu(menu_painter,
function(menu) {
1986 var domenu = menu.painter.FillContextMenu(menu, kind, obj);
1989 if (fp && (!domenu || (frame_corner && (kind!==
"frame") && (fp!=menu.painter))))
1990 domenu = fp.FillContextMenu(menu);
1993 menu.painter.FillObjectExecMenu(menu, kind,
function() {
1995 menu.painter.SwitchTooltip(
false);
1996 menu.show(menu.painter.ctx_menu_evnt, menu.painter.SwitchTooltip.bind(menu.painter,
true) );
2002 TFramePainter.prototype.FillContextMenu =
function(menu, kind, obj) {
2005 this.clearInteractiveElements();
2007 if ((kind==
"x") || (kind==
"y")) {
2012 menu.add(
"header: " + kind.toUpperCase() +
" axis");
2013 menu.add(
"Unzoom", this.Unzoom.bind(
this, kind));
2015 if (
this[kind+
"_kind"] ==
"normal")
2016 menu.addchk(
this[
"log"+kind],
"SetLog"+kind, this.ToggleLog.bind(
this, kind) );
2022 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kMoreLogLabels),
"More log",
2023 function() { faxis.InvertBit(JSROOT.EAxisBits.kMoreLogLabels); this.RedrawPad(); });
2024 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kNoExponent),
"No exponent",
2025 function() { faxis.InvertBit(JSROOT.EAxisBits.kNoExponent); this.RedrawPad(); });
2026 menu.add(
"sub:Labels");
2027 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterLabels),
"Center",
2028 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterLabels); this.RedrawPad(); });
2029 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kLabelsVert),
"Rotate",
2030 function() { faxis.InvertBit(JSROOT.EAxisBits.kLabelsVert); this.RedrawPad(); });
2031 this.AddColorMenuEntry(menu,
"Color", faxis.fLabelColor,
2032 function(arg) { faxis.fLabelColor = parseInt(arg); this.RedrawPad(); });
2033 this.AddSizeMenuEntry(menu,
"Offset", 0, 0.1, 0.01, faxis.fLabelOffset,
2034 function(arg) { faxis.fLabelOffset = parseFloat(arg); this.RedrawPad(); } );
2035 this.AddSizeMenuEntry(menu,
"Size", 0.02, 0.11, 0.01, faxis.fLabelSize,
2036 function(arg) { faxis.fLabelSize = parseFloat(arg); this.RedrawPad(); } );
2037 menu.add(
"endsub:");
2038 menu.add(
"sub:Title");
2039 menu.add(
"SetTitle",
function() {
2040 var t = prompt(
"Enter axis title", faxis.fTitle);
2041 if (t!==null) { faxis.fTitle = t; this.RedrawPad(); }
2043 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterTitle),
"Center",
2044 function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); this.RedrawPad(); });
2045 menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kRotateTitle),
"Rotate",
2046 function() { faxis.InvertBit(JSROOT.EAxisBits.kRotateTitle); this.RedrawPad(); });
2047 this.AddColorMenuEntry(menu,
"Color", faxis.fTitleColor,
2048 function(arg) { faxis.fTitleColor = parseInt(arg); this.RedrawPad(); });
2049 this.AddSizeMenuEntry(menu,
"Offset", 0, 3, 0.2, faxis.fTitleOffset,
2050 function(arg) { faxis.fTitleOffset = parseFloat(arg); this.RedrawPad(); } );
2051 this.AddSizeMenuEntry(menu,
"Size", 0.02, 0.11, 0.01, faxis.fTitleSize,
2052 function(arg) { faxis.fTitleSize = parseFloat(arg); this.RedrawPad(); } );
2053 menu.add(
"endsub:");
2054 menu.add(
"sub:Ticks");
2055 this.AddColorMenuEntry(menu,
"Color", faxis.fAxisColor,
2056 function(arg) { faxis.fAxisColor = parseInt(arg); this.RedrawPad(); });
2057 this.AddSizeMenuEntry(menu,
"Size", -0.05, 0.055, 0.01, faxis.fTickLength,
2058 function(arg) { faxis.fTickLength = parseFloat(arg); this.RedrawPad(); } );
2059 menu.add(
"endsub:");
2064 var alone = menu.size()==0;
2067 menu.add(
"header:Frame");
2069 menu.add(
"separator");
2071 if (this.zoom_xmin !== this.zoom_xmax)
2072 menu.add(
"Unzoom X", this.Unzoom.bind(
this,
"x"));
2073 if (this.zoom_ymin !== this.zoom_ymax)
2074 menu.add(
"Unzoom Y", this.Unzoom.bind(
this,
"y"));
2075 if (this.zoom_zmin !== this.zoom_zmax)
2076 menu.add(
"Unzoom Z", this.Unzoom.bind(
this,
"z"));
2077 menu.add(
"Unzoom all", this.Unzoom.bind(
this,
"xyz"));
2079 menu.addchk(this.logx,
"SetLogx", this.ToggleLog.bind(
this,
"x"));
2080 menu.addchk(this.logy,
"SetLogy", this.ToggleLog.bind(
this,
"y"));
2083 menu.add(
"separator");
2086 menu.addchk(this.IsTooltipAllowed(),
"Show tooltips",
function() {
2087 this.SetTooltipAllowed(
"toggle");
2089 this.FillAttContextMenu(menu,alone ?
"" :
"Frame ");
2090 menu.add(
"separator");
2091 menu.add(
"Save as frame.png",
function() { this.pad_painter().SaveAs(
"png",
'frame',
'frame.png'); });
2092 menu.add(
"Save as frame.svg",
function() { this.pad_painter().SaveAs(
"svg",
'frame',
'frame.svg'); });
2102 TFramePainter.prototype.ShowAxisStatus =
function(axis_name) {
2105 var status_func = this.GetShowStatusFunc();
2107 if (typeof status_func !=
"function")
return;
2109 var taxis = null, hint_name = axis_name, hint_title =
"TAxis",
2110 m = d3.mouse(this.svg_frame().node()),
id = (axis_name==
"x") ? 0 : 1;
2112 if (taxis) { hint_name = taxis.fName; hint_title = taxis.fTitle ||
"histogram TAxis object"; }
2114 if (this.swap_xy)
id = 1-id;
2116 var axis_value = (axis_name==
"x") ? this.RevertX(m[
id]) : this.RevertY(m[
id]);
2118 status_func(hint_name, hint_title, axis_name +
" : " + this.AxisAsText(axis_name, axis_value), m[0]+
","+m[1]);
2121 TFramePainter.prototype.AddInteractive =
function() {
2124 if (JSROOT.BatchMode || (!JSROOT.gStyle.Zooming && !JSROOT.gStyle.ContextMenu))
return;
2126 var pp = this.pad_painter();
2127 if (pp && pp._fast_drawing)
return;
2129 var svg = this.svg_frame();
2131 if (svg.empty())
return;
2133 var svg_x = svg.selectAll(
".xaxis_container"),
2134 svg_y = svg.selectAll(
".yaxis_container");
2136 if (!svg.property(
'interactive_set')) {
2137 this.AddKeysHandler();
2139 this.last_touch =
new Date(0);
2141 this.zoom_rect = null;
2142 this.zoom_origin = null;
2143 this.zoom_curr = null;
2147 if (JSROOT.gStyle.Zooming && (!
this.options || !
this.options.Proj)) {
2148 if (JSROOT.gStyle.ZoomMouse) {
2149 svg.on(
"mousedown", this.startRectSel.bind(
this));
2150 svg.on(
"dblclick", this.mouseDoubleClick.bind(
this));
2152 if (JSROOT.gStyle.ZoomWheel) {
2153 svg.on(
"wheel", this.mouseWheel.bind(
this));
2157 if (JSROOT.touches && ((JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomTouch) || JSROOT.gStyle.ContextMenu))
2158 svg.on(
"touchstart",
this.startTouchZoom.bind(
this));
2160 if (JSROOT.gStyle.ContextMenu) {
2161 if (JSROOT.touches) {
2162 svg_x.on(
"touchstart", this.startTouchMenu.bind(
this,
"x"));
2163 svg_y.on(
"touchstart", this.startTouchMenu.bind(
this,
"y"));
2165 svg.on(
"contextmenu", this.ShowContextMenu.bind(
this));
2166 svg_x.on(
"contextmenu", this.ShowContextMenu.bind(
this,
"x"));
2167 svg_y.on(
"contextmenu", this.ShowContextMenu.bind(
this,
"y"));
2170 svg_x.on(
"mousemove", this.ShowAxisStatus.bind(
this,
"x"));
2171 svg_y.on(
"mousemove", this.ShowAxisStatus.bind(
this,
"y"));
2173 svg.property(
'interactive_set',
true);
2176 TFramePainter.prototype.mouseWheel =
function() {
2177 d3.event.stopPropagation();
2179 d3.event.preventDefault();
2180 this.clearInteractiveElements();
2182 var itemx = { name:
"x", ignore:
false },
2183 itemy = { name:
"y", ignore: !this.AllowDefaultYZooming() },
2184 cur = d3.mouse(this.svg_frame().node()),
2185 w = this.frame_width(), h = this.frame_height();
2187 this.AnalyzeMouseWheelEvent(d3.event,
this.swap_xy ? itemy : itemx, cur[0] / w, (cur[1] >=0) && (cur[1] <= h));
2189 this.AnalyzeMouseWheelEvent(d3.event,
this.swap_xy ? itemx : itemy, 1 - cur[1] / h, (cur[0] >= 0) && (cur[0] <= w));
2191 this.Zoom(itemx.min, itemx.max, itemy.min, itemy.max);
2193 if (itemx.changed || itemy.changed) this.zoom_changed_interactive = 2;
2196 TFramePainter.prototype.AllowDefaultYZooming =
function() {
2201 var pad_painter = this.pad_painter();
2202 if (pad_painter && pad_painter.painters)
2203 for (var k = 0; k < pad_painter.painters.length; ++k) {
2204 var subpainter = pad_painter.painters[k];
2205 if (subpainter && (subpainter.wheel_zoomy!==undefined))
2206 return subpainter.wheel_zoomy;
2213 TFramePainter.prototype.AnalyzeMouseWheelEvent =
function(event, item, dmin, ignore) {
2215 item.min = item.max = undefined;
2216 item.changed =
false;
2217 if (ignore && item.ignore)
return;
2219 var delta = 0, delta_left = 1, delta_right = 1;
2221 if (
'dleft' in item) { delta_left = item.dleft; delta = 1; }
2222 if (
'dright' in item) { delta_right = item.dright; delta = 1; }
2224 if (
'delta' in item) {
2226 }
else if (event && event.wheelDelta !== undefined ) {
2228 delta = -
event.wheelDelta;
2229 }
else if (event && event.deltaY !== undefined ) {
2231 delta =
event.deltaY;
2232 }
else if (event && event.detail !== undefined) {
2233 delta =
event.detail;
2236 if (delta===0)
return;
2237 delta = (delta<0) ? -0.2 : 0.2;
2240 delta_right *= delta;
2242 var lmin = item.min =
this[
"scale_"+item.name+
"min"],
2243 lmax = item.max =
this[
"scale_"+item.name+
"max"],
2244 gmin =
this[item.name+
"min"],
2245 gmax =
this[item.name+
"max"];
2247 if ((item.min === item.max) && (delta<0)) {
2252 if (item.min >= item.max)
return;
2254 if ((dmin>0) && (dmin<1)) {
2255 if (
this[
'log'+item.name]) {
2256 var factor = (item.min>0) ? JSROOT.log10(item.max/item.min) : 2;
2257 if (factor>10) factor = 10;
else if (factor<0.01) factor = 0.01;
2258 item.min = item.min / Math.pow(10, factor*delta_left*dmin);
2259 item.max = item.max * Math.pow(10, factor*delta_right*(1-dmin));
2261 var rx_left = (item.max - item.min), rx_right = rx_left;
2262 if (delta_left>0) rx_left = 1.001 * rx_left / (1-delta_left);
2263 item.min += -delta_left*dmin*rx_left;
2265 if (delta_right>0) rx_right = 1.001 * rx_right / (1-delta_right);
2267 item.max -= -delta_right*(1-dmin)*rx_right;
2269 if (item.min >= item.max)
2270 item.min = item.max = undefined;
2272 if (delta_left !== delta_right) {
2274 if (((item.min < gmin) && (lmin===gmin)) ||
2275 ((item.max > gmax) && (lmax==gmax)))
2276 item.min = item.max = undefined;
2280 item.min = item.max = undefined;
2283 item.changed = ((item.min !== undefined) && (item.max !== undefined));
2286 TFramePainter.prototype.AddKeysHandler =
function() {
2287 if (this.keys_handler || JSROOT.BatchMode || (typeof window ==
'undefined'))
return;
2289 this.keys_handler = this.ProcessKeyPress.bind(
this);
2291 window.addEventListener(
'keydown', this.keys_handler,
false);
2294 TFramePainter.prototype.ProcessKeyPress =
function(evnt) {
2296 var main = this.select_main();
2297 if (main.empty())
return;
2300 switch (evnt.keyCode) {
2301 case 33: key =
"PageUp";
break;
2302 case 34: key =
"PageDown";
break;
2303 case 37: key =
"ArrowLeft";
break;
2304 case 38: key =
"ArrowUp";
break;
2305 case 39: key =
"ArrowRight";
break;
2306 case 40: key =
"ArrowDown";
break;
2307 case 42: key =
"PrintScreen";
break;
2308 case 106: key =
"*";
break;
2309 default:
return false;
2312 if (evnt.shiftKey) key =
"Shift " + key;
2313 if (evnt.altKey) key =
"Alt " + key;
2314 if (evnt.ctrlKey) key =
"Ctrl " + key;
2316 var zoom = { name:
"x", dleft: 0, dright: 0 };
2319 case "ArrowLeft": zoom.dleft = -1; zoom.dright = 1;
break;
2320 case "ArrowRight": zoom.dleft = 1; zoom.dright = -1;
break;
2321 case "Ctrl ArrowLeft": zoom.dleft = zoom.dright = -1;
break;
2322 case "Ctrl ArrowRight": zoom.dleft = zoom.dright = 1;
break;
2323 case "ArrowUp": zoom.name =
"y"; zoom.dleft = 1; zoom.dright = -1;
break;
2324 case "ArrowDown": zoom.name =
"y"; zoom.dleft = -1; zoom.dright = 1;
break;
2325 case "Ctrl ArrowUp": zoom.name =
"y"; zoom.dleft = zoom.dright = 1;
break;
2326 case "Ctrl ArrowDown": zoom.name =
"y"; zoom.dleft = zoom.dright = -1;
break;
2329 if (zoom.dleft || zoom.dright) {
2330 if (!JSROOT.gStyle.Zooming)
return false;
2332 if (this.mode3d && (key.indexOf(
"Ctrl")!==0))
return false;
2333 this.AnalyzeMouseWheelEvent(null, zoom, 0.5);
2334 this.Zoom(zoom.name, zoom.min, zoom.max);
2335 if (zoom.changed) this.zoom_changed_interactive = 2;
2336 evnt.stopPropagation();
2337 evnt.preventDefault();
2339 var pp = this.pad_painter(),
2340 func = pp ? pp.FindButton(key) :
"";
2342 pp.PadButtonClick(func);
2343 evnt.stopPropagation();
2344 evnt.preventDefault();
2351 TFramePainter.prototype.CreateXY =
function() {
2361 this.swap_xy =
false;
2362 this.reverse_x =
false;
2363 this.reverse_y =
false;
2366 this.logx = this.logy =
false;
2368 var w = this.frame_width(), h = this.frame_height();
2370 this.scale_xmin = this.xmin;
2371 this.scale_xmax = this.xmax;
2373 this.scale_ymin = this.ymin;
2374 this.scale_ymax = this.ymax;
2387 if (this._xaxis_timedisplay) {
2388 this.x_kind =
'time';
2389 this.timeoffsetx = JSROOT.Painter.getTimeOffset();
2390 this.ConvertX =
function(x) {
return new Date(this.timeoffsetx + x*1000); };
2391 this.RevertX =
function(grx) {
return (this.x.invert(grx) - this.timeoffsetx) / 1000; };
2393 this.x_kind =
'normal';
2394 this.ConvertX =
function(x) {
return x; };
2395 this.RevertX =
function(grx) {
return this.x.invert(grx); };
2398 if (this.zoom_xmin != this.zoom_xmax) {
2399 this.scale_xmin = this.zoom_xmin;
2400 this.scale_xmax = this.zoom_xmax;
2403 if (this.x_kind ==
'time') {
2404 this.x = d3.scaleTime();
2405 }
else if (this.logx) {
2406 if (this.scale_xmax <= 0) this.scale_xmax = 1;
2407 if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax))
2408 this.scale_xmin = this.scale_xmax * 0.0001;
2410 this.x = d3.scaleLog();
2412 this.x = d3.scaleLinear();
2415 var gr_range_x = this.reverse_x ? [ w, 0 ] : [ 0, w ],
2416 gr_range_y = this.reverse_y ? [ 0, h ] : [ h, 0 ];
2418 this.x.domain([this.ConvertX(this.scale_xmin), this.ConvertX(this.scale_xmax)])
2419 .range(this.swap_xy ? gr_range_y : gr_range_x);
2421 if (this.x_kind ==
'time') {
2423 this.grx =
function(val) {
return this.x(this.ConvertX(val)); }
2424 }
else if (this.logx) {
2425 this.grx =
function(val) {
return (val < this.scale_xmin) ? (this.swap_xy ? this.x.range()[0]+5 : -5) : this.x(val); }
2430 if (this.zoom_ymin != this.zoom_ymax) {
2431 this.scale_ymin = this.zoom_ymin;
2432 this.scale_ymax = this.zoom_ymax;
2435 if (this._yaxis_timedisplay) {
2436 this.y_kind =
'time';
2437 this.timeoffsety = JSROOT.Painter.getTimeOffset();
2438 this.ConvertY =
function(y) {
return new Date(this.timeoffsety + y*1000); };
2439 this.RevertY =
function(gry) {
return (this.y.invert(gry) - this.timeoffsety) / 1000; };
2441 this.y_kind =
'normal';
2442 this.ConvertY =
function(y) {
return y; };
2443 this.RevertY =
function(gry) {
return this.y.invert(gry); };
2447 if (this.scale_ymax <= 0) this.scale_ymax = 1;
2448 if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax))
2449 this.scale_ymin = 3e-4 * this.scale_ymax;
2451 this.y = d3.scaleLog();
2452 }
else if (this.y_kind ==
'time') {
2453 this.y = d3.scaleTime();
2455 this.y = d3.scaleLinear()
2458 this.y.domain([ this.ConvertY(this.scale_ymin), this.ConvertY(this.scale_ymax) ])
2459 .range(this.swap_xy ? gr_range_x : gr_range_y);
2461 if (this.y_kind==
'time') {
2463 this.gry =
function(val) {
return this.y(this.ConvertY(val)); }
2464 }
else if (this.logy) {
2466 this.gry =
function(val) {
return (val < this.scale_ymin) ? (this.swap_xy ? -5 : this.y.range()[0]+5) : this.y(val); }
2475 TFramePainter.prototype.SetRootPadRange =
function(pad, is3d) {
2518 TFramePainter.prototype.ToggleLog =
function(axis) {
2519 var painter = this.main_painter() ||
this,
2520 pad = this.root_pad();
2521 var curr = pad[
"fLog" + axis];
2524 var kind =
this[axis+
"_kind"];
2525 if (this.swap_xy && axis===
"x") kind =
this[
"y_kind"];
else
2526 if (this.swap_xy && axis===
"y") kind =
this[
"x_kind"];
2527 if (kind ===
"labels")
return;
2530 var pp = this.pad_painter(), canp = this.canv_painter();
2531 if (pp && pp.snapid && canp && canp._websocket) {
2532 console.warn(
'Change log scale on server here!!!!');
2535 pad[
"fLog" + axis] = curr ? 0 : 1;
2536 painter.RedrawPad();
2540 function drawFrame(divid, obj, opt) {
2541 var p =
new TFramePainter(obj);
2542 if (opt ==
"3d") p.mode3d =
true;
2543 p.SetDivId(divid, 2);
2545 return p.DrawingReady();
2550 function TPadPainter(pad, iscan) {
2551 JSROOT.TObjectPainter.call(
this, pad);
2552 this.csstype =
"pad";
2555 this.this_pad_name =
"";
2556 if (!this.iscan && (pad !== null)) {
2558 this.this_pad_name =
"pad" + pad.fObjectID;
2560 this.this_pad_name =
"ppp" + JSROOT.id_counter++;
2563 this.has_canvas =
true;
2566 TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
2568 TPadPainter.prototype.Cleanup =
function() {
2571 for (var k=0;k<this.painters.length;++k)
2572 this.painters[k].Cleanup();
2574 var svg_p = this.svg_pad(this.this_pad_name);
2575 if (!svg_p.empty()) {
2576 svg_p.property(
'pad_painter', null);
2577 svg_p.property(
'mainpainter', null);
2578 if (!this.iscan) svg_p.remove();
2581 delete this.frame_painter_ref;
2582 delete this.pads_cache;
2585 this.draw_object = null;
2586 this.pad_frame = null;
2587 this.this_pad_name =
"";
2588 this.has_canvas =
false;
2590 JSROOT.Painter.SelectActivePad({ pp:
this, active:
false });
2592 JSROOT.TObjectPainter.prototype.Cleanup.call(
this);
2599 TPadPainter.prototype.CleanPrimitives =
function(selector) {
2600 if (!selector || (typeof selector !==
'function'))
return;
2602 for (var k = this.painters.length-1; k >= 0; --k)
2603 if (selector(this.painters[k])) {
2604 this.painters[k].Cleanup();
2605 this.painters.splice(k, 1);
2613 TPadPainter.prototype.ForEachPainterInPad =
function(userfunc, kind) {
2614 if (!kind) kind =
"all";
2615 if (kind!=
"objects") userfunc(
this);
2616 for (var k = 0; k < this.painters.length; ++k) {
2617 var sub = this.painters[k];
2618 if (typeof sub.ForEachPainterInPad ===
'function') {
2619 if (kind!=
"objects") sub.ForEachPainterInPad(userfunc, kind);
2620 }
else if (kind !=
"pads") userfunc(sub);
2624 TPadPainter.prototype.ButtonSize =
function(fact) {
2625 return Math.round((!fact ? 1 : fact) * (this.iscan || !this.has_canvas ? 16 : 12));
2628 TPadPainter.prototype.RegisterForPadEvents =
function(receiver) {
2629 this.pad_events_receiver = receiver;
2632 TPadPainter.prototype.SelectObjectPainter =
function(_painter, pos) {
2635 var istoppad = (this.iscan || !this.has_canvas),
2636 canp = istoppad ?
this : this.canv_painter(),
2637 pp = _painter instanceof TPadPainter ? _painter : _painter.pad_painter();
2639 if (pos && !istoppad)
2640 this.CalcAbsolutePosition(this.svg_pad(this.this_pad_name), pos);
2642 JSROOT.Painter.SelectActivePad({ pp: pp, active:
true });
2644 if (typeof canp.SelectActivePad ==
"function")
2645 canp.SelectActivePad(pp, _painter, pos);
2647 if (canp.pad_events_receiver)
2648 canp.pad_events_receiver({ what:
"select", padpainter: pp, painter: _painter, position: pos });
2653 TPadPainter.prototype.SetActive =
function(on) {
2654 var fp = this.frame_painter();
2655 if (fp && (typeof fp.SetActive ==
'function')) fp.SetActive(on);
2658 TPadPainter.prototype.CreateCanvasSvg =
function(check_resize, new_size) {
2660 var factor = null, svg = null, lmt = 5, rect = null, btns;
2662 if (check_resize > 0) {
2664 if (this._fixed_size)
return (check_resize > 1);
2666 svg = this.svg_canvas();
2668 if (svg.empty())
return false;
2670 factor = svg.property(
'height_factor');
2672 rect = this.check_main_resize(check_resize, null, factor);
2674 if (!rect.changed)
return false;
2676 btns = this.svg_layer(
"btns_layer");
2680 var render_to = this.select_main();
2682 if (render_to.style(
'position')==
'static')
2683 render_to.style(
'position',
'relative');
2685 svg = render_to.append(
"svg")
2686 .attr(
"class",
"jsroot root_canvas")
2687 .property(
'pad_painter',
this)
2688 .property(
'mainpainter', null)
2689 .property(
'current_pad',
"")
2690 .property(
'redraw_by_resize',
false);
2692 svg.append(
"svg:title").text(
"ROOT canvas");
2693 var frect = svg.append(
"svg:rect").attr(
"class",
"canvas_fillrect")
2694 .attr(
"x",0).attr(
"y",0);
2695 if (!JSROOT.BatchMode)
2696 frect.style(
"pointer-events",
"visibleFill")
2697 .on(
"dblclick", this.EnlargePad.bind(
this))
2698 .on(
"click", this.SelectObjectPainter.bind(
this,
this))
2699 .on(
"mouseenter", this.ShowObjectStatus.bind(
this));
2701 svg.append(
"svg:g").attr(
"class",
"primitives_layer");
2702 svg.append(
"svg:g").attr(
"class",
"info_layer");
2703 btns = svg.append(
"svg:g").attr(
"class",
"btns_layer")
2704 .property(
'leftside', JSROOT.gStyle.ToolBarSide ==
'left')
2705 .property(
'vertical', JSROOT.gStyle.ToolBarVert);
2707 if (JSROOT.gStyle.ContextMenu)
2708 svg.select(
".canvas_fillrect").on(
"contextmenu", this.ShowContextMenu.bind(
this));
2711 if (this.pad && this.pad.fCw &&
this.pad.fCh && (
this.pad.fCw > 0)) {
2712 factor = this.pad.fCh / this.pad.fCw;
2713 if ((factor < 0.1) || (factor > 10)) factor = 0.66;
2716 if (this._fixed_size) {
2717 render_to.style(
"overflow",
"auto");
2718 rect = { width: this.pad.fCw, height: this.pad.fCh };
2720 rect = this.check_main_resize(2, new_size, factor);
2726 if ((rect.width<=lmt) || (rect.height<=lmt)) {
2727 svg.style(
"display",
"none");
2728 console.warn(
"Hide canvas while geometry too small w=",rect.width,
" h=",rect.height);
2729 rect.width = 200; rect.height = 100;
2731 svg.style(
"display", null);
2734 if (this._fixed_size) {
2737 .attr(
"width", rect.width)
2738 .attr(
"height", rect.height)
2739 .style(
"position",
"absolute");
2743 .style(
"width",
"100%")
2744 .style(
"height",
"100%")
2745 .style(
"position",
"absolute")
2749 .style(
"bottom", 0);
2754 svg.attr(
"viewBox",
"0 0 " + rect.width +
" " + rect.height)
2755 .attr(
"preserveAspectRatio",
"none")
2756 .property(
'height_factor', factor)
2757 .property(
'draw_x', 0)
2758 .property(
'draw_y', 0)
2759 .property(
'draw_width', rect.width)
2760 .property(
'draw_height', rect.height);
2767 this._fast_drawing = JSROOT.gStyle.SmallPad && ((rect.width < JSROOT.gStyle.SmallPad.width) || (rect.height < JSROOT.gStyle.SmallPad.height));
2769 this.AlignBtns(btns, rect.width, rect.height, svg);
2774 TPadPainter.prototype.EnlargePad =
function() {
2777 d3.event.preventDefault();
2778 d3.event.stopPropagation();
2781 var svg_can = this.svg_canvas(),
2782 pad_enlarged = svg_can.property(
"pad_enlarged");
2784 if (this.iscan || !this.has_canvas || (!pad_enlarged && !this.HasObjectsToDraw() && !this.painters)) {
2785 if (this._fixed_size)
return;
2786 if (!this.enlarge_main(
'toggle'))
return;
2787 if (this.enlarge_main(
'state')==
'off') svg_can.property(
"pad_enlarged", null);
2788 }
else if (!pad_enlarged) {
2789 this.enlarge_main(
true,
true);
2790 svg_can.property(
"pad_enlarged", this.pad);
2791 }
else if (pad_enlarged === this.pad) {
2792 this.enlarge_main(
false);
2793 svg_can.property(
"pad_enlarged", null);
2795 console.error(
'missmatch with pad double click events');
2798 var was_fast = this._fast_drawing;
2800 this.CheckResize({ force:
true });
2802 if (this._fast_drawing != was_fast)
2806 TPadPainter.prototype.CreatePadSvg =
function(only_resize) {
2809 if (!this.has_canvas) {
2810 this.CreateCanvasSvg(only_resize ? 2 : 0);
2814 var svg_parent = this.svg_pad(),
2815 svg_can = this.svg_canvas(),
2816 width = svg_parent.property(
"draw_width"),
2817 height = svg_parent.property(
"draw_height"),
2818 pad_enlarged = svg_can.property(
"pad_enlarged"),
2819 pad_visible = !pad_enlarged || (pad_enlarged === this.pad),
2820 w = width, h = height, x = 0, y = 0,
2821 svg_pad = null, svg_rect = null, btns = null;
2823 if (this.pad && this.pad.fPos &&
this.pad.fSize) {
2824 x = Math.round(width * this.pad.fPos.fHoriz.fArr[0]);
2825 y = Math.round(height * this.pad.fPos.fVert.fArr[0]);
2826 w = Math.round(width * this.pad.fSize.fHoriz.fArr[0]);
2827 h = Math.round(height * this.pad.fSize.fVert.fArr[0]);
2830 if (pad_enlarged === this.pad) { w = width; h = height; x = y = 0; }
2833 svg_pad = this.svg_pad(this.this_pad_name);
2834 svg_rect = svg_pad.select(
".root_pad_border");
2835 btns = this.svg_layer(
"btns_layer", this.this_pad_name);
2837 svg_pad = svg_parent.select(
".primitives_layer")
2839 .classed(
"__root_pad_" + this.this_pad_name,
true)
2840 .attr(
"pad", this.this_pad_name)
2841 .property(
'pad_painter',
this)
2842 .property(
'mainpainter', null);
2843 svg_rect = svg_pad.append(
"svg:rect").attr(
"class",
"root_pad_border");
2845 svg_pad.append(
"svg:g").attr(
"class",
"primitives_layer");
2846 btns = svg_pad.append(
"svg:g").attr(
"class",
"btns_layer")
2847 .property(
'leftside', JSROOT.gStyle.ToolBarSide !=
'left')
2848 .property(
'vertical', JSROOT.gStyle.ToolBarVert);
2850 if (JSROOT.gStyle.ContextMenu)
2851 svg_rect.on(
"contextmenu", this.ShowContextMenu.bind(
this));
2853 if (!JSROOT.BatchMode)
2854 svg_rect.attr(
"pointer-events",
"visibleFill")
2855 .on(
"dblclick", this.EnlargePad.bind(
this))
2856 .on(
"click", this.SelectObjectPainter.bind(
this,
this))
2857 .on(
"mouseenter", this.ShowObjectStatus.bind(
this));
2860 this.createAttFill({ attr: this.pad });
2862 this.createAttLine({ attr: this.pad, color0: this.pad.fBorderMode == 0 ?
'none' :
'' });
2866 .attr(
"display", pad_visible ? null :
"none")
2867 .attr(
"viewBox",
"0 0 " + w +
" " + h)
2868 .attr(
"preserveAspectRatio",
"none")
2873 .property(
'draw_x', x)
2874 .property(
'draw_y', y)
2875 .property(
'draw_width', w)
2876 .property(
'draw_height', h);
2878 svg_rect.attr(
"x", 0)
2882 .call(this.fillatt.func)
2883 .call(this.lineatt.func);
2885 this._fast_drawing = JSROOT.gStyle.SmallPad && ((w < JSROOT.gStyle.SmallPad.width) || (h < JSROOT.gStyle.SmallPad.height));
2887 if (svg_pad.property(
'can3d') === 1)
2890 .select(
".draw3d_" + this.this_pad_name)
2891 .style(
'display', pad_visible ?
'' :
'none');
2893 this.AlignBtns(btns, w, h);
2898 TPadPainter.prototype.RemovePrimitive =
function(obj) {
2899 if (!this.pad || !this.pad.fPrimitives)
return;
2900 var indx = this.pad.fPrimitives.arr.indexOf(obj);
2901 if (indx>=0) this.pad.fPrimitives.RemoveAt(indx);
2904 TPadPainter.prototype.FindPrimitive =
function(exact_obj, classname, name) {
2905 if (!this.pad || !this.pad.fPrimitives)
return null;
2907 for (var i=0; i < this.pad.fPrimitives.arr.length; i++) {
2908 var obj = this.pad.fPrimitives.arr[i];
2910 if ((exact_obj!==null) && (obj !== exact_obj))
continue;
2912 if ((classname !== undefined) && (classname !== null))
2913 if (obj._typename !== classname)
continue;
2915 if ((name !== undefined) && (name !== null))
2916 if (obj.fName !== name)
continue;
2924 TPadPainter.prototype.HasObjectsToDraw =
function() {
2927 var arr = this.pad ? this.pad.fPrimitives : null;
2930 for (var n=0;n<arr.length;++n)
2931 if (arr[n] && arr[n]._typename !=
"ROOT::Experimental::RPadDisplayItem")
return true;
2936 TPadPainter.prototype.DrawPrimitives =
function(indx, callback, ppainter) {
2940 this._doing_pad_draw =
true;
2943 this._start_tm = this._lasttm_tm =
new Date().getTime();
2946 this._num_primitives = this.pad && this.pad.fPrimitives ? this.pad.fPrimitives.length : 0;
2950 if (ppainter && (typeof ppainter==
'object')) ppainter._primitive =
true;
2952 if (!this.pad || (indx >= this.pad.fPrimitives.length)) {
2953 delete this._doing_pad_draw;
2954 delete this._current_primitive_indx;
2956 if (this._start_tm) {
2957 var spenttm =
new Date().getTime() - this._start_tm;
2958 if (spenttm > 3000) console.log(
"Canvas drawing took " + (spenttm*1e-3).toFixed(2) +
"s");
2959 delete this._start_tm;
2960 delete this._lasttm_tm;
2963 return JSROOT.CallBack(callback);
2967 var handle = { func: this.DrawPrimitives.bind(
this, indx+1, callback) };
2970 this._current_primitive_indx = indx;
2972 ppainter = JSROOT.draw(this.divid, this.pad.fPrimitives[indx],
"", handle);
2976 if (!handle.completed)
return;
2978 if (!JSROOT.BatchMode &&
this.iscan) {
2979 var curtm =
new Date().getTime();
2980 if (curtm > this._lasttm_tm + 500) {
2981 this._lasttm_tm = curtm;
2982 ppainter._primitive =
true;
2983 return requestAnimationFrame(handle.func);
2989 TPadPainter.prototype.GetTooltips =
function(pnt) {
2990 var painters = [], hints = [];
2993 if (this.painters !== null)
2994 this.painters.forEach(
function(obj) {
2995 if (
'ProcessTooltip' in obj) painters.push(obj);
2998 if (pnt) pnt.nproc = painters.length;
3000 painters.forEach(
function(obj) {
3001 var hint = obj.ProcessTooltip(pnt);
3002 if (!hint) hint = { user_info: null };
3004 if (hint && pnt && pnt.painters) hint.painter = obj;
3010 TPadPainter.prototype.FillContextMenu =
function(menu) {
3013 menu.add(
"header: " + this.pad._typename +
"::" +
this.pad.fName);
3015 menu.add(
"header: Canvas");
3017 menu.addchk(this.IsTooltipAllowed(),
"Show tooltips", this.SetTooltipAllowed.bind(
this,
"toggle"));
3019 if (!this._websocket) {
3021 function ToggleGridField(arg) {
3022 this.pad[arg] = this.pad[arg] ? 0 : 1;
3023 var main = this.svg_pad(this.this_pad_name).property(
'mainpainter');
3024 if (main && (typeof main.DrawGrids ==
'function')) main.DrawGrids();
3027 function SetTickField(arg) {
3028 this.pad[arg.substr(1)] = parseInt(arg[0]);
3030 var main = this.svg_pad(this.this_pad_name).property(
'mainpainter');
3031 if (main && (typeof main.DrawAxes ==
'function')) main.DrawAxes();
3034 menu.addchk(this.pad.fGridx,
'Grid x',
'fGridx', ToggleGridField);
3035 menu.addchk(this.pad.fGridy,
'Grid y',
'fGridy', ToggleGridField);
3036 menu.add(
"sub:Ticks x");
3037 menu.addchk(this.pad.fTickx == 0,
"normal",
"0fTickx", SetTickField);
3038 menu.addchk(this.pad.fTickx == 1,
"ticks on both sides",
"1fTickx", SetTickField);
3039 menu.addchk(this.pad.fTickx == 2,
"labels up",
"2fTickx", SetTickField);
3040 menu.add(
"endsub:");
3041 menu.add(
"sub:Ticks y");
3042 menu.addchk(this.pad.fTicky == 0,
"normal",
"0fTicky", SetTickField);
3043 menu.addchk(this.pad.fTicky == 1,
"ticks on both side",
"1fTicky", SetTickField);
3044 menu.addchk(this.pad.fTicky == 2,
"labels right",
"2fTicky", SetTickField);
3045 menu.add(
"endsub:");
3050 this.FillAttContextMenu(menu);
3053 menu.add(
"separator");
3055 if (this.ToggleEventStatus)
3056 menu.addchk(this.HasEventStatus(),
"Event status", this.ToggleEventStatus.bind(
this));
3058 if (this.enlarge_main() || (this.has_canvas && this.HasObjectsToDraw()))
3059 menu.addchk((this.enlarge_main(
'state')==
'on'),
"Enlarge " + (this.iscan ?
"canvas" :
"pad"), this.EnlargePad.bind(
this));
3061 var fname = this.this_pad_name;
3062 if (fname.length===0) fname = this.iscan ?
"canvas" :
"pad";
3063 menu.add(
"Save as "+fname+
".png", fname+
".png", this.SaveAs.bind(
this,
"png",
false));
3064 menu.add(
"Save as "+fname+
".svg", fname+
".svg", this.SaveAs.bind(
this,
"svg",
false));
3069 TPadPainter.prototype.ShowContextMenu =
function(evnt) {
3072 var pos = d3.mouse(this.svg_pad(this.this_pad_name).node());
3074 if (pos && (pos.length==2) && (pos[0]>0) && (pos[0]<10) && (pos[1]>0) && pos[1]<10)
return;
3076 d3.event.stopPropagation();
3077 d3.event.preventDefault();
3082 var fp = this.frame_painter();
3083 if (fp) fp.SetLastEventPos();
3086 JSROOT.Painter.createMenu(
this,
function(menu) {
3088 menu.painter.FillContextMenu(menu);
3090 menu.painter.FillObjectExecMenu(menu,
"",
function() { menu.show(evnt); });
3094 TPadPainter.prototype.Redraw =
function(resize) {
3097 if (this._doing_pad_draw)
return console.log(
'Prevent redrawing', this.pad.fName);
3099 var showsubitems =
true;
3102 this.CreateCanvasSvg(2);
3104 showsubitems = this.CreatePadSvg(
true);
3108 for (var i = 0; i < this.painters.length; ++i) {
3109 var sub = this.painters[i];
3110 if (showsubitems || sub.this_pad_name) sub.Redraw(resize);
3114 TPadPainter.prototype.NumDrawnSubpads =
function() {
3115 if (this.painters === undefined)
return 0;
3119 for (var i = 0; i < this.painters.length; ++i) {
3120 var obj = this.painters[i].GetObject();
3121 if (obj && (obj._typename ===
"TPad")) num++;
3127 TPadPainter.prototype.RedrawByResize =
function() {
3128 if (this.access_3d_kind() === 1)
return true;
3130 for (var i = 0; i < this.painters.length; ++i)
3131 if (typeof this.painters[i].RedrawByResize ===
'function')
3132 if (this.painters[i].RedrawByResize())
return true;
3137 TPadPainter.prototype.CheckCanvasResize =
function(size, force) {
3139 if (!this.iscan && this.has_canvas)
return false;
3141 if ((size ===
true) || (size ===
false)) { force = size; size = null; }
3143 if (size && (typeof size ===
'object') && size.force) force =
true;
3145 if (!force) force = this.RedrawByResize();
3147 var changed = this.CreateCanvasSvg(force ? 2 : 1, size);
3152 for (var i = 0; i < this.painters.length; ++i)
3153 this.painters[i].Redraw(force ?
false :
true);
3158 TPadPainter.prototype.UpdateObject =
function(obj) {
3159 if (!obj)
return false;
3161 this.pad.fCw = obj.fCw;
3162 this.pad.fCh = obj.fCh;
3163 this.pad.fTitle = obj.fTitle;
3168 TPadPainter.prototype.DrawNextSnap =
function(lst, indx, call_back, objpainter) {
3174 this._doing_pad_draw =
true;
3175 this._snaps_map = {};
3176 this._num_primitives = lst ? lst.length : 0;
3180 if (objpainter ===
"workaround") { --indx; objpainter = null; }
3184 if (objpainter && lst && lst[indx] && objpainter.snapid === undefined) {
3186 if (this.painters.indexOf(objpainter)<0) this.painters.push(objpainter);
3187 objpainter.snapid = lst[indx].fObjectID;
3188 objpainter.rstyle = lst[indx].fStyle;
3195 if (!lst || indx >= lst.length) {
3196 delete this._doing_pad_draw;
3197 delete this._snaps_map;
3198 delete this._current_primitive_indx;
3199 return JSROOT.CallBack(call_back,
this);
3202 var snap = lst[indx],
3203 snapid = snap.fObjectID,
3204 cnt = this._snaps_map[snapid];
3206 if (cnt) cnt++;
else cnt=1;
3207 this._snaps_map[snapid] = cnt;
3209 this._current_primitive_indx = indx;
3213 for (var k=0; k<this.painters.length; ++k) {
3214 if (this.painters[k].snapid === snapid)
3215 if (--cnt === 0) { objpainter = this.painters[k];
break; }
3219 var draw_callback = this.DrawNextSnap.bind(
this, lst, indx, call_back);
3223 if (snap._typename ==
"ROOT::Experimental::RPadDisplayItem")
3224 return objpainter.RedrawPadSnap(snap, draw_callback);
3226 if (objpainter.UpdateObject(snap.fDrawable || snap.fObject, snap.fOption ||
""))
3227 objpainter.Redraw();
3232 if (snap._typename ==
"ROOT::Experimental::RPadDisplayItem") {
3236 var padpainter =
new TPadPainter(subpad,
false);
3237 padpainter.DecodeOptions(
"");
3238 padpainter.SetDivId(this.divid);
3239 padpainter.snapid = snap.fObjectID;
3240 padpainter.rstyle = snap.fStyle;
3242 padpainter.CreatePadSvg();
3244 if (snap.fPrimitives && snap.fPrimitives.length > 0) {
3245 padpainter.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"PadSnapShot");
3246 padpainter.AddButton(JSROOT.ToolbarIcons.circle,
"Enlarge pad",
"EnlargePad");
3248 if (JSROOT.gStyle.ContextMenu)
3249 padpainter.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
3253 var prev_name = padpainter.CurrentPadName(padpainter.this_pad_name);
3255 padpainter.DrawNextSnap(snap.fPrimitives, -1,
function() {
3256 padpainter.CurrentPadName(prev_name);
3257 draw_callback(padpainter);
3262 var handle = { func: draw_callback };
3264 if (snap._typename ===
"ROOT::Experimental::RObjectDisplayItem")
3265 if (!this.frame_painter())
3266 return JSROOT.draw(
this.divid, { _typename:
"TFrame", $dummy:
true },
"",
function() {
3267 handle.func(
"workaround");
3271 objpainter = JSROOT.draw(this.divid, snap.fDrawable || snap.fObject, snap.fOption ||
"", handle);
3273 if (!handle.completed)
return;
3277 TPadPainter.prototype.FindSnap =
function(snapid) {
3279 if (this.snapid === snapid)
return this;
3281 if (!this.painters)
return null;
3283 for (var k=0;k<this.painters.length;++k) {
3284 var sub = this.painters[k];
3286 if (typeof sub.FindSnap ===
'function') sub = sub.FindSnap(snapid);
3287 else if (sub.snapid !== snapid) sub = null;
3289 if (sub)
return sub;
3295 TPadPainter.prototype.AddOnlineButtons =
function() {
3296 this.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"CanvasSnapShot",
"Ctrl PrintScreen");
3297 if (JSROOT.gStyle.ContextMenu)
3298 this.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
3300 if (this.enlarge_main(
'verify'))
3301 this.AddButton(JSROOT.ToolbarIcons.circle,
"Enlarge canvas",
"EnlargePad");
3304 TPadPainter.prototype.RedrawPadSnap =
function(snap, call_back) {
3307 if (!snap || !snap.fPrimitives)
return;
3310 var padattr = { fCw: snap.fWinSize[0], fCh: snap.fWinSize[1], fTitle: snap.fTitle };
3313 if (this.batch_mode && this.iscan && (!padattr.fCw || !padattr.fCh)) { padattr.fCw = 900; padattr.fCh = 700; }
3315 if (this.iscan && snap.fTitle && document)
3316 document.title = snap.fTitle;
3318 if (this.iscan && snap.fTitle && document)
3319 document.title = snap.fTitle;
3321 if (this.snapid === undefined) {
3324 this.snapid = snap.fObjectID;
3326 this.draw_object = padattr;
3328 this.pad_frame = snap.fFrame;
3330 if (this.batch_mode && this.iscan)
3331 this._fixed_size =
true;
3333 this.CreateCanvasSvg(0);
3334 this.SetDivId(this.divid);
3335 this.AddOnlineButtons();
3337 this.DrawNextSnap(snap.fPrimitives, -1, call_back);
3343 this.UpdateObject(padattr);
3347 this.CreateCanvasSvg(2);
3349 this.CreatePadSvg(
true);
3352 var isanyfound =
false, isanyremove =
false;
3355 for (var k=0;k<this.painters.length;++k) {
3356 var sub = this.painters[k];
3357 if (sub.snapid===undefined)
continue;
3359 for (var i=0;i<snap.fPrimitives.length;++i)
3360 if (snap.fPrimitives[i].fObjectID === sub.snapid) { sub = null; isanyfound =
true;
break; }
3364 this.painters.splice(k--,1);
3371 delete this.pads_cache;
3375 var svg_p = this.svg_pad(this.this_pad_name),
3376 fp = this.frame_painter();
3377 if (svg_p && !svg_p.empty())
3378 svg_p.property(
'mainpainter', null);
3379 for (var k=0;k<this.painters.length;++k)
3380 if (fp !== this.painters[k])
3381 this.painters[k].Cleanup();
3384 this.painters.push(fp);
3385 fp.CleanFrameDrawings();
3387 this.RemoveButtons();
3388 this.AddOnlineButtons();
3391 var padpainter =
this,
3392 prev_name = padpainter.CurrentPadName(padpainter.this_pad_name);
3394 padpainter.DrawNextSnap(snap.fPrimitives, -1,
function() {
3395 padpainter.CurrentPadName(prev_name);
3396 call_back(padpainter);
3400 TPadPainter.prototype.CreateImage =
function(format, call_back) {
3401 if (format==
"pdf") {
3403 JSROOT.CallBack(call_back, btoa(
"dummy PDF file"));
3404 }
else if ((format==
"png") || (format==
"jpeg") || (format==
"svg")) {
3405 this.ProduceImage(
true, format,
function(res) {
3406 if ((format==
"svg") || !res)
3407 return JSROOT.CallBack(call_back, res);
3408 var separ = res.indexOf(
"base64,");
3409 JSROOT.CallBack(call_back, (separ>0) ? res.substr(separ+7) :
"");
3412 JSROOT.CallBack(call_back,
"");
3416 TPadPainter.prototype.ItemContextMenu =
function(name) {
3417 var rrr = this.svg_pad(this.this_pad_name).node().getBoundingClientRect();
3418 var evnt = { clientX: rrr.left+10, clientY: rrr.top + 10 };
3422 return setTimeout(this.ShowContextMenu.bind(
this, evnt), 50);
3424 var selp = null, selkind;
3430 selp = this.main_painter();
3434 selp = this.frame_painter();
3437 var indx = parseInt(name);
3438 if (!isNaN(indx)) selp = this.painters[indx];
3442 if (!selp || (typeof selp.FillContextMenu !==
'function'))
return;
3444 JSROOT.Painter.createMenu(selp,
function(menu) {
3445 if (selp.FillContextMenu(menu,selkind))
3446 setTimeout(menu.show.bind(menu, evnt), 50);
3450 TPadPainter.prototype.SaveAs =
function(kind, full_canvas, filename) {
3452 filename = this.this_pad_name;
3453 if (filename.length === 0) filename = this.iscan ?
"canvas" :
"pad";
3454 filename +=
"." + kind;
3456 this.ProduceImage(full_canvas, kind,
function(imgdata) {
3457 var a = document.createElement(
'a');
3458 a.download = filename;
3459 a.href = (kind !=
"svg") ? imgdata :
"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(imgdata);
3460 document.body.appendChild(a);
3461 a.addEventListener(
"click",
function(e) {
3462 a.parentNode.removeChild(a);
3468 TPadPainter.prototype.ProduceImage =
function(full_canvas, file_format, call_back) {
3470 var use_frame = (full_canvas ===
"frame");
3472 var elem = use_frame ? this.svg_frame() : (full_canvas ? this.svg_canvas() : this.svg_pad(this.this_pad_name));
3474 if (elem.empty())
return JSROOT.CallBack(call_back);
3476 var painter = (full_canvas && !use_frame) ? this.canv_painter() :
this;
3483 painter.ForEachPainterInPad(
function(pp) {
3487 var item = { prnt: pp.svg_pad(pp.this_pad_name) };
3491 var btns = pp.svg_layer(
"btns_layer", pp.this_pad_name);
3492 item.btns_node = btns.node();
3493 if (item.btns_node) {
3494 item.btns_prnt = item.btns_node.parentNode;
3495 item.btns_next = item.btns_node.nextSibling;
3499 var main = pp.frame_painter_ref;
3500 if (!main || (typeof main.Render3D !==
'function'))
return;
3502 var can3d = main.access_3d_kind();
3504 if ((can3d !== 1) && (can3d !== 2))
return;
3506 var sz2 = main.size_for_3d(2);
3508 var sz = (can3d == 2) ? sz : main.size_for_3d(1);
3512 var canvas = main.renderer.domElement;
3514 var dataUrl = canvas.toDataURL(
"image/png");
3523 item.foreign = item.prnt.select(
"." + sz2.clname);
3524 item.foreign.remove();
3527 var svg_frame = main.svg_frame();
3528 item.frame_node = svg_frame.node();
3529 if (item.frame_node) {
3530 item.frame_next = item.frame_node.nextSibling;
3538 item.img = item.prnt.insert(
"image",
".primitives_layer")
3541 .attr(
"width", canvas.width)
3542 .attr(
"height", canvas.height)
3543 .attr(
"href", dataUrl);
3547 function reEncode(data) {
3548 data = encodeURIComponent(data);
3549 data = data.replace(/%([0-9A-F]{2})/g,
function(match, p1) {
3550 var c = String.fromCharCode(
'0x'+p1);
3551 return c ===
'%' ?
'%25' : c;
3553 return decodeURIComponent(data);
3556 function reconstruct(res) {
3557 for (var k=0;k<items.length;++k) {
3558 var item = items[k];
3563 var prim = item.prnt.select(
".primitives_layer");
3566 item.prnt.node().insertBefore(item.foreign.node(), prim.node());
3568 if (item.frame_node)
3569 prim.node().insertBefore(item.frame_node, item.frame_next);
3572 item.btns_prnt.insertBefore(item.btns_node, item.btns_next);
3575 JSROOT.CallBack(call_back, res);
3578 var width = elem.property(
'draw_width'), height = elem.property(
'draw_height');
3579 if (use_frame) { width = this.frame_width(); height = this.frame_height(); }
3581 var svg =
'<svg width="' + width +
'" height="' + height +
'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
3582 elem.node().innerHTML +
3585 if (file_format ==
"svg")
3586 return reconstruct(svg);
3588 var doctype =
'<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
3590 var image =
new Image();
3591 image.onload =
function() {
3596 var canvas = document.createElement(
'canvas');
3597 canvas.width = image.width;
3598 canvas.height = image.height;
3599 var context = canvas.getContext(
'2d');
3600 context.drawImage(image, 0, 0);
3602 reconstruct(canvas.toDataURL(
'image/' + file_format));
3605 image.onerror =
function(arg) {
3606 console.log(
'IMAGE ERROR', arg);
3610 image.src =
'data:image/svg+xml;base64,' + window.btoa(reEncode(doctype + svg));
3614 TPadPainter.prototype.PadButtonClick =
function(funcname) {
3616 if (funcname ==
"CanvasSnapShot")
return this.SaveAs(
"png",
true);
3618 if (funcname ==
"EnlargePad")
return this.EnlargePad();
3620 if (funcname ==
"PadSnapShot")
return this.SaveAs(
"png",
false);
3622 if (funcname ==
"PadContextMenus") {
3624 d3.event.preventDefault();
3625 d3.event.stopPropagation();
3627 if (JSROOT.Painter.closeMenu())
return;
3629 var pthis =
this, evnt = d3.event;
3631 JSROOT.Painter.createMenu(pthis,
function(menu) {
3632 menu.add(
"header:Menus");
3635 menu.add(
"Canvas",
"pad", pthis.ItemContextMenu);
3637 menu.add(
"Pad",
"pad", pthis.ItemContextMenu);
3639 if (pthis.frame_painter())
3640 menu.add(
"Frame",
"frame", pthis.ItemContextMenu);
3642 var main = pthis.main_painter();
3645 menu.add(
"X axis",
"xaxis", pthis.ItemContextMenu);
3646 menu.add(
"Y axis",
"yaxis", pthis.ItemContextMenu);
3647 if ((typeof main.Dimension ===
'function') && (main.Dimension() > 1))
3648 menu.add(
"Z axis",
"zaxis", pthis.ItemContextMenu);
3651 if (pthis.painters && (pthis.painters.length>0)) {
3652 menu.add(
"separator");
3654 for (var n=0;n<pthis.painters.length;++n) {
3655 var pp = pthis.painters[n];
3656 var obj = pp ? pp.GetObject() : null;
3657 if (!obj || (shown.indexOf(obj)>=0))
continue;
3659 var name = (
'_typename' in obj) ? (obj._typename +
"::") :
"";
3660 if (
'fName' in obj) name += obj.fName;
3661 if (name.length==0) name =
"item" + n;
3662 menu.add(name, n, pthis.ItemContextMenu);
3676 for (var i = 0; i < this.painters.length; ++i) {
3677 var pp = this.painters[i];
3679 if (typeof pp.PadButtonClick ==
'function')
3680 pp.PadButtonClick(funcname);
3682 if (!done && (typeof pp.ButtonClick ==
'function'))
3683 done = pp.ButtonClick(funcname);
3687 TPadPainter.prototype.FindButton =
function(keyname) {
3688 var group = this.svg_layer(
"btns_layer", this.this_pad_name), found_func =
"";
3690 group.selectAll(
"svg").each(
function() {
3691 if (d3.select(
this).attr(
"key") === keyname)
3692 found_func = d3.select(
this).attr(
"name");
3697 TPadPainter.prototype.toggleButtonsVisibility =
function(action) {
3698 var group = this.svg_layer(
"btns_layer", this.this_pad_name),
3699 btn = group.select(
"[name='Toggle']");
3701 if (btn.empty())
return;
3703 var state = btn.property(
'buttons_state');
3705 if (btn.property(
'timout_handler')) {
3706 if (action!==
'timeout') clearTimeout(btn.property(
'timout_handler'));
3707 btn.property(
'timout_handler', null);
3710 var is_visible =
false;
3712 case 'enable': is_visible =
true;
break;
3713 case 'enterbtn':
return;
3714 case 'timeout': is_visible =
false;
break;
3717 btn.property(
'buttons_state', state);
3722 if (!state) btn.property(
'timout_handler', setTimeout(this.toggleButtonsVisibility.bind(
this,
'timeout'), 500));
3726 group.selectAll(
'svg').each(
function() {
3727 if (
this===btn.node())
return;
3728 d3.select(
this).style(
'display', is_visible ?
"" :
"none");
3732 TPadPainter.prototype.RemoveButtons =
function() {
3733 var group = this.svg_layer(
"btns_layer", this.this_pad_name);
3734 if (!group.empty()) {
3735 group.selectAll(
"*").remove();
3736 group.property(
"nextx", null);
3740 TPadPainter.prototype.RemoveButtons =
function() {
3741 var group = this.svg_layer(
"btns_layer", this.this_pad_name);
3742 if (!group.empty()) {
3743 group.selectAll(
"*").remove();
3744 group.property(
"nextx", null);
3748 TPadPainter.prototype.AddButton =
function(_btn, _tooltip, _funcname, _keyname) {
3749 if (!JSROOT.gStyle.ToolBar)
return;
3751 if (!this._buttons) this._buttons = [];
3754 for (var k=0;k<this._buttons.length;++k)
3755 if (this._buttons[k].funcname == _funcname)
return;
3757 this._buttons.push({ btn: _btn, tooltip: _tooltip, funcname: _funcname, keyname: _keyname });
3759 var iscan = this.iscan || !this.has_canvas;
3760 if (!iscan && (_funcname.indexOf(
"Pad")!=0) && (_funcname !==
"EnlargePad")) {
3761 var cp = this.canv_painter();
3762 if (cp && (cp!==
this)) cp.AddButton(_btn, _tooltip, _funcname);
3766 TPadPainter.prototype.ShowButtons =
function() {
3768 if (!this._buttons)
return;
3770 var group = this.svg_layer(
"btns_layer", this.this_pad_name);
3771 if (group.empty())
return;
3774 group.selectAll(
"*").remove();
3776 var iscan = this.iscan || !this.has_canvas, ctrl,
3777 x = group.property(
'leftside') ? this.ButtonSize(1.25) : 0, y = 0;
3779 if (this._fast_drawing) {
3780 ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.circle,
this.ButtonSize(),
"EnlargePad");
3781 ctrl.attr(
"name",
"Enlarge").attr(
"x", 0).attr(
"y", 0)
3783 .on(
"click", this.PadButtonClick.bind(
this,
"EnlargePad"));
3785 ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.rect,
this.ButtonSize(),
"Toggle tool buttons");
3787 ctrl.attr(
"name",
"Toggle").attr(
"x", 0).attr(
"y", 0)
3788 .property(
"buttons_state", (JSROOT.gStyle.ToolBar!==
'popup'))
3789 .on(
"click", this.toggleButtonsVisibility.bind(
this,
'toggle'))
3790 .on(
"mouseenter", this.toggleButtonsVisibility.bind(
this,
'enable'))
3791 .on(
"mouseleave", this.toggleButtonsVisibility.bind(
this,
'disable'));
3793 for (var k=0;k<this._buttons.length;++k) {
3794 var item = this._buttons[k];
3796 var svg = JSROOT.ToolbarIcons.CreateSVG(group, item.btn,
this.ButtonSize(),
3797 item.tooltip + (iscan ?
"" : (
" on pad " + this.this_pad_name)) + (item.keyname ?
" (keyshortcut " + item.keyname +
")" :
""));
3799 if (group.property(
'vertical'))
3800 svg.attr(
"x", y).attr(
"y", x);
3802 svg.attr(
"x", x).attr(
"y", y);
3804 svg.attr(
"name", item.funcname)
3805 .style(
'display', (ctrl.property(
"buttons_state") ?
'' :
'none'))
3806 .on(
"mouseenter", this.toggleButtonsVisibility.bind(
this,
'enterbtn'))
3807 .on(
"mouseleave", this.toggleButtonsVisibility.bind(
this,
'leavebtn'));
3809 if (item.keyname) svg.attr(
"key", item.keyname);
3811 svg.on(
"click", this.PadButtonClick.bind(
this, item.funcname));
3813 x += this.ButtonSize(1.25);
3817 group.property(
"nextx", x);
3819 this.AlignBtns(group, this.pad_width(this.this_pad_name), this.pad_height(this.this_pad_name));
3821 if (group.property(
'vertical')) ctrl.attr(
"y", x);
3822 else if (!group.property(
'leftside')) ctrl.attr(
"x", x);
3825 TPadPainter.prototype.AlignBtns =
function(btns, width, height, svg) {
3826 var sz0 = this.ButtonSize(1.25), nextx = (btns.property(
'nextx') || 0) + sz0, btns_x, btns_y;
3827 if (btns.property(
'vertical')) {
3828 btns_x = btns.property(
'leftside') ? 2 : (width - sz0);
3829 btns_y = height - nextx;
3831 btns_x = btns.property(
'leftside') ? 2 : (width - nextx);
3832 btns_y = height - sz0;
3835 btns.attr(
"transform",
"translate("+btns_x+
","+btns_y+
")");
3838 TPadPainter.prototype.GetCoordinate =
function(pos) {
3839 var res = { x: 0, y: 0 };
3841 if (!pos)
return res;
3843 function GetV(len, indx, dflt) {
3844 return (len.fArr && (len.fArr.length>indx)) ? len.fArr[indx] : dflt;
3847 var w = this.pad_width(this.this_pad_name),
3848 h = this.pad_height(this.this_pad_name),
3849 h_norm = GetV(pos.fHoriz, 0, 0),
3850 h_pixel = GetV(pos.fHoriz, 1, 0),
3851 h_user = GetV(pos.fHoriz, 2),
3852 v_norm = GetV(pos.fVert, 0, 0),
3853 v_pixel = GetV(pos.fVert, 1, 0),
3854 v_user = GetV(pos.fVert, 2);
3856 if (!this.pad_frame || (h_user === undefined)) {
3857 res.x = h_norm * w + h_pixel;
3862 if (!this.pad_frame || (v_user === undefined)) {
3863 res.y = h - v_norm * h - v_pixel;
3878 TPadPainter.prototype.DecodeOptions =
function(opt) {
3879 var pad = this.GetObject();
3882 var d =
new JSROOT.DrawOptions(opt);
3884 if (d.check(
'WEBSOCKET')) this.OpenWebsocket();
3885 if (!this.options) this.options = {};
3887 JSROOT.extend(this.options, { GlobalColors:
true, LocalColors:
false, IgnorePalette:
false, RotateFrame:
false, FixFrame:
false });
3889 if (d.check(
'NOCOLORS') || d.check(
'NOCOL')) this.options.GlobalColors =
this.options.LocalColors =
false;
3890 if (d.check(
'LCOLORS') || d.check(
'LCOL')) { this.options.GlobalColors =
false; this.options.LocalColors =
true; }
3891 if (d.check(
'NOPALETTE') || d.check(
'NOPAL')) this.options.IgnorePalette =
true;
3892 if (d.check(
'ROTATE')) this.options.RotateFrame =
true;
3893 if (d.check(
'FIXFRAME')) this.options.FixFrame =
true;
3895 if (d.check(
'WHITE')) pad.fFillColor = 0;
3896 if (d.check(
'LOGX')) pad.fLogx = 1;
3897 if (d.check(
'LOGY')) pad.fLogy = 1;
3898 if (d.check(
'LOGZ')) pad.fLogz = 1;
3899 if (d.check(
'LOG')) pad.fLogx = pad.fLogy = pad.fLogz = 1;
3900 if (d.check(
'GRIDX')) pad.fGridx = 1;
3901 if (d.check(
'GRIDY')) pad.fGridy = 1;
3902 if (d.check(
'GRID')) pad.fGridx = pad.fGridy = 1;
3903 if (d.check(
'TICKX')) pad.fTickx = 1;
3904 if (d.check(
'TICKY')) pad.fTicky = 1;
3905 if (d.check(
'TICK')) pad.fTickx = pad.fTicky = 1;
3908 function drawPad(divid, pad, opt) {
3909 var painter =
new TPadPainter(pad,
false);
3910 painter.DecodeOptions(opt);
3912 painter.SetDivId(divid);
3914 if (painter.svg_canvas().empty()) {
3915 painter.has_canvas =
false;
3916 painter.this_pad_name =
"";
3919 painter.CreatePadSvg();
3921 if (painter.MatchObjectType(
"TPad") && (!painter.has_canvas || painter.HasObjectsToDraw())) {
3922 painter.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"PadSnapShot");
3924 if ((painter.has_canvas && painter.HasObjectsToDraw()) || painter.enlarge_main(
'verify'))
3925 painter.AddButton(JSROOT.ToolbarIcons.circle,
"Enlarge pad",
"EnlargePad");
3927 if (JSROOT.gStyle.ContextMenu)
3928 painter.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
3932 var prev_name = painter.has_canvas ? painter.CurrentPadName(painter.this_pad_name) : undefined;
3934 JSROOT.Painter.SelectActivePad({ pp: painter, active:
false });
3937 painter.DrawPrimitives(0,
function() {
3938 painter.ShowButtons();
3940 painter.CurrentPadName(prev_name);
3941 painter.DrawingReady();
3949 function TCanvasPainter(canvas) {
3951 TPadPainter.call(
this, canvas,
true);
3952 this._websocket = null;
3953 this.tooltip_allowed = (JSROOT.gStyle.Tooltip > 0);
3956 TCanvasPainter.prototype = Object.create(TPadPainter.prototype);
3958 TCanvasPainter.prototype.ChangeLayout =
function(layout_kind, call_back) {
3959 var current = this.get_layout_kind();
3960 if (current == layout_kind)
return JSROOT.CallBack(call_back,
true);
3962 var origin = this.select_main(
'origin'),
3963 sidebar = origin.select(
'.side_panel'),
3964 main = this.select_main(), lst = [];
3966 while (main.node().firstChild)
3967 lst.push(main.node().removeChild(main.node().firstChild));
3969 if (!sidebar.empty()) JSROOT.cleanup(sidebar.node());
3971 this.set_layout_kind(
"simple");
3974 if (layout_kind ==
'simple') {
3976 for (var k=0;k<lst.length;++k)
3977 main.node().appendChild(lst[k]);
3978 this.set_layout_kind(layout_kind);
3979 JSROOT.resize(main.node());
3980 return JSROOT.CallBack(call_back,
true);
3985 JSROOT.AssertPrerequisites(
"jq2d",
function() {
3987 var grid =
new JSROOT.GridDisplay(origin.node(), layout_kind);
3989 if (layout_kind.indexOf(
"vert")==0) {
3990 main = d3.select(grid.GetFrame(0));
3991 sidebar = d3.select(grid.GetFrame(1));
3993 main = d3.select(grid.GetFrame(1));
3994 sidebar = d3.select(grid.GetFrame(0));
3997 main.classed(
"central_panel",
true).style(
'position',
'relative');
3998 sidebar.classed(
"side_panel",
true).style(
'position',
'relative');
4001 for (var k=0;k<lst.length;++k)
4002 main.node().appendChild(lst[k]);
4004 pthis.set_layout_kind(layout_kind,
".central_panel");
4007 origin.property(
'mdi', null);
4010 JSROOT.resize(main.node());
4012 JSROOT.CallBack(call_back,
true);
4016 TCanvasPainter.prototype.ToggleProjection =
function(kind, call_back) {
4017 delete this.proj_painter;
4019 if (kind) this.proj_painter = 1;
4021 if (this.ShowUI5ProjectionArea)
4022 return this.ShowUI5ProjectionArea(kind, call_back);
4024 var layout =
'simple';
4026 if (kind ==
"X") layout =
'vert2_31';
else
4027 if (kind ==
"Y") layout =
'horiz2_13';
4029 this.ChangeLayout(layout, call_back);
4032 TCanvasPainter.prototype.DrawProjection =
function(kind,hist) {
4033 if (!this.proj_painter)
return;
4035 if (this.proj_painter === 1) {
4037 var canv = JSROOT.Create(
"TCanvas"), pthis =
this, pad = this.root_pad(), main = this.main_painter(), drawopt;
4040 canv.fLeftMargin = pad.fLeftMargin;
4041 canv.fRightMargin = pad.fRightMargin;
4042 canv.fLogx = main.logx ? 1 : 0;
4043 canv.fUxmin = main.logx ? JSROOT.log10(main.scale_xmin) : main.scale_xmin;
4044 canv.fUxmax = main.logx ? JSROOT.log10(main.scale_xmax) : main.scale_xmax;
4045 drawopt =
"fixframe";
4047 canv.fBottomMargin = pad.fBottomMargin;
4048 canv.fTopMargin = pad.fTopMargin;
4049 canv.fLogx = main.logy ? 1 : 0;
4050 canv.fUxmin = main.logy ? JSROOT.log10(main.scale_ymin) : main.scale_ymin;
4051 canv.fUxmax = main.logy ? JSROOT.log10(main.scale_ymax) : main.scale_ymax;
4055 canv.fPrimitives.Add(hist,
"hist");
4057 if (this.DrawInUI5ProjectionArea) {
4059 this.DrawInUI5ProjectionArea(canv, drawopt,
function(painter) { pthis.proj_painter = painter; })
4061 this.DrawInSidePanel(canv, drawopt,
function(painter) { pthis.proj_painter = painter; })
4064 var hp = this.proj_painter.main_painter();
4065 if (hp) hp.UpdateObject(hist,
"hist");
4066 this.proj_painter.RedrawPad();
4070 TCanvasPainter.prototype.DrawInSidePanel =
function(canv, opt, call_back) {
4071 var side = this.select_main(
'origin').select(
".side_panel");
4072 if (side.empty())
return JSROOT.CallBack(call_back, null);
4073 JSROOT.draw(side.node(), canv, opt, call_back);
4076 TCanvasPainter.prototype.ShowMessage =
function(msg) {
4077 JSROOT.progress(msg, 7000);
4081 TCanvasPainter.prototype.SaveCanvasAsFile =
function(fname) {
4082 var pthis =
this, pnt = fname.indexOf(
".");
4083 this.CreateImage(fname.substr(pnt+1),
function(res) {
4084 pthis.SendWebsocket(
"SAVE:" + fname +
":" + res);
4088 TCanvasPainter.prototype.SendSaveCommand =
function(fname) {
4089 this.SendWebsocket(
"PRODUCE:" + fname);
4092 TCanvasPainter.prototype.SendWebsocket =
function(msg, chid) {
4093 if (this._websocket)
4094 this._websocket.Send(msg, chid);
4097 TCanvasPainter.prototype.CloseWebsocket =
function(force) {
4098 if (this._websocket) {
4099 this._websocket.Close(force);
4100 this._websocket.Cleanup();
4101 delete this._websocket;
4105 TCanvasPainter.prototype.OpenWebsocket =
function(socket_kind) {
4109 this.CloseWebsocket();
4111 this._websocket =
new JSROOT.WebWindowHandle(socket_kind);
4112 this._websocket.SetReceiver(
this);
4113 this._websocket.Connect();
4116 TCanvasPainter.prototype.UseWebsocket =
function(handle, href) {
4117 this.CloseWebsocket();
4119 this._websocket = handle;
4120 console.log(
'Use websocket', this._websocket.key);
4121 this._websocket.SetReceiver(
this);
4122 this._websocket.Connect(href);
4125 TCanvasPainter.prototype.WindowBeforeUnloadHanlder =
function() {
4127 this.CloseWebsocket(
true);
4130 TCanvasPainter.prototype.OnWebsocketOpened =
function(handle) {
4134 TCanvasPainter.prototype.OnWebsocketClosed =
function(handle) {
4135 JSROOT.CloseCurrentWindow();
4138 TCanvasPainter.prototype.OnWebsocketMsg =
function(handle, msg) {
4139 console.log(
"GET MSG " + msg.substr(0,30));
4141 if (msg ==
"CLOSE") {
4142 this.OnWebsocketClosed();
4143 this.CloseWebsocket(
true);
4144 }
else if (msg.substr(0,5)==
'SNAP:') {
4145 msg = msg.substr(5);
4146 var p1 = msg.indexOf(
":"),
4147 snapid = msg.substr(0,p1),
4148 snap = JSROOT.parse(msg.substr(p1+1));
4149 this.RedrawPadSnap(snap,
function() {
4150 handle.Send(
"SNAPDONE:" + snapid);
4152 }
else if (msg.substr(0,4)==
'JSON') {
4153 var obj = JSROOT.parse(msg.substr(4));
4155 this.RedrawObject(obj);
4157 }
else if (msg.substr(0,5)==
'MENU:') {
4159 var lst = JSROOT.parse(msg.substr(5));
4161 if (typeof this._getmenu_callback ==
'function')
4162 this._getmenu_callback(lst);
4163 }
else if (msg.substr(0,4)==
'CMD:') {
4164 msg = msg.substr(4);
4165 var p1 = msg.indexOf(
":"),
4166 cmdid = msg.substr(0,p1),
4167 cmd = msg.substr(p1+1),
4168 reply =
"REPLY:" + cmdid +
":";
4169 if ((cmd ==
"SVG") || (cmd ==
"PNG") || (cmd ==
"JPEG")) {
4170 this.CreateImage(cmd.toLowerCase(),
function(res) {
4171 handle.Send(reply + res);
4173 }
else if (cmd.indexOf(
"ADDPANEL:") == 0) {
4174 var relative_path = cmd.substr(9);
4175 console.log(
'request panel = ' + relative_path);
4176 if (!this.ShowUI5Panel) {
4177 handle.Send(reply +
"false");
4180 var conn =
new JSROOT.WebWindowHandle(handle.kind);
4186 OnWebsocketOpened:
function(hhh) {
4187 console.log(
'Panel socket connected');
4190 OnWebsocketMsg:
function(panel_handle, msg) {
4192 var panel_name = (msg.indexOf(
"SHOWPANEL:")==0) ? msg.substr(10) :
"";
4193 console.log(
'Panel get message ' + msg +
" show " + panel_name);
4195 this.cpainter.ShowUI5Panel(panel_name, panel_handle,
function(res) {
4196 handle.Send(reply + (res ?
"true" :
"false"));
4200 OnWebsocketClosed:
function(hhh) {
4202 handle.Send(reply +
"false");
4205 OnWebsocketError:
function(hhh) {
4207 handle.Send(reply +
"false");
4212 var addr = handle.href;
4213 if (relative_path.indexOf(
"../")==0) {
4214 var ddd = addr.lastIndexOf(
"/",addr.length-2);
4215 addr = addr.substr(0,ddd) + relative_path.substr(2);
4217 addr += relative_path;
4223 console.log(
'Unrecognized command ' + cmd);
4226 }
else if ((msg.substr(0,7)==
'DXPROJ:') || (msg.substr(0,7)==
'DYPROJ:')) {
4228 hist = JSROOT.parse(msg.substr(7));
4229 this.DrawProjection(kind, hist);
4230 }
else if (msg.substr(0,5)==
'SHOW:') {
4231 var that = msg.substr(5),
4232 on = that[that.length-1] ==
'1';
4233 this.ShowSection(that.substr(0,that.length-2), on);
4235 console.log(
"unrecognized msg len:" + msg.length +
" msg:" + msg.substr(0,20));
4239 TCanvasPainter.prototype.ShowSection =
function(that, on) {
4242 case "StatusBar":
break;
4243 case "Editor":
break;
4244 case "ToolBar":
break;
4245 case "ToolTips": this.SetTooltipAllowed(on);
break;
4249 JSROOT.TCanvasStatusBits = {
4250 kShowEventStatus : JSROOT.BIT(15),
4251 kAutoExec : JSROOT.BIT(16),
4252 kMenuBar : JSROOT.BIT(17),
4253 kShowToolBar : JSROOT.BIT(18),
4254 kShowEditor : JSROOT.BIT(19),
4255 kMoveOpaque : JSROOT.BIT(20),
4256 kResizeOpaque : JSROOT.BIT(21),
4257 kIsGrayscale : JSROOT.BIT(22),
4258 kShowToolTips : JSROOT.BIT(23)
4261 TCanvasPainter.prototype.CompeteCanvasSnapDrawing =
function() {
4262 if (!this.pad)
return;
4264 if (document) document.title = this.pad.fTitle;
4266 if (this._all_sections_showed)
return;
4267 this._all_sections_showed =
true;
4268 this.ShowSection(
"Menu", this.pad.TestBit(JSROOT.TCanvasStatusBits.kMenuBar));
4269 this.ShowSection(
"StatusBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEventStatus));
4270 this.ShowSection(
"ToolBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolBar));
4271 this.ShowSection(
"Editor", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEditor));
4272 this.ShowSection(
"ToolTips", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolTips));
4275 TCanvasPainter.prototype.HasEventStatus =
function() {
4276 return this.has_event_status;
4279 function drawCanvas(divid, can, opt) {
4280 var nocanvas = !can;
4282 console.log(
"No canvas specified");
4287 var painter =
new TCanvasPainter(can);
4288 painter.normal_canvas = !nocanvas;
4290 painter.SetDivId(divid, -1);
4291 painter.CreateCanvasSvg(0);
4292 painter.SetDivId(divid);
4294 painter.AddButton(JSROOT.ToolbarIcons.camera,
"Create PNG",
"CanvasSnapShot",
"Ctrl PrintScreen");
4295 if (JSROOT.gStyle.ContextMenu)
4296 painter.AddButton(JSROOT.ToolbarIcons.question,
"Access context menus",
"PadContextMenus");
4298 if (painter.enlarge_main(
'verify'))
4299 painter.AddButton(JSROOT.ToolbarIcons.circle,
"Enlarge canvas",
"EnlargePad");
4301 JSROOT.Painter.SelectActivePad({ pp: painter, active:
false });
4303 painter.DrawPrimitives(0,
function() {
4304 painter.ShowButtons();
4305 painter.DrawingReady();
4313 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RHistDrawable<1>", icon:
"img_histo1d", prereq:
"v7hist", func:
"JSROOT.v7.drawHist1", opt:
"" });
4314 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RHistDrawable<2>", icon:
"img_histo2d", prereq:
"v7hist", func:
"JSROOT.v7.drawHist2", opt:
"" });
4315 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RText", icon:
"img_text", prereq:
"v7more", func:
"JSROOT.v7.drawText", opt:
"", direct:
true, csstype:
"text" });
4316 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RLine", icon:
"img_graph", prereq:
"v7more", func:
"JSROOT.v7.drawLine", opt:
"", direct:
true, csstype:
"line" });
4317 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RBox", icon:
"img_graph", prereq:
"v7more", func:
"JSROOT.v7.drawBox", opt:
"", direct:
true, csstype:
"box" });
4318 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RMarker", icon:
"img_graph", prereq:
"v7more", func:
"JSROOT.v7.drawMarker", opt:
"", direct:
true, csstype:
"marker" });
4319 JSROOT.addDrawFunc({ name:
"ROOT::Experimental::RLegend", icon:
"img_graph", prereq:
"v7more", func:
"JSROOT.v7.drawLegend", opt:
"", direct:
true, csstype:
"legend" });
4321 JSROOT.v7.TAxisPainter = TAxisPainter;
4322 JSROOT.v7.TFramePainter = TFramePainter;
4323 JSROOT.v7.TPadPainter = TPadPainter;
4324 JSROOT.v7.TCanvasPainter = TCanvasPainter;
4325 JSROOT.v7.drawFrame = drawFrame;
4326 JSROOT.v7.drawPad = drawPad;
4327 JSROOT.v7.drawCanvas = drawCanvas;