Check out this codepen I created where I modify the basemap context of an OpenLayers map on the postcompose
event. Now, I'm facing a challenge in translating this working demo to a Vue SPA using OpenLayers 6. I want to link the dark mode map effect to a toggle button. However, the postcompose
event behaves differently in OL6 compared to OL3, so I attempted to use the prerender
event instead.
import TileLayer from 'ol/layer/Tile';
...
osm: new TileLayer({source: new OSM()})
In OL3, the following code successfully gives me a constant dark mode map:
OSM_LAYER.on('postcompose', function (evt) {
evt.context.globalCompositeOperation = 'color';
evt.context.fillStyle = 'rgba(0,0,0,' + 1.0 + ')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
evt.context.globalCompositeOperation = 'overlay';
evt.context.fillStyle = 'rgb(' + [200,200,200].toString() + ')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
evt.context.globalCompositeOperation = 'source-over';
document.querySelector('canvas').style.filter="invert(99%)";
});
Currently, I'm attempting to utilize getVectorContext
as suggested in this answer, but for some reason, my code isn't achieving the desired dark mode effect:
OSM_LAYER.on('prerender', function (evt) {
var ctx = getVectorContext(evt).context_
ctx.globalCompositeOperation = ‘color’;
ctx.fillStyle = ‘rgba(0,0,0,’ + 1.0 + ‘)’;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = ‘overlay’;
ctx.fillStyle = ‘rgb(‘ + [200,200,200].toString() + ‘)’;
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = ‘source-over’;
document.querySelector('canvas').style.filter="invert(99%)";
});
EDIT : Thanks to Mr. Mike's answer I am able to replicate the look of the OL3 dark mode. The problem now is that I actually use this basemap to create an animation where I update the time parameters of all layers in a for loop and then extract the map canvas using :
getMapCanvas () {
var mapCanvas = document.createElement('canvas');
var divElement = document.querySelector(".map");
mapCanvas.width = divElement.offsetWidth;//size[0];
mapCanvas.height = divElement.offsetHeight;//size[1];
var mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(
document.querySelectorAll('.ol-layer canvas'),
function (canvas) {
if (canvas.width > 0) {
const opacity = canvas.parentNode.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
const transform = canvas.style.transform;
const matrix = transform
.match(/^matrix\(([^\(]*)\)$/)[1] //eslint-disable-line
.split(',')
.map(Number);
CanvasRenderingContext2D.prototype.setTransform.apply(mapContext,matrix);
mapContext.drawImage(canvas, 0, 0);
}
}
);
return mapCanvas;
},
which is called only after a rendercomplete
promise is resolved. Using Mr. Mike's method I get a weird white hue instead of the dark mode OSM and I think it is because of how I am exporting the canvas in the getMapCanvas
function. Can someone help me out debug this?