Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Supercharge Your Maps
Search
shortdiv
September 23, 2017
Programming
3
98
Supercharge Your Maps
Talk for React Boston 2017
shortdiv
September 23, 2017
Tweet
Share
More Decks by shortdiv
See All by shortdiv
In VDOM we Trust; unraveling the mystery of Virtual DOM
shortdiv
0
32
Other Decks in Programming
See All in Programming
CSC305 Lecture 02
javiergs
PRO
1
260
Signals & Resource API in Angular: 3 Effective Rules for Your Architecture @BASTA 2025 in Mainz
manfredsteyer
PRO
0
110
Go言語の特性を活かした公式MCP SDKの設計
hond0413
1
200
Model Pollution
hschwentner
1
190
なぜあの開発者はDevRelに伴走し続けるのか / Why Does That Developer Keep Running Alongside DevRel?
nrslib
3
380
タスクの特性や不確実性に応じた最適な作業スタイルの選択(ペアプロ・モブプロ・ソロプロ)と実践 / Optimal Work Style Selection: Pair, Mob, or Solo Programming.
honyanya
3
150
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
110
Back to the Future: Let me tell you about the ACP protocol
terhechte
0
130
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
210
登壇は dynamic! な営みである / speech is dynamic
da1chi
0
160
どの様にAIエージェントと 協業すべきだったのか?
takefumiyoshii
2
620
Advance Your Career with Open Source
ivargrimstad
0
410
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
269
13k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
51k
Mobile First: as difficult as doing things right
swwweet
224
10k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
30
2.9k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
Faster Mobile Websites
deanohume
310
31k
Embracing the Ebb and Flow
colly
88
4.8k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.9k
Writing Fast Ruby
sferik
629
62k
The Invisible Side of Design
smashingmag
301
51k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
GitHub's CSS Performance
jonrohan
1032
460k
Transcript
Divya Sasidharan Supercharging Your Maps with React
Web Developer @ KnightLab Divya Sasidharan @shortdiv
You are here
None
None
None
None
None
Tiles
Vector Tiles Raster Tiles
Raster Tiles
Raster Tiles
Raster Tiles - +
Anatomy of a map tile [abc]. tile.openstreetmap.org/[z]/[x]/[y].png subdomain zoom level
coordinates
Vector Tiles
Vector Tiles
None
import mapboxgl from ‘mapbox-gl’; mapboxgl.accessToken = ‘ACCESS_TOKEN_HERE’ const map =
new mapboxgl.Map({ container: ‘map’, style: ‘mapbox://styles/mapbox/streets-v9’, center: [-71.05888010000001, 42.3600825], zoom: 9 }) <div id=“map”></div> Mapbox
https://codepen.io/shortdiv/pen/OxVapR
Bring on the data!
{ “type": "FeatureCollection", "features": [ { type: “Feature”, geometry: {
type: “Point”, coordinates: [-71.114213, 42.366646] } }, properties: { name: “Wayfair”, address: “4 Copley Place, Boston, MA 02116” } ] } GeoJSON
Title Text Getting GeoJSON
Leaflet Omnivore Getting GeoJSON http://bit.ly/geoData
You are here
import mapboxgl from ‘mapbox-gl’; mapboxgl.accessToken = ‘ACCESS_TOKEN_HERE’ const map =
new mapboxgl.Map({ container: ‘map’, style: ‘mapbox://styles/mapbox/streets-v9’, center: [-87.623177, 41.881832], zoom: 9 }) map.on('load' () => { map.addSource(‘react-boston’, { "type": "geojson", “data": [GeoJSON_HERE] }) }) `Add Source`
mapboxgl.accessToken = ‘ACCESS_TOKEN_HERE’ const map = new mapboxgl.Map({ container: ‘map’,
style: ‘mapbox://styles/mapbox/streets-v9’, center: [-87.623177, 41.881832], zoom: 9 }) map.on('load' () => { map.addSource(‘react-boston’, { “type": "geojson", “data": [GeoJSON_HERE] }) map.addLayer({ "id": "react-boston-venue" "type": "symbol", “source”: ‘react-boston’, "layer": {"icon-image": "star-15"} }) }) `Add Layer` https://codepen.io/shortdiv/pen/veNgoK
https://codepen.io/shortdiv/pen/veNgoK
Layers
Data Styles Events
https://codepen.io/shortdiv/pen/xXEpVW
style: 'mapbox://styles/mapbox/streets-v9', center: [-71.05888010000001, 42.3600825], zoom: 9 }); map.on('load', ()
=> { map.addSource('neighborhoods', { "type": "geojson", “data": [GeoJSON_HERE] }) map.addLayer({ "id": “neighborhoods-borders", "type": "line", "source": "neighborhoods", "paint": { “line-color": “#877b59”, “line-width: 1” } }); map.addLayer({ "id": “neighborhoods-fill", "type": "fill", "source": "neighborhoods", “paint": { “fill-color": “grey”, “opacity”: 0.7 } }); }) Same Source; Diff Layers NEEDS LINK
'pk.eyJ1Ijoic2hvcnRkaXYiLCJhIjoiY2l3OGc5YmE5MDJzZjJ5bWhkdDZieGdzcSJ9.1z- swTWtcCHYI_RawDJCEw'; var map = new mapboxgl.Map({ container: ‘map', style:
'mapbox://styles/mapbox/streets-v9', center: [-71.05888010000001, 42.3600825], zoom: 9 }); map.on('load', () => { … input.on(‘change’, (e) => { let visibility = map.getLayoutProperty('neighborhoods-fill', 'visibility') let visible = visibility === 'visible' ? 'none' : 'visible' map.setLayoutProperty('neighborhoods-fill', 'visibility', visible) }) }) Events https://codepen.io/shortdiv/pen/YrGEJv
https://codepen.io/shortdiv/pen/MEjKYp
map.addLayer({ "id": “neighborhoods-fill", "type": "fill", "source": "neighborhoods", "layout": { “fill-color":
“grey”, “opacity”: 0.7 } }); map.addLayer({ “id”: “neighborhood-selected", “type”: "fill", “source”: "neighborhoods", “layout”: {}, “paint”: { "fill-color": "#b3d5ed", "fill-opacity": 0.6 }, filter: ["==", "Name", “"] }) … }) Filter Layers
"id": “neighborhoods-fill", "type": "fill", "source": "neighborhoods", "layout": { “fill-color": “grey”,
“opacity”: 0.7 } }); map.addLayer({ “id”: “neighborhood-selected", “type”: "fill", “source”: "neighborhoods", “layout”: {}, “paint”: { "fill-color": "#b3d5ed", "fill-opacity": 0.6 }, filter: ["==", "Name", “"] }) map.on(‘mousemove’, ‘neighborhoods-fill’, (e) => { map.setFilter(“neighborhoods-hover", [“==", "Name", e.features[0].properties.name]) }) map.on(‘mouseleave’, ‘neighborhoods-fill’, (e) => { map.setFilter("neighborhoods-hover", ["==", “Name", ""]); }) … }) Filter Layers
React ftw!
<Components />
class Map extends Component { componentDidMount() { mapboxgl.accessToken = [ACCESS_TOKEN_HERE]
var map = new mapboxgl.Map({ container: this.map, style: 'mapbox://styles/mapbox/light-v8', center: [-71.058880, 42.360083], zoom: 9 }) } render(){ return ( <div id='map' ref={(x) => this.map = x}> </div> ) } }; ReactDOM.render(<Map />, document.getElementById(‘app')); https://codepen.io/shortdiv/pen/qPOrPZ
https://codepen.io/shortdiv/pen/qPOrPZ
super(props) this.state = { map: null } } componentDidMount() {
... map.on('load', () => { map.addSource(‘react-boston’, { “type”: “geojson”, “data”: [GeoJSON_HERE] }) map.addLayer({ "id": "react-boston-venue", "type": "symbol", “source": ‘react-boston’, "layout": { "icon-image": “star-15" } }); }) } render(){ return ( <div id='map' ref={(x) => this.map = x}> </div> https://codepen.io/shortdiv/pen/boVqaj
https://codepen.io/shortdiv/pen/boVqaj
Componentize your components
<Map> <Layer data = { data } /> </Map>
class Map extends Component { componentDidMount() { … map.on(‘load’, ()
=> { fetch(‘URL_HERE’).then((res) => {return res.json()}) .then((data) => { this.setState({ data }) }) }) } render() { const { map, data } = this.state return ( <div id='map' ref={(x) => this.map = x}> <Layer data={data} /> </div>) } } <Map />
class Layer extends Component { componentWillMount() { const { data
} = this.props map.addSource(‘react-boston’, { “type”: “geojson”, “data”: data }) map.addLayer({ "id": "react-boston-venue" "type": "symbol", “source": ‘react-boston’, "layer": {"icon-image": "star-15"} }) } render() { return null } } <Layer />
None
class Map extends Component { componentDidMount() { map.on(‘load’, () =>
{ fetch(‘URL_HERE’).then((res) => {return res.json()}) .then((data) => { this.setState({ map, data }) }) }) } render() { const { map, data } = this.state return ( <div id='map' ref={(x) => this.map = x}> {map && (<Layer data={data} />)} </div>) } } <Map />
None
class Layer extends Component { componentWillMount() { const { map
} = this.context map.addLayer({…}) } } Layer.contextTypes = { map: PropTypes.object } class Map extends Component { … getChildContext() { return { map: this.state.map } } … } Map.childContextTypes = { map: PropTypes.object } Layer Map
https://codepen.io/shortdiv/pen/XeNXxE
class Layer extends Component { componentWillMount() { const { map
} = this.context const { data } = this.props map.addLayer({ "id": "react-boston-venue" "type": "symbol", "source": { "type": "geojson", “data": data }, "layer": {"icon-image": "star-15"} }) } render() { return null } } <Layer />
<Map> <Layer id type sourceType data styles /> </Map>
class Layer extends Component { componentWillMount() { const { map
} = this.context const { id, type, sourceType, data, styles } = this.props map.addSource(‘react-boston’, { “type”: sourceType, “data”: data }) map.addLayer({ "id": id "type": type, “source": ‘react-boston’, "layer": styles }) } render() { return null } } <Layer />
<Source /> <Layer /> { } <> Data Component(s) <Map
/> <>
<Map> <Source id type data /> <Layer … /> </Map>
class Source extends Component { componentWillMount() { const { map
} = this.context const { id, type, data } = this.props map.addSource({ map.addSource(id, { "type": type, “data": data }) }) } render() { return null } } <Source />
Lifecycle them in
Mount Update Unmount Update
<Map> <Layer isLayerVisible /> </Map> <Checkbox handleCheck={this.showLayer.bind(this)} />
https://codepen.io/shortdiv/pen/xXEpVW
class Map extends Component { showLayer() { this.setState({ showLayer: !this.state.isLayerVisible
}) } render(){ const { showLayer } = this.state return ( <div> <div id='map' ref={(x) => this.map = x}> {map && ( <Layer … isLayerVisible=isLayerVisible … /> )} </div> <CheckBox handleChange={this.showLayer.bind(this)} /> </div> ) } };
ComponentWillReceiveProps class Layer extends Component { … componentWillReceiveProps(nextProps) { const
{map} = this.context const {isLayerVisible} = this.props if(nextProps.isLayerVisible != isLayerVisible) { const visibility = nextProps.isLayerVisible ? 'visible' : 'none' map.setLayoutProperty("neighborhoods", 'visibility', visibility) } } render() { return null } }
None
Realtime Data Updates class Source extends Component { … componentWillReceiveProps(nextProps)
{ const {map} = this.context if(nextProps.data != this.props.data) { map.getSource(this.props.id).setData(nextProps.data) } } render() { return null } }
Mapbox Maps React Renders
Thanks! @shortdiv https://github.com/shortdiv/react-mapboxgl-components http://bit.ly/reactMaps