-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add mobile gesture handling for pitch #3405
Comments
This is a special case of #2618. As far as I can tell, gesture event support exists in mobile browsers and Internet Explorer, Edge, and Safari on the desktop. Blink and Gecko appear to lack gesture event support, but given the importance of mobile Web browsing, I don’t think that should matter. |
Any update or work around? |
bump - Any update or work around? |
here's some quick and dirty code just using simple map events, not perfect but it gets the job done until something similar is added to the touch_zoom_rotate handler demo here: http://bit.ly/2SY7p2S this.map.on('touchstart', function(data) {
if (data.points.length == 2) {
var diff = Math.abs(data.points[0].y - data.points[1].y);
if (diff <= 50) {
data.originalEvent.preventDefault(); //prevent browser refresh on pull down
self.map.touchZoomRotate.disable(); //disable native touch controls
self.map.dragPan.disable();
self.dpPoint = data.point;
self.dpPitch = self.map.getPitch();
}
}
});
this.map.on('touchmove', function(data) {
if (self.dpPoint) {
data.preventDefault();
data.originalEvent.preventDefault();
var diff = (self.dpPoint.y - data.point.y) * 0.5;
self.map.setPitch(self.dpPitch + diff);
}
});
this.map.on('touchend', function(data) {
if (self.dpPoint){
self.map.touchZoomRotate.enable();
self.map.dragPan.enable();
}
self.dpPoint = null;
});
this.map.on('touchcancel', function(data) {
if (self.dpPoint){
self.map.touchZoomRotate.enable();
self.map.dragPan.enable();
}
self.dpPoint = null;
}); |
@bFlood Good job. it's working as expected. |
beyond @bFlood 's solution would be checking distance between two points instead y-distance.
to
|
@cs09g Good job. How about remove the const distance = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2)); alert(distance); |
yet another solution base on @bFlood one. function addMobilePitchGesture(mbMap) {
const minDiffX = 70; // min x distance to recognize pitch gesture
const maxDiffY = 100; // max y distance to recognize pitch gesture
const minDiff = 30; // min distance to recognize zoom gesture
const delay = 160; // delay for pitch, in case it's a zoom gesture
let dpPoint;
let dpPitch;
let startTiming;
let startDistance;
let startEventData;
mbMap
.on("touchstart", data => {
if (data.points.length === 2) {
const diffY = data.points[0].y - data.points[1].y;
const diffX = data.points[0].x - data.points[1].x;
if (Math.abs(diffX) >= minDiffX && Math.abs(diffY) <= maxDiffY) {
data.originalEvent.preventDefault(); // prevent browser refresh on pull down
mbMap.touchZoomRotate.disable(); // disable native touch controls
mbMap.dragPan.disable();
dpPoint = data.point;
dpPitch = mbMap.getPitch();
startTiming = Date.now();
startDistance = Math.hypot(diffX, diffY);
startEventData = data;
}
}
})
.on("touchmove", data => {
if (dpPoint !== undefined && dpPitch !== undefined) {
data.preventDefault();
data.originalEvent.preventDefault();
const diffY = data.points[0].y - data.points[1].y;
const diffX = data.points[0].x - data.points[1].x;
const distance = Math.hypot(diffX, diffY);
if (Math.abs(distance - startDistance) >= minDiff) {
if (dpPoint) {
mbMap.touchZoomRotate.enable();
mbMap.dragPan.enable();
mbMap.touchZoomRotate.onStart(
Date.now() - startTiming >= delay
? data.originalEvent
: startEventData.originalEvent
);
}
dpPoint = undefined;
return;
}
if (Date.now() - startTiming >= delay) {
const diff = (dpPoint.y - data.point.y) * 0.5;
mbMap.setPitch(dpPitch + diff);
}
}
})
.on("touchend", () => {
if (dpPoint) {
mbMap.touchZoomRotate.enable();
mbMap.dragPan.enable();
}
dpPoint = undefined;
})
.on("touchcancel", () => {
if (dpPoint) {
mbMap.touchZoomRotate.enable();
mbMap.dragPan.enable();
}
dpPoint = undefined;
});
} |
Any updates on this? It basically means that someone that uses a mobile device can't see 3D buildings without this custom code... This is a must... |
Yet another option - this time in typescript based on @fishead code. the only difference is that if you try to rotate the map when both fingers are on the "same" y position it will rotate if they are enough apart ( import { Map, MapTouchEvent, Point } from "mapbox-gl";
export class TouchPitchHandler {
/**
* min x distance to recognize pitch gesture
*/
private static readonly MIN_DIFF_X = 55;
/**
* max x distance to recognize pitch gesture -
* this is in order to allow rotate when the fingers are spread apart enough
* and both have the "same" y value
*/
private static readonly MAX_DIFF_X = 200;
/**
* max y distance to recognize pitch gesture
*/
private static readonly MAX_DIFF_Y = 100;
/**
* min distance threshold the fingers drifted from the original touch -
* this is in order to recognize zoom gesture
*/
private static readonly MIN_DIFF = 30;
/**
* delay for pitch, in case it's a zoom gesture
*/
private static readonly DELAY = 160;
private startEventData: MapTouchEvent;
private point: Point;
private pitch: number;
private startTiming: number;
private startDistance: number;
constructor(private readonly map: Map) {
this.startEventData = null;
this.point = null;
this.pitch = null;
this.startDistance = null;
this.startTiming = null;
}
public enable() {
this.map.on("touchstart", (touchEvent: MapTouchEvent) => {
this.handleTouchStart(touchEvent);
});
this.map.on("touchmove", (touchEvent: MapTouchEvent) => {
this.handleTouchMove(touchEvent);
});
this.map.on("touchend", () => {
this.resetInteractions();
})
this.map.on("touchcancel", () => {
this.resetInteractions();
});
}
private handleTouchStart(touchEvent: MapTouchEvent) {
if (touchEvent.points.length !== 2) {
return;
}
const diffY = touchEvent.points[0].y - touchEvent.points[1].y;
const diffX = touchEvent.points[0].x - touchEvent.points[1].x;
if (Math.abs(diffX) < TouchPitchInteraction.MIN_DIFF_X
|| Math.abs(diffY) > TouchPitchInteraction.MAX_DIFF_Y
|| Math.abs(diffX) > TouchPitchInteraction.MAX_DIFF_X) {
return;
}
touchEvent.originalEvent.preventDefault(); // prevent browser refresh on pull down
this.map.touchZoomRotate.disable(); // disable native touch controls
this.map.dragPan.disable();
this.point = touchEvent.point;
this.pitch = this.map.getPitch();
this.startTiming = Date.now();
this.startDistance = Math.hypot(diffX, diffY);
this.startEventData = touchEvent;
}
private handleTouchMove(touchEvent: MapTouchEvent) {
if (this.point == null || this.pitch === null) {
return;
}
touchEvent.preventDefault();
touchEvent.originalEvent.preventDefault();
const diffY = touchEvent.points[0].y - touchEvent.points[1].y;
const diffX = touchEvent.points[0].x - touchEvent.points[1].x;
const distance = Math.hypot(diffX, diffY);
let isTimePassed = Date.now() - this.startTiming >= TouchPitchInteraction.DELAY;
if (Math.abs(distance - this.startDistance) >= TouchPitchInteraction.MIN_DIFF) {
let eventData = isTimePassed ? touchEvent.originalEvent : this.startEventData.originalEvent;
this.resetInteractions();
(this.map.touchZoomRotate as any).onStart(eventData);
return;
}
if (isTimePassed) {
const diff = (this.point.y - touchEvent.point.y) * 0.5;
this.map.setPitch(this.pitch + diff);
}
}
private resetInteractions() {
if (this.point) {
this.map.touchZoomRotate.enable();
this.map.dragPan.enable();
}
this.point = null;
}
} |
any update ? |
Thanks to everyone that has provided workarounds for this! A two-finger-drag-to-pitch gesture has been implemented by #9365. If you have a chance to test and confirm, that would be great! The fix is in |
Hello, just a heads up about the beta, it was published yesterday, feel free to give it a try and provide some feedback! https://www.npmjs.com/package/mapbox-gl/v/1.10.0-beta.1 |
I've used the relevant code since I need a patched version and it seems to be working great! I was able to remove the code I wrote for the same purpose, thanks!! |
@karimnaaji I seem to be experiencing a bug in touchend event - the |
We need gesture support on mobile web to allow the map to be pitched. The way this works gesturally on native mobile is two fingers swiped up or down, both in parallel with each other and approximately the same y-value.
Without this, there isn't a way to pitch on mobile without an external control button or similar that toggles between pitch values a là
View elevation profile
in https://www.mapbox.com/blog/dc-bikeshare-revisited/.Related: #2449
The text was updated successfully, but these errors were encountered: