文章插图
地图结构
创建地图后的完整代码:
import * as THREE from 'three' import * as d3 from 'd3-geo' const MATERIAL_COLOR1 = "#2887ee"; const MATERIAL_COLOR2 = "#2887d9"; class Map3D { constructor() { this.scene = undefined // 场景 this.camera = undefined // 相机 this.renderer = undefined // 渲染器 this.geojson = undefined // 地图json数据 this.init() } init() { // 创建场景 this.scene = new THREE.Scene() // 创建相机 this.setCamera() // 创建渲染器 this.setRender() // 渲染函数 this.render() // 加载数据 this.loadData() } /** * 创建相机 */ 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)) } getGeoJson (adcode = '100000') { return fetch(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}_full.json`) .then(res => res.json()) } async loadData(adcode) { // 获取geojson数据 this.geojson = await this.getGeoJson(adcode) // 创建墨卡托投影 this.projection = d3 .geoMercator() .center([104.0, 37.5]) .translate([0, 0]) // Object3D是Three.js中大部分对象的基类 , 提供了一系列的属性和方法来对三维空间中的物体进行操纵 。// 初始化一个地图 this.map = new THREE.Object3D(); this.geojson.features.forEach(elem => { const area = new THREE.Object3D() // 坐标系数组(为什么是数组 , 因为有地区不止一个几何体 , 比如河北被北京分开了 , 比如舟山群岛) const coordinates = elem.geometry.coordinates const type = elem.geometry.type // 定义一个画几何体的方法 const drawPolygon = (polygon) => { // Shape(形状) 。使用路径以及可选的孔洞来定义一个二维形状平面 。它可以和ExtrudeGeometry、ShapeGeometry一起使用 , 获取点 , 或者获取三角面 。const shape = new THREE.Shape() // 存放的点位 , 最后需要用THREE.Line将点位构成一条线 , 也就是地图上区域间的边界线 // 为什么两个数组 , 因为需要三维地图的两面都画线 , 且它们的z坐标不同 let points1 = []; let points2 = []; for (let i = 0; i < polygon.length; i++) { // 将经纬度通过墨卡托投影转换成threejs中的坐标 const [x, y] = this.projection(polygon[i]); // 画二维形状 if (i === 0) { shape.moveTo(x, -y); } shape.l.NETo(x, -y); points1.push(new THREE.Vector3(x, -y, 10)); points2.push(new THREE.Vector3(x, -y, 0)); } /** * ExtrudeGeometry (挤压缓冲几何体) * 文档链接:https://threejs.org/docs/index.html?q=ExtrudeGeometry#api/zh/geometries/ExtrudeGeometry */ const geometry = new THREE.ExtrudeGeometry(shape, { depth: 10, bevelEnabled: false, }); /** * 基础材质 */ // 正反两面的材质 const material1 = new THREE.MeshBasicMaterial({ color: MATERIAL_COLOR1, }); // 侧边材质 const material2 = new THREE.MeshBasicMaterial({ color: MATERIAL_COLOR2, }); // 生成一个几何物体(如果是中国地图 , 那么每一个mesh就是一个省份几何体) const mesh = new THREE.Mesh(geometry, [material1, material2]); area.add(mesh); /** * 画线 * link: https://threejs.org/docs/index.html?q=Line#api/zh/objects/Line */ const lineGeometry1 = new THREE.BufferGeometry().setFromPoints(points1); const lineGeometry2 = new THREE.BufferGeometry().setFromPoints(points2); const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff }); const line1 = new THREE.Line(lineGeometry1, lineMaterial); const line2 = new THREE.Line(lineGeometry2, lineMaterial); area.add(line1); area.add(line2); } // type可能是MultiPolygon 也可能是Polygon if (type === "MultiPolygon") { coordinates.forEach((multiPolygon) => { multiPolygon.forEach((polygon) => { drawPolygon(polygon); }); }); } else { coordinates.forEach((polygon) => { drawPolygon(polygon); }); } // 把区域添加到地图中 this.map.add(area); }) // 把地图添加到场景中 this.scene.add(this.map) } } const map = new Map3D()
文章插图
简单地图
这时 , 已经生成一个完整的地图 , 但是当我们试着去交互时还不能旋转 , 只需要添加一个控制器
推荐阅读
- 迟志强|迟志强近况!狱中立志,考政法大学,儿子替他实现狱中心愿
- 苹果戴口罩人脸识别系统可以识别吗? 苹果新版更新可实现戴口罩人脸识别嘛
- 远程控制通过什么实现 远程控制系统可以应用在哪些场合上
- 高德地图支持ar导航的行车记录仪 高德地图ar导航支持的记录仪
- Word表格中如何实现每一页都出现标题行?
- 朱一龙|飞升成功!朱一龙成85后首位金鸡影帝,实现影史留名愿望
- 李帝勋|李帝勋为南宫珉应援 休学入行演戏实现梦想 凭借建筑学概论走红
- 玉龙雪山位于云南哪里 玉龙雪山在云南哪里的地图
- 我国首次实现月球表面软着陆探测器 人类以及探测器登月
- 2012年玛雅预言最后一个为何没实现 玛雅2012预言不算失误