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
[Fin-JAWS 第38回 ~re:Invent 2024 金融re:Cap~]FaultInjectionServiceアップデート@pre:Invent2024
shintaro_fukatsu
0
400
いりゃあせ、PHPカンファレンス名古屋2025 / Welcome to PHP Conference Nagoya 2025
ttskch
1
270
Amazon ECS とマイクロサービスから考えるシステム構成
hiyanger
2
490
Writing documentation can be fun with plugin system
okuramasafumi
0
120
Linux && Docker 研修/Linux && Docker training
forrep
23
4.5k
Amazon Q Developer Proで効率化するAPI開発入門
seike460
PRO
0
110
動作確認やテストで漏れがちな観点3選
starfish719
6
1k
『GO』アプリ バックエンドサーバのコスト削減
mot_techtalk
0
130
ペアーズでの、Langfuseを中心とした評価ドリブンなリリースサイクルのご紹介
fukubaka0825
2
300
Kubernetes History Inspector(KHI)を触ってみた
bells17
0
200
なぜイベント駆動が必要なのか - CQRS/ESで解く複雑系システムの課題 -
j5ik2o
7
2.5k
パスキーのすべて ── 導入・UX設計・実装の紹介 / 20250213 パスキー開発者の集い
kuralab
3
670
Featured
See All Featured
Speed Design
sergeychernyshev
25
780
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
A designer walks into a library…
pauljervisheath
205
24k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.4k
How to train your dragon (web standard)
notwaldorf
90
5.8k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
44
9.4k
The Pragmatic Product Professional
lauravandoore
32
6.4k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
How STYLIGHT went responsive
nonsquared
98
5.3k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
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