$30 off During Our Annual Pro Sale. View Details »
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
33
Other Decks in Programming
See All in Programming
これならできる!個人開発のすゝめ
tinykitten
PRO
0
110
令和最新版Android Studioで化石デバイス向けアプリを作る
arkw
0
410
【CA.ai #3】Google ADKを活用したAI Agent開発と運用知見
harappa80
0
320
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
130
Cap'n Webについて
yusukebe
0
130
UIデザインに役立つ 2025年の最新CSS / The Latest CSS for UI Design 2025
clockmaker
18
7.5k
まだ間に合う!Claude Code元年をふりかえる
nogu66
5
840
Integrating WordPress and Symfony
alexandresalome
0
160
TestingOsaka6_Ozono
o3
0
160
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
3
810
開発に寄りそう自動テストの実現
goyoki
2
1k
LLM Çağında Backend Olmak: 10 Milyon Prompt'u Milisaniyede Sorgulamak
selcukusta
0
120
Featured
See All Featured
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.1k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Making Projects Easy
brettharned
120
6.5k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
RailsConf 2023
tenderlove
30
1.3k
Unsuck your backbone
ammeep
671
58k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
Scaling GitHub
holman
464
140k
Building Applications with DynamoDB
mza
96
6.8k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
How to Think Like a Performance Engineer
csswizardry
28
2.4k
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