vue3.0 + typescript openlayers实现图标点、移动、画线、显示范围测量长度测量面积、画三角形、画正方形、画圆、线选、画笔清除测量清除地图所有等功能

由于最近项目用到地图,所以今天时间代码摘出来,自己写个地图的小demo标记
话不多说,先看效果

map1

1、安装ol

 npm i ol@6.14.1

这是我的目录结构
在这里插入图片描述

2、下面是OpenlayerMap/index.vue地图)的代码,记得申请地图key,记得填到下方的代码中

<template>
  <div class="openlayersMap"&gt;
    <div id="map"&gt;</div>

    <!-- 鼠标经纬度指示 -->
    <div
      id="mouse-position"
      :style="assignMouseIndicatePosition"
      v-if="needMouseIndicate"
    ></div>

    <!-- 图层展示弹窗 -->
    <div id="popup-box">
      <!-- <span id="popup-closer"></span> -->
      <div id="popup-content">
        <slot :value="sol"></slot>
      </div>
    </div>

    <div id="popup-box-right" :style="{top:'-90px',left:'5px'}">
      <hr :style="{border: '2px solid #2af0e1',borderRadius: '40px',width:'2vw',marginTop:'80px'}"/>
      <div id="popup-content">
        <slot name="right" :value="sol">
        </slot>
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, nextTick } from "vue";
import { getTopLeft, getWidth } from "ol/extent";
import { getArea, getLength } from "ol/sphere";
import { Map, View, Feature, Overlay } from "ol";
import { Draw, Modify, Snap } from "ol/interaction";
import { Circle as CircleGeo } from "ol/geom";
import { Circle, Fill, Stroke, Style, Text, Icon } from "ol/style";
import { Tile, Vector as VectorLayer } from "ol/layer";
import { defaults, MousePosition } from "ol/control";
import { get, fromLonLat } from "ol/proj";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import { createStringXY } from "ol/coordinate";
import { WMTS, Vector as VectorSource } from "ol/source";
import { LineString, Point, Polygon } from "ol/geom";
import { createBox, createRegularPolygon } from "ol/interaction/Draw";
import CircleStyle from "ol/style/Circle";
import { unByKey } from "ol/Observable";
const startImg: any = require("@/image/startPoint.png"); //轨迹起点图标
const endImg: any = require("@/image/endPoint.png"); //轨迹终点图标
// 是否显示地图经纬度指示
const props = withDefaults(defineProps<{ needMouseIndicate: boolean }>(), {
  needMouseIndicate: true
});
const modelMange: String='';
let sol: any = ref(null); // 插槽回填数据
let assignMouseIndicatePosition: IMosueIndicatePosition;
let drawSource: VectorSource;
let drawVector: any = null;
let exportDrawVector: any = ref(null);
let map: Map | undefined = undefined;
const exportMap =ref<any>(null)
let saveVectorLayer: any | null = null;
let mousePositionControl: MousePosition;
const layerObj: any=ref(null);
const isActivePopup:any=ref(false);
const singleLayer:any=ref(null);
const saveGroupLayer:any=ref(null);  //图形Layer

const draw:any=ref(null);  //画笔
const drawList:any=ref([]);  //
const snap:any=ref(null);  //

const state=reactive<any>({
  shapeType:'',
  layerIndex:0,
  drawCache:[],
  helpTooltip:'',
  continueLineMsg:'',
  helpTooltipElement:null,
  measureTooltipElement:null,
  measureTooltip:null,
  sketch:null,
  listener:null,

  //路径相关
  routeMap:[],

})

/**
 * 在地图绘制图层
 */
//#region
const initDrawSource = () => {
  drawSource = new VectorSource();
  drawVector = new VectorLayer({
    source: drawSource,
    style: new Style({
      fill: new Fill({
        color: "rgba(255, 255, 255, 0.2)",
      }),
      stroke: new Stroke({
        color: "#ffcc33",
        width: 2,
      }),
      image: new Circle({
        radius: 7,
        fill: new Fill({
          color: "#ffcc33",
        }),
      }),
    }),
  });
  exportDrawVector.value=drawVector
  const modify = new Modify({ source: drawSource });
  // exportMap.value.addInteraction(modify)
  return modify;
};
// 得到初始化地图控制器
function getIninialControl(mouseInfoTargetId: string = "mouse-position") {
  if (props.needMouseIndicate) {
    mousePositionControl = new MousePosition({
      coordinateFormat: createStringXY(5),
      projection: "EPSG:4326",
      className: "custom-mouse-position",
      target: document.getElementById(mouseInfoTargetId) || undefined,
      undefinedHTML: " ",
    });
    return defaults({ zoom: false, rotate: false }).extend([
      mousePositionControl,
      // 全屏插件
      // new FullScreen(),
    ]);
  } else {
    return defaults({ zoom: false, rotate: false });
  }
}
// 地图初始化
const initMap=()=>{
  try {
    let projection: any = get("EPSG:4326");
    let projectionExtent = projection!.getExtent();
    let size = getWidth(projectionExtent) / 256;
    let resolutions = new Array(18);
    let matrixIds = new Array(18);
    const modify = initDrawSource();

    for (let i = 1; i <= 18; i++) {
      resolutions[i] = size / Math.pow(2, i);
      matrixIds[i] = i;
    }
    map = new Map({
      controls: getIninialControl(),
      layers: [
        // 卫星图层数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/img_c/wmts?tk=你的KEY",//这里是你申请key
            layer: "img",
            style: "default",
            matrixSet: "c",
            projection: projection,
            format: "tiles",
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        // 卫星行政数据
        new Tile({
          source: new WMTS({
            url: "http://t{0-7}.tianditu.gov.cn/cia_c/wmts?tk=你的KEY",//这里是你申请key
            layer: "cia", //vec/cva img/cia
            matrixSet: "c",
            format: "tiles",
            style: "default",
            projection: projection,
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
        }),
        drawVector,
      ],
      target: "map",
      view: new View({
        center: [108.8821,34.2227], // 初始化中心点 西安软件
        maxZoom: 18,
        minZoom: 8,
        zoom: 15,//地图层
        projection: "EPSG:4326",
      }),
    });
    exportMap.value=map
    map.addInteraction(modify);
  } catch (err) {
    console.log(err);
  }
}

// 在页面展示
const lastShowPoints= (dataList: any[], imgStr: string,scale: number=1,fn?: any,)=>{   
  if (dataList.length === 0)  return;
  try {
    let features: any[] = []; // 定义坐标s
    imgStr =require(`../../image/${imgStr}`);
    let vectorLayer = new VectorLayer({
      renderBuffer: 200,
      source: new VectorSource(),
      style: (feature) => [
        new Style({
          image: new Icon({
            src: imgStr,
            scale: scale,
            // imgSize: [50, 50],
          }),
        }),
      ],
    });
    // console.log('points',dataList);
    dataList.forEach((item) => {
      item.sol = fn(JSON.parse(JSON.stringify(item)));
      if ((item.lng || item.longitude) &amp;&amp; (item.lat || item.latitude)) {
        let newObj = Object.assign({}, item);
        const wz=[+item.lng?item.lng:item.longitude, +item.lat?item.lat:item.latitude];
        // console.log('wz',wz);
        newObj.geometry = new Point(wz);
        features.push(new Feature(newObj));
        if(item.sol.circle){
          let circleFeature = new Feature({  //添加
            geometry: new CircleGeo([wz[0]*1,wz[1]*1], 0.005)
          });
          circleFeature.setStyle(new Style({  // 设置样式
            fill: new Fill({
              color: 'rgba(255, 255, 255, 0.1)'
            }),
            stroke: new Stroke({
              color: 'rgba(217, 11, 53, 0.4)',
              lineDash: [20, 10]
            })
          }));
          features.push(circleFeature);
        }
      }
    });
    vectorLayer.getSource()!.addFeatures(features);
    map!.addLayer(vectorLayer);
    saveVectorLayer=vectorLayer
    return saveVectorLayer
  } catch (error) {
    console.log(error);
  }
}

//点数绘图
const groupPlot=(data:any,color?:string,borderColor?:string)=>{
  console.log(color);
  color=color || "rgba(252, 51, 40, 0.2700)"
  let source = new VectorSource();
  let style = new Style({
    text: new Text({
        // font: '15px Microsoft YaHei',
        // text:'xxxx',
        fill: new Fill({
          color: '#fff'
        })
    }),
    fill: new Fill({
        color
    }),
    stroke: new Stroke({
        color: borderColor || 'rgba(252, 51, 40, 1)',
        width:  2
    }),
    image: new Circle({
        radius: 10,
        fill: new Fill({
            color: '#ffcc33'
        })
    })
  });
  //矢量图层
  let vectorLayer = new VectorLayer({
      source: source,
      style: style,
  });    
  let features: any[] = [];
 
  //多边形要素类
  data.map((n:any)=>{
    //声明一个新的数组
    let coordinatesPolygon = new Array();
    
    //循环遍历经纬度转到"EPSG:4326"投影坐标系
    for (let i = 0; i < n.pointList.length; i++) {
        let pointTransform = fromLonLat([n.pointList[i][0], n.pointList[i][1]], "EPSG:4326");
        coordinatesPolygon.push(pointTransform);
    }
    let feature = new Feature({
        ...n,
        geometry: new Polygon([coordinatesPolygon]),//多边形此处注意一定要是[坐标数组]
    });
    features.push(feature)
  })
  
  source.addFeatures(features);
  map!.addLayer(vectorLayer);
  saveGroupLayer.value=vectorLayer;
  return vectorLayer
}
 // 点击地图后的交互(主要是图标)
const mapClick=()=>{    
  map!.on("click", (event) => {
    console.log(784,event)
   
    removeModel();
    let bool=true;
    let pixel =map!.getEventPixel(event.originalEvent);
    map?.forEachFeatureAtPixel(pixel, (feature: any,a) => {     
      try {
        let myfeature;
        if(feature.values_.features){//聚合点击
          myfeature=feature.values_.features[0];
        }else{
          myfeature=feature;
        }
        // console.log('myfeature',myfeature);
        
        if(!myfeature.values_.sol) return
        sol.value=myfeature.values_.sol;
        console.log('sol',sol.value)
        // console.log('sol',sol.value || myfeature.values_);
        let x = myfeature.get("longitude") || myfeature.get("lng"),
          y = myfeature.get("latitude") || myfeature.get("lat");
        let coordinate = [x, y]; 
        //来控制弹框样式         
        let popupClass="popup-box";   //popup-box-right
        if(sol.value.popupClass) popupClass=sol.value.popupClass
        //来控制弹框边距样式
        // this.modelMangebottom=this.sol.bottom || '0';     
        // this.modelMangeleft=this.sol.left || '0';     
        let overlay = new Overlay({ 
          element: document.getElementById(popupClass) || undefined,
        });
        
        map!.addOverlay(overlay);
        overlay.setPosition(coordinate);
        layerObj.value = overlay;
        bool=false
        isActivePopup.value=true;
      } catch (error) {
        console.log(error);
      }   
    });
    // if((this.$parent as any).isPopup &amp;&amp; (this.$parent as any).isPopup.length>0) (this.$parent as any).isPopup=[];
    
    if(bool) map!.removeLayer(singleLayer.value);
  });
}

//清除打开弹框
const removeModel=()=>{
  if(isActivePopup.value){
    layerObj.value.setPosition(undefined);
    sol.value = {};
    layerObj.value=null;
    isActivePopup.value=false
  }
}

// 移动到指定中心点位
const moveToPoint=async (x: number, y: number)=>{
  // console.log(x,y);
  map!.getView().animate({
    center: [x, y],
  });
}

//画线
const drawLine=(bool:boolean)=>{
    draw.value &amp;&amp; map!.removeInteraction(draw.value);
    draw.value = new Draw({
      source:drawVector.getSource(),
      type: "LineString",
      freehand: bool,
      stopClick: true,
    });
    exportMap.value.addInteraction(draw.value);
    draw.value &amp;&amp; draw.value.on('drawend',() =>drawList.value.push(draw.value))
    // console.log('drawVector',drawVector);
    return draw.value;
}

// 多边形
const drawPolygon=()=>{
  draw.value &amp;&amp; map!.removeInteraction(draw.value);
  draw.value = new Draw({
    source: drawVector.getSource(),
    type: "Polygon",
    stopClick: true,
  });
  exportMap.value.addInteraction(draw.value);
  draw.value &amp;&amp; draw.value.on('drawend',() =>drawList.value.push(draw.value))
}

// 画圆
const drawCircle=(type:string)=>{
  draw.value &amp;&amp; map!.removeInteraction(draw.value);
  if (type == "triangle") {
    //正三角
    draw.value = new Draw({
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createRegularPolygon(3),
      stopClick: true,
    });
  } else if (type == "circle") {
    draw.value = new Draw({
      //正圆
      source: drawVector.getSource(),
      type: "Circle",
      stopClick: true,
    });
  } else if (type == "square") {
    draw.value = new Draw({
      //正方形
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createRegularPolygon(4),
      stopClick: true,
    });
  } else if (type == "rectangle") {
    draw.value = new Draw({
      //长方形
      source: drawVector.getSource(),
      type: "Circle",
      geometryFunction: createBox(),
      stopClick: true,
    });
  }
  snap.value = new Snap({source: drawSource });
  exportMap.value.addInteraction(snap.value); //鼠标捕捉
  exportMap.value.addInteraction(draw.value);
  draw.value &amp;& draw.value.on('drawend',() =>drawList.value.push(draw.value))
}

 /** 测距、测面*/
const measure=(type:string)=>{
  draw.value && exportMap.value.removeInteraction(draw.value);
  state.shapeType = type;
  state.layerIndex++;
  state.drawCache[state.layerIndex] = {
    feature: null,
    measureTooltip: null,
  };
  if (draw.value) {
    exportMap.value.removeInteraction(draw.value);
  }
  // 添加map事件
  addMapEvent();
}

const addMapEvent=()=>{
  exportMap.value.on("pointermove", (evt:any) => {
    draw.value? pointerMoveHandler(evt): exportMap.value.removeOverlay(state.helpTooltip);
  });
  exportMap.value.getViewport().addEventListener("mouseout", () => {
    state.helpTooltipElement &&
    state.helpTooltipElement.classList.add("hidden");
  });
  addInteraction();
}

const addInteraction=()=> {
  draw.value = new Draw({
    source: drawVector.getSource(),
    type: state.shapeType,
    style: new Style({
      fill: new Fill({ color: "rgba(255, 255, 255, 0.2)" }),
      stroke: new Stroke({
        color: "rgba(255, 255, 255, 1)",
        lineDash: [10, 10],
        width: 2,
      }),
      image: new CircleStyle({
        radius: 5,
        stroke: new Stroke({ color: "rgba(255, 255, 255, 0.8)" }),
        fill: new Fill({ color: "rgba(255, 255, 255, 0.2)" }),
      }),
    }),
  });
  exportMap.value.addInteraction(draw.value);
  createMeasureTooltip();
  createHelpTooltip();
  drawHandler();
}

const createMeasureTooltip=()=>{
  if(state.measureTooltipElement) {
    state.measureTooltipElement.parentNode.removeChild(
      state.measureTooltipElement
    );
  }
  state.measureTooltipElement = document.createElement("div");
  state.measureTooltipElement.className = "ol-tooltip ol-tooltip-measure";
  state.measureTooltip = new Overlay({
    element: state.measureTooltipElement,
    offset: [0, -15],
    positioning: "bottom-center",
  });
  exportMap.value.addOverlay(state.measureTooltip);
}

const createHelpTooltip=()=>{
  if (state.helpTooltipElement) {
    state.helpTooltipElement.parentNode.removeChild(state.helpTooltipElement);
  }
  state.helpTooltipElement = document.createElement("div");
  state.helpTooltipElement.className = "ol-tooltip hidden";
  state.helpTooltip = new Overlay({
    element: state.helpTooltipElement,
    offset: [15, 0],
    positioning: "center-left",
  });
  exportMap.value.addOverlay(state.helpTooltip);
}

const drawHandler=()=>{
  draw.value.on("drawstart", (evt:any) => {
    state.sketch = evt.feature;
    let tooltipCoord = evt.coordinate;

    state.listener = state.sketch.getGeometry().on("change", (evt:any) => {
      let output;
      const geom = evt.target;
      if (geom instanceof LineString) {
        output = formatLength(geom);
        tooltipCoord = geom.getLastCoordinate();
      } else if (geom instanceof Polygon) {
        output = formatArea(geom);
        tooltipCoord = geom.getInteriorPoint().getCoordinates();
      }
      let closeBtn =
        "<i class='tooltip-close-btn tooltip-close-btn_" +
        state.layerIndex +
        "' data-index='" +
        state.layerIndex +
        "'></i>";
        state.measureTooltipElement.innerHTML = output + closeBtn;
        state.measureTooltip.setPosition(tooltipCoord);
        state.drawCache[state.layerIndex].measureTooltip = state.measureTooltip;
    });
  });

  draw.value.on("drawend", (evt:any) => {
    // console.log('hhhh');
    
    // (this.$parent as any).toolsindex ='';
    state.drawCache[state.layerIndex].feature = evt.feature;
    state.measureTooltipElement.className = "ol-tooltip ol-tooltip-static";
    state.measureTooltip.setOffset([0, -7]);
    state.sketch = null;
    state.measureTooltipElement = null;
    createMeasureTooltip();
    unByKey(state.listener);
    exportMap.value.removeInteraction(draw.value);
    draw.value = null;        
    // 删除图层
    const self = this;
    document?.querySelector(".tooltip-close-btn_" + state.layerIndex).addEventListener("click", function (e:any) {
      // console.log('dataset',e);
      
      // state.drawVector
      //     .getSource()
      //     .removeFeature(state.drawCache[state.dataset.index].feature);
      //     state.map.removeOverlay(
      //       state.drawCache[state.dataset.index].measureTooltip
      //   );
      //   delete state.drawCache[state.dataset.index];
      });
  });
}

const formatLength=(line:any)=>{
  const sourceProj = exportMap.value.getView().getProjection(); //获取投影坐标系
  var length = getLength(line, { projection: sourceProj });
  var 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:any)=>{
  const sourceProj = exportMap.value.getView().getProjection(); //获取投影坐标系
  const geom = polygon.clone().transform(sourceProj, "EPSG:3857");
  const area = getArea(geom);

  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;
}

const pointerMoveHandler=(evt:any)=>{
  if (evt.dragging) {
    return;
  }
  /** @type {string} */
  var helpMsg = "测量";

  if (state.sketch) {
    var geom = state.sketch.getGeometry();
    if (geom instanceof LineString) {
      helpMsg = state.continueLineMsg;
    }
  }
  state.helpTooltipElement.innerHTML = helpMsg;
  state.helpTooltip.setPosition(evt.coordinate);
  state.helpTooltipElement.classList.remove("hidden");
}
// **************

//路径相关
// 开始显示一条轨迹
const  showWay=async(_routeInfo: IRouteInfo)=>{  
  if (state.routeMap.some((route:any) => route.id === _routeInfo.id)) {
    // 已经有了路径直接移动视野到该点
    moveToPoint(_routeInfo.gis[0][0], _routeInfo.gis[0][1]);
    return;
  }
  
  // 根据一系列设置地图视野中点
  const point = _routeInfo.gis[0];

  // 将地图设置最大缩放
  const view = map!.getView();
  const MaxZoom = view.getMaxZoom();
  const MinZoom = view.getMinZoom();
  const zoom = Math.ceil((MaxZoom + MinZoom) / 2);
  view.setZoom(zoom);

  await moveToPoint(point[0], point[1]);

  showRouterMap(_routeInfo);
}

// 路径显示
const showRouterMap=(_routeInfo: any)=>{
  let pointsList = _routeInfo.gis;
  // pointsList.map(n=>{
  //   n=[1*n[0],1*n[1]]
  // })
  let roadLine = new LineString(pointsList);
  let output=formatLength(roadLine)
  console.log('output',pointsList,output);
  
  let roadLineSource = new VectorSource({
    features: [new Feature(roadLine)],
  });
  const roadLineLayer = new VectorLayer({
    source: roadLineSource,
    style: new Style({
      stroke: new Stroke({
        color: "#38A0FF",
        width: 4,
      }),
    }),
  });
  map!.addLayer(roadLineLayer);
  let pointLayer1 = addVectorLabel({
    pointsList: pointsList[0],
    txt: "起",
  });
  let pointLayer2 = addVectorLabel({
    pointsList: pointsList[pointsList.length - 1],
    txt: "终",
  });
  let label = addVectorLabel({
    pointsList: [pointsList[0][0], pointsList[0][1]],
    txt: _routeInfo.name + ",全程" + output,
    fill: "#111111",
    stroke: "#ffffff",
  });

  // 保存实例
  state.routeMap.push({
    id: _routeInfo.id as string,
    routeLayerExample: roadLineLayer,
    vectorLabels: [label],
    points: [pointLayer1, pointLayer2],
  });
}

// 添加矢量标签例如路径的起终点、描述
const addVectorLabel=(opt: any)=>{
  let vectorSource = new VectorSource(); //矢量标注数据源
  const layer = new VectorLayer({
    source: vectorSource,
  }); //矢量标注图层
  map!.addLayer(layer);
  if (opt.txt == "起" || opt.txt == "终") {
    // 添加起点以及终点的layer
    let newFeature = new Feature({
      geometry: new Point(opt.pointsList || []),
    });
    newFeature.setStyle(
      new Style({
        image: new Icon({
          src: opt.txt == "起" ? startImg : endImg,
          offset: [0, -26],
          offsetOrigin: "bottom-right",
          size: [32, 60],
        }),
        fill: new Fill({ color: "#ffffff" }),
        zIndex: 1,
      })
    );
    // 将新要素添加数据源
    vectorSource.addFeature(newFeature);
    return layer;
  }
  let overlayerElement = document.createElement("div");
  overlayerElement.className = "ol-tooltip-draw-route";
  overlayerElement.innerHTML = opt.txt;
  const overlayObj = new Overlay({
    element: overlayerElement,
    offset: [0, -30],
    positioning: "bottom-center",
  });
  overlayObj.setPosition(opt.pointsList);
  map!.addOverlay(overlayObj);
  return overlayObj;
}

// 清除部分路径
const clearRoute=(_routeId: number|string | Array<number|string>)=>{  
  if (Array.isArray(_routeId)) {
    for (let routeId of _routeId) {
      let routeWayIndex = state.routeMap.findIndex((it:any)=>it.id == routeId)
      let routeItem = state.routeMap[routeWayIndex]
      // console.log('routeItem',routeItem,state.routeMap,routeId);
      
      exportMap.value.removeLayer(routeItem.routeLayerExample);
      routeItem.points?.forEach((it:any) => exportMap.value.removeLayer(it));
      routeItem.vectorLabels.forEach((it:any) => exportMap.value.removeOverlay(it));
      state.routeMap.splice(routeWayIndex, 1);
    }
  } else {
    if (!_routeId) return;
    let routeWayIndex = state.routeMap.findIndex((it:any)=>it.id == _routeId)
    let routeItem = state.routeMap[routeWayIndex]

    exportMap.value.removeLayer(routeItem.routeLayerExample);
    routeItem.points?.forEach((it:any) => exportMap.value.removeLayer(it));
    routeItem.vectorLabels.forEach((it:any) => exportMap.value.removeOverlay(it));
    state.routeMap.splice(routeWayIndex, 1);
  }
}

nextTick(()=>{
  
})
defineExpose({measure,removeModel,lastShowPoints,groupPlot,moveToPoint,exportMap,drawLine,drawPolygon,drawCircle,draw,exportDrawVector,state,showWay,clearRoute})

onMounted(() => {
  initMap();
  mapClick()
});

</script>

<style lang="scss" scoped>
.openlayersMap {
  width: 100%;
  height: 100%;
  #map {
    height: 100%;
  }
  #mouse-position {
    position: absolute;
    top: 10px;
    right: 20px;
    color: #fff;
    font-weight: bold;
    font-size: 18px;
  }
  #popup-box{
    bottom: 25px;
    left: 0px;
    background-color: rgba(0, 0, 1, 0.5);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  }
  #popup-box ,#popup-box-right{
    position: absolute;
    z-index: -1;
    box-sizing: border-box;
    padding: 4px 6px;
    border-radius: 4px;
    
    border: 2px solid #84f199;
    min-width: 280px;
    position: absolute;
    // bottom: 20px;
    // left: -50px;
    #popup-closer {
      font-size: 14px;
      height: 20px;
      line-height: 20px;
      text-align: right;
      position: absolute;
      right: 0;
      top: 0;
      margin-right: 4px;
      user-select: none;
      cursor: pointer;
      color: #fff;
    }
    #popup-content {
      // margin-top: 24px;
      display: flex;
      max-height: 600px;
      // overflow-y: scroll;
      position: relative;
    }
    &:after,
    &:before {
      top: 100%;
      border: solid transparent;
      content: " ";
      height: 0;
      width: 0;
      position: absolute;
      pointer-events: none;
    }
    &:after {
      border-top-color: white;
      border-width: 10px;
      left: 48px;
      margin-left: -10px;
    }
    &:before {
      border-top-color: #cccccc;
      border-width: 11px;
      left: 48px;
      margin-left: -11px;
    }
  }
  #popup-box-right{
    // bottom: -24vh;
    // left: 2vh;
    border: none;
    display: flex;
    &:after,
    &:before {content:none;}
    > #popup-content{
        background: url("~@/image/chart.png") no-repeat;
        background-size: 100% 100%;
    }
  }
  
}
</style>


