@mapbox/mapbox-gl-draw
Version:
A drawing component for Mapbox GL JS
84 lines (75 loc) • 2.95 kB
JavaScript
import * as Constants from '../constants.js';
const {
LAT_MIN,
LAT_MAX,
LAT_RENDERED_MIN,
LAT_RENDERED_MAX,
LNG_MIN,
LNG_MAX,
} = Constants;
function extent(feature) {
const depth = {
Point: 0,
LineString: 1,
Polygon: 2,
MultiPoint: 1,
MultiLineString: 2,
MultiPolygon: 3,
}[feature.geometry.type];
const coords = [feature.geometry.coordinates].flat(depth);
const lngs = coords.map(coord => coord[0]);
const lats = coords.map(coord => coord[1]);
const min = vals => Math.min.apply(null, vals);
const max = vals => Math.max.apply(null, vals);
return [min(lngs), min(lats), max(lngs), max(lats)];
}
// Ensure that we do not drag north-south far enough for
// - any part of any feature to exceed the poles
// - any feature to be completely lost in the space between the projection's
// edge and the poles, such that it couldn't be re-selected and moved back
export default function(geojsonFeatures, delta) {
// "inner edge" = a feature's latitude closest to the equator
let northInnerEdge = LAT_MIN;
let southInnerEdge = LAT_MAX;
// "outer edge" = a feature's latitude furthest from the equator
let northOuterEdge = LAT_MIN;
let southOuterEdge = LAT_MAX;
let westEdge = LNG_MAX;
let eastEdge = LNG_MIN;
geojsonFeatures.forEach((feature) => {
const bounds = extent(feature);
const featureSouthEdge = bounds[1];
const featureNorthEdge = bounds[3];
const featureWestEdge = bounds[0];
const featureEastEdge = bounds[2];
if (featureSouthEdge > northInnerEdge) northInnerEdge = featureSouthEdge;
if (featureNorthEdge < southInnerEdge) southInnerEdge = featureNorthEdge;
if (featureNorthEdge > northOuterEdge) northOuterEdge = featureNorthEdge;
if (featureSouthEdge < southOuterEdge) southOuterEdge = featureSouthEdge;
if (featureWestEdge < westEdge) westEdge = featureWestEdge;
if (featureEastEdge > eastEdge) eastEdge = featureEastEdge;
});
// These changes are not mutually exclusive: we might hit the inner
// edge but also have hit the outer edge and therefore need
// another readjustment
const constrainedDelta = delta;
if (northInnerEdge + constrainedDelta.lat > LAT_RENDERED_MAX) {
constrainedDelta.lat = LAT_RENDERED_MAX - northInnerEdge;
}
if (northOuterEdge + constrainedDelta.lat > LAT_MAX) {
constrainedDelta.lat = LAT_MAX - northOuterEdge;
}
if (southInnerEdge + constrainedDelta.lat < LAT_RENDERED_MIN) {
constrainedDelta.lat = LAT_RENDERED_MIN - southInnerEdge;
}
if (southOuterEdge + constrainedDelta.lat < LAT_MIN) {
constrainedDelta.lat = LAT_MIN - southOuterEdge;
}
if (westEdge + constrainedDelta.lng <= LNG_MIN) {
constrainedDelta.lng += Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360;
}
if (eastEdge + constrainedDelta.lng >= LNG_MAX) {
constrainedDelta.lng -= Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360;
}
return constrainedDelta;
}