Skip to content

绘制自定义图层

在这一节,我们将通过一个绘制自定义图层的实例了解一下引擎的自定义图层使用流程:

ts
import { Map } from "maplibre-gl";
import { ThreeGISMap } from "@jodvf/three-gis-map";
import * as maplibregl from "maplibre-gl";
import { CircleGeometry, Mesh, MeshBasicMaterial } from "three";

const container = document.createElement("div");
container.style.width = "100%";
container.style.height = "100%";
document.body.appendChild(container);

const map = new Map({
  container: container,
  style:
    "https://api.maptiler.com/maps/b01b290f-bdf7-452e-9a34-f6e300dacc4f/style.json?key=MNqni2pVxL0GkkL0hgYb", // stylesheet location
  maxPitch: 85,
  center: [104.07410531052449, 30.656418650992663],
  pitch: 50,
  zoom: 2.5
});

window.maplibregl = maplibregl;
const joGISThree = new ThreeGISMap(map, maplibregl, {
  projection: "EPSG:3857"
});

joGISThree.on("jogisthree.load", () => {
  addCirclePlan();
});

function addCirclePlan() {
  // custom
  joGISThree.addLayer({
    id: "custom_circle_plan",
    type: "custom",
    onAdd: function (map, gl) {
      this.options.initLayer(this, map, gl);
    },
    initLayer(layer, map, gl) {
      this.map = map;
      this.layer = layer;
      this.points = [];
      this.material = this.createMaterial();
    },
    onRender(gl, matrix) {
      this.options.layerAnimate();
    },
    layerAnimate() {
      if (!this.mesh) return;
      // @ts-ignore
      (this.mesh as Mesh).rotation.z += 0.01;
    },
    setData(geojson) {
      // let data = joGISThree.geojsonTrans.trans(geojson);
      this.processGeoJSON(geojson);
      this.createMesh();
    },
    createMaterial() {
      const material = new MeshBasicMaterial({
        map: joGISThree.loader.load("./images/bg_circle.png"),
        transparent: true,
        depthWrite: true,
        depthTest: true
        // side: DoubleSide,
      });

      return material;
    },
    createMesh() {
      // const radius = TileUtil.convertHeight(
      //   joGISThree.projection.code,
      //   4000000
      // );

      const geometry = new CircleGeometry(4000000, 32);
      const mesh = new Mesh(geometry, this.material);
      this.mesh = mesh;
      // mesh.renderOrder = 102;
      this.layer.addObject(mesh, this.points[0], {
        rotation: [Math.PI / 2, 0, 0]
      });
    },
    processGeoJSON(geojson) {
      let coords: number[][] = [];

      for (let i = 0, ilen = geojson.features.length; i < ilen; i++) {
        const feature = geojson.features[i];
        const geometry = feature.geometry;
        if (geometry && geometry.type) {
          switch (geometry.type) {
            case "Point":
              coords = [geometry.coordinates];
              break;
            case "MultiPoint":
              coords = geometry.coordinates;
              break;
          }

          coords.forEach((c: number[]) => {
            this.points.push(c);
          });
        }
      }
    }
  });

  const flyLayer = joGISThree.getLayer("custom_circle_plan");
  flyLayer.options.setData({
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [108.92361111111111, 34.54083333333333]
        },
        properties: {
          name: "陕西省泾阳县永乐镇北流村"
        }
      }
    ]
  });
}

引入模块

首先,我们需要引入相应的模块:

typescript
import { JoGISThree } from "@jodvf/three-gis-map";
模块说明
JoGISThreeJoGISThree 类为引擎主体,包含引擎初始化启动、运行渲染等核心方法

初始化引擎

typescript
const joGISThree = new JoGISThree(map, maplibregl, {
  projection: "EPSG:3857"
});

监听地图初始化完成

typescript
joGISThree.on("jogisthree.load", () => {
  // ...
});

初始化自定义图层

这里的 addLayertype 属性是传入了 custom,表示利用图层的生命周期函数来自定义绘制图层;

typescript
function addCirclePlan() {
  joGISThree.addLayer({
    id: "custom_circle_plan",
    type: "custom",
    onAdd: function (map, gl) {
      this.options.initLayer(this, map, gl);
    },
    initLayer(layer, map, gl) {
      this.map = map;
      this.layer = layer;
      this.points = [];
      this.material = this.createMaterial();
    },
    onRender(gl, matrix) {
      this.options.layerAnimate();
    },
    layerAnimate() {
      if (!this.mesh) return;
      (this.mesh as Mesh).rotation.z += 0.01;
    },
    setData(geojson) {
      // let data = joGISThree.geojsonTrans.trans(geojson);
      this.processGeoJSON(geojson);
      this.createMesh();
    },
    createMaterial() {
      const material = new MeshBasicMaterial({
        map: joGISThree.loader.load("./images/bg_circle.png"),
        transparent: true,
        depthWrite: true,
        depthTest: true
        // side: DoubleSide,
      });

      return material;
    },
    createMesh() {
      // const radius = TileUtil.convertHeight(
      //   joGISThree.projection.code,
      //   4000000
      // );

      const geometry = new CircleGeometry(4000000, 32);
      let mesh = new Mesh(geometry, this.material);
      this.mesh = mesh;
      // mesh.renderOrder = 102;
      this.layer.addObject(mesh, this.points[0], {
        rotation: [Math.PI / 2, 0, 0]
      });
    },
    processGeoJSON(geojson) {
      let coords: number[][] = [];

      for (let i = 0, ilen = geojson.features.length; i < ilen; i++) {
        const feature = geojson.features[i];
        const geometry = feature.geometry;
        if (geometry && geometry.type) {
          switch (geometry.type) {
            case "Point":
              coords = [geometry.coordinates];
              break;
            case "MultiPoint":
              coords = geometry.coordinates;
              break;
          }

          coords.forEach((c: number[]) => {
            this.points.push(c);
          });
        }
      }
    }
  });

  const flyLayer = joGISThree.getLayer("custom_circle_plan");
  flyLayer.options.setData({
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [108.92361111111111, 34.54083333333333]
        },
        properties: {
          name: "陕西省泾阳县永乐镇北流村"
        }
      }
    ]
  });
}

加载自定义图层

typescript
joGISThree.on("jogisthree.load", () => {
  addCirclePlan();
});