threejs 鼠标移入地图显示标签信息 学习笔记

threejs yekong

threejs实现地图,并在鼠标移入地图后显示标签信息,这和echarts的tooltip很相似。
threejs 鼠标移入地图显示标签信息

鼠标移入地图显示标签信息实例

鼠标移入地图显示标签信息

标签代码

import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
// 创建一个HTML标签
function tag() {
  // 创建div元素(作为标签)
  var div = document.createElement('div');
  div.style.visibility = 'hidden';
  div.innerHTML = 'GDP:'+0;
  div.style.padding = '5px 10px';
  div.style.color = '#fff';
  div.style.fontSize = '16px';
  div.style.position = 'absolute';
  div.style.backgroundColor = 'rgba(25,25,25,0.5)';
  div.style.borderRadius = '5px';
  //div元素包装为CSS2模型对象CSS2DObject
  var label = new CSS2DObject(div);
  div.style.pointerEvents = 'none';//避免HTML标签遮挡三维场景的鼠标事件
  // 设置HTML元素标签在three.js世界坐标中位置
  // label.position.set(x, y, z);
  return label;//返回CSS2模型标签
}

// 创建一个CSS2渲染器CSS2DRenderer
var labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
// // 避免renderer.domElement影响HTMl标签定位,设置top为0px
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.left = '0px';
// //设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement);

export {tag,labelRenderer}

加载地图

loader.load(modelUrl + 'json/gdp.json', function (data2) {
    var gdpObj = {};//每个省份的名字作为属性,属性值是国家对应GDP
    // GDP最高对应红色,GDP最低对应白色
    var color1 = new THREE.Color(0xffffff);
    var color2 = new THREE.Color(0xff0000);
    var gdpMax = 110000//设置一个基准值,以最高的广东gdp为准
    data2.arr.forEach(function (obj) {
        var gdp = obj.value;//当前省份GDP
        gdpObj[obj.name] = gdp;//每个省份的名字作为属性,属性值是国家对应GDP
    })
    //  加载./china.json,结构和world.json 一样,省份对应国家
    loader.load(modelUrl + 'json/china.json', function (data) {
        // 访问所有省份边界坐标数据:data.features
        data.features.forEach(function (area) {
            // "Polygon":省份area有一个封闭轮廓
            //"MultiPolygon":省份area有多个封闭轮廓
            if (area.geometry.type === "Polygon") {
                // 把"Polygon"和"MultiPolygon"的geometry.coordinates数据结构处理为一致
                area.geometry.coordinates = [area.geometry.coordinates];
            }
            // 解析所有封闭轮廓边界坐标area.geometry.coordinates
            lineGroup.add(metesBounds(area.geometry.coordinates));//省份边界轮廓插入组对象mapGroup
            var mesh = shapeMesh(area.geometry.coordinates);
            mesh.name = area.properties.name;//设置mesh对应的省份名字
            meshGroup.add(mesh);//省份轮廓Mesh插入组对象mapGroup
            // 颜色插值计算
            var color = color1.clone().lerp(color2.clone(), gdpObj[mesh.name] / gdpMax);
            // console.log(gdp / gdpMax)
            mesh.material.color.copy(color);

            var gdp = gdpObj[mesh.name];
            mesh.gdp = gdp;//mesh自定义一个gdp属性,用于标签设置
            mesh.经纬度 = area.properties.center;//用于控制标签位置
            mesh.color = color;//记录下自身的颜色,以便选中改变mesh颜色的时候,不选中状态再改变回来
        });
    })
})

射线拾取获取地图信息

射线拾取获取地图数据

/**
 * 射线投射器`Raycaster`的射线拾取选中网格模型对象函数choose()
 * 选中的网格模型变色
 */
var label = tag();
scene.add(label);//标签插入场景中
console.log(label);
var chooseMesh = null;//标记鼠标拾取到的mesh
function choose(event) {
    if (chooseMesh) {
        // 把上次选中的mesh设置为原来的颜色
        chooseMesh.material.color.copy(chooseMesh.color);
    } else {
        label.element.style.visibility = 'hidden';//没有选中mesh,隐藏标签
    }
    var Sx = event.clientX; //鼠标单击位置横坐标
    var Sy = event.clientY; //鼠标单击位置纵坐标
    //屏幕坐标转WebGL标准设备坐标
    var x = (Sx / window.innerWidth) * 2 - 1; //WebGL标准设备横坐标
    var y = -(Sy / window.innerHeight) * 2 + 1; //WebGL标准设备纵坐标
    //创建一个射线投射器`Raycaster`
    var raycaster = new THREE.Raycaster();
    //通过鼠标单击位置标准设备坐标和相机参数计算射线投射器`Raycaster`的射线属性.ray
    raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
    //返回.intersectObjects()参数中射线选中的网格模型对象
    // 未选中对象返回空数组[],选中一个数组1个元素,选中两个数组两个元素
    var intersects = raycaster.intersectObjects(meshGroup.children);
    // console.log("射线器返回的对象", intersects);
    // console.log("射线投射器返回的对象 点point", intersects[0].point);
    // console.log("射线投射器的对象 几何体",intersects[0].object.geometry.vertices)
    // intersects.length大于0说明,说明选中了模型
    if (intersects.length > 0) {
        chooseMesh = intersects[0].object;
        chooseMesh.material.color.set(0x00ffff);//选中改变颜色
        label.position.set(chooseMesh.经纬度[0], chooseMesh.经纬度[1], 0);
        label.element.innerHTML = chooseMesh.name + 'GDP:' + chooseMesh.gdp + '亿元';
        label.element.style.visibility = 'visible';
    } else {
        chooseMesh = null;
    }
}
// addEventListener('click', choose); // 监听窗口鼠标单击事件
addEventListener('mousemove', choose); // 监听窗口鼠标滑动事件

渲染

将label标签渲染进去

// 渲染函数
function render() {
    labelRenderer.render(scene, camera);
    renderer.render(scene, camera); //执行渲染操作
    requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}

render();

最终实现效果

webGL 3D地图可视化实例

教程地址

WebGL/Three.js前端3D可视化

喜欢