Skip to content

Commit

Permalink
fix(ControlPoint): fix draggable behavior for leaflet 1.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
landonreed committed Mar 7, 2017
1 parent 6b2492f commit 4c07e81
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 91 deletions.
53 changes: 49 additions & 4 deletions lib/editor/actions/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import shp from 'shpjs'
import lineSlice from 'turf-line-slice'
import point from 'turf-point'
import lineDistance from 'turf-line-distance'
import ll from 'lonlng'
import ll from '@conveyal/lonlat'

import { updateActiveGtfsEntity, saveActiveGtfsEntity } from '../active'
import { handlePatternEdit } from '../../util/map'
import { handlePatternEdit, getControlPointSnap } from '../../util/map'
import {polyline as getPolyline} from '../../../scenario-editor/utils/valhalla'

export function updateMapSetting (props) {
Expand All @@ -23,6 +23,50 @@ export function addControlPoint (controlPoint, index) {
}
}

export function dragControlPointEnded (index, controlPoint, evt, pattern) {
return {
type: 'HANDLE_CONTROL_POINT_DRAG_END',
index,
controlPoint,
evt,
pattern
}
}

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

export function dragControlPoint (latlng, previous, next, pattern) {
return {
type: 'HANDLE_CONTROL_POINT_DRAG',
latlng,
previous,
next,
pattern
}
}

export function handleControlPointDrag (latlng, previous, next, pattern) {
return function (dispatch, getState) {
// dispatch(dragControlPoint(latlng, previous, next, pattern))
const { followStreets, patternCoordinates } = getState().editor.editSettings
const defaultToStraightLine = false
handlePatternEdit(latlng, previous, next, pattern, followStreets, patternCoordinates, defaultToStraightLine)
.then(coords => {
if (coords) {
dispatch(updatePatternCoordinates(coords))
}
})
}
}

