1、需求描述
在地理信息系统中,客户想要不同于原色的地图颜色,让页面看起来更有科技感。本文的目标是对openlayer加载的天地图的颜色进行修改。
2、参考文章
(1)blog.csdn.net/linzi199005...
(2)blog.csdn.net/weixin_4495...
3、最终效果
4、实现方式
4.1通过css实现
通过css的filter属性,将模糊或颜色偏移等图形效果应用于元素。
javascript
:deep(.ol-layer) {
filter: invert(100%) hue-rotate(180deg);
/* -webkit-filter: invert(100%) hue-rotate(180deg); */
}
使用这种方式能修改地图的颜色,但是需要注意的是,这种实现是对所有的ol-layer都改变的颜色。即,不仅是天地图底图会被修改颜色,所有加载进地图的图层的颜色都会被修改。例如:imageLayer、overLayer等都会受到影响。
4.2 图层加载时修改颜色
4.2.1外部调用实现
使用openlayer的RasterSource,对数据进行转换。RasterSource是使用运算函数将来自任意数量输入源的数据转换为输出像素值的一种源。
颜色转换函数
javascript
import ImageLayer from 'ol/layer/Image';
import RasterSource from 'ol/source/Raster';
// 定义颜色转换方法
const reverseFunc = (pixelsTemp: any) => {
// 蓝色
for (let i = 0; i < pixelsTemp.length; i += 4) {
const r = pixelsTemp[i];
const g = pixelsTemp[i + 1];
const b = pixelsTemp[i + 2];
// 设置灰度值
const grey = r * 0.3 + g * 0.59 + b * 0.11;
// console.log(grey);
// 将rgb的值替换为灰度值
// pixelsTemp[i] = grey;
// pixelsTemp[i + 1] = grey;
// pixelsTemp[i + 2] = grey;
// 基于灰色设置为蓝色
pixelsTemp[i] = 55 - grey; //R
pixelsTemp[i + 1] = 255 - grey; //G
pixelsTemp[i + 2] = 305 - grey; //B
}
};
//图层颜色转换
const translate = (layerOrigin: any) => {
const raster = new RasterSource({
sources: [layerOrigin],
// 这里设置为img类型,为了优化速度
operationType: 'image',
operation: function (pixels: any, _data) {
// 执行颜色转换方法
reverseFunc(pixels[0].data);
return pixels[0];
},
// 线程数
threads: 10,
lib: {
// 允许operation使用外部方法
reverseFunc: reverseFunc,
},
});
// 创建新图层
const layer = new ImageLayer({
source: raster,
});
return layer;
};
//图层加载
const map=new Map({...})
const layerOrigin=new TileLayer({
source:new XYZ({
url: tiandituVecUrl + '&tk=' + tiandituKey,
})
})
const layer=translate(layerOrigin)
map.addLayer(layer)
使用这个方法,存在不好调整地图颜色问题,我们在reverseFunc中输出我们设置的灰度值。查看灰度值的众数,这个众数就是地图的基本色调计算后的灰度值,然后再根据这个数计算。
注意:使用这个方法可能会出现image跨域的问题。如果遇到请使用4.3的方法。
4.3 内部函数实现
影像地图加载时,通过tileLoadFunction指定瓦片加载的方法。在此方法中对加载的图片进行颜色转换。
javascript
const layer = new TileLayer({
source: new XYZ({
url: tiandituVecUrl + '&tk=' + tiandituKey,
// layer: 'img',
tileLoadFunction: function (imageTile: any, src) {
const img = new Image();
img.crossOrigin = '';
img.onload = function () {
const canvas = document.createElement('canvas');
const w = img.width;
const h = img.height;
canvas.width = w;
canvas.height = h;
const context = canvas.getContext('2d') as any;
context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
const imageData = context.getImageData(0, 0, w, h);
for (let i = 0; i < imageData?.height; i++) {
for (let j = 0; j < imageData?.width; j++) {
let x = i * 4 * imageData.width + j * 4;
//灰度计算
imageData.data[x] =
imageData.data[x + 1] =
imageData.data[x + 2] =
imageData.data[x] * 0.3 +
imageData.data[x + 1] * 0.59 +
imageData.data[x + 2] * 0.11;
//颜色计算
imageData.data[x] = 55 - imageData.data[x];
imageData.data[x + 1] = 255 - imageData.data[x + 1];
imageData.data[x + 2] = 305 - imageData.data[x + 2];
}
}
context?.putImageData(imageData, 0, 0);
imageTile.getImage().src = canvas.toDataURL('image/png');
};
img.src = src;
},
}),
// Opacity: 1,
// format: new parseGeoJson(),
zIndex: -1,
});
也可以拿出来封装成一个函数
javascript
export function tileLoadFunction(imageTile: any, src) {
const img = new Image();
img.crossOrigin = '';
img.onload = function () {
const canvas = document.createElement('canvas');
const w = img.width;
const h = img.height;
canvas.width = w;
canvas.height = h;
const context = canvas.getContext('2d') as any;
context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
const imageData = context.getImageData(0, 0, w, h);
for (let i = 0; i < imageData?.height; i++) {
for (let j = 0; j < imageData?.width; j++) {
const x = i * 4 * imageData.width + j * 4;
imageData.data[x] =
imageData.data[x + 1] =
imageData.data[x + 2] =
imageData.data[x] * 0.3 + imageData.data[x + 1] * 0.59 + imageData.data[x + 2] * 0.11;
imageData.data[x] = 55 - imageData.data[x];
imageData.data[x + 1] = 255 - imageData.data[x + 1];
imageData.data[x + 2] = 305 - imageData.data[x + 2];
}
}
context?.putImageData(imageData, 0, 0);
imageTile.getImage().src = canvas.toDataURL('image/png');
};
img.src = src;
}
const layerOrigin = new TileLayer({
source: new XYZ({
url: tiandituVecUrl + '&tk=' + tiandituKey,
tileLoadFunction: (imageTile, src) => tileLoadFunction(imageTile, src) as any,
}),
// Opacity: 1,
// format: new parseGeoJson(),
zIndex: -1,
});