Skip to content

Commit

Permalink
Add support for 2-finger pan and zoom gestures
Browse files Browse the repository at this point in the history
Also adjust the zooming delta function on Firefox
(which uses wheel events in line units instead of pixel units)
  • Loading branch information
bhousel committed Nov 20, 2018
1 parent b7e218a commit 45a3e58
Showing 1 changed file with 83 additions and 47 deletions.
130 changes: 83 additions & 47 deletions modules/renderer/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function rendererMap(context) {
var dimensions = [1, 1];
var _dblClickEnabled = true;
var _redrawEnabled = true;
var _scaleLast;
var _transformStart = projection.transform();
var _transformLast;
var _transformed = false;
Expand Down Expand Up @@ -178,36 +179,10 @@ export function rendererMap(context) {
.selectAll('.surface')
.attr('id', 'surface');


var prevScale;

surface
.call(drawLabels.observe)
.on('gesturestart.surface', function() {
prevScale = d3_event.scale;
})
.on('gesturechange.surface', function() {
// Remap Safari gesture events to wheel events - #5492
// We want these disabled most places, but enabled for zoom/unzoom on map surface
// https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
var e = d3_event;
e.preventDefault();

var deltaY = (e.scale > prevScale) ? -15 : 20;
prevScale = e.scale;

var props = {
deltaY: deltaY ,
clientX: e.clientX,
clientY: e.clientY,
screenX: e.screenX,
screenY: e.screenY,
x: e.x,
y: e.y
};
var e2 = new WheelEvent('wheel', props);
_selection.node().dispatchEvent(e2);
})
.on('gesturestart.surface', gestureStart)
.on('gesturechange.surface', gestureChange)
.on('mousedown.zoom', function() {
if (d3_event.button === 2) {
d3_event.stopPropagation();
Expand Down Expand Up @@ -391,6 +366,34 @@ export function rendererMap(context) {
}
}

function gestureStart() {
_scaleLast = d3_event.scale;
}

function gestureChange() {
// Remap Safari gesture events to wheel events - #5492
// We want these disabled most places, but enabled for zoom/unzoom on map surface
// https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
var e = d3_event;
e.preventDefault();

var deltaY = (e.scale > _scaleLast) ? -10 : 10;
_scaleLast = e.scale;

var props = {
ctrlKey: true,
deltaY: deltaY,
clientX: e.clientX,
clientY: e.clientY,
screenX: e.screenX,
screenY: e.screenY,
x: e.x,
y: e.y
};
var e2 = new WheelEvent('wheel', props);
_selection.node().dispatchEvent(e2);
}


function zoomPan(manualEvent) {
var event = (manualEvent || d3_event);
Expand All @@ -403,28 +406,52 @@ export function rendererMap(context) {
return; // no change
}

// Normalize mousewheel - #3029
// If wheel delta is provided in LINE units, recalculate it in PIXEL units
// We are essentially redoing the calculations that occur here:
// https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
// See this for more info:
// https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
// pick sensible scroll amount if user scrolling fast or slow..
var lines = Math.abs(source.deltaY);
var scroll = lines > 2 ? 40 : lines * 10;

var t0 = _transformed ? _transformLast : _transformStart;
var p0 = mouse(source);
var p1 = t0.invert(p0);
var k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500);
var x2 = p0[0] - p1[0] * k2;
var y2 = p0[1] - p1[1] * k2;
// Special handling of 'wheel' events:
// They might be triggered by the user scrolling the mouse wheel,
// or 2-finger pinch/zoom gestures, the transform may need adjustment.
if (source && source.type === 'wheel') {
var dX = source.deltaX;
var dY = source.deltaY;

// Normalize mousewheel scroll speed - #3029
// If wheel delta is provided in LINE units, recalculate it in PIXEL units
// We are essentially redoing the calculations that occur here:
// https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
// See this for more info:
// https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
if (source.deltaMode === 1 /* LINE */) {
// pick sensible scroll amount if user scrolling fast or slow..
var lines = clamp(Math.abs(source.deltaY), 0, 12);
var sign = (source.deltaY > 0) ? 1 : -1;
dY = sign * Math.exp((lines - 1) * 0.35) * 4.000244140625;

var t0 = _transformed ? _transformLast : _transformStart;
var p0 = mouse(source);
var p1 = t0.invert(p0);
var k2 = t0.k * Math.pow(2, -dY / 500);
var x2 = p0[0] - p1[0] * k2;
var y2 = p0[1] - p1[1] * k2;

eventTransform = d3_zoomIdentity.translate(x2, y2).scale(k2);
_selection.node().__zoom = eventTransform;
}

eventTransform = d3_zoomIdentity.translate(x2,y2).scale(k2);
_selection.node().__zoom = eventTransform;
// Support 2 finger map panning - #5492
// Panning via the `wheel` event will always have
// - `ctrlKey = false`
// - `deltaX`,`deltaY` are perfect integer pixels
if (!source.ctrlKey && isInteger(dX) && isInteger(dY)) {
var p = projection.translate();
var k = projection.scale();

p[0] -= dX;
p[1] -= dY;
eventTransform = d3_zoomIdentity.translate(p[0], p[1]).scale(k);
_selection.node().__zoom = eventTransform;
}
}


if (geoScaleToZoom(eventTransform.k, TILESIZE) < minzoom) {
surface.interrupt();
uiFlash().text(t('cannot_zoom'))();
Expand Down Expand Up @@ -455,6 +482,15 @@ export function rendererMap(context) {
scheduleRedraw();

dispatch.call('move', this, map);


function clamp(num, min, max) {
return Math.max(min, Math.min(num, max));
}

function isInteger(val) {
return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
}
}


Expand Down

0 comments on commit 45a3e58

Please sign in to comment.