OpenLayers
官网有整个图层的渐变示例,但是没有单个要素的渐变示例,我们这里来补充一下。OpenLayers
中的渐变是通过fill
选项中实现的。fill
选项可以传一个ColorLike
,本质是通过Canvas
实现的,此时ColorLike
对应的是CanvasPattern
或CanvasGradient
。
const source = new VectorSource();
let polygon = new Feature({
geometry:new Polygon([
[
[106.542384,30.485627],
[106.542384,40.485627],
[117.542384,40.485627],
[117.542384,30.485627],
[106.542384,30.485627],
]
])
});
source.addFeature(polygon)
const vectorLayer = new VectorLayer({
source: source,
});
const map = new Map({
layers: [vectorLayer],
target: 'map',
view: new View({
center: [126.980366, 37.52654],
zoom: 1,
projection:'EPSG:4326'
}),
});
//import {DEVICE_PIXEL_RATIO} from 'ol/has'
getLineGradientStyle(){
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const pixelRatio = DEVICE_PIXEL_RATIO;
let gradient = context.createLinearGradient(0,0,1024*pixelRatio,0);
let mainColor = '#56e90e';
let secondColor = '#0e57e9';
gradient.addColorStop(0,mainColor);
gradient.addColorStop(1,secondColor);
return gradient;
}
let style = new Style({
fill:new Fill({
color:this.getLineGradientStyle()
})
})
polygon.setStyle(style)
现在我们的要素在地图的正中间,能看到两个颜色之间的过渡。我们把地图左键进行移动一下,使得要素分别在最后边和最后边,然后再来看看效果。
发现了什么?效果是变化的!所以我们的渐变策略是不太对的,渐变填充应该根据面的范围以及当前所处的位置来进行动态计算。具体来说就是要在createLinearGradient
的时候去动态计算.现在我把渐变改成从【512,0】到【1024,0】的渐变,然后我们把地图往左移动,再看看效果
let gradient = context.createLinearGradient(512*pixelRatio,0,1024*pixelRatio,0);
这次发现了什么?貌似始终是在【512,0】到【1024,0】渐变。但如果你真的这样以为了,那你就错了。现在把地图往右移动,看看会发生什么事?
好像渐变的位置发生了偏移,不是我们最初设定的【512,0】到【1024,0】了。为什么挥发生这种现象。我们来看OpenLayers
官网是是怎么解释的。在OpenLayers
官网关于渐变有这样一段描述:
翻译过来就是
CanvasRenderingContext2D.fillStyle或CanvasRendering Context2D.strokeStyle接受的类型。表示颜色、图案或渐变。图案和渐变作为填充样式的原点是从地图坐标[0,0]增加512个css像素。对于无缝重复图案,图案图像的宽度和高度必须是两倍(2,4,8,…,512)。
重点是这一句:图案和渐变作为填充样式的原点是从地图坐标[0,0]增加512个css像素
也就是说这个[0,0]是屏幕坐标,不是我们以为的经纬度坐标。而且渐变的位置也不是我们想要的,我们想要的是从某个经纬度到某个经纬度的渐变。
512个css像素是什么意思?
答:屏幕在出厂时就从硬件上面决定了,用几个物理像素来代表一个css像素。因此才有设备像素比这个参数,也就是我们上文导入的DEVICE_PIXEL_RATIO
。
getCenterGradientStyle(polygon){
let canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
let extent = polygon.getExtent()
let minLon = extent[0]
let maxLon = extent[2]
let minLat = extent[1]
let maxLat = extent[3]
let resolution = this.map.getView().getResolution()
const pixelRatio = DEVICE_PIXEL_RATIO;
let height = (maxLat - minLat)/resolution*pixelRatio
let width = (maxLon-minLon)/resolution*pixelRatio
canvas.width = width
canvas.height = height
let radius = Math.max(height,width)
let center = map.getPixelFromCoordinate([
(minLon+maxLon)/2,
(maxLat+minLat)/2
])
let gradient = context.createRadialGradient(
center[0],
center[1],
radius/6,
center[0],
center[1],
radius/2
)
let mainColor = '#56e90e';
let secondColor = '#0e57e9';
gradient.addColorStop(0,mainColor);
gradient.addColorStop(1,secondColor);
return gradient;
}
let style = new Style({
fill:new Fill({
color:this.getCenterGradientStyle()
})
})
polygon.setStyle(style)
在change:resolution事件中去调用,保证算出来的宽高的正确性
OpenLayers
中的渐变效果实在很难令人满意,又或者是我们理解的有问题,因为其是动态变化的,我们很难得到想要的结果。目前,我们要时刻注意监听视图的变化来修改渐变的效果。本文算是抛砖引玉吧,如果某位有志之士能谁能解决掉这个问题,希望能告诉我一下,回见~