threejs生成3d中国地图
`import React, { useState, useEffect } from 'react'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import styles from './index.less'
import * as d3 from 'd3'
import china from './json/china.json'
export default function index() { let activeInstersect = []; // 设置为空 let provinceInfo = null const [container, setContainer] = useState(document.body) const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // 渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement);
// 场景
const scene = new THREE.Scene();
// 相机 透视相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, -70, 150);
camera.lookAt(0, 0, 0);
useEffect(() => {
provinceInfo = document.getElementById('provinceInfo');
setController(); // 设置控制
setLight(); // 设置灯光
setRaycaster();
animate();
initMap(china)
// this.loadFont(); // 加载字体
// loadMapData();
setResize(); // 绑定浏览器缩放事件
}, [])
const setResize = () => {
window.addEventListener('resize', function () {
renderer.setSize(window.innerWidth, window.innerHeight);
})
}
const initMap = (chinaJson) => {
// 建一个空对象存放对象
const map = new THREE.Object3D();
// 墨卡托投影转换
const projection = d3.geoMercator().center([104.0, 37.5]).scale(80).translate([0, 0]);
chinaJson.features.forEach(elem => {
// 定一个省份3D对象
const province = new THREE.Object3D();
// province.name = elem.name;
// 每个的 坐标 数组
const coordinates = elem.geometry.coordinates;
// 循环坐标数组
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
const shape = new THREE.Shape();
const lineMaterial = new THREE.LineBasicMaterial({
color: 'white'
});
const lineGeometry = new THREE.BufferGeometry()
const points = []
for (let i = 0; i < polygon.length; i++) {
const [x, y] = projection(polygon[i]);
if (i === 0) {
shape.moveTo(x, -y);
}
shape.lineTo(x, -y);
points.push(new THREE.Vector3(x, -y, 4.01))
}
lineGeometry.setFromPoints(points);
const extrudeSettings = {
depth: 4,
bevelEnabled: false
};
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshBasicMaterial({
color: '#02A1E2',
transparent: true,
opacity: 0.6
});
const material1 = new THREE.MeshBasicMaterial({
color: '#3480C4',
transparent: true,
opacity: 0.5
});
const mesh = new THREE.Mesh(geometry, [material, material1]);
// mesh.name = polygon.name
const line = new THREE.Line(lineGeometry, lineMaterial);
province.add(mesh);
province.add(line)
})
})
// 将geo的属性放到省份模型中
province.properties = elem.properties;
if (elem.properties.contorid) {
const [x, y] = projection(elem.properties.contorid);
province.properties._centroid = [x, y];
}
map.add(province);
})
scene.add(map);
}
const setRaycaster = () => {
const eventOffset = {};
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
eventOffset.x = event.clientX;
eventOffset.y = event.clientY;
provinceInfo.style.left = eventOffset.x + 2 + 'px';
provinceInfo.style.top = eventOffset.y + 2 + 'px';
}
window.addEventListener('mousemove', onMouseMove, false);
}
const setLight = () => {
let ambientLight = new THREE.AmbientLight(0xffffff); // 环境光
scene.add(ambientLight);
}
const setController = () => {
const controller = new OrbitControls(camera, renderer.domElement);
scene.add(controller);
/* this.controller.enablePan = false; // 禁止右键拖拽
this.controller.enableZoom = true; // false-禁止右键缩放
this.controller.maxDistance = 200; // 最大缩放 适用于 PerspectiveCamera
this.controller.minDistance = 50; // 最大缩放
this.controller.enableRotate = true; // false-禁止旋转 */
/* this.controller.minZoom = 0.5; // 最小缩放 适用于OrthographicCamera
this.controller.maxZoom = 2; // 最大缩放 */
}
const animate = () => {
requestAnimationFrame(animate);
raycaster.setFromCamera(mouse, camera);
//
var intersects = raycaster.intersectObjects(scene.children, true);
if (activeInstersect && activeInstersect.length > 0) { // 将上一次选中的恢复颜色
activeInstersect.forEach(element => {
element.object.material[0].color.set('#02A1E2');
element.object.material[1].color.set('#3480C4');
});
}
activeInstersect = []
for (var i = 0; i < intersects.length; i++) {
if (intersects[i].object.material && intersects[i].object.material.length === 2) {
activeInstersect.push(intersects[i]);
intersects[i].object.material[0].color.set(0xff0000);
intersects[i].object.material[1].color.set(0xff0000);
break; // 只取第一个
}
}
const createProvinceInfo = () => { // 显示省份的信息
if (activeInstersect.length !== 0 && activeInstersect[0].object.parent.properties.name) {
var properties = activeInstersect[0].object.parent.properties;
provinceInfo.textContent = properties.name;
provinceInfo.name = properties.name;
provinceInfo.style.visibility = 'visible';
} else {
provinceInfo.style.visibility = 'hidden';
}
}
createProvinceInfo(); //省份名字的显示隐藏
renderer.render(scene, camera);
}
return (
<div className={styles.provinceInfo} id='provinceInfo'>
</div>
)
}
`