欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenLayer基于vue的封裝使用教程

 更新時間:2022年10月12日 14:13:02   作者:GhostPaints  
這篇文章主要介紹了OpenLayer基于vue的封裝使用,openlayer使用的版本是"^6.4.3",引入了mapbox的樣式,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

openlayer是目前我們gis常用的一款開源的,并且反饋都特別好的軟件了,像之前的ol3, 風靡一時,地圖實現(xiàn)也很簡單,很實用,目前vue中使用地圖也是非常多的,那么如果在vue中引入openlayer并且實現(xiàn)地圖撒點效果,甚至是更深層的地圖聚合效果呢,本文來分享下OpenLayer基于vue的封裝使用,感興趣的朋友一起看看吧!

前言

公司項目使用了openlayer作為2d平面地圖來使用,之前沒有接觸過,開一篇文章記錄一下。順便捋一下代碼里面封裝的結(jié)構(gòu)。

基本結(jié)構(gòu) 

openlayer使用的版本是"^6.4.3",引入了mapbox的樣式,"ol-mapbox-style": "^8.2.0"。地圖的初始化專門封裝了一個class類,用于初始化地圖使用。

import Object from 'ol/Object'
import View from 'ol/View'
import Map from 'ol/Map'
 
class EMap extends Object {
  constructor (options) {
    super(options)
    this.options = assignObj({}, options)
    this._view = undefined
    this._baseLayers = []
    this._map = undefined
    this.vectorLayers = []
    this.rasterLayers = []
    this.controls = []
    this._mapClickFunc = options.mapclickFunction
    this._mapEvtBus = options.mapEvtBus
 
    this._interactionsState = {}
    this._initMap()
  }
}

assignObj方法是Object.assign方法,但是剛好ol自己有一個Object類,避免沖突就需要更改一下這個方法名了。

主要結(jié)構(gòu)有這幾種:map地圖,view視圖,layer圖層,controls控制器,mapClickFunc地圖相關(guān)的點擊事件,mapEvtBus地圖事件總線。

_initMap()方法用來初始化地圖。方法代碼內(nèi)容如下:

  _initMap () {
    this._view = this._createView()
    this._baseLayers = this._createBaseLayer()
    this._map = this._createMap()
    this._initMapEvt()
  }

_createView 

_createView()方法用來初始化view視圖。方法代碼內(nèi)容如下:

import {get as getProject} from 'ol/proj' 
 _createView () {
    let viewOptions = assignObj( this._getDefaultViewOptions(), this.options.view)
    if (!viewOptions.projectionCode) {
      viewOptions.projection = 'EPSG:3857'
    } else {
      viewOptions.projection = `EPSG:${viewOptions.projectionCode}`
    }
    delete viewOptions.projectionCode
 
    // let projection = getProject(viewOptions.projection)
    // if (!projection) {
    //  projection = getProject('EPSG:4326')
    // }
    // let projectionExtent = projection.getExtent()
    // let width = getWidth(projectionExtent)
    // let resolutions = []
    // for (let z = 0; z < 25; z++) {
    //   resolutions[z] = width / (256 * Math.pow(2, z))
    // }
 
    // console.log('分辨率1', resolutions)
 
    // viewOptions.resolutions = resolutions
    let view = new View(viewOptions)
    return view
  }

首先通過_getDefaultViewOptions方法,獲取view的一些默認配置,然后將傳入的options的配置使用assign方法進行合并。

然后就是判斷坐標系編碼,這個判斷邏輯可以根據(jù)需要來更改,ol默認的坐標系就是3857,在官網(wǎng)中有說明。

 注釋掉的代碼,是對分辨率進行的處理,根據(jù)需要可以自行添加進去。

_getDefaultViewOptions()方法存儲一些默認配置,比如中心點,坐標系,縮放這種。

_getDefaultViewOptions() {
  let options = {
    projectionCode: '3857',
    center: [120, 69],
    zoom: 5
  }
  return options
}

如果地圖的配置項是通過接口獲取數(shù)據(jù),那默認配置最好和接口返回的數(shù)據(jù)對應(yīng),這樣即使接口中有某個數(shù)據(jù)沒法通過校驗,就可以使用默認值了。校驗方法放在_createView中和默認配置分開,邏輯會清晰點,不會擠在同一個方法里面。

