From 645e359cde3c6422f4a0a37043f6c8798f0a915b Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Tue, 4 Jul 2017 15:16:39 +0200 Subject: [PATCH 1/2] 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. --- src/ol/renderer/canvas/vectorlayer.js | 34 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/ol/renderer/canvas/vectorlayer.js b/src/ol/renderer/canvas/vectorlayer.js index 14f3beeb79..55471f16b8 100644 --- a/src/ol/renderer/canvas/vectorlayer.js +++ b/src/ol/renderer/canvas/vectorlayer.js @@ -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) { From c33383d248fd5774ec40e4302bedd72f98bcec26 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 12 Jul 2017 10:29:43 +0200 Subject: [PATCH 2/2] Add rendering test for transparent layer --- .../expected/vector-canvas-transparent.png | Bin 0 -> 1980 bytes test_rendering/spec/ol/layer/vector.test.js | 39 ++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 test_rendering/spec/ol/layer/expected/vector-canvas-transparent.png diff --git a/test_rendering/spec/ol/layer/expected/vector-canvas-transparent.png b/test_rendering/spec/ol/layer/expected/vector-canvas-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf3ff79d4c8ea883f610faa4c5f7c252a03a595 GIT binary patch literal 1980 zcmV;t2SfOYP)@%dpxZ6bf&sw8%c+_6E^qe< z98(?uF5{i6wN&i}epK*J;Fv-b=r({B^aDzOhkyYIR!~DCcqn-QSVc9}tdOz%Ef9gd z3Oa%Z7hIxS09tS}@H}vPs>_H1ObxFM_*}t-U_|~Uat3I@a9|E_i?geU1C*hj2R11< zoeRXA09r5xr~qzs4mUn=<36rwRe3+@NX0nddZCIE%oRp46%hfE+E0kq&z z;1RzLV+1gzMw5cj0f*24Ew~4GCg`sfLx7^v*9v|P(#`oi6hI4x0xx*Yc`=;>-NTkS z@lyq7bRlX3wBRP-C18+F<1w{BQSBV?v4TrFdTIf*ps(%c-Ko>4l!-Aw8UAm;29;c3 zd_@=F)4;t!jm69l3{q#mf^9*C0s&fZAMjLALp@{;bgR**;HaPOz5p$d=dS^SdnrKK z@--;1vgscL@B!e7u<&}o9OzVen}YqJ0ou_OvA%)59N%BtKeKC@lyD@H^C3g6cO8STy;%R|aa@Cd9*H{w84b-$P2(F)x zfazT3I(Vu2Qn1?J|`6Pq@XI8s54PR2$)09HZughrSnao?Oob|)vDEqDQZ94IyJ zrlbV+?j?~RS^y=5X6jVfx6fEL`%o%lG4TTUGBCurmpyx+v^1Iko10+j zmkr=@W9NDCVyLT&2f!suVC709I{`Wr)OG=Ar(`TPZ54a*NY#(D1?Ik()TS~U(ywq% z3rL?naQQOyy|(jwr<YqG}HR3?KHpt%oNSqZCG#|z-1MNnUF3NY;pIswZ5SN6f-rS}2cuAtdH z2O6Eeb<(b=Kq4@)nges&(rs37*bQ(LFfY9M$$g|U*tIKO0B6jArqH=WDIL>ct?uyy zUE4V6CGx9qZrizZK*0%6lEck*BK`V7Yby-Cc6=OZfbH!tbZ9OCg_Wsfb$2kqd@n3+ zjJPwlL>i#DFXG0SiT7Su+OnY1BnzQ)9Ill((f}7OgtcqU@IkwRwEyF_K*@I=Z`5*} z!dat7gTw{RB;$0>4bV81qjM~>AC`S_lot_+1IhwoF6muJh8ttQ!gAl^b$6guyRQWc zprIk!0O!w#4I8voaut*$qg4w2O8wsJP)Sb1hZ*%CVXb4w;I6x(>BbyB43j4162{7i zMt8A5+X{2aiAn8BBDsj<7C;a@T{8K-EYN&Mk}}(a2T5$19IbQV$9BW?=|(S>qf$B! z==TcW0K6#|290|gJC;QGPt<%MdFcU?kIaNOE>Zo>L^ystXf%G$FDO{$E^z&li$;Dz z%_)rlcRm1)SV#5mFXjSI>K;pzO(B&327TXC%Ekz0F=sB(+!kLL=#60GkzT z_X6RUp(?4pi%idndl10Oc8ag(#haicb7PmL2LbfGgct-+k}SmvL$Am^1fXw%xu+xT ze$P!4j(P~d^w~$Yg+S+~lBE1TNAh;Mw)6miEx;E+_vHcs+AFerkwb23-lj`1<^cb& zZ)^tUz-a-rA>L}IerRkjVtrdvR$JM!{i$Ot+5l~cl0P#aknNtY#MA=i!u4mVyq6#y zwH6VNMMWzGB&Go63m(_9L^TM8vcOb(I@iEr2rxe%op3;$2t1kX`w1}uD6j2T3XW+Q zT$dt77U+N|k!x{r3g3}7`GYv>6aW?gY7i*A!WxkLiWC4A0RF%K4&y(loYsCbW6x{= O0000