import { ClickEvent, PointerMoveEvent, ModeProps, GuideFeatureCollection, TentativeFeature, } from '../types'; import { Polygon, FeatureCollection } from '../geojson-types'; import { getPickedEditHandle } from '../utils'; import { GeoJsonEditMode } from './geojson-edit-mode'; export class DrawPolygonMode extends GeoJsonEditMode { createTentativeFeature(props: ModeProps): TentativeFeature { const { lastPointerMoveEvent } = props; const clickSequence = this.getClickSequence(); const lastCoords = lastPointerMoveEvent ? [lastPointerMoveEvent.mapCoords] : []; let tentativeFeature; if (clickSequence.length === 1 || clickSequence.length === 2) { tentativeFeature = { type: 'Feature', properties: { guideType: 'tentative', }, geometry: { type: 'LineString', coordinates: [...clickSequence, ...lastCoords], }, }; } else if (clickSequence.length > 2) { tentativeFeature = { type: 'Feature', properties: { guideType: 'tentative', }, geometry: { type: 'Polygon', coordinates: [[...clickSequence, ...lastCoords, clickSequence[0]]], }, }; } return tentativeFeature; } getGuides(props: ModeProps): GuideFeatureCollection { const clickSequence = this.getClickSequence(); const guides = { type: 'FeatureCollection', features: [], }; const tentativeFeature = this.createTentativeFeature(props); if (tentativeFeature) { guides.features.push(tentativeFeature); } const editHandles = clickSequence.map((clickedCoord, index) => ({ type: 'Feature', properties: { guideType: 'editHandle', editHandleType: 'existing', featureIndex: -1, positionIndexes: [index], }, geometry: { type: 'Point', coordinates: clickedCoord, }, })); guides.features.push(...editHandles); // @ts-ignore return guides; } handleClick(event: ClickEvent, props: ModeProps) { const { picks } = event; const clickedEditHandle = getPickedEditHandle(picks); let positionAdded = false; if (!clickedEditHandle) { // Don't add another point right next to an existing one this.addClickSequence(event); positionAdded = true; } const clickSequence = this.getClickSequence(); if ( clickSequence.length > 2 && clickedEditHandle && Array.isArray(clickedEditHandle.properties.positionIndexes) && (clickedEditHandle.properties.positionIndexes[0] === 0 || clickedEditHandle.properties.positionIndexes[0] === clickSequence.length - 1) ) { // They clicked the first or last point (or double-clicked), so complete the polygon // Remove the hovered position const polygonToAdd: Polygon = { type: 'Polygon', coordinates: [[...clickSequence, clickSequence[0]]], }; this.resetClickSequence(); const editAction = this.getAddFeatureOrBooleanPolygonAction(polygonToAdd, props); if (editAction) { props.onEdit(editAction); } } else if (positionAdded) { // new tentative point props.onEdit({ // data is the same updatedData: props.data, editType: 'addTentativePosition', editContext: { position: event.mapCoords, }, }); } } handleKeyUp(event: KeyboardEvent, props: ModeProps) { if (event.key === 'Enter') { const clickSequence = this.getClickSequence(); if (clickSequence.length > 2) { const polygonToAdd: Polygon = { type: 'Polygon', coordinates: [[...clickSequence, clickSequence[0]]], }; this.resetClickSequence(); const editAction = this.getAddFeatureOrBooleanPolygonAction(polygonToAdd, props); if (editAction) { props.onEdit(editAction); } } } } handlePointerMove(event: PointerMoveEvent, props: ModeProps) { props.onUpdateCursor('cell'); super.handlePointerMove(event, props); } }