3、下面是OpenlayerMap/index.ts的代码

import OpenLayerMap from "./index.vue"

export {
    OpenLayerMap
}

4、这是我地图中用到三张图片chart.png是地图上弹窗的背景图icon.png是个标点的小图标,剩下两个是地图画轨迹时一个起点和终点的图标,如果你粘贴我的代码,没这几张图片报错
在这里插入图片描述
把几张图片分别给大家贴出来吧:
chart.png

在这里插入图片描述
endPoint.png
在这里插入图片描述
startPoint.png
请添加图片描述
icon.png
在这里插入图片描述

5、全局引入

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
//引入地图
import components from "@/components/index";
let app=createApp(App)
Object.values(components).forEach((com) => {
  app.use(com);
});
app.use(store).use(router).use(Antd).mount('#app')

6、页面代码

<template>
  <div class="Box">
    <div class="homeBox">
      <div class="leftBox">
        <a-button type="primary" @click="showIcon">在地图上显示点</a-button
        ><br /><br />
        <a-button type="primary" @click="moveXiAn([108.9423, 34.261])"
          >移动到西安钟楼</a-button
        ><br /><br />
        <a-button type="primary" @click="moveXiAn([108.8821, 34.2227])"
          >移动到初始</a-button
        ><br /><br />
        <a-button type="primary" @click="trajectory">显示一段轨迹</a-button
        ><br /><br />
        <a-button type="primary" @click="clearTrajectory"
          >清除上面的轨迹</a-button
        ><br /><br />
        <a-button type="primary" @click="range">显示范围</a-button><br /><br />
      </div>
      <!-- 地图 -->
      <section class="map-wrap">
        <OpenlayerMap
          ref="mapRef"
          :assignMouseIndicatePosition="{
            zIndex: 1,
            right: '83px',
            top: '14px',
            fontSize: '16px',
            fontWeight: '400',
            color: '#fff',
          }"
        >
          <!-- 地图弹框 -->
          <template #right="sol">
            <div :style="{ width: '0vh' }"></div>
            <div>
              <div class="map_right" v-if="sol.value?.showLength">
                <div v-for="(item, l) in sol.value.show" :key="l">
                  <span v-for="(n, i) in item" :key="i">{{ n }}</span>
                </div>
                <button v-if="sol.value.button">
                  {{ sol.value.buttonText ? sol.value.buttonText : "查看" }}
                </button>
              </div>
              <div class="map_right" v-else>
                <span v-for="(n, i) in sol.value?.show" :key="i">{{ n }}</span>
                <button v-if="sol.value?.button">
                  {{ sol.value.buttonText ? sol.value.buttonText : "查看" }}
                </button>
              </div>
            </div>
          </template>
        </OpenlayerMap>
        <!-- 工具箱 -->
        <div class="work-box">
          <div class="tool">
            <div v-for="(n, i) in toolData" :key="i">
              <span>{{ n.title }}</span>
              <div>
                <span
                  :style="{ color: toolsindex == `${i}${l}` ? '#409EFF' : '' }"
                  v-for="(e, l) in n.data"
                  :key="l"
                  @click="clickTool(e, i, l)"
                  >{{ e.title }}</span
                >
              </div>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineComponent, reactive, ref, onMounted, nextTick } from "vue";
