数据可视化大屏项目开发工程中,对效果追求越来越高,之前我们实现的是:threejs 3d地图通过gsap实现从远到近的入场动画,今天要实现的效果是:地图标签要显示自定义图标,并且鼠标移入地图后,弹窗显示地图区域的内容。
threejs版本号
"three": "^0.154.0",
vue版本号
"vue": "^3.2.45",
效果截图
动态效果
在线演示地址
threejs 3d地图添加自定义图片标签鼠标移入地图弹窗跟随
实现思路
通过射线拾取获取地图信息,并创建div,鼠标移入后显示div,鼠标移出后,隐藏div
关键代码
创建一个div
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
射线拾取处理
我们监听鼠标移入事件,然后显示弹窗信息,鼠标移出地图后,隐藏div,地图中的自定义信息我们可以通过创建地图时传入,也可以根据当前地图的地名去查询数据渲染。
var highlightedMaterial = new THREE.MeshBasicMaterial({color: 0xffff00}); // 高亮材质,颜色设置为黄色
var selectedObject = {mesh: null, originalMaterial: null}; // 存储选中的网格和它的原始材质
function choose(event) {
var Sx = event.clientX;
var Sy = event.clientY;
var x = (Sx / window.innerWidth) * 2 - 1;
var y = -(Sy / window.innerHeight) * 2 + 1;
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
var intersects = raycaster.intersectObjects(meshGroup.children);
if (selectedObject.mesh) { // 如果已经选中了一个网格
selectedObject.mesh.material = selectedObject.originalMaterial; // 恢复原始材质
selectedObject.mesh = null; // 清空存储的网格
}
if (intersects.length > 0) { // 如果鼠标悬停在一个网格上
selectedObject.mesh = intersects[0].object;
selectedObject.originalMaterial = selectedObject.mesh.material; // 存储原始材质
selectedObject.mesh.material = highlightedMaterial; // 应用高亮材质
console.log(selectedObject.mesh)
tooltip.innerHTML = `<div class="popWin">
<div class="popWins">
<div class="titleInfos">
<p class="cityName">${selectedObject.mesh.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.style.left = `${event.clientX}px`; // 设置信息窗口的位置
tooltip.style.top = `${event.clientY}px`;
} else {
tooltip.style.display = 'none'; // 设置信息窗口为可见
}
}
addEventListener('mousemove', choose); // 监听窗口鼠标滑动事件
完整实例代码
代码环境 vue3 + vite + js + nodejs 14