一、绘制多边形
1. 多边形
- 数据结构json5
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 107.6220703125, 34.939985151560435 ], [ 110.2862548828125, 34.939985151560435 ], [ 110.2862548828125, 36.491973470593685 ], [ 107.6220703125, 36.491973470593685 ], [ 107.6220703125, 34.939985151560435 ] ] ] } } ] }
- 在
geojson.io
上显示
2. 使用axios
获取多边形geojson
数据
axios
插件安装shellyarn add axios -S
- 安装完成
package.json
json5{ "dependencies": { "axios": "^0.27.2", "three": "^0.140.2" } }
3. 使用d3
将地图的二维坐标,转换成空间坐标
d3
安装shellyarn add d3 -S
- 安装完成
package.json
json5{ "dependencies": { "axios": "^0.27.2", "d3": "^7.4.4", "three": "^0.140.2" } }
二、绘制多边形
1. extends
- 继承
ThreeBase
基础类,重写initObj
方法即可。 - 将经纬度坐标转成空间三维坐标js
/** * 将经纬度坐标转成三维空间坐标 * @param lnglat * @return {(*|number)[]} */ lnglatToVector(lnglat) { if (!this.#projection) { this.#projection = D3.geoMercator() .center([112.946332, 28.236672]) .scale(400) .translate([0,0]); } const [y, x] = this.#projection([...lnglat]); const z = 0; return [y, x, z]; }
- 绘制多边形核心代码js
/** * 根据空间坐标,绘制多边形 */ drawPolygon(points = []) { const shape = new Shape(); points.map((point, index) => { const [x, y] = point; if (index === 0) { shape.moveTo(x, y); } else if (index === points.length - 1) { // 二次曲线 shape.quadraticCurveTo(x, y, x, y) } else { shape.lineTo(x, y, x, y) } }) // bevelEnabled 是否启用斜角 const geometry = new ExtrudeGeometry( shape, { depth: -2, bevelEnabled: false } ) // 材质 const material = new MeshBasicMaterial({ color: "#007cff", transparent: true, opacity: 0.5 }); // 合并 const mesh = new Mesh(geometry, material); return mesh; }
2. 完整示例
代码示例
jsimport ThreeBase from "./ThreeBase"; import * as D3 from 'd3'; import axios from "axios"; import { Group, Shape, ExtrudeGeometry, MeshBasicMaterial, Mesh } from 'three'; /** * 绘制多边形 */ export default class ThreePolygonMap extends ThreeBase { #projection; #mapData; #vector3Json = []; constructor() { super(); } /** * 重写 ThreeBase 中的 initObj 方法实现 */ initObj() { this.initMapData().then(() => { this.initPolygon() }) } /** * 获取地图数据 * @return {Promise<AxiosResponse<any>>} */ initMapData() { return axios.get('geojson/polygon.json').then(res => { this.#mapData = res.data; }) } /** * 处理需要渲染多边形的经纬度数据 */ initPolygon() { this.#mapData?.features?.map(item => { const areas = item.geometry.coordinates; const areaVector = { coordinates: [] }; areas.map(area => { area.map(point => { areaVector.coordinates.push(this.lnglatToVector(point)) }) this.#vector3Json.push(areaVector) }) }) // 绘制模块 const group = new Group(); this.#vector3Json.map(vector => { const mesh = this.drawPolygon(vector.coordinates); group.add(mesh); }) this.scene.add(group); } /** * 根据空间坐标,绘制多边形 */ drawPolygon(points= []) { const shape = new Shape(); points.map((point, index) => { const [x, y] = point; // if (index === 0) { // shape.moveTo(x, y) // } // shape.lineTo(x, y) if (index === 0) { shape.moveTo(x, y); } else if (index === points.length - 1) { // 二次曲线 shape.quadraticCurveTo(x, y, x, y) } else { shape.lineTo(x, y, x, y) } }) // bevelEnabled 是否启用斜角 const geometry = new ExtrudeGeometry( shape, { depth: -2, bevelEnabled: false } ) // 材质 const material = new MeshBasicMaterial({ color: "#007cff", transparent: true, opacity: 0.5 }); // 合并 const mesh = new Mesh(geometry, material); return mesh; } /** * 将经纬度坐标转成三维空间坐标 * @param lnglat * @return {(*|number)[]} */ lnglatToVector(lnglat) { if (!this.#projection) { this.#projection = D3.geoMercator() .center([112.946332, 28.236672]) .scale(400) .translate([0,0]); } const [y, x] = this.#projection([...lnglat]); const z = 0; return [y, x, z]; } }
效果