mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.08k stars 2.21k forks source link

Support dragPan.disable() mid-drag #2419

Closed kristfal closed 6 years ago

kristfal commented 8 years ago

mapbox-gl-js version: Master branch

Steps to Trigger Behavior

  1. Start dragging the map (mouse or touch input)
  2. Set map.dragPan.disable() during the drag event

    Expected Behavior

Dragging should no longer move the map.

Actual Behavior

Map will continue being draggable until mouseup or touchend

Afaik, the root issue is that event listeners can't be removed until the ongoing mousedown / touchstart event is finished.

Workaround:

Update the following drag_pan.js handlers:


_onDown: function (e) {
        if (this._ignoreEvent(e)) return;
        if (this.isActive()) return;
        if (!this._enabled) { // Added check for _enabled
            this._inertia = [];
            return;
        };

        if (e.touches) {
            document.addEventListener('touchmove', this._onMove);
            document.addEventListener('touchend', this._onTouchEnd);
        } else {
            document.addEventListener('mousemove', this._onMove);
            document.addEventListener('mouseup', this._onMouseUp);
        }

        this._active = false;
        this._startPos = this._pos = DOM.mousePos(this._el, e);
        this._inertia = [[Date.now(), this._pos]];
    },

    _onMove: function (e) {
        if (this._ignoreEvent(e)) return;
         if (!this._enabled) { // Added check for _enabled
            this._inertia = [];
            return;
        };

        if (!this.isActive()) {
            this._active = true;
            this._fireEvent('dragstart', e);
            this._fireEvent('movestart', e);
        }

        var pos = DOM.mousePos(this._el, e),
            map = this._map;

        map.stop();
        this._drainInertiaBuffer();
        this._inertia.push([Date.now(), pos]);

        map.transform.setLocationAtPoint(map.transform.pointLocation(this._pos), pos);

        this._fireEvent('drag', e);
        this._fireEvent('move', e);

        this._pos = pos;

        e.preventDefault();
    },
lucaswoj commented 8 years ago

What are your thoughts, @bhousel?

kristfal commented 8 years ago

The reason for wanting/needing to use dragPan.disable() mid-drag is that it is currently not possible to replicate the draggable marker functionality on touch devices.

On desktop, you can dragPan.disable() on mousemove (as per example) and lock the map prior to the drag event. On touch-devices, this is not possible, so the dragPan.disable() has to be called during the actual drag-event.

averas commented 8 years ago

I identified more limitations (#2237) in the current interactions implementation a while back that probably, along with this, should be adressed in a broader re-design of how interactions are enabled/disabled and how interactions that depend on the state of others get such information...

bhousel commented 8 years ago

should be adressed in a broader re-design of how interactions are enabled/disabled and how interactions that depend on the state of others get such information...

^ yes, this

mcwhittemore commented 8 years ago

Being able to disable interactions better would be nice. We are stepping around this in a few places with Draw currently. Mostly with zoom on double click.

lucaswoj commented 8 years ago

@bhousel I'd love to see a clean-slate reimagining of our interaction handlers, when you have some spare cycles 😄

rajputneeru commented 7 years ago

I got this error when app is in background and i am trying to open the app again ,i search a lot and get solution to disable map ,i tried this mapView.setEnabled(false); but unfortunately that's not working Anyone can help me to resolve this issue:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.orbis, PID: 15833 java.lang.NullPointerException: Attempt to invoke virtual method 'void com.mapbox.mapboxsdk.maps.NativeMapView.createSurface(android.view.Surface)' on a null object reference at com.mapbox.mapboxsdk.maps.MapView$SurfaceCallback.surfaceCreated(MapView.java:426) at android.view.SurfaceView.updateWindow(SurfaceView.java:656) at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:266) at android.view.View.dispatchWindowVisibilityChanged(View.java:11139) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1290) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1855) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1550) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7190) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959) at android.view.Choreographer.doCallbacks(Choreographer.java:734) at android.view.Choreographer.doFrame(Choreographer.java:670) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6776) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

krabbypattified commented 6 years ago

+1 I'm running into the same exact issue as @kristfal (disabling dragPan mid-drag for mobile/touch devices). It is a crucial functionality for my app. Is there any progress on this?

krabbypattified commented 6 years ago

I've created a pull request that fixes this issue.

clemishow commented 6 years ago

Really need this feature ! https://github.com/mapbox/mapbox-gl-js/pull/5486

krabbypattified commented 6 years ago

@clemishow Agreed, this PR has been dead for a while! Can we get an owner to look at it again and help us get it accepted?

clemishow commented 6 years ago

@krabbypattified Yeah, and in addition it works perfectly

sameerabit commented 4 years ago

This solved my problem.

map.on("mousemove", e => {
        var features = map.queryRenderedFeatures(e.point);
        if (features.length > 0) {
            if (hoveredStateId) {
                map.dragPan.disable();
                map.setFeatureState(
                    { source: 'states', id: hoveredStateId },
                    { hover: false }
                );
            }
                hoveredStateId = e.features[0].id;
                map.setFeatureState(
                { source: 'states', id: hoveredStateId },
                { hover: true }
            );
        }
    });
 map.on("mouseleave", e => {
        var features = map.queryRenderedFeatures(e.point);
        if (features.length > 0) {
            map.dragPan.enable();
        }
    });