const mapRef = ref<null | HTMLElement>(null);

const data = ref<any>([
  {
    id: 14,
    name: "张三",
    longitude: "108.8821",
    latitude: "34.2227",
    pointList: [
      [108.8646, 34.2136],
      [108.8695, 34.2134],
      [108.8647, 34.2187],
    ],
  },
  {
    id: 14,
    name: "李四",
    longitude: "108.8867",
    latitude: "34.2283",
    pointList: [
      [108.8943, 34.2149],
      [108.8951, 34.2127],
      [108.8909, 34.2135],
      [108.8973, 34.2122],
    ],
  },
]);
const toolData = ref<any>([
  {
    title: "基础",
    key: 0,
    data: [
      { title: "测量距离" },
      { title: "测量面积" },
      { title: "清除测量" },
    ],
  },
  {
    title: "消防",
    key: 1,
    data: [
      { title: "画笔" },
      { title: "隔离带" },
      { title: "线选" },
      { title: "框选" },
      { title: "多边形选" },
      { title: "圈选" },
      { title: "清除" },
    ],
  },
]);
const toolsindex = ref<string>("");
//地图跳转
function moveXiAn(coordinate: any) {
  (mapRef.value as any).moveToPoint(...coordinate);
}
//显示轨迹
function trajectory() {
  let gis = [
    [108.9423, 34.261],
    [108.9424, 34.2568],
    [108.9478, 34.2566],
    [108.9538, 34.2496],
  ];
  (mapRef.value as any).showWay({
    id: 11, //id
    gis: gis,
    name: "轨迹", //
  });
}
function clearTrajectory() {
  (mapRef.value as any).clearRoute(11);
}
//地图上显示图标
function showIcon() {
  data.value.forEach((item: any) => {
    nextTick(() => {
      (mapRef.value as any).lastShowPoints(
        data.value,
        "icon.png",
        1,
        (item: any) => {
          return {
            show: [
              `${item.name}`,
              `纬度:${item.latitude},经度:${item.longitude}`,
            ],
            data: item,
            popupClass: "popup-box-right",
            bottom: "-13vh",
            left: "15px",
            button: true, //地图弹窗是否显示按钮
            buttonText: "点击", //地图弹窗按钮文字
            circle: true, //是否展示范围
          };
        }
      );
    });
  });
}

