5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootCore',
'd3',
'JSRootPainter.hist',
'threejs',
'threejs_all'], factory );
7 }
else if (typeof exports ===
'object' && typeof module !==
'undefined') {
8 var jsroot = require(
"./JSRootCore.js");
9 factory(jsroot, require(
"d3"), require(
"./JSRootPainter.hist.js"), require(
"three"), require(
"./three.extra.min.js"),
10 jsroot.nodejs || (typeof document==
'undefined') ? jsroot.nodejs_document : document);
12 if (typeof JSROOT ==
'undefined')
13 throw new Error(
'JSROOT is not defined',
'JSRootPainter.hist3d.js');
14 if (typeof d3 !=
'object')
15 throw new Error(
'This extension requires d3.js',
'JSRootPainter.hist3d.js');
16 if (typeof THREE ==
'undefined')
17 throw new Error(
'THREE is not defined',
'JSRoot3DPainter.js');
18 factory(JSROOT, d3, JSROOT, THREE, THREE);
20 } (
function(JSROOT, d3, __DUMMY__, THREE, THREE_MORE, document) {
24 JSROOT.sources.push(
"hist3d");
26 if ((typeof document==
'undefined') && (typeof window==
'object')) document = window.document;
28 if (typeof JSROOT.THistPainter ===
'undefined')
29 throw new Error(
'JSROOT.THistPainter is not defined',
'JSRootPainter.hist3d.js');
31 JSROOT.TFramePainter.prototype.SetCameraPosition =
function(pad, first_time) {
32 var max3d = Math.max(0.75*this.size_xy3d, this.size_z3d);
35 this.camera.position.set(-1.6*max3d, -3.5*max3d, 1.4*this.size_z3d);
37 if (pad && (first_time || !this.zoom_changed_interactive))
38 if (!isNaN(pad.fTheta) && !isNaN(pad.fPhi) && ((pad.fTheta !==
this.camera_Theta) || (pad.fPhi !==
this.camera_Phi))) {
39 max3d = 3*Math.max(this.size_xy3d, this.size_z3d);
40 var phi = (-pad.fPhi-90)/180*Math.PI, theta = pad.fTheta/180*Math.PI;
42 this.camera_Phi = pad.fPhi;
43 this.camera_Theta = pad.fTheta;
45 this.camera.position.set(max3d*Math.cos(phi)*Math.cos(theta),
46 max3d*Math.sin(phi)*Math.cos(theta),
47 this.size_z3d + max3d*Math.sin(theta));
53 this.camera.lookAt(this.lookat);
57 JSROOT.TFramePainter.prototype.Create3DScene =
function(arg) {
59 if ((arg!==undefined) && (arg<0)) {
61 if (!this.mode3d)
return;
64 this.TestAxisVisibility(null, this.toplevel);
66 this.clear_3d_canvas();
68 JSROOT.Painter.DisposeThreejsObject(this.scene);
69 if (this.control) this.control.Cleanup();
72 if (this.renderer.dispose) this.renderer.dispose();
73 if (this.renderer.context)
delete this.renderer.context;
76 delete this.size_xy3d;
78 delete this.tooltip_mesh;
82 delete this.pointLight;
85 if (
'render_tmout' in
this) {
86 clearTimeout(this.render_tmout);
87 delete this.render_tmout;
97 if (
'toplevel' in
this) {
99 this.scene.remove(this.toplevel);
100 JSROOT.Painter.DisposeThreejsObject(this.toplevel);
101 delete this.tooltip_mesh;
102 delete this.toplevel;
103 if (this.control) this.control.HideTooltip();
105 var newtop =
new THREE.Object3D();
106 this.scene.add(newtop);
107 this.toplevel = newtop;
111 this.SetCameraPosition(this.root_pad(),
false);
116 this.usesvg = JSROOT.Painter.UseSVGFor3D();
119 var sz = this.size_for_3d(this.usesvg ? 3 : undefined);
122 this.size_xy3d = (sz.height > 10) && (sz.width > 10) ? Math.round(sz.width/sz.height*
this.size_z3d) : this.size_z3d;
125 this.scene =
new THREE.Scene();
128 this.toplevel =
new THREE.Object3D();
129 this.scene.add(this.toplevel);
130 this.scene_width = sz.width;
131 this.scene_height = sz.height;
133 this.camera =
new THREE.PerspectiveCamera(45, this.scene_width / this.scene_height, 1, 40*this.size_z3d);
135 this.camera_Phi = 30;
136 this.camera_Theta = 30;
138 this.pointLight =
new THREE.PointLight(0xffffff,1);
139 this.camera.add(this.pointLight);
140 this.pointLight.position.set(this.size_xy3d/2, this.size_xy3d/2, this.size_z3d/2);
141 this.lookat =
new THREE.Vector3(0,0,0.8*this.size_z3d);
142 this.camera.up =
new THREE.Vector3(0,0,1);
143 this.scene.add( this.camera );
145 this.SetCameraPosition(this.root_pad(),
true);
147 var res = JSROOT.Painter.Create3DRenderer(this.scene_width, this.scene_height, this.usesvg, (sz.can3d == 4));
149 this.renderer = res.renderer;
150 this.webgl = res.usewebgl;
151 this.add_3d_canvas(sz, res.dom);
153 this.first_render_tm = 0;
154 this.enable_highlight =
false;
156 if (JSROOT.BatchMode)
return;
158 this.control = JSROOT.Painter.CreateOrbitControl(
this, this.camera, this.scene, this.renderer, this.lookat);
160 var axis_painter =
this, obj_painter = this.main_painter();
162 this.control.ProcessMouseMove =
function(intersects) {
163 var tip = null, mesh = null, zoom_mesh = null;
165 for (var i = 0; i < intersects.length; ++i) {
166 if (intersects[i].
object.tooltip) {
167 tip = intersects[i].object.tooltip(intersects[i]);
168 if (tip) { mesh = intersects[i].object;
break; }
169 }
else if (intersects[i].
object.zoom && !zoom_mesh) {
170 zoom_mesh = intersects[i].object;
174 if (tip && !tip.use_itself) {
175 var delta_xy = 1e-4*axis_painter.size_xy3d, delta_z = 1e-4*axis_painter.size_z3d;
176 if ((tip.x1 > tip.x2) || (tip.y1 > tip.y2) || (tip.z1 > tip.z2)) console.warn(
'check 3D hints coordinates');
177 tip.x1 -= delta_xy; tip.x2 += delta_xy;
178 tip.y1 -= delta_xy; tip.y2 += delta_xy;
179 tip.z1 -= delta_z; tip.z2 += delta_z;
182 axis_painter.BinHighlight3D(tip, mesh);
184 if (!tip && zoom_mesh && axis_painter.Get3DZoomCoord) {
185 var pnt = zoom_mesh.GlobalIntersect(this.raycaster),
186 axis_name = zoom_mesh.zoom,
187 axis_value = axis_painter.Get3DZoomCoord(pnt, axis_name);
189 if ((axis_name===
"z") && zoom_mesh.use_y_for_z) axis_name =
"y";
191 var taxis = axis_painter.GetAxis(axis_name);
193 var hint = { name: axis_name,
198 if (taxis) { hint.name = taxis.fName; hint.title = taxis.fTitle ||
"histogram TAxis object"; }
200 hint.line = axis_name +
" : " + axis_painter.AxisAsText(axis_name, axis_value);
205 return (tip && tip.lines) ? tip :
"";
208 this.control.ProcessMouseLeave =
function() {
209 axis_painter.BinHighlight3D(null);
212 this.control.ContextMenu =
function(pos, intersects) {
213 var kind =
"hist", p = obj_painter;
215 for (var n=0;n<intersects.length;++n) {
216 var mesh = intersects[n].object;
217 if (mesh.zoom) { kind = mesh.zoom;
break; }
218 if (mesh.painter && typeof mesh.painter.ShowContextMenu ===
'function') {
219 p = mesh.painter;
break;
223 p.ShowContextMenu(kind, pos);
230 JSROOT.TFramePainter.prototype.SetActive =
function(on) {
232 this.control.enableKeys = on;
245 JSROOT.TFramePainter.prototype.Render3D =
function(tmout) {
247 if (tmout === -1111) {
251 var rrr = THREE.CreateSVGRenderer(
false, 0, document);
252 rrr.setSize(this.scene_width, this.scene_height);
253 rrr.render(this.scene, this.camera);
254 if (rrr.makeOuterHTML) {
256 var d = document.createElement(
'div');
257 d.innerHTML = rrr.makeOuterHTML();
258 return d.childNodes[0];
260 return rrr.domElement;
263 if (tmout === undefined) tmout = 5;
265 if ((tmout <= 0) || this.usesvg || JSROOT.BatchMode) {
266 if (
'render_tmout' in
this) {
267 clearTimeout(this.render_tmout);
269 if (tmout === -2222)
return;
272 if (this.renderer === undefined)
return;
274 var tm1 =
new Date();
276 if (!this.opt3d) this.opt3d = { FrontBox:
true, BackBox:
true };
279 this.TestAxisVisibility(this.camera, this.toplevel, this.opt3d.FrontBox,
this.opt3d.BackBox);
282 this.renderer.render(this.scene, this.camera);
285 if ((this.first_render_tm === 0) && (this.renderer instanceof THREE.SoftwareRenderer))
286 this.renderer.render(this.scene, this.camera);
288 JSROOT.Painter.AfterRender3D(this.renderer);
290 var tm2 =
new Date();
292 delete this.render_tmout;
294 if (this.first_render_tm === 0) {
295 this.first_render_tm = tm2.getTime() - tm1.getTime();
296 this.enable_highlight = (this.first_render_tm < 1200) && this.IsTooltipAllowed();
297 console.log(
'First render tm = ' + this.first_render_tm);
304 if (
'render_tmout' in
this)
return;
306 this.render_tmout = setTimeout(this.Render3D.bind(
this,0), tmout);
309 JSROOT.TFramePainter.prototype.Resize3D =
function() {
311 var sz = this.size_for_3d(this.access_3d_kind());
313 this.apply_3d_size(sz);
315 if ((this.scene_width === sz.width) && (
this.scene_height === sz.height))
return false;
317 if ((sz.width<10) || (sz.height<10))
return false;
322 this.scene_width = sz.width;
323 this.scene_height = sz.height;
325 this.camera.aspect = this.scene_width / this.scene_height;
326 this.camera.updateProjectionMatrix();
328 this.renderer.setSize( this.scene_width, this.scene_height );
333 JSROOT.TFramePainter.prototype.BinHighlight3D =
function(tip, selfmesh) {
335 var changed =
false, tooltip_mesh = null, changed_self =
true,
336 want_remove = !tip || (tip.x1===undefined) || !this.enable_highlight;
338 if (this.tooltip_selfmesh) {
339 changed_self = (this.tooltip_selfmesh !== selfmesh)
340 this.tooltip_selfmesh.material.color =
this.tooltip_selfmesh.save_color;
341 delete this.tooltip_selfmesh;
345 if (this.tooltip_mesh) {
346 tooltip_mesh = this.tooltip_mesh;
347 this.toplevel.remove(this.tooltip_mesh);
348 delete this.tooltip_mesh;
353 if (changed) this.Render3D();
354 this.ProvideUserTooltip(null);
358 if (tip.use_itself) {
359 selfmesh.save_color = selfmesh.material.color;
360 selfmesh.material.color =
new THREE.Color(tip.color);
361 this.tooltip_selfmesh = selfmesh;
362 changed = changed_self;
366 var indicies = JSROOT.Painter.Box3D.Indexes,
367 normals = JSROOT.Painter.Box3D.Normals,
368 vertices = JSROOT.Painter.Box3D.Vertices,
370 color =
new THREE.Color(tip.color ? tip.color : 0xFF0000),
371 opacity = tip.opacity || 1;
374 pos =
new Float32Array(indicies.length*3);
375 norm =
new Float32Array(indicies.length*3);
376 var geom =
new THREE.BufferGeometry();
377 geom.addAttribute(
'position',
new THREE.BufferAttribute( pos, 3 ) );
378 geom.addAttribute(
'normal',
new THREE.BufferAttribute( norm, 3 ) );
379 var mater =
new THREE.MeshBasicMaterial( { color: color, opacity: opacity, flatShading:
true } );
380 tooltip_mesh =
new THREE.Mesh(geom, mater);
382 pos = tooltip_mesh.geometry.attributes.position.array;
383 tooltip_mesh.geometry.attributes.position.needsUpdate =
true;
384 tooltip_mesh.material.color = color;
385 tooltip_mesh.material.opacity = opacity;
388 if (tip.x1 === tip.x2) console.warn(
'same tip X', tip.x1, tip.x2);
389 if (tip.y1 === tip.y2) console.warn(
'same tip Y', tip.y1, tip.y2);
390 if (tip.z1 === tip.z2) { tip.z2 = tip.z1 + 0.0001; }
392 for (var k=0,nn=-3;k<indicies.length;++k) {
393 var vert = vertices[indicies[k]];
394 pos[k*3] = tip.x1 + vert.x * (tip.x2 - tip.x1);
395 pos[k*3+1] = tip.y1 + vert.y * (tip.y2 - tip.y1);
396 pos[k*3+2] = tip.z1 + vert.z * (tip.z2 - tip.z1);
400 norm[k*3] = normals[nn];
401 norm[k*3+1] = normals[nn+1];
402 norm[k*3+2] = normals[nn+2];
405 this.tooltip_mesh = tooltip_mesh;
406 this.toplevel.add(tooltip_mesh);
409 if (changed) this.Render3D();
411 if (changed && tip.$painter && (typeof tip.$painter.RedrawProjection ==
'function'))
412 tip.$painter.RedrawProjection(tip.ix-1, tip.ix, tip.iy-1, tip.iy);
414 if (this.GetObject())
415 this.ProvideUserTooltip({ obj: this.GetObject(), name: this.GetObject().fName,
416 bin: tip.bin, cont: tip.value,
417 binx: tip.ix, biny: tip.iy, binz: tip.iz,
418 grx: (tip.x1+tip.x2)/2, gry: (tip.y1+tip.y2)/2, grz: (tip.z1+tip.z2)/2 });
421 JSROOT.TFramePainter.prototype.TestAxisVisibility =
function(camera, toplevel, fb, bb) {
423 if (toplevel && toplevel.children)
424 for (var n=0;n<toplevel.children.length;++n) {
425 top = toplevel.children[n];
426 if (top.axis_draw)
break;
434 toplevel.remove(top);
439 fb = fb ?
true :
false;
440 bb = bb ?
true :
false;
442 var qudrant = 1, pos = camera.position;
443 if ((pos.x < 0) && (pos.y >= 0)) qudrant = 2;
444 if ((pos.x >= 0) && (pos.y >= 0)) qudrant = 3;
445 if ((pos.x >= 0) && (pos.y < 0)) qudrant = 4;
447 function testvisible(
id, range) {
448 if (
id <= qudrant)
id+=4;
449 return (
id > qudrant) && (
id < qudrant+range);
452 for (var n=0;n<top.children.length;++n) {
453 var chld = top.children[n];
454 if (chld.grid) chld.visible = bb && testvisible(chld.grid, 3);
else
455 if (chld.zid) chld.visible = testvisible(chld.zid, 2);
else
456 if (chld.xyid) chld.visible = testvisible(chld.xyid, 3);
else
458 var range = 5, shift = 0;
459 if (bb && !fb) { range = 3; shift = -2; }
else
460 if (fb && !bb) range = 3;
else
461 if (!fb && !bb) range = (chld.bottom ? 3 : 0);
462 chld.visible = testvisible(chld.xyboxid + shift, range);
463 if (!chld.visible && chld.bottom && bb)
464 chld.visible = testvisible(chld.xyboxid, 3);
467 var range = 2, shift = 0;
468 if (fb && bb) range = 5;
else
469 if (bb && !fb) range = 4;
else
470 if (!bb && fb) { shift = -2; range = 4; }
471 chld.visible = testvisible(chld.zboxid + shift, range);
476 JSROOT.TFramePainter.prototype.Set3DOptions =
function(hopt) {
480 JSROOT.TFramePainter.prototype.DrawXYZ =
function(toplevel, opts) {
481 if (!opts) opts = {};
483 var grminx = -this.size_xy3d, grmaxx = this.size_xy3d,
484 grminy = -this.size_xy3d, grmaxy = this.size_xy3d,
485 grminz = 0, grmaxz = 2*this.size_z3d,
486 textsize = Math.round(this.size_z3d * 0.05),
487 pad = this.root_pad(),
488 xmin = this.xmin, xmax = this.xmax,
489 ymin = this.ymin, ymax = this.ymax,
490 zmin = this.zmin, zmax = this.zmax,
491 y_zoomed =
false, z_zoomed =
false;
493 if (!this.size_z3d) {
494 grminx = this.xmin; grmaxx = this.xmax;
495 grminy = this.ymin; grmaxy = this.ymax;
496 grminz = this.zmin; grmaxz = this.zmax;
497 textsize = (grmaxz - grminz) * 0.05;
500 if ((
'zoom_xmin' in
this) && (
'zoom_xmax' in
this) && (this.zoom_xmin !== this.zoom_xmax)) {
501 xmin = this.zoom_xmin; xmax = this.zoom_xmax;
503 if ((
'zoom_ymin' in
this) && (
'zoom_ymax' in
this) && (this.zoom_ymin !== this.zoom_ymax)) {
504 ymin = this.zoom_ymin; ymax = this.zoom_ymax; y_zoomed =
true;
507 if ((
'zoom_zmin' in
this) && (
'zoom_zmax' in
this) && (this.zoom_zmin !== this.zoom_zmax)) {
508 zmin = this.zoom_zmin; zmax = this.zoom_zmax; z_zoomed =
true;
511 if (opts.use_y_for_z) {
512 this.zmin = this.ymin; this.zmax = this.ymax;
513 zmin = ymin; zmax = ymax; z_zoomed = y_zoomed;
519 this.lego_zmin = zmin; this.lego_zmax = zmax;
522 if ((opts.zmult !== undefined) && !z_zoomed) zmax *= opts.zmult;
526 if (pad && pad.fLogx) {
527 if (xmax <= 0) xmax = 1.;
528 if ((xmin <= 0) && this.xaxis)
529 for (var i=0;i<this.xaxis.fNbins;++i) {
530 xmin = Math.max(xmin, this.xaxis.GetBinLowEdge(i+1));
533 if (xmin <= 0) xmin = 1e-4*xmax;
534 this.grx = d3.scaleLog();
537 this.grx = d3.scaleLinear();
538 if (this.xaxis && this.xaxis.fLabels) this.x_kind =
"labels";
539 else this.x_kind =
"normal";
542 this.logx = (this.x_kind ===
"log");
544 this.grx.domain([ xmin, xmax ]).range([ grminx, grmaxx ]);
545 this.x_handle =
new JSROOT.TAxisPainter(this.xaxis);
546 this.x_handle.SetAxisConfig(
"xaxis", this.x_kind, this.grx, this.xmin, this.xmax, xmin, xmax);
547 this.x_handle.CreateFormatFuncs();
548 this.scale_xmin = xmin; this.scale_xmax = xmax;
550 if (pad && pad.fLogy && !opts.use_y_for_z) {
551 if (ymax <= 0) ymax = 1.;
552 if ((ymin <= 0) && this.yaxis)
553 for (var i=0;i<this.yaxis.fNbins;++i) {
554 ymin = Math.max(ymin, this.yaxis.GetBinLowEdge(i+1));
558 if (ymin <= 0) ymin = 1e-4*ymax;
559 this.gry = d3.scaleLog();
562 this.gry = d3.scaleLinear();
563 if (this.yaxis && this.yaxis.fLabels) this.y_kind =
"labels";
564 else this.y_kind =
"normal";
567 this.logy = (this.y_kind ===
"log");
569 this.gry.domain([ ymin, ymax ]).range([ grminy, grmaxy ]);
570 this.y_handle =
new JSROOT.TAxisPainter(this.yaxis);
571 this.y_handle.SetAxisConfig(
"yaxis", this.y_kind, this.gry, this.ymin, this.ymax, ymin, ymax);
572 this.y_handle.CreateFormatFuncs();
573 this.scale_ymin = ymin; this.scale_ymax = ymax;
575 if (pad && pad.fLogz) {
576 if (zmax <= 0) zmax = 1;
577 if (zmin <= 0) zmin = 1e-4*zmax;
578 this.grz = d3.scaleLog();
581 this.grz = d3.scaleLinear();
582 this.z_kind =
"normal";
583 if (this.zaxis && this.zaxis.fLabels && (opts.ndim === 3)) this.z_kind =
"labels";
586 this.logz = (this.z_kind ===
"log");
588 this.grz.domain([ zmin, zmax ]).range([ grminz, grmaxz ]);
590 this.SetRootPadRange(pad,
true);
592 this.z_handle =
new JSROOT.TAxisPainter(this.zaxis);
593 this.z_handle.SetAxisConfig(
"zaxis", this.z_kind, this.grz, this.zmin, this.zmax, zmin, zmax);
594 this.z_handle.CreateFormatFuncs();
595 this.scale_zmin = zmin; this.scale_zmax = zmax;
597 this.x_handle.debug =
true;
599 var textMaterial =
new THREE.MeshBasicMaterial({ color: 0x000000 }),
600 lineMaterial =
new THREE.LineBasicMaterial({ color: 0x000000 }),
601 ticklen = textsize*0.5, text, tick, lbls = [], text_scale = 1,
602 xticks = this.x_handle.CreateTicks(
false,
true),
603 yticks = this.y_handle.CreateTicks(
false,
true),
604 zticks = this.z_handle.CreateTicks(
false,
true);
607 var top =
new THREE.Object3D();
608 top.axis_draw =
true;
611 var ticks = [], maxtextheight = 0, xaxis = this.xaxis;
613 while (xticks.next()) {
614 var grx = xticks.grpos,
615 is_major = (xticks.kind===1),
616 lbl = this.x_handle.format(xticks.tick,
true,
true);
617 if (xticks.last_major()) {
if (!xaxis || !xaxis.fTitle) lbl =
"x"; }
else
618 if (lbl === null) { is_major =
false; lbl =
""; }
620 if (is_major && lbl && (lbl.length>0)) {
621 var text3d =
new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
622 text3d.computeBoundingBox();
623 var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
624 draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
625 text3d.center =
true;
629 maxtextheight = Math.max(maxtextheight, draw_height);
634 if (!xticks.last_major()) {
635 var space = (xticks.next_major_grpos() - grx);
637 text_scale = Math.min(text_scale, 0.9*space/draw_width)
638 if (this.x_handle.IsCenterLabels()) text3d.grx += space/2;
642 ticks.push(grx, 0, 0, grx, (is_major ? -ticklen : -ticklen * 0.6), 0);
645 if (xaxis && xaxis.fTitle) {
646 var text3d =
new THREE.TextGeometry(xaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
647 text3d.computeBoundingBox();
648 text3d.center = (xaxis.TestBit(JSROOT.EAxisBits.kCenterTitle));
650 text3d.grx = (grminx + grmaxx)/2;
654 this.Get3DZoomCoord =
function(point, kind) {
656 var pos = point[kind], min =
this[
'scale_'+kind+
'min'], max =
this[
'scale_'+kind+
'max'];
658 if (kind===
"z") pos = pos/2/this.size_z3d;
659 else pos = (pos+this.size_xy3d)/2/this.size_xy3d;
661 if (
this[
"log"+kind]) {
662 pos = Math.exp(Math.log(min) + pos*(Math.log(max)-Math.log(min)));
664 pos = min + pos*(max-min);
669 function CreateZoomMesh(kind, size_3d, use_y_for_z) {
670 var geom =
new THREE.Geometry();
674 new THREE.Vector3(0,0,0),
675 new THREE.Vector3(ticklen*4, 0, 0),
676 new THREE.Vector3(ticklen*4, 0, 2*size_3d),
677 new THREE.Vector3(0, 0, 2*size_3d));
680 new THREE.Vector3(-size_3d,0,0),
681 new THREE.Vector3(size_3d,0,0),
682 new THREE.Vector3(size_3d,-ticklen*4,0),
683 new THREE.Vector3(-size_3d,-ticklen*4,0));
685 geom.faces.push(
new THREE.Face3(0, 2, 1));
686 geom.faces.push(
new THREE.Face3(0, 3, 2));
687 geom.computeFaceNormals();
689 var material =
new THREE.MeshBasicMaterial({ transparent:
true,
690 vertexColors: THREE.NoColors,
691 side: THREE.DoubleSide,
694 var mesh =
new THREE.Mesh(geom, material);
696 mesh.size_3d = size_3d;
697 mesh.use_y_for_z = use_y_for_z;
698 if (kind==
"y") mesh.rotateZ(Math.PI/2).rotateX(Math.PI);
700 mesh.GlobalIntersect =
function(raycaster) {
701 var plane =
new THREE.Plane(),
702 geom = this.geometry;
704 if (!geom || !geom.vertices)
return undefined;
706 plane.setFromCoplanarPoints(geom.vertices[0], geom.vertices[1], geom.vertices[2]);
707 plane.applyMatrix4(this.matrixWorld);
709 var v1 = raycaster.ray.origin.clone(),
710 v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10);
712 var pnt = plane.intersectLine(
new THREE.Line3(v1,v2),
new THREE.Vector3());
714 if (!pnt)
return undefined;
716 var min = -this.size_3d, max = this.size_3d;
717 if (this.zoom===
"z") { min = 0; max = 2*this.size_3d; }
719 if (pnt[this.zoom] < min) pnt[this.zoom] = min;
else
720 if (pnt[this.zoom] > max) pnt[this.zoom] = max;
725 mesh.ShowSelection =
function(pnt1,pnt2) {
728 var tgtmesh = this.children ? this.children[0] : null, gg, kind = this.zoom;
729 if (!pnt1 || !pnt2) {
732 JSROOT.Painter.DisposeThreejsObject(tgtmesh);
738 gg = this.geometry.clone();
739 if (kind===
"z") gg.vertices[1].x = gg.vertices[2].x = ticklen;
740 else gg.vertices[2].y = gg.vertices[3].y = -ticklen;
741 tgtmesh =
new THREE.Mesh(gg,
new THREE.MeshBasicMaterial({ color: 0xFF00, side: THREE.DoubleSide }));
744 gg = tgtmesh.geometry;
748 gg.vertices[0].z = gg.vertices[1].z = pnt1[kind];
749 gg.vertices[2].z = gg.vertices[3].z = pnt2[kind];
751 gg.vertices[0].x = gg.vertices[3].x = pnt1[kind];
752 gg.vertices[1].x = gg.vertices[2].x = pnt2[kind];
755 gg.computeFaceNormals();
757 gg.verticesNeedUpdate =
true;
758 gg.normalsNeedUpdate =
true;
766 var xcont =
new THREE.Object3D();
767 xcont.position.set(0, grminy, grminz)
768 xcont.rotation.x = 1/4*Math.PI;
770 var xtickslines = JSROOT.Painter.createLineSegments( ticks, lineMaterial );
771 xcont.add(xtickslines);
773 lbls.forEach(
function(lbl) {
774 var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
775 posx = lbl.center ? lbl.grx - w/2 : grmaxx - w,
776 m =
new THREE.Matrix4();
778 m.set(text_scale, 0, 0, posx,
779 0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen) * (lbl.gry || 1),
783 var mesh =
new THREE.Mesh(lbl, textMaterial);
788 if (opts.zoom) xcont.add(CreateZoomMesh(
"x", this.size_xy3d));
791 xcont =
new THREE.Object3D();
792 xcont.position.set(0, grmaxy, grminz);
793 xcont.rotation.x = 3/4*Math.PI;
794 xcont.add(
new THREE.LineSegments(xtickslines.geometry, lineMaterial));
795 lbls.forEach(
function(lbl) {
797 var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
798 posx = lbl.center ? lbl.grx + w/2 : grmaxx,
799 m =
new THREE.Matrix4();
801 m.set(-text_scale, 0, 0, posx,
802 0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen) * (lbl.gry || 1),
805 var mesh =
new THREE.Mesh(lbl, textMaterial);
812 if (opts.zoom) xcont.add(CreateZoomMesh(
"x", this.size_xy3d));
815 lbls = []; text_scale = 1; maxtextheight = 0; ticks = [];
817 var yaxis = this.yaxis;
819 while (yticks.next()) {
820 var gry = yticks.grpos,
821 is_major = (yticks.kind===1),
822 lbl = this.y_handle.format(yticks.tick,
true,
true);
823 if (yticks.last_major()) {
if (!yaxis || !yaxis.fTitle) lbl =
"y"; }
else
824 if (lbl === null) { is_major =
false; lbl =
""; }
827 var text3d =
new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
828 text3d.computeBoundingBox();
829 var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
830 draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
832 text3d.center =
true;
834 maxtextheight = Math.max(maxtextheight, draw_height);
839 if (!yticks.last_major()) {
840 var space = (yticks.next_major_grpos() - gry);
842 text_scale = Math.min(text_scale, 0.9*space/draw_width)
843 if (this.y_handle.IsCenterLabels()) text3d.gry += space/2;
846 ticks.push(0,gry,0, (is_major ? -ticklen : -ticklen*0.6), gry, 0);
849 if (yaxis && yaxis.fTitle) {
850 var text3d =
new THREE.TextGeometry(yaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
851 text3d.computeBoundingBox();
852 text3d.center = yaxis.TestBit(JSROOT.EAxisBits.kCenterTitle);
854 text3d.gry = (grminy + grmaxy)/2;
858 if (!opts.use_y_for_z) {
859 var yticksline = JSROOT.Painter.createLineSegments(ticks, lineMaterial),
860 ycont =
new THREE.Object3D();
861 ycont.position.set(grminx, 0, grminz);
862 ycont.rotation.y = -1/4*Math.PI;
863 ycont.add(yticksline);
866 lbls.forEach(
function(lbl) {
868 var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
869 posy = lbl.center ? lbl.gry + w/2 : grmaxy,
870 m =
new THREE.Matrix4();
872 m.set(0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen)*(lbl.grx || 1),
873 -text_scale, 0, 0, posy,
877 var mesh =
new THREE.Mesh(lbl, textMaterial);
883 if (opts.zoom) ycont.add(CreateZoomMesh(
"y", this.size_xy3d));
886 ycont =
new THREE.Object3D();
887 ycont.position.set(grmaxx, 0, grminz);
888 ycont.rotation.y = -3/4*Math.PI;
889 ycont.add(
new THREE.LineSegments(yticksline.geometry, lineMaterial));
891 lbls.forEach(
function(lbl) {
892 var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
893 posy = lbl.center ? lbl.gry - w/2 : grmaxy - w,
894 m =
new THREE.Matrix4();
895 m.set(0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen)*(lbl.grx || 1),
896 text_scale, 0, 0, posy,
900 var mesh =
new THREE.Mesh(lbl, textMaterial);
905 if (opts.zoom) ycont.add(CreateZoomMesh(
"y", this.size_xy3d));
910 lbls = []; text_scale = 1;
914 var zgridx = null, zgridy = null, lastmajorz = null,
915 zaxis = this.zaxis, maxzlblwidth = 0;
918 zgridx = []; zgridy = [];
921 while (zticks.next()) {
922 var grz = zticks.grpos,
923 is_major = (zticks.kind == 1),
924 lbl = this.z_handle.format(zticks.tick,
true,
true);
925 if (lbl === null) { is_major =
false; lbl =
""; }
927 if (is_major && lbl) {
928 var text3d =
new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
929 text3d.computeBoundingBox();
930 var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
931 draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
932 text3d.translate(-draw_width, -draw_height/2, 0);
936 if ((lastmajorz !== null) && (draw_height>0))
937 text_scale = Math.min(text_scale, 0.9*(grz - lastmajorz)/draw_height);
939 maxzlblwidth = Math.max(maxzlblwidth, draw_width);
945 if (zgridx && is_major)
946 zgridx.push(grminx,0,grz, grmaxx,0,grz);
948 if (zgridy && is_major)
949 zgridy.push(0,grminy,grz, 0,grmaxy,grz);
951 ticks.push(0, 0, grz, (is_major ? ticklen : ticklen * 0.6), 0, grz);
954 if (zgridx && (zgridx.length > 0)) {
956 var material =
new THREE.LineDashedMaterial({ color: 0x0, dashSize: 2, gapSize: 2 });
958 var lines1 = JSROOT.Painter.createLineSegments(zgridx, material);
959 lines1.position.set(0,grmaxy,0);
961 lines1.visible =
false;
964 var lines2 =
new THREE.LineSegments(lines1.geometry, material);
965 lines2.position.set(0,grminy,0);
967 lines2.visible =
false;
971 if (zgridy && (zgridy.length > 0)) {
973 var material =
new THREE.LineDashedMaterial({ color: 0x0, dashSize: 2, gapSize: 2 });
975 var lines1 = JSROOT.Painter.createLineSegments(zgridy, material);
976 lines1.position.set(grmaxx,0, 0);
978 lines1.visible =
false;
981 var lines2 =
new THREE.LineSegments(lines1.geometry, material);
982 lines2.position.set(grminx, 0, 0);
984 lines2.visible =
false;
988 var zcont = [], zticksline = JSROOT.Painter.createLineSegments( ticks, lineMaterial );
989 for (var n=0;n<4;++n) {
990 zcont.push(
new THREE.Object3D());
992 lbls.forEach(
function(lbl) {
993 var m =
new THREE.Matrix4();
995 m.set(-text_scale, 0, 0, 2*ticklen,
997 0, text_scale, 0, lbl.grz);
998 var mesh =
new THREE.Mesh(lbl, textMaterial);
1003 if (zaxis && zaxis.fTitle) {
1004 var text3d =
new THREE.TextGeometry(zaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 });
1005 text3d.computeBoundingBox();
1006 var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
1007 draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y,
1008 posz = zaxis.TestBit(JSROOT.EAxisBits.kCenterTitle) ? (grmaxz + grminz - draw_width)/2 : grmaxz - draw_width;
1010 text3d.rotateZ(Math.PI/2);
1012 var m =
new THREE.Matrix4();
1013 m.set(-text_scale, 0, 0, 3*ticklen + maxzlblwidth,
1015 0, text_scale, 0, posz);
1016 var mesh =
new THREE.Mesh(text3d, textMaterial);
1017 mesh.applyMatrix(m);
1021 zcont[n].add(n==0 ? zticksline :
new THREE.LineSegments(zticksline.geometry, lineMaterial));
1022 if (opts.zoom) zcont[n].add(CreateZoomMesh(
"z", this.size_z3d, opts.use_y_for_z));
1024 zcont[n].zid = n + 2;
1028 zcont[0].position.set(grminx,grmaxy,0);
1029 zcont[0].rotation.z = 3/4*Math.PI;
1031 zcont[1].position.set(grmaxx,grmaxy,0);
1032 zcont[1].rotation.z = 1/4*Math.PI;
1034 zcont[2].position.set(grmaxx,grminy,0);
1035 zcont[2].rotation.z = -1/4*Math.PI;
1037 zcont[3].position.set(grminx,grminy,0);
1038 zcont[3].rotation.z = -3/4*Math.PI;
1042 if (this.size_z3d === 0)
return;
1044 var linex_geom = JSROOT.Painter.createLineSegments([grminx,0,0, grmaxx,0,0], lineMaterial, null,
true);
1045 for(var n=0;n<2;++n) {
1046 var line =
new THREE.LineSegments(linex_geom, lineMaterial);
1047 line.position.set(0, grminy, (n===0) ? grminz : grmaxz);
1048 line.xyboxid = 2; line.bottom = (n == 0);
1051 line =
new THREE.LineSegments(linex_geom, lineMaterial);
1052 line.position.set(0, grmaxy, (n===0) ? grminz : grmaxz);
1053 line.xyboxid = 4; line.bottom = (n == 0);
1057 var liney_geom = JSROOT.Painter.createLineSegments([0,grminy,0, 0,grmaxy,0], lineMaterial, null,
true);
1058 for(var n=0;n<2;++n) {
1059 var line =
new THREE.LineSegments(liney_geom, lineMaterial);
1060 line.position.set(grminx, 0, (n===0) ? grminz : grmaxz);
1061 line.xyboxid = 3; line.bottom = (n == 0);
1064 line =
new THREE.LineSegments(liney_geom, lineMaterial);
1065 line.position.set(grmaxx, 0, (n===0) ? grminz : grmaxz);
1066 line.xyboxid = 1; line.bottom = (n == 0);
1070 var linez_geom = JSROOT.Painter.createLineSegments([0,0,grminz, 0,0,grmaxz], lineMaterial, null,
true);
1071 for(var n=0;n<4;++n) {
1072 var line =
new THREE.LineSegments(linez_geom, lineMaterial);
1073 line.zboxid = zcont[n].zid;
1074 line.position.copy(zcont[n].position);
1080 JSROOT.THistPainter.prototype.Draw3DBins =
function() {
1082 if (!this.draw_content)
return;
1084 if (this.IsTH2Poly() && this.DrawPolyLego)
1085 return this.DrawPolyLego();
1087 if ((this.Dimension()==2) && this.options.Contour && this.DrawContour3D)
1088 return this.DrawContour3D(
true);
1090 if ((this.Dimension()==2) && this.options.Surf && this.DrawSurf)
1091 return this.DrawSurf();
1093 if ((this.Dimension()==2) && this.options.Error && this.DrawError)
1094 return this.DrawError();
1098 var vertices = JSROOT.Painter.Box3D.Vertices,
1099 indicies = JSROOT.Painter.Box3D.Indexes,
1100 vnormals = JSROOT.Painter.Box3D.Normals,
1101 segments = JSROOT.Painter.Box3D.Segments,
1103 rsegments = [0, 1, 1, 2, 2, 3, 3, 0],
1105 rvertices = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 1, 0),
new THREE.Vector3(1, 0, 0) ],
1106 main = this.frame_painter(),
1107 axis_zmin = main.grz.domain()[0],
1108 axis_zmax = main.grz.domain()[1],
1109 handle = this.PrepareColorDraw({ rounding:
false, use3d:
true, extra: 1 }),
1110 i1 = handle.i1, i2 = handle.i2, j1 = handle.j1, j2 = handle.j2,
1111 i, j, x1, x2, y1, y2, binz1, binz2, reduced, nobottom, notop,
1113 histo =
this.GetHisto(),
1114 basehisto = histo ? histo.$baseh : null,
1115 split_faces = (this.options.Lego === 11) || (this.options.Lego === 13);
1117 if ((i1 >= i2) || (j1 >= j2))
return;
1119 function GetBinContent(ii,jj, level) {
1123 binz2 = histo.getBinContent(ii+1, jj+1);
1125 binz1 = basehisto.getBinContent(ii+1, jj+1);
1126 else if (pthis.options.BaseLine !==
false)
1127 binz1 = pthis.options.BaseLine;
1129 binz1 = pthis.options.Zero ? axis_zmin : 0;
1130 if (binz2 < binz1) { var d = binz1; binz1 = binz2; binz2 = d; }
1132 if ((binz1 >= zmax) || (binz2 < zmin))
return false;
1134 reduced = (binz2 === zmin) || (binz1 >= binz2);
1136 if (!reduced || (level>0))
return true;
1138 if (histo[
'$baseh'])
return false;
1140 if (pthis.options.Zero || (axis_zmin>0))
return true;
1142 return pthis._show_empty_bins;
1146 var use16indx = (histo.getBin(i2, j2) < 0xFFFF),
1147 levels = [ axis_zmin, axis_zmax ], palette = null, totalvertices = 0;
1151 if ((this.options.Lego === 12) || (this.options.Lego === 14)) {
1153 levels = this.CreateContour(histo.fContour ? histo.fContour.length : 20, main.lego_zmin, main.lego_zmax);
1154 palette = this.GetPalette();
1159 for (var nlevel=0; nlevel<levels.length-1;++nlevel) {
1161 var zmin = levels[nlevel], zmax = levels[nlevel+1],
1162 z1 = 0, z2 = 0, numvertices = 0, num2vertices = 0;
1165 if (palette && (nlevel==levels.length-2) && zmax < axis_zmax) zmax = axis_zmax;
1167 var grzmin = main.grz(zmin), grzmax = main.grz(zmax);
1172 for (j=j1;j<j2;++j) {
1174 if (!GetBinContent(i,j,nlevel))
continue;
1176 nobottom = !reduced && (nlevel>0);
1177 notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2);
1179 numvertices += (reduced ? 12 : indicies.length);
1180 if (nobottom) numvertices -= 6;
1181 if (notop) numvertices -= 6;
1183 if (split_faces && !reduced) {
1189 totalvertices += numvertices + num2vertices;
1191 var positions =
new Float32Array(numvertices*3),
1192 normals =
new Float32Array(numvertices*3),
1193 face_to_bins_index = use16indx ?
new Uint16Array(numvertices/3) : new Uint32Array(numvertices/3),
1194 pos2 = null, norm2 = null, face_to_bins_indx2 = null,
1195 v = 0, v2 = 0, vert, bin, k, nn;
1197 if (num2vertices > 0) {
1198 pos2 =
new Float32Array(num2vertices*3);
1199 norm2 =
new Float32Array(num2vertices*3);
1200 face_to_bins_indx2 = use16indx ?
new Uint16Array(num2vertices/3) : new Uint32Array(num2vertices/3);
1203 for (i=i1;i<i2;++i) {
1204 x1 = handle.grx[i] + handle.xbar1*(handle.grx[i+1]-handle.grx[i]);
1205 x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]);
1206 for (j=j1;j<j2;++j) {
1208 if (!GetBinContent(i,j,nlevel))
continue;
1210 nobottom = !reduced && (nlevel>0);
1211 notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2);
1213 y1 = handle.gry[j] + handle.ybar1*(handle.gry[j+1] - handle.gry[j]);
1214 y2 = handle.gry[j] + handle.ybar2*(handle.gry[j+1] - handle.gry[j]);
1216 z1 = (binz1 <= zmin) ? grzmin : main.grz(binz1);
1217 z2 = (binz2 > zmax) ? grzmax : main.grz(binz2);
1228 var size = indicies.length, bin_index = histo.getBin(i+1, j+1);
1229 if (nobottom) size -= 6;
1234 vert = vertices[indicies[k]];
1236 if (split_faces && (k < 12)) {
1237 pos2[v2] = x1 + vert.x * (x2 - x1);
1238 pos2[v2+1] = y1 + vert.y * (y2 - y1);
1239 pos2[v2+2] = z1 + vert.z * (z2 - z1);
1241 norm2[v2] = vnormals[nn];
1242 norm2[v2+1] = vnormals[nn+1];
1243 norm2[v2+2] = vnormals[nn+2];
1244 if (v2%9===0) face_to_bins_indx2[v2/9] = bin_index;
1247 positions[v] = x1 + vert.x * (x2 - x1);
1248 positions[v+1] = y1 + vert.y * (y2 - y1);
1249 positions[v+2] = z1 + vert.z * (z2 - z1);
1251 normals[v] = vnormals[nn];
1252 normals[v+1] = vnormals[nn+1];
1253 normals[v+2] = vnormals[nn+2];
1254 if (v%9===0) face_to_bins_index[v/9] = bin_index;
1262 if (notop && (k === indicies.length - 12)) {
1270 var geometry =
new THREE.BufferGeometry();
1271 geometry.addAttribute(
'position',
new THREE.BufferAttribute( positions, 3 ) );
1272 geometry.addAttribute(
'normal',
new THREE.BufferAttribute( normals, 3 ) );
1275 var rootcolor = histo.fFillColor,
1276 fcolor = this.get_color(rootcolor);
1279 fcolor = palette.calcColor(nlevel, levels.length);
1281 if ((this.options.Lego === 1) || (rootcolor < 2)) {
1288 var material =
new THREE.MeshBasicMaterial( { color: fcolor, flatShading:
true } );
1290 var mesh =
new THREE.Mesh(geometry, material);
1292 mesh.face_to_bins_index = face_to_bins_index;
1293 mesh.painter =
this;
1294 mesh.zmin = axis_zmin;
1295 mesh.zmax = axis_zmax;
1296 mesh.baseline = (this.options.BaseLine!==
false) ? this.options.BaseLine : (
this.options.Zero ? axis_zmin : 0);
1297 mesh.tip_color = (rootcolor===3) ? 0xFF0000 : 0x00FF00;
1298 mesh.handle = handle;
1300 mesh.tooltip =
function(intersect) {
1301 if (isNaN(intersect.faceIndex)) {
1302 console.error(
'faceIndex not provided, check three.js version', THREE.REVISION,
'expected r97');
1306 if ((intersect.faceIndex < 0) || (intersect.faceIndex >=
this.face_to_bins_index.length))
return null;
1308 var p = this.painter,
1309 handle = this.handle,
1310 main = p.frame_painter(),
1311 histo = p.GetHisto(),
1312 tip = p.Get3DToolTip( this.face_to_bins_index[intersect.faceIndex] );
1314 tip.x1 = Math.max(-main.size_xy3d, handle.grx[tip.ix-1] + handle.xbar1*(handle.grx[tip.ix]-handle.grx[tip.ix-1]));
1315 tip.x2 = Math.min(main.size_xy3d, handle.grx[tip.ix-1] + handle.xbar2*(handle.grx[tip.ix]-handle.grx[tip.ix-1]));
1317 tip.y1 = Math.max(-main.size_xy3d, handle.gry[tip.iy-1] + handle.ybar1*(handle.gry[tip.iy] - handle.gry[tip.iy-1]));
1318 tip.y2 = Math.min(main.size_xy3d, handle.gry[tip.iy-1] + handle.ybar2*(handle.gry[tip.iy] - handle.gry[tip.iy-1]));
1320 var binz1 = this.baseline, binz2 = tip.value;
1321 if (histo[
'$baseh']) binz1 = histo[
'$baseh'].getBinContent(tip.ix, tip.iy);
1322 if (binz2<binz1) { var v = binz1; binz1 = binz2; binz2 = v; }
1324 tip.z1 = main.grz(Math.max(
this.zmin,binz1));
1325 tip.z2 = main.grz(Math.min(
this.zmax,binz2));
1327 tip.color = this.tip_color;
1329 if (p.is_projection && (p.Dimension()==2)) tip.$painter = p;
1334 main.toplevel.add(mesh);
1336 if (num2vertices > 0) {
1337 var geom2 =
new THREE.BufferGeometry();
1338 geom2.addAttribute(
'position',
new THREE.BufferAttribute( pos2, 3 ) );
1339 geom2.addAttribute(
'normal',
new THREE.BufferAttribute( norm2, 3 ) );
1344 var color2 = (rootcolor<2) ?
new THREE.Color(0xFF0000) :
1345 new THREE.Color(d3.rgb(fcolor).darker(0.5).toString());
1347 var material2 =
new THREE.MeshBasicMaterial( { color: color2, flatShading:
true } );
1349 var mesh2 =
new THREE.Mesh(geom2, material2);
1350 mesh2.face_to_bins_index = face_to_bins_indx2;
1351 mesh2.painter =
this;
1352 mesh2.handle = mesh.handle;
1353 mesh2.tooltip = mesh.tooltip;
1354 mesh2.zmin = mesh.zmin;
1355 mesh2.zmax = mesh.zmax;
1356 mesh2.baseline = mesh.baseline;
1357 mesh2.tip_color = mesh.tip_color;
1359 main.toplevel.add(mesh2);
1364 if (this.options.Lego > 12)
return;
1368 var numlinevertices = 0, numsegments = 0, uselineindx =
true, nskip = 0;
1370 zmax = axis_zmax; zmin = axis_zmin;
1373 for (j=j1;j<j2;++j) {
1374 if (!GetBinContent(i,j,0)) { nskip++;
continue; }
1377 numlinevertices += (reduced ? rvertices.length : vertices.length);
1378 numsegments += (reduced ? rsegments.length : segments.length);
1384 if (numlinevertices > 0xFFF0) uselineindx =
false;
1386 if (!uselineindx) numlinevertices = numsegments*3;
1388 var lpositions =
new Float32Array( numlinevertices * 3 ),
1389 lindicies = uselineindx ?
new Uint16Array( numsegments ) : null,
1390 grzmin = main.grz(axis_zmin),
1391 grzmax = main.grz(axis_zmax),
1392 z1 = 0, z2 = 0, ll = 0, ii = 0;
1394 for (i=i1;i<i2;++i) {
1395 x1 = handle.grx[i] + handle.xbar1*(handle.grx[i+1]-handle.grx[i]);
1396 x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]);
1397 for (j=j1;j<j2;++j) {
1399 if (!GetBinContent(i,j,0))
continue;
1401 y1 = handle.gry[j] + handle.ybar1*(handle.gry[j+1] - handle.gry[j]);
1402 y2 = handle.gry[j] + handle.ybar2*(handle.gry[j+1] - handle.gry[j]);
1404 z1 = (binz1 <= axis_zmin) ? grzmin : main.grz(binz1);
1405 z2 = (binz2 > axis_zmax) ? grzmax : main.grz(binz2);
1407 var seg = reduced ? rsegments : segments,
1408 vvv = reduced ? rvertices : vertices;
1412 for (k=0; k < seg.length; ++k) {
1414 lindicies[ii++] = ll/3 + seg[k];
1417 for (k=0; k < vvv.length; ++k) {
1419 lpositions[ll] = x1 + vert.x * (x2 - x1);
1420 lpositions[ll+1] = y1 + vert.y * (y2 - y1);
1421 lpositions[ll+2] = z1 + vert.z * (z2 - z1);
1426 for (k=0; k < seg.length; ++k) {
1428 lpositions[ll] = x1 + vert.x * (x2 - x1);
1429 lpositions[ll+1] = y1 + vert.y * (y2 - y1);
1430 lpositions[ll+2] = z1 + vert.z * (z2 - z1);
1439 var lcolor = this.get_color(histo.fLineColor);
1440 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(lcolor) });
1441 if (!JSROOT.browser.isIE) material.linewidth = histo.fLineWidth;
1443 var line = JSROOT.Painter.createLineSegments(lpositions, material, uselineindx ? lindicies : null );
1454 main.toplevel.add(line);
1459 JSROOT.Painter.drawAxis3D =
function(divid, axis, opt) {
1461 var painter =
new JSROOT.TObjectPainter(axis);
1463 if (!(
'_main' in axis))
1464 painter.SetDivId(divid);
1466 painter.Draw3DAxis =
function() {
1467 var main = this.frame_painter();
1469 if (!main || !main._toplevel)
1470 return console.warn(
'no geo object found for 3D axis drawing');
1472 var box =
new THREE.Box3().setFromObject(main._toplevel);
1474 this.xmin = box.min.x; this.xmax = box.max.x;
1475 this.ymin = box.min.y; this.ymax = box.max.y;
1476 this.zmin = box.min.z; this.zmax = box.max.z;
1479 this.size_xy3d = this.size_z3d = 0;
1481 this.DrawXYZ = JSROOT.TFramePainter.prototype.DrawXYZ;
1483 this.DrawXYZ(main._toplevel);
1485 main.adjustCameraPosition();
1490 painter.Draw3DAxis();
1492 return painter.DrawingReady();
1498 JSROOT.TH1Painter.prototype.Draw3D =
function(call_back, resize) {
1502 var main = this.frame_painter(),
1503 is_main = this.is_main_painter(),
1504 histo = this.GetHisto();
1508 if (is_main && main.Resize3D()) main.Render3D();
1514 this.ScanContent(
true);
1517 main.Create3DScene();
1518 main.SetAxesRanges(histo.fXaxis,
this.xmin,
this.xmax, histo.fYaxis,
this.ymin,
this.ymax, histo.fZaxis, 0, 0);
1519 main.Set3DOptions(this.options);
1520 main.DrawXYZ(main.toplevel, { use_y_for_z:
true, zmult: 1.1, zoom: JSROOT.gStyle.Zooming, ndim: 1 });
1526 this.UpdateStatWebCanvas();
1527 main.AddKeysHandler();
1533 this.DrawColorPalette(this.options.Zscale && ((
this.options.Lego===12) || (
this.options.Lego===14)));
1538 JSROOT.CallBack(call_back);
1543 JSROOT.TH2Painter.prototype.Draw3D =
function(call_back, resize) {
1547 var main = this.frame_painter(),
1548 is_main = this.is_main_painter(),
1549 histo = this.GetHisto();
1553 if (is_main && main.Resize3D()) main.Render3D();
1557 var pad = this.root_pad(), zmult = 1.1;
1559 this.zmin = pad.fLogz ? this.gminposbin * 0.3 : this.gminbin;
1560 this.zmax = this.gmaxbin;
1562 if (this.options.minimum !== -1111) this.zmin = this.options.minimum;
1563 if (this.options.maximum !== -1111) { this.zmax = this.options.maximum; zmult = 1; }
1565 if (pad.fLogz && (
this.zmin<=0)) this.zmin = this.zmax * 1e-5;
1570 main.Create3DScene();
1571 main.SetAxesRanges(histo.fXaxis,
this.xmin,
this.xmax, histo.fYaxis,
this.ymin,
this.ymax, histo.fZaxis,
this.zmin,
this.zmax);
1572 main.Set3DOptions(this.options);
1573 main.DrawXYZ(main.toplevel, { zmult: zmult, zoom: JSROOT.gStyle.Zooming, ndim: 2 });
1579 this.UpdateStatWebCanvas();
1580 main.AddKeysHandler();
1587 this.DrawColorPalette(this.options.Zscale && ((
this.options.Lego===12) || (
this.options.Lego===14) ||
1588 (
this.options.Surf===11) || (
this.options.Surf===12)));
1593 JSROOT.CallBack(call_back);
1596 JSROOT.TH2Painter.prototype.DrawContour3D =
function(realz) {
1598 var main = this.frame_painter(),
1599 handle = this.PrepareColorDraw({rounding:
false, use3d:
true, extra: 100, middle: 0.0 }),
1600 histo = this.GetHisto(),
1601 levels = this.GetContour(),
1602 palette = this.GetPalette(),
1603 layerz = 2*main.size_z3d, pnts = [];
1605 this.BuildContour(handle, levels, palette,
1606 function(colindx,xp,yp,iminus,iplus,ilevel) {
1608 if (iplus - iminus < 3)
return;
1611 layerz = main.grz(levels[ilevel]);
1612 if ((layerz < 0) || (layerz > 2*main.size_z3d))
return;
1615 for (var i=iminus;i<iplus;++i) {
1616 pnts.push(xp[i], yp[i], layerz);
1617 pnts.push(xp[i+1], yp[i+1], layerz);
1622 var lines = JSROOT.Painter.createLineSegments(pnts, JSROOT.Painter.Create3DLineMaterial(
this, histo));
1623 main.toplevel.add(lines);
1626 JSROOT.TH2Painter.prototype.DrawSurf =
function() {
1627 var histo = this.GetHisto(),
1628 main = this.frame_painter(),
1629 handle = this.PrepareColorDraw({rounding:
false, use3d:
true, extra: 1, middle: 0.5 }),
1630 i,j, x1, y1, x2, y2, z11, z12, z21, z22,
1631 axis_zmin = main.grz.domain()[0],
1632 axis_zmax = main.grz.domain()[1];
1636 var main_grz = !main.logz ? main.grz :
function(value) {
return value < axis_zmin ? -0.1 : main.grz(value); }
1638 if ((handle.i2 - handle.i1 < 2) || (handle.j2 - handle.j1 < 2))
return;
1640 var ilevels = null, levels = null, dolines =
true, dogrid =
false,
1641 donormals =
false, palette = null;
1643 switch(this.options.Surf) {
1644 case 11: ilevels = this.GetContour(); palette = this.GetPalette();
break;
1647 case 17: ilevels = this.GetContour(); palette = this.GetPalette(); dolines =
false;
break;
1648 case 14: dolines =
false; donormals =
true;
break;
1649 case 16: ilevels = this.GetContour(); dogrid =
true; dolines =
false;
break;
1650 default: ilevels = main.z_handle.CreateTicks(
true); dogrid =
true;
break;
1655 levels =
new Float32Array(ilevels.length);
1656 for (var ll=0;ll<ilevels.length;++ll)
1657 levels[ll] = main_grz(ilevels[ll]);
1659 levels = [0, 2*main.size_z3d];
1662 var loop, nfaces = [], pos = [], indx = [],
1663 nsegments = 0, lpos = null, lindx = 0,
1664 ngridsegments = 0, grid = null, gindx = 0,
1667 function CheckSide(z,level1, level2) {
1668 if (z<level1)
return -1;
1669 if (z>level2)
return 1;
1673 function AddLineSegment(x1,y1,z1, x2,y2,z2) {
1674 if (!dolines)
return;
1675 var side1 = CheckSide(z1,0,2*main.size_z3d),
1676 side2 = CheckSide(z2,0,2*main.size_z3d);
1677 if ((side1===side2) && (side1!==0))
return;
1678 if (!loop)
return ++nsegments;
1682 z1 = (side1<0) ? 0 : 2*main.size_z3d;
1683 x1 = x2 - (x2-x1)/diff*(z2-z1);
1684 y1 = y2 - (y2-y1)/diff*(z2-z1);
1688 z2 = (side2<0) ? 0 : 2*main.size_z3d;
1689 x2 = x1 - (x1-x2)/diff*(z1-z2);
1690 y2 = y1 - (y1-y2)/diff*(z1-z2);
1693 lpos[lindx] = x1; lpos[lindx+1] = y1; lpos[lindx+2] = z1; lindx+=3;
1694 lpos[lindx] = x2; lpos[lindx+1] = y2; lpos[lindx+2] = z2; lindx+=3;
1697 var pntbuf =
new Float32Array(6*3), k = 0, lastpart = 0;
1698 var gridpnts =
new Float32Array(2*3), gridcnt = 0;
1700 function AddCrossingPoint(xx1,yy1,zz1, xx2,yy2,zz2, crossz, with_grid) {
1701 if (k>=pntbuf.length) console.log(
'more than 6 points???');
1703 var part = (crossz - zz1) / (zz2 - zz1), shift = 3;
1704 if ((lastpart!==0) && (Math.abs(part) < Math.abs(lastpart))) {
1706 pntbuf[k] = pntbuf[k-3];
1707 pntbuf[k+1] = pntbuf[k-2];
1708 pntbuf[k+2] = pntbuf[k-1];
1712 pntbuf[k] = xx1 + part*(xx2-xx1);
1713 pntbuf[k+1] = yy1 + part*(yy2-yy1);
1714 pntbuf[k+2] = crossz;
1716 if (with_grid && grid) {
1717 gridpnts[gridcnt] = pntbuf[k];
1718 gridpnts[gridcnt+1] = pntbuf[k+1];
1719 gridpnts[gridcnt+2] = pntbuf[k+2];
1727 function RememberVertex(indx, ii,jj) {
1728 var bin = ((ii-handle.i1) * (handle.j2-handle.j1) + (jj-handle.j1))*8;
1730 if (normindx[bin]>=0)
1731 return console.error(
'More than 8 vertexes for the bin');
1733 var pos = bin+8+normindx[bin];
1735 normindx[pos] = indx;
1738 function RecalculateNormals(arr) {
1739 for (var ii=handle.i1;ii<handle.i2;++ii) {
1740 for (var jj=handle.j1;jj<handle.j2;++jj) {
1741 var bin = ((ii-handle.i1) * (handle.j2-handle.j1) + (jj-handle.j1)) * 8;
1743 if (normindx[bin] === -1)
continue;
1745 var beg = (normindx[bin] >=0) ? bin : bin+9+normindx[bin],
1746 end = bin+8, sumx=0, sumy = 0, sumz = 0;
1748 for (var kk=beg;kk<end;++kk) {
1749 var indx = normindx[kk];
1750 if (indx<0)
return console.error(
'FAILURE in NORMALS RECALCULATIONS');
1756 sumx = sumx/(end-beg); sumy = sumy/(end-beg); sumz = sumz/(end-beg);
1758 for (var kk=beg;kk<end;++kk) {
1759 var indx = normindx[kk];
1768 function AddMainTriangle(x1,y1,z1, x2,y2,z2, x3,y3,z3, is_first) {
1770 for (var lvl=1;lvl<levels.length;++lvl) {
1772 var side1 = CheckSide(z1, levels[lvl-1], levels[lvl]),
1773 side2 = CheckSide(z2, levels[lvl-1], levels[lvl]),
1774 side3 = CheckSide(z3, levels[lvl-1], levels[lvl]),
1775 side_sum = side1 + side2 + side3;
1777 if (side_sum === 3)
continue;
1778 if (side_sum === -3)
return;
1781 var npnts = Math.abs(side2-side1) + Math.abs(side3-side2) + Math.abs(side1-side3);
1782 if (side1===0) ++npnts;
1783 if (side2===0) ++npnts;
1784 if (side3===0) ++npnts;
1786 if ((npnts===1) || (npnts===2)) console.error(
'FOND npnts', npnts);
1789 if (nfaces[lvl]===undefined) nfaces[lvl] = 0;
1790 nfaces[lvl] += npnts-2;
1794 if (((side1>0) || (side2>0) || (side3>0)) &&
1795 ((side1!==side2) || (side2!==side3) || (side3!==side1))) ++ngridsegments;
1803 if (side1 === 0) { pntbuf[k] = x1; pntbuf[k+1] = y1; pntbuf[k+2] = z1; k+=3; }
1805 if (side1!==side2) {
1808 if ((side1<0) || (side2<0)) AddCrossingPoint(x1,y1,z1, x2,y2,z2, levels[lvl-1]);
1809 if ((side1>0) || (side2>0)) AddCrossingPoint(x1,y1,z1, x2,y2,z2, levels[lvl],
true);
1812 if (side2 === 0) { pntbuf[k] = x2; pntbuf[k+1] = y2; pntbuf[k+2] = z2; k+=3; }
1814 if (side2!==side3) {
1817 if ((side2<0) || (side3<0)) AddCrossingPoint(x2,y2,z2, x3,y3,z3, levels[lvl-1]);
1818 if ((side2>0) || (side3>0)) AddCrossingPoint(x2,y2,z2, x3,y3,z3, levels[lvl],
true);
1821 if (side3 === 0) { pntbuf[k] = x3; pntbuf[k+1] = y3; pntbuf[k+2] = z3; k+=3; }
1823 if (side3!==side1) {
1826 if ((side3<0) || (side1<0)) AddCrossingPoint(x3,y3,z3, x1,y1,z1, levels[lvl-1]);
1827 if ((side3>0) || (side1>0)) AddCrossingPoint(x3,y3,z3, x1,y1,z1, levels[lvl],
true);
1830 if (k===0)
continue;
1831 if (k<9) { console.log(
'found less than 3 points', k/3);
continue; }
1833 if (grid && (gridcnt === 6)) {
1834 for (var jj=0;jj < 6; ++jj)
1835 grid[gindx+jj] = gridpnts[jj];
1842 var buf = pos[lvl], s = indx[lvl];
1843 if (donormals && (k===9)) {
1844 RememberVertex(s, i, j);
1845 RememberVertex(s+3, i+1, is_first ? j+1 : j);
1846 RememberVertex(s+6, is_first ? i : i+1, j+1);
1849 for (var k1=3;k1<k-3;k1+=3) {
1850 buf[s] = pntbuf[0]; buf[s+1] = pntbuf[1]; buf[s+2] = pntbuf[2]; s+=3;
1851 buf[s] = pntbuf[k1]; buf[s+1] = pntbuf[k1+1]; buf[s+2] = pntbuf[k1+2]; s+=3;
1852 buf[s] = pntbuf[k1+3]; buf[s+1] = pntbuf[k1+4]; buf[s+2] = pntbuf[k1+5]; s+=3;
1861 normindx =
new Int32Array((handle.i2-handle.i1)*(handle.j2-handle.j1)*8);
1862 for (var n=0;n<normindx.length;++n) normindx[n] = -1;
1865 for (loop=0;loop<2;++loop) {
1867 for (var lvl=1;lvl<levels.length;++lvl)
1869 pos[lvl] =
new Float32Array(nfaces[lvl] * 9);
1872 if (dolines && (nsegments > 0))
1873 lpos =
new Float32Array(nsegments * 6);
1874 if (dogrid && (ngridsegments>0))
1875 grid =
new Float32Array(ngridsegments * 6);
1877 for (i=handle.i1;i<handle.i2-1;++i) {
1879 x2 = handle.grx[i+1];
1880 for (j=handle.j1;j<handle.j2-1;++j) {
1882 y2 = handle.gry[j+1];
1883 z11 = main_grz(histo.getBinContent(i+1, j+1));
1884 z12 = main_grz(histo.getBinContent(i+1, j+2));
1885 z21 = main_grz(histo.getBinContent(i+2, j+1));
1886 z22 = main_grz(histo.getBinContent(i+2, j+2));
1888 AddMainTriangle(x1,y1,z11, x2,y2,z22, x1,y2,z12,
true);
1890 AddMainTriangle(x1,y1,z11, x2,y1,z21, x2,y2,z22,
false);
1892 AddLineSegment(x1,y2,z12, x1,y1,z11);
1893 AddLineSegment(x1,y1,z11, x2,y1,z21);
1895 if (i===handle.i2-2) AddLineSegment(x2,y1,z21, x2,y2,z22);
1896 if (j===handle.j2-2) AddLineSegment(x1,y2,z12, x2,y2,z22);
1901 for (var lvl=1;lvl<levels.length;++lvl)
1903 if (indx[lvl] !== nfaces[lvl]*9)
1904 console.error(
'SURF faces missmatch lvl', lvl,
'faces', nfaces[lvl],
'index', indx[lvl],
'check', nfaces[lvl]*9 - indx[lvl]);
1905 var geometry =
new THREE.BufferGeometry();
1906 geometry.addAttribute(
'position',
new THREE.BufferAttribute( pos[lvl], 3 ) );
1907 geometry.computeVertexNormals();
1908 if (donormals && (lvl===1)) RecalculateNormals(geometry.getAttribute(
'normal').array);
1910 var fcolor, material;
1912 fcolor = palette.calcColor(lvl, levels.length);
1914 fcolor = histo.fFillColor > 1 ? this.get_color(histo.fFillColor) :
'white';
1915 if ((this.options.Surf === 14) && (histo.fFillColor<2)) fcolor = this.get_color(48);
1917 if (this.options.Surf === 14)
1918 material =
new THREE.MeshLambertMaterial( { color: fcolor, side: THREE.DoubleSide } );
1920 material =
new THREE.MeshBasicMaterial( { color: fcolor, side: THREE.DoubleSide } );
1922 var mesh =
new THREE.Mesh(geometry, material);
1924 main.toplevel.add(mesh);
1926 mesh.painter =
this;
1931 if (nsegments*6 !== lindx)
1932 console.error(
'SURF lines mismmatch nsegm', nsegments,
' lindx', lindx,
'difference', nsegments*6 - lindx);
1934 var lcolor = this.get_color(histo.fLineColor),
1935 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(lcolor) });
1936 if (!JSROOT.browser.isIE) material.linewidth = histo.fLineWidth;
1937 var line = JSROOT.Painter.createLineSegments(lpos, material);
1938 line.painter =
this;
1939 main.toplevel.add(line);
1943 if (ngridsegments*6 !== gindx)
1944 console.error(
'SURF grid draw mismatch ngridsegm', ngridsegments,
'gindx', gindx,
'diff', ngridsegments*6 - gindx);
1948 if (this.options.Surf === 1)
1949 material =
new THREE.LineDashedMaterial( { color: 0x0, dashSize: 2, gapSize: 2 } );
1951 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(this.get_color(histo.fLineColor)) });
1953 var line = JSROOT.Painter.createLineSegments(grid, material);
1954 line.painter =
this;
1955 main.toplevel.add(line);
1958 if (this.options.Surf === 17)
1959 this.DrawContour3D();
1961 if (this.options.Surf === 13) {
1963 handle = this.PrepareColorDraw({rounding:
false, use3d:
true, extra: 100, middle: 0.0 });
1966 var levels = this.GetContour(),
1967 palette = this.GetPalette(),
1968 lastcolindx = -1, layerz = 2*main.size_z3d;
1970 this.BuildContour(handle, levels, palette,
1971 function(colindx,xp,yp,iminus,iplus) {
1973 if ((xp[iplus] === xp[iminus]) && (yp[iplus] === yp[iminus])) iplus--;
1976 if (iplus - iminus < 3)
return;
1980 for (var i = iminus; i <= iplus; ++i)
1981 if ((i === iminus) || (xp[i] !== xp[i-1]) || (yp[i] !== yp[i-1]))
1982 pnts.push(
new THREE.Vector2(xp[i], yp[i]));
1984 if (pnts.length < 3)
return;
1986 var faces = THREE.ShapeUtils.triangulateShape(pnts , []);
1988 if (!faces || (faces.length === 0))
return;
1990 if ((lastcolindx < 0) || (lastcolindx !== colindx)) {
1991 lastcolindx = colindx;
1992 layerz+=0.0001*main.size_z3d;
1995 var pos =
new Float32Array(faces.length*9),
1996 norm =
new Float32Array(faces.length*9),
1999 for (var n=0;n<faces.length;++n) {
2000 var face = faces[n];
2001 for (var v=0;v<3;++v) {
2002 var pnt = pnts[face[v]];
2004 pos[indx+1] = pnt.y;
2005 pos[indx+2] = layerz;
2014 var geometry =
new THREE.BufferGeometry();
2015 geometry.addAttribute(
'position',
new THREE.BufferAttribute( pos, 3 ) );
2016 geometry.addAttribute(
'normal',
new THREE.BufferAttribute( norm, 3 ) );
2018 var fcolor = palette.getColor(colindx);
2019 var material =
new THREE.MeshBasicMaterial( { color: fcolor, flatShading:
true, side: THREE.DoubleSide, opacity: 0.5 } );
2020 var mesh =
new THREE.Mesh(geometry, material);
2021 mesh.painter =
this;
2022 main.toplevel.add(mesh);
2028 JSROOT.TH2Painter.prototype.DrawError =
function() {
2030 main = this.frame_painter(),
2031 histo = this.GetHisto(),
2032 handle = this.PrepareColorDraw({ rounding:
false, use3d:
true, extra: 1 }),
2033 zmin = main.grz.domain()[0],
2034 zmax = main.grz.domain()[1],
2035 i, j, bin, binz, binerr, x1, y1, x2, y2, z1, z2,
2036 nsegments = 0, lpos = null, binindx = null, lindx = 0;
2038 function check_skip_min() {
2040 if (pthis.options.Zero || (zmin>0))
return false;
2041 return !pthis._show_empty_bins;
2045 for (var loop=0;loop<2;++loop) {
2047 for (i=handle.i1;i<handle.i2;++i) {
2049 x2 = handle.grx[i+1];
2050 for (j=handle.j1;j<handle.j2;++j) {
2051 binz = histo.getBinContent(i+1, j+1);
2052 if ((binz < zmin) || (binz > zmax))
continue;
2053 if ((binz===zmin) && check_skip_min())
continue;
2056 if (loop===0) { nsegments+=3;
continue; }
2058 bin = histo.getBin(i+1,j+1);
2059 binerr = histo.getBinError(bin);
2060 binindx[lindx/18] = bin;
2063 y2 = handle.gry[j+1];
2065 z1 = main.grz((binz - binerr < zmin) ? zmin : binz-binerr);
2066 z2 = main.grz((binz + binerr > zmax) ? zmax : binz+binerr);
2068 lpos[lindx] = x1; lpos[lindx+3] = x2;
2069 lpos[lindx+1] = lpos[lindx+4] = (y1+y2)/2;
2070 lpos[lindx+2] = lpos[lindx+5] = (z1+z2)/2;
2073 lpos[lindx] = lpos[lindx+3] = (x1+x2)/2;
2074 lpos[lindx+1] = y1; lpos[lindx+4] = y2;
2075 lpos[lindx+2] = lpos[lindx+5] = (z1+z2)/2;
2078 lpos[lindx] = lpos[lindx+3] = (x1+x2)/2;
2079 lpos[lindx+1] = lpos[lindx+4] = (y1+y2)/2;
2080 lpos[lindx+2] = z1; lpos[lindx+5] = z2;
2086 if (nsegments===0)
return;
2087 lpos =
new Float32Array(nsegments*6);
2088 binindx =
new Int32Array(nsegments/3);
2093 var lcolor = this.get_color(this.GetObject().fLineColor),
2094 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(lcolor) }),
2095 line = JSROOT.Painter.createLineSegments(lpos, material);
2097 if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth;
2099 line.painter =
this;
2100 line.intersect_index = binindx;
2103 line.tip_color = (this.GetObject().fLineColor===3) ? 0xFF0000 : 0x00FF00;
2105 line.tooltip =
function(intersect) {
2106 if (isNaN(intersect.index)) {
2107 console.error(
'segment index not provided, check three.js version', THREE.REVISION,
'expected r97');
2111 var pos = Math.floor(intersect.index / 6);
2112 if ((pos<0) || (pos >= this.intersect_index.length))
return null;
2113 var p = this.painter,
2114 histo = p.GetHisto(),
2115 main = p.frame_painter(),
2116 tip = p.Get3DToolTip(this.intersect_index[pos]);
2118 tip.x1 = Math.max(-main.size_xy3d, main.grx(histo.fXaxis.GetBinLowEdge(tip.ix)));
2119 tip.x2 = Math.min(main.size_xy3d, main.grx(histo.fXaxis.GetBinLowEdge(tip.ix+1)));
2120 tip.y1 = Math.max(-main.size_xy3d, main.gry(histo.fYaxis.GetBinLowEdge(tip.iy)));
2121 tip.y2 = Math.min(main.size_xy3d, main.gry(histo.fXaxis.GetBinLowEdge(tip.iy+1)));
2123 tip.z1 = main.grz(tip.value-tip.error <
this.zmin ?
this.zmin : tip.value-tip.error);
2124 tip.z2 = main.grz(tip.value+tip.error >
this.zmax ?
this.zmax : tip.value+tip.error);
2126 tip.color = this.tip_color;
2131 main.toplevel.add(line);
2134 JSROOT.TH2Painter.prototype.DrawPolyLego =
function() {
2135 var histo = this.GetHisto(),
2136 pmain = this.frame_painter(),
2137 axis_zmin = pmain.grz.domain()[0],
2138 axis_zmax = pmain.grz.domain()[1],
2139 colindx, bin, i, len = histo.fBins.arr.length, cnt = 0, totalnfaces = 0,
2140 z0 = pmain.grz(axis_zmin), z1 = z0;
2143 this.fContour = null;
2144 this.fCustomContour =
false;
2147 this.maxbin = this.gmaxbin;
2148 this.minbin = this.gminbin;
2149 this.minposbin = this.gminposbin;
2151 for (i = 0; i < len; ++ i) {
2152 bin = histo.fBins.arr[i];
2153 if (bin.fContent < axis_zmin)
continue;
2155 colindx = this.getContourColor(bin.fContent,
true);
2156 if (colindx === null)
continue;
2159 if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) ||
2160 (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin))
continue;
2162 z1 = pmain.grz((bin.fContent > axis_zmax) ? axis_zmax : bin.fContent);
2164 var all_pnts = [], all_faces = [],
2165 ngraphs = 1, gr = bin.fPoly, nfaces = 0;
2167 if (gr._typename==
'TMultiGraph') {
2168 ngraphs = bin.fPoly.fGraphs.arr.length;
2172 for (var ngr = 0; ngr < ngraphs; ++ngr) {
2173 if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr];
2175 var npnts = gr.fNpoints, x = gr.fX, y = gr.fY;
2176 while ((npnts>2) && (x[0]===x[npnts-1]) && (y[0]===y[npnts-1])) --npnts;
2180 for (var ntry=0;ntry<2;++ntry) {
2183 var lastx, lasty, currx, curry,
2184 dist2 = pmain.size_xy3d*pmain.size_z3d,
2185 dist2limit = (ntry>0) ? 0 : dist2/1e6;
2187 pnts = []; faces = null;
2189 for (var vert = 0; vert < npnts; ++vert) {
2190 currx = pmain.grx(x[vert]);
2191 curry = pmain.gry(y[vert]);
2193 dist2 = (currx-lastx)*(currx-lastx) + (curry-lasty)*(curry-lasty);
2194 if (dist2 > dist2limit) {
2195 pnts.push(
new THREE.Vector2(currx, curry));
2202 if (pnts.length > 2)
2203 faces = THREE.ShapeUtils.triangulateShape(pnts , []);
2208 if (faces && (faces.length>pnts.length-3))
break;
2211 if (faces && faces.length && pnts) {
2212 all_pnts.push(pnts);
2213 all_faces.push(faces);
2215 nfaces += faces.length * 2;
2216 if (z1>z0) nfaces += pnts.length*2;
2220 var pos =
new Float32Array(nfaces*9), indx = 0;
2222 for (var ngr=0;ngr<all_pnts.length;++ngr) {
2223 var pnts = all_pnts[ngr], faces = all_faces[ngr];
2225 for (var layer=0;layer<2;++layer) {
2226 for (var n=0;n<faces.length;++n) {
2227 var face = faces[n],
2228 pnt1 = pnts[face[0]],
2229 pnt2 = pnts[face[(layer===0) ? 2 : 1]],
2230 pnt3 = pnts[face[(layer===0) ? 1 : 2]];
2233 pos[indx+1] = pnt1.y;
2234 pos[indx+2] = layer ? z1 : z0;
2238 pos[indx+1] = pnt2.y;
2239 pos[indx+2] = layer ? z1 : z0;
2243 pos[indx+1] = pnt3.y;
2244 pos[indx+2] = layer ? z1 : z0;
2250 for (var n=0;n<pnts.length;++n) {
2252 pnt2 = pnts[(n>0) ? n-1 : pnts.length-1];
2255 pos[indx+1] = pnt1.y;
2260 pos[indx+1] = pnt2.y;
2265 pos[indx+1] = pnt2.y;
2270 pos[indx+1] = pnt1.y;
2275 pos[indx+1] = pnt2.y;
2280 pos[indx+1] = pnt1.y;
2287 var geometry =
new THREE.BufferGeometry();
2288 geometry.addAttribute(
'position',
new THREE.BufferAttribute( pos, 3 ) );
2289 geometry.computeVertexNormals();
2291 var fcolor = this.fPalette.getColor(colindx);
2292 var material =
new THREE.MeshBasicMaterial( { color: fcolor, flatShading:
true } );
2293 var mesh =
new THREE.Mesh(geometry, material);
2295 pmain.toplevel.add(mesh);
2297 mesh.painter =
this;
2298 mesh.bins_index = i;
2301 mesh.tip_color = 0x00FF00;
2303 mesh.tooltip =
function(intersects) {
2305 var p = this.painter, main = p.frame_painter(),
2306 bin = p.GetObject().fBins.arr[this.bins_index];
2310 x1: main.grx(bin.fXmin),
2311 x2: main.grx(bin.fXmax),
2312 y1: main.gry(bin.fYmin),
2313 y2: main.gry(bin.fYmax),
2316 bin: this.bins_index,
2317 value: bin.fContent,
2318 color: this.tip_color,
2319 lines: p.ProvidePolyBinHints(this.bins_index)
2325 totalnfaces += nfaces;
2332 function TH3Painter(histo) {
2333 JSROOT.THistPainter.call(
this, histo);
2338 TH3Painter.prototype = Object.create(JSROOT.THistPainter.prototype);
2340 TH3Painter.prototype.ScanContent =
function(when_axis_changed) {
2343 if (when_axis_changed && this.nbinsx && this.nbinsy && this.nbinsz)
return;
2345 var histo = this.GetObject();
2347 this.nbinsx = histo.fXaxis.fNbins;
2348 this.nbinsy = histo.fYaxis.fNbins;
2349 this.nbinsz = histo.fZaxis.fNbins;
2351 this.xmin = histo.fXaxis.fXmin;
2352 this.xmax = histo.fXaxis.fXmax;
2354 this.ymin = histo.fYaxis.fXmin;
2355 this.ymax = histo.fYaxis.fXmax;
2357 this.zmin = histo.fZaxis.fXmin;
2358 this.zmax = histo.fZaxis.fXmax;
2362 this.gminbin = this.gmaxbin = histo.getBinContent(1,1,1);
2364 for (var i = 0; i < this.nbinsx; ++i)
2365 for (var j = 0; j < this.nbinsy; ++j)
2366 for (var k = 0; k < this.nbinsz; ++k) {
2367 var bin_content = histo.getBinContent(i+1, j+1, k+1);
2368 if (bin_content < this.gminbin) this.gminbin = bin_content;
else
2369 if (bin_content > this.gmaxbin) this.gmaxbin = bin_content;
2372 this.draw_content = this.gmaxbin > 0;
2374 this.CreateAxisFuncs(
true,
true);
2377 TH3Painter.prototype.CountStat =
function() {
2378 var histo = this.GetHisto(), xaxis = histo.fXaxis, yaxis = histo.fYaxis, zaxis = histo.fZaxis,
2379 stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0,
2380 stat_sumz1 = 0, stat_sumx2 = 0, stat_sumy2 = 0, stat_sumz2 = 0,
2381 i1 = this.GetSelectIndex(
"x",
"left"),
2382 i2 = this.GetSelectIndex(
"x",
"right"),
2383 j1 = this.GetSelectIndex(
"y",
"left"),
2384 j2 = this.GetSelectIndex(
"y",
"right"),
2385 k1 = this.GetSelectIndex(
"z",
"left"),
2386 k2 = this.GetSelectIndex(
"z",
"right"),
2387 fp = this.frame_painter(),
2388 res = { name: histo.fName, entries: 0, integral: 0, meanx: 0, meany: 0, meanz: 0, rmsx: 0, rmsy: 0, rmsz: 0 },
2389 xi, yi, zi, xx, xside, yy, yside, zz, zside, cont;
2391 for (xi = 0; xi < this.nbinsx+2; ++xi) {
2393 xx = xaxis.GetBinCoord(xi - 0.5);
2394 xside = (xi < i1) ? 0 : (xi > i2 ? 2 : 1);
2396 for (yi = 0; yi < this.nbinsy+2; ++yi) {
2398 yy = yaxis.GetBinCoord(yi - 0.5);
2399 yside = (yi < j1) ? 0 : (yi > j2 ? 2 : 1);
2401 for (zi = 0; zi < this.nbinsz+2; ++zi) {
2403 zz = zaxis.GetBinCoord(zi - 0.5);
2404 zside = (zi < k1) ? 0 : (zi > k2 ? 2 : 1);
2406 cont = histo.getBinContent(xi, yi, zi);
2407 res.entries += cont;
2409 if ((xside==1) && (yside==1) && (zside==1)) {
2411 stat_sumx1 += xx * cont;
2412 stat_sumy1 += yy * cont;
2413 stat_sumz1 += zz * cont;
2414 stat_sumx2 += xx * xx * cont;
2415 stat_sumy2 += yy * yy * cont;
2416 stat_sumz2 += zz * zz * cont;
2422 if ((histo.fTsumw > 0) && !fp.IsAxisZoomed(
"x") && !fp.IsAxisZoomed(
"y") && !fp.IsAxisZoomed(
"z")) {
2423 stat_sum0 = histo.fTsumw;
2424 stat_sumx1 = histo.fTsumwx;
2425 stat_sumx2 = histo.fTsumwx2;
2426 stat_sumy1 = histo.fTsumwy;
2427 stat_sumy2 = histo.fTsumwy2;
2428 stat_sumz1 = histo.fTsumwz;
2429 stat_sumz2 = histo.fTsumwz2;
2432 if (stat_sum0 > 0) {
2433 res.meanx = stat_sumx1 / stat_sum0;
2434 res.meany = stat_sumy1 / stat_sum0;
2435 res.meanz = stat_sumz1 / stat_sum0;
2436 res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx));
2437 res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany));
2438 res.rmsz = Math.sqrt(Math.abs(stat_sumz2 / stat_sum0 - res.meanz * res.meanz));
2441 res.integral = stat_sum0;
2443 if (histo.fEntries > 1) res.entries = histo.fEntries;
2448 TH3Painter.prototype.FillStatistic =
function(stat, dostat, dofit) {
2451 if (this.IgnoreStatsFill())
return false;
2453 var data = this.CountStat(),
2454 print_name = dostat % 10,
2455 print_entries = Math.floor(dostat / 10) % 10,
2456 print_mean = Math.floor(dostat / 100) % 10,
2457 print_rms = Math.floor(dostat / 1000) % 10,
2458 print_under = Math.floor(dostat / 10000) % 10,
2459 print_over = Math.floor(dostat / 100000) % 10,
2460 print_integral = Math.floor(dostat / 1000000) % 10;
2467 stat.AddText(data.name);
2469 if (print_entries > 0)
2470 stat.AddText(
"Entries = " + stat.Format(data.entries,
"entries"));
2472 if (print_mean > 0) {
2473 stat.AddText(
"Mean x = " + stat.Format(data.meanx));
2474 stat.AddText(
"Mean y = " + stat.Format(data.meany));
2475 stat.AddText(
"Mean z = " + stat.Format(data.meanz));
2478 if (print_rms > 0) {
2479 stat.AddText(
"Std Dev x = " + stat.Format(data.rmsx));
2480 stat.AddText(
"Std Dev y = " + stat.Format(data.rmsy));
2481 stat.AddText(
"Std Dev z = " + stat.Format(data.rmsz));
2484 if (print_integral > 0) {
2485 stat.AddText(
"Integral = " + stat.Format(data.integral,
"entries"));
2488 if (dofit) stat.FillFunctionStat(this.FindFunction(
'TF1'), dofit);
2493 TH3Painter.prototype.GetBinTips =
function (ix, iy, iz) {
2494 var lines = [], pmain = this.frame_painter(), histo = this.GetHisto();
2496 lines.push(this.GetTipName());
2498 if (pmain.x_kind ==
'labels')
2499 lines.push(
"x = " + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(ix+1)) +
" xbin=" + (ix+1));
2501 lines.push(
"x = [" + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(ix+1)) +
", " + pmain.AxisAsText(
"x", histo.fXaxis.GetBinLowEdge(ix+2)) +
") xbin=" + (ix+1));
2503 if (pmain.y_kind ==
'labels')
2504 lines.push(
"y = " + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(iy+1)) +
" ybin=" + (iy+1));
2506 lines.push(
"y = [" + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(iy+1)) +
", " + pmain.AxisAsText(
"y", histo.fYaxis.GetBinLowEdge(iy+2)) +
") ybin=" + (iy+1));
2508 if (pmain.z_kind ==
'labels')
2509 lines.push(
"z = " + pmain.AxisAsText(
"z", histo.fZaxis.GetBinLowEdge(iz+1)) +
" zbin=" + (iz+1));
2511 lines.push(
"z = [" + pmain.AxisAsText(
"z", histo.fZaxis.GetBinLowEdge(iz+1)) +
", " + pmain.AxisAsText(
"z", histo.fZaxis.GetBinLowEdge(iz+2)) +
") zbin=" + (iz+1));
2513 var binz = histo.getBinContent(ix+1, iy+1, iz+1);
2514 if (binz === Math.round(binz))
2515 lines.push(
"entries = " + binz);
2517 lines.push(
"entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat));
2522 TH3Painter.prototype.Draw3DScatter =
function() {
2526 var histo = this.GetObject(),
2527 main = this.frame_painter(),
2528 i1 = this.GetSelectIndex(
"x",
"left", 0.5),
2529 i2 = this.GetSelectIndex(
"x",
"right", 0),
2530 j1 = this.GetSelectIndex(
"y",
"left", 0.5),
2531 j2 = this.GetSelectIndex(
"y",
"right", 0),
2532 k1 = this.GetSelectIndex(
"z",
"left", 0.5),
2533 k2 = this.GetSelectIndex(
"z",
"right", 0),
2534 name = this.GetTipName(
"<br/>"),
2535 i, j, k, bin_content;
2537 if ((i2<=i1) || (j2<=j1) || (k2<=k1))
return true;
2540 var coef = (this.gmaxbin > 1000) ? 1000/this.gmaxbin : 1,
2541 numpixels = 0, sumz = 0, content_lmt = Math.max(0,
this.gminbin);
2543 for (i = i1; i < i2; ++i) {
2544 for (j = j1; j < j2; ++j) {
2545 for (k = k1; k < k2; ++k) {
2546 bin_content = histo.getBinContent(i+1, j+1, k+1);
2547 sumz += bin_content;
2548 if (bin_content <= content_lmt)
continue;
2549 numpixels += Math.round(bin_content*coef);
2555 if (numpixels > (main.webgl ? 100000 : 30000))
return false;
2559 var pnts =
new JSROOT.Painter.PointsCreator(numpixels, main.webgl, main.size_xy3d/200),
2560 bins =
new Int32Array(numpixels), nbin = 0;
2562 for (i = i1; i < i2; ++i) {
2563 for (j = j1; j < j2; ++j) {
2564 for (k = k1; k < k2; ++k) {
2565 bin_content = histo.getBinContent(i+1, j+1, k+1);
2566 if (bin_content <= content_lmt)
continue;
2567 var num = Math.round(bin_content*coef);
2569 for (var n=0;n<num;++n) {
2570 var binx = histo.fXaxis.GetBinCoord(i+JSROOT.random()),
2571 biny = histo.fYaxis.GetBinCoord(j+JSROOT.random()),
2572 binz = histo.fZaxis.GetBinCoord(k+JSROOT.random());
2575 bins[nbin++] = histo.getBin(i+1, j+1, k+1);
2577 pnts.AddPoint(main.grx(binx), main.gry(biny), main.grz(binz));
2583 var mesh = pnts.CreatePoints(this.get_color(histo.fMarkerColor));
2584 main.toplevel.add(mesh);
2587 mesh.painter =
this;
2588 mesh.tip_color = (histo.fMarkerColor===3) ? 0xFF0000 : 0x00FF00;
2590 mesh.tooltip =
function(intersect) {
2591 if (isNaN(intersect.index)) {
2592 console.error(
'intersect.index not provided, check three.js version', THREE.REVISION,
'expected r97');
2596 var indx = Math.floor(intersect.index /
this.nvertex);
2597 if ((indx<0) || (indx >= this.bins.length))
return null;
2599 var p = this.painter, histo = p.GetHisto(),
2600 main = p.frame_painter(),
2601 tip = p.Get3DToolTip(this.bins[indx]);
2603 tip.x1 = main.grx(histo.fXaxis.GetBinLowEdge(tip.ix));
2604 tip.x2 = main.grx(histo.fXaxis.GetBinLowEdge(tip.ix+1));
2605 tip.y1 = main.gry(histo.fYaxis.GetBinLowEdge(tip.iy));
2606 tip.y2 = main.gry(histo.fYaxis.GetBinLowEdge(tip.iy+1));
2607 tip.z1 = main.grz(histo.fZaxis.GetBinLowEdge(tip.iz));
2608 tip.z2 = main.grz(histo.fZaxis.GetBinLowEdge(tip.iz+1));
2609 tip.color = this.tip_color;
2618 TH3Painter.prototype.Draw3DBins =
function() {
2620 if (!this.draw_content)
return;
2622 if (!this.options.Box && !
this.options.GLBox && !
this.options.GLColor && !
this.options.Lego)
2623 if (this.Draw3DScatter())
return;
2625 var rootcolor = this.GetObject().fFillColor,
2626 fillcolor = this.get_color(rootcolor),
2627 main = this.frame_painter(),
2628 buffer_size = 0, use_lambert =
false,
2629 use_helper =
false, use_colors =
false, use_opacity = 1, use_scale =
true,
2630 single_bin_verts, single_bin_norms,
2631 box_option = this.options.Box ? this.options.BoxStyle : 0,
2634 if (!box_option && this.options.Lego) box_option = (this.options.Lego===1) ? 10 : this.options.Lego;
2636 if ((this.options.GLBox === 11) || (this.options.GLBox === 12)) {
2640 if (this.options.GLBox === 12) use_colors =
true;
2642 var geom = JSROOT.Painter.TestWebGL() ?
new THREE.SphereGeometry(0.5, 16, 12) :
new THREE.SphereGeometry(0.5, 8, 6);
2643 geom.applyMatrix(
new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
2645 buffer_size = geom.faces.length*9;
2646 single_bin_verts =
new Float32Array(buffer_size);
2647 single_bin_norms =
new Float32Array(buffer_size);
2652 for (var face = 0; face < geom.faces.length; ++face) {
2653 single_bin_verts[9*face ] = geom.vertices[geom.faces[face].a].x;
2654 single_bin_verts[9*face+1] = geom.vertices[geom.faces[face].a].y;
2655 single_bin_verts[9*face+2] = geom.vertices[geom.faces[face].a].z;
2656 single_bin_verts[9*face+3] = geom.vertices[geom.faces[face].b].x;
2657 single_bin_verts[9*face+4] = geom.vertices[geom.faces[face].b].y;
2658 single_bin_verts[9*face+5] = geom.vertices[geom.faces[face].b].z;
2659 single_bin_verts[9*face+6] = geom.vertices[geom.faces[face].c].x;
2660 single_bin_verts[9*face+7] = geom.vertices[geom.faces[face].c].y;
2661 single_bin_verts[9*face+8] = geom.vertices[geom.faces[face].c].z;
2663 single_bin_norms[9*face ] = geom.faces[face].vertexNormals[0].x;
2664 single_bin_norms[9*face+1] = geom.faces[face].vertexNormals[0].y;
2665 single_bin_norms[9*face+2] = geom.faces[face].vertexNormals[0].z;
2666 single_bin_norms[9*face+3] = geom.faces[face].vertexNormals[1].x;
2667 single_bin_norms[9*face+4] = geom.faces[face].vertexNormals[1].y;
2668 single_bin_norms[9*face+5] = geom.faces[face].vertexNormals[1].z;
2669 single_bin_norms[9*face+6] = geom.faces[face].vertexNormals[2].x;
2670 single_bin_norms[9*face+7] = geom.faces[face].vertexNormals[2].y;
2671 single_bin_norms[9*face+8] = geom.faces[face].vertexNormals[2].z;
2676 var indicies = JSROOT.Painter.Box3D.Indexes,
2677 normals = JSROOT.Painter.Box3D.Normals,
2678 vertices = JSROOT.Painter.Box3D.Vertices;
2680 buffer_size = indicies.length*3;
2681 single_bin_verts =
new Float32Array(buffer_size);
2682 single_bin_norms =
new Float32Array(buffer_size);
2684 for (var k=0,nn=-3;k<indicies.length;++k) {
2685 var vert = vertices[indicies[k]];
2686 single_bin_verts[k*3] = vert.x-0.5;
2687 single_bin_verts[k*3+1] = vert.y-0.5;
2688 single_bin_verts[k*3+2] = vert.z-0.5;
2691 single_bin_norms[k*3] = normals[nn];
2692 single_bin_norms[k*3+1] = normals[nn+1];
2693 single_bin_norms[k*3+2] = normals[nn+2];
2697 if (box_option===12) { use_colors =
true; }
else
2698 if (box_option===13) { use_colors =
true; use_helper =
false; }
else
2699 if (this.options.GLColor) { use_colors =
true; use_opacity = 0.5; use_scale =
false; use_helper =
false; use_lambert =
true; }
2703 use_scale = (this.gminbin || this.gmaxbin) ? 1 / Math.max(Math.abs(
this.gminbin), Math.abs(this.gmaxbin)) : 1;
2705 var histo = this.GetHisto(),
2706 i1 = this.GetSelectIndex(
"x",
"left", 0.5),
2707 i2 = this.GetSelectIndex(
"x",
"right", 0),
2708 j1 = this.GetSelectIndex(
"y",
"left", 0.5),
2709 j2 = this.GetSelectIndex(
"y",
"right", 0),
2710 k1 = this.GetSelectIndex(
"z",
"left", 0.5),
2711 k2 = this.GetSelectIndex(
"z",
"right", 0),
2712 name = this.GetTipName(
"<br/>");
2714 if ((i2<=i1) || (j2<=j1) || (k2<=k1))
return;
2716 var scalex = (main.grx(histo.fXaxis.GetBinLowEdge(i2+1)) - main.grx(histo.fXaxis.GetBinLowEdge(i1+1))) / (i2-i1),
2717 scaley = (main.gry(histo.fYaxis.GetBinLowEdge(j2+1)) - main.gry(histo.fYaxis.GetBinLowEdge(j1+1))) / (j2-j1),
2718 scalez = (main.grz(histo.fZaxis.GetBinLowEdge(k2+1)) - main.grz(histo.fZaxis.GetBinLowEdge(k1+1))) / (k2-k1);
2720 var nbins = 0, i, j, k, wei, bin_content, cols_size = [], num_colors = 0, cols_sequence = [];
2722 for (i = i1; i < i2; ++i) {
2723 for (j = j1; j < j2; ++j) {
2724 for (k = k1; k < k2; ++k) {
2725 bin_content = histo.getBinContent(i+1, j+1, k+1);
2726 if ((bin_content===0) || (bin_content < this.gminbin))
continue;
2727 wei = use_scale ? Math.pow(Math.abs(bin_content*use_scale), 0.3333) : 1;
2728 if (wei < 1e-3)
continue;
2732 if (!use_colors)
continue;
2734 var colindx = this.getContourColor(bin_content,
true);
2735 if (colindx !== null) {
2736 if (cols_size[colindx] === undefined) {
2737 cols_size[colindx] = 0;
2738 cols_sequence[colindx] = num_colors++;
2740 cols_size[colindx]+=1;
2742 console.error(
'not found color for', bin_content);
2749 cols_size.push(nbins);
2751 cols_sequence = [0];
2754 var cols_nbins =
new Array(num_colors),
2755 bin_verts =
new Array(num_colors),
2756 bin_norms =
new Array(num_colors),
2757 bin_tooltips =
new Array(num_colors),
2758 helper_kind =
new Array(num_colors),
2759 helper_indexes =
new Array(num_colors),
2760 helper_positions =
new Array(num_colors);
2762 for(var ncol=0;ncol<cols_size.length;++ncol) {
2763 if (!cols_size[ncol])
continue;
2765 nbins = cols_size[ncol];
2766 var nseq = cols_sequence[ncol];
2768 cols_nbins[nseq] = 0;
2770 helper_kind[nseq] = 0;
2775 helper_kind[nseq] = (nbins * buffer_size / 3 > 0xFFF0) ? 2 : 1;
2777 bin_verts[nseq] =
new Float32Array(nbins * buffer_size);
2778 bin_norms[nseq] =
new Float32Array(nbins * buffer_size);
2779 bin_tooltips[nseq] =
new Int32Array(nbins);
2781 if (helper_kind[nseq]===1)
2782 helper_indexes[nseq] =
new Uint16Array(nbins * JSROOT.Painter.Box3D.MeshSegments.length);
2784 if (helper_kind[nseq]===2)
2785 helper_positions[nseq] =
new Float32Array(nbins * JSROOT.Painter.Box3D.Segments.length * 3);
2788 var binx, grx, biny, gry, binz, grz;
2790 for (i = i1; i < i2; ++i) {
2791 binx = histo.fXaxis.GetBinCenter(i+1); grx = main.grx(binx);
2792 for (j = j1; j < j2; ++j) {
2793 biny = histo.fYaxis.GetBinCenter(j+1); gry = main.gry(biny);
2794 for (k = k1; k < k2; ++k) {
2795 bin_content = histo.getBinContent(i+1, j+1, k+1);
2796 if ((bin_content===0) || (bin_content < this.gminbin))
continue;
2798 wei = use_scale ? Math.pow(Math.abs(bin_content*use_scale), 0.3333) : 1;
2799 if (wei < 1e-3)
continue;
2803 var colindx = this.getContourColor(bin_content,
true);
2804 if (colindx === null)
continue;
2805 nseq = cols_sequence[colindx];
2808 nbins = cols_nbins[nseq];
2810 binz = histo.fZaxis.GetBinCenter(k+1); grz = main.grz(binz);
2813 bin_tooltips[nseq][nbins] = histo.getBin(i+1, j+1, k+1);
2815 var vvv = nbins * buffer_size, bin_v = bin_verts[nseq], bin_n = bin_norms[nseq];
2818 for (var vi = 0; vi < buffer_size; vi+=3, vvv+=3) {
2819 bin_v[vvv] = grx + single_bin_verts[vi]*scalex*wei;
2820 bin_v[vvv+1] = gry + single_bin_verts[vi+1]*scaley*wei;
2821 bin_v[vvv+2] = grz + single_bin_verts[vi+2]*scalez*wei;
2823 bin_n[vvv] = single_bin_norms[vi];
2824 bin_n[vvv+1] = single_bin_norms[vi+1];
2825 bin_n[vvv+2] = single_bin_norms[vi+2];
2828 if (helper_kind[nseq]===1) {
2830 var helper_segments = JSROOT.Painter.Box3D.MeshSegments;
2831 vvv = nbins * helper_segments.length;
2832 var shift = Math.round(nbins * buffer_size/3),
2833 helper_i = helper_indexes[nseq];
2834 for (var n=0;n<helper_segments.length;++n)
2835 helper_i[vvv+n] = shift + helper_segments[n];
2838 if (helper_kind[nseq]===2) {
2839 var helper_segments = JSROOT.Painter.Box3D.Segments,
2840 helper_p = helper_positions[nseq];
2841 vvv = nbins * helper_segments.length * 3;
2842 for (var n=0;n<helper_segments.length;++n, vvv+=3) {
2843 var vert = JSROOT.Painter.Box3D.Vertices[helper_segments[n]];
2844 helper_p[vvv] = grx + (vert.x-0.5)*scalex*wei;
2845 helper_p[vvv+1] = gry + (vert.y-0.5)*scaley*wei;
2846 helper_p[vvv+2] = grz + (vert.z-0.5)*scalez*wei;
2850 cols_nbins[nseq] = nbins+1;
2855 for(var ncol=0;ncol<cols_size.length;++ncol) {
2856 if (!cols_size[ncol])
continue;
2858 nbins = cols_size[ncol];
2859 var nseq = cols_sequence[ncol];
2862 var all_bins_buffgeom =
new THREE.BufferGeometry();
2865 all_bins_buffgeom.addAttribute(
'position',
new THREE.BufferAttribute( bin_verts[nseq], 3 ) );
2866 all_bins_buffgeom.addAttribute(
'normal',
new THREE.BufferAttribute( bin_norms[nseq], 3 ) );
2868 if (use_colors) fillcolor = this.fPalette.getColor(ncol);
2870 var material = use_lambert ?
new THREE.MeshLambertMaterial({ color: fillcolor, opacity: use_opacity, transparent: (use_opacity<1) })
2871 :
new THREE.MeshBasicMaterial({ color: fillcolor, opacity: use_opacity });
2873 var combined_bins =
new THREE.Mesh(all_bins_buffgeom, material);
2875 combined_bins.bins = bin_tooltips[nseq];
2876 combined_bins.bins_faces = buffer_size/9;
2877 combined_bins.painter =
this;
2879 combined_bins.scalex = tipscale*scalex;
2880 combined_bins.scaley = tipscale*scaley;
2881 combined_bins.scalez = tipscale*scalez;
2882 combined_bins.tip_color = (rootcolor===3) ? 0xFF0000 : 0x00FF00;
2883 combined_bins.use_scale = use_scale;
2885 combined_bins.tooltip =
function(intersect) {
2886 if (isNaN(intersect.faceIndex)) {
2887 console.error(
'intersect.faceIndex not provided, check three.js version', THREE.REVISION,
'expected r97');
2890 var indx = Math.floor(intersect.faceIndex /
this.bins_faces);
2891 if ((indx<0) || (indx >= this.bins.length))
return null;
2893 var p = this.painter,
2894 histo = p.GetHisto(),
2895 main = p.frame_painter(),
2896 tip = p.Get3DToolTip(this.bins[indx]),
2897 grx = main.grx(histo.fXaxis.GetBinCoord(tip.ix-0.5)),
2898 gry = main.gry(histo.fYaxis.GetBinCoord(tip.iy-0.5)),
2899 grz = main.grz(histo.fZaxis.GetBinCoord(tip.iz-0.5)),
2900 wei = this.use_scale ? Math.pow(Math.abs(tip.value*
this.use_scale), 0.3333) : 1;
2902 tip.x1 = grx - this.scalex*wei; tip.x2 = grx + this.scalex*wei;
2903 tip.y1 = gry - this.scaley*wei; tip.y2 = gry + this.scaley*wei;
2904 tip.z1 = grz - this.scalez*wei; tip.z2 = grz + this.scalez*wei;
2906 tip.color = this.tip_color;
2911 main.toplevel.add(combined_bins);
2913 if (helper_kind[nseq] > 0) {
2914 var lcolor = this.get_color(this.GetObject().fLineColor),
2915 helper_material =
new THREE.LineBasicMaterial( { color: lcolor } ),
2918 if (helper_kind[nseq] === 1) {
2920 lines = JSROOT.Painter.createLineSegments( bin_verts[nseq], helper_material, helper_indexes[nseq] );
2922 lines = JSROOT.Painter.createLineSegments( helper_positions[nseq], helper_material );
2925 main.toplevel.add(lines);
2930 TH3Painter.prototype.Redraw =
function(resize) {
2932 var main = this.frame_painter(),
2933 histo = this.GetHisto();
2937 if (main.Resize3D()) main.Render3D();
2941 main.Create3DScene();
2942 main.SetAxesRanges(histo.fXaxis,
this.xmin,
this.xmax, histo.fYaxis,
this.ymin,
this.ymax, histo.fZaxis,
this.zmin,
this.zmax);
2943 main.Set3DOptions(this.options);
2944 main.DrawXYZ(main.toplevel, { zoom: JSROOT.gStyle.Zooming, ndim: 3 });
2947 this.UpdateStatWebCanvas();
2948 main.AddKeysHandler();
2954 TH3Painter.prototype.FillToolbar =
function() {
2955 var pp = this.pad_painter();
2958 pp.AddButton(JSROOT.ToolbarIcons.auto_zoom,
'Unzoom all axes',
'ToggleZoom',
"Ctrl *");
2959 if (this.draw_content)
2960 pp.AddButton(JSROOT.ToolbarIcons.statbox,
'Toggle stat box',
"ToggleStatBox");
2964 TH3Painter.prototype.CanZoomIn =
function(axis,min,max) {
2966 var obj = this.GetHisto();
2967 if (obj) obj = obj[
"f"+axis.toUpperCase()+
"axis"];
2968 return !obj || (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1);
2971 TH3Painter.prototype.AutoZoom =
function() {
2972 var i1 = this.GetSelectIndex(
"x",
"left"),
2973 i2 = this.GetSelectIndex(
"x",
"right"),
2974 j1 = this.GetSelectIndex(
"y",
"left"),
2975 j2 = this.GetSelectIndex(
"y",
"right"),
2976 k1 = this.GetSelectIndex(
"z",
"left"),
2977 k2 = this.GetSelectIndex(
"z",
"right"),
2978 i,j,k, histo = this.GetObject();
2980 if ((i1 === i2) || (j1 === j2) || (k1 === k2))
return;
2983 var min = histo.getBinContent(i1 + 1, j1 + 1, k1+1);
2984 for (i = i1; i < i2; ++i)
2985 for (j = j1; j < j2; ++j)
2986 for (k = k1; k < k2; ++k)
2987 min = Math.min(min, histo.getBinContent(i+1, j+1, k+1));
2991 var ileft = i2, iright = i1, jleft = j2, jright = j1, kleft = k2, kright = k1;
2993 for (i = i1; i < i2; ++i)
2994 for (j = j1; j < j2; ++j)
2995 for (k = k1; k < k2; ++k)
2996 if (histo.getBinContent(i+1, j+1, k+1) > min) {
2997 if (i < ileft) ileft = i;
2998 if (i >= iright) iright = i + 1;
2999 if (j < jleft) jleft = j;
3000 if (j >= jright) jright = j + 1;
3001 if (k < kleft) kleft = k;
3002 if (k >= kright) kright = k + 1;
3005 var xmin, xmax, ymin, ymax, zmin, zmax, isany =
false;
3007 if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; }
3008 if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; }
3009 if ((kleft === kright-1) && (kleft > k1+1) && (kright < k2-1)) { kleft--; kright++; }
3011 if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) {
3012 xmin = histo.fXaxis.GetBinLowEdge(ileft+1);
3013 xmax = histo.fXaxis.GetBinLowEdge(iright+1);
3017 if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) {
3018 ymin = histo.fYaxis.GetBinLowEdge(jleft+1);
3019 ymax = histo.fYaxis.GetBinLowEdge(jright+1);
3023 if ((kleft > k1 || kright < k2) && (kleft < kright - 1)) {
3024 zmin = histo.fZaxis.GetBinLowEdge(kleft+1);
3025 zmax = histo.fZaxis.GetBinLowEdge(kright+1);
3029 if (isany) this.frame_painter().Zoom(xmin, xmax, ymin, ymax, zmin, zmax);
3032 TH3Painter.prototype.FillHistContextMenu =
function(menu) {
3034 var sett = JSROOT.getDrawSettings(
"ROOT." + this.GetObject()._typename,
'nosame');
3036 menu.addDrawMenu(
"Draw with", sett.opts,
function(arg) {
3037 if (arg===
'inspect')
3038 return this.ShowInspector();
3040 this.DecodeOptions(arg);
3042 this.InteractiveRedraw(
true,
"drawopt");
3046 JSROOT.Painter.drawHistogram3D =
function(divid, histo, opt) {
3048 var painter =
new JSROOT.TH3Painter(histo);
3050 painter.SetDivId(divid, 4);
3052 painter.DecodeOptions(opt);
3054 painter.CheckPadRange();
3056 painter.ScanContent();
3060 var stats = painter.CreateStat();
3061 if (stats) JSROOT.draw(painter.divid, stats,
"");
3063 painter.FillToolbar();
3065 return painter.DrawingReady();
3070 function TGraph2DPainter(graph) {
3071 JSROOT.TObjectPainter.call(
this, graph);
3074 TGraph2DPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype);
3076 TGraph2DPainter.prototype.DecodeOptions =
function(opt) {
3077 var d =
new JSROOT.DrawOptions(opt);
3082 var res = this.options;
3084 res.Color = d.check(
"COL");
3085 res.Line = d.check(
"LINE");
3086 res.Error = d.check(
"ERR") && this.MatchObjectType(
"TGraph2DErrors");
3087 res.Circles = d.check(
"P0");
3088 res.Markers = d.check(
"P");
3090 if (!res.Markers && !res.Error && !res.Circles && !res.Line) res.Markers =
true;
3091 if (!res.Markers) res.Color =
false;
3093 this.OptionsStore(opt);
3096 TGraph2DPainter.prototype.CreateHistogram =
function() {
3097 var gr = this.GetObject(),
3098 xmin = gr.fX[0], xmax = xmin,
3099 ymin = gr.fY[0], ymax = ymin,
3100 zmin = gr.fZ[0], zmax = zmin;
3102 for (var p = 0; p < gr.fNpoints;++p) {
3104 var x = gr.fX[p], y = gr.fY[p], z = gr.fZ[p],
3105 errx = this.options.Error ? gr.fEX[p] : 0,
3106 erry = this.options.Error ? gr.fEY[p] : 0,
3107 errz = this.options.Error ? gr.fEZ[p] : 0;
3109 xmin = Math.min(xmin, x-errx);
3110 xmax = Math.max(xmax, x+errx);
3111 ymin = Math.min(ymin, y-erry);
3112 ymax = Math.max(ymax, y+erry);
3113 zmin = Math.min(zmin, z-errz);
3114 zmax = Math.max(zmax, z+errz);
3117 if (xmin >= xmax) xmax = xmin+1;
3118 if (ymin >= ymax) ymax = ymin+1;
3119 if (zmin >= zmax) zmax = zmin+1;
3120 var dx = (xmax-xmin)*0.02, dy = (ymax-ymin)*0.02, dz = (zmax-zmin)*0.02,
3121 uxmin = xmin - dx, uxmax = xmax + dx,
3122 uymin = ymin - dy, uymax = ymax + dy,
3123 uzmin = zmin - dz, uzmax = zmax + dz;
3125 if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.98;
3126 if ((uxmax>0) && (xmax<=0)) uxmax = 0;
3128 if ((uymin<0) && (ymin>=0)) uymin = ymin*0.98;
3129 if ((uymax>0) && (ymax<=0)) uymax = 0;
3131 if ((uzmin<0) && (zmin>=0)) uzmin = zmin*0.98;
3132 if ((uzmax>0) && (zmax<=0)) uzmax = 0;
3134 var graph = this.GetObject();
3136 if (graph.fMinimum != -1111) uzmin = graph.fMinimum;
3137 if (graph.fMaximum != -1111) uzmax = graph.fMaximum;
3139 var histo = JSROOT.CreateHistogram(
"TH2I", 10, 10);
3140 histo.fName = graph.fName +
"_h";
3141 histo.fTitle = graph.fTitle;
3142 histo.fXaxis.fXmin = uxmin;
3143 histo.fXaxis.fXmax = uxmax;
3144 histo.fYaxis.fXmin = uymin;
3145 histo.fYaxis.fXmax = uymax;
3146 histo.fZaxis.fXmin = uzmin;
3147 histo.fZaxis.fXmax = uzmax;
3148 histo.fMinimum = uzmin;
3149 histo.fMaximum = uzmax;
3150 histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats;
3154 TGraph2DPainter.prototype.Graph2DTooltip =
function(intersect) {
3155 if (isNaN(intersect.index)) {
3156 console.error(
'intersect.index not provided, check three.js version', THREE.REVISION,
'expected r97');
3160 var indx = Math.floor(intersect.index /
this.nvertex);
3161 if ((indx<0) || (indx >= this.index.length))
return null;
3163 indx = this.index[indx];
3165 var p = this.painter,
3166 grx = p.grx(this.graph.fX[indx]),
3167 gry = p.gry(this.graph.fY[indx]),
3168 grz = p.grz(this.graph.fZ[indx]);
3170 if (this.check_next && indx+1<this.graph.fX.length) {
3171 function sqr(v) {
return v*v; }
3172 var d = intersect.point,
3173 grx1 = p.grx(this.graph.fX[indx+1]),
3174 gry1 = p.gry(this.graph.fY[indx+1]),
3175 grz1 = p.grz(this.graph.fZ[indx+1]);
3176 if (sqr(d.x-grx1)+sqr(d.y-gry1)+sqr(d.z-grz1) < sqr(d.x-grx)+sqr(d.y-gry)+sqr(d.z-grz)) {
3177 grx = grx1; gry = gry1; grz = grz1; indx++;
3182 x1: grx - this.scale0,
3183 x2: grx + this.scale0,
3184 y1: gry - this.scale0,
3185 y2: gry + this.scale0,
3186 z1: grz - this.scale0,
3187 z2: grz + this.scale0,
3188 color: this.tip_color,
3189 lines: [ this.tip_name,
3191 "x: " + p.AxisAsText(
"x", this.graph.fX[indx]),
3192 "y: " + p.AxisAsText(
"y", this.graph.fY[indx]),
3193 "z: " + p.AxisAsText(
"z", this.graph.fZ[indx])
3199 TGraph2DPainter.prototype.PointsCallback =
function(args, mesh) {
3206 JSROOT.extend(mesh, args);
3208 mesh.tip_name = this.GetTipName();
3209 mesh.tooltip = this.Graph2DTooltip;
3211 mesh.painter.toplevel.add(mesh);
3213 this.points_callback_cnt--;
3215 this.CheckCallbacks();
3218 TGraph2DPainter.prototype.CheckCallbacks =
function() {
3219 if (this.points_callback_cnt > 0)
return;
3221 var fp = this.frame_painter();
3222 if (fp) fp.Render3D(100);
3224 if (!this._drawing_ready) {
3225 this.DrawingReady();
3226 this._drawing_ready =
true;
3230 TGraph2DPainter.prototype.Redraw =
function() {
3232 var main = this.main_painter(),
3233 fp = this.frame_painter(),
3234 graph = this.GetObject(),
3237 if (!graph || !main || !fp || !fp.mode3d)
return;
3239 function CountSelected(zmin, zmax) {
3241 for (var i=0; i < graph.fNpoints; ++i) {
3242 if ((graph.fX[i] < fp.scale_xmin) || (graph.fX[i] > fp.scale_xmax) ||
3243 (graph.fY[i] < fp.scale_ymin) || (graph.fY[i] > fp.scale_ymax) ||
3244 (graph.fZ[i] < zmin) || (graph.fZ[i] >= zmax))
continue;
3252 if ((JSROOT.gStyle.OptimizeDraw > 0) && !fp.webgl) {
3253 var numselected = CountSelected(fp.scale_zmin, fp.scale_zmax),
3256 if (numselected > sizelimit) {
3257 step = Math.floor(numselected / sizelimit);
3258 if (step <= 2) step = 2;
3262 var markeratt =
new JSROOT.TAttMarkerHandler(graph),
3264 levels = [fp.scale_zmin, fp.scale_zmax],
3265 scale = fp.size_xy3d / 100 * markeratt.GetFullSize();
3267 if (this.options.Circles) scale = 0.06*fp.size_xy3d;
3269 if (fp.usesvg) scale*=0.3;
3271 if (this.options.Color) {
3272 levels = main.GetContour();
3273 palette = main.GetPalette();
3277 this.points_callback_cnt = levels.length-1;
3279 for (var lvl=0;lvl<levels.length-1;++lvl) {
3281 var lvl_zmin = Math.max(levels[lvl], fp.scale_zmin),
3282 lvl_zmax = Math.min(levels[lvl+1], fp.scale_zmax);
3284 if (lvl_zmin >= lvl_zmax) {
3285 this.points_callback_cnt--;
3289 var size = Math.floor(CountSelected(lvl_zmin, lvl_zmax) / step),
3290 pnts = null, select = 0,
3291 index =
new Int32Array(size), icnt = 0,
3292 err = null, line = null, ierr = 0, iline = 0;
3294 if (this.options.Markers ||
this.options.Circles)
3295 pnts =
new JSROOT.Painter.PointsCreator(size, fp.webgl, scale/3);
3297 if (this.options.Error)
3298 err =
new Float32Array(size*6*3);
3300 if (this.options.Line)
3301 line =
new Float32Array((size-1)*6);
3303 for (var i=0; i < graph.fNpoints; ++i) {
3304 if ((graph.fX[i] < fp.scale_xmin) || (graph.fX[i] > fp.scale_xmax) ||
3305 (graph.fY[i] < fp.scale_ymin) || (graph.fY[i] > fp.scale_ymax) ||
3306 (graph.fZ[i] < lvl_zmin) || (graph.fZ[i] >= lvl_zmax))
continue;
3309 select = (select+1) % step;
3310 if (select!==0)
continue;
3315 var x = fp.grx(graph.fX[i]),
3316 y = fp.gry(graph.fY[i]),
3317 z = fp.grz(graph.fZ[i]);
3319 if (pnts) pnts.AddPoint(x,y,z);
3322 err[ierr] = fp.grx(graph.fX[i] - graph.fEX[i]);
3325 err[ierr+3] = fp.grx(graph.fX[i] + graph.fEX[i]);
3330 err[ierr+1] = fp.gry(graph.fY[i] - graph.fEY[i]);
3333 err[ierr+4] = fp.gry(graph.fY[i] + graph.fEY[i]);
3338 err[ierr+2] = fp.grz(graph.fZ[i] - graph.fEZ[i]);
3341 err[ierr+5] = fp.grz(graph.fZ[i] + graph.fEZ[i]);;
3347 line[iline] = line[iline-3];
3348 line[iline+1] = line[iline-2];
3349 line[iline+2] = line[iline-1];
3359 if (line && (iline>3) && (line.length == iline)) {
3360 var lcolor = this.get_color(this.GetObject().fLineColor),
3361 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(lcolor) });
3362 if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth;
3363 var linemesh = JSROOT.Painter.createLineSegments(line, material);
3364 fp.toplevel.add(linemesh);
3366 linemesh.graph = graph;
3367 linemesh.index = index;
3368 linemesh.painter = fp;
3369 linemesh.scale0 = 0.7*scale;
3370 linemesh.tip_name = this.GetTipName();
3371 linemesh.tip_color = (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00;
3372 linemesh.nvertex = 2;
3373 linemesh.check_next =
true;
3375 linemesh.tooltip = this.Graph2DTooltip;
3379 var lcolor = this.get_color(this.GetObject().fLineColor),
3380 material =
new THREE.LineBasicMaterial({ color:
new THREE.Color(lcolor) });
3381 if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth;
3382 var errmesh = JSROOT.Painter.createLineSegments(err, material);
3383 fp.toplevel.add(errmesh);
3385 errmesh.graph = graph;
3386 errmesh.index = index;
3387 errmesh.painter = fp;
3388 errmesh.scale0 = 0.7*scale;
3389 errmesh.tip_name = this.GetTipName();
3390 errmesh.tip_color = (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00;
3391 errmesh.nvertex = 6;
3393 errmesh.tooltip = this.Graph2DTooltip;
3397 this.points_callback_cnt--;
3400 var fcolor =
'blue';
3402 if (!this.options.Circles)
3403 fcolor = palette ? palette.calcColor(lvl, levels.length) :
3404 this.get_color(graph.fMarkerColor);
3406 pnts.AssignCallback(this.PointsCallback.bind(
this, {
3411 tip_color: (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00
3414 pnts.CreatePoints({ color: fcolor, style: this.options.Circles ? 4 : graph.fMarkerStyle });
3418 this.CheckCallbacks();
3421 JSROOT.Painter.drawGraph2D =
function(divid, gr, opt) {
3423 var painter =
new JSROOT.TGraph2DPainter(gr);
3425 painter.SetDivId(divid, -1);
3427 painter.DecodeOptions(opt);
3429 if (painter.main_painter()) {
3430 painter.SetDivId(divid);
3436 gr.fHistogram = painter.CreateHistogram();
3438 JSROOT.draw(divid, gr.fHistogram,
"lego;axis",
function(hpainter) {
3439 painter.ownhisto =
true;
3440 painter.SetDivId(divid);
3449 JSROOT.Painter.drawPolyMarker3D =
function(divid, poly, opt) {
3451 var painter =
new JSROOT.TObjectPainter(poly);
3453 painter.SetDivId(divid);
3455 painter.Redraw =
function() {
3457 var fp = this.frame_painter();
3459 if (!fp || !fp.mode3d) {
3460 if (!this._did_redraw) this.DrawingReady();
3461 this._did_redraw =
true;
3465 var step = 1, sizelimit = 50000, numselect = 0;
3467 for (var i=0;i<poly.fP.length;i+=3) {
3468 if ((poly.fP[i] < fp.scale_xmin) || (poly.fP[i] > fp.scale_xmax) ||
3469 (poly.fP[i+1] < fp.scale_ymin) || (poly.fP[i+1] > fp.scale_ymax) ||
3470 (poly.fP[i+2] < fp.scale_zmin) || (poly.fP[i+2] > fp.scale_zmax))
continue;
3474 if ((JSROOT.gStyle.OptimizeDraw > 0) && (numselect > sizelimit)) {
3475 step = Math.floor(numselect/sizelimit);
3476 if (step <= 2) step = 2;
3479 var size = Math.floor(numselect/step),
3480 pnts =
new JSROOT.Painter.PointsCreator(size, fp.webgl, fp.size_xy3d/100),
3481 index =
new Int32Array(size),
3482 select = 0, icnt = 0;
3484 for (var i=0; i<poly.fP.length; i+=3) {
3486 if ((poly.fP[i] < fp.scale_xmin) || (poly.fP[i] > fp.scale_xmax) ||
3487 (poly.fP[i+1] < fp.scale_ymin) || (poly.fP[i+1] > fp.scale_ymax) ||
3488 (poly.fP[i+2] < fp.scale_zmin) || (poly.fP[i+2] > fp.scale_zmax))
continue;
3491 select = (select+1) % step;
3492 if (select!==0)
continue;
3497 pnts.AddPoint(fp.grx(poly.fP[i]), fp.gry(poly.fP[i+1]), fp.grz(poly.fP[i+2]));
3500 pnts.AssignCallback(
function(mesh) {
3501 fp.toplevel.add(mesh);
3503 mesh.tip_color = (poly.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00;
3504 mesh.tip_name = poly.fName ||
"Poly3D";
3507 mesh.scale0 = 0.7*pnts.scale;
3510 mesh.tooltip =
function(intersect) {
3511 if (isNaN(intersect.index)) {
3512 console.error(
'intersect.index not provided, check three.js version', THREE.REVISION,
'expected r97');
3515 var indx = Math.floor(intersect.index /
this.nvertex);
3516 if ((indx<0) || (indx >= this.index.length))
return null;
3518 indx = this.index[indx];
3520 var p = this.painter,
3521 grx = p.grx(this.poly.fP[indx]),
3522 gry = p.gry(this.poly.fP[indx+1]),
3523 grz = p.grz(this.poly.fP[indx+2]);
3526 x1: grx - this.scale0,
3527 x2: grx + this.scale0,
3528 y1: gry - this.scale0,
3529 y2: gry + this.scale0,
3530 z1: grz - this.scale0,
3531 z2: grz + this.scale0,
3532 color: this.tip_color,
3533 lines: [ this.tip_name,
3535 "x: " + p.AxisAsText(
"x", this.poly.fP[indx]),
3536 "y: " + p.AxisAsText(
"y", this.poly.fP[indx+1]),
3537 "z: " + p.AxisAsText(
"z", this.poly.fP[indx+2])
3545 if (!painter._did_redraw) painter.DrawingReady();
3546 painter._did_redraw =
true;
3550 pnts.CreatePoints({ color: this.get_color(poly.fMarkerColor),
3551 style: poly.fMarkerStyle });
3559 JSROOT.TH3Painter = TH3Painter;
3560 JSROOT.TGraph2DPainter = TGraph2DPainter;