一般有两种表现形式:指南针、小方盒(方位魔方)。
Hightopo 的 HT for Web 产品可以很方便地构造轻量化的 3D 可视化场景,在 web 端 我们可以利用 HT 2D 引擎 和 3D 渲染引擎 来实现这个功能,搭建一个简易的类 maya 操作界面。
方位魔方 通过在一个小场景 (ht.graph3d.Graph3dView)中放置一个魔方 obj 模型来实现,然后把这个小场景放置在图纸的右上角(即下图中的位置 2) 即可。
const g3d = new ht.graph3d.Graph3dView(); g3d.setOriginAxisVisible(true); g3d.setGridVisible(true); g3d.addToDOM(); const g2d = new ht.graph.GraphView(); g2d.deserialize('displays/test.json', json => { g2d.addToDOM(g3d.getView()); });复制代码
由于 指南针 的目的是用于指示鸟瞰图中的方位,所以与 Y 轴并没有什么关系,我们可以将整个计算过程放在二维空间中进行。
const eye = this.g3d.getEye(); const center = this.g3d.getCenter(); const v = new ht.Math.Vector2(eye[0], eye[2]); const v2 = new ht.Math.Vector2(center[0], center[2]); const angle = v.sub(v2).angle() - Math.PI / 2; compass.setRotation(-angle); compass.a('angle', angle); compass.a('angle2', angle);复制代码
利用向量减法,求得由 center 指向 eye 的向量并存入变量 v 中,利用 angle() 方法可以获取到当前向量与 x 正半轴 (即正东方向)的夹角(弧度制),为什么要减去 Math.PI / 2 呢,因为我们计算求得的是与 x 轴的夹角,而指南针的正方向(北方)是对应着 z 轴的负半轴。
利用 HT 2D 引擎提供的 数据绑定 的功能,轮盘图标 和 角度图标 的旋转角度可以通过给 compass 这个节点设置属性值来实时动态改变。
graph3dView.addPropertyChangeListener(e=>{ if(e.property === 'eye' || e.property === 'center'){ changeCompass(); //... } });复制代码
graph3dView.addPropertyChangeListener(e => { if (e.property === 'eye') { const newValue = e.newValue; const vEye = new ht.Math.Vector3(newValue[0], newValue[1], newValue[2]).normalize(); graph3dView2.setEye([300 * vEye.x, 300 * vEye.y, 300 * vEye.z]); } });复制代码
其中,e.newValue 会获取到场景视点改变后的值,我们用这个值构建一个三维向量(ht.Math.Vector3)并调用 normalize() 方法进行归一化,这样可以使得任何角度、位置求得的距离都保持一致。
在这里我们需要用到一个求交点的方法: graph3dView.intersectObject(event, data),该方法会返回一个对象,该对象用于描述点击的位置信息, 其中 world 属性用来表示点击位置的世界坐标。
graph3dView2.addInteractorListener(event => { if (event.kind === 'clickData') { const obj = graph3dView2.intersectObject(event.event, event.data); if(obj) { const world = obj.world; //... } } });复制代码
判断了出了点击的哪个面之后,只需要在两个三维场景中分别设置各自视点(eye) 的位置即可。
const world = obj.world; const x = world.x; const y = world.y; const z = world.z; if (Math.abs(x) - Math.abs(y) > 0 && Math.abs(x) - Math.abs(z) > 0) { if (x > 0) { graph3dView2.setEye([300, 0, 0]); graph3dView.setEye([this._distance, 0, 0]); graph3dView2.setCenter([0, 0, 0]); this._g3d.setCenter([0, 0, 0]); } else { graph3dView2.setEye([-300, 0, 0]); graph3dView.setEye([-this._distance, 0, 0]); graph3dView2.setCenter([0, 0, 0]); graph3dView.setCenter([0, 0, 0]); } } else if (Math.abs(y) - Math.abs(x) > 0 && Math.abs(y) - Math.abs(z) > 0) { //... }复制代码
其中,this._distance 是用来描述主场景中视线与原点的距离,可根据需要来调整,300 与之前的描述一致,是小场景中一个比较合适的视角位置,也可以根据需要调整。
1 const sm = graph3dView2.dm().getSelectionModel(); 2 sm.setSelection(null);复制代码
web 3D 有无限的想象空间,有着非常丰富的数据呈现方式,更有着诸多让人眼前一亮的可视化效果,等着我们去将这些数据呈现方式在各个行业中落地,HT 在这方面做了大量的探索和尝试,例如这个好玩儿的太阳系监控系统:www.hightopo.com/demo/solar-…
2019 我们也更新了数百个工业互联网 2D/3D 可视化案例集,在这里你能发现许多新奇的实例,也能发掘出不一样的工业互联网:《分享数百个 HT 工业互联网 2D 3D 可视化应用案例之 2019 篇》,更多行业应用实例可以参考官网案例链接: