Javascript Openlayers3-使用按压手势在触摸设备上进行分数缩放?

Javascript Openlayers3-使用按压手势在触摸设备上进行分数缩放?,javascript,touch,zooming,openlayers-3,fractions,Javascript,Touch,Zooming,Openlayers 3,Fractions,Openlayers3可以通过在setZoom()中指定分数,以编程方式以分数缩放级别显示地图 然而,我希望我的用户能够在移动触摸驱动设备(即智能手机)上获得分数缩放级别。当手指从屏幕上移开时,收缩或反向收缩通过跳到最近的整个缩放级别进行缩小/放大 触摸/移动用户如何才能让Openlayers3保持在用户所控制的精确范围(分数缩放级别) 我是否可以为Openlayers3地图或视图添加javascript,以使其按预期工作 特别是,我注意到Openlayers3有一个ol.interaction

Openlayers3可以通过在
setZoom()
中指定分数,以编程方式以分数缩放级别显示地图

然而,我希望我的用户能够在移动触摸驱动设备(即智能手机)上获得分数缩放级别。当手指从屏幕上移开时,收缩或反向收缩通过跳到最近的整个缩放级别进行缩小/放大

触摸/移动用户如何才能让Openlayers3保持在用户所控制的精确范围(分数缩放级别)

我是否可以为Openlayers3地图或视图添加javascript,以使其按预期工作

特别是,我注意到Openlayers3有一个
ol.interaction.PinchZoom()
class()。这是
ol.interaction.Pointer
的一个子类,它有一个
handleUpEvent
和一个
handleEvent
(应该是一个函数)。因此从理论上讲,我应该能够在
PinchZoom
中替换
handleUpEvent
,或者将默认的
PinchZoom
交互替换为具有自定义事件处理函数的交互。但使用这两种方法,我无法调用新的handleUpEvent函数

(在拖网查看
PinchZoom
的OL代码时,我发现默认的
PinchZoom
可以实现我想要的功能,如果一个手指先从触摸屏上抬起,然后再从另一个手指上抬起,但我仍然希望在同时抬起两个手指时能够工作。)

这是我到目前为止试过的

第一次尝试-这只是尝试将标准的
PinchZoom
手动事件替换为自定义事件,并将其设置为地图的唯一交互。但是,从不调用事件函数(从不记录任何内容)

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

函数handleDownEvent(mapBrowserEvent){
log(“关闭事件处理程序”);
this.anchor=null;
此.lastDistance=未定义;
this.lastScaleDelta=1;
mapBrowserEvent.map.render();
返回true;//开始拖动
}
函数handleDragEvent(mapBrowserEvent){
if(this.targetPointers.length<2){
log(“拖动事件忽略-触摸”,this.targetPointers.length);
}否则{
log(“已处理的拖动事件”);
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;
//触间距离
变量距离=数学sqrt(dx*dx+dy*dy);
if(this.lastDistance=未定义){
scaleDelta=此.lastDistance uuz/距离;
}
此.lastDistance=距离;
如果(scaleDelta!=1.0){
this.lastScaleDelta=scaleDelta;
}
var map=mapBrowserEvent.map;
var view=map.getView();
var resolution=view.getResolution();
//缩放锚点。
var viewportPosition=map.getViewport().getBoundingClientRect();
var centroid=ol.interaction.Pointer.centroid(this.targetPointers);
质心[0]-=视口位置.left;
质心[1]-=viewportPosition.top;
this.anchor=map.getCoordinateCompixel(质心);
//缩放,绕过分辨率约束
map.render();
ol.interaction.interaction.zoomWithoutConstraints(
地图、视图、分辨率*scaleDelta,this.anchor_u2;);
}
}
函数handleUpEvent(mapBrowserEvent){
log(“向上事件处理程序”);
返回true;//停止拖动
}
var pinchZoom=new ol.interaction.Pointer({
handleDownEvent:handleDownEvent,
handleDragEvent:handleDragEvent,
handleUpEvent:handleUpEvent
});
pinchZoom.targetPointers=[];
map=新ol.map({
交互:ol.interaction.defaults().extend([pinchZoom]),
图层:[
新ol.layer.Tile({
source:newol.source.TileJSON({url:'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure'})
})
],
目标:“地图”,
视图:新ol.view({中心:[0,0],缩放:3})
});

尝试时出现的问题:

第一次尝试
ol.interaction.PinchZoom
handleEvent
选项不存在。这就是为什么不执行回调

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

解决方案 添加选项以在openlayers源中的收缩缩放端保持分数分辨率

问题:

拉取请求:

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


早期的想法是:

例如,我将选项
keepFractionalZoomLevel
添加到
ol.interaction.PinchZoom

请参阅此小提琴以了解工作示例:

注意:fiddle使用自定义openlayers构建:
部署url为:

此示例是否按照您的要求运行?
由于这可能对其他人有用,我们可以尝试将其集成到openlayers中。

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