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
95
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
30
Other Decks in Programming
See All in Programming
バックエンドのためのアプリ内課金入門 (サブスク編)
qnighy
8
1.7k
お前もAI鬼にならないか?👹Bolt & Cursor & Supabase & Vercelで人間をやめるぞ、ジョジョー!👺
taishiyade
5
3.8k
Grafana Loki によるサーバログのコスト削減
mot_techtalk
1
110
プログラミング言語学習のススメ / why-do-i-learn-programming-language
yashi8484
0
120
GAEログのコスト削減
mot_techtalk
0
110
Open source software: how to live long and go far
gaelvaroquaux
0
620
XStateを用いた堅牢なReact Components設計~複雑なClient Stateをシンプルに~ @React Tokyo ミートアップ #2
kfurusho
1
770
Compose でデザインと実装の差異を減らすための取り組み
oidy
1
300
さいきょうのレイヤードアーキテクチャについて考えてみた
yahiru
3
730
テストをしないQAエンジニアは何をしているか?
nealle
0
130
ペアーズでの、Langfuseを中心とした評価ドリブンなリリースサイクルのご紹介
fukubaka0825
2
300
iOSエンジニアから始める visionOS アプリ開発
nao_randd
3
120
Featured
See All Featured
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Rails Girls Zürich Keynote
gr2m
94
13k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Building Better People: How to give real-time feedback that sticks.
wjessup
366
19k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Building Applications with DynamoDB
mza
93
6.2k
Testing 201, or: Great Expectations
jmmastey
41
7.2k
The Invisible Side of Design
smashingmag
299
50k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
175
51k
How to train your dragon (web standard)
notwaldorf
90
5.8k
Building an army of robots
kneath
302
45k
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