废话不多说,代码端上来

<template>

<div ref="map" id="map">
    <div id="contextmenu_container" class="contextmenu">
      <ul>
        <li @click="drawFeature">
          <a href="#">绘制</a>
        </li>
        <li @click="toHome">
          <a href="#">常用区域</a>
        </li>
        <li @click="outputJson">
          <a href="#">输出Json</a>
        </li>
        <li @click="measure('distence')">
          <a href="#">测距</a>
        </li>
        <li @click="measure('area')">
          <a href="#">测面</a>
        </li>
        <li @click="measure('angle')">
          <a href="#">量角</a>
        </li>
        <li @click="fullscreen" v-html="textarr">
          <a href="#">全屏</a>
        </li>
        <li @click="clear">
          <a href="#">清除</a>
        </li>
        <li @click="pointPopup">
          <a href="#">点坐标</a>
        </li>
        <li @click="zoomIn">
          <a href="#">放大</a>
        </li>
        <li @click="zoomOut">
          <a href="#">缩小</a>
        </li>
        <li @click="refresh">
          <a href="#">刷新</a>
        </li>
      </ul>
    </div>
    <div id="popup" class="ol-popup">
      <a
        href="#"
        ref="external nofollow"
        id="popup-closer"
        class="ol-popup-closer"
      ></a>
      <div id="popup-content"></div>
    </div>
  </div>

<import>

import 'ol/ol.css'
import Map from 'ol/Map'
import View from 'ol/View'
import VectorSource from 'ol/source/Vector'
import OSM from 'ol/source/OSM'
import VectorLayer from 'ol/layer/Vector'
import TileLayer from 'ol/layer/Tile'
import { GeoJSON } from 'ol/format'
import { Draw } from 'ol/interaction'
import Overlay from 'ol/Overlay'
// 线条几何形状。
import { LineString } from 'ol/geom'
import Feature from 'ol/Feature'
// 使用返回的键或
import { unByKey } from 'ol/Observable'
// 获取几何形状的球形长度和面积
import { getLength, getArea, offset } from 'ol/sphere'
import Style from 'ol/style/Style'
import Stroke from 'ol/style/Stroke'
import Fill from 'ol/style/Fill'
import Circle from 'ol/style/Circle'
import { ScaleLine, defaults as defaultControls } from 'ol/control'
import MousePosition from 'ol/control/MousePosition'
import { createStringXY } from 'ol/coordinate'
import Icon from 'ol/style/Icon'
import Text from 'ol/style/Text'
import { transform } from 'ol/proj'
import { fromLonLat } from 'ol/proj'
import Point from 'ol/geom/Point'
import ImageSource from 'ol/source/Image'
import { fromExtent } from 'ol/geom/Polygon'

重头戏

export default

data() {
    return {
      map: null,
      vectorLayer: null,
      vectorSource: null,
      draw: null,
      select: null,
      modify: null,
      editorBtnText: '编辑',
      overlay: null,
      textarr: '全屏',
      measureType: 'diatence',
      tipDiv: null,
      pointermoveEvent: null, // 地图pointermove事件
      sketchFeature: null, // 绘制的要素
      geometryListener: null, // 要素几何change事件
      measureResult: '0', // 测量结果
      pointLayer: null,
    }
  },

mounted

var baseLayer = new TileLayer({
      source: new OSM(),
    })
this.vectorSource = new VectorSource({
      wrapX: false,
    })
    this.vectorLayer = new VectorLayer({
      source: this.vectorSource,
    })
    const scaleLineControl = new ScaleLine({
      target: 'scalebar',
      className: 'ol-scale-line',
    })
    const mousePositionControl = new MousePosition({
      coordinateFormat: createStringXY(4),
      projection: 'EPSG:4326',
      className: 'custom-mouse-position',
      target: document.getElementById('mouse-position'),
    })
    this.map = new Map({
      layers: [baseLayer, this.vectorLayer],
      controls: defaultControls({
        zoom: false,
        // rotate: false,
        attribution: false,
      }).extend([scaleLineControl, mousePositionControl]),
      target: 'map',
      view: new View({
        projection: 'EPSG:4326',
        center: [123.476492, 25.744676],
        zoom: 8,
      }),
    })
    this.map.addControl(scaleLineControl)

方法定义

refresh() {
      let that = this
      that.reload()
    },
    pointPopup() {
      var container = document.getElementById('popup')
      var content = document.getElementById('popup-content')
      var popupCloser = document.getElementById('popup-closer')
      this.overlay = new Overlay({
        element: container,
        antoPan: true,
        autoPanAnimation: {
          duration: 250,
        },
      })
      this.map.addOverlay(this.overlay)
      let that = this
      that.map.on('singleclick', function(evt) {
        let coordinate = transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
        let coordinate2 = evt.coordinate
        that.addPoints(coordinate)
        content.innerHTML = `
          <p>你点击了这里:</p>
          <p>坐标:</p>X:${coordinate2[0]} Y:${coordinate2[1]}`
        that.overlay.setPosition(coordinate2) //把 overlay 显示到指定的 x,y坐标
      })
      popupCloser.onclick = function() {
        that.overlay.setPosition(undefined)
        popupCloser.blur()
        return false
      }
    },
    addPoints(coordinate) {
      const feature = new Feature({
        geometry: new Point(fromLonLat(coordinate)),
        name: 'isbig',
      })
      const iconStyle = new Style({
        image: new Icon({
          anchor: [0.5, 0.5],
          src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png',
        }),
      })
      feature.setStyle(iconStyle)
      const vectorSource = new VectorSource({})
      this.pointLayer = new VectorLayer({
        source: vectorSource,
      })
      this.map.addLayer(this.pointLayer)
      this.vectorSource.addFeature(feature)
      return iconStyle
    },
    drawFeature() {
      this.draw = new Draw({
        source: this.vectorSource,
        // 用此实例绘制的几何形状类型。
        type: 'Polygon',
      })
      this.map.addInteraction(this.draw)
      // 绘制完成
      this.draw.on('drawend', () => {
        this.map.removeInteraction(this.draw)
        this.draw = null
      })
    },
    toHome() {
      var to = [120.38, 36.07]
      var view = this.map.getView()
      view.setZoom(8),
        view.animate({
          center: to,
          duration: 0,
        })
    },
    // 输出矢量图层要素为GeoJson数据
    outputJson() {
      let features = this.vectorSource.getFeatures()
      let jsonObj = new GeoJSON().writeFeatures(features)
      console.log('->GeoJson格式数据:', jsonObj)
    },
    creatDraw(type) {
      let maxPoints = null
      if (this.measureType == 'angle') maxPoints = 3
      else maxPoints = null

      // 矢量图层源
      let vectorSource = new VectorSource({
        wrapX: false,
      })
      // 矢量图层
      this.vectorLayer = new VectorLayer({
        source: vectorSource,
        style: new Style({
          fill: new Fill({
            color: 'rgba(252, 86, 49, 0.1)',
          }),
          stroke: new Stroke({
            color: '#fc5531',
            width: 3,
          }),
          image: new Circle({
            radius: 0,
            fill: new Fill({
              color: '#fc5531',
            }),
          }),
        }),
        name: '测量图层',
      })
      this.map.addLayer(this.vectorLayer)
      this.draw = new Draw({
        source: vectorSource,
        type: type,
        maxPoints: maxPoints,
        style: new Style({
          fill: new Fill({
            color: 'rgba(252, 86, 49, 0.1)',
          }),
          stroke: new Stroke({
            color: '#fc5531',
            lineDash: [10, 10],
            width: 3,
          }),
          image: new Circle({
            radius: 0,
            fill: new Fill({
              color: '#fc5531',
            }),
          }),
        }),
        // 绘制时点击处理事件
        condition: (evt) => {
          // 测距时添加点标注
          if (
            this.measureResult != '0' &&
            !this.map.getOverlayById(this.measureResult) &&
            this.measureType == 'distence'
          )
            this.creatMark(
              null,
              this.measureResult,
              this.measureResult
            ).setPosition(evt.coordinate)
          return true
        },
      })
      this.map.addInteraction(this.draw)

      /**
       * 绘制开始事件
       */
      this.draw.on('drawstart', (e) => {
        this.sketchFeature = e.feature
        let proj = this.map.getView().getProjection()
        //******距离测量开始时*****//
        if (this.measureType == 'distence') {
          this.creatMark(null, '起点', 'start').setPosition(
            this.map.getCoordinateFromPixel(e.target.downPx_)
          )
          this.tipDiv.innerHTML = '总长:0 m</br>单击确定地点,双击结束'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              this.measureResult = this.distenceFormat(
                getLength(evt.target, {
                  projection: 'EPSG:3857',
                  radius: 6378137,
                })
              )
              this.tipDiv.innerHTML =
                '总长:' + this.measureResult + '</br>单击确定地点,双击结束'
            })
        }
        //******面积测量开始时*****//
        else if (this.measureType == 'area') {
          this.tipDiv.innerHTML = '面积:0 m<sup>2</sup></br>继续单击确定地点'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              if (evt.target.getCoordinates()[0].length < 4)
                this.tipDiv.innerHTML =
                  '面积:0m<sup>2</sup></br>继续单击确定地点'
              else {
                this.measureResult = this.formatArea(
                  getArea(evt.target, { projection: proj, radius: 6378137 })
                )
                this.tipDiv.innerHTML =
                  '面积:' + this.measureResult + '</br>单击确定地点,双击结束'
              }
            })
        }
        //******角度测量开始时*****//
        else if (this.measureType == 'angle') {
          this.tipDiv.innerHTML = '继续单击确定顶点'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              if (evt.target.getCoordinates().length < 3)
                this.tipDiv.innerHTML = '继续单击确定顶点'
              else {
                this.measureResult = this.formatAngle(evt.target)
                this.tipDiv.innerHTML =
                  '角度:' + this.measureResult + '</br>继续单击结束'
              }
            })
        }
      })

      /**
       * 绘制开始事件
       */
      this.draw.on('drawend', (e) => {
        let closeBtn = document.createElement('span')
        closeBtn.innerHTML = '×'
        closeBtn.title = '清除测量'
        closeBtn.style =
          'width: 10px;height:10px;line-height: 12px;text-align: center;border-radius: 5px;display: inline-block;padding: 2px;color: rgb(255, 68, 0);border: 2px solid rgb(255, 68, 0);background-color: rgb(255, 255, 255);font-weight: 600;position: absolute;top: -25px;right: -2px;cursor: pointer;'
        closeBtn.addEventListener('click', () => {
          this.clearMeasure()
        })
        //******距离测量结束时*****//
        if (this.measureType == 'distence') {
          this.creatMark(closeBtn, null, 'close1').setPosition(
            e.feature.getGeometry().getLastCoordinate()
          )
          this.creatMark(
            null,
            '总长:' + this.measureResult + '',
            'length'
          ).setPosition(e.feature.getGeometry().getLastCoordinate())
          this.map.removeOverlay(this.map.getOverlayById(this.measureResult))
        }
        //******面积测量结束时*****//
        else if (this.measureType == 'area') {
          this.creatMark(closeBtn, null, 'close2').setPosition(
            e.feature
              .getGeometry()
              .getInteriorPoint()
              .getCoordinates()
          )
          this.creatMark(
            null,
            '总面积:' + this.measureResult + '',
            'area'
          ).setPosition(
            e.feature
              .getGeometry()
              .getInteriorPoint()
              .getCoordinates()
          )
        }
        //******角度测量结束时*****//
        else if (this.measureType == 'angle') {
          this.creatMark(closeBtn, null, 'close3').setPosition(
            e.feature.getGeometry().getCoordinates()[1]
          )
          this.creatMark(
            null,
            '角度:' + this.measureResult + '',
            'angle'
          ).setPosition(e.feature.getGeometry().getCoordinates()[1])
        }
        // 停止测量
        this.stopMeasure()
      })
    },
    measure(type) {
      if (this.draw != null) return false // 防止在绘制过程再创建测量
      this.measureType = type
      if (this.vectorLayer != null) this.clearMeasure()
      this.tipDiv = document.createElement('div')
      this.tipDiv.innerHTML = '单击确定起点'
      this.tipDiv.className = 'tipDiv'
      this.tipDiv.style =
        'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;'

      let overlay = new Overlay({
        element: this.tipDiv,
        autoPan: false,
        positioning: 'bottom-center',
        id: 'tipLay',
        stopEvent: false, //停止事件传播到地图
      })
      this.map.addOverlay(overlay)

      this.pointermoveEvent = this.map.on('pointermove', (evt) => {
        overlay.setPosition(evt.coordinate)
      })
      if (this.measureType == 'distence' || this.measureType == 'angle') {
        this.creatDraw('LineString')
      } else if (this.measureType == 'area') {
        this.creatDraw('Polygon')
      }
    },
    creatMark(markDom, txt, idstr) {
      if (markDom == null) {
        markDom = document.createElement('div')
        markDom.innerHTML = txt
        markDom.style =
          'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;'
      }
      let overlay = new Overlay({
        element: markDom,
        autoPan: false,
        positioning: 'bottom-center',
        id: idstr,
        stopEvent: false,
      })
      this.map.addOverlay(overlay)
      return overlay
    },
    distenceFormat(length) {
      let output
      if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km' //换算成km单位
      } else {
        output = Math.round(length * 100) / 100 + ' ' + 'm' //m为单位
      }
      return output //返回线的长度
    },
    formatArea(area) {
      let output
      if (area > 10000) {
        output =
          Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' //换算成km单位
      } else {
        output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>' //m为单位
      }
      return output //返回多边形的面积
    },
    formatAngle(line) {
      var coordinates = line.getCoordinates()
      var angle = '0°'
      if (coordinates.length == 3) {
        const disa = getLength(
          new Feature({
            geometry: new LineString([coordinates[0], coordinates[1]]),
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection(),
          }
        )
        const disb = getLength(
          new Feature({
            geometry: new LineString([coordinates[1], coordinates[2]]),
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection(),
          }
        )

        const disc = getLength(
          new Feature({
            geometry: new LineString([coordinates[0], coordinates[2]]),
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection(),
          }
        )
        var cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb) // 计算cos值
        angle = (Math.acos(cos) * 180) / Math.PI // 角度值
        angle = angle.toFixed(2) // 结果保留两位小数
      }
      if (isNaN(angle)) return '0°'
      else return angle + '°' // 返回角度
    },

    // 停止测量
    stopMeasure() {
      this.tipDiv = null
      this.map.removeInteraction(this.draw) 
      this.draw = null
      this.map.removeOverlay(this.map.getOverlayById('tipLay')) 
    },

    //清除测量
    clearMeasure() {
      this.vectorLayer.getSource().clear()
      this.map.getOverlays().clear()
      //移除监听事件
      unByKey(this.pointermoveEvent) 
      unByKey(this.geometryListener) 
      this.pointermoveEvent = null
      this.geometryListener = null
      this.measureResult = '0'
    },
    // 全屏
    fullscreen() {
      if (this.textarr == '全屏') {
        this.textarr = '缩小'
        let rfs =
          this.$refs.map.requestFullScreen ||
          this.$refs.map.webkitRequestFullScreen ||
          this.$refs.map.mozRequestFullScreen ||
          this.$refs.map.msRequestFullScreen
        if (typeof rfs !== 'undefined' && rfs) {
          rfs.call(this.$refs.map)
          console.log('1全屏')
        } else if (typeof window.ActiveXObject !== 'undefined') {
          // for IE,这里其实就是模拟了按下键盘的F11,使浏览器全屏
          // eslint-disable-next-line no-undef
          let wscript = new ActiveXObject('WScript.Shell')
          console.log(wscript)
          if (wscript != null) {
            wscript.SendKeys('{F11}')
            console.log('3全屏')
          }
          console.log('2全屏')
        }
      } else {
        // el.webkitExitFullscreen()
        this.textarr = '全屏'
        let cfs =
          document.exitFullscreen ||
          document.msExitFullscreen ||
          document.mozCancelFullScreen ||
          document.webkitCancelFullScreen
        console.log(cfs, 'cfs')
        if (typeof cfs !== 'undefined' && cfs) {
          cfs.call(document)
          console.log('4全屏')
        } else if (typeof window.ActiveXObject !== 'undefined') {
          // for IE,这里和fullScreen相同,模拟按下F11键退出全屏
          // eslint-disable-next-line no-undef
          let wscript = new ActiveXObject('WScript.Shell')
          console.log('5全屏')
          if (wscript != null) {
            wscript.SendKeys('{F11}')
            console.log('6全屏')
          }
        }
      }
      // this.map.addControl(new FullScreen())
    },
    // 清除
    clear() {
      this.vectorLayer.getSource().clear()
      this.map.getOverlays().clear()
    },
    zoomIn() {
      let view = this.map.getView()
      let zoom = view.getZoom()
      view.setZoom(zoom + 1)
    },
    zoomOut() {
      let view = this.map.getView()
      let zoom = view.getZoom()
      view.setZoom(zoom - 1)
    },
  },

css样式这玩意就不展示了,菜鸟一个,请多指教


我不会
2 声望0 粉丝

//一杯茶一包烟,一个bug改一天