之前我们实现的是:地图标签要显示自定义图标,并且鼠标移入地图后,弹窗显示地图区域的内容,今天我们在之前的基础上进行二次修改,我们不需要鼠标移入地图显示弹窗了,我们改为点击自定义图标显示弹窗。
threejs版本号
"three": "^0.154.0",
vue版本号
"vue": "^3.2.45",
效果截图
动态效果
在线演示地址
实现思路
我们来给css2d标签来绑定点击事件,创建一个弹窗,点击标签后,显示弹窗。
关键代码
点击标签显示弹窗,移动鼠标隐藏弹窗。
import {CSS2DRenderer, CSS2DObject} from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import mapIcon1 from '../assets/mapIcon1.png'
import mapIcon2 from '../assets/mapIcon2.png'
let tooltip = null; // 创建一个tooltip变量用来存储信息窗口
tooltip = document.createElement('div');
tooltip.style.position = 'absolute';
tooltip.style.padding = '10px';
tooltip.style.borderRadius = '4px';
tooltip.style.color = '#fff';
tooltip.style.background = 'rgba(0, 0, 0, 0)';
tooltip.style.display = 'none'; // 初始设为不可见
tooltip.style.pointerEvents = 'none'; // 阻止鼠标事件触发
tooltip.style.zIndex = '999'; // 设置一个较高的z-index以确保其在最顶层
document.body.appendChild(tooltip); // 将tooltip添加到body
// 创建一个HTML标签
const tag = (name, x, y, z) => {
const div = document.createElement('div');
Object.assign(div.style, {
position: 'absolute'
});
div.innerHTML = `<div class="tagInfo">
<div class="tagInfoIcon"><img src="${mapIcon1}" alt=""></div>
<div class="tagInfoName">${name}</div>
<div>`;
const label = new CSS2DObject(div); //div元素包装为CSS2模型对象CSS2DObject
// 设置HTML元素标签在three.js世界坐标中位置
label.position.set(x, y, z);
// 更新点击事件处理函数
div.addEventListener('click', (e) => {
// 设置 tooltip 的内容为标签的名字
// tooltip.innerHTML = name;
console.log(e)
tooltip.innerHTML = `<div class="popWin">
<div class="popWins">
<div class="titleInfos">
<p class="cityName">${name}办案中心</p>
</div>
<div class="popWins2">
<div class="listItem">
<div class="icon"></div>
<div class="listItemr">
<p>子机构名称1</p>
<span>地址:宜阳县中心大街111号</span>
</div>
</div>
<div class="listItem">
<div class="icon"></div>
<div class="listItemr">
<p>子机构名称1</p>
<span>地址:宜阳县中心大街111号</span>
</div>
</div>
<div class="listItem">
<div class="icon"></div>
<div class="listItemr">
<p>子机构名称1</p>
<span>地址:宜阳县中心大街111号</span>
</div>
</div>
</div>
</div>
</div>`;
tooltip.style.display = 'block'; // 设置信息窗口为可见
// 设置 tooltip 的位置与被点击元素的位置相同
tooltip.style.left = `${e.pageX}px`;
tooltip.style.top = `${e.pageY}px`;
// 将 tooltip 显示出来
tooltip.style.display = 'block';
});
div.addEventListener('mouseleave', () => {
// 隐藏 tooltip
tooltip.style.display = 'none';
});
return label; //返回CSS2模型标签
};
// 创建一个CSS2渲染器CSS2DRenderer
const labelRenderer = (width, height) => {
const renderer = new CSS2DRenderer();
renderer.setSize(width, height);
Object.assign(renderer.domElement.style, {
position: 'absolute',
top: '0px',
left: '0px',
pointerEvents: 'none' // 避免模型标签HTML元素遮挡鼠标选择场景模型
});
return renderer;
};
export {tag, labelRenderer};
获取坐标
我们在实现从远到近的动画的时候,需要两个坐标,一个远坐标一个近坐标,组合起来实现我们的从远到近的动画,那么我们如何获取这两个坐标呢?
// 定义动画开始和结束时相机的位置和控制器的目标
const cameraStartPosition = {x: 112.20929449299491, y: 5.19241909563627, z: 13.291026054316227};
const cameraEndPosition = {x: 112.14357995282774, y: 31.705195961754452, z: 1.7322278452088524};
const controlsTargetStart = {x: center.x, y: center.y, z: 0};
const controlsTargetEnd = {x: center.x, y: center.y, z: 0};
首先调试相机位置
我们在render方法中添加一段代码用来获取当前相机的位置console.log(camera.position)
,然后
const render = () => {
renderer.render(scene, camera);
labelRenderers.render(scene, camera);
console.log(camera.position)
requestAnimationFrame(render);
}
render();
这时候我们在开发工具里就可以看到当前相机的坐标信息了。
然后我们通过鼠标调整地图的位置和大小来得到我们满意的角度,再回到调试工具里将相机坐标复制出来替换掉我们上面的相机坐标就可以实现我们想要的动画角度了。
完整实例代码
代码环境 vue3 + vite + js + nodejs 14