关于vue.js:Openlayersvue集成实现地图简单功能

57次阅读

共计 12316 个字符,预计需要花费 31 分钟才能阅读完成。

废话不多说,代码端上来

<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 款式这玩意就不展现了,菜鸟一个,请多指教

正文完
 0