5 if ( typeof define ===
"function" && define.amd ) {
6 define( [
'JSRootPainter',
'd3',
'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(
"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',
'JSRoot3DPainter.js');
14 if (typeof d3 !=
'object')
15 throw new Error(
'This extension requires d3.js',
'JSRoot3DPainter.js');
16 if (typeof THREE ==
'undefined')
17 throw new Error(
'THREE is not defined',
'JSRoot3DPainter.js');
18 factory(JSROOT, d3, THREE);
20 } (
function(JSROOT, d3, THREE, THREE_MORE, document) {
24 JSROOT.sources.push(
"3d");
26 if ((typeof document==
'undefined') && (typeof window==
'object')) document = window.document;
28 if (typeof JSROOT.Painter !=
'object')
29 throw new Error(
'JSROOT.Painter is not defined',
'JSRoot3DPainter.js');
39 JSROOT.Painter.TestWebGL =
function() {
41 if (JSROOT.gStyle.NoWebGL || JSROOT.nodejs)
return false;
43 if (
'_Detect_WebGL' in
this)
return this._Detect_WebGL;
46 var canvas = document.createElement(
'canvas' );
47 this._Detect_WebGL = !! ( window.WebGLRenderingContext && ( canvas.getContext(
'webgl' ) || canvas.getContext(
'experimental-webgl' ) ) );
50 this._Detect_WebGL =
false;
53 return this._Detect_WebGL;
63 JSROOT.Painter.UseSVGFor3D =
function() {
64 if (!JSROOT.nodejs)
return false;
66 if (this._Detect_UseSVGFor3D !== undefined)
67 return this._Detect_UseSVGFor3D;
69 var nodejs_canvas = null;
72 nodejs_canvas = require(
'canvas');
77 this._Detect_UseSVGFor3D = !nodejs_canvas;
78 return this._Detect_UseSVGFor3D;
91 JSROOT.Painter.Create3DRenderer =
function(width, height, usesvg, makeimage, usewebgl, args) {
96 usesvgimg: usesvg && JSROOT.gStyle.ImageSVG
99 if (!args) args = { antialias:
true, alpha:
true };
102 res.usewebgl =
false;
103 }
else if (usewebgl !== undefined) {
104 res.usewebgl = usewebgl;
106 res.usewebgl = JSROOT.Painter.TestWebGL();
111 if (JSROOT.BatchMode && JSROOT.browser.isChromeHeadless && res.usewebgl)
112 args.premultipliedAlpha =
false;
116 var nodejs_canvas = null;
118 if (JSROOT.nodejs && res.usesvgimg) {
120 nodejs_canvas = require(
'canvas');
122 nodejs_canvas = null;
123 res.usesvgimg =
false;
124 JSROOT.gStyle.ImageSVG =
false;
131 args.canvas =
new nodejs_canvas(width, height);
132 args.canvas.style = {};
135 res.renderer = res.usewebgl ?
new THREE.WebGLRenderer(args) :
new THREE.SoftwareRenderer(args);
138 res.renderer = THREE.CreateSVGRenderer(
false, 0, document);
141 if (res.usesvgimg || (res.renderer.makeOuterHTML !== undefined)) {
143 if (!JSROOT.svg_workaround) JSROOT.svg_workaround = [];
144 res.renderer.workaround_id = JSROOT.svg_workaround.length;
145 JSROOT.svg_workaround[res.renderer.workaround_id] =
"<svg></svg>";
148 res.dom = document.createElementNS(
'http://www.w3.org/2000/svg',
'path');
149 res.dom.setAttribute(
'jsroot_svg_workaround', res.renderer.workaround_id);
152 res.renderer = res.usewebgl ?
new THREE.WebGLRenderer(args) :
new THREE.SoftwareRenderer(args);
157 res.renderer.setSize(width, height);
160 res.dom = res.renderer.domElement;
161 if (!usesvg && makeimage) {
162 res.dom = res.renderer.svgImage = document.createElementNS(
'http://www.w3.org/2000/svg',
'image');
163 d3.select(res.dom).attr(
"width", width)
164 .attr(
"height", height);
171 JSROOT.Painter.AfterRender3D =
function(renderer) {
172 if (renderer.svgImage) {
173 var dataUrl = renderer.domElement.toDataURL(
"image/png");
174 var attrname = JSROOT.nodejs ?
"xlink_href_nodejs" :
"xlink:href";
175 d3.select(renderer.svgImage).attr(attrname, dataUrl);
179 if (renderer.workaround_id !== undefined) {
180 if (typeof renderer.makeOuterHTML ==
'function') {
181 JSROOT.svg_workaround[renderer.workaround_id] = renderer.makeOuterHTML();
183 var canvas = renderer.domElement;
184 var dataUrl = canvas.toDataURL(
"image/png");
185 var svg =
'<image width="' + canvas.width +
'" height="' + canvas.height +
'" xlink:href="' + dataUrl +
'"></image>';
186 JSROOT.svg_workaround[renderer.workaround_id] = svg;
191 JSROOT.Painter.ProcessSVGWorkarounds =
function(svg) {
192 if (!JSROOT.svg_workaround)
return svg;
193 for (var k=0;k<JSROOT.svg_workaround.length;++k)
194 svg = svg.replace(
'<path jsroot_svg_workaround="' + k +
'"></path>', JSROOT.svg_workaround[k]);
195 JSROOT.svg_workaround = undefined;
200 JSROOT.Painter.TooltipFor3D =
function(prnt, canvas) {
204 this.parent = prnt ? prnt : document.body;
205 this.canvas = canvas;
208 this.check_parent =
function(prnt) {
209 if (prnt && (this.parent !== prnt)) {
216 this.extract_pos =
function(e) {
217 if (typeof e ==
'object' && (e.u !== undefined) && (e.l !== undefined))
return e;
218 var res = { u: 0, l: 0 };
220 res.l = JSROOT.browser.isIE ? (e.clientX + document.documentElement.scrollLeft) : e.pageX;
221 res.u = JSROOT.browser.isIE ? (e.clientY + document.documentElement.scrollTop) : e.pageY;
234 this.pos =
function(e) {
236 if (!this.tt)
return;
238 var pos = this.extract_pos(e);
240 var rect1 = this.parent.getBoundingClientRect(),
241 rect2 = this.canvas.getBoundingClientRect();
243 if ((rect1.left !== undefined) && (rect2.left!== undefined)) pos.l += (rect2.left-rect1.left);
245 if ((rect1.top !== undefined) && (rect2.top!== undefined)) pos.u += rect2.top-rect1.top;
247 if (pos.l +
this.tt.offsetWidth + 3 >=
this.parent.offsetWidth)
248 pos.l = this.parent.offsetWidth - this.tt.offsetWidth - 3;
250 if (pos.u +
this.tt.offsetHeight + 15 >=
this.parent.offsetHeight)
251 pos.u = this.parent.offsetHeight - this.tt.offsetHeight - 15;
255 var abs_parent = this.parent;
257 var style = getComputedStyle(abs_parent);
258 if (!style || (style.position !==
'static'))
break;
259 if (!abs_parent.parentNode || (abs_parent.parentNode.nodeType != 1))
break;
260 abs_parent = abs_parent.parentNode;
263 if (abs_parent && (abs_parent !== this.parent)) {
264 var rect0 = abs_parent.getBoundingClientRect();
265 pos.l += (rect1.left - rect0.left);
266 pos.u += (rect1.top - rect0.top);
270 this.tt.style.top = (pos.u + 15) +
'px';
271 this.tt.style.left = (pos.l + 3) +
'px';
274 this.show =
function(v, mouse_pos, status_func) {
276 if (!v || (v===
""))
return this.hide();
278 if (v && (typeof v ==
'object') && (v.lines || v.line)) {
279 if (v.only_status)
return this.hide();
284 var res = v.lines[0];
285 for (var n=1;n<v.lines.length;++n) res+=
"<br/>" + v.lines[n];
290 if (this.tt === null) {
291 this.tt = document.createElement(
'div');
292 this.tt.setAttribute(
'class',
'jsroot_tt3d_main');
293 this.cont = document.createElement(
'div');
294 this.cont.setAttribute(
'class',
'jsroot_tt3d_cont');
295 this.tt.appendChild(this.cont);
296 this.parent.appendChild(this.tt);
299 if (this.lastlbl !== v) {
300 this.cont.innerHTML = v;
302 this.tt.style.width =
'auto';
303 if (JSROOT.browser.isIE)
304 this.tt.style.width = this.tt.offsetWidth;
308 this.hide =
function() {
309 if (this.tt !== null)
310 this.parent.removeChild(this.tt);
321 JSROOT.Painter.CreateOrbitControl =
function(painter, camera, scene, renderer, lookat) {
323 if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel)
324 renderer.domElement.addEventListener(
'wheel', control_mousewheel);
326 var enable_zoom = JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomMouse,
327 enable_select = typeof painter.ProcessMouseClick ==
"function";
329 if (enable_zoom || enable_select) {
330 renderer.domElement.addEventListener(
'mousedown', control_mousedown);
331 renderer.domElement.addEventListener(
'mouseup', control_mouseup);
334 var control =
new THREE.OrbitControls(camera, renderer.domElement);
336 control.enableDamping =
false;
337 control.dampingFactor = 1.0;
338 control.enableZoom =
true;
340 control.target.copy(lookat);
341 control.target0.copy(lookat);
345 control.tooltip =
new JSROOT.Painter.TooltipFor3D(painter.select_main().node(), renderer.domElement);
347 control.painter = painter;
348 control.camera = camera;
349 control.scene = scene;
350 control.renderer = renderer;
351 control.raycaster =
new THREE.Raycaster();
352 control.raycaster.linePrecision = 10;
353 control.mouse_zoom_mesh = null;
354 control.block_ctxt =
false;
355 control.block_mousemove =
false;
356 control.cursor_changed =
false;
357 control.control_changed =
false;
358 control.control_active =
false;
359 control.mouse_ctxt = { x:0, y: 0, on:
false };
360 control.enable_zoom = enable_zoom;
361 control.enable_select = enable_select;
363 control.Cleanup =
function() {
364 if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel)
365 this.domElement.removeEventListener(
'wheel', control_mousewheel);
366 if (this.enable_zoom || this.enable_select) {
367 this.domElement.removeEventListener(
'mousedown', control_mousedown);
368 this.domElement.removeEventListener(
'mouseup', control_mouseup);
371 this.domElement.removeEventListener(
'dblclick', this.lstn_dblclick);
372 this.domElement.removeEventListener(
'contextmenu', this.lstn_contextmenu);
373 this.domElement.removeEventListener(
'mousemove', this.lstn_mousemove);
374 this.domElement.removeEventListener(
'mouseleave', this.lstn_mouseleave);
383 delete this.renderer;
384 delete this.raycaster;
385 delete this.mouse_zoom_mesh;
388 control.HideTooltip =
function() {
392 control.GetMousePos =
function(evnt, mouse) {
393 mouse.x = (
'offsetX' in evnt) ? evnt.offsetX : evnt.layerX;
394 mouse.y = (
'offsetY' in evnt) ? evnt.offsetY : evnt.layerY;
395 mouse.clientX = evnt.clientX;
396 mouse.clientY = evnt.clientY;
400 control.GetOriginDirectionIntersects =
function(origin, direction) {
401 this.raycaster.set(origin, direction);
402 var intersects = this.raycaster.intersectObjects(this.scene.children,
true);
404 if (typeof this.painter.FilterIntersects ==
'function')
405 intersects = this.painter.FilterIntersects(intersects);
409 control.GetMouseIntersects =
function(mouse) {
411 var sz = (this.renderer instanceof THREE.WebGLRenderer) ?
412 this.renderer.getSize(
new THREE.Vector2()) :
413 this.renderer.domElement;
415 var pnt = { x: mouse.x / sz.width * 2 - 1, y: -mouse.y / sz.height * 2 + 1 };
417 this.camera.updateMatrix();
418 this.camera.updateMatrixWorld();
419 this.raycaster.setFromCamera( pnt, this.camera );
420 var intersects = this.raycaster.intersectObjects(this.scene.children,
true);
423 if (typeof this.painter.FilterIntersects ==
'function')
424 intersects = this.painter.FilterIntersects(intersects);
429 control.DetectZoomMesh =
function(evnt) {
430 var mouse = this.GetMousePos(evnt, {});
431 var intersects = this.GetMouseIntersects(mouse);
433 for (var n=0;n<intersects.length;++n)
434 if (intersects[n].
object.zoom)
435 return intersects[n];
440 control.ProcessDblClick =
function(evnt) {
441 var intersect = this.DetectZoomMesh(evnt);
442 if (intersect && this.painter) {
443 this.painter.Unzoom(intersect.object.use_y_for_z ?
"y" : intersect.object.zoom);
450 control.ChangeEvent =
function() {
451 this.mouse_ctxt.on =
false;
452 this.painter.zoom_changed_interactive = 1;
453 this.painter.Render3D(0);
454 this.control_changed =
true;
457 control.StartEvent =
function() {
458 this.control_active =
true;
459 this.block_ctxt =
false;
460 this.mouse_ctxt.on =
false;
469 control.EndEvent =
function() {
470 this.control_active =
false;
471 if (this.mouse_ctxt.on) {
472 this.mouse_ctxt.on =
false;
473 this.ContextMenu(this.mouse_ctxt, this.GetMouseIntersects(this.mouse_ctxt));
477 this.control_changed =
false;
480 control.MainProcessContextMenu =
function(evnt) {
481 evnt.preventDefault();
482 this.GetMousePos(evnt, this.mouse_ctxt);
483 if (this.control_active)
484 this.mouse_ctxt.on =
true;
487 this.block_ctxt =
false;
489 this.ContextMenu(this.mouse_ctxt, this.GetMouseIntersects(this.mouse_ctxt));
492 control.ContextMenu =
function(pos, intersects) {
496 control.SwitchTooltip =
function(on) {
497 this.block_mousemove = !on;
500 this.RemoveZoomMesh();
504 control.RemoveZoomMesh =
function() {
505 if (this.mouse_zoom_mesh && this.mouse_zoom_mesh.object.ShowSelection())
506 this.painter.Render3D();
507 this.mouse_zoom_mesh = null;
510 control.MainProcessMouseMove =
function(evnt) {
511 if (this.control_active && evnt.buttons && (evnt.buttons & 2))
512 this.block_ctxt =
true;
514 if (this.control_active || this.block_mousemove || !this.ProcessMouseMove)
return;
516 if (this.mouse_zoom_mesh) {
519 var zoom2 = this.DetectZoomMesh(evnt), pnt2 = null;
521 if (zoom2 && (zoom2.object ===
this.mouse_zoom_mesh.object)) {
524 pnt2 = this.mouse_zoom_mesh.object.GlobalIntersect(this.raycaster);
527 if (pnt2) this.mouse_zoom_mesh.point2 = pnt2;
529 if (pnt2 && this.painter.enable_highlight)
530 if (this.mouse_zoom_mesh.object.ShowSelection(
this.mouse_zoom_mesh.point, pnt2))
531 this.painter.Render3D(0);
537 evnt.preventDefault();
540 this.tmout_mouse = this.GetMousePos(evnt, {});
541 this.tmout_ttpos = this.tooltip ? this.tooltip.extract_pos(evnt) : null;
543 if (this.tmout_handle) {
544 clearTimeout(this.tmout_handle);
545 delete this.tmout_handle;
548 if (!this.mouse_tmout)
549 this.DelayedProcessMouseMove();
551 this.tmout_handle = setTimeout(this.DelayedProcessMouseMove.bind(
this), this.mouse_tmout);
555 control.DelayedProcessMouseMove =
function() {
557 delete this.tmout_handle;
559 var mouse = this.tmout_mouse,
560 intersects = this.GetMouseIntersects(mouse),
561 tip = this.ProcessMouseMove(intersects),
562 status_func = this.painter.GetShowStatusFunc();
564 if (tip && status_func) {
565 var name =
"", title =
"", coord =
"", info =
"";
566 if (mouse) coord = mouse.x.toFixed(0)+
"," + mouse.y.toFixed(0);
567 if (typeof tip ==
"string") {
570 name = tip.name; title = tip.title;
571 if (tip.line) info = tip.line;
else
572 if (tip.lines) { info = tip.lines.slice(1).join(
' '); name = tip.lines[0]; }
574 status_func(name, title, info, coord);
577 this.cursor_changed =
false;
578 if (tip && this.painter && this.painter.IsTooltipAllowed()) {
579 this.tooltip.check_parent(this.painter.select_main().node());
581 this.tooltip.show(tip, mouse);
582 this.tooltip.pos(this.tmout_ttpos);
586 for (var n=0;n<intersects.length;++n)
587 if (intersects[n].
object.zoom) this.cursor_changed =
true;
590 document.body.style.cursor = this.cursor_changed ?
'pointer' :
'auto';
593 control.MainProcessMouseLeave =
function() {
595 if (this.tmout_handle) {
596 clearTimeout(this.tmout_handle);
597 delete this.tmout_handle;
600 if (typeof this.ProcessMouseLeave ===
'function')
601 this.ProcessMouseLeave();
602 if (this.cursor_changed) {
603 document.body.style.cursor =
'auto';
604 this.cursor_changed =
false;
608 function control_mousewheel(evnt) {
611 if (JSROOT.Painter.IsRender3DFired(control.painter) || control.mouse_zoom_mesh) {
612 evnt.preventDefault();
613 evnt.stopPropagation();
614 evnt.stopImmediatePropagation();
618 var intersect = control.DetectZoomMesh(evnt);
619 if (!intersect)
return;
621 evnt.preventDefault();
622 evnt.stopPropagation();
623 evnt.stopImmediatePropagation();
625 if (control.painter && (typeof control.painter.AnalyzeMouseWheelEvent ==
'function')) {
626 var kind = intersect.object.zoom,
627 position = intersect.point[kind],
628 item = { name: kind, ignore:
false };
631 if (kind!==
"z") position = (position + control.painter.size_xy3d)/2/control.painter.size_xy3d;
632 else position = position/2/control.painter.size_z3d;
634 control.painter.AnalyzeMouseWheelEvent(evnt, item, position,
false);
636 if ((kind===
"z") && intersect.object.use_y_for_z) kind=
"y";
638 control.painter.Zoom(kind, item.min, item.max);
642 function control_mousedown(evnt) {
646 if (control.mouse_zoom_mesh) {
647 evnt.stopImmediatePropagation();
648 evnt.stopPropagation();
653 if ((evnt.button!==undefined) && (evnt.button !==0))
return;
654 if ((evnt.buttons!==undefined) && (evnt.buttons !== 1))
return;
656 if (control.enable_zoom) {
657 control.mouse_zoom_mesh = control.DetectZoomMesh(evnt);
658 if (control.mouse_zoom_mesh) {
660 evnt.stopImmediatePropagation();
661 evnt.stopPropagation();
666 if (control.enable_select) {
667 control.mouse_select_pnt = control.GetMousePos(evnt, {});
671 function control_mouseup(evnt) {
673 if (control.mouse_zoom_mesh && control.mouse_zoom_mesh.point2 && control.painter.Get3DZoomCoord) {
675 var kind = control.mouse_zoom_mesh.object.zoom,
676 pos1 = control.painter.Get3DZoomCoord(control.mouse_zoom_mesh.point, kind),
677 pos2 = control.painter.Get3DZoomCoord(control.mouse_zoom_mesh.point2, kind);
679 if (pos1>pos2) { var v = pos1; pos1 = pos2; pos2 = v; }
681 if ((kind===
"z") && control.mouse_zoom_mesh.object.use_y_for_z) kind=
"y";
683 if ((kind===
"z") && control.mouse_zoom_mesh.object.use_y_for_z) kind=
"y";
687 if (control.painter.Zoom(kind, pos1, pos2))
688 control.mouse_zoom_mesh = null;
692 if (control.enable_zoom)
693 control.RemoveZoomMesh();
699 if (control.enable_select && control.mouse_select_pnt) {
701 var pnt = control.GetMousePos(evnt, {});
703 var same_pnt = (pnt.x == control.mouse_select_pnt.x) && (pnt.y == control.mouse_select_pnt.y);
704 delete control.mouse_select_pnt;
707 var intersects = control.GetMouseIntersects(pnt);
708 control.painter.ProcessMouseClick(pnt, intersects, evnt);
713 control.MainProcessDblClick =
function(evnt) {
714 this.ProcessDblClick(evnt);
717 control.addEventListener(
'change', control.ChangeEvent.bind(control));
718 control.addEventListener(
'start', control.StartEvent.bind(control));
719 control.addEventListener(
'end', control.EndEvent.bind(control));
721 control.lstn_contextmenu = control.MainProcessContextMenu.bind(control);
722 control.lstn_dblclick = control.MainProcessDblClick.bind(control);
723 control.lstn_mousemove = control.MainProcessMouseMove.bind(control);
724 control.lstn_mouseleave = control.MainProcessMouseLeave.bind(control);
726 renderer.domElement.addEventListener(
'dblclick', control.lstn_dblclick);
727 renderer.domElement.addEventListener(
'contextmenu', control.lstn_contextmenu);
728 renderer.domElement.addEventListener(
'mousemove', control.lstn_mousemove);
729 renderer.domElement.addEventListener(
'mouseleave', control.lstn_mouseleave);
738 JSROOT.Painter.DisposeThreejsObject =
function(obj, only_childs) {
742 for (var i = 0; i < obj.children.length; i++)
743 JSROOT.Painter.DisposeThreejsObject(obj.children[i]);
751 obj.children = undefined;
754 obj.geometry.dispose();
755 obj.geometry = undefined;
758 if (obj.material.map) {
759 obj.material.map.dispose();
760 obj.material.map = undefined;
762 obj.material.dispose();
763 obj.material = undefined;
768 delete obj.bins_index;
771 delete obj.drawn_highlight;
776 JSROOT.Painter.createLineSegments =
function(arr, material, index, only_geometry) {
780 var geom =
new THREE.BufferGeometry();
782 geom.addAttribute(
'position', arr instanceof Float32Array ?
new THREE.BufferAttribute( arr, 3 ) :
new THREE.Float32BufferAttribute( arr, 3 ) );
783 if (index) geom.setIndex(
new THREE.BufferAttribute(index, 1) );
785 if (material.isLineDashedMaterial) {
787 var v1 =
new THREE.Vector3(),
788 v2 =
new THREE.Vector3(),
789 d = 0, distances = null;
792 distances =
new Float32Array(index.length);
793 for (var n=0; n<index.length; n+=2) {
794 var i1 = index[n], i2 = index[n+1];
795 v1.set(arr[i1],arr[i1+1],arr[i1+2]);
796 v2.set(arr[i2],arr[i2+1],arr[i2+2]);
798 d += v2.distanceTo( v1 );
802 distances =
new Float32Array(arr.length/3);
803 for (var n=0; n<arr.length; n+=6) {
804 v1.set(arr[n],arr[n+1],arr[n+2]);
805 v2.set(arr[n+3],arr[n+4],arr[n+5]);
807 d += v2.distanceTo( v1 );
808 distances[n/3+1] = d;
811 geom.addAttribute(
'lineDistance',
new THREE.BufferAttribute(distances, 1) );
814 return only_geometry ? geom :
new THREE.LineSegments(geom, material);
817 JSROOT.Painter.Box3D = {
818 Vertices: [
new THREE.Vector3(1, 1, 1),
new THREE.Vector3(1, 1, 0),
819 new THREE.Vector3(1, 0, 1),
new THREE.Vector3(1, 0, 0),
820 new THREE.Vector3(0, 1, 0),
new THREE.Vector3(0, 1, 1),
821 new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 0, 1) ],
822 Indexes: [ 0,2,1, 2,3,1, 4,6,5, 6,7,5, 4,5,1, 5,0,1, 7,6,2, 6,3,2, 5,7,0, 7,2,0, 1,3,4, 3,6,4 ],
823 Normals: [ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ],
824 Segments: [0, 2, 2, 7, 7, 5, 5, 0, 1, 3, 3, 6, 6, 4, 4, 1, 1, 0, 3, 2, 6, 7, 4, 5]
828 JSROOT.Painter.Box3D.MeshSegments = (
function() {
829 var box3d = JSROOT.Painter.Box3D,
830 arr =
new Int32Array(box3d.Segments.length);
832 for (var n=0;n<arr.length;++n) {
833 for (var k=0;k<box3d.Indexes.length;++k)
834 if (box3d.Segments[n] === box3d.Indexes[k]) {
841 JSROOT.Painter.IsRender3DFired =
function(painter) {
842 if (!painter || painter.renderer === undefined)
return false;
844 return painter.render_tmout !== undefined;
849 function InteractiveControl() {}
851 InteractiveControl.prototype.cleanup =
function() {}
853 InteractiveControl.prototype.extractIndex =
function(intersect) {
return undefined; }
855 InteractiveControl.prototype.setSelected =
function(col, indx) {}
857 InteractiveControl.prototype.setHighlight =
function(col, indx) {}
859 InteractiveControl.prototype.checkHighlightIndex =
function(indx) {
return undefined; }
865 function PointsControl(mesh) {
866 InteractiveControl.call(
this);
870 PointsControl.prototype = Object.create(InteractiveControl.prototype);
872 PointsControl.prototype.cleanup =
function() {
873 if (!this.mesh)
return;
874 delete this.mesh.is_selected;
875 this.createSpecial(null);
879 PointsControl.prototype.extractIndex =
function(intersect) {
880 return intersect && intersect.index!==undefined ? intersect.index : undefined;
883 PointsControl.prototype.setSelected =
function(col, indx) {
885 if ((m.select_col == col) && (m.select_indx == indx)) {
886 console.log(
"Reset selection");
887 col = null; indx = undefined;
890 m.select_indx = indx;
891 this.createSpecial(col, indx);
895 PointsControl.prototype.setHighlight =
function(col, indx) {
899 this.createSpecial(col, indx);
901 this.createSpecial(m.select_col, m.select_indx);
905 PointsControl.prototype.createSpecial =
function(color, index) {
909 m.remove(m.js_special);
910 JSROOT.Painter.DisposeThreejsObject(m.js_special);
917 var geom =
new THREE.BufferGeometry();
918 geom.addAttribute(
'position', m.geometry.getAttribute(
"position"));
919 var material =
new THREE.PointsMaterial( { size: m.material.size*2, color: color } );
920 material.sizeAttenuation = m.material.sizeAttenuation;
922 m.js_special =
new THREE.Points(geom, material);
923 m.js_special.jsroot_special =
true;
927 if (color) m.js_special.material.color =
new THREE.Color(color);
928 if (index !== undefined) m.js_special.geometry.setDrawRange(index, 1);
932 function PointsCreator(size, iswebgl, scale) {
933 this.webgl = (iswebgl === undefined) ?
true : iswebgl;
934 this.scale = scale || 1.;
936 this.pos =
new Float32Array(size*3);
937 this.geom =
new THREE.BufferGeometry();
938 this.geom.addAttribute(
'position',
new THREE.BufferAttribute(
this.pos, 3 ) );
942 PointsCreator.prototype.AddPoint =
function(x,y,z) {
943 this.pos[this.indx] = x;
944 this.pos[this.indx+1] = y;
945 this.pos[this.indx+2] = z;
950 PointsCreator.prototype.AssignCallback =
function(callback) {
951 this.callback = callback;
954 PointsCreator.prototype.Complete =
function(arg) {
959 if ((arg ==
'loaded') && this.texture.onUpdate) this.texture.onUpdate(
this.texture );
960 if (this._did_create)
return;
961 material =
new THREE.PointsMaterial( { size: (this.webgl ? 3 : 1) * this.scale, map: this.texture, transparent:
true } );
963 if (this._did_create)
return;
964 material =
new THREE.PointsMaterial( { size: (this.webgl ? 3 : 1) * this.scale * this.k, color: this.color } );
967 this._did_create =
true;
969 var pnts =
new THREE.Points(this.geom, material);
975 JSROOT.CallBack(this.callback, pnts);
978 PointsCreator.prototype.CreatePoints =
function(args) {
980 if (typeof args !==
'object') args = { color: args };
981 if (!args.color) args.color =
'black';
984 this.color = args.color;
986 this._did_create =
false;
989 if (args.style === 1) this.k = 0.3;
else
990 if (args.style === 6) this.k = 0.5;
else
991 if (args.style === 7) this.k = 0.7;
994 if (!args.style || (
this.k !== 1) || JSROOT.BatchMode)
995 return this.Complete();
997 var handler =
new JSROOT.TAttMarkerHandler({ style: args.style, color: args.color, size: 8 });
999 var plainSVG =
'<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg">' +
1000 '<path d="' + handler.create(32,32) +
'" stroke="' + handler.getStrokeColor() +
'" fill="' + handler.getFillColor() +
'"/></svg>';
1002 this.texture =
new THREE.Texture();
1003 this.texture.needsUpdate =
true;
1004 this.texture.format = THREE.RGBAFormat;
1005 this.texture.image = document.createElement(
'img');
1007 this.texture.image.onload = this.Complete.bind(
this,
'loaded')
1009 this.texture.image.src =
'data:image/svg+xml;utf8,' + plainSVG;
1012 return this.Complete();
1017 function Create3DLineMaterial(painter, obj) {
1018 if (!painter || !obj)
return null;
1020 var lcolor = painter.get_color(obj.fLineColor),
1022 style = obj.fLineStyle ? JSROOT.Painter.root_line_styles[obj.fLineStyle] :
"",
1023 dash = style ? style.split(
",") : [];
1025 if (dash && dash.length>=2)
1026 material =
new THREE.LineDashedMaterial( { color: lcolor, dashSize: parseInt(dash[0]), gapSize: parseInt(dash[1]) } );
1028 material =
new THREE.LineBasicMaterial({ color: lcolor });
1030 if (obj.fLineWidth && (obj.fLineWidth>1) && !JSROOT.browser.isIE) material.linewidth = obj.fLineWidth;
1037 function drawPolyLine3D() {
1038 var line = this.GetObject(),
1039 main = this.frame_painter();
1041 if (!main || !main.mode3d || !main.toplevel || !line)
return;
1043 var fN, fP, fOption, pnts = [];
1045 if (line._blob && (line._blob.length==4)) {
1049 fOption = line._blob[3];
1053 fOption = line.fOption;
1056 for (var n=3;n<3*fN;n+=3)
1057 pnts.push(main.grx(fP[n-3]), main.gry(fP[n-2]), main.grz(fP[n-1]),
1058 main.grx(fP[n]), main.gry(fP[n+1]), main.grz(fP[n+2]));
1060 var lines = JSROOT.Painter.createLineSegments(pnts, Create3DLineMaterial(
this, line));
1062 main.toplevel.add(lines);
1069 JSROOT.Painter.PointsCreator = PointsCreator;
1070 JSROOT.Painter.InteractiveControl = InteractiveControl;
1071 JSROOT.Painter.PointsControl = PointsControl;
1073 JSROOT.Painter.drawPolyLine3D = drawPolyLine3D;
1075 JSROOT.Painter.Create3DLineMaterial = Create3DLineMaterial;