Render transparent vector layers to an intermediate canvas

Until now, the features of transparent vector layers were rendered using
the layer opacity. This caused colors to mix together and the opacities
to stack up to an higher value than the expected layer opacity.

With this commit, the features are rendered at 100% opacity to an
intermediate canvas which ensures colors do not mix up even in the case
of features using an array of styles. The intermediate canvas is then
composed to the map canvas using the layer opacity.

Transparent layers are automatically detected, non-transparent layers
are not affected by the change.
This commit is contained in:
Guillaume Beraudo
2017-07-04 15:16:39 +02:00
parent aced192bcd
commit 645e359cde

View File

@@ -97,7 +97,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
var drawOffsetX = 0;
var drawOffsetY = 0;
var replayContext;
if (layer.hasListener(ol.render.EventType.RENDER)) {
var transparentLayer = layerState.opacity !== 1;
var hasRenderListeners = layer.hasListener(ol.render.EventType.RENDER);
if (transparentLayer || hasRenderListeners) {
var drawWidth = context.canvas.width;
var drawHeight = context.canvas.height;
if (rotation) {
@@ -113,11 +115,15 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
} else {
replayContext = context;
}
// for performance reasons, context.save / context.restore is not used
// to save and restore the transformation matrix and the opacity.
// see http://jsperf.com/context-save-restore-versus-variable
var alpha = replayContext.globalAlpha;
replayContext.globalAlpha = layerState.opacity;
if (!transparentLayer) {
// for performance reasons, context.save / context.restore is not used
// to save and restore the transformation matrix and the opacity.
// see http://jsperf.com/context-save-restore-versus-variable
replayContext.globalAlpha = layerState.opacity;
}
if (replayContext != context) {
replayContext.translate(drawOffsetX, drawOffsetY);
}
@@ -159,11 +165,23 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
width / 2, height / 2);
if (replayContext != context) {
this.dispatchRenderEvent(replayContext, frameState, transform);
context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);
if (hasRenderListeners) {
this.dispatchRenderEvent(replayContext, frameState, transform);
}
if (transparentLayer) {
var mainContextAlpha = context.globalAlpha;
context.globalAlpha = layerState.opacity;
context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);
context.globalAlpha = mainContextAlpha;
} else {
context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);
}
replayContext.translate(-drawOffsetX, -drawOffsetY);
}
replayContext.globalAlpha = alpha;
if (!transparentLayer) {
replayContext.globalAlpha = alpha;
}
}
if (clipped) {