UNPKG

mapbox-gl-draw-snap-mode

Version:
199 lines (164 loc) 5.8 kB
import MapboxDraw from "@mapbox/mapbox-gl-draw"; import { addPointToVertices, createSnapList, getGuideFeature, IDS, shouldHideGuide, snap, } from "./../utils/index.js"; const { doubleClickZoom } = MapboxDraw.lib; const { geojsonTypes, modes, cursors } = MapboxDraw.constants; const DrawLine = MapboxDraw.modes.draw_line_string; const SnapLineMode = { ...DrawLine }; SnapLineMode.onSetup = function (options) { options = options || {}; const featureId = options.featureId; var currentVertexPosition = 0; var direction = 'forwards' let line; if (featureId) { line = this.getFeature(featureId); if (!line) { throw new Error('Could not find a feature with the provided featureId'); } let from = options.from; if (from && from.type === 'Feature' && from.geometry && from.geometry.type === 'Point') { from = from.geometry; } if (from && from.type === 'Point' && from.coordinates && from.coordinates.length === 2) { from = from.coordinates; } if (!from || !Array.isArray(from)) { throw new Error('Please use the `from` property to indicate which point to continue the line from'); } const lastCoord = line.coordinates.length - 1; if (line.coordinates[lastCoord][0] === from[0] && line.coordinates[lastCoord][1] === from[1]) { currentVertexPosition = lastCoord + 1; // add one new coordinate to continue from line.addCoordinate(currentVertexPosition, ...line.coordinates[lastCoord]); } else if (line.coordinates[0][0] === from[0] && line.coordinates[0][1] === from[1]) { direction = 'backwards'; currentVertexPosition = 0; // add one new coordinate to continue from line.addCoordinate(currentVertexPosition, ...line.coordinates[0]); } else { throw new Error('`from` should match the point at either the start or the end of the provided LineString'); } } else { line = this.newFeature({ type: MapboxDraw.constants.geojsonTypes.FEATURE, properties: {}, geometry: { type: MapboxDraw.constants.geojsonTypes.LINE_STRING, coordinates: [] } }); } const verticalGuide = this.newFeature(getGuideFeature(IDS.VERTICAL_GUIDE)); const horizontalGuide = this.newFeature( getGuideFeature(IDS.HORIZONTAL_GUIDE) ); this.addFeature(line); this.addFeature(verticalGuide); this.addFeature(horizontalGuide); const selectedFeatures = this.getSelected(); this.clearSelectedFeatures(); doubleClickZoom.disable(this); const [snapList, vertices] = createSnapList( this.map, this._ctx.api, line, this._ctx.options.snapOptions?.snapGetFeatures ); const state = { map: this.map, line, currentVertexPosition: currentVertexPosition, vertices, snapList, selectedFeatures, verticalGuide, horizontalGuide, direction: direction }; state.options = this._ctx.options; const moveendCallback = () => { const [snapList, vertices] = createSnapList( this.map, this._ctx.api, line, this._ctx.options.snapOptions?.snapGetFeatures ); state.vertices = vertices; state.snapList = snapList; }; // for removing listener later on close state["moveendCallback"] = moveendCallback; const optionsChangedCallback = (options) => { state.options = options; }; // for removing listener later on close state["optionsChangedCallback"] = optionsChangedCallback; this.map.on("moveend", moveendCallback); this.map.on("draw.snap.options_changed", optionsChangedCallback); return state; }; SnapLineMode.onClick = function (state) { // We save some processing by rounding on click, not mousemove const lng = state.snappedLng; const lat = state.snappedLat; // End the drawing if this click is on the previous position // Note: not bothering with 'direction' if (state.currentVertexPosition > 0) { const lastVertex = state.line.coordinates[state.currentVertexPosition - 1]; state.lastVertex = lastVertex; if (lastVertex[0] === lng && lastVertex[1] === lat) { return this.changeMode(modes.SIMPLE_SELECT, { featureIds: [state.line.id], }); } } // const point = state.map.project({ lng: lng, lat: lat }); addPointToVertices(state.map, state.vertices, { lng, lat }); state.line.updateCoordinate(state.currentVertexPosition, lng, lat); state.currentVertexPosition++; state.line.updateCoordinate(state.currentVertexPosition, lng, lat); }; SnapLineMode.onMouseMove = function (state, e) { const { lng, lat } = snap(state, e); state.line.updateCoordinate(state.currentVertexPosition, lng, lat); state.snappedLng = lng; state.snappedLat = lat; if ( state.lastVertex && state.lastVertex[0] === lng && state.lastVertex[1] === lat ) { this.updateUIClasses({ mouse: cursors.POINTER }); // cursor options: // ADD: "add" // DRAG: "drag" // MOVE: "move" // NONE: "none" // POINTER: "pointer" } else { this.updateUIClasses({ mouse: cursors.ADD }); } }; // This is 'extending' DrawLine.toDisplayFeatures SnapLineMode.toDisplayFeatures = function (state, geojson, display) { if (shouldHideGuide(state, geojson)) return; // This relies on the the state of SnapLineMode being similar to DrawLine DrawLine.toDisplayFeatures(state, geojson, display); }; // This is 'extending' DrawLine.onStop SnapLineMode.onStop = function (state) { this.deleteFeature(IDS.VERTICAL_GUIDE, { silent: true }); this.deleteFeature(IDS.HORIZONTAL_GUIDE, { silent: true }); // remove moveend callback this.map.off("moveend", state.moveendCallback); // This relies on the the state of SnapLineMode being similar to DrawLine DrawLine.onStop.call(this, state); }; export default SnapLineMode;