From ca0796a74fc2efed7141f335ed37e081999e381b Mon Sep 17 00:00:00 2001 From: Xiaoji Chen Date: Thu, 26 Sep 2019 12:10:22 -0700 Subject: [PATCH] Use JSX sources/layers in examples (PR 2/2) (#897) --- examples/filter/package.json | 1 - examples/filter/src/app.js | 19 +-- examples/filter/src/map-style.js | 71 +++-------- examples/geojson-animation/package.json | 1 - examples/geojson-animation/src/app.js | 50 ++++---- examples/geojson-animation/src/map-style.js | 14 --- examples/geojson/package.json | 1 - examples/geojson/src/app.js | 28 ++--- examples/geojson/src/map-style.js | 11 +- examples/heatmap/src/app.js | 133 ++++++-------------- examples/heatmap/src/map-style.js | 37 ++++++ 11 files changed, 145 insertions(+), 221 deletions(-) delete mode 100644 examples/geojson-animation/src/map-style.js create mode 100644 examples/heatmap/src/map-style.js diff --git a/examples/filter/package.json b/examples/filter/package.json index 04d032ef..4c69b3e0 100644 --- a/examples/filter/package.json +++ b/examples/filter/package.json @@ -4,7 +4,6 @@ "start-local": "webpack-dev-server --env.local --progress --hot --open" }, "dependencies": { - "immutable": "^3.8.1", "react": "^16.3.0", "react-dom": "^16.3.0", "react-map-gl": "^5.0.0" diff --git a/examples/filter/src/app.js b/examples/filter/src/app.js index 9f29338a..9fb79e2a 100644 --- a/examples/filter/src/app.js +++ b/examples/filter/src/app.js @@ -1,15 +1,15 @@ import React, {Component} from 'react'; import {render} from 'react-dom'; -import MapGL, {Popup} from 'react-map-gl'; +import MapGL, {Popup, Source, Layer} from 'react-map-gl'; import ControlPanel from './control-panel'; -import {defaultMapStyle, highlightLayerIndex} from './map-style.js'; +import {countiesLayer, highlightLayer} from './map-style.js'; const MAPBOX_TOKEN = ''; // Set your mapbox token here export default class App extends Component { state = { - mapStyle: defaultMapStyle, + filter: ['in', 'COUNTY', ''], viewport: { latitude: 38.88, longitude: -98, @@ -27,7 +27,7 @@ export default class App extends Component { let countyName = ''; let hoverInfo = null; - const county = event.features && event.features.find(f => f.layer.id === 'counties'); + const county = event.features[0]; if (county) { hoverInfo = { lngLat: event.lngLat, @@ -36,7 +36,7 @@ export default class App extends Component { countyName = county.properties.COUNTY; } this.setState({ - mapStyle: defaultMapStyle.setIn(['layers', highlightLayerIndex, 'filter', 2], countyName), + filter: ['in', 'COUNTY', countyName], hoverInfo }); }; @@ -54,18 +54,23 @@ export default class App extends Component { } render() { - const {viewport, mapStyle} = this.state; + const {viewport, filter} = this.state; return ( + + + + {this._renderPopup()} diff --git a/examples/filter/src/map-style.js b/examples/filter/src/map-style.js index 906c60fc..4749f9fa 100644 --- a/examples/filter/src/map-style.js +++ b/examples/filter/src/map-style.js @@ -1,52 +1,21 @@ -import {fromJS} from 'immutable'; -import MAP_STYLE from '../../map-style-basic-v8.json'; - -// Make a copy of the map style -const mapStyle = { - ...MAP_STYLE, - sources: {...MAP_STYLE.sources}, - layers: MAP_STYLE.layers.slice() -}; - -// Add the vector tile source for counties -mapStyle.sources.counties = { - type: 'vector', - url: 'mapbox://mapbox.82pkq93d' -}; - -// Insert custom layers before city labels -mapStyle.layers.splice( - mapStyle.layers.findIndex(layer => layer.id === 'place_label_city'), - 0, - // Counties polygons - { - id: 'counties', - interactive: true, - type: 'fill', - source: 'counties', - 'source-layer': 'original', - paint: { - 'fill-outline-color': 'rgba(0,0,0,0.1)', - 'fill-color': 'rgba(0,0,0,0.1)' - } - }, - // Highlighted county polygons - { - id: 'counties-highlighted', - type: 'fill', - source: 'counties', - 'source-layer': 'original', - paint: { - 'fill-outline-color': '#484896', - 'fill-color': '#6e599f', - 'fill-opacity': 0.75 - }, - filter: ['in', 'COUNTY', ''] +export const countiesLayer = { + id: 'counties', + type: 'fill', + 'source-layer': 'original', + paint: { + 'fill-outline-color': 'rgba(0,0,0,0.1)', + 'fill-color': 'rgba(0,0,0,0.1)' } -); - -export const highlightLayerIndex = mapStyle.layers.findIndex( - layer => layer.id === 'counties-highlighted' -); - -export const defaultMapStyle = fromJS(mapStyle); +}; +// Highlighted county polygons +export const highlightLayer = { + id: 'counties-highlighted', + type: 'fill', + source: 'counties', + 'source-layer': 'original', + paint: { + 'fill-outline-color': '#484896', + 'fill-color': '#6e599f', + 'fill-opacity': 0.75 + } +}; diff --git a/examples/geojson-animation/package.json b/examples/geojson-animation/package.json index 04d032ef..4c69b3e0 100644 --- a/examples/geojson-animation/package.json +++ b/examples/geojson-animation/package.json @@ -4,7 +4,6 @@ "start-local": "webpack-dev-server --env.local --progress --hot --open" }, "dependencies": { - "immutable": "^3.8.1", "react": "^16.3.0", "react-dom": "^16.3.0", "react-map-gl": "^5.0.0" diff --git a/examples/geojson-animation/src/app.js b/examples/geojson-animation/src/app.js index fff25c1b..9fd76ff5 100644 --- a/examples/geojson-animation/src/app.js +++ b/examples/geojson-animation/src/app.js @@ -1,20 +1,24 @@ /* global window */ import React, {Component} from 'react'; import {render} from 'react-dom'; -import MapGL from 'react-map-gl'; +import MapGL, {Source, Layer} from 'react-map-gl'; import ControlPanel from './control-panel'; -import {defaultMapStyle, pointLayer} from './map-style.js'; import {pointOnCircle} from './utils'; -import {fromJS} from 'immutable'; const MAPBOX_TOKEN = ''; // Set your mapbox token here -let animation = null; +const pointLayer = { + type: 'circle', + paint: { + 'circle-radius': 10, + 'circle-color': '#007cbf' + } +}; export default class App extends Component { state = { - mapStyle: defaultMapStyle, + pointData: null, viewport: { latitude: 0, longitude: -100, @@ -25,47 +29,41 @@ export default class App extends Component { }; componentDidMount() { - animation = window.requestAnimationFrame(this._animatePoint); + this._animatePoint(); } componentWillUnmount() { - window.cancelAnimationFrame(animation); + window.cancelAnimationFrame(this.animation); } + animation = null; + _animatePoint = () => { - this._updatePointData(pointOnCircle({center: [-100, 0], angle: Date.now() / 1000, radius: 20})); - animation = window.requestAnimationFrame(this._animatePoint); - }; - - _updatePointData = pointData => { - let {mapStyle} = this.state; - if (!mapStyle.hasIn(['sources', 'point'])) { - mapStyle = mapStyle - // Add geojson source to map - .setIn(['sources', 'point'], fromJS({type: 'geojson'})) - // Add point layer to map - .set('layers', mapStyle.get('layers').push(pointLayer)); - } - // Update data source - mapStyle = mapStyle.setIn(['sources', 'point', 'data'], pointData); - - this.setState({mapStyle}); + this.setState({ + pointData: pointOnCircle({center: [-100, 0], angle: Date.now() / 1000, radius: 20}) + }); + this.animation = window.requestAnimationFrame(this._animatePoint); }; _onViewportChange = viewport => this.setState({viewport}); render() { - const {viewport, mapStyle} = this.state; + const {viewport, pointData} = this.state; return ( + {pointData && ( + + + + )} ); diff --git a/examples/geojson-animation/src/map-style.js b/examples/geojson-animation/src/map-style.js deleted file mode 100644 index ceac0d09..00000000 --- a/examples/geojson-animation/src/map-style.js +++ /dev/null @@ -1,14 +0,0 @@ -import {fromJS} from 'immutable'; -import MAP_STYLE from '../../map-style-basic-v8.json'; - -export const pointLayer = fromJS({ - id: 'point', - source: 'point', - type: 'circle', - paint: { - 'circle-radius': 10, - 'circle-color': '#007cbf' - } -}); - -export const defaultMapStyle = fromJS(MAP_STYLE); diff --git a/examples/geojson/package.json b/examples/geojson/package.json index 92579dfd..548dae44 100644 --- a/examples/geojson/package.json +++ b/examples/geojson/package.json @@ -6,7 +6,6 @@ "dependencies": { "d3-request": "^1.0.5", "d3-scale": "^1.0.6", - "immutable": "^3.8.1", "react": "^16.3.0", "react-dom": "^16.3.0", "react-map-gl": "^5.0.0" diff --git a/examples/geojson/src/app.js b/examples/geojson/src/app.js index 464e1bb7..53216922 100644 --- a/examples/geojson/src/app.js +++ b/examples/geojson/src/app.js @@ -1,18 +1,16 @@ import React, {Component} from 'react'; import {render} from 'react-dom'; -import MapGL from 'react-map-gl'; +import MapGL, {Source, Layer} from 'react-map-gl'; import ControlPanel from './control-panel'; -import {defaultMapStyle, dataLayer} from './map-style.js'; +import {dataLayer} from './map-style.js'; import {updatePercentiles} from './utils'; -import {fromJS} from 'immutable'; import {json as requestJson} from 'd3-request'; const MAPBOX_TOKEN = ''; // Set your mapbox token here export default class App extends Component { state = { - mapStyle: defaultMapStyle, year: 2015, data: null, hoveredFeature: null, @@ -35,25 +33,18 @@ export default class App extends Component { _loadData = data => { updatePercentiles(data, f => f.properties.income[this.state.year]); - - const mapStyle = defaultMapStyle - // Add geojson source to map - .setIn(['sources', 'incomeByState'], fromJS({type: 'geojson', data})) - // Add point layer to map - .set('layers', defaultMapStyle.get('layers').push(dataLayer)); - - this.setState({data, mapStyle}); + this.setState({data}); }; _updateSettings = (name, value) => { if (name === 'year') { this.setState({year: value}); - const {data, mapStyle} = this.state; + const {data} = this.state; if (data) { updatePercentiles(data, f => f.properties.income[value]); - const newMapStyle = mapStyle.setIn(['sources', 'incomeByState', 'data'], fromJS(data)); - this.setState({mapStyle: newMapStyle}); + // trigger update + this.setState({data: {...data}}); } } }; @@ -85,7 +76,7 @@ export default class App extends Component { } render() { - const {viewport, mapStyle} = this.state; + const {viewport, data} = this.state; return (
@@ -93,11 +84,14 @@ export default class App extends Component { {...viewport} width="100%" height="100%" - mapStyle={mapStyle} + mapStyle="mapbox://styles/mapbox/light-v9" onViewportChange={this._onViewportChange} mapboxApiAccessToken={MAPBOX_TOKEN} onHover={this._onHover} > + + + {this._renderTooltip()} diff --git a/examples/geojson/src/map-style.js b/examples/geojson/src/map-style.js index 7ab10f1b..9fda04a6 100644 --- a/examples/geojson/src/map-style.js +++ b/examples/geojson/src/map-style.js @@ -1,12 +1,7 @@ -import {fromJS} from 'immutable'; -import MAP_STYLE from '../../map-style-basic-v8.json'; - // For more information on data-driven styles, see https://www.mapbox.com/help/gl-dds-ref/ -export const dataLayer = fromJS({ +export const dataLayer = { id: 'data', - source: 'incomeByState', type: 'fill', - interactive: true, paint: { 'fill-color': { property: 'percentile', @@ -24,6 +19,4 @@ export const dataLayer = fromJS({ }, 'fill-opacity': 0.8 } -}); - -export const defaultMapStyle = fromJS(MAP_STYLE); +}; diff --git a/examples/heatmap/src/app.js b/examples/heatmap/src/app.js index 0a0ef2f4..576463f7 100644 --- a/examples/heatmap/src/app.js +++ b/examples/heatmap/src/app.js @@ -1,11 +1,27 @@ import React, {Component} from 'react'; import {render} from 'react-dom'; -import MapGL from 'react-map-gl'; +import MapGL, {Source, Layer} from 'react-map-gl'; import ControlPanel from './control-panel'; import {json as requestJson} from 'd3-request'; +import {heatmapLayer} from './map-style'; const MAPBOX_TOKEN = ''; // Set your mapbox token here -const HEATMAP_SOURCE_ID = 'earthquakes-source'; + +function filterFeaturesByDay(featureCollection, time) { + const date = new Date(time); + const year = date.getFullYear(); + const month = date.getMonth(); + const day = date.getDate(); + const features = featureCollection.features.filter(feature => { + const featureDate = new Date(feature.properties.time); + return ( + featureDate.getFullYear() === year && + featureDate.getMonth() === month && + featureDate.getDate() === day + ); + }); + return {type: 'FeatureCollection', features}; +} export default class App extends Component { constructor(props) { @@ -27,79 +43,11 @@ export default class App extends Component { earthquakes: null }; - this._mapRef = React.createRef(); - this._handleMapLoaded = this._handleMapLoaded.bind(this); this._handleChangeDay = this._handleChangeDay.bind(this); this._handleChangeAllDay = this._handleChangeAllDay.bind(this); } - _mkFeatureCollection = features => ({type: 'FeatureCollection', features}); - - _filterFeaturesByDay = (features, time) => { - const date = new Date(time); - const year = date.getFullYear(); - const month = date.getMonth(); - const day = date.getDate(); - return features.filter(feature => { - const featureDate = new Date(feature.properties.time); - return ( - featureDate.getFullYear() === year && - featureDate.getMonth() === month && - featureDate.getDate() === day - ); - }); - }; - - _mkHeatmapLayer = (id, source) => { - const MAX_ZOOM_LEVEL = 9; - return { - id, - source, - maxzoom: MAX_ZOOM_LEVEL, - type: 'heatmap', - paint: { - // Increase the heatmap weight based on frequency and property magnitude - 'heatmap-weight': ['interpolate', ['linear'], ['get', 'mag'], 0, 0, 6, 1], - // Increase the heatmap color weight weight by zoom level - // heatmap-intensity is a multiplier on top of heatmap-weight - 'heatmap-intensity': ['interpolate', ['linear'], ['zoom'], 0, 1, MAX_ZOOM_LEVEL, 3], - // Color ramp for heatmap. Domain is 0 (low) to 1 (high). - // Begin color ramp at 0-stop with a 0-transparancy color - // to create a blur-like effect. - 'heatmap-color': [ - 'interpolate', - ['linear'], - ['heatmap-density'], - 0, - 'rgba(33,102,172,0)', - 0.2, - 'rgb(103,169,207)', - 0.4, - 'rgb(209,229,240)', - 0.6, - 'rgb(253,219,199)', - 0.8, - 'rgb(239,138,98)', - 0.9, - 'rgb(255,201,101)' - ], - // Adjust the heatmap radius by zoom level - 'heatmap-radius': ['interpolate', ['linear'], ['zoom'], 0, 2, MAX_ZOOM_LEVEL, 20], - // Transition from heatmap to circle layer by zoom level - 'heatmap-opacity': ['interpolate', ['linear'], ['zoom'], 7, 1, 9, 0] - } - }; - }; - - _onViewportChange = viewport => this.setState({viewport}); - - _getMap = () => { - return this._mapRef.current ? this._mapRef.current.getMap() : null; - }; - - _handleMapLoaded = event => { - const map = this._getMap(); - + componentDidMount() { requestJson( 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson', (error, response) => { @@ -111,59 +59,56 @@ export default class App extends Component { const startTime = features[features.length - 1].properties.time; this.setState({ + data: response, earthquakes: response, endTime, startTime, selectedTime: endTime }); - map.addSource(HEATMAP_SOURCE_ID, {type: 'geojson', data: response}); - map.addLayer(this._mkHeatmapLayer('heatmap-layer', HEATMAP_SOURCE_ID)); } } ); - }; + } + + _onViewportChange = viewport => this.setState({viewport}); _handleChangeDay = time => { this.setState({selectedTime: time}); - if (this.state.earthquakes !== null && this.state.earthquakes.features) { - const features = this._filterFeaturesByDay(this.state.earthquakes.features, time); - this._setMapData(features); + if (this.state.earthquakes) { + this.setState({data: filterFeaturesByDay(this.state.earthquakes, time)}); } }; _handleChangeAllDay = allDay => { this.setState({allDay}); - if (this.state.earthquakes !== null && this.state.earthquakes.features) { - this._setMapData( - allDay - ? this.state.earthquakes.features - : this._filterFeaturesByDay(this.state.earthquakes.features, this.state.selectedTime) - ); - } - }; - - _setMapData = features => { - const map = this._getMap(); - if (map) { - map.getSource(HEATMAP_SOURCE_ID).setData(this._mkFeatureCollection(features)); + if (this.state.earthquakes) { + this.setState({ + data: allDay + ? this.state.earthquakes + : filterFeaturesByDay(this.state.earthquakes, this.state.selectedTime) + }); } }; render() { - const {viewport, allDay, selectedTime, startTime, endTime} = this.state; + const {viewport, data, allDay, selectedTime, startTime, endTime} = this.state; return (
+ > + {data && ( + + + + )} +