Skip to content

Commit

Permalink
fix(editor): improve pattern shape editing
Browse files Browse the repository at this point in the history
refactor some other things to make them easier to read
  • Loading branch information
evansiroky committed Aug 7, 2017
1 parent 67c7254 commit 4efe951
Show file tree
Hide file tree
Showing 26 changed files with 1,639 additions and 1,699 deletions.
2 changes: 2 additions & 0 deletions lib/common/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export function retrievalMethodString (method) {
}

export function generateUID () {
// TODO: replace with better UID generator if possible
// this has a 1 in 1.7 million chance of a collision
return ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
}

Expand Down
237 changes: 142 additions & 95 deletions lib/editor/actions/map/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import ll from '@conveyal/lonlat'
import uniqueId from 'lodash.uniqueid'
import shp from 'shpjs'
import lineDistance from 'turf-line-distance'
import lineSlice from 'turf-line-slice'
import point from 'turf-point'
import lineDistance from 'turf-line-distance'
import ll from '@conveyal/lonlat'

import {updateActiveGtfsEntity, saveActiveGtfsEntity} from '../active'
import {getControlPointSnap, recalculatePatternCoordinates, newControlPoint} from '../../util/map'
import {setErrorMessage} from '../../../manager/actions/status'
import {polyline as getPolyline} from '../../../scenario-editor/utils/valhalla'

export function updateMapSetting (props) {
return {
type: 'UPDATE_MAP_SETTING',
props
}
}
import {recalculateShape, newControlPoint} from '../../util/map'

