diff --git a/lib/editor/components/pattern/EditShapePanel.js b/lib/editor/components/pattern/EditShapePanel.js index 91bea36c0..7a85a9fd7 100644 --- a/lib/editor/components/pattern/EditShapePanel.js +++ b/lib/editor/components/pattern/EditShapePanel.js @@ -1,8 +1,8 @@ // @flow import Icon from '@conveyal/woonerf/components/icon' -import React, {Component} from 'react' -import {Alert, Button, ButtonGroup, ButtonToolbar, OverlayTrigger, Tooltip} from 'react-bootstrap' +import React, { Component } from 'react' +import { Alert, Button, ButtonGroup, ButtonToolbar, OverlayTrigger, Tooltip } from 'react-bootstrap' import ll from '@conveyal/lonlat' import numeral from 'numeral' import lineDistance from 'turf-line-distance' @@ -10,19 +10,19 @@ import lineString from 'turf-linestring' import * as activeActions from '../../actions/active' import * as mapActions from '../../actions/map' -import {ARROW_MAGENTA, PATTERN_TO_STOP_DISTANCE_THRESHOLD_METERS} from '../../constants' +import { ARROW_MAGENTA, PATTERN_TO_STOP_DISTANCE_THRESHOLD_METERS } from '../../constants' import * as tripPatternActions from '../../actions/tripPattern' import OptionButton from '../../../common/components/OptionButton' import * as statusActions from '../../../manager/actions/status' -import {polyline as getPolyline} from '../../../scenario-editor/utils/valhalla' +import { polyline as getPolyline } from '../../../scenario-editor/utils/valhalla' import { controlPointsFromSegments, generateControlPointsFromPatternStops, getPatternDistance, isValidStopControlPoint } from '../../util/map' -import type {ControlPoint, GtfsRoute, LatLng, Pattern, GtfsStop} from '../../../types' -import type {EditSettingsUndoState} from '../../../types/reducers' +import type { ControlPoint, GtfsRoute, LatLng, Pattern, GtfsStop } from '../../../types' +import type { EditSettingsUndoState } from '../../../types/reducers' import EditSettings from './EditSettings' @@ -50,19 +50,22 @@ export default class EditShapePanel extends Component { * Construct new pattern geometry from the pattern stop locations. */ async drawPatternFromStops (pattern: Pattern, stopsCoordinates: Array, followStreets: boolean): Promise { - const {editSettings, saveActiveGtfsEntity, setErrorMessage, updatePatternGeometry} = this.props + const { editSettings, saveActiveGtfsEntity, setErrorMessage, updatePatternGeometry } = this.props + const { avoidMotorways, followRail } = editSettings.present let patternSegments = [] - if (followStreets) { - patternSegments = await getPolyline(stopsCoordinates, true, editSettings.present.avoidMotorways) - } else { - // Construct straight-line segments using stop coordinates - stopsCoordinates - .forEach((stop, i) => { - if (i < stopsCoordinates.length - 1) { - const segment = [ll.toCoordinates(stop), ll.toCoordinates(stopsCoordinates[i + 1])] - patternSegments.push(segment) - } - }) + if (followStreets || followRail) { + patternSegments = await getPolyline(stopsCoordinates, true, avoidMotorways, followRail) + } + + // Fallback to straight-line segments if routing failed or was not requested + if (!patternSegments || patternSegments.length === 0) { + patternSegments = [] + stopsCoordinates.forEach((stop, i) => { + if (i < stopsCoordinates.length - 1) { + const segment = [ll.toCoordinates(stop), ll.toCoordinates(stopsCoordinates[i + 1])] + patternSegments.push(segment) + } + }) } if (patternSegments && patternSegments.length > 0) { const controlPoints = controlPointsFromSegments(pattern.patternStops, patternSegments) @@ -73,13 +76,13 @@ export default class EditShapePanel extends Component { saveActiveGtfsEntity('trippattern') return true } else { - setErrorMessage({message: 'Error drawing pattern from stops! Some stops may be unreachable by streets.'}) + setErrorMessage({ message: 'Error drawing pattern from stops! Some stops may be unreachable by streets.' }) return false } } _cancelEdits = () => { - const {activePattern, resetActiveGtfsEntity, togglePatternEditing} = this.props + const { activePattern, resetActiveGtfsEntity, togglePatternEditing } = this.props if (this._hasEdits()) { if (!window.confirm('You have unsaved shape edits. Are you sure you want to cancel and revert these changes?')) { return @@ -93,16 +96,16 @@ export default class EditShapePanel extends Component { } _generateShapeFromStops = () => { - const {activePattern, editSettings, stops} = this.props + const { activePattern, editSettings, stops } = this.props const stopLocations = stops && activePattern.patternStops && activePattern.patternStops.length ? activePattern.patternStops .map((s, index) => { const stop = stops.find(st => st.stop_id === s.stopId) if (!stop) { console.warn(`Could not locate stop with stop_id=${s.stopId}`) - return {lng: 0, lat: 0} + return { lng: 0, lat: 0 } } - return {lng: stop.stop_lon, lat: stop.stop_lat} + return { lng: stop.stop_lon, lat: stop.stop_lat } }) : [] this.drawPatternFromStops(activePattern, stopLocations, editSettings.present.followStreets) @@ -114,7 +117,7 @@ export default class EditShapePanel extends Component { const body = this._hasShapePoints() ? 'Are you sure you want to overwrite the existing shape for this trip pattern?' : 'Are you sure you want to create an auto-generated shape for this trip pattern?' - this.props.showConfirmModal({title, body, onConfirm}) + this.props.showConfirmModal({ title, body, onConfirm }) } _deleteShape = () => { @@ -136,7 +139,7 @@ export default class EditShapePanel extends Component { updateActiveGtfsEntity({ component: 'trippattern', entity: activePattern, - props: {shapePoints: [], shapeId: null} + props: { shapePoints: [], shapeId: null } }) saveActiveGtfsEntity('trippattern') } @@ -149,20 +152,20 @@ export default class EditShapePanel extends Component { * user on resolving the issue. */ _getPatternStopsWithShapeIssues = () => { - const {controlPoints, stops} = this.props + const { controlPoints, stops } = this.props return controlPoints // $FlowFixMe: can't tell flow all elements are defined in the map. .filter(isValidStopControlPoint) .map((controlPoint, index) => { - const {point, stopId} = controlPoint + const { point, stopId } = controlPoint let exceedsThreshold = false - const {coordinates: cpCoord} = point.geometry + const { coordinates: cpCoord } = point.geometry // Find stop entity for control point. const stop = stops.find(s => s.stop_id === stopId) if (!stop) { // If no stop entity found, do not attempt to draw a line to the // missing stop. - return {controlPoint, index, stop: null, distance: 0, exceedsThreshold} + return { controlPoint, index, stop: null, distance: 0, exceedsThreshold } } const coordinates = [[cpCoord[1], cpCoord[0]], [stop.stop_lat, stop.stop_lon]] const distance: number = lineDistance(lineString(coordinates), 'meters') @@ -181,7 +184,7 @@ export default class EditShapePanel extends Component { } _beginEditing = () => { - const {togglePatternEditing} = this.props + const { togglePatternEditing } = this.props togglePatternEditing() } @@ -189,7 +192,7 @@ export default class EditShapePanel extends Component { this.props.activePattern.shapePoints.length > 0 save = () => { - const {editSettings, saveActiveGtfsEntity, updateEditSetting} = this.props + const { editSettings, saveActiveGtfsEntity, updateEditSetting } = this.props saveActiveGtfsEntity('trippattern') // $FlowFixMe action is actually wrapped in promise when connected .then(() => updateEditSetting({ @@ -211,7 +214,7 @@ export default class EditShapePanel extends Component { updateEditSetting, undoActiveTripPatternEdits } = this.props - const {present: editSettings} = editSettingsState + const { present: editSettings } = editSettingsState const hasEdits = this._hasEdits() const fromStopsButton = { @@ -238,21 +241,21 @@ export default class EditShapePanel extends Component { {' '} ({formattedShapeDistance} miles) -
+
{!activePattern.shapeId ? {' '} No shape associated with this pattern. : - + shape_id:{' '} {activePattern.shapeId}
{patternStopsWithShapeIssues.length > 0 - ? + ?

Pattern stop snapping issue

-
    +
      {patternStopsWithShapeIssues .map(item => { - const {distance, index, stop} = item + const { distance, index, stop } = item if (!stop) return null const roundedDist = Math.round(distance * 100) / 100 return (
    • #{index + 1} {stop.stop_name}{' '} - + {roundedDist} m
    • @@ -313,24 +316,24 @@ export default class EditShapePanel extends Component { {fromStopsButton} - + - Prev + Prev = controlPoints.length - 1} value={nextSegment} bsSize='xsmall'> @@ -345,7 +348,7 @@ export default class EditShapePanel extends Component { value={nextSegment} disabled={patternSegment >= controlPoints.length - 1} bsSize='xsmall'> - Next + Next @@ -372,7 +375,7 @@ export default class EditShapePanel extends Component {