diff --git a/.gitignore b/.gitignore index 24de88105db..cf0e2727407 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ _site yarn-error.log yarn-debug.log npm-debug.log +.vscode/ diff --git a/src/ui/handler/drag_pan.js b/src/ui/handler/drag_pan.js index 9d78e877d71..6865d88d975 100644 --- a/src/ui/handler/drag_pan.js +++ b/src/ui/handler/drag_pan.js @@ -1,7 +1,7 @@ // @flow import DOM from '../../util/dom'; -import { bezier, bindAll } from '../../util/util'; +import { bindAll } from '../../util/util'; import window from '../../util/window'; import browser from '../../util/browser'; import { Event } from '../../util/evented'; @@ -11,10 +11,12 @@ import type Map from '../map'; import type Point from '@mapbox/point-geometry'; import type {TaskID} from '../../util/task_queue'; -const inertiaLinearity = 0.3, - inertiaEasing = bezier(0, 0, inertiaLinearity, 1), - inertiaMaxSpeed = 1400, // px/s - inertiaDeceleration = 2500; // px/s^2 +export type DragInertia = { + linearity: number, + easing: (t: number) => number, + maxSpeed: number, + deceleration: number, +}; /** * The `DragPanHandler` allows the user to pan the map by clicking and dragging @@ -31,17 +33,20 @@ class DragPanHandler { _inertia: Array<[number, Point]>; _frameId: ?TaskID; _clickTolerance: number; + _dragInertia: DragInertia; /** * @private */ constructor(map: Map, options: { - clickTolerance?: number + clickTolerance?: number, + dragInertia: DragInertia }) { this._map = map; this._el = map.getCanvasContainer(); this._state = 'disabled'; this._clickTolerance = options.clickTolerance || 1; + this._dragInertia = options.dragInertia; bindAll([ '_onMove', @@ -290,20 +295,22 @@ class DragPanHandler { } // calculate px/s velocity & adjust for increased initial animation speed when easing out - const velocity = flingOffset.mult(inertiaLinearity / flingDuration); + const {linearity, easing, maxSpeed, deceleration} = this._dragInertia; + + const velocity = flingOffset.mult(linearity / flingDuration); let speed = velocity.mag(); // px/s - if (speed > inertiaMaxSpeed) { - speed = inertiaMaxSpeed; + if (speed > maxSpeed) { + speed = maxSpeed; velocity._unit()._mult(speed); } - const duration = speed / (inertiaDeceleration * inertiaLinearity), + const duration = speed / (deceleration * linearity), offset = velocity.mult(-duration / 2); this._map.panBy(offset, { duration: duration * 1000, - easing: inertiaEasing, + easing, noMoveStart: true }, { originalEvent: e }); } diff --git a/src/ui/map.js b/src/ui/map.js index fd4a6967305..f37980e3586 100755 --- a/src/ui/map.js +++ b/src/ui/map.js @@ -1,6 +1,6 @@ // @flow -import { extend, bindAll, warnOnce, uniqueId } from '../util/util'; +import { extend, bezier, bindAll, warnOnce, uniqueId } from '../util/util'; import browser from '../util/browser'; import window from '../util/window'; @@ -39,7 +39,7 @@ import type {StyleImageInterface} from '../style/style_image'; import type ScrollZoomHandler from './handler/scroll_zoom'; import type BoxZoomHandler from './handler/box_zoom'; import type DragRotateHandler from './handler/drag_rotate'; -import type DragPanHandler from './handler/drag_pan'; +import type DragPanHandler, {DragInertia} from './handler/drag_pan'; import type KeyboardHandler from './handler/keyboard'; import type DoubleClickZoomHandler from './handler/dblclick_zoom'; import type TouchZoomRotateHandler from './handler/touch_zoom_rotate'; @@ -85,6 +85,7 @@ type MapOptions = { boxZoom?: boolean, dragRotate?: boolean, dragPan?: boolean, + dragInertia?: $Shape, keyboard?: boolean, doubleClickZoom?: boolean, touchZoomRotate?: boolean, @@ -114,6 +115,12 @@ const defaultOptions = { boxZoom: true, dragRotate: true, dragPan: true, + dragInertia: { + linearity: 0.3, + easing: bezier(0, 0, 0.3, 1), + maxSpeed: 1400, + deceleration: 2500, + }, keyboard: true, doubleClickZoom: true, touchZoomRotate: true, @@ -193,6 +200,7 @@ const defaultOptions = { * @param {boolean} [options.boxZoom=true] If `true`, the "box zoom" interaction is enabled (see {@link BoxZoomHandler}). * @param {boolean} [options.dragRotate=true] If `true`, the "drag to rotate" interaction is enabled (see {@link DragRotateHandler}). * @param {boolean} [options.dragPan=true] If `true`, the "drag to pan" interaction is enabled (see {@link DragPanHandler}). + * @param {DragInertia} [options.dragInertia] If set, the drag inertia will obey the given parameters. * @param {boolean} [options.keyboard=true] If `true`, keyboard shortcuts are enabled (see {@link KeyboardHandler}). * @param {boolean} [options.doubleClickZoom=true] If `true`, the "double click to zoom" interaction is enabled (see {@link DoubleClickZoomHandler}). * @param {boolean|Object} [options.touchZoomRotate=true] If `true`, the "pinch to rotate and zoom" interaction is enabled. An `Object` value is passed as options to {@link TouchZoomRotateHandler#enable}. @@ -312,6 +320,7 @@ class Map extends Camera { constructor(options: MapOptions) { options = extend({}, defaultOptions, options); + options.dragInertia = extend({}, defaultOptions.dragInertia, options.dragInertia); if (options.minZoom != null && options.maxZoom != null && options.minZoom > options.maxZoom) { throw new Error(`maxZoom must be greater than minZoom`); diff --git a/src/util/util.js b/src/util/util.js index e39b4e2ca4e..5a20bb42fc9 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -28,7 +28,7 @@ export function easeCubicInOut(t: number): number { } /** - * Given given (x, y), (x1, y1) control points for a bezier curve, + * Given (x, y), (x1, y1) control points for a bezier curve, * return a function that interpolates along that curve. * * @param p1x control point 1 x coordinate