Skip to content
Advertisement

Viewport affecting relative position of a nested element in resizable div

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" />

enter image description here

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.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement