mirror of
https://github.com/visgl/react-map-gl.git
synced 2025-12-08 20:16:02 +00:00
215 lines
6.3 KiB
JavaScript
215 lines
6.3 KiB
JavaScript
import test from 'tape-catch';
|
|
import MapState, {MAPBOX_LIMITS} from '../../src/utils/map-state';
|
|
import WebMercatorViewport from 'viewport-mercator-project';
|
|
import {toLowPrecision, isSameLocation} from '../test-utils';
|
|
|
|
const SAMPLE_VIEWPORTS = [
|
|
// SF
|
|
{
|
|
width: 800,
|
|
height: 600,
|
|
longitude: -122.58,
|
|
latitude: 37.74,
|
|
zoom: 14
|
|
},
|
|
// Edge location, custom zoom limit
|
|
{
|
|
width: 800,
|
|
height: 600,
|
|
longitude: -179,
|
|
latitude: 75,
|
|
zoom: 3,
|
|
maxZoom: 0.5
|
|
},
|
|
// SF with rotation, custom pitch limit
|
|
{
|
|
width: 800,
|
|
height: 600,
|
|
longitude: -122.58,
|
|
latitude: 37.74,
|
|
zoom: 14,
|
|
pitch: 60,
|
|
bearing: 45,
|
|
maxPitch: 90
|
|
}
|
|
];
|
|
|
|
test('MapState - Constructor', t => {
|
|
SAMPLE_VIEWPORTS.forEach(viewport => {
|
|
t.ok(new MapState(viewport), 'Constructed MapState instance');
|
|
});
|
|
|
|
// Normalize props
|
|
{
|
|
const mapState = new MapState(Object.assign({}, SAMPLE_VIEWPORTS[0], {longitude: -200}));
|
|
t.is(mapState.getViewportProps().longitude, 160, 'Normalized props');
|
|
}
|
|
|
|
// Missing required prop
|
|
try {
|
|
t.notOk(new MapState({width: 100, height: 100}), 'Should throw error for missing prop');
|
|
} catch (error) {
|
|
t.ok(/must be supplied/.test(error.message), 'Should throw error for missing prop');
|
|
}
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('MapState - Low zoom', t => {
|
|
|
|
const viewport = new MapState({
|
|
width: 800,
|
|
height: 600,
|
|
longitude: -179,
|
|
latitude: 80,
|
|
zoom: 0,
|
|
maxZoom: 0.5
|
|
}).getViewportProps();
|
|
|
|
t.ok(viewport.zoom > 0, 'Constrained zoom');
|
|
t.ok(Math.abs(viewport.latitude) < 1e-7, 'Centered map');
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('MapState - Pan', t => {
|
|
const POS_START = [100, 100];
|
|
const POS_IMTERMIDIATE = [200, 200];
|
|
const POS_END = [300, 300];
|
|
|
|
SAMPLE_VIEWPORTS.forEach(viewport => {
|
|
// one-off panning
|
|
const viewport1 = new MapState(viewport)
|
|
.pan({pos: POS_END, startPos: POS_START})
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.longitude) !== toLowPrecision(viewport.longitude) ||
|
|
toLowPrecision(viewport1.latitude) !== toLowPrecision(viewport.latitude),
|
|
'Map center has changed');
|
|
t.ok(viewport1.longitude < 180 &&
|
|
viewport1.longitude >= -180, 'Longitude is within bounds');
|
|
t.ok(viewport1.latitude <= 90 &&
|
|
viewport1.latitude >= -90, 'Latitude is within bounds');
|
|
t.ok(isSameLocation(
|
|
new WebMercatorViewport(viewport).unproject(POS_START),
|
|
new WebMercatorViewport(viewport1).unproject(POS_END)),
|
|
'Location under the pointer remains the same');
|
|
|
|
// chained panning
|
|
const viewport2 = new MapState(viewport)
|
|
.panStart({pos: POS_START})
|
|
.pan({pos: POS_IMTERMIDIATE})
|
|
.pan({pos: POS_END})
|
|
.panEnd()
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.longitude) === toLowPrecision(viewport2.longitude) &&
|
|
toLowPrecision(viewport1.latitude) === toLowPrecision(viewport2.latitude),
|
|
'Consistent result');
|
|
});
|
|
|
|
// insufficient arguments
|
|
const viewport = new MapState(SAMPLE_VIEWPORTS[0]);
|
|
t.is(viewport, viewport.pan({pos: POS_START}), 'Do nothing when missing argument');
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('MapState - Rotate', t => {
|
|
const X_DELTA = -0.2;
|
|
const Y_DELTA = 0.2;
|
|
|
|
SAMPLE_VIEWPORTS.forEach(viewport => {
|
|
// one-off rotating
|
|
const viewport1 = new MapState(viewport)
|
|
.rotateStart({})
|
|
.rotate({deltaScaleX: X_DELTA, deltaScaleY: Y_DELTA})
|
|
.rotateEnd()
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.bearing) !== toLowPrecision(viewport.bearing || 0),
|
|
'Bearing has changed');
|
|
t.ok(toLowPrecision(viewport1.pitch) !== toLowPrecision(viewport.pitch || 0),
|
|
'Pitch has changed');
|
|
t.ok(viewport1.pitch <= viewport1.maxPitch &&
|
|
viewport1.pitch >= viewport1.minPitch, 'Pitch is within bounds');
|
|
t.ok(viewport1.bearing < 180 &&
|
|
viewport1.bearing >= -180, 'Bearing is within bounds');
|
|
|
|
// chained rotating
|
|
const viewport2 = new MapState(viewport)
|
|
.rotateStart({})
|
|
.rotate({deltaScaleX: 0, deltaScaleY: 0})
|
|
.rotate({deltaScaleX: X_DELTA, deltaScaleY: Y_DELTA})
|
|
.rotateEnd()
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.pitch) === toLowPrecision(viewport2.pitch) &&
|
|
toLowPrecision(viewport1.bearing) === toLowPrecision(viewport2.bearing),
|
|
'Consistent result');
|
|
|
|
// out of bounds arguments
|
|
const state = new MapState(viewport).rotateStart({});
|
|
|
|
t.is(state.rotate({deltaScaleY: 2}).getViewportProps().pitch,
|
|
viewport.maxPitch || MAPBOX_LIMITS.maxPitch,
|
|
'Capped at max pitch');
|
|
|
|
t.is(state.rotate({deltaScaleY: -2}).getViewportProps().pitch,
|
|
viewport.minPitch || MAPBOX_LIMITS.minPitch,
|
|
'Capped at min pitch');
|
|
|
|
t.is(state.rotate({deltaScaleX: 2}).getViewportProps().bearing,
|
|
viewport.bearing || 0,
|
|
'Big delta X is fine');
|
|
});
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('MapState - Zoom', t => {
|
|
const POS_START = [300, 300];
|
|
const POS_IMTERMIDIATE = [200, 200];
|
|
const POS_END = [100, 100];
|
|
const SCALE = 2;
|
|
|
|
SAMPLE_VIEWPORTS.forEach(viewport => {
|
|
// one-off panning
|
|
const viewport1 = new MapState(viewport)
|
|
.zoom({pos: POS_END, startPos: POS_START, scale: SCALE})
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.zoom) !== toLowPrecision(viewport.zoom),
|
|
'Zoom has changed');
|
|
t.ok(viewport1.zoom <= viewport1.maxZoom &&
|
|
viewport1.zoom >= viewport1.minZoom, 'Zoom is within bounds');
|
|
t.ok(isSameLocation(
|
|
new WebMercatorViewport(viewport).unproject(POS_START),
|
|
new WebMercatorViewport(viewport1).unproject(POS_END)),
|
|
'Location under the pointer remains the same');
|
|
|
|
// chained panning
|
|
const viewport2 = new MapState(viewport)
|
|
.zoomStart({pos: POS_START})
|
|
.zoom({pos: POS_IMTERMIDIATE, scale: 1.5})
|
|
.zoom({pos: POS_END, scale: SCALE})
|
|
.zoomEnd()
|
|
.getViewportProps();
|
|
|
|
t.ok(toLowPrecision(viewport1.longitude) === toLowPrecision(viewport2.longitude) &&
|
|
toLowPrecision(viewport1.latitude) === toLowPrecision(viewport2.latitude) &&
|
|
toLowPrecision(viewport1.zoom) === toLowPrecision(viewport2.zoom),
|
|
'Consistent result');
|
|
});
|
|
|
|
// argument out of bounds
|
|
try {
|
|
new MapState(SAMPLE_VIEWPORTS[0]).zoom({pos: POS_END, scale: -1});
|
|
t.fail('Should throw error with out of bounds argument');
|
|
} catch (error) {
|
|
t.ok(/scale/.test(error.message), 'Should throw error with out of bounds argument');
|
|
}
|
|
|
|
t.end();
|
|
});
|