Skip to content

Commit

Permalink
Merge pull request mapbox#457 from mapbox/move-feature-limits
Browse files Browse the repository at this point in the history
Move feature limits
  • Loading branch information
mcwhittemore authored Jul 7, 2016
2 parents 3eac361 + 0321c8b commit 525e415
Show file tree
Hide file tree
Showing 13 changed files with 891 additions and 112 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
},
"dependencies": {
"geojson-area": "^0.2.1",
"geojson-extent": "^0.3.2",
"geojson-normalize": "0.0.1",
"geojsonhint": "^1.2.0",
"hat": "0.0.3",
Expand Down
8 changes: 7 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,11 @@ module.exports = {
activeStates: {
ACTIVE: 'true',
INACTIVE: 'false'
}
},
LAT_MIN: -90,
LAT_RENDERED_MIN: -85,
LAT_MAX: 90,
LAT_RENDERED_MAX: 85,
LNG_MIN: -270,
LNG_MAX: 270
};
67 changes: 67 additions & 0 deletions src/lib/constrain_feature_movement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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
let 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;
};
9 changes: 9 additions & 0 deletions src/lib/create_midpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ module.exports = function(parent, startVertex, endVertex, map) {
var startCoord = startVertex.geometry.coordinates;
var endCoord = endVertex.geometry.coordinates;

// If a coordinate exceeds the projection, we can't calculate a midpoint,
// so run away
if (startCoord[1] > Constants.LAT_RENDERED_MAX
|| startCoord[1] < Constants.LAT_RENDERED_MIN
|| endCoord[1] > Constants.LAT_RENDERED_MAX
|| endCoord[1] < Constants.LAT_RENDERED_MIN) {
return null;
}

var ptA = map.project([ startCoord[0], startCoord[1] ]);
var ptB = map.project([ endCoord[0], endCoord[1] ]);
var mid = map.unproject([ (ptA.x + ptB.x) / 2, (ptA.y + ptB.y) / 2 ]);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/create_supplementary_points.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) {
// vertex before this one. If so, add a midpoint
// between that vertex and this one.
if (options.midpoints && lastVertex) {
supplementaryPoints.push(createMidpoint(featureId, lastVertex, vertex, options.map));
const midpoint = createMidpoint(featureId, lastVertex, vertex, options.map);
if (midpoint) supplementaryPoints.push(midpoint);
}
lastVertex = vertex;

Expand Down
25 changes: 0 additions & 25 deletions src/lib/move_feature.js

This file was deleted.

28 changes: 28 additions & 0 deletions src/lib/move_features.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const xtend = require('xtend');
const constrainFeatureMovement = require('./constrain_feature_movement');
const Constants = require('../constants');

module.exports = function(features, delta) {
const constrainedDelta = constrainFeatureMovement(features.map(feature => feature.toGeoJSON()), delta);

features.forEach(feature => {
const currentCoordinates = feature.getCoordinates();

const moveCoordinate = (coord) => [coord[0] + constrainedDelta.lng, coord[1] + constrainedDelta.lat];
const moveRing = (ring) => ring.map(coord => moveCoordinate(coord));
const moveMultiPolygon = (multi) => multi.map(ring => moveRing(ring));

let nextCoordinates;
if (feature.type === Constants.geojsonTypes.POINT) {
nextCoordinates = moveCoordinate(currentCoordinates);
} else if (feature.type === Constants.geojsonTypes.LINE_STRING || feature.type === Constants.geojsonTypes.MULTI_POINT) {
nextCoordinates = currentCoordinates.map(moveCoordinate);
} else if (feature.type === Constants.geojsonTypes.POLYGON || feature.type === Constants.geojsonTypes.MULTI_LINE_STRING) {
nextCoordinates = currentCoordinates.map(moveRing);
} else if (feature.type === Constants.geojsonTypes.MULTI_POLYGON) {
nextCoordinates = currentCoordinates.map(moveMultiPolygon);
}

feature.incomingCoords(nextCoordinates);
});
};
6 changes: 1 addition & 5 deletions src/modes/direct_select.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = function(ctx, opts) {
};

var startDragging = function(e) {
ctx.map.dragPan.disable();
canDragMove = true;
startPos = e.lngLat;
};
Expand All @@ -74,11 +75,6 @@ module.exports = function(ctx, opts) {
ctx.store.setSelected(featureId);
doubleClickZoom.disable(ctx);

// Anytime the mouse goes down in the active feature, disable dragPan
this.on('mousedown', e => isVertex(e) || isMidpoint(e), () => {
ctx.map.dragPan.disable();
});

// On mousemove that is not a drag, stop vertex movement.
this.on('mousemove', CommonSelectors.true, stopDragging);

Expand Down
12 changes: 6 additions & 6 deletions src/modes/simple_select.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const featuresAt = require('../lib/features_at');
const createSupplementaryPoints = require('../lib/create_supplementary_points');
const StringSet = require('../lib/string_set');
const doubleClickZoom = require('../lib/double_click_zoom');
const moveFeature = require('../lib/move_feature');
const moveFeatures = require('../lib/move_features');
const Constants = require('../constants');

module.exports = function(ctx, options = {}) {
Expand Down Expand Up @@ -153,12 +153,12 @@ module.exports = function(ctx, options = {}) {
dragMoving = true;
e.originalEvent.stopPropagation();

const lngDelta = e.lngLat.lng - dragMoveLocation.lng;
const latDelta = e.lngLat.lat - dragMoveLocation.lat;
const delta = {
lng: e.lngLat.lng - dragMoveLocation.lng,
lat: e.lngLat.lat - dragMoveLocation.lat
};

ctx.store.getSelected().forEach(feature => {
moveFeature(feature, lngDelta, latDelta);
});
moveFeatures(ctx.store.getSelected(), delta);

dragMoveLocation = e.lngLat;
});
Expand Down
Loading

0 comments on commit 525e415

Please sign in to comment.