openlayers 添加测量工具

要求

主要有距离和面积测量,绘制的时候清空上一次绘制的图形。做到距离和面积切换

实现

  • html
<label class="m-l-20 measure">
        <span
          class="measure-item"
          :class="{ 'measure-active': ruleType === 'line' }"
          @click="setRule('line')"
          ><icon-font type="icon--Ruler"></icon-font
        ></span>
        <span
          class="m-l-10 measure-item"
          :class="{ 'measure-active': ruleType === 'area' }"
          @click="setRule('area')"
          ><icon-font type="icon-rule-area"></icon-font
        ></span>
      </label>
  • ts 这里的style是画图时显示的样式 不是画完图后的样式
// 这个是画图时显示的样式 不是画完图后的样式
const MeasureStyle = new Style({
    fill: new Fill({
        color: 'rgba(255, 255, 255, 0.2)'
    }),
    stroke: new Stroke({
        color: 'rgba(0, 0, 0, 0.5)',
        lineDash: [10, 10],
        width: 2,
    }),
    image: new Circle({
        radius: 5,
        stroke: new Stroke({
            color: 'rgba(0, 0, 0, 0.7)',
        }),
        fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)',
        }),
    })
})

measureVectorLayer这里的style时画完图后的样式

const drawSource = new VectorSource();
// 这里的style时画完图后的样式
const measureVectorLayer = new VectorLayer({
       source: drawSource,
       style: new Style({
       stroke: new Stroke({
       color: "#ffcc33",
       width: 2,
     }),
   }),
});
state.map.addLayer(measureVectorLayer)

// 测量
    const ruleType = ref(null);
    let helpTooltipElement: HTMLElement | null;
    let measureTooltipElement: HTMLElement | null;
    let helpTooltip: Overlay, measureTooltip: Overlay;
    let sketch: Feature | null;
    let draw = ref();
    const createMeasureDom = () => {
      helpTooltipElement = document.createElement("div");
      helpTooltipElement.className = "ol-tooltip hidden";
      helpTooltip = new Overlay({
        element: helpTooltipElement,
        offset: [15, 0],
        positioning: "center-left",
      });
      measureTooltipElement = document.createElement("div");
      measureTooltipElement.className = "ol-tooltip ol-tooltip-measure";
      measureTooltip = new Overlay({
        element: measureTooltipElement,
        offset: [0, -15],
        positioning: "bottom-center",
        stopEvent: false,
        insertFirst: false,
      });
      state.map.addOverlay(measureTooltip);
      state.map.addOverlay(helpTooltip);
    };
    const formatLength = (line) => {
      const length = getLength(line);
      let output;
      if (length > 100)
        output = Math.round((length / 1000) * 100) / 100 + " km";
      else output = Math.round(length * 100) / 100 + " m";
      return output;
    };
    const formatArea = (polygon) => {
      const area = getArea(polygon);
      let output;
      if (area > 10000)
        output = Math.round((area / 1000000) * 100) / 100 + " km<sup>2</sup>";
      else output = Math.round(area * 100) / 100 + " m<sup>2</sup>";
      return output;
    };
    let listener;
    const drawStart = (evt) => {
      sketch = evt.feature;
      drawSource.clear();
      let tooltipCoord;
      if (!sketch) return;
      listener = sketch.getGeometry()?.on("change", (sevt) => {
        const geom = sevt.target;
        let output;
        if (geom instanceof Polygon) {
          output = formatArea(geom);
          tooltipCoord = geom.getInteriorPoint().getCoordinates();
        } else if (geom instanceof LineString) {
          output = formatLength(geom);
          tooltipCoord = geom.getLastCoordinate();
        }
        measureTooltipElement!.innerHTML = output;
        measureTooltip.setPosition(tooltipCoord);
      });
    };
    const drawEnd = () => {
      measureTooltipElement!.className = "ol-tooltip ol-tooltip-static";
      measureTooltip.setOffset([0, -7]);
      sketch = null;
      unByKey(listener);
    };
    const addInteraction = (ruleType) => {
      const type = ruleType === "line" ? "LineString" : "Polygon";
      draw.value = new Draw({
        source: drawSource,
        type: type,
        style: MeasureStyle,
      });
      state.map.addInteraction(draw.value);
      draw.value.on("drawstart", drawStart);
      draw.value.on("drawend", drawEnd);
    };
    const setRule = (type) => {
      state.map.removeInteraction(draw.value);
      if (ruleType.value === type) {
        ruleType.value = null;
        return;
      } else ruleType.value = type;
      addInteraction(type);
    };
    const pointerMoveHandle = (evt) => {
      if (evt.dragging || !ruleType.value) {
        helpTooltipElement!.classList.add("hidden");
        return;
      }
      let helpMsg = "点击开始测量";
      if (sketch) {
        helpMsg = "点击继续画";
      }
      helpTooltipElement!.innerHTML = helpMsg;
      helpTooltip.setPosition(evt.coordinate);
      helpTooltipElement!.classList.remove("hidden");
    };
    const listenHandle = () => {
      state.map.getView().addEventListener("mouseout", () => {
        helpTooltipElement!.classList.add("hidden");
      });
      state.map.on("pointermove", pointerMoveHandle);
    };

  • css
// 测量样式
.measure {
  &-item {
    margin: 0 10px;
    padding: 0 4px;
    height: 30px;
    line-height: 30px;
    font-size: 20px;
    color: #333;
    cursor: pointer;
  }
  .measure-active {
    background: rgba(51, 51, 51, 0.5);
  }
}
.ol-tooltip {
  position: relative;
  border-radius: 4px;
  padding: 4px 8px;
  opacity: 0.7;
  white-space: nowrap;
  font-size: 12px;
  user-select: none;
}
.ol-tooltip.hidden {
  display: none;
}
.ol-tooltip-measure {
  opacity: 1;
  font-weight: bold;
}
.ol-tooltip-static {
  // 提示框
  background-color: #ffcc33;
  color: black;
  border: 1px solid white;
}
.ol-tooltip-measure:before,
// 三角形
.ol-tooltip-static:before {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}
.ol-tooltip-static:before {
  border-top-color: #ffcc33;
}

注意

draw不能在vue3 setup()组件直接设置let draw:Draw,否则removeInteraction会移除失败。设置let draw = ref()不用return可以正常使用。