在Three.js中绘制中国地图,通常有两种方法:一种是使用Three.js直接根据地理坐标绘制,另一种是结合其他库(如Echarts)来实现。以下是基于Three.js直接绘制中国地图的基本步骤:
- 获取地图数据:首先,你需要获取中国地图的地理坐标数据。这些数据通常以GeoJSON格式提供,包含了中国各省市边界的经纬度信息。
- 转换坐标:由于GeoJSON中的坐标是经纬度格式,而Three.js使用的是笛卡尔坐标系,因此需要将经纬度转换为Three.js可以使用的坐标。
- 绘制地图:使用转换后的坐标在Three.js中绘制地图。这可以通过创建多边形几何体(
THREE.ShapeGeometry
)来实现,每个省份可以是一个多边形几何体。 - 添加细节:为了提高地图的可视化效果,可以添加光照、材质和阴影等细节。
three和vue版本
"three": "^0.154.0",
"vue": "^3.2.45",
实例代码
<script>
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
import data from './data/data.json';
import {borderLine} from './js/line.js';
import {getBoxCenter, getBoxSize} from './js/centerCamera.js';
import {ExtrudeMesh} from './js/ExtrudeMesh.js';
import {createLights} from './js/lights.js';
import {destroyMap} from './js/destroyMap.js';
let mapHeight = 1;
let TensileHeight = 3;
let mapGroup = null;
let lineGroup = null;
let meshGroup = null;
let renderer = null;
let scene = null;
let camera = null;
let resizeObserver = null;
export default {
name: 'map3D',
data() {
return {};
},
mounted() {
this.initScene();
this.drawMap();
this.handleResize();
const viewElem = document.body;
this.resizeObserver = new ResizeObserver(() => {
setTimeout(() => {
this.handleResize();
}, 300);
});
this.resizeObserver.observe(viewElem);
},
beforeDestroy() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
destroyMap(scene, renderer);
},
methods: {
handleResize() {
const width = this.$refs.map3DMain.offsetWidth;
const height = this.$refs.map3DMain.offsetHeight;
if (renderer) {
renderer.setSize(width, height);
}
},
initScene() {
scene = new THREE.Scene();
mapGroup = new THREE.Group();
lineGroup = new THREE.Group();
meshGroup = new THREE.Group();
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
// 其他初始化代码保持不变
},
drawMap() {
const width = this.$refs.map3DMain.offsetWidth; // 使用 this.$refs 来访问 ref
const height = this.$refs.map3DMain.offsetHeight;
// 使用 this 来引用 data 中的属性
const lights = createLights();
scene.add(lights.directionalLight);
scene.add(lights.directionalLight2);
scene.add(lights.ambient);
scene.add(mapGroup);
mapGroup.add(lineGroup);
mapGroup.add(meshGroup);
data.features.forEach((area) => {
if (area.geometry.type === 'Polygon') {
area.geometry.coordinates = [area.geometry.coordinates];
}
lineGroup.add(borderLine(area.geometry.coordinates));
const mesh = ExtrudeMesh(area.geometry.coordinates, TensileHeight);
meshGroup.add(mesh);
});
const lineGroup2 = lineGroup.clone();
mapGroup.add(lineGroup2);
lineGroup2.position.z = TensileHeight + TensileHeight * 0.001;
const k = width / height;
let s = (getBoxSize(mapGroup).x + getBoxSize(mapGroup).y) / 4;
camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(104, -105, 200);
camera.lookAt(scene.position);
renderer.setClearColor(0x000000, 0);
renderer.setSize(width, height);
const render = () => {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
const controls = new OrbitControls(camera, renderer.domElement);
const getBoxCenterData = getBoxCenter(mapGroup);
controls.target.set(getBoxCenterData.x, getBoxCenterData.y, 0);
controls.update();
this.$refs.map3DMain.appendChild(renderer.domElement);
}
},
};
</script>
演示地址
完整实例代码
代码环境 vue3 + vite + js + nodejs 16
vue3框架vue2写法