export function removingControlPoint (pattern, index, begin, end) {
return {
type: 'REMOVE_CONTROL_POINT',
Expand All @@ -37,7 +81,8 @@ export function constructControlPoint (pattern, latlng, controlPoints) {
return function (dispatch, getState) {
// slice line
const beginPoint = point(pattern.shape.coordinates[0])
const clickPoint = point(ll.toCoordinates(latlng))
const coord = ll.toCoordinates(latlng)
const clickPoint = point(coord)
const lineSegment = lineSlice(beginPoint, clickPoint, pattern.shape)

// measure line segment
Expand Down Expand Up @@ -70,7 +115,7 @@ export function removeControlPoint (pattern, index, begin, end) {
const { followStreets, patternCoordinates } = getState().editor.editSettings
const coordinates = await handlePatternEdit(null, begin, end, pattern, followStreets, patternCoordinates)
// update pattern
dispatch(updateActiveGtfsEntity(pattern, 'trippattern', {shape: {type: 'LineString', coordinates: coordinates}}))
dispatch(updateActiveGtfsEntity(pattern, 'trippattern', {shape: {type: 'LineString', coordinates}}))
// remove controlPoint
dispatch(removingControlPoint(index))
}
Expand Down
8 changes: 4 additions & 4 deletions lib/editor/actions/map/stopStrategies.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import along from 'turf-along'
import ll from 'lonlng'
import ll from '@conveyal/lonlat'
import lineDistance from 'turf-line-distance'
import lineSlice from 'turf-line-slice'

Expand Down Expand Up @@ -82,7 +82,7 @@ export function addStopAtIntersection (latlng, activePattern) {
: constructPoint(feature.geometry.coordinates[feature.geometry.coordinates.length - 1])
const lineFromPoint = lineSlice(start, end, {type: 'Feature', geometry: shape})
const stopLocation = along(lineFromPoint, distanceFromIntersection / 1000, 'kilometers')
const latlng = ll.toLatlng(stopLocation.geometry.coordinates)
const latlng = ll.toLeaflet(stopLocation.geometry.coordinates)
// const {afterIntersection, intersectionStep, distanceFromIntersection} = getState().editor.editSettings
return dispatch(addStopAtPoint(latlng, false, patternStops.length, activePattern))
}))
Expand Down Expand Up @@ -128,7 +128,7 @@ export function addStopAtInterval (latlng, activePattern) {

// add stops along shape at interval (stopInterval)
const position = along(updatedShape, stopDistance, 'meters')
const stopLatlng = ll.toLatlng(position.geometry.coordinates)
const stopLatlng = ll.toLeaflet(position.geometry.coordinates)
latlngList.push(stopLatlng)
}
return Promise.all(latlngList.map(latlng => {
Expand Down Expand Up @@ -166,7 +166,7 @@ export function addStopToPattern (pattern, stop, index) {
if (typeof index === 'undefined' || index === null) {
// if shape coordinates already exist, just extend them
if (coordinates) {
const endPoint = ll.toLatlng(coordinates[coordinates.length - 1])
const endPoint = ll.toLeaflet(coordinates[coordinates.length - 1])
patternStops.push(newStop)
dispatch(updateActiveGtfsEntity(pattern, 'trippattern', {patternStops: patternStops}))
// saveActiveGtfsEntity('trippattern')
Expand Down
86 changes: 49 additions & 37 deletions lib/editor/components/map/ControlPoint.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,71 @@
import {Draggable} from 'leaflet'
import throttle from 'lodash.throttle'
import React, { Component, PropTypes } from 'react'
import { Marker } from 'react-leaflet'

import { handlePatternEdit, handleControlPointDragEnd } from '../../util/map'
import { shallowEqual } from 'react-pure-render'

export default class ControlPoint extends Component {
static propTypes = {
position: PropTypes.array
activePattern: PropTypes.object,
icon: PropTypes.object,
index: PropTypes.number,
handleControlPointDrag: PropTypes.func,
handleControlPointDragEnd: PropTypes.func,
next: PropTypes.object,
permanent: PropTypes.bool,
position: PropTypes.array,
previous: PropTypes.object,
removeControlPoint: PropTypes.func,
updateActiveEntity: PropTypes.func,
updateControlPoint: PropTypes.func,
updatePatternCoordinates: PropTypes.func
}
constructor (props) {
super(props)
this.state = {
timer: null,
latlng: null
}
}
shouldComponentUpdate (nextProps) {
// TODO: fix this hack that keeps unknown position change (perhaps react-leaflet is updating it) from triggering
// a component update, which funks with the position of the marker
return !shallowEqual(nextProps.controlPoint.snap, this.props.controlPoint.snap)
}
_onClick = (e) => {
console.log('control point clicked', e)
// only remove controlPoint if it's not based on pattern stop (i.e., has permanent prop)
if (!this.props.permanent) {
this.props.removeControlPoint(this.props.activePattern, this.props.index, this.props.previous, this.props.next)
}
}
_onDrag = () => {
const throttled = throttle(this.handleDrag, 750)
throttled()
}
handleDrag = () => {
const latlng = this.refs.marker.leafletElement.getLatLng()
this.setState({latlng})
this.props.handleControlPointDrag(latlng, this.props.previous, this.props.next, this.props.activePattern)
}
_onDragEnd = (e) => {
this.setState({latlng: null})
this.props.handleControlPointDragEnd(this.props.index, this.props.controlPoint, e, this.props.activePattern)
}
render () {
const { position, icon, previous, next, activePattern, index, permanent, removeControlPoint, updateActiveEntity, updateControlPoint, editSettings } = this.props
const { patternCoordinates, followStreets } = editSettings
if (this.props.index === 1) console.log(this.props)
const { position, icon } = this.props
const {latlng} = this.state
const markerPosition = latlng ? [latlng.lat, latlng.lng] : position
return (
<Marker
position={this.state.latlng || position}
position={markerPosition}
icon={icon}
ref='marker'
zIndexOffset={1000}
draggable
onDragStart={(e) => {
const timerFunction = () => {
const latlng = this.refs.marker.leafletElement.getLatLng()
// console.log(latlng)
handlePatternEdit(latlng, this.props.previous, this.props.next, this.props.activePattern, followStreets, patternCoordinates)
.then(coords => {
this.setState({latlng})
this.props.updatePatternCoordinates(coords)
})
}
timerFunction()
const timer = setInterval(timerFunction, 500)
this.setState({timer})
}}
onDragEnd={(e) => {
// console.log('drag end')
// clear timer
if (this.state.timer) clearInterval(this.state.timer)
const { snap, distTraveled } = handleControlPointDragEnd(e, patternCoordinates)
updateActiveEntity(activePattern, 'trippattern', {shape: {type: 'LineString', coordinates: patternCoordinates}})
updateControlPoint(index, snap, distTraveled)
this.setState({latlng: null})
}}
onClick={(e) => {
console.log('control point clicked', e)
// only remove controlPoint if it's not based on pattern stop (i.e., has permanent prop)
if (!permanent) {
removeControlPoint(activePattern, index, previous, next)
}
}}
onDrag={throttle(this.handleDrag, 500)}
onDragEnd={this._onDragEnd}
onClick={this._onClick}
color='black'
/>
)
Expand Down
25 changes: 19 additions & 6 deletions lib/editor/components/map/ControlPointsLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@ export default class ControlPointsLayer extends Component {
const {
stops,
activePattern,
editSettings,
controlPoints
controlPoints,
snapToStops,
handleControlPointDrag,
handleControlPointDragEnd,
removeControlPoint,
updateActiveEntity,
updateControlPoint,
updatePatternCoordinates
} = this.props
return (
<FeatureGroup ref='controlPoints' key='controlPoints'>
{stops && activePattern && activePattern.shape && editSettings.editGeometry && controlPoints
<FeatureGroup ref='controlPoints'>
{stops && activePattern && activePattern.shape && controlPoints
? controlPoints.map((cp, index) => {
// don't include controlPoint on end of segment (for now) or hidden controlPoints
if (cp.stopId && editSettings.snapToStops) {
if (cp.stopId && snapToStops) {
return null
}
const position = cp.point
Expand All @@ -57,12 +63,19 @@ export default class ControlPointsLayer extends Component {
<ControlPoint
position={[position.geometry.coordinates[1], position.geometry.coordinates[0]]}
icon={icon}
controlPoint={cp}
key={`controlPoint-${index}`}
index={index}
permanent={cp.permanent}
previous={this.getPrevious(index, controlPoints, activePattern)}
next={this.getNext(index, controlPoints)}
{...this.props}
activePattern={activePattern}
handleControlPointDrag={handleControlPointDrag}
handleControlPointDragEnd={handleControlPointDragEnd}
removeControlPoint={removeControlPoint}
updateActiveEntity={updateActiveEntity}
updateControlPoint={updateControlPoint}
updatePatternCoordinates={updatePatternCoordinates}
/>
)
})
Expand Down
27 changes: 15 additions & 12 deletions lib/editor/components/map/EditorMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,21 @@ export default class EditorMap extends Component {
<DirectionIconsLayer
patternCoordinates={this.props.editSettings.patternCoordinates}
mapState={mapState} />
<ControlPointsLayer
stops={stops}
activePattern={activePattern}
editSettings={editSettings}
handlePatternEdit={this.props.handlePatternEdit}
updateControlPoint={this.props.updateControlPoint}
removeControlPoint={this.props.removeControlPoint}
updateActiveEntity={this.props.updateActiveEntity}
handleControlPointDragEnd={this.props.handleControlPointDragEnd}
updatePatternCoordinates={this.props.updatePatternCoordinates}
controlPoints={this.props.controlPoints}
polyline={activePattern && this.refs[activePattern.id]} />
{editSettings.editGeometry &&
<ControlPointsLayer
stops={stops}
activePattern={activePattern}
snapToStops={editSettings.snapToStops}
handlePatternEdit={this.props.handlePatternEdit}
handleControlPointDrag={this.props.handleControlPointDrag}
handleControlPointDragEnd={this.props.handleControlPointDragEnd}
updateControlPoint={this.props.updateControlPoint}
removeControlPoint={this.props.removeControlPoint}
updateActiveEntity={this.props.updateActiveEntity}
updatePatternCoordinates={this.props.updatePatternCoordinates}
controlPoints={this.props.controlPoints}
polyline={activePattern && this.refs[activePattern.id]} />
}
<PatternStopsLayer
stops={stops}
activePattern={activePattern}
Expand Down
1 change: 0 additions & 1 deletion lib/editor/components/map/EditorMapLayersControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export default class EditorMapLayersControl extends Component {
}
]
const activeMapLayerIndex = MAP_LAYERS.findIndex(l => l.id === getUserMetadataProperty(user.profile, 'editor.map_id'))
console.log(process.env)
const MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN
const MAPBOX_ATTRIBUTION = process.env.MAPBOX_ATTRIBUTION
return (
Expand Down
4 changes: 4 additions & 0 deletions lib/editor/containers/ActiveGtfsEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
import {
updateControlPoint,
addControlPoint,
handleControlPointDrag,
handleControlPointDragEnd,
removeControlPoint,
updateMapSetting,
constructControlPoint,
Expand Down Expand Up @@ -239,6 +241,8 @@ const mapDispatchToProps = (dispatch, ownProps) => {
removeControlPoint: (index, begin, end, pattern, polyline) => { dispatch(removeControlPoint(index, begin, end, pattern, polyline)) },
updateControlPoint: (index, point, distance) => { dispatch(updateControlPoint(index, point, distance)) },
constructControlPoint: (pattern, latlng, controlPoints) => { dispatch(constructControlPoint(pattern, latlng, controlPoints)) },
handleControlPointDragEnd: (index, controlPoint, evt, pattern) => { dispatch(handleControlPointDragEnd(index, controlPoint, evt, pattern)) },
handleControlPointDrag: (latlng, previous, next, pattern) => { dispatch(handleControlPointDrag(latlng, previous, next, pattern)) },

// EDITOR UI
setTutorialHidden: (value) => { dispatch(setTutorialHidden(value)) }
Expand Down
2 changes: 1 addition & 1 deletion lib/editor/reducers/data.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import update from 'react-addons-update'
import clone from 'lodash.clonedeep'
import ll from 'lonlng'
import ll from '@conveyal/lonlat'

import { stopToGtfs, routeToGtfs, agencyToGtfs, calendarToGtfs, fareToGtfs, gtfsSort } from '../util/gtfs'
import { getStopsForPattern } from '../util'
Expand Down
8 changes: 4 additions & 4 deletions lib/editor/reducers/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ const editSettings = (state = defaultState, action) => {
actions: {$splice: [[action.lastActionIndex, 1]]}
}
switch (action.lastActionType) {
case 'ADD_CONTROL_POINT':
case 'ADD_CONTROL_POINT': // THIS IS AN UNDO ACTION
stateUpdate.controlPoints = {$splice: [[action.lastControlPointsIndex, 1]]}
break
case 'UPDATE_CONTROL_POINT':
case 'UPDATE_CONTROL_POINT': // THIS IS AN UNDO ACTION
stateUpdate.controlPoints = {$splice: [[action.lastControlPointsIndex, 1]]}
stateUpdate.coordinatesHistory = {$splice: [[action.lastCoordinatesIndex, 1]]}
stateUpdate.patternCoordinates = {$set: action.lastCoordinates}
break
case 'REMOVE_CONTROL_POINT':
case 'REMOVE_CONTROL_POINT': // THIS IS AN UNDO ACTION
stateUpdate.controlPoints = {$splice: [[action.lastControlPointsIndex, 1]]}
stateUpdate.coordinatesHistory = {$splice: [[action.lastCoordinatesIndex, 1]]}
stateUpdate.patternCoordinates = {$set: action.lastCoordinates}
Expand Down Expand Up @@ -138,7 +138,7 @@ const editSettings = (state = defaultState, action) => {
for (var i = 0; i < controlPoints.length; i++) {
newControlPoints.push(Object.assign({}, controlPoints[i]))
}
const newest = update(newControlPoints, {[action.index]: {point: {$set: action.point}, distance: {$set: action.distance}}})
const newest = update(newControlPoints, {[action.index]: {point: {$set: action.point}, distance: {$set: action.distance}, snap: {$set: Math.random()}}})
return update(state, {
controlPoints: {$push: [newest]},
actions: {$push: [action.type]}
Expand Down
Loading

0 comments on commit 4c07e81

Please sign in to comment.