maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
92 lines (76 loc) • 3.13 kB
text/typescript
import {describe, beforeEach, afterEach, test, expect} from 'vitest';
import Point from '@mapbox/point-geometry';
import {DOM} from '../util/dom.ts';
import {beforeMapTest} from '../util/test/util.ts';
import {restoreNow, setNow} from '../util/time_control.ts';
import {Map} from './map.ts';
import type {EaseToOptions} from './camera.ts';
import {HandlerInertia} from './handler_inertia.ts';
type PanGesture = {
/**
* The pixels panned in each recorded frame, oldest first. `null` records a frame without
* any delta, which is what a terrain gesture does while the camera is not moving.
*/
frames: Array<number | null>;
/**
* The milliseconds between the recorded frames.
*/
frameTime?: number;
/**
* The milliseconds the gesture is held still between the last recorded frame and the release.
*/
holdTime?: number;
};
/**
* Records a horizontal pan gesture and returns the inertial ease it produces, if any.
*/
function panAndRelease(inertia: HandlerInertia, {frames, frameTime = 16, holdTime = 0}: PanGesture) {
let time = 1000;
setNow(time);
for (const pixels of frames) {
setNow(time += frameTime);
inertia.record(pixels === null ? {} : {panDelta: new Point(pixels, 0)});
}
setNow(time + holdTime);
return inertia._onMoveEnd();
}
/**
* Returns the horizontal distance the map keeps panning after the gesture ended.
*/
function panOnDistance(ease: EaseToOptions) {
return (ease.offset as Point).x;
}
describe('HandlerInertia', () => {
let map: Map;
let inertia: HandlerInertia;
beforeEach(() => {
beforeMapTest();
map = new Map({container: DOM.create('div', '', window.document.body)});
inertia = new HandlerInertia(map);
});
afterEach(() => {
restoreNow();
map.remove();
});
test('pans on when the gesture is released while still moving', () => {
const ease = panAndRelease(inertia, {frames: [20, 20, 20, 20, 20]});
expect(panOnDistance(ease)).toBeGreaterThan(50);
});
test('barely pans on when the gesture is held still before being released', () => {
const ease = panAndRelease(inertia, {frames: [20, 20, 20, 20, 20], holdTime: 100});
expect(Math.abs(panOnDistance(ease))).toBeLessThan(5);
});
test('pans on at frame rates too low for two frames to fit into the velocity window', () => {
const ease = panAndRelease(inertia, {frames: [80, 80, 80], frameTime: 80});
expect(panOnDistance(ease)).toBeGreaterThan(20);
});
test('does not pan on when a single frame was recorded, twice in a row', () => {
expect(panAndRelease(inertia, {frames: [20]})).toBeUndefined();
// the frame left over by the first gesture must not be measured as part of the second
expect(panAndRelease(inertia, {frames: [20]})).toBeUndefined();
});
test('does not ease when the recorded frames hold no movement', () => {
const ease = panAndRelease(inertia, {frames: [20, 20, 20, null, null, null, null]});
expect(ease).toBeUndefined();
});
});