_createBaselayer

_createBaselayer()方法主要是創(chuàng)建底圖,底圖可能是天地圖,mapbox,高德,百度等,因此不同的底圖執(zhí)行的代碼邏輯是不一樣的,需要加判斷分別處理。

  _createBaseLayer () {
    const baseLayerOptions = this.options.baseLayer
    if (!baseLayerOptions.type ) {
      baseLayerOptions.type = 'mapbox'
    }
 
    if (baseLayerOptions.type === 'tianditu') {
      return this._createTianDiTuLayers(baseLayerOptions)
    } else if (baseLayerOptions.type === 'mapbox') {
      return this._createMapBoxLayers(baseLayerOptions)
    } else {
      return this._createXYZLayer(baseLayerOptions)
    }
  }

以處理天地圖_createTianDiTuLayers為例,通過接口請求到的底圖參數(shù)中有一個baseLayer屬性,存儲一個對象,除了攜帶type屬性外,還有對應(yīng)的token信息。

import {createXYZ} from 'ol/tilegrid'
import Tile from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
 
_createTianDiTuLayers() {
    const tdtToken = baseLayerOptions.tdtToken
    const baseURL = 'http://t{0-7}.tianditu.gov.cn/'
    const layerOptions = [
      {
        title: '天地圖矢量',
        layerName: 'vec_c',
        attributions: '右下角署名',
        visible: true,
        type: 'vec'
      },
      {
        title: '天地圖矢量注記',
        layerName: 'cva_c',
        attributions: '',
        visible: true,
        type: 'vec'
      },
      {
        title: '天地圖衛(wèi)星影像',
        layerName: 'img_c',
        attributions: '右下角署名',
        visible: false,
        type: 'img'
      },
      {
        title: '天地圖衛(wèi)星影像注記',
        layerName: 'cia_c',
        attributions: '',
        visible: false,
        type: 'img'
      },
    ]
}

底圖可以是多個圖層疊加的,因此baseLayers是一個數(shù)組。layerOptions存儲了一些天地圖的信息,通過visible設(shè)置是否啟用,一般是矢量圖或者圖片加上對應(yīng)的標注。

    var projection = new getProject('EPSG:3857')
 
    let tilegrid = createXYZ({
      extent: projection.getExtent()
    })
 
    const layers = layerOptions.map((item) => {
      let layerType = item.layerName.split('_')
      const url = `${baseURL}${item.layerName}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layerType[0]}&STYLE=default&TILEMATRIXSET=${layerType[1]}&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${tdtToken}`
      const attributions = item.attributions === '' ? undefined : `? <a  target="_blank">${item.attributions}</a>`
      const layer = new Tile({
        title: item.title,
        source: new XYZ({
          attributions: attributions,
          url: url,
          wrapx: false,
          crossOrigin: 'anonymous',
          projection: projection,
          tileGrid: tilegrid
        }),
        minZoom: 0,
        maxZoom: 20
      })
      layer.setProperties({
        layerType: item.type,
        isBaseLayer: true
      })
      layer.setVisible(item.visible)
      return layer
    })

最主要的內(nèi)容還是layer,使用ol/layer/Tile設(shè)置標題,數(shù)據(jù)源,最大最小縮放,tileGrid根據(jù)坐標系設(shè)置范圍。openlayer的圖層添加后,會在右下角有一個感嘆號,里面的內(nèi)容就是由source的attributions來定義的。crossOrigin是設(shè)置canvas的跨域?qū)傩浴dn對它有解釋,它有三種值可以設(shè)置。

是h5的特性支持,和openlayer無關(guān)就是了。

為layer設(shè)置了兩個值,這兩個值本身是沒有的,用setProperties添加進去。后續(xù)可以使用getProperties()來獲取這兩個值。根據(jù)設(shè)置好的visible設(shè)置layer的可見性。這樣關(guān)于天地圖的底圖設(shè)置邏輯就完成了。 

_createMap

_createMap()方法創(chuàng)建map地圖,添加一些控件,代碼中添加了一個比例尺

