Openlayers3 - 使用捏合手势在触摸设备上进行部分缩放?

Openlayers3 - fractional zoom on touch device using pinch gesture?

Openlayers3 可以通过在 setZoom().

中指定小数以编程方式以小数缩放级别显示地图

但是,我希望我的用户能够在移动触摸驱动设备(即智能 phone)上获得分数缩放级别。当手指从屏幕上移开时,通过跳转到最近的整个缩放级别来进行捏合或反向捏合缩放 out/in。

touch/mobile 用户如何让 Openlayers3 保持在用户捏到的确切范围(分数缩放级别)?

有什么我可以添加到我的 Openlayers3 地图或视图的 javascript 以使其按需要工作的东西吗?

特别是,我注意到 Openlayers3 有一个 ol.interaction.PinchZoom() class ( https://openlayers.org/en/latest/apidoc/ol.interaction.PinchZoom.html )。这是 ol.interaction.Pointer 的子 class,它有一个 handleUpEvent 和一个 handleEvent(应该是一个函数)。所以理论上,我应该能够替换 PinchZoom 中的 handleUpEvent 或将默认的 PinchZoom 交互替换为具有自定义事件处理函数的交互。但是使用这两种方法,我都无法调用新的 handleUpEvent 函数。

(在搜索 PinchZoom 的 OL 代码时,我发现如果一根手指在另一根手指之前从触摸屏上抬起,默认的 PinchZoom 会做我想要的,但我仍然想要在同时抬起两个手指时让它工作。)

这是我到目前为止尝试过的...

FIRST ATTEMPT - 这只是尝试将标准 PinchZoomhandleUpEvent 替换为自定义的,并将其设置为唯一的交互地图。但是,永远不会调用事件函数(永远不会记录任何内容)。

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})
});

第二次尝试 - 此尝试基于创建标准 PinchZoom 交互的实际 OL 代码。在这种情况下,我的所有事件处理程序函数都会被调用,触摸次数 ( targetPointers ) 始终为零(如记录的那样)。我不是 javascript 专家,但我怀疑这是因为 ol.js 中的符号与我基于此的 ol-debug.js 中的符号不​​同。事实上,我必须自己声明 targetPointers 才能达到 运行,即使 OL 本身已经声明了它(但可能在非调试版本中使用了不同的符号名称)。

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})
});

您尝试的问题:

第一次尝试

ol.interaction.PinchZoom 的选项 handleEvent 不存在。这就是你的回调没有被执行的原因。

第二次尝试

正如您已经注意到的,您尝试使用 openlayers 内部结构。这可能适用于调试版本,但不适用于发布版本,因为名称不同于。

解决方案

添加选项以在 openlayers 源中的缩放端保持分数分辨率。

问题:https://github.com/openlayers/ol3/issues/6223

拉取请求:https://github.com/openlayers/ol3/issues/6224

默认情况下,双指缩放将保持用户选择的小数缩放级别。从 OpenLayers 3.20 开始


一个较早的想法:

例如,我将选项 keepFractionalZoomLevel 添加到 ol.interaction.PinchZoomhttps://github.com/aAXEe/ol3/commit/7639cb20d17858492652896bcd4a6ff7992a9bb0

请参阅此 fiddle 以获取工作示例:https://jsfiddle.net/wm78prro/5/

注意:fiddle 使用自定义 openlayers 构建:https://github.com/aAXEe/ol3/pull/1
部署 url 是:https://deploy-preview-1--pump-attendant-rhinoceros-42285.netlify.com/ol-debug.js

这个例子是否如你所愿?
由于这可能对其他人有用,我们可以尝试将其集成到 openlayers 中。