//地图上显示范围
function range() {
  nextTick(() => {
    (mapRef.value as any).groupPlot(data.value);
  });
}
//点击工具
function clickTool(n:any,i:number,l:number){
  if(toolsindex.value=='') toolsindex.value=`${i}${l}`; else {
    toolsindex.value='';
    nextTick(()=>{
      (mapRef.value as any).exportMap.removeInteraction((mapRef.value as any).draw);
      (mapRef.value as any).draw = null;
    });
  }
  switch (`${i}${l}`) {
    case '00': //测量距离
    if(toolsindex.value==`00`) (mapRef.value as any).measure("LineString");
      break;
    case '01': //测量面积
    if(toolsindex.value==`01`) (mapRef.value as any).measure("Polygon");
      break;
    case '02': //清除测量
    if(toolsindex.value==`02`) {
      for (const key in (mapRef.value as any).state.drawCache) {
        (mapRef.value as any).exportMap.removeOverlay(
          (mapRef.value as any).state.drawCache[key].measureTooltip
        );
      }
      (mapRef.value as any).exportDrawVector.getSource().clear();
      toolsindex.value =''
    }
      break;
    case "01": //测量距离
      if (toolsindex.value == `01`) (mapRef.value as any).measure("LineString");
      break;
    case "02": //测量面积
      if (toolsindex.value == `02`) (mapRef.value as any).measure("Polygon");
      break;
    case "03": //清除测量
      if (toolsindex.value == `03`) {
        for (const key in (mapRef.value as any).drawCache) {
          (mapRef.value as any).map.removeOverlay(
            (mapRef.value as any).drawCache[key].measureTooltip
          );
        }
        (mapRef.value as any).drawVector.getSource().clear();
        toolsindex.value = "";
      }
      break;
    case "10": //点
      if (toolsindex.value == `10`) (mapRef.value as any).drawLine(true);
      break;
    case "11": //正三角 隔离
      if (toolsindex.value == `11`) (mapRef.value as any).drawCircle("triangle");
      break;
    case "12": //线
      if (toolsindex.value == `12`) (mapRef.value as any).drawLine(false);
      break;
    case "13": //正方形
      if (toolsindex.value == `13`) (mapRef.value as any).drawCircle("square");
      break;
    case "14": //多边形
      if (toolsindex.value == `14`) (mapRef.value as any).drawPolygon();
      break;
    case "15": //圆形
      if (toolsindex.value == `15`) (mapRef.value as any).drawCircle("circle");
      break;
    case '16': //清除
    if(toolsindex.value==`16`){     
      (mapRef.value as any).exportDrawVector.getSource().clear();
      toolsindex.value =''
    } break;
    default:
      break;
  }
  (mapRef.value as any).draw && (mapRef.value as any).draw.on("drawend", () => {
      (mapRef.value as any).exportMap.removeInteraction((mapRef.value as any).draw);
      (mapRef.value as any).draw = null;
      toolsindex.value = '';
    });
}

