In this app I made, where I use Vue and OpenLayers to create animations, a img
element with position: relative
is placed at the top right corner of a canvas
element with resize: both; overflow: auto;
. The problem (CodePen) is said element is used to create an animation in a for loop where at each iteration the canvas
element is used as a frame after updated and rendered. At each step the canvas
element is sued to compose a new canvas and another img
tag (same as the one overlaying the canvas
but hidden to overcome some Vue and OpenLayers particularities) is .getElementById(...)
and .getContext("2d").drawImage(...)
onto the frame canvas
. For some weird viewport
related reason the img
element tends to drift to the middle of the canvas
element when the viewport is resized or on a multi-monitor (uncommon aspect ratios also trigger it) setup even though before the loop starts composing the canvas
frames it freezes the dimensions of all the elements so that size of the output is consistent with the initial frame.
My question is what could be affecting the widths I used to calculate where the img
element should be (see JS code below) that is related to multi-screen setup, viewport
or other but works 100% on more regular setups?
if (showLegendFlag === true) { const mapLegend = document.getElementById("mapLegend"); mapCnv .getContext("2d") .drawImage( mapLegend, mapCnv.width - mapLegend.width, 0, mapLegend.width, mapLegend.height ); // drawImage(image, dx, dy, dWidth, dHeight) }
<div id="map" class="map"> <img id="legendMapOverlay" src="https://geo.weather.gc.ca/geomet?version=1.3.0&service=WMS&request=GetLegendGraphic&sld_version=1.1.0&layer=GDPS.CONV_KINDEX.PT3H&format=image/png&STYLE=KINDEX&lang=en"/> </div> <img id="mapLegend" :src="mapLegendURL" style="display: none;" v-if="displayMapLegend" crossorigin="anonymous" />
Advertisement
Answer
OpenLayers may have a transform set on the canvas depending on the device pixel ratio. You could try two options:
Option 1
Specify pixelRatio: 1,
in the ol.Map
options to override the device pixel ratio so no transform is needed.
Option 2
Reset the transform before you draw the image, but surround the calls with save()
and restore()
const mapCtx = mapCnv.getContext("2d") mapCtx.save(); mapCtx.resetTransform() mapCtx .drawImage( mapLegend, mapCnv.width - mapLegend.width, 0, mapLegend.width, mapLegend.height ); mapCtx.restore();
Note that OpenLayers version 6 and 7 do not have a single map canvas and your approach might not work.