【OpenLayers 进阶】添加滤镜改变底图样式

一、前言

   项目实施过程中,需要根据不同的业务场景需求变换地图样式。如果客户提供的底图服务或自建底图服务是类似Mapbox这种矢量切片,那只要按照需求配置不同的样式文件即可。如果没有矢量切片,只有一张张瓦片图如何实现呢?下面提供两种实现方式,以供参考

二、准备工作

首先要将完成地图的初始化

  1. 添加地图DIV

    <div class="app-container">
      <div id="map" ref="mapEl" class="map">
      </div>
    </div>
    
  2. 初始化地图

    //底图服务
    let tdt_vec = new TileLayer({
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
      })
    })
    // 注记服务
    let tdt_cva = new TileLayer({
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
      })
    })
    this.map = new Map({
      target: 'map',
      view: new View({
        projection: 'EPSG:4326',
        center: [103.23, 35.33],
        zoom: 12,
        maxZoom: 18
      }),
      layers: [tdt_vec,tdt_cva]
    })
    let vlayer = new VectorLayer({
      source: new VectorSource({
        features: [new Feature({
          geometry: new Point([103.23, 35.33]),
        })]
      }),
      style: [new Style({
        image: new Icon({
          src: 'https://openlayers.org/en/latest/examples/data/icon.png',
          crossOrigin: 'anonymous',
        })
      })]
    })
    this.map.addLayer(vlayer)
    
三、实现方式
  1. 第一种滤镜方式:通过绑定瓦片图层的className实现

    • 先添加一个CSS的滤镜样式
    /*在CSS里添加滤镜代码*/
    ::v-deep .filter-class {
      filter: grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%);
    }
    
    • 对上面的底图追加className
    //底图服务
    let tdt_vec = new TileLayer({
      className:'filter-class', // 添加配置的样式Class
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
      })
    })
    // 注记服务
    let tdt_cva = new TileLayer({
      className:'filter-class',// 添加配置的样式Class
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
      })
    })
    
  2. 第二种滤镜方式:通过tileLoadFunction直接将原始瓦片图替换成加了滤镜的瓦片图

    //底图服务
    let tdt_vec = new TileLayer({
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
        tileLoadFunction:this.tileLoadFunction
      })
    })
    // 注记服务
    let tdt_cva = new TileLayer({
      source: new XYZ({
        crossOrigin:'anonymous',
        url: "http://t{0-7}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=" + this.mapKey,
        tileLoadFunction:this.tileLoadFunction
      })
    })
    
    function tileLoadFunction (imageTile, src) {
      //第2种方式
      // 获取原始瓦片图片信息
      let img = new Image()
      img.setAttribute('crossOrigin','anonymous')
      img.onload = function () {
        // 设置canvas画布将图片信息绘制上去
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')
        let w = img.width
        let h = img.height
        canvas.width = w
        canvas.height = h
        // 设置canvas滤镜
        ctx.filter = "grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%)"
        ctx.drawImage(img, 0, 0)
        // canvas绘制的图像替换原有图片信息
        imageTile.getImage().src = canvas.toDataURL('image/png');
    
      }
      img.src = src
    }
    
四、总结

两种事项方式对比

    上述两种方式都可以实现改变底图颜色的需求,但实现的逻辑有所区别。className是在canvas节点添加了滤镜,作用到载入画布的所有图像,不作用于原始瓦片。tileLoadFunction则是将请求的原始瓦片用滤镜预处理一遍产生一张加了滤镜的新瓦片,然后再加到canvas中的。将两种实现方式的地图导出就能看到差异了。

完整代码参见:GitHub

本文首发于我的个人博客。可以关注收藏一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值