import { Feature as GeoJSONFeature , LineString } from 'geojson' ; import * as React from 'react' ; import { GeoJSONLayer } from 'react-mapbox-gl' ; import { shallowEqual , Feature , FeatureCollection } from '../../utils' ; import { mixColors } from './utils' ; const BICYCLE_STROKE = '#0089F8' ; const BICYCLE_OUTLINE = '#002440' ; export interface Props { geojson : FeatureCollection ; visibility : 'visible' | 'none' ; before ? : string ; } interface State { /** Same as props.geojson, but with fillColor set */ walkFeatures : FeatureCollection ; otherFeatures : FeatureCollection ; } function coalesceFeatures ( geojson ) { const features = JSON . parse ( JSON . stringify ( geojson . features ) ) as any ; const outFeatures = [ features [ 0 ] ] ; for ( let i = 1 ; i < features . length ; i ++ ) { const lastF = outFeatures [ outFeatures . length - 1 ] ; const f = features [ i ] ; if ( f . properties . mode === lastF . properties . mode ) { lastF . geometry . coordinates . push ( f . geometry . coordinates [ 1 ] ) ; } else { outFeatures . push ( f ) ; } } return { type : 'FeatureCollection' , features : outFeatures } ; } function makeStyledFeatures ( geojson ) { return { type : 'FeatureCollection' , features : geojson . features . map ( f => { const { properties } = f ; const isBicycle = properties . mode === 'BICYCLE' ; const lineColor = isBicycle ? BICYCLE_STROKE : properties . stroke ; const lineOutlineColor = isBicycle ? BICYCLE_OUTLINE : mixColors ( lineColor , '#000000' ) ; return { ... f , properties : { ... f . properties , lineColor , lineOutlineColor , isWalk : ! ( 'tripId' in f . properties ) && ! isBicycle , } , } ; } ) , } ; } const LINE_PAINT_TRANSIT = { 'line-color' : [ 'get' , 'lineColor' ] , 'line-width' : 3 , } ; const LINE_PAINT_TRANSIT_CASING = { 'line-color' : [ 'get' , 'lineOutlineColor' ] , 'line-width' : 1 , 'line-gap-width' : 3 , 'line-opacity' : 0.75 , } ; const LINE_PAINT_WALK = { 'line-color' : '#000000' , 'line-width' : 3 , 'line-dasharray' : [ 1 , 1 ] , } ; function splitFeatureCollection ( featureCollection , predicate ) { const results = [ [ ] , [ ] ] ; for ( const feature of featureCollection . features ) { results [ predicate ( feature ) ? 0 : 1 ] . push ( feature ) ; } return [ { type : 'FeatureCollection' , features : results [ 0 ] , } , { type : 'FeatureCollection' , features : results [ 1 ] , } , ] ; } function propsToState ( props ) { const features = makeStyledFeatures ( coalesceFeatures ( props . geojson ) ) ; const [ walkFeatures , otherFeatures ] = splitFeatureCollection ( features , f => f . properties . isWalk ) ; return { walkFeatures , otherFeatures , } ; } export class RouteLayer extends React . Component < Props , State > { constructor ( props ) { super ( props ) ; this . state = propsToState ( props ) ; } render ( ) { const { before , visibility } = this . props ; return ( < > < GeoJSONLayer data = { this . state . walkFeatures } linePaint = { LINE_PAINT_WALK } lineLayout = { { visibility } } before = { before } / > < GeoJSONLayer data = { this . state . otherFeatures } linePaint = { LINE_PAINT_TRANSIT } lineLayout = { { visibility } } before = { before } / > < GeoJSONLayer data = { this . state . otherFeatures } linePaint = { LINE_PAINT_TRANSIT_CASING } lineLayout = { { visibility } } before = { before } / > < />); } shouldComponentUpdate ( nextProps , nextState ) { return ! shallowEqual ( this . props , nextProps ) || ! shallowEqual ( this . state , nextState ) ; } componentWillReceiveProps ( nextProps ) { if ( this . props . geojson === nextProps . geojson ) { return ; } this . setState ( propsToState ( nextProps ) ) ; } }