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
新しいモバイルアプリ勉強会(仮)について
uetyo
1
250
Nuances on Kubernetes - RubyConf Taiwan 2025
envek
0
150
Flutterと Vibe Coding で個人開発!
hyshu
1
250
QA x AIエコシステム段階構築作戦
osu
0
270
「リーダーは意思決定する人」って本当?~ 学びを現場で活かす、リーダー4ヶ月目の試行錯誤 ~
marina1017
0
220
コーディングは技術者(エンジニア)の嗜みでして / Learning the System Development Mindset from Rock Lady
mackey0225
2
440
AIのメモリー
watany
13
1.4k
物語を動かす行動"量" #エンジニアニメ
konifar
14
4.7k
Flutter로 Gemini와 MCP를 활용한 Agentic App 만들기 - 박제창 2025 I/O Extended Seoul
itsmedreamwalker
0
130
Dart 参戦!!静的型付き言語界の隠れた実力者
kno3a87
0
190
CEDEC2025 長期運営ゲームをあと10年続けるための0から始める自動テスト ~4000項目を50%自動化し、月1→毎日実行にした3年間~
akatsukigames_tech
0
120
Comparing decimals in Swift Testing
417_72ki
0
170
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
45
7.6k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Making Projects Easy
brettharned
117
6.3k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.5k
Measuring & Analyzing Core Web Vitals
bluesmoon
8
550
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
Building Applications with DynamoDB
mza
96
6.5k
Rails Girls Zürich Keynote
gr2m
95
14k
What's in a price? How to price your products and services
michaelherold
246
12k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
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