开源

Vue.js+OpenLayers 4、添加自定义矢量标注

2020-05-09  本文已影响0人  e20a12f8855d

一、添加标注功能方法封装

添加矢量标注所需依赖,并封装方法。

InitMap.vue

/* eslint-disable no-unused-vars */
import mapConfig from '@/mapConfig' // 地图配置
import "ol/ol.css"
import Map from "ol/Map"
import View from "ol/View"
import TileLayer from "ol/layer/Tile"
import TileWMS from "ol/source/TileWMS"
import OSM from "ol/source/OSM"
import { defaults as defaultControls } from 'ol/control'
import ZoomSlider from 'ol/control/ZoomSlider' // 缩放控制
import WMSGetFeatureInfo from 'ol/format/WMSGetFeatureInfo'

// 添加图标相关
import OlFeature from 'ol/Feature'
import OlGeomPoint from 'ol/geom/Point'
import OlLayerVector from 'ol/layer/Vector'
import OlSourceVector from 'ol/source/Vector'
import OlStyleStyle from 'ol/style/Style'
import OlStyleIcon from 'ol/style/Icon'
// 添加相关文字描述
import Text from 'ol/style/Text'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'

export default {

  methods: {
    // 移除自定义矢量标注图层
    removeIconLayer(data) {
      if (data.length) {
        for (let i = 0; i < data.length; i++) {
          this.map.removeLayer(this.getLayerByName(data[i].address))
        }
      } else {
        this.map.removeLayer(this.getLayerByName(data.address))
      }
    },

    // 添加自定义矢量标注图层
    addIconLayer(data, ID) {
      if (data.length) {
        // 多个点
        let nData = data.filter((item) => {
          // 过滤出没有坐标信息的点
          return item.x && item.y
        })
        for (let i = 0; i < nData.length; i++) {
          if (nData[i].x && nData[i].y) {
            this.addCustomPoniter(nData[i], ID)
          }
        }
      } else {
        // 单个点
        if (data.x && data.y) {
          this.addCustomPoniter(data, ID)
        }
      }
    },

    // 添加自定义矢量标注
    addCustomPoniter(data, ID) {
      let iconOption = {}
      switch (ID) {
        case '网格员':
          iconOption = {
            src: require('@/assets/icon02.png'),
            scale: 1
          }
          break
        default:
          iconOption = {
            src: require('@/assets/ico.png'),
            scale: 1
          }
      }
      let vectorLayer = null // 矢量图层
      let startMarker = new OlFeature({
        type: 'icon',
        id: ID, // 通过指定的 ID 去查找对应图层的 layerName 做请求
        geometry: new OlGeomPoint([data.x, data.y])

      })
      vectorLayer = new OlLayerVector({
        source: new OlSourceVector({
          features: [startMarker]
        }),
        style: new OlStyleStyle({
          image: new OlStyleIcon({
            // anchor: [0.5, 1],
            src: iconOption.src,
            scale: iconOption.scale || 1
          }),
          // 设置图片下面显示字体的样式和内容
          text: new Text({
            font: '14px sans-serif', // 设置字体
            maxAngle: 30,
            offsetx: 10, // 设置文字偏移量
            offsetY: 10,
            text: data.address,// 文字描述
            fill: new Fill({ // 字体颜色
              color: '#000'
            }),
            stroke: new Stroke({ // 文字描边
              color: '#fff',
              width: 5
            })
          })
        }),
        zIndex: 9,
        name: data.address
      })
      this.map.removeLayer(this.getLayerByName(data.address)) // 先移除一次,防止多次点击图层覆盖
      this.map.addLayer(vectorLayer)
    },

    // 根据 name 获取 mapConfig.js 中的 layerName,作为点击标注获取详细信息的请求条件
    getLayerNameFromConf(name) {
      let layers = mapConfig.map.layers
      let nameArr = []
      for (let i = 0; i < layers.length; i++) {
        nameArr.push(layers[i].name)
      }
      let index = nameArr.indexOf(name)
      return layers[index].layerName
    },

    // 地图单击事件
    singleClickFun(view) {
      this.map.on('singleclick', (event) => {
        // 点击标注
        if (this.map.hasFeatureAtPixel(event.pixel)) {
          let feature = this.map.getFeaturesAtPixel(event.pixel)
          let layerName = feature[0].values_.id
          let LAYERS = this.getLayerNameFromConf(layerName)
          let wmsSource = new TileWMS({
            url: "geoserver/geoserver/DLQ/wms", // 跨域访问(获取点击的详细信息,出现跨域问题,本地测试做了代理)
            params: { LAYERS: LAYERS, TILED: true },
            serverType: "geoserver",
            transition: 0,
          })
          let viewResolution = (view.getResolution())
          let url = wmsSource.getFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:4326',
            { 'INFO_FORMAT': 'application/json' })
          if (url) {
            fetch(url)
              .then((response) => {
                return response.json()
              })
              .then((data) => {
                console.log(data)
              })
          }
        }
        else {
          let wmsSource = new TileWMS({
            // 怎么针对某个图层做点击事件?点击需要传对应图层的 name,如果有多个图层,怎么判断点击的是哪个图层?
            url: "geoserver/geoserver/DLQ/wms", // 跨域访问(获取点击的详细信息,出现跨域问题,本地测试做了代理)
            params: { LAYERS: 'DLQ:DLQFHR', TILED: true },
            serverType: "geoserver",
            transition: 0,
          })
          let viewResolution = (view.getResolution())
          let url = wmsSource.getFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:4326',
            { 'INFO_FORMAT': 'application/json' })
          if (url) {
            fetch(url)
              .then((response) => {
                return response.json()
              })
              .then((data) => {
                console.log(data)
              })
          }
        }
      })
    },

  }
}
</script>

