Openlayers3 can display a map at a fractional zoom level programmatically by specifying a fractional number in setZoom()
.
However, I want my users to be able to get a fractional zoom level on a mobile touch-driven device (ie, a smart phone). Pinch or reverse pinch zooms out/in by jumping to the nearest whole zoom level when the fingers are removed from the screen.
How can a touch/mobile user get Openlayers3 to stay at the exact extent (fractional zoom level) that the user has pinched to?
Is there something I can add to the javascript for my Openlayers3 map or view to get this to work as desired?
In particular, I note that Openlayers3 has a ol.interaction.PinchZoom()
class ( https://openlayers.org/en/latest/apidoc/ol.interaction.PinchZoom.html ). This is a subclass of ol.interaction.Pointer
which has a handleUpEvent
and a handleEvent
(which should be a function). So in theory, I should be able to either replace the handleUpEvent
in PinchZoom
OR replace the default PinchZoom
interaction with one that has a custom event handler function. But with both of these approaches, I can't get my new handleUpEvent function to be called.
(While trawling the OL code for PinchZoom
I have found that the default PinchZoom
does what I want if one finger is lifted from the touch-screen before the other finger, but I still want to get this working when both fingers are lifted simultaneously.)
Here is what I've tried so far...
FIRST ATTEMPT - This just attempts to replace the standard PinchZoom
's handleUpEvent
with a custom one, and set this as the only interaction for the map. However, the event function is never called (never logs anything).
function handleUpEvent(evt) {
console.log("Up event handler");
return true; // Stop drag
}
map = new ol.Map({
layers: [],
target: 'map',
controls: controls,
interactions: [new ol.interaction.PinchZoom({handleEvent: handleUpEvent})],
view: new ol.View({projection: projCode})
});
SECOND ATTEMPT - This attempt is based on the actual OL code for creating the standard PinchZoom
interaction. In this case, all my event handler functions DO get called, the number of touches ( targetPointers
) is always zero (as logged). I'm no javascript guru, but I suspect that this is because the symbols in ol.js are different to in ol-debug.js which I'm basing this on. In fact I had to declare targetPointers
myself to even get this to run, even though it is declared by OL itself already (but presumably using a different symbol name in the non-debug version).
function handleDownEvent(mapBrowserEvent) {
console.log("DOWN event handler");
this.anchor_ = null;
this.lastDistance_ = undefined;
this.lastScaleDelta_ = 1;
mapBrowserEvent.map.render();
return true; // Start drag
}
function handleDragEvent(mapBrowserEvent) {
if ( this.targetPointers.length < 2 ) {
console.log("DRAG event ignored - touches ", this.targetPointers.length);
} else {
console.log("DRAG event handled");
var scaleDelta = 1.0;
var touch0 = this.targetPointers[0];
var touch1 = this.targetPointers[1];
var dx = touch0.clientX - touch1.clientX;
var dy = touch0.clientY - touch1.clientY;
// distance between touches
var distance = Math.sqrt(dx * dx + dy * dy);
if (this.lastDistance_ !== undefined) {
scaleDelta = this.lastDistance_ / distance;
}
this.lastDistance_ = distance;
if (scaleDelta != 1.0) {
this.lastScaleDelta_ = scaleDelta;
}
var map = mapBrowserEvent.map;
var view = map.getView();
var resolution = view.getResolution();
// scale anchor point.
var viewportPosition = map.getViewport().getBoundingClientRect();
var centroid = ol.interaction.Pointer.centroid(this.targetPointers);
centroid[0] -= viewportPosition.left;
centroid[1] -= viewportPosition.top;
this.anchor_ = map.getCoordinateFromPixel(centroid);
// scale, bypass the resolution constraint
map.render();
ol.interaction.Interaction.zoomWithoutConstraints(
map, view, resolution * scaleDelta, this.anchor_);
}
}
function handleUpEvent(mapBrowserEvent) {
console.log("UP event handler");
return true; // Stop drag
}
var pinchZoom = new ol.interaction.Pointer({
handleDownEvent: handleDownEvent,
handleDragEvent: handleDragEvent,
handleUpEvent: handleUpEvent
});
pinchZoom.targetPointers = [];
map = new ol.Map({
interactions: ol.interaction.defaults().extend([pinchZoom]),
layers: [
new ol.layer.Tile({
source: new ol.source.TileJSON({url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure'})
})
],
target: 'map',
view: new ol.View({center: [0, 0], zoom: 3})
});
The problems with your attempts:
The option handleEvent
for ol.interaction.PinchZoom
does not exists. That is why your callback is not executed.
As you already noted you try to use openlayers internals. This might work with the debug build but will not work in the release build as the names are different than.
Add the option to keep a fractional resolution at the pinch zoom end in the openlayers sources.
Issue: https://github.com/openlayers/ol3/issues/6223
Pull request: https://github.com/openlayers/ol3/issues/6224
The pinch zoom will by default keep the fractional zoom level as chosen by the user .. starting with OpenLayers 3.20
An earlier idea:
As an example I added the option keepFractionalZoomLevel
to ol.interaction.PinchZoom
: https://github.com/aAXEe/ol3/commit/7639cb20d17858492652896bcd4a6ff7992a9bb0
See this fiddle for a working example: https://jsfiddle.net/wm78prro/5/
Note: The fiddle uses a custom openlayers build: https://github.com/aAXEe/ol3/pull/1
The deploy url is: https://deploy-preview-1--pump-attendant-rhinoceros-42285.netlify.com/ol-debug.js
Does this example behave as you want?
As this may be usefull for others we can try to integrate it into openlayers.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.