import ScaleLine from 'ol/control/ScaleLine'
import { defaults } from 'ol/control'
 
  _createMap () {
    const map = new Map({
      target: this.options.target,
      view: this._view,
      layers: this._baseLayers,
      controls: new defaults({
        attribution: true,
        attributionOptions: {
          tipLabel: '信息'
        },
        zoomOptions: {
          zoomInTipLabel: '放大',
          zoomOutTipLabel: '縮小',
        }
      })
    })
    const scale = new ScaleLine({
      bar: true, 
      text: true, 
      minWidth: 125
    })
    map.addControl(scale)
    return map
  }

 _initMapEvt

_initMapEvt()處理地圖的一些控制和交互功能。

  _initMapEvt () {
    this._initMapControl()
    this._initMapClickEvent()
    this._initPointMoveEvent()
  }

 _initMapControl

_initMapControl()方法主要是去除一些容易和后面的操作沖突的事件。

import DoubleClickZoom from 'ol/interaction/DoubleClickZoom'
 
  _initMapControl () {
    // 移除雙擊縮放控件(與雙擊彈屬性窗沖突)
    let controls = this._map.getInteractions()
    let dbClickZoomControl = controls.getArray().find((control) => control instanceof DoubleClickZoom)
    if(dbClickZoomControl) {
      this._map.removeInteraction(dbClickZoomControl)
    }
 
    this._singleClickControl = new Select({
      condition: function (evt) {
        return evt.type === 'singleclick' || evt.type === 'dblclick'
      },
      // style: this._singleClickStyle.bind(this), // 如果需要自定義每個圖層的選中樣式,請開啟這個屬性
      layers: function (layer) {
        const layerName = layer.rootLayerName
        return this.findLayer(this.vectorLayers, layerName)
      }.bind(this)
    })
 
    var selectedFeatures = this._singleClickControl.getFeatures()
    selectedFeatures.on(['add','remove'], (evt) => {
      this.dispatchEvent({
        type: 'selectDataChanged',
        target: selectedFeatures,
        element: evt.element,
        option: evt.type
      })
    })
 
    if(this._map) {
      this._map.addInteraction(this._singleClickControl)
    }
  }

 使用getInteractions()獲取到所有交互,用類型檢測出雙擊事件,然后移除。再加入自定義的singleClickControl,在add和remove的時候觸發(fā)。

 _initMapClickEvent()

  _initMapClickEvent () {
    this._map.on('click', (evt) => {
      // 單擊事件優(yōu)先選擇控件中的單擊選中事件
      const features = this._map.getFeaturesAtPixel(evt.pixel)
      if(features.length > 0) {
        features.forEach((ft) => {
          // map上的單擊事件和layer的單擊事件,取其一,優(yōu)先map
          if(this._mapClickFunc) {
            this._mapClickFunc({
              data: ft,
              evt: evt
            })
          } else {
            const layerName = ft.get('layerName')
            const eLayer = this.findLayer(this.vectorLayers, layerName)
            if(eLayer) {
              eLayer._singleClick(ft, evt)
            }
          }
        })
      } else {
        if(this._mapClickFunc) {
          this._mapClickFunc({
            data: undefined,
            evt: evt
          })
        }
      }
    })
 
    this._map.on('dblclick', (evt) => {
      const features = this._map.getFeaturesAtPixel(evt.pixel)
      if (features.length > 0) {
        features.forEach((ft) => {
          const layerName = ft.get('layerName')
          const eLayer = this.findLayer(this.vectorLayers, layerName)
          if(eLayer) {
            eLayer._dbClick(ft, evt)
          }
        })
      }
    })
  }

_initMapClickEvent()主要處理單擊和雙擊事件,后續(xù)加入進去的layer圖層可以自己定義單擊事件。初始化map對象的時候,也可以自己傳入mapClickFunc。代碼中優(yōu)先取map的單擊事件。

findLayer方法為自定義方法,主要是通過layername拿到對應(yīng)的layer。