二、传递点位信息

模拟一些点位做测试。

MapMain.vue

  data() {
    return {
      clickFlag: false,
      fhrData: [
        {
          address: '昆俞北路明旭社区明盛园4号楼',
          x: 117.29548,
          y: 39.16232
        },
        {
          address: '津北公路',
          x: 117.432727,
          y: 39.080622
        },
        {
          address: '华明街弘顺道金泰丽湾嘉园7号楼',
          x: 117.365064,
          y: 39.163788
        }
      ]
    }
  },
  methods: {
    // 添加自定义标注
    addCustomPoniter() {
      // 单个点
      let point = {
        x: 117.3671,
        y: 39.17287,
        name: 'test',
        address: 'test'
      }
      this.$refs.InitMap.addIconLayer(point, '网格员')

      // 多个点
      this.$refs.InitMap.addIconLayer(this.fhrData, '房户人')
    },
    // 移除自定义标注
    removeCustomPoniter() {
      this.$refs.InitMap.removeIconLayer(this.buildingData)
    },

  }
image

三、完整的 InitMap.vue

<template>
  <div></div>
</template>
<script>
/* eslint-disable no-unused-vars */
import mapConfig from '@/mapConfig' // 地图配置
import "ol/ol.css"
import Map from "ol/Map"
import View from "ol/View"
import TileLayer from "ol/layer/Tile"
import TileWMS from "ol/source/TileWMS"
import OSM from "ol/source/OSM"
import { defaults as defaultControls } from 'ol/control'
import ZoomSlider from 'ol/control/ZoomSlider' // 缩放控制
import WMSGetFeatureInfo from 'ol/format/WMSGetFeatureInfo'

// 添加图标相关
import OlFeature from 'ol/Feature'
import OlGeomPoint from 'ol/geom/Point'
import OlLayerVector from 'ol/layer/Vector'
import OlSourceVector from 'ol/source/Vector'
import OlStyleStyle from 'ol/style/Style'
import OlStyleIcon from 'ol/style/Icon'
// 添加相关文字描述
import Text from 'ol/style/Text'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'

