以前使用百度、高德在线地图时,可以直接配置地图样式。配置一些暗黑等主题的,并可以在线加载。
现在项目中都使用的是 openlayers ,加载的地图底图基本都是瓦片形式。
系统主题色调成暗黑的,还使用以前的地图怎么感觉都是不搭配的。
瓦片底图都是一张张图片,可以对这些图片处理就好了。
一、filter
CSS3 的新特性 filter 可以对图片进行处理。那么直接写 css 怎么样?
经过一番查找,直接对加载地图的 canvas 设置 filter 样式就可以。
canvas { filter: grayscale(1) invert(1) !important; }
在 openlayers 中对 canvas 设置了这个属性,所以要加 !important
其中 grayscale 是做灰度处理,inver 是做倒置处理。
这两个可以单独使用,也可以结合使用。根据自己主题搭配合理使用。
效果如下:
看上去效果还是比前面好不少。
问题:
在接下来有有了新问题:因为是对 canvas 做的 filter 处理,所以所有的地图、自己添加的点、线等都做了处理(这些是不想被处理的)。
寻找了一圈之后发现:openlayers 可以单独对 瓦片处理。
二、openlayers 处理
openlayers 可以对加载的任何图片做处理。主要是通过 tileLoadFunction
通过搜索API发现在 ol/source 下面的能加载图片的基本都有这个函数。如:XYZ、WMTS、Tile、BingMaps。
这个函数是在加载图片的时候对图片做了预处理。
具体代码实现如下:
const vecLayer = new TileLayer({ source: new XYZ({ url: mapUrls['aMap-vec-a'], tileLoadFunction: function(imageTitle, src) { const img = new Image() img.crossOrigin = '' img.onload = () => { const canvas = document.createElement('canvas') const w = img.width const h = img.height canvas.width = w canvas.height = h const context = canvas.getContext('2d') context.drawImage(img, 0, 0, w, h, 0, 0, w, h) const imgData = context.getImageData(0, 0, w, h) for (let i = 0; i < imgData.height; i++) { for (let j = 0; j < imgData.width; j++) { const x = (i * 4) * imgData.width + j * 4 const r = imgData.data[x] const g = imgData.data[x + 1] const b = imgData.data[x + 2] const avg = (r + g + b) / 3 // 注意这里:avg 是灰度值,如果只需要灰度那就直接赋值,需要倒置(invert)的,用 255 减去灰度值 imgData.data[x] = imgData.data[x + 1] = imgData.data[x + 2] = 255 - avg } } context.putImageData(imgData, 0, 0) imageTitle.getImage().src = canvas.toDataURL('image/png') } img.src = src } }), title: '矢量底图' })
这样处理的好处:只针对需要的图层做处理,其他图层、自己添加的点、线、面等要素不受影响。