Skip to content

常用工具

上次更新 2025年8月20日星期三 3:16:20 字数 0 字 时长 0 分钟

本章将介绍 OpenLayers 中一些常用的地图工具,包括绘图工具、编辑工具和视图控制等功能。

示例

新标签页预览

代码实现

vue
<template>
  <div class="h-screen">
    <div id="map" class="w-full h-full"></div>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import { Draw, Modify, Snap } from "ol/interaction";
import { fromLonLat } from "ol/proj";
import { Circle as CircleStyle, Fill, Stroke, Style } from "ol/style";
import { Control } from "ol/control";

onMounted(() => {
  // 创建地图
  const map = new Map({
    target: "map",
    view: new View({
      center: fromLonLat([117.33083, 39.094899]), // 天津
      zoom: 4,
    }),
  });

  // 添加天地图图层
  const tdtLayer = new TileLayer({
    source: new XYZ({
      url: "http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
    }),
  });
  map.addLayer(tdtLayer);

  // 保存初始范围
  const initialExtent = map.getView().calculateExtent(map.getSize());

  // 创建绘图图层
  const source = new VectorSource();
  const vector = new VectorLayer({
    source: source,
    style: new Style({
      fill: new Fill({
        color: "rgba(24, 144, 255, 0.2)",
      }),
      stroke: new Stroke({
        color: "#1890ff",
        width: 2,
      }),
      image: new CircleStyle({
        radius: 7,
        fill: new Fill({
          color: "#1890ff",
        }),
      }),
    }),
  });
  map.addLayer(vector);

  // 创建绘图工具
  let draw;
  const addInteraction = function (type) {
    if (draw) {
      map.removeInteraction(draw);
    }
    draw = new Draw({
      source: source,
      type: type,
    });
    map.addInteraction(draw);
  };

  // 创建编辑工具
  const modify = new Modify({ source: source });
  map.addInteraction(modify);

  // 创建删除工具
  const snap = new Snap({ source: source });
  map.addInteraction(snap);

  // 添加绘图控件
  const drawControls = document.createElement("div");
  drawControls.className = "ol-control draw-controls";

  // 定义绘图工具图标
  const icons = {
    Point:
      '<svg class="icon" viewBox="0 0 1024 1024"><path d="M512 85.333333c-164.949333 0-298.666667 133.738667-298.666667 298.666667 0 224 298.666667 554.666667 298.666667 554.666667s298.666667-330.666667 298.666667-554.666667c0-164.928-133.717333-298.666667-298.666667-298.666667z m0 448a149.333333 149.333333 0 1 1 0-298.666666 149.333333 149.333333 0 0 1 0 298.666666z"/></svg>',
    LineString:
      '<svg class="icon" viewBox="0 0 1024 1024"><path d="M904.533333 119.466667L119.466667 904.533333l42.666666 42.666667 785.066667-785.066667z"/></svg>',
    Polygon:
      '<svg class="icon" viewBox="0 0 1024 1024"><path d="M834.56 955.733333H189.44c-66.56 0-121.173333-54.613333-121.173333-121.173333V189.44c0-66.56 54.613333-121.173333 121.173333-121.173333h645.12c66.56 0 121.173333 54.613333 121.173333 121.173333v645.12c0 66.56-54.613333 121.173333-121.173333 121.173333z"/></svg>',
    Circle:
      '<svg class="icon" viewBox="0 0 1024 1024"><path d="M512 85.333333c-235.648 0-426.666667 191.018667-426.666667 426.666667s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667-191.018667-426.666667-426.666667-426.666667z"/></svg>',
  };

  const drawTypes = ["Point", "LineString", "Polygon", "Circle"];
  drawTypes.forEach((type) => {
    const button = document.createElement("button");
    button.innerHTML = icons[type];
    button.title = type;
    button.addEventListener("click", () => {
      addInteraction(type);
    });
    drawControls.appendChild(button);
  });

  // 添加清除按钮
  const clearButton = document.createElement("button");
  clearButton.innerHTML =
    '<svg class="icon" viewBox="0 0 1024 1024"><path d="M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6c-0.3 1.5-0.4 3-0.4 4.4 0 14.4 11.6 26 26 26h723c1.5 0 3-0.1 4.4-0.4 14.2-2.4 23.7-15.9 21.2-30zM204 390h272V182h72v208h272v104H204V390z m468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z"/></svg>';
  clearButton.title = "清除";
  clearButton.addEventListener("click", () => {
    source.clear();
  });
  drawControls.appendChild(clearButton);

  // 添加取消绘制按钮
  const cancelButton = document.createElement("button");
  cancelButton.className = "cancel-draw-btn";
  cancelButton.innerHTML =
    '<svg class="icon" viewBox="0 0 1024 1024"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m165.4 618.2l-66-0.3L512 563.4l-99.3 118.4-66.1 0.3c-4.4 0-8-3.5-8-8 0-1.9 0.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1 0.3L512 464.6l99.3-118.4 66-0.3c4.4 0 8 3.5 8 8 0 1.9-0.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"/></svg>';
  cancelButton.title = "取消绘制";
  cancelButton.addEventListener("click", () => {
    if (draw) {
      map.removeInteraction(draw);
      draw = null;
    }
  });
  drawControls.appendChild(cancelButton);

  // 添加重置范围按钮
  const resetControl = document.createElement("div");
  resetControl.className = "ol-control reset-extent";
  const resetButton = document.createElement("button");
  resetButton.innerHTML =
    '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 1024 1024"><path fill="currentColor" d="M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384a384 384 0 0 1-384-384a384 384 0 0 1 643.712-282.88"/></svg>';
  resetButton.title = "重置范围";
  resetButton.addEventListener("click", () => {
    map.getView().fit(initialExtent, {
      duration: 1000,
    });
  });
  resetControl.appendChild(resetButton);

  map.addControl(
    new Control({
      element: drawControls,
    })
  );
  map.addControl(
    new Control({
      element: resetControl,
    })
  );
});
</script>

<style scoped>
.h-screen {
  height: 24rem;
}

.w-full {
  width: 100%;
}

.h-full {
  height: 100%;
}

:deep(.ol-control button) {
  background-color: #1890ff;
  border: none;
  color: white;
  padding: 8px;
  border-radius: 4px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
}

:deep(.ol-control button:hover) {
  background-color: #40a9ff;
}

:deep(.draw-controls) {
  top: 50%;
  right: 0.5em;
  left: auto;
  transform: translateY(-50%);
  background: white;
  padding: 5px;
  border-radius: 4px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

:deep(.draw-controls button) {
  display: block;
  float: none;
  margin: 5px;
  min-width: 40px;
  height: 40px;
  font-size: 14px;
}

:deep(.draw-controls .cancel-draw-btn) {
  background-color: #ff4d4f;
  margin-top: 10px;
}

:deep(.draw-controls .cancel-draw-btn:hover) {
  background-color: #ff7875;
}

:deep(.reset-extent) {
  top: 50%;
  left: 0.5em;
  transform: translateY(-50%);
}

:deep(.reset-extent button) {
  font-size: 18px;
  width: 40px;
  height: 40px;
}

:deep(.icon) {
  width: 24px;
  height: 24px;
  fill: currentColor;
}
</style>
关注公众号