Skip to content

绘制几何图形

TIP

可以选择不同的类型,绘制不同的几何图形。

代码如下:

点我查看代码
vue
<template>
  <div id="menu">
    几何图形类型:
    <el-select v-model="state.value" size="large" @change="handleChange">
      <el-option
        v-for="item in state.options"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      />
    </el-select>
  </div>
  <div id="map"></div>
</template>

<script lang="ts" setup>
import { onMounted, reactive, onBeforeUnmount } from "vue";
import { Map, View } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import { Style, Fill, Stroke, Circle } from "ol/style";
import { Draw } from "ol/interaction";
import { createRegularPolygon } from "ol/interaction/Draw";
import { Polygon, Geometry } from "ol/geom";
import { MAPURL, ATTRIBUTIONS } from "../../../constants";
import { Coordinate } from "ol/coordinate";
import { GeometryFunction } from "ol/interaction/Draw";

enum GraphType {
  None = "None",
  Point = "Point",
  LineString = "LineString",
  Polygon = "Polygon",
  Circle = "Circle",
  Square = "Square",
  Box = "Box",
}

interface State {
  value: GraphType;
  options: {
    label: string;
    value: GraphType;
  }[];
}
let map: Map | null = null;
let draw: Draw | null = null; // 绘制对象

const state: State = reactive({
  value: GraphType.Point,
  options: [
    {
      label: "无",
      value: GraphType.None,
    },
    {
      label: "点",
      value: GraphType.Point,
    },
    {
      label: "线",
      value: GraphType.LineString,
    },
    {
      label: "多边形",
      value: GraphType.Polygon,
    },
    {
      label: "圆",
      value: GraphType.Circle,
    },
    {
      label: "正方形",
      value: GraphType.Square,
    },
    {
      label: "长方形",
      value: GraphType.Box,
    },
  ],
});
//实例化一个矢量图层Vector作为绘制层
let source: VectorSource<Geometry> | null = new VectorSource({ wrapX: false });
const vector = new VectorLayer({
  source,
  style: new Style({
    fill: new Fill({
      color: "rgba(255, 255, 255, 0.2)",
    }),
    stroke: new Stroke({
      color: "#ff0000",
      width: 2,
    }),
    image: new Circle({
      radius: 7,
      fill: new Fill({
        color: "#ff0000",
      }),
    }),
  }),
});

const raster = new TileLayer({
  source: new XYZ({
    attributions: ATTRIBUTIONS,
    url: MAPURL,
    maxZoom: 20,
  }),
});

const initMap = () => {
  map = new Map({
    //初始化map
    target: "map",
    //地图容器中加载的图层
    layers: [
      //加载瓦片图层数据
      raster,
    ],
    view: new View({
      projection: "EPSG:4326", // 坐标系,有EPSG:4326和EPSG:3 857
      center: [0, 0], // 深圳坐标
      //地图初始显示级别
      zoom: 5,
    }),
  });
};

//根据绘制类型进行交互绘制图形处理
const addInteraction = () => {
  //绘制类型
  let value = state.value;
  if (value !== GraphType.None) {
    if (source == null) {
      source = new VectorSource({ wrapX: false });
      //添加绘制层数据源
      vector.setSource(source);
    }
    let geometryFunction: GeometryFunction | undefined,
      maxPoints: number | undefined;
    if (value === GraphType.Square) {
      value = GraphType.Circle;
      //正方形图形(圆)
      geometryFunction = createRegularPolygon(4);
    } else if (value === GraphType.Box) {
      value = GraphType.LineString;
      maxPoints = 2;
      geometryFunction = (coordinates, geometry) => {
        const start = coordinates[0] as Coordinate;
        const end = coordinates[1] as Coordinate;
        if (!geometry) {
          //多边形
          geometry = new Polygon([
            [start, [start[0], end[1]], end, [end[0], start[1]], start],
          ]);
        }
        geometry.setCoordinates([
          [start, [start[0], end[1]], end, [end[0], start[1]], start],
        ]);
        return geometry;
      };
    }
    //实例化交互绘制类对象并添加到地图容器中
    draw = new Draw({
      //绘制层数据源
      source: source,
      /** @type {ol.geom.GeometryType}几何图形类型 */
      type: value,
      //几何信息变更时调用函数
      geometryFunction: geometryFunction,
      //最大点数
      maxPoints: maxPoints,
    });
    map?.addInteraction(draw);
  } else {
    source = null;
    //清空绘制图形
    vector.setSource(source);
  }
};
const handleChange = () => {
  if (map && draw) {
    //移除绘制图形
    map.removeInteraction(draw);
    //添加交互绘制功能控件
    addInteraction();
  }
};
onMounted(() => {
  initMap();
  //将绘制层添加到地图容器中
  map?.addLayer(vector);
  //添加交互绘制功能控件
  addInteraction();
});

onBeforeUnmount(() => {
  if (map) {
    map.dispose();
    map = null;
  }
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#map {
  height: 650px;
}
#menu {
  height: 50px;
  line-height: 50px;
  text-align: center;
}
</style>

如有转载或 CV 的请标注本站原文地址