TeChn4K TeChn4K - 1 month ago 16
Javascript Question

Issue with layer rotation via compose hooks

I'm developing a tool to rotate a static image layer and I'm currently facing an issue on mobile.

Static image layer must rotate around a specific point. I use precompose and postcompose hooks in order to alter canvas and make the rotation.
It works great on desktop but i don't understand what is going on on mobile (Android Chrome or FF).

jsFiddle : https://jsfiddle.net/wuty2m9v/7/

/* Vars */
const center = ol.proj.transform([1.44, 43.603], "EPSG:4326", "EPSG:3857")
const imgSize = [400, 267]
const imgExtent = [center[0], center[1], center[0] + imgSize[0], center[1] + imgSize[1]]
let rotation = 45

/* Init map */
const map = new ol.Map({
target: 'map',
view: new ol.View({
zoom: 16,
center,
}),
layers: [
// Map tiles layer
new ol.layer.Tile({
source: new ol.source.OSM()
}),
// Feature layer
new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(center),
}),
],
}),
}),
],
})

/* Init image layer */
const imgLayer = new ol.layer.Image({
opacity: 0.7,
source: new ol.source.ImageStatic({
url: "https://pbs.twimg.com/profile_images/685220121598660608/2uZUdcS1.jpg",
imageExtent: imgExtent,
})
})
imgLayer.on("precompose", evt => {
const pixel = map.getPixelFromCoordinate(center)
const ctx = evt.context
ctx.save()
ctx.translate(pixel[0], pixel[1])
ctx.rotate(rotation * Math.PI / 180)
ctx.translate(-pixel[0], -pixel[1])
})
imgLayer.on("postcompose", evt => {
const ctx = evt.context
ctx.restore()
})
map.addLayer(imgLayer)


On desktop, image rotate correctly around the point. Drag the map : point and image follow the map.
On mobile, image doesn't rotate correctly around the point, it is made around the canvas origin, canvas translations don't look good. Drag the map to watch the chaos :)

Answer

You'll need to take into account the pixel ratio when doing transforms. The pixels you get from map.getPixelFromCoordinate are css pixels. To get canvas pixels, you need to multiply them by ol.has.DEVICE_PIXEL_RATIO:

ctx.translate(pixel[0] * ol.has.DEVICE_PIXEL_RATIO, pixel[1] * ol.has.DEVICE_PIXEL_RATIO);

and

ctx.translate(-pixel[0] * ol.has.DEVICE_PIXEL_RATIO, -pixel[1] * ol.has.DEVICE_PIXEL_RATIO);

See https://jsfiddle.net/wuty2m9v/8/ for an updated version of your JSFiddle.

Comments