下面给你一份基于 Three.js + GeoJSON 实现三维地图显示的完整示例思路和示范代码,帮你快速入门三维地图可视化开发。
Three.js + GeoJSON 实现三维地图三维显示
核心思路
- 加载 GeoJSON
GeoJSON 是一种存储地理数据的 JSON 格式,包含区域的经纬度坐标。 - 经纬度坐标投影转换
地理坐标是经纬度,Three.js 需要用笛卡尔坐标系,通常用墨卡托投影或简单转换将经纬度转为 X, Y 平面坐标。 - 创建二维地图轮廓 (Shape)
使用 Three.js 的THREE.Shape
将每个区域的边界坐标连接成二维路径。 - 拉伸生成三维几何体
通过THREE.ExtrudeGeometry
给二维区域形状加高度,形成立体地图块。 - 添加材质和灯光
让三维地图更有视觉效果。 - 添加交互控制
利用OrbitControls
实现鼠标旋转缩放。
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Three.js + GeoJSON 三维地图</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.157.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.157.0/examples/js/controls/OrbitControls.js"></script>
<script>
let scene, camera, renderer, controls;
init();
loadGeoJSON();
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(0, -200, 200);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 50;
controls.maxDistance = 500;
// 光源
const ambientLight = new THREE.AmbientLight(0x888888);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(100, 100, 200);
scene.add(directionalLight);
window.addEventListener('resize', onWindowResize, false);
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
// 经纬度转墨卡托平面坐标,适当缩放
function lngLatToXY(lng, lat) {
const x = lng * 20037508.34 / 180;
let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
y = y * 20037508.34 / 180;
return [x / 100000, y / 100000]; // 缩放比例调整
}
function loadGeoJSON() {
fetch('china_provinces.geojson') // 请替换成你的GeoJSON文件路径
.then(res => res.json())
.then(data => {
data.features.forEach(feature => {
const coords = feature.geometry.coordinates;
const geomType = feature.geometry.type;
if (geomType === 'MultiPolygon') {
coords.forEach(polygon => {
polygon.forEach(ring => {
addShape(ring);
});
});
} else if (geomType === 'Polygon') {
coords.forEach(ring => {
addShape(ring);
});
}
});
})
.catch(err => {
console.error('加载 GeoJSON 失败:', err);
});
}
function addShape(coordArray) {
const shape = new THREE.Shape();
coordArray.forEach((lnglat, i) => {
const [x, y] = lngLatToXY(lnglat[0], lnglat[1]);
if (i === 0) shape.moveTo(x, y);
else shape.lineTo(x, y);
});
// 拉伸高度,模拟三维效果
const extrudeSettings = { depth: 5, bevelEnabled: false };
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshPhongMaterial({
color: 0x66ccff,
transparent: true,
opacity: 0.7,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
}
</script>
</body>
</html>
说明
- 该示例使用了简单墨卡托投影进行坐标转换,适合展示区域范围地图。
china_provinces.geojson
是中国省级边界的 GeoJSON 文件,可以在网上公开数据源下载。- 地图高度固定为5单位,也可以根据数据(如人口、GDP)动态调整,实现数据可视化。
- 使用了
OrbitControls
实现旋转、缩放操作,方便观察地图。 - 材质设置为半透明蓝色,可以根据需要调整颜色、光照效果。
你可以扩展的方向
- 加载城市、道路、河流等不同类型的 GeoJSON 数据叠加显示
- 结合热力图、飞线动画、点聚合等效果
- 动态更新地图区域高度,实现数据变化实时反映
- 加载真实建筑模型(GLTF)与地理坐标对齐
- 性能优化:合并几何体、减少多边形点数、使用 BufferGeometry 等
发表回复