const extent = require('geojson-extent');
const Constants = require('../constants');
const {
LAT_MIN,
LAT_MAX,
LAT_RENDERED_MIN,
LAT_RENDERED_MAX,
LNG_MIN,
LNG_MAX
} = Constants;
// 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
module.exports = 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;
};
|