7. 鼠标选中模型弹出标签(工厂)
# 鼠标选中模型弹出标签(工厂案例)
射线、标签等知识点都学习过,你可以把本节课作为练习题,实现鼠标点击模型,弹出标签的功能。
# 添加HTML元素标签,并隐藏
引入标签的HTML、CSS代码,在射线拾取模型对象之前注意先隐藏display: none;
。
<div id="tag" style="display: none;">
# HTML元素转化为CSS2模型对象
// 引入CSS2模型对象CSS2DObject
import {
CSS2DObject
} from 'three/addons/renderers/CSS2DRenderer.js';
const div = document.getElementById('tag');
div.style.top = '-161px'; //指示线端点和标注点重合
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);
export default tag;
# 设置CSS2渲染器代码
// 引入CSS2渲染器CSS2DRenderer
import {CSS2DRenderer} from 'three/addons/renderers/CSS2DRenderer.js';
// 创建一个CSS2渲染器CSS2DRenderer
const css2Renderer = new CSS2DRenderer();
css2Renderer.setSize(width, height);
// HTML标签<div id="tag"></div>外面父元素叠加到canvas画布上且重合
css2Renderer.domElement.style.position = 'absolute';
css2Renderer.domElement.style.top = '0px';
//设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
css2Renderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(css2Renderer.domElement);
// 渲染循环
function render() {
css2Renderer.render(scene, camera);
// ...
requestAnimationFrame(render);
}
# 在射线代码基础上,添加标签代码
当发生鼠标事件,如果射线拾取到模型对象,就把标签做为选中模型的子对象,或作为选中模型对应标注点空对象的子对象。
前面说过,如果你想标注工厂中模型,CSS2模型对象有两种定位方式,下面两种定位模型位置方法任选其一即可。
需要标注的模型,把局部坐标系坐标原点设置在需要标注的位置
if (intersects.length > 0) {
// 通过.ancestors属性判断那个模型对象被选中了
outlinePass.selectedObjects = [intersects[0].object.ancestors];
//tag会标注在intersects[0].object.ancestors模型的局部坐标系原点位置
intersects[0].object.ancestors.add(tag);
}
工厂模型添加一个空对象,用来标记需要标注的位置。
标注点对应空对象命名规则和代码规则息息相关,模型中两个设备的名字是设备A、设备B,对应的标注点空对象命名分别为设备A标注、设备B标注。
if (intersects.length > 0) {
// 通过.ancestors属性判断那个模型对象被选中了
outlinePass.selectedObjects = [intersects[0].object.ancestors];
// 获取模型对象对应的标注点
// console.log('intersects[0].object.ancestors.name',intersects[0].object.ancestors.name);
const obj = model.getObjectByName(intersects[0].object.ancestors.name+'标注');
//tag会标注在空对象obj对应的位置
obj.add(tag);
}
# 没有选中模型,不显示标签和发光描边
在射线鼠标事件函数外面声明一个变量chooseObj来表示,此时是否有模型处于选中状态,如果没有,就把标签和发光描边取消。
let chooseObj = null;
addEventListener('click', function (event) {
// ...射线拾取的代码
// 射线交叉计算拾取模型
const intersects = raycaster.intersectObjects(cunchu.children);
if (intersects.length > 0) {
// 通过.ancestors属性判断那个模型对象被选中了
outlinePass.selectedObjects = [intersects[0].object.ancestors];
//tag会标注在intersects[0].object.ancestors模型的局部坐标系原点位置
intersects[0].object.ancestors.add(tag);
chooseObj = intersects[0].object.ancestors;
}else{
if(chooseObj){//把原来选中模型对应的标签和发光描边隐藏
outlinePass.selectedObjects = [];//无发光描边
chooseObj.remove(tag);//从场景移除
}
}
})
# 修改标签内容
可以根据选中的设备设置对应的标签内容数据,下面只是以设备名称为例进行演示,其它的标签数据,也可以类似修改。
<span id="name">设备A</span>
// 获取设备名称标签
const span = document.getElementById('name');
addEventListener('click', function (event) {
// ...
// ...
// 射线交叉计算拾取模型
const intersects = raycaster.intersectObjects(cunchu.children);
if (intersects.length > 0) {
span.innerHTML = intersects[0].object.ancestors.name;//修改标签数据
}
})