openlayers 图层管理(2) | 「掘金日新计划 · 12 月更文挑战」

247 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

前段时间第一次使用openlayers开发了一个应急系统的可视化,本编文章大致记录一下在项目中封装的图层管理部分的相关功能代码。

image.png

功能描述

  • 动态添加图层:能支持不同类型的图层动态叠加上图展示【文中会遇到的图层类型有Arcgis dynamic动态服务、Arcgis tile切片服务、geojson矢量数据、 image图片、矢量MVT服务'】
  • 动态移动图层层级:支持点击上下移动图标移动图层显示层级【Zindex】
  • 动态设置图层透明度:支持滑动透明度滑竿改变图层透明度【Opacity】
  • 动态设置图层可见与否:点击眼睛小图标设置图层是否可见【Visible】
  • 动态移除图层:点击回收站小图标移除图层【removeLayer】

上篇文章出于时间原因写了部图层添加,可以看这里 这篇文章我们继续把剩下的内容讲清楚

geojson矢量数据

const vectorSource = new ol.source.Vector({
          crossOrigin: 'anonymous',
          features: new ol.format.GeoJSON().readFeatures(geojson) 传入geojson格式数据
       })
const vectorLayer = new ol.layer.Vector({
  title,
  zIndex,
  source: vectorSource,
  style:new Style({
    fill: new Fill({
      color: 'red'//填充颜色
    }),
    stroke: new Stroke({
      color: 'white'//边框颜色
    })
  })
})

viewer.addLayer(vectorLayer)

添加矢量MVT服务

MVT全称 Mapbox Vector Tile,是Mapbox标准的矢量切片。矢量瓦片具有创建效率高、传输和渲染速度快、数据和风格样式独立,更改配图方案无需重新创建瓦片、高显示质量,能够很好地支持高分辨率显示屏等特点.

 /**
     * 加载矢量MVT服务
     * @param data 服务参数
     * viewer 地图实例
     */
  addmvtLayer (data, viewer) {
    let { serviceURL } = data.attributes
    let projection = ol.proj.get('EPSG:4326')
    let mvtLayer = new ol.layer.VectorTile({
      title: data.text,
      opacity: data.attributes.opacity || 1,
      zIndex: this.getlayerZindex(viewer),
      declutter: true,
      source: new ol.source.VectorTile({
        crossOrigin: 'anonymous',
        format: new ol.format.MVT(),
        // 格网我这里写死了,我这里由于展示的都是全国地区的数据,
        // 大家可以根据自己的实际情况去修改调整
        tileGrid: new ol.tilegrid.TileGrid({
          extent: [-180, -90, 180, 90],
          origin: [-180, 90],
          tileSize: [512, 512],
          resolutions: [
            0.3515625,
            0.17578125,
            0.087890625,
            0.0439453125,
            0.02197265625,
            0.010986328125,
            0.0054931640625,
            0.00274658203125,
            0.001373291015625,
            0.0006866455078125,
            0.00034332275390625,
            0.000171661376953125,
            0.0000858306884765625,
            0.00004291534423828125,
            0.000021457672119140625,
            0.000010728836059570312,
            0.000005364418029785156,
            0.000002682209014892578,
            0.000001341104507446289,
            6.705522537231445e-7,
            3.3527612686157227e-7,
            1.6763806343078613e-7
          ]
        }),
        url: `${serviceURL}/{z}/{x}/{y}`, mvt地
        projection: projection
      }),
      style: createMapboxStreetsV6Style()  // 根据矢量属性信息动态设置渲染样式
    })
    viewer.addLayer(mvtLayer)
  }

createMapboxStreetsV6Style是根据矢量属性中去动态生成样式,其就是一个styleFunction,其好处就是可以无限扩展,并且杂渲染效率和速度上都有很大的优势。下面给提供一个示例