</script>
<style lang="scss" scoped>
.Box {
  width: 100%;
  height: 100vh;
  position: relative;
  .homeBox {
    width: 100%;
    height: 100%;
    border: 1px solid gray;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    .leftBox {
      width: 20%;
    }
    .map-wrap {
      flex: 1;
      height: 100%;
      position: relative;
    }
  }
}

//地图弹窗样式
.map_right {
  color: #fff;
  font-size: 14px;
  padding: 15px 20px;
  display: flex;
  flex-direction: column;
  span:nth-child(n) {
    display: flex;
    flex-direction: column;
    margin-bottom: 10px;
    white-space: nowrap;
  }
  span:nth-child(1) {
    font-size: 16px;
    font-weight: 500;
    margin-top: 10px;
  }
  > button {
    // color: #409EFF;
    background: #409eff;
    text-align: center !important;
    padding: 6px 0;
    border: none;
    margin: 10px 16px 20px 16px;
    cursor: pointer;
  }
}
.work-box {
  display: flex;
  align-items: center;
  color: #fff;
  position: absolute;
  bottom: 60px;
  left: 30px;
  .tool {
    position: absolute;
    // bottom: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    border: 1px solid;
    margin: 0 20px;
    background: gray;
    border-radius: 5px;
    > * {
      padding: 0 10px;
      display: flex;
      width: 510px;
      align-items: center;
      > span {
        font-size: 16px;
        font-weight: 700;
      }
      > div:first-child {
        border-bottom: 1px solid;
      }
      > div {
        margin: 3px 10px;
        display: flex;
        flex: 1;
        justify-content: space-around;
        span {
          display: inline-block;
          padding: 8px;
          border: 1px solid;
          cursor: pointer;
          margin: 3px 5px;
          font-size: 14px;
          border-radius: 5px;
        }
      }
    }
  }
}
</style>

原文地址:https://blog.csdn.net/qq_43923146/article/details/127118074

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_36722.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注