Skip to content

一、three.js地图-绘制多多边形

1. 多多边形

  • 数据结构
    json5
       {
        "type": "FeatureCollection",
        "features": [
          {
            "type": "Feature",
            "properties": {},
            "geometry": {
              "type": "MultiPolygon",
              "coordinates": [
                  [
                      [
                        [30.0, 20.0], [45.0, 40.0],
                        [10.0, 40.0], [30.0, 20.0]
                      ]
                  ], 
                  [
                      [
                        [15.0, 5.0], [40.0, 10.0],
                        [10.0, 20.0], [5.0, 10.0], 
                        [15.0, 5.0]
                      ]
                  ]
              ]
            }
          }
        ]
      }
    观察与多边形的genjson结构就会发现,多多边形coordinates节点下是多个数组
  • geojson.io 上显示 multi-polygon.png

2. 绘制多多边形

  • 多多边形绘制,根据其数据节点,需要改造的代码地方,地图数据解析 和 绘制模块

  • 地图数据解析 和 模块绘制

    js
      /**
     * 处理地图经纬度数据
     */
    initMultiplePoly()
    {
      this.#mapData?.features?.map(item => {
        const areas = item.geometry.coordinates;
        areas.map(area => {
          const areaVector = { coordinates: [] };
          area.map((point, index) => {
            if (Array.isArray(point[0])) {
              areaVector.coordinates[index] = [];
              point?.map(pointInner => {
                areaVector.coordinates[index].push(this.lnglatToVector(pointInner))
              })
            }
            this.#vector3Json.push(areaVector)
          })
        })
      })
      // 绘制模块
      const group = new Group();
      this.#vector3Json.map(vectors => {
        vectors.coordinates.map(vector => {
          const mesh = this.drawMultiPolyon(vector);
          group.add(mesh);
        })
      })
      this.scene.add(group);
    }

3. 完整示例

  • 代码示例

    js
    import ThreeBase from "./ThreeBase";
    import * as D3 from 'd3-geo';
    import axios from "axios";
    import { Group, Shape, ExtrudeGeometry, MeshBasicMaterial, Mesh } from 'three';
    
    /**
     * 绘制多多边形
     */
    export default class ThreeMultiplePolygonMap extends ThreeBase {
    
      #projection;
      #mapData;
      #vector3Json = [];
    
      constructor() {
        super();
    
      }
    
      initObj() {
        this.initMapData().then(() => {
          this.initMultiplePoly()
        })
      }
    
      initMapData() {
        return axios.get('geojson/multi-polygon.json').then(res => {
          this.#mapData = res.data;
        })
      }
    
      /**
       * 绘制网格
       */
      drawMultiPolyon(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;
      }
    
      /**
       * 处理地图经纬度数据
       */
      initMultiplePoly() {
        this.#mapData?.features?.map(item => {
          const areas = item.geometry.coordinates;
          areas.map(area => {
            const areaVector = { coordinates: [] };
            area.map((point, index) => {
              if (Array.isArray(point[0])) {
                areaVector.coordinates[index] = [];
                point?.map(pointInner => {
                  areaVector.coordinates[index].push(this.lnglatToVector(pointInner))
                })
              }
              this.#vector3Json.push(areaVector)
            })
          })
        })
        // 绘制模块
        const group = new Group();
        this.#vector3Json.map(vectors => {
          vectors.coordinates.map(vector => {
            const mesh = this.drawMultiPolyon(vector);
            group.add(mesh);
          })
        })
        this.scene.add(group);
      }
    
      lnglatToVector(lnglat) {
        if (!this.#projection) {
          this.#projection = D3.geoMercator()
            .center([112.946332, 28.236672])
            .scale(80)
            .translate([0,0]);
        }
        const [y, x] = this.#projection([...lnglat]);
        const z = 0;
        return [y, x, z];
      }
    }
  • 效果展示

    multi-polygon-map.png

Released under the MIT License.