Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

git dif #4

Open
wants to merge 33 commits into
base: last-official-mapbox-gl-draw-commit
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8e06744
Fix selection event in direct_select w/ coordPath
Zirak Jun 29, 2019
29dd32e
trash correct vertices by changing sort to be numeric-aware
kkaefer Dec 18, 2019
fb2b9c3
WIP snapping for line features.
stevage Dec 24, 2019
9d6e8e7
Merge remote-tracking branch 'origin/skip-render-for-select-handler-m…
stevage Dec 24, 2019
4ce8443
Support snapping to polygons.
stevage Dec 30, 2019
7e9afa6
Refactor.
stevage Dec 30, 2019
816c7ab
Configurable snap distance.
stevage Dec 30, 2019
8c768e9
Refactoring, additional snapping combinations.
stevage Dec 30, 2019
c783170
Skip rerenders for mousemove handlers when in selection modes
kkaefer Dec 18, 2019
1ab4ffc
WIP snapping for line features.
stevage Dec 24, 2019
5ce4a08
Support snapping to polygons.
stevage Dec 30, 2019
28a86ac
Refactor.
stevage Dec 30, 2019
ef6d287
Configurable snap distance.
stevage Dec 30, 2019
072e5c1
Refactoring, additional snapping combinations.
stevage Dec 30, 2019
a3f4d6c
Updates, formatting.
stevage May 28, 2020
e61c1c8
Merge branch 'snapping' of github.com:stevage/mapbox-gl-draw into sna…
stevage May 28, 2020
a4ecaad
Merge remote-tracking branch 'Zirak/direct-select-selectionchange' in…
stevage May 28, 2020
9cbb782
Fix bug with point snapping lagging.
stevage May 28, 2020
c299ec6
Add clearSnapCoord()
stevage May 29, 2020
5f0865d
Refactor snapping.js to remove unused circle-stroke properties
edforsberg Sep 3, 2024
ddaf2ca
Refactor render.js for improved performance and readability
edforsberg Sep 5, 2024
c93ab58
Refactor render.js to fix filter function syntax error
edforsberg Sep 5, 2024
00871f8
Refactor render.js to fix filter function syntax error
edforsberg Sep 5, 2024
13e8ade
Merge pull request #1 from ParametricSolutions/add-filter-in-renderer
edforsberg Sep 5, 2024
ebd4826
Refactor snapping.js to optimize performance and remove unused proper…
edforsberg Sep 9, 2024
a4e7a13
Refactor snapping.js to use map instance for layer check
edforsberg Sep 9, 2024
681e7ed
Merge pull request #2 from ParametricSolutions/add-layer-exists-check
edforsberg Sep 9, 2024
c8a2bc5
Refactor snapping.js to set snap-hover state for guidelines
edforsberg Sep 13, 2024
6335a3d
Refactor snapping.js to parse guidelineIds as JSON
edforsberg Sep 13, 2024
6c09498
Refactor snapping.js to parse guidelineIds as JSON and set snap-hover…
edforsberg Sep 13, 2024
2a2b03c
Refactor snapping.js to remove unused code and console logs
edforsberg Sep 13, 2024
14cba18
Refactor snapping.js to remove unused code and console logs
edforsberg Sep 13, 2024
ebb334c
Merge pull request #3 from ParametricSolutions/hover-state-guidelines
edforsberg Sep 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"@mapbox/geojson-normalize": "0.0.1",
"@mapbox/geojsonhint": "3.0.0",
"@mapbox/point-geometry": "0.1.0",
"@turf/turf": "^5.1.6",
"hat": "0.0.3",
"lodash.isequal": "^4.2.0",
"xtend": "^4.0.1"
Expand Down
31 changes: 22 additions & 9 deletions src/modes/direct_select.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ DirectSelect.onSetup = function(opts) {
selectedCoordPaths: opts.coordPath ? [opts.coordPath] : []
};

this.setSelectedCoordinates(this.pathsToCoordinates(featureId, state.selectedCoordPaths));
this.setSelected(featureId);
this.setSelectedCoordinates(this.pathsToCoordinates(featureId, state.selectedCoordPaths));
doubleClickZoom.disable(this);

