@mapbox/mapbox-gl-draw
Version:
A drawing component for Mapbox GL JS
153 lines (135 loc) • 5.59 kB
JavaScript
import * as CommonSelectors from '../lib/common_selectors.js';
import isEventAtCoordinates from '../lib/is_event_at_coordinates.js';
import doubleClickZoom from '../lib/double_click_zoom.js';
import * as Constants from '../constants.js';
import createVertex from '../lib/create_vertex.js';
const DrawLineString = {};
DrawLineString.onSetup = function(opts) {
opts = opts || {};
const featureId = opts.featureId;
let line, currentVertexPosition;
let direction = 'forward';
if (featureId) {
line = this.getFeature(featureId);
if (!line) {
throw new Error('Could not find a feature with the provided featureId');
}
let from = opts.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: Constants.geojsonTypes.FEATURE,
properties: {},
geometry: {
type: Constants.geojsonTypes.LINE_STRING,
coordinates: []
}
});
currentVertexPosition = 0;
this.addFeature(line);
}
this.clearSelectedFeatures();
doubleClickZoom.disable(this);
this.updateUIClasses({ mouse: Constants.cursors.ADD });
this.activateUIButton(Constants.types.LINE);
this.setActionableState({
trash: true
});
return {
line,
currentVertexPosition,
direction
};
};
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])) {
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);
if (state.direction === 'forward') {
state.currentVertexPosition++;
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
} else {
state.line.addCoordinate(0, e.lngLat.lng, e.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);
if (CommonSelectors.isVertex(e)) {
this.updateUIClasses({ mouse: Constants.cursors.POINTER });
}
};
DrawLineString.onTap = DrawLineString.onClick = function(state, e) {
if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e);
this.clickAnywhere(state, e);
};
DrawLineString.onKeyUp = function(state, e) {
if (CommonSelectors.isEnterKey(e)) {
this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] });
} else if (CommonSelectors.isEscapeKey(e)) {
this.deleteFeature([state.line.id], { silent: true });
this.changeMode(Constants.modes.SIMPLE_SELECT);
}
};
DrawLineString.onStop = function(state) {
doubleClickZoom.enable(this);
this.activateUIButton();
// check to see if we've deleted this feature
if (this.getFeature(state.line.id) === undefined) return;
//remove last added coordinate
state.line.removeCoordinate(`${state.currentVertexPosition}`);
if (state.line.isValid()) {
this.fire(Constants.events.CREATE, {
features: [state.line.toGeoJSON()]
});
} else {
this.deleteFeature([state.line.id], { silent: true });
this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true });
}
};
DrawLineString.onTrash = function(state) {
this.deleteFeature([state.line.id], { silent: true });
this.changeMode(Constants.modes.SIMPLE_SELECT);
};
DrawLineString.toDisplayFeatures = function(state, geojson, display) {
const isActiveLine = geojson.properties.id === state.line.id;
geojson.properties.active = (isActiveLine) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE;
if (!isActiveLine) return display(geojson);
// Only render the line if it has at least one real coordinate
if (geojson.geometry.coordinates.length < 2) return;
geojson.properties.meta = Constants.meta.FEATURE;
display(createVertex(
state.line.id,
geojson.geometry.coordinates[state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1],
`${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`,
false
));
display(geojson);
};
export default DrawLineString;