_initPointMoveEvent

  _initPointMoveEvent () {
    this._map.on('pointermove', (evt) => {
      const features = this._map.getFeaturesAtPixel(evt.pixel)
      if(features.length > 0) {
        this._map.getTargetElement().style.cursor = 'pointer'
      } else {
        this._map.getTargetElement().style.cursor = 'auto'
      }
    })
  }

 _initPointMoveEvent()方法,當鼠標移動到某個features上時候,鼠標形狀改變。用來告訴用戶,鼠標位置存在可以交互的東西。

然后就是一些普通的getter和setter方法。可以按自己喜好多封裝一些常用的。

  getOlMap () {
    return this._map
  }
 
  getView () {
    return this._view
  }
 
  getMapProjection () {
    return this.getView().getProjection()
  }
 
  getZoom () {
    if(this._view) {
      return this._view.getZoom()
    }
  }
 
  getBaseLayers () {
    return this._baseLayers
  }
 
  setZoom (zoom) {
    if (this._view) {
      this._view.setZoom(zoom)
    }
  }
 
  setCenter (point) {
    this._view.setCenter(point)
  }
 
  setView (view) {
    this._map.setView(view)
    this._view = view
  }
 
  zoomToNext () {
    let zoom = this.getZoom()
    zoom = parseInt(zoom)
    this.setZoom(zoom + 1)
  }
 
  fit (geom) {
    this._view.fit(geom)
  }
 
  fitToLayer (eLayer) {
    if(eLayer.getDataExtent) {
      const extent = eLayer.getDataExtent()
      const resolution = this._view.getResolution()
      // 范圍縮小一點,要不然碰到地圖邊界
      extent[0] = extent[0] - 1 * resolution
      extent[1] = extent[1] - 1 * resolution
      extent[2] = extent[2] + 1 * resolution
      extent[3] = extent[3] + 1 * resolution
      if (extent) {
        this.fit(extent)
      }
    }
  }
 
  zoomToPrevious () {
    let zoom = this.getZoom()
    zoom = parseInt(zoom)
    this.setZoom(zoom - 1)
  }
 
  getExtent () {
    return this._view.calculateExtent(this._map.getSize())
  }

地圖的初始化操作就這么多,接下來就是一些layer圖層上面的添加,查找,移除的操作。

import _ from 'lodash'
 
  addLayer (eLayer) {
    const layer = eLayer.getLayer()
    if (layer) {
      if (eLayer.get('eLayerType') === layerDataType.vector) {
        if (!this.findLayer(this.vectorLayers, eLayer.get('layerName'))) {
          this.vectorLayers.push(eLayer)
          this._map.addLayer(layer)
        } else {
          console.log('layer is exist')
        }
      } else if (eLayer.get('eLayerType') === layerDataType.raster ) {
        if (!this.findLayer(this.rasterLayers, eLayer.get('layerName'))) {
          this.rasterLayers.push(eLayer)
          this._map.addLayer(layer)
        } else {  
          console.log('layer is exist')
        }
      } else {
        console.log('layer is not eMapLayer...')
      }
    }
  }
 
  findLayer (layerList, layerName) {
    if (layerList) {
      const layer = _.find(layerList, (layer) => {
        return layer.get('layerName') === layerName
      })
      return layer
    }
    return null
  }
 
  removeLayer (eLayer) {
    const layer = eLayer.getLayer()
    if (layer) {
      if (eLayer.get('eLayerType') === layerDataType.vector) {
        _.remove(this.vectorLayers, (layer) => {
          return layer === eLayer
        })
        this._map.removeLayer(layer)
      } else if(eLayer.get('eLayerType') === layerDataType.raster) {
        _.remove(this.rasterLayers, (layer) => {
          return layer === eLayer
        })
        this._map.removeLayer(layer)
      } else {
        console.log('layer is not eMapLayer...')
      }
    }
  }
 
  removeLayerByName (layerName) {
    let eLayer = this.findLayer(this.vectorLayers, layerName)
    if (eLayer) {
      this.removeLayer(eLayer)
    } else {
      eLayer = this.findLayer(this.rasterLayers, layerName)
      if (eLayer) {
        this.removeLayer(eLayer)
      }
    }
  }

