容器缩放导致三维模型鼠标事件坐标偏移问题

377 阅读1分钟

起因

最近在做一个数据大屏功能,要求显示中国地图,方法百度一搜一把,思路是: 通过 d3.js 的墨卡托投影工具 d3.geoMercator() 将中国地理位置 JSON 内的经纬度转换成二维坐标,再通过 three.js 渲染成三维模型。

问题

对模型设置光线投射 THREE.Raycaster() 实现鼠标事件时,鼠标拾取坐标与模型坐标间发生了偏移,表现为鼠标移动到北京实际上取到了河北的数据。

然而在页面全屏时,偏移现象消失。基本可以确定该问题是由于数据大屏自适应容器导致的。自适应原理为计算屏幕长宽比,通过 CSS 属性 transform:scale() 设置缩放使长边完全显示、短边正好显示。

解决方案

通过 DOM 方法 getBoundingClientRect() 获取三维模型在浏览器中的坐标,得出鼠标拾取坐标与模型坐标间的偏移量。鼠标相对模型坐标 = 鼠标拾取坐标 - 偏移量。

正常情况下 Raycaster 接受的鼠标坐标的二维向量取值是:

this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + ;

修正后:

const rect = this.renderer.domElement.getBoundingClientRect();
this.mouse.x = ((event.clientX - rect.left) / (rect.right - rect.left)) * 2 - 1;
this.mouse.y = -((event.clientY - rect.top) / (rect.bottom - rect.top)) * 2 + 1;