three.js实现3D地图

地图下钻是前端开发中常见的开发需求 。通常会使用高德、百度等第三方地图实现 , 不过这些都不是3d的 。echarts倒是提供了map3D , 以及常用的点位、飞线等功能 , 就是有一些小bug[泪奔] , 而且如果领导比较可爱 , 提一些奇奇怪怪的需求 , 可能就不好搞了……
这篇文章我会用three.js实现一个geojson下钻地图 。

three.js实现3D地图

文章插图
地图预览
一、搭建环境
我这里用parcel搭建一个简易的开发环境 , 安装依赖如下:
{ "name": "three", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "parcel src/index.html", "build": "parcel build src/index.html" }, "author": "", "license": "ISC", "devDependencies": { "parcel-bundler": "^1.12.5" }, "dependencies": { "d3": "^7.6.1", "d3-geo": "^3.0.1", "three": "^0.142.0" } }二、创建场景、相机、渲染器以及地图import * as THREE from 'three' class Map3D { constructor() { this.scene = undefined // 场景 this.camera = undefined // 相机 this.renderer = undefined // 渲染器 this.init() } init() { // 创建场景 this.scene = new THREE.Scene() // 创建相机 this.setCamera() // 创建渲染器 this.setRender() // 渲染函数 this.render() } /** * 创建相机 */ setCamera() { // PerspectiveCamera(角度 , 长宽比 , 近端面 , 远端面) —— 透视相机 this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) // 设置相机位置 this.camera.position.set(0, 0, 120) // 把相机添加到场景中 this.scene.add(this.camera) } /** * 创建渲染器 */ setRender() { this.renderer = new THREE.WebGLRenderer() // 渲染器尺寸 this.renderer.setSize(window.innerWidth, window.innerHeight) //设置背景颜色 this.renderer.setClearColor(0x000000) // 将渲染器追加到dom中 document.body.AppendChild(this.renderer.domElement) } render() { this.renderer.render(this.scene, this.camera) requestAnimationFrame(this.render.bind(this)) } } const map = new Map3D()
场景、相机、渲染器是threejs中必不可少的要素 。以上代码运行起来后可以看到屏幕一片黑 , 审查元素是一个canvas占据了窗口 。
three.js实现3D地图

文章插图
啥也没有
接下来需要geojson数据了,阿里的datav免费提供区级以上的数据:https://datav.aliyun.com/portal/school/atlas/area_selector
class Map3D { // 省略代码 // 以下为新增代码 init() { ...... this.loadData() } getGeoJson (adcode = '100000') { return fetch(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`) .then(res => res.json()) } async loadData(adcode) { this.geojson = await this.getGeoJson(adcode) console.log(this.geojson) } } const map = new Map3D()
得到的json大概是下图这样的数据格式:
three.js实现3D地图

文章插图
geojson
然后 , 我们初始化一个地图 当然 , 咱们拿到的json数据中的所有坐标都是经纬度坐标 , 是不能直接在我们的threejs项目中使用的 。需要 “墨卡托投影转换”把经纬度转换成画布中的坐标 。在这里 , 我们使用现成的工具——d3中的墨卡托投影转换工具
import * as d3 from 'd3-geo' class Map3D { ...... async loadData(adcode) { // 获取geojson数据 this.geojson = await this.getGeoJson(adcode) // 墨卡托投影转换 。将中心点设置成经纬度为 104.0, 37.5 的地点 , 且不平移 this.projection = d3 .geoMercator() .center([104.0, 37.5]) .translate([0, 0]) } }
接着就可以创建地图了 。
创建地图的思路:以中国地图为例 , 创建一个Object3D对象 , 作为整个中国地图 。再创建N个Object3D子对象 , 每个子对象都是一个省份 , 再将这些子对象add到中国地图这个父Object3D对象上 。
three.js实现3D地图


推荐阅读