this.setActionableState({
Expand Down Expand Up @@ -165,7 +165,11 @@ DirectSelect.toDisplayFeatures = function(state, geojson, push) {
};

DirectSelect.onTrash = function(state) {
state.selectedCoordPaths.sort().reverse().forEach(id => state.feature.removeCoordinate(id));
// Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them
// in reverse order so that we can remove by index safely.
state.selectedCoordPaths
.sort((a, b) => b.localeCompare(a, 'en', { numeric: true }))
.forEach(id => state.feature.removeCoordinate(id));
this.fireUpdate();
state.selectedCoordPaths = [];
this.clearSelectedCoordinates();
Expand Down Expand Up @@ -208,15 +212,24 @@ DirectSelect.onDrag = function(state, e) {
if (state.canDragMove !== true) return;
state.dragMoving = true;
e.originalEvent.stopPropagation();
let lngLat = e.lngLat;

const delta = {
lng: e.lngLat.lng - state.dragMoveLocation.lng,
lat: e.lngLat.lat - state.dragMoveLocation.lat
};
if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta);
else this.dragFeature(state, e, delta);
if (state.selectedCoordPaths.length === 1) {
lngLat = this._ctx.snapping.snapCoord(e.lngLat);
// following the dragVertex() path below seems to cause a lag where our point
// ends up one step behind the snapped location
state.feature.updateCoordinate(state.selectedCoordPaths[0], lngLat.lng, lngLat.lat);
} else {

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

if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta);
else this.dragFeature(state, e, delta);
}
state.dragMoveLocation = lngLat;
};

DirectSelect.onClick = function(state, e) {
Expand Down
14 changes: 9 additions & 5 deletions src/modes/draw_line_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,28 @@ DrawLineString.onSetup = function(opts) {

DrawLineString.clickAnywhere = function(state, e) {
if (state.currentVertexPosition > 0 && isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition - 1]) ||
state.direction === 'backwards' && isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition + 1])) {
state.direction === 'backwards' && isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition + 1])) {
return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] });
}
this.updateUIClasses({ mouse: Constants.cursors.ADD });
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
const lngLat = this._ctx.snapping.snapCoord(e.lngLat);
state.line.updateCoordinate(state.currentVertexPosition, lngLat.lng, lngLat.lat);
if (state.direction === 'forward') {
state.currentVertexPosition++;
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
state.line.updateCoordinate(state.currentVertexPosition, lngLat.lng, lngLat.lat);
} else {
state.line.addCoordinate(0, e.lngLat.lng, e.lngLat.lat);
state.line.addCoordinate(0, lngLat.lng, lngLat.lat);
}
};

DrawLineString.clickOnVertex = function(state) {
return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] });
};


DrawLineString.onMouseMove = function(state, e) {
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
const lngLat = this._ctx.snapping.snapCoord(e.lngLat);
state.line.updateCoordinate(state.currentVertexPosition, lngLat.lng, lngLat.lat);
if (CommonSelectors.isVertex(e)) {
this.updateUIClasses({ mouse: Constants.cursors.POINTER });
}
Expand Down Expand Up @@ -149,4 +152,5 @@ DrawLineString.toDisplayFeatures = function(state, geojson, display) {
display(geojson);
};


module.exports = DrawLineString;
4 changes: 3 additions & 1 deletion src/modes/draw_point.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ DrawPoint.stopDrawingAndRemove = function(state) {

DrawPoint.onTap = DrawPoint.onClick = function(state, e) {
this.updateUIClasses({ mouse: Constants.cursors.MOVE });
state.point.updateCoordinate('', e.lngLat.lng, e.lngLat.lat);
const lngLat = this._ctx.snapping.snapCoord(e.lngLat);

state.point.updateCoordinate('', lngLat.lng, lngLat.lat);
this.map.fire(Constants.events.CREATE, {
features: [state.point.toGeoJSON()]
});
Expand Down
8 changes: 5 additions & 3 deletions src/modes/draw_polygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,19 @@ DrawPolygon.clickAnywhere = function(state, e) {
return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] });
}
this.updateUIClasses({ mouse: Constants.cursors.ADD });
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat);
const lngLat = this._ctx.snapping.snapCoord(e.lngLat);
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, lngLat.lng, lngLat.lat);
state.currentVertexPosition++;
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat);
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, lngLat.lng, lngLat.lat);
};

