Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
208 lines (177 sloc)
6.11 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import turfDistance from '@turf/distance'; | |
import turfMidpoint from '@turf/midpoint'; | |
import { FeatureCollection } from '../geojson-types'; | |
import { ClickEvent, PointerMoveEvent, ModeProps, GuideFeatureCollection, Tooltip } from '../types'; | |
import { getPickedEditHandle } from '../utils'; | |
import { GeoJsonEditMode } from './geojson-edit-mode'; | |
export class MeasureDistanceMode extends GeoJsonEditMode { | |
_isMeasuringSessionFinished = false; | |
_currentTooltips = []; | |
_currentDistance = 0; | |
_calculateDistanceForTooltip = ({ positionA, positionB, modeConfig }) => { | |
const { turfOptions, measurementCallback } = modeConfig || {}; | |
const distance = turfDistance(positionA, positionB, turfOptions); | |
if (measurementCallback) { | |
measurementCallback(distance); | |
} | |
return distance; | |
}; | |
_formatTooltip(distance, modeConfig?) { | |
const { formatTooltip, turfOptions } = modeConfig || {}; | |
const units = (turfOptions && turfOptions.units) || 'kilometers'; | |
let text; | |
if (formatTooltip) { | |
text = formatTooltip(distance); | |
} else { | |
// By default, round to 2 decimal places and append units | |
text = `${parseFloat(distance).toFixed(2)} ${units}`; | |
} | |
return text; | |
} | |
handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>) { | |
const { modeConfig, data, onEdit } = props; | |
const { centerTooltipsOnLine = false } = modeConfig || {}; | |
// restart measuring session | |
if (this._isMeasuringSessionFinished) { | |
this._isMeasuringSessionFinished = false; | |
this.resetClickSequence(); | |
this._currentTooltips = []; | |
this._currentDistance = 0; | |
} | |
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 > 1 && | |
clickedEditHandle && | |
Array.isArray(clickedEditHandle.properties.positionIndexes) && | |
clickedEditHandle.properties.positionIndexes[0] === clickSequence.length - 1 | |
) { | |
// They clicked the last point (or double-clicked), so add the LineString | |
this._isMeasuringSessionFinished = true; | |
} else if (positionAdded) { | |
if (clickSequence.length > 1) { | |
this._currentDistance += this._calculateDistanceForTooltip({ | |
positionA: clickSequence[clickSequence.length - 2], | |
positionB: clickSequence[clickSequence.length - 1], | |
modeConfig, | |
}); | |
const tooltipPosition = centerTooltipsOnLine | |
? turfMidpoint( | |
clickSequence[clickSequence.length - 2], | |
clickSequence[clickSequence.length - 1] | |
).geometry.coordinates | |
: event.mapCoords; | |
this._currentTooltips.push({ | |
position: tooltipPosition, | |
text: this._formatTooltip(this._currentDistance, modeConfig), | |
}); | |
} | |
// new tentative point | |
onEdit({ | |
// data is the same | |
updatedData: data, | |
editType: 'addTentativePosition', | |
editContext: { | |
position: event.mapCoords, | |
}, | |
}); | |
} | |
} | |
handleKeyUp(event: KeyboardEvent, props: ModeProps<FeatureCollection>) { | |
if (this._isMeasuringSessionFinished) return; | |
event.stopPropagation(); | |
const { key } = event; | |
const clickSequenceLength = this.getClickSequence().length; | |
switch (key) { | |
case 'Escape': | |
this._isMeasuringSessionFinished = true; | |
if (clickSequenceLength === 1) { | |
this.resetClickSequence(); | |
this._currentTooltips = []; | |
} | |
// force update drawings | |
props.onUpdateCursor('cell'); | |
break; | |
case 'Enter': | |
this.handleClick(props.lastPointerMoveEvent, props); | |
this._isMeasuringSessionFinished = true; | |
break; | |
default: | |
break; | |
} | |
} | |
getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection { | |
const { lastPointerMoveEvent } = props; | |
const clickSequence = this.getClickSequence(); | |
const lastCoords = | |
lastPointerMoveEvent && !this._isMeasuringSessionFinished | |
? [lastPointerMoveEvent.mapCoords] | |
: []; | |
const guides = { | |
type: 'FeatureCollection', | |
features: [], | |
}; | |
if (clickSequence.length > 0) { | |
guides.features.push({ | |
type: 'Feature', | |
properties: { | |
guideType: 'tentative', | |
}, | |
geometry: { | |
type: 'LineString', | |
coordinates: [...clickSequence, ...lastCoords], | |
}, | |
}); | |
} | |
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; | |
} | |
handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>) { | |
props.onUpdateCursor('cell'); | |
} | |
getTooltips(props: ModeProps<FeatureCollection>): Tooltip[] { | |
const { lastPointerMoveEvent, modeConfig } = props; | |
const { centerTooltipsOnLine = false } = modeConfig || {}; | |
const positions = this.getClickSequence(); | |
if (positions.length > 0 && lastPointerMoveEvent && !this._isMeasuringSessionFinished) { | |
const distance = this._calculateDistanceForTooltip({ | |
positionA: positions[positions.length - 1], | |
positionB: lastPointerMoveEvent.mapCoords, | |
modeConfig: props.modeConfig, | |
}); | |
const tooltipPosition = centerTooltipsOnLine | |
? turfMidpoint(positions[positions.length - 1], lastPointerMoveEvent.mapCoords).geometry | |
.coordinates | |
: lastPointerMoveEvent.mapCoords; | |
return [ | |
...this._currentTooltips, | |
{ | |
position: tooltipPosition, | |
text: this._formatTooltip(this._currentDistance + distance, modeConfig), | |
}, | |
]; | |
} | |
return this._currentTooltips; | |
} | |
} |