Skip to content

一、绘制多边形

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 上显示 polygon.png

2. 使用axios获取多边形geojson数据

  • axios插件安装
    shell
    yarn add axios -S
  • 安装完成package.json
    json5
    {
      "dependencies": {
        "axios": "^0.27.2",
        "three": "^0.140.2"
      }
    }

3. 使用d3将地图的二维坐标,转换成空间坐标

  • d3安装
    shell
    yarn 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. 完整示例

  • 代码示例

    js
    import 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];
      }
    }
  • 效果

    polygon-map.png

Released under the MIT License.