function createMapboxStreetsV6Style () {
  let fill = new ol.style.Fill({
    color: ''
  })
  let stroke = new ol.style.Stroke({
    color: '',
    width: 1
  })
  let polygon = new ol.style.Style({
    fill: fill
  })
  let strokedPolygon = new ol.style.Style({
    fill: fill,
    stroke: stroke
  })
  let line = new ol.style.Style({
    stroke: stroke
  })
  let text = new ol.style.Style({
    text: new ol.style.Text({
      text: '',
      fill: fill,
      stroke: stroke
    })
  })

  // 红色填充
  let redfill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#fe0000'
    })
  })
  // 橙色
  let orangefill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#ffa903'
    })
  })
  // 黄
  let yellowfill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#fffd08'
    })
  })
  // 蓝
  let bluefill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#0071fe'
    })
  })

  // 山洪可能发生 利用ol-ext 插件扩展更多的渲染样式
  const shonghongPossible = new ol.style.Style({
    fill: new ol.style.FillPattern(
      {
        pattern: 'hatch',
        image: undefined,
        ratio: 1,
        icon: undefined,
        color: '#0070FF',
        offset: 0,
        scale: 1,
        fill: new ol.style.Fill({ color: 'rgba(255,255,255,0)' }),
        size: 2,
        spacing: 5,
        angle: 90
      }),
    stroke: new ol.style.Stroke({
      color: '#0070FF',
      width: 2
    })
  })
 

  // 渍涝风险 黄色预警  这里还可以自行通过canvas 去绘制生成 渲染样式
  const zilaofengxSlightlyfill = (function () {
    let canvas = document.createElement('canvas')
    let context = canvas.getContext('2d')
    canvas.width = 11
    canvas.height = 11
    // 背景
    context.fillStyle = 'rgba(255,255,255,0)'
    context.fillRect(0, 0, canvas.width, canvas.height)
    // 内圈颜色
    context.fillStyle = 'rgba(255,255,1,1)'
    context.beginPath()
    context.arc(5, 5, 4, 0, 2 * Math.PI)
    context.fill()
    // // 内部实心颜色
    // context.fillStyle = 'rgb(55, 0, 170)'
    // context.beginPath()
    // context.arc(5, 5, 2, 0, 2 * Math.PI)
    // context.fill()
    return context.createPattern(canvas, 'repeat')
  }())

  const zilaofengxSlightly = new ol.style.Style({
    fill: new ol.style.Fill({
      color: zilaofengxSlightlyfill
    }),
    stroke: new ol.style.Stroke({
      color: '#FFFF01',
      width: 2
    })
  })

 
  // 全国短时强降水预警
  const qgdsqjsyjFill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#ffffff00'
    }),
    stroke: new ol.style.Stroke({
      color: '#38a800',
      width: 1.5
    })
  })

  // 全国风暴大风或冰雹预警
  const qgfbdfhbbyjFill = new ol.style.Style({
    fill: new ol.style.Fill({
      color: '#ffffff00'
    }),
    stroke: new ol.style.Stroke({
      color: '#e60000',
      width: 1.5
    })
  })
  var styles = []
  return function (feature, resolution) {
    // 自定义渲染 根据获取的属性去选择上方已定义好的样式
    var length = 0
    var layer = feature.get('layer')
    var properties = feature.getProperties()

    if (layer === '山洪灾害气象预警') {
      switch (properties.type) {
        case 'Possible':
          styles[length++] = shonghongPossible
          break
        case 'Slightly high':
          styles[length++] = shonghongSlightly
          break
        case 'High':
          styles[length++] = shonghongHigh
          break
        case 'Extreme high':
          styles[length++] = shonghongExtreme
          break
        default:
          break
      }
    } else if (layer === '农田泽涝气象预警') {
      switch (properties.type) {
        case 'Slightly high':
          styles[length++] = zilaofengxSlightly
          break
        case 'High':
          styles[length++] = zilaofengxHigh
          break
        case 'Extreme high':
          styles[length++] = zilaofengxExtreme
          break
        default:
          break
      }
    } 
    。。。。这里不做全部分享
    styles.length = length
    return styles
  }
}

动态移动图层层级

移动层级的意思就是把两个图层 显示的层级进行调整,调整谁在上,谁压盖谁。先说一下我的大概思路:

  1. 在添加图层的时候默认按照进入map的顺序给初始化一个Zindex【如果有特殊要求的另外自行处理】。
  2. 分别获取当前图层和上/下 图层的层级参数zIndex,分别给两个图层进行Zindex 对调
 /**
     * 图层控制顺序
     * @param ckname 选中要调整的图层名称 title
     * @param cgname 与之调整的图层名称 title 上一个或者下一个
     * @param viewer map实例
     * @param 图层控制顺序    type : 0 上移  ;1下移
     */
  setSort (ckname, cgname, viewer, type) {
    let layers = viewer.getLayers().getArray() //获取当前的所有图层
    let cklayer, cglayer
    // 根据名称或者id匹配拿到需要调整的图层
    for (let i = 0; i < layers.length; i++) {
      if (layers[i].get('title') && layers[i].get('title') === ckname) {
        cklayer = layers[i]
      }
      if (layers[i].get('title') && layers[i].get('title') === cgname) {
        cglayer = layers[i]
      }
    }
    // 分别对调zindex
    if (cklayer && cglayer) {
      let myindex = cklayer.getZIndex()
      let cgindex = cglayer.getZIndex()
      cklayer.setZIndex(cgindex)
      cglayer.setZIndex(myindex)
    }
  }

动态设置图层透明度

基本思路就是获取所有的图层,然后根据预留的信息(id、title)去获取到具体图层,然后设置图层的setOpacity。

  /**
     * 控制服务透明度
     * @param text 图层名称
     * viewer 地图实例
     * isshow为true 显示,false 隐藏
     */
  setOpacity (name, viewer, opacity) {
    let layers = viewer.getLayers().getArray()
    for (let i = 0; i < layers.length; i++) {
      if (layers[i].get('title') && layers[i].get('title') === name) {
        layers[i].setOpacity(opacity)
        break
      }
    }
  }

动态设置图层可见与否

基本思路就是获取所有的图层,然后根据预留的信息(id、title)去获取到具体图层,然后设置图层的setVisible。

   /**
     * 控制服务显示和隐藏
     * @param text 图层名称
     * viewer 地图实例
     * isshow为true 显示,false 隐藏
     */
  setShow (name, viewer, isshow) {
    let layers = viewer.getLayers().getArray()
    for (let i = 0; i < layers.length; i++) {
      if (layers[i].get('title') && layers[i].get('title') === name) {
        layers[i].setVisible(isshow)
        break
      }
    }
  }

动态移除图层

基本思路就是获取所有的图层,然后根据预留的信息(id、title)去获取到具体图层,然后直接移除图层removeLayer。

   /**
     * 控制服务显示和隐藏
     * @param name 图层名称
     * viewer 地图实例
     */
  removeEarthLayer (name, viewer) {
    let layers = viewer.getLayers().getArray()
    for (let i = 0; i < layers.length; i++) {
      if (layers[i].get('title') && layers[i].get('title') === name) {
        viewer.removeLayer(layers[i])
        break
      }
    }
  }