前言
基于 WebGL 架构的 3D 可视化平台—平面图导航(一)中已经完成了 iframe 面板与我们的 3D 场景的简单交互,下面我们继续完善并给 iframe 页加上鼠标悬停事件让 iframe 页的 img 标签和我们场景中的 obj 一起动起来。
实现
第一步,还是使用之前的场景接着上次的继续,先编写 iframe 页。给每一个 img 标签都加上 onmouseover、onmouseout 事件。
<!DOCTYPE html><html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>Document</title>
<style>
.total_image {
margin : 20px;
}
.total_image img{
cursor: pointer;
transition: all 0.6s;
width: 50px;
}
.total_image img:hover{
transform: scale(1.5);
position:relative;
z-index:100;
}
</style>
</head>
<body><div class=”total_image” style=”width: 500px;height: 280px;background-size: 100% auto”>
<img class=”model_imag” src=” 发电室 1.jpg” style=”float: left;display: block;width: 85px;height: 84px”
onclick=”onClick(‘PowerGenerationGroup_01′,’viewPoint_1’)” onmouseover=”onMouseOver(‘PowerGenerationGroup_01′,’viewPoint_1’)” onmouseout=”onMouseOut(‘PowerGenerationGroup_01’)”>
<img class=”model_imag” src=” 发电室 2.jpg” style=”float: left;display: block;width: 78px;height: 84px”
onclick=”onClick(‘PowerGenerationGroup_02′,’viewPoint_2’)” onmouseover=”onMouseOver(‘PowerGenerationGroup_02′,’viewPoint_2’)” onmouseout=”onMouseOut(‘PowerGenerationGroup_02’)”>
<img class=”model_imag” src=” 发电室 3.jpg” style=”float: left;display: block;width:170px;height: 84px”
onclick=”onClick(‘PowerGenerationGroup_03′,’viewPoint_3’)” onmouseover=”onMouseOver(‘PowerGenerationGroup_03′,’viewPoint_3’)” onmouseout=”onMouseOut(‘PowerGenerationGroup_03’)”>
<img class=”model_imag” src=” 发电室 4.jpg” style=”float: left;display: block;width:167px;height: 84px”
onclick=”onClick(‘PowerGenerationGroup_04′,’viewPoint_4’)” onmouseover=”onMouseOver(‘PowerGenerationGroup_04′,’viewPoint_4’)” onmouseout=”onMouseOut(‘PowerGenerationGroup_04’)”>
<div style=”display: block;float: left;width: 100px;height: 145px;background-color:white”>
<img class=”model_imag” src=” 办公室 1.jpg” style=”float: left;display: block;width:100px;height: 60px”
onclick=”onClick(‘Office’,’viewPoint_5′)” onmouseover=”onMouseOver(‘Office’,’viewPoint_5′)” onmouseout=”onMouseOut(‘Office’)”>
<img class=”model_imag” src=” 返回.png” style=”float: left;display: block;width:100px;height: 80px” onclick=”initViewPoint()”>
</div>
<img class=”model_imag” src=” 发电室 5.jpg” style=”float: right;display: block;width:123px”
onclick=”onClick(‘PowerGenerationGroup_05′,’viewPoint_8’)” onmouseover=”onMouseOver(‘PowerGenerationGroup_05′,’viewPoint_8’)” onmouseout=”onMouseOut(‘PowerGenerationGroup_05’)”>
<img class=”model_imag” src=” 会议室 1.jpg” style=”float: left;display: block;width: 138px;height: 145px” alt=””
onclick=”onClick(‘BoardRoom_01′,’viewPoint_6’)” onmouseover=”onMouseOver(‘BoardRoom_01′,’viewPoint_6’)” onmouseout=”onMouseOut(‘BoardRoom_01’)”>
<img class=”model_imag” src=” 会议室 2.jpg” style=”float: left;display: block;width: 138px;height: 145px” alt=””
onclick=”onClick(‘BoardRoom_02′,’viewPoint_7’)” onmouseover=”onMouseOver(‘BoardRoom_02′,’viewPoint_7’)” onmouseout=”onMouseOut(‘BoardRoom_02’)”>
</div>
<script>
function onClick(viewPoint,target){
window.parent.onClick(viewPoint,target);
}
function onMouseOver(targetObj,viewPoint){
window.parent.onMouseOver(targetObj,viewPoint);
}
function onMouseOut(targetObj){
window.parent.onMouseOut(targetObj);
}
function initViewPoint(){
window.parent.initViewPoint();
}
</script>
</body></html>
第二步,房间里的物体不要要让他“飞起来”,还要给他加一个“底座”。这里叫他 SurveillanceCamera 类,在自己编写类的时候一定要注意,想要当前类生效一定要继承 THING.Thing,并且 THING.factory.registerClass(‘ClassName’, ClassName);
class SurveillanceCamera extends THING.Thing {
constructor(app) {
super(app);
this.app = app;
this.isFrustum = true;
this.opacity = 1;
this.color = 0xff00ff;
this.vertices = [];
this.near = 0.1;
this.camera = null;
this.node = new THREE.Object3D();
this._frustum = new THREE.Frustum();
this._projScreenMatrix = new THREE.Matrix4();
}
setup(param) {
super.setup(param);
this.fov = param[‘fov’];
this.aspect = param[‘aspect’];
this.far = param[‘far’];
this.alpha = param[‘alpha’];
this.lineAlpha = param[‘lineAlpha’];
this.setupComplete(param);
}
setupComplete(param) {
super.setupComplete(param);
this.build();
}
build() {
if (this.node.children.length > 0) {
this.node.children = [];
}
if (this.camera != null) {
this.camera = null;
}
var h = this.far * Math.tan(this.fov * 0.5 * 0.017453293);
var w = this.aspect * h;
var geometry = new THREE.Geometry();
this.vertices = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(w, -h, -this.far), new THREE.Vector3(w, h, -this.far), new THREE.Vector3(-w, h, -this.far), new THREE.Vector3(-w, -h, -this.far)];
var faces = [new THREE.Face3(0, 1, 2), new THREE.Face3(0, 2, 3), new THREE.Face3(0, 3, 4), new THREE.Face3(0, 4, 1), new THREE.Face3(3, 4, 1), new THREE.Face3(3, 1, 2)];
geometry.vertices = this.vertices;
var line_mat = new THREE.LineBasicMaterial({
color: “#b4f5f8”,
opacity: this.lineAlpha || 0.5,
})
var texture = THREE.ImageUtils.loadTexture(“images/light2.png”);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
var frustum_mat = new THREE.MeshBasicMaterial({
color: “#0aa5ff”,
opacity: this.alpha || 0.5,
transparent: true,
side: THREE.DoubleSide,
});
var line_mesh = new THREE.Line(geometry, line_mat);
var frustum_mesh = new THREE.Mesh(geometry, frustum_mat);
geometry.faces = faces;
this.node.add(frustum_mesh, line_mesh);
this.camera = new THREE.PerspectiveCamera(this.fov, this.aspect, this.near, this.far);
this.camera.position.set(this.position[0], this.position[1], this.position[2]);
this.camera.rotation.copy(this.node.rotation);
this.camera.updateMatrixWorld(true);
this._updateFrustum();
}
setPosition() {
this.camera.position.set(this.position[0], this.position[1], this.position[2]);
this.camera.updateMatrixWorld(true);
this._updateFrustum();
}
_updateFrustum() {
if (this.camera) {
this._projScreenMatrix.multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse);
this._frustum.setFromMatrix(this._projScreenMatrix);
}
}
intersectsObject(object) {
this._updateFrustum();
return this._frustum.intersectsObject(object);
}
intersectsBox(box) {
this._updateFrustum();
return this._frustum.intersectsBox(box);
}
intersectsSphere(sphere) {
this._updateFrustum();
return this._frustum.intersectsSphere(sphere);
}
intersectsSprite(sprite) {
this._updateFrustum();
return this._frustum.intersectsSprite(sprite);
}
}
THING.factory.registerClass(‘SurveillanceCamera’, SurveillanceCamera);
第三步,鼠标悬浮事件和鼠标离开事件,这里我们使用了之前创建的 SurveillanceCamera 类为 obj 加上了一个“底座”。
// 鼠标悬浮事件 function onMouseOver(targetObj,viewPoint) {
if (currentModule != null)
return;
overModule = app.query(targetObj)[0];
overModule.style.boundingBox = true;
overModule.moveTo({
“offset”: [0, 6, 0],
“time”: 80,
});
sCamera = app.create({
type: ‘SurveillanceCamera’,
name: ‘SurveillanceCamera_’,
position:app.query(viewPoint)[0].position,
fov: 65,
aspect: 1.3,
far: 6,
});
sCamera.angleX = 90;
sCamera.style.opacity = 0.1;
}// 鼠标离开事件 function onMouseOut(targetObj) {
if (currentModule != null)
return;
if (sCamera) {
sCamera.destroy();
sCamera = null;
}
outModule = overModule;
outModule.style.boundingBox = false;
outModule.stopMoving();
outModule.position = [0, 0, 0];
outModule = null;
}
演示地址:EXAMPLE
总结
利用 iframe 与 ThingJS 进行交互完成了平面图导航功能,通过自制的 HTML 界面,嵌入 ThingJS 的面板中,形成一个可自定义的导航界面,通过偏移实现相应的视觉效果。
制作一个视锥,达到投放影像的效果,这里运用面向对象的方式是为了,能够更快捷的创建视锥,起到复用的作用。
在制作过程中,将物体悬浮的过程时出现了问题,发现如果快速的操作鼠标,物体不会达到预期的视觉效果,例如,鼠标快速的在两个导航图之间切换时,对应的两个物体会不断的上升,尽管将上升与还原的速度加快,也依然无法解决问题。最后解决的办法是:新添加一个变量,将上一次悬浮的物体记录下来,就是文中的 outModule,通过对 outModule 单独操作来解决影响问题。