export default {
  name: 'InitMap',
  data() {
    return {
      map: null
    }
  },
  mounted() {
    this.initMap()
    // this.getAllFeaturesByXML()
  },
  methods: {
    // 移除自定义矢量标注图层
    removeIconLayer(data) {
      if (data.length) {
        for (let i = 0; i < data.length; i++) {
          this.map.removeLayer(this.getLayerByName(data[i].address))
        }
      } else {
        this.map.removeLayer(this.getLayerByName(data.address))
      }
    },

    // 添加自定义矢量标注图层
    addIconLayer(data, ID) {
      if (data.length) {
        // 多个点
        let nData = data.filter((item) => {
          // 过滤出没有坐标信息的点
          return item.x && item.y
        })
        for (let i = 0; i < nData.length; i++) {
          if (nData[i].x && nData[i].y) {
            this.addCustomPoniter(nData[i], ID)
          }
        }
      } else {
        // 单个点
        if (data.x && data.y) {
          this.addCustomPoniter(data, ID)
        }
      }
    },

    // 添加自定义矢量标注
    addCustomPoniter(data, ID) {
      let iconOption = {}
      switch (ID) {
        case '网格员':
          iconOption = {
            src: require('@/assets/icon02.png'),
            scale: 1
          }
          break
        default:
          iconOption = {
            src: require('@/assets/ico.png'),
            scale: 1
          }
      }
      let vectorLayer = null // 矢量图层
      let startMarker = new OlFeature({
        type: 'icon',
        id: ID, // 通过指定的 ID 去查找对应图层的 layerName 做请求
        geometry: new OlGeomPoint([data.x, data.y])

      })
      vectorLayer = new OlLayerVector({
        source: new OlSourceVector({
          features: [startMarker]
        }),
        style: new OlStyleStyle({
          image: new OlStyleIcon({
            // anchor: [0.5, 1],
            src: iconOption.src,
            scale: iconOption.scale || 1
          }),
          // 设置图片下面显示字体的样式和内容
          text: new Text({
            font: '14px sans-serif', // 设置字体
            maxAngle: 30,
            offsetx: 10, // 设置文字偏移量
            offsetY: 10,
            text: data.address,// 文字描述
            fill: new Fill({ // 字体颜色
              color: '#000'
            }),
            stroke: new Stroke({ // 文字描边
              color: '#fff',
              width: 5
            })
          })
        }),
        zIndex: 9,
        name: data.address
      })
      this.map.removeLayer(this.getLayerByName(data.address)) // 先移除一次,防止多次点击图层覆盖
      this.map.addLayer(vectorLayer)
    },

    // 根据 name 获取 mapConfig.js 中的 layerName,作为点击标注获取详细信息的请求条件
    getLayerNameFromConf(name) {
      let layers = mapConfig.map.layers
      let nameArr = []
      for (let i = 0; i < layers.length; i++) {
        nameArr.push(layers[i].name)
      }
      let index = nameArr.indexOf(name)
      return layers[index].layerName
    },

    // 地图单击事件
    singleClickFun(view) {
      this.map.on('singleclick', (event) => {
        // 点击标注
        if (this.map.hasFeatureAtPixel(event.pixel)) {
          let feature = this.map.getFeaturesAtPixel(event.pixel)
          let layerName = feature[0].values_.id
          let LAYERS = this.getLayerNameFromConf(layerName)
          let wmsSource = new TileWMS({
            url: "geoserver/geoserver/DLQ/wms", // 跨域访问(获取点击的详细信息,出现跨域问题,本地测试做了代理)
            params: { LAYERS: LAYERS, TILED: true },
            serverType: "geoserver",
            transition: 0,
          })
          let viewResolution = (view.getResolution())
          let url = wmsSource.getFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:4326',
            { 'INFO_FORMAT': 'application/json' })
          if (url) {
            fetch(url)
              .then((response) => {
                return response.json()
              })
              .then((data) => {
                console.log(data)
              })
          }
        }
        else {
          let wmsSource = new TileWMS({
            // 怎么针对某个图层做点击事件?点击需要传对应图层的 name,如果有多个图层,怎么判断点击的是哪个图层?
            url: "geoserver/geoserver/DLQ/wms", // 跨域访问(获取点击的详细信息,出现跨域问题,本地测试做了代理)
            params: { LAYERS: 'DLQ:DLQFHR', TILED: true },
            serverType: "geoserver",
            transition: 0,
          })
          let viewResolution = (view.getResolution())
          let url = wmsSource.getFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:4326',
            { 'INFO_FORMAT': 'application/json' })
          if (url) {
            fetch(url)
              .then((response) => {
                return response.json()
              })
              .then((data) => {
                console.log(data)
              })
          }
        }
      })
    },

    // 切换图层
    changeLayer(name, flag) {
      let layer = this.getLayerByName(name)
      this.setLayerVisible(layer, flag)
    },

    // 设置图层显隐
    setLayerVisible(layer, flag) {
      switch (flag) {
        case true:
          layer.setVisible(true)
          break
        case false:
          layer.setVisible(false)
          break
      }
    },

    // 根据图层名称获取图层
    getLayerByName(name) {
      let layers = this.map.getLayers().array_
      let nameArr = []
      let targetIndex = -1
      for (let i = 0; i < layers.length; i++) {
        nameArr.push(layers[i].values_.name)
      }
      targetIndex = nameArr.indexOf(name)
      return layers[targetIndex]
    },

    // 获取所有图层
    getAllTileLayers() {
      let allLayers = mapConfig.map.layers
      for (let i = 0; i < allLayers.length; i++) {
        if (!allLayers[i].layerName) {
          // 没有 GeoServer 用的是 OSM
          let layer = new TileLayer({
            source: new OSM(),
            visible: allLayers[i].visible,
            zIndex: allLayers[i].zIndex,
            name: allLayers[i].name
          })
          this.map.addLayer(layer)
        } else {
          let layer = new TileLayer({
            source: new TileWMS({
              url: mapConfig.map.geoserver,
              params: { LAYERS: allLayers[i].layerName, TILED: true },
              serverType: "geoserver",
              transition: 0,
            }),
            visible: allLayers[i].visible,
            zIndex: allLayers[i].zIndex,
            name: allLayers[i].name
          })
          this.map.addLayer(layer)
        }
      }
    },

    // 初始化地图
    initMap() {
      let view = new View(mapConfig.map.view)
      this.map = new Map({
        layers: [],
        target: "map",
        view: view,
        controls: defaultControls().extend([new ZoomSlider()]) // 缩放控制
      })
      this.getAllTileLayers() // 获取所有图层
      this.singleClickFun(view) // 地图单击事件
    }

  }
}
</script>
上一篇 下一篇

猜你喜欢

热点阅读