export function addControlPoint (controlPoint, index) {
return {
Expand All @@ -23,48 +18,6 @@ export function addControlPoint (controlPoint, index) {
}
}

export function handleControlPointDragEnd (index, controlPoint, evt, pattern) {
return function (dispatch, getState) {
const coordinates = getState().editor.editSettings.patternCoordinates
const controlPointGeoJson = evt.target.toGeoJSON()
const { snap, distTraveled } = getControlPointSnap(controlPointGeoJson, coordinates)
dispatch(updateActiveGtfsEntity(pattern, 'trippattern', {shape: {type: 'LineString', coordinates}}))
dispatch(updateControlPoint(index, snap, distTraveled))
}
}

export function handleControlPointDrag (controlPoints, index, latlng, patternShape) {
return function (dispatch, getState) {
const {followStreets} = getState().editor.editSettings
recalculatePatternCoordinates(
controlPoints,
'update',
index,
followStreets,
latlng,
patternShape,
false
)
.then(coords => {
if (coords) {
dispatch(updatePatternCoordinates(coords))
// const coord = ll.toCoordinates(latlng)
// const cpPoint = point(coord)
// const { snap, distTraveled } = getControlPointSnap(cpPoint, coords)
// dispatch(updateControlPoint(index, snap, distTraveled, false))
}
})
}
}

export function removingControlPoint (pattern, index) {
return {
type: 'REMOVE_CONTROL_POINT',
pattern,
index
}
}

export function constructControlPoint (pattern, latlng, controlPoints) {
return function (dispatch, getState) {
// slice line
Expand All @@ -91,50 +44,10 @@ export function constructControlPoint (pattern, latlng, controlPoints) {
}
}

export function updatePatternCoordinates (coordinates) {
return {
type: 'UPDATE_PATTERN_COORDINATES',
coordinates
}
}

export function removeControlPoint (controlPoints, index, pattern) {
return async function (dispatch, getState) {
const {followStreets} = getState().editor.editSettings
const coordinates = await recalculatePatternCoordinates(
controlPoints,
'delete',
index,
followStreets,
null,
pattern.shape
)
// update pattern
dispatch(
updateActiveGtfsEntity(pattern, 'trippattern', {
shape: {type: 'LineString', coordinates}
})
)
// remove controlPoint
dispatch(removingControlPoint(pattern, index))
}
}

export function updateControlPoint (index, point, distance, hardUpdate = true) {
return {
type: 'UPDATE_CONTROL_POINT',
index,
point,
distance,
hardUpdate
}
}

function receivedRoutesShapefile (feedSource, geojson) {
function controlPointDragOrEnd (dragId) {
return {
type: 'RECEIVED_ROUTES_SHAPEFILE',
feedSource,
geojson
type: 'CONTROL_POINT_DRAG_START_OR_END',
dragId
}
}

Expand Down Expand Up @@ -171,3 +84,137 @@ export function extendPatternToPoint (pattern, endPoint, newEndPoint) {
return shape
}
}

/**
* Calculate a new shape according to newly dragged position of control point
*
* @param {ControlPoint[]} controlPoints
* @param {Number} index Index of the control point being dragged
* @param {Position} latlng Position of drag point
* @param {Object} patternShape
*/
export function handleControlPointDrag (
controlPoints,
index,
latlng,
patternShape
) {
return function (dispatch, getState) {
const {currentDragId, followStreets} = getState().editor.editSettings
recalculateShape({
controlPoints,
defaultToStraightLine: false,
dragId: currentDragId,
editType: 'update',
followStreets,
index,
newPoint: latlng,
patternShape
}).then(result => {
// make sure dragging hasn't already stopped and that coordinates are returned
if (
result.dragId === getState().editor.editSettings.currentDragId &&
result.coordinates
) {
dispatch(updatePatternCoordinates(result.coordinates))
}
})
}
}

export function handleControlPointDragEnd (controlPoints, index, latlng, pattern) {
return function (dispatch, getState) {
// proclaim end of dragging
dispatch(controlPointDragOrEnd())

// recalculate shape for final position
const {followStreets} = getState().editor.editSettings
recalculateShape({
controlPoints,
defaultToStraightLine: false,
editType: 'update',
index,
followStreets,
newPoint: latlng,
patternShape: pattern.shape,
snapControlPointToNewSegment: true
}).then(result => {
if (!result.coordinates) {
dispatch(setErrorMessage(
'An error occurred while trying to recalculate the shape. Please try again.'
))
} else {
dispatch(
updateActiveGtfsEntity(pattern, 'trippattern', {
shape: {type: 'LineString', coordinates: result.coordinates}
})
)
dispatch(updateControlPoints(result.updatedControlPoints))
}
})
}
}

/**
* Save data to store that dragging is in progress
*
* @param {ControlPoint} controlPoint
* @return {Action}
*/
export function handleControlPointDragStart (controlPoint) {
return controlPointDragOrEnd(uniqueId(controlPoint.id))
}

function receivedRoutesShapefile (feedSource, geojson) {
return {
type: 'RECEIVED_ROUTES_SHAPEFILE',
feedSource,
geojson
}
}

export function removeControlPoint (controlPoints, index, pattern) {
return async function (dispatch, getState) {
const {followStreets} = getState().editor.editSettings
const {
coordinates,
updatedControlPoints
} = await recalculateShape({
controlPoints,
editType: 'delete',
index,
followStreets,
patternShape: pattern.shape
})
// TODO-CONTROL-POINT-FIX: update distance of other control points
// update pattern
dispatch(
updateActiveGtfsEntity(pattern, 'trippattern', {
shape: {type: 'LineString', coordinates}
})
)
// update controlPoints
dispatch(updateControlPoints(updatedControlPoints))
}
}

export function updateControlPoints (newControlPoints) {
return {
type: 'UPDATE_CONTROL_POINTS',
newControlPoints
}
}

export function updateMapSetting (props) {
return {
type: 'UPDATE_MAP_SETTING',
props
}
}

export function updatePatternCoordinates (coordinates) {
return {
type: 'UPDATE_PATTERN_COORDINATES',
coordinates
}
}
37 changes: 18 additions & 19 deletions lib/editor/actions/map/stopStrategies.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {getSegment} from '../../../scenario-editor/utils/valhalla'
import {
constructStop,
stopToStopTime,
recalculatePatternCoordinates,
recalculateShape,
getPatternEndPoint,
street,
constructPoint
Expand Down Expand Up @@ -56,6 +56,8 @@ export function addStopAtIntersection (latlng, activePattern) {
const last = json.data.features[json.data.features.length - 1]
const start = constructPoint(endPoint)
const end = constructPoint(last.geometry.coordinates[last.geometry.coordinates.length - 1])
// TODO-lineSlice: refactor below code to not use lineSlice
// the current code may have undesired results in cases where the shape overlaps itself
const trimmed = lineSlice(start, end, {type: 'Feature', geometry: {type: 'LineString', coordinates: extension}})
const { afterIntersection, intersectionStep, distanceFromIntersection } = getState().editor.editSettings
const shape = {type: 'LineString', coordinates: [...activePattern.shape.coordinates, ...trimmed.geometry.coordinates]}
Expand Down Expand Up @@ -83,6 +85,8 @@ export function addStopAtIntersection (latlng, activePattern) {
const end = afterIntersection
? constructPoint(shape.coordinates[shape.coordinates.length - 1])
: constructPoint(feature.geometry.coordinates[feature.geometry.coordinates.length - 1])
// TODO-lineSlice: refactor below code to use only relevant section of shape with lineSlice
// the current code may have undesired results in cases where the shape overlaps itself
const lineFromPoint = lineSlice(start, end, {type: 'Feature', geometry: shape})
const stopLocation = along(lineFromPoint, distanceFromIntersection / 1000, 'kilometers')
const latlng = ll.toLeaflet(stopLocation.geometry.coordinates)
Expand Down Expand Up @@ -199,20 +203,8 @@ export function addStopToPattern (pattern, stop, index) {
}
}

function removingStopFromPattern (pattern, stop, index, controlPoints) {
return {
type: 'REMOVING_STOP_FROM_PATTERN',
pattern,
stop,
index,
controlPoints
}
}

export function removeStopFromPattern (pattern, stop, index, controlPoints) {
return async function (dispatch, getState) {
dispatch(removingStopFromPattern(pattern, stop, index, controlPoints))

if (!controlPoints) {
const controlPointsFromState = getState().editor.editSettings
.controlPoints
Expand Down Expand Up @@ -243,26 +235,33 @@ export function removeStopFromPattern (pattern, stop, index, controlPoints) {

let coordinates
try {
coordinates = await recalculatePatternCoordinates(
const result = await recalculateShape({
controlPoints,
'delete',
cpIndex,
editType: 'delete',
index: cpIndex,
followStreets,
null,
pattern.shape
)
patternShape: pattern.shape
})
coordinates = result.coordinates
} catch (err) {
console.log(err)
dispatch(setErrorMessage(`Could not remove pattern from stop: ${err}`))
return
}
if (!coordinates) {
dispatch(setErrorMessage(
'An error occurred while trying to recalculate the shape. Please try again.'
))
return
}
shape = {type: 'LineString', coordinates}
}
const patternStops = [...pattern.patternStops]
patternStops.splice(index, 1)
dispatch(
updateActiveGtfsEntity(pattern, 'trippattern', {patternStops, shape})
)
// saving the trip pattern will recalculate the control points
dispatch(saveActiveGtfsEntity('trippattern'))
}
}
Expand Down
22 changes: 16 additions & 6 deletions lib/editor/actions/tripPattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,22 @@ export function undoingActiveTripPatternEdits (lastActionIndex, lastActionType,

export function undoActiveTripPatternEdits () {
return function (dispatch, getState) {
const lastActionIndex = getState().editor.editSettings.actions.length - 1
const lastActionType = getState().editor.editSettings.actions[lastActionIndex]
const lastCoordinatesIndex = getState().editor.editSettings.coordinatesHistory.length - 1
const lastControlPointsIndex = getState().editor.editSettings.controlPoints.length - 1
const lastCoordinates = getState().editor.editSettings.coordinatesHistory[lastCoordinatesIndex]
dispatch(undoingActiveTripPatternEdits(lastActionIndex, lastActionType, lastCoordinatesIndex, lastControlPointsIndex, lastCoordinates))
const editSettings = getState().editor.editSettings
const lastActionIndex = editSettings.actions.length - 1
const lastActionType = editSettings.actions[lastActionIndex]
const lastCoordinatesIndex = editSettings.coordinatesHistory.length - 1
const lastControlPointsIndex = editSettings.controlPoints.length - 1
const lastCoordinates =
editSettings.coordinatesHistory[lastCoordinatesIndex]
dispatch(
undoingActiveTripPatternEdits(
lastActionIndex,
lastActionType,
lastCoordinatesIndex,
lastControlPointsIndex,
lastCoordinates
)
)
}
}

Expand Down
Loading

0 comments on commit 4efe951

Please sign in to comment.