DrawPolygon.clickOnVertex = function(state) {
return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] });
};

DrawPolygon.onMouseMove = function(state, e) {
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat);
const lngLat = this._ctx.snapping.snapCoord(e.lngLat);
state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, lngLat.lng, lngLat.lat);
if (CommonSelectors.isVertex(e)) {
this.updateUIClasses({ mouse: Constants.cursors.POINTER });
}
Expand Down
23 changes: 14 additions & 9 deletions src/modes/simple_select.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,20 @@ SimpleSelect.dragMove = function(state, e) {
// Dragging when drag move is enabled
state.dragMoving = true;
e.originalEvent.stopPropagation();

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

moveFeatures(this.getSelected(), delta);

state.dragMoveLocation = e.lngLat;
let lngLat = e.lngLat;
// TODO more efficient
if (this.getSelected().length === 1 && this.getSelected()[0].type === 'Point') {
lngLat = this._ctx.snapping.snapCoord(e.lngLat);
this.getSelected()[0].incomingCoords([lngLat.lng, lngLat.lat])
} else {
const delta = {
lng: lngLat.lng - state.dragMoveLocation.lng,
lat: lngLat.lat - state.dragMoveLocation.lat
};

moveFeatures(this.getSelected(), delta);
}
state.dragMoveLocation = lngLat;
};

