three.js实现3D地图( 三 )


// 引入构造器 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' init() { this.setControls() } setControls() { this.controls = new OrbitControls(this.camera, this.renderer.domElement) // 太灵活了 , 来个阻尼 this.controls.enableDamping = true; this.controls.dampingFactor = 0.1; }

three.js实现3D地图

文章插图
controls
好了 , 现在就可以想看哪儿就看哪儿了 。
三、当鼠标移入地图时让对应的地区高亮
Raycaster —— 光线投射Raycaster
文档链接:https://threejs.org/docs/index.html?q=Raycaster#api/zh/core/Raycaster
Raycaster用于进行raycasting(光线投射) 。光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体) 。
这个类有两个方法 , 
第一个setFromCamera(coords, camera)方法 , 它接收两个参数:
coords —— 在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间 。
camera —— 射线所来源的摄像机 。
通过这个方法可以更新射线 。
第二个intersectObjects: 检测所有在射线与这些物体之间 , 包括或不包括后代的相交部分 。返回结果时 , 相交部分将按距离进行排序 , 最近的位于第一个) 。
我们可以通过监听鼠标事件 , 实时更新鼠标的坐标 , 同时实时在渲染函数中更新射线 , 然后通过intersectObjects方法查找当前鼠标移过的物体 。
// 以下是新添加的代码 init() { // 创建场景 this.scene = new THREE.Scene() // 创建相机 this.setCamera() // 创建渲染器 this.setRender() // 创建控制器 this.setControls() // 光线投射 this.setRaycaster() // 加载数据 this.loadData() // 渲染函数 this.render() } setRaycaster() { this.raycaster = new THREE.Raycaster(); this.mouse = new THREE.Vector2(); const onMouse = (event) => { // 将鼠标位置归一化为设备坐标 。x 和 y 方向的取值范围是 (-1 to +1) // threejs的三维坐标系是中间为原点 , 鼠标事件的获得的坐标是左上角为原点 。因此需要在这里转换 this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1 this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1 }; window.addEventListener("mousemove", onMouse, false); } render() { this.raycaster.setFromCamera(this.mouse, this.camera) const intersects = this.raycaster.intersectObjects( this.scene.children, true ) // 如果this.lastPick存在 , 将材质颜色还原 if (this.lastPick) { this.lastPick.object.material[0].color.set(MATERIAL_COLOR1); this.lastPick.object.material[1].color.set(MATERIAL_COLOR2); } // 置空 this.lastPick = null; // 查询当前鼠标移动所产生的射线与物体的焦点 // 有两个material的就是我们要找的对象 this.lastPick = intersects.find( (item) => item.object.material && item.object.material.length === 2 ); // 找到后把颜色换成一个鲜艳的绿色 if (this.lastPick) { this.lastPick.object.material[0].color.set("aquamarine"); this.lastPick.object.material[1].color.set("aquamarine"); } this.renderer.render(this.scene, this.camera) requestAnimationFrame(this.render.bind(this)) }
three.js实现3D地图

文章插图
高亮
四、还差一个tooltip
引入 css2DRenderer 和 CSS2DObject , 创建一个2D渲染器 , 用2D渲染器生成一个tooltip 。在此之前 , 需要在 loadData方法创建area时把地区属性添加到Mesh对象上 。确保lastPick对象上能取到地域名称 。
// 把地区属性存到area对象中 area.properties = elem.properties
three.js实现3D地图

文章插图
把地区属性存到Mash对象中
【three.js实现3D地图】// 引入CSS2DObject, CSS2DRenderer import { CSS2DObject, CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer' class Map3D { setRender() { ...... // CSS2DRenderer 创建的是html的div元素 // 这里将div设置成绝对定位 , 盖住canvas画布 this.css2dRenderer = new CSS2DRenderer(); this.css2dRenderer.setSize(window.innerWidth, window.innerHeight); this.css2dRenderer.domElement.style.position = "absolute"; this.css2dRenderer.domElement.style.top = "0px"; this.css2dRenderer.domElement.style.pointerEvents = "none"; document.body.appendChild(this.css2dRenderer.domElement); } render() { // 省略...... this.showTip() this.css2dRenderer.render(this.scene, this.camera) // 省略 ...... } showTip () { if (!this.dom) { this.dom = document.createElement("div"); this.tip = new CSS2DObject(this.dom); } if (this.lastPick) { const { x, y, z } = this.lastPick.point; const properties = this.lastPick.object.parent.properties; // label的样式在直接用css写在样式表中 this.dom.className = "label"; this.dom.innerText = properties.name this.tip.position.set(x + 10, y + 10, z); this.map && this.map.add(this.tip); } } }


推荐阅读