后面layer圖層也會進行一次封裝,有一個eLayerType的字符串值,決定是放在哪個圖層數(shù)組里面。名稱不能重復(fù),如果檢測到重復(fù)名稱說明圖層已經(jīng)添加過了,就不會重新添加了。

當存在一些編輯功能的時候,防止沖突,就要停止和恢復(fù)一些交互功能。封裝兩個方法。

  /**
   * 暫停作用域以外的交互控件(默認不暫停)
   * @param {string}} scope 
   */
  pauseInteraction (scope) {
    let interactions = this._map.getInteractions()
    interactions.forEach((itc) => {
      if(!itc.rootName) {
        return
      }
      if(itc.rootName !== scope) {
        let id = itc.ol_uid
        this._interactionsState[id] = itc.getActive()
        itc.setActive(false)
      }
    })
  }
 
  resumeInteraction () {
    let interactions = this._map.getInteractions()
    interactions.forEach((itc) => {
      if(itc.rootName) {
        let id = itc.ol_uid
        let active = this._interactionsState[id]
        if(active) {
          itc.setActive(active)
        }
      }
    })
  }

單擊顯示的數(shù)據(jù)

  showDetail (data, zoom, point, id, geomType) {
    if (this._mapEvtBus) {
      const options = {
        data,
        zoom,
        point,
        id,
        geomType
      }
      this._mapEvtBus.$emit('showDetail', options)
    }
  }

到此這篇關(guān)于OpenLayer基于vue的封裝使用的文章就介紹到這了,更多相關(guān)vue OpenLayer內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue實現(xiàn)驗證碼倒計時按鈕

    vue實現(xiàn)驗證碼倒計時按鈕

    這篇文章主要為大家詳細介紹了vue實現(xiàn)驗證碼倒計時按鈕,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • vue項目動態(tài)渲染input,綁定的參數(shù)不實時更新問題

    vue項目動態(tài)渲染input,綁定的參數(shù)不實時更新問題

    這篇文章主要介紹了vue項目動態(tài)渲染input,綁定的參數(shù)不實時更新問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue項目中form?data形式傳參方式

    vue項目中form?data形式傳參方式

    這篇文章主要介紹了vue項目中form?data形式傳參方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue實現(xiàn)div拖拽互換位置

    vue實現(xiàn)div拖拽互換位置

    這篇文章主要為大家詳細介紹了vue實現(xiàn)div拖拽互換位置的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • 解決vue中修改export default中腳本報一大堆錯的問題

    解決vue中修改export default中腳本報一大堆錯的問題

    今天小編就為大家分享一篇解決vue中修改export default中腳本報一大堆錯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • vuex與map映射實現(xiàn)方法梳理分析

    vuex與map映射實現(xiàn)方法梳理分析

    Vuex中的映射允許您將state中的任何屬性(state、getter、mutation和action)綁定到組件中的計算屬性,并直接使用state中的數(shù)據(jù),下面我們來詳細了解
    2022-09-09
  • Vue3 封裝回到頂部組件的實現(xiàn)示例

    Vue3 封裝回到頂部組件的實現(xiàn)示例

    回到頂部在很多網(wǎng)頁中都可以見到,本文主要介紹了Vue3 封裝回到頂部組件的實現(xiàn)示例,文中根據(jù)實例編碼詳細介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Vue表單驗證插件的制作過程

    Vue表單驗證插件的制作過程

    這篇文章主要為大家詳細介紹了Vue表單驗證插件的制作過程,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • vue中設(shè)置echarts寬度自適應(yīng)的代碼步驟

    vue中設(shè)置echarts寬度自適應(yīng)的代碼步驟

    這篇文章主要介紹了vue中設(shè)置echarts寬度自適應(yīng)的問題及解決方案,常常需要做到echarts圖表的自適應(yīng),一般是根據(jù)頁面的寬度做對應(yīng)的適應(yīng),本文記錄一下設(shè)置echarts圖表的自適應(yīng)的步驟,需要的朋友可以參考下
    2022-09-09
  • VUE 文字轉(zhuǎn)語音播放的實現(xiàn)示例

    VUE 文字轉(zhuǎn)語音播放的實現(xiàn)示例

    本文主要介紹了VUE 文字轉(zhuǎn)語音播放的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評論