SimpleSelect.onMouseUp = function(state, e) {
Expand Down
29 changes: 19 additions & 10 deletions src/options.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const xtend = require('xtend');
const Constants = require('./constants');
const xtend = require("xtend");
const Constants = require("./constants");

const defaultOptions = {
defaultMode: Constants.modes.SIMPLE_SELECT,
Expand All @@ -9,10 +9,16 @@ const defaultOptions = {
touchBuffer: 25,
boxSelect: true,
displayControlsDefault: true,
styles: require('./lib/theme'),
modes: require('./modes'),
styles: require("./lib/theme"),
modes: require("./modes"),
controls: {},
userProperties: false
userProperties: false,
snapLayers: [],
snapFeatureFilter: undefined,
snapDistance: 20,
snapping: {
layers: [],
},
};

const showControls = {
Expand All @@ -21,7 +27,7 @@ const showControls = {
polygon: true,
trash: true,
combine_features: true,
uncombine_features: true
uncombine_features: true,
};

const hideControls = {
Expand All @@ -30,20 +36,21 @@ const hideControls = {
polygon: false,
trash: false,
combine_features: false,
uncombine_features: false
uncombine_features: false,
};

function addSources(styles, sourceBucket) {
return styles.map((style) => {
if (style.source) return style;
return xtend(style, {
id: `${style.id}.${sourceBucket}`,
source: (sourceBucket === 'hot') ? Constants.sources.HOT : Constants.sources.COLD
source:
sourceBucket === "hot" ? Constants.sources.HOT : Constants.sources.COLD,
});
});
}

module.exports = function(options = {}) {
module.exports = function (options = {}) {
let withDefaults = xtend(options);

if (!options.controls) {
Expand All @@ -59,7 +66,9 @@ module.exports = function(options = {}) {
withDefaults = xtend(defaultOptions, withDefaults);

// Layers with a shared source should be adjacent for performance reasons
withDefaults.styles = addSources(withDefaults.styles, 'cold').concat(addSources(withDefaults.styles, 'hot'));
withDefaults.styles = addSources(withDefaults.styles, "cold").concat(
addSources(withDefaults.styles, "hot")
);

return withDefaults;
};
63 changes: 42 additions & 21 deletions src/render.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const Constants = require('./constants');
const Constants = require("./constants");

module.exports = function render() {
const store = this;
const mapExists = store.ctx.map && store.ctx.map.getSource(Constants.sources.HOT) !== undefined;
const mapExists =
store.ctx.map &&
store.ctx.map.getSource(Constants.sources.HOT) !== undefined;
if (!mapExists) return cleanup();

const mode = store.ctx.events.currentModeName();
Expand All @@ -15,20 +17,32 @@ module.exports = function render() {
if (store.isDirty) {
newColdIds = store.getAllIds();
} else {
newHotIds = store.getChangedIds().filter(id => store.get(id) !== undefined);
newColdIds = store.sources.hot.filter(geojson => geojson.properties.id && newHotIds.indexOf(geojson.properties.id) === -1 && store.get(geojson.properties.id) !== undefined).map(geojson => geojson.properties.id);
newHotIds = store
.getChangedIds()
.filter((id) => store.get(id) !== undefined);
newColdIds = store.sources.hot
.filter(
(geojson) =>
geojson.properties.id &&
newHotIds.indexOf(geojson.properties.id) === -1 &&
store.get(geojson.properties.id) !== undefined
)
.map((geojson) => geojson.properties.id);
}

store.sources.hot = [];
const lastColdCount = store.sources.cold.length;
store.sources.cold = store.isDirty ? [] : store.sources.cold.filter((geojson) => {
const id = geojson.properties.id || geojson.properties.parent;
return newHotIds.indexOf(id) === -1;
});

const coldChanged = lastColdCount !== store.sources.cold.length || newColdIds.length > 0;
newHotIds.forEach(id => renderFeature(id, 'hot'));
newColdIds.forEach(id => renderFeature(id, 'cold'));
store.sources.cold = store.isDirty
? []
: store.sources.cold.filter((geojson) => {
const id = geojson.properties.id || geojson.properties.parent;
return newHotIds.indexOf(id) === -1;
});

const coldChanged =
lastColdCount !== store.sources.cold.length || newColdIds.length > 0;
newHotIds.forEach((id) => renderFeature(id, "hot"));
newColdIds.forEach((id) => renderFeature(id, "cold"));

function renderFeature(id, source) {
const feature = store.get(id);
Expand All @@ -41,37 +55,44 @@ module.exports = function render() {
if (coldChanged) {
store.ctx.map.getSource(Constants.sources.COLD).setData({
type: Constants.geojsonTypes.FEATURE_COLLECTION,
features: store.sources.cold
features: store.sources.cold,
});
}

store.ctx.map.getSource(Constants.sources.HOT).setData({
type: Constants.geojsonTypes.FEATURE_COLLECTION,
features: store.sources.hot
features: store.sources.hot,
});

if (store._emitSelectionChange) {
store.ctx.map.fire(Constants.events.SELECTION_CHANGE, {
features: store.getSelected().map(feature => feature.toGeoJSON()),
points: store.getSelectedCoordinates().map(coordinate => ({
features: store
.getSelected()
.filter((feature) => {
feature != undefined;
})
.map((feature) => feature.toGeoJSON()),
points: store.getSelectedCoordinates().map((coordinate) => ({
type: Constants.geojsonTypes.FEATURE,
properties: {},
geometry: {
type: Constants.geojsonTypes.POINT,
coordinates: coordinate.coordinates
}
}))
coordinates: coordinate.coordinates,
},
})),
});
store._emitSelectionChange = false;
}

if (store._deletedFeaturesToEmit.length) {
const geojsonToEmit = store._deletedFeaturesToEmit.map(feature => feature.toGeoJSON());
const geojsonToEmit = store._deletedFeaturesToEmit.map((feature) =>
feature.toGeoJSON()
);

store._deletedFeaturesToEmit = [];

store.ctx.map.fire(Constants.events.DELETE, {
features: geojsonToEmit
features: geojsonToEmit,
});
}

Expand Down
3 changes: 3 additions & 0 deletions src/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Store = require('./store');
const ui = require('./ui');
const Constants = require('./constants');
const xtend = require('xtend');
const Snapping = require('./snapping');

module.exports = function(ctx) {

Expand All @@ -23,6 +24,7 @@ module.exports = function(ctx) {
ctx.map = null;
ctx.container = null;
ctx.store = null;
ctx.snapping.disableSnapping();

if (controlContainer && controlContainer.parentNode) controlContainer.parentNode.removeChild(controlContainer);
controlContainer = null;
Expand All @@ -33,6 +35,7 @@ module.exports = function(ctx) {
ctx.map.off('load', setup.connect);
clearInterval(mapLoadedInterval);
setup.addLayers();
(new Snapping(ctx)).enableSnapping();
ctx.store.storeMapConfig();
ctx.events.addEventListeners();
},
Expand Down
Loading