-
Interactive GeoJSON
-
- Map showing median household income by state in year {settings.year} . Hover over a
- state to see details.
-
-
- Data source: US Census Bureau
-
-
-
-
-
- Year
- this.props.onChange('year', evt.target.value)}
- />
-
+ return (
+
+
Interactive GeoJSON
+
+ Map showing median household income by state in year {year} . Hover over a state to
+ see details.
+
+
+ Data source: US Census Bureau
+
+
- );
- }
+
+
+
+ Year
+ props.onChange(evt.target.value)}
+ />
+
+
+ );
}
+
+export default React.memo(ControlPanel);
diff --git a/examples/get-started/classic/README.md b/examples/get-started/classic/README.md
index d0fcd324..121c4e67 100644
--- a/examples/get-started/classic/README.md
+++ b/examples/get-started/classic/README.md
@@ -1,13 +1,18 @@
-
-
-
+# react-map-gl Example Using React Class Component
-## react-map-gl example with React Component
+This example shows a minimal app configuration to use react-map-gl with a React class component.
-The configuration showcased here is a bit less straightforward than its browserify
-equivalent due to some incompatibilities with mapbox-gl, but has been kept at a
-strict minimum.
+## Usage
-You should keep in mind that it is a development configuration, and probably
-should be tweaked a bit for production optimization, there is plenty ressources
-on the subject and are not in the scope of this example.
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
+
+To build a production version:
+
+```bash
+npm run build
+```
diff --git a/examples/get-started/classic/package.json b/examples/get-started/classic/package.json
index e53e7514..ee6df9c0 100644
--- a/examples/get-started/classic/package.json
+++ b/examples/get-started/classic/package.json
@@ -1,11 +1,12 @@
{
"scripts": {
- "start": "webpack-dev-server --progress --hot --open"
+ "start": "webpack-dev-server --progress --hot --open",
+ "build": "webpack -p"
},
"dependencies": {
"react": "^16.3.0",
"react-dom": "^16.3.0",
- "react-map-gl": "^5.1.0"
+ "react-map-gl": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
diff --git a/examples/get-started/hooks/README.md b/examples/get-started/hooks/README.md
index f1a05e9f..9e24da61 100644
--- a/examples/get-started/hooks/README.md
+++ b/examples/get-started/hooks/README.md
@@ -1,13 +1,18 @@
-
-
-
+# react-map-gl Example Using React Functional Component
-## react-map-gl example with React Hooks
+This example shows a minimal app configuration to use react-map-gl with a React functional component.
-The configuration showcased here is a bit less straightforward than its browserify
-equivalent due to some incompatibilities with mapbox-gl, but has been kept at a
-strict minimum.
+## Usage
-You should keep in mind that it is a development configuration, and probably
-should be tweaked a bit for production optimization, there is plenty ressources
-on the subject and are not in the scope of this example.
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
+
+To build a production version:
+
+```bash
+npm run build
+```
diff --git a/examples/get-started/hooks/app.js b/examples/get-started/hooks/app.js
index 12850f71..80b4967e 100644
--- a/examples/get-started/hooks/app.js
+++ b/examples/get-started/hooks/app.js
@@ -21,7 +21,7 @@ function Root() {
width="100vw"
height="100vh"
mapStyle="mapbox://styles/mapbox/dark-v9"
- onViewportChange={nextViewport => setViewport(nextViewport)}
+ onViewportChange={setViewport}
mapboxApiAccessToken={MAPBOX_TOKEN}
/>
);
diff --git a/examples/get-started/hooks/package.json b/examples/get-started/hooks/package.json
index 8545fe57..b2a022ee 100644
--- a/examples/get-started/hooks/package.json
+++ b/examples/get-started/hooks/package.json
@@ -5,7 +5,7 @@
"dependencies": {
"react": "^16.8.0",
"react-dom": "^16.8.0",
- "react-map-gl": "^5.1.0"
+ "react-map-gl": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
diff --git a/examples/heatmap/README.md b/examples/heatmap/README.md
index 45cc928e..a1831066 100644
--- a/examples/heatmap/README.md
+++ b/examples/heatmap/README.md
@@ -1,15 +1,12 @@
-## Example: Heatmap layer
+# Example: Heatmap layer
-This example showcases how to add a heatmap similar as described in https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/.
+This app reproduces Mapbox's [Create a heatmap layer](https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/) example.
-### How to run `heatmap layer example`?
+## Usage
-Install dependencies (only once)
-```
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
npm i
+npm run start
```
-and run example
-```
-MapboxAccessToken={YOUR_MAPBOX_TOKEN} npm run start-local
-```
-which will open and point your browser to http://localhost:8081/
diff --git a/examples/heatmap/package.json b/examples/heatmap/package.json
index 9cc136e9..0ae73b96 100644
--- a/examples/heatmap/package.json
+++ b/examples/heatmap/package.json
@@ -4,7 +4,6 @@
"start-local": "webpack-dev-server --env.local --progress --hot --open"
},
"dependencies": {
- "d3-request": "^1.0.5",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"react-map-gl": "^6.0.0"
diff --git a/examples/heatmap/src/app.js b/examples/heatmap/src/app.js
index 08710a1f..e6d25eec 100644
--- a/examples/heatmap/src/app.js
+++ b/examples/heatmap/src/app.js
@@ -1,9 +1,8 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState, useEffect, useMemo} from 'react';
import {render} from 'react-dom';
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
@@ -24,104 +23,66 @@ function filterFeaturesByDay(featureCollection, time) {
return {type: 'FeatureCollection', features};
}
-export default class App extends Component {
- constructor(props) {
- super(props);
- const current = new Date().getTime();
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 40,
+ longitude: -100,
+ zoom: 3,
+ bearing: 0,
+ pitch: 0
+ });
+ const [allDays, useAllDays] = useState(true);
+ const [timeRange, setTimeRange] = useState([0, 0]);
+ const [selectedTime, selectTime] = useState(0);
+ const [earthquakes, setEarthQuakes] = useState(null);
- this.state = {
- viewport: {
- latitude: 40,
- longitude: -100,
- zoom: 3,
- bearing: 0,
- pitch: 0
- },
- allDay: true,
- startTime: current,
- endTime: current,
- selectedTime: current,
- earthquakes: null
- };
+ useEffect(() => {
+ /* global fetch */
+ fetch('https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson')
+ .then(resp => resp.json())
+ .then(json => {
+ // Note: In a real application you would do a validation of JSON data before doing anything with it,
+ // but for demonstration purposes we ingore this part here and just trying to select needed data...
+ const features = json.features;
+ const endTime = features[0].properties.time;
+ const startTime = features[features.length - 1].properties.time;
- this._handleChangeDay = this._handleChangeDay.bind(this);
- this._handleChangeAllDay = this._handleChangeAllDay.bind(this);
- }
-
- componentDidMount() {
- requestJson(
- 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson',
- (error, response) => {
- if (!error) {
- // Note: In a real application you would do a validation of JSON data before doing anything with it,
- // but for demonstration purposes we ingore this part here and just trying to select needed data...
- const features = response.features;
- const endTime = features[0].properties.time;
- const startTime = features[features.length - 1].properties.time;
-
- this.setState({
- data: response,
- earthquakes: response,
- endTime,
- startTime,
- selectedTime: endTime
- });
- }
- }
- );
- }
-
- _onViewportChange = viewport => this.setState({viewport});
-
- _handleChangeDay = time => {
- this.setState({selectedTime: time});
- if (this.state.earthquakes) {
- this.setState({data: filterFeaturesByDay(this.state.earthquakes, time)});
- }
- };
-
- _handleChangeAllDay = allDay => {
- this.setState({allDay});
- if (this.state.earthquakes) {
- this.setState({
- data: allDay
- ? this.state.earthquakes
- : filterFeaturesByDay(this.state.earthquakes, this.state.selectedTime)
+ setTimeRange([startTime, endTime]);
+ setEarthQuakes(json);
+ selectTime(endTime);
});
- }
- };
+ }, []);
- render() {
- const {viewport, data, allDay, selectedTime, startTime, endTime} = this.state;
+ const data = useMemo(() => {
+ return allDays ? earthquakes : filterFeaturesByDay(earthquakes, selectedTime);
+ }, [earthquakes, allDays, selectedTime]);
- return (
-
-
- {data && (
-
-
-
- )}
-
-
-
- );
- }
+ return (
+ <>
+
+ {data && (
+
+
+
+ )}
+
+
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/heatmap/src/control-panel.js b/examples/heatmap/src/control-panel.js
index b5aab712..648131dc 100644
--- a/examples/heatmap/src/control-panel.js
+++ b/examples/heatmap/src/control-panel.js
@@ -1,69 +1,70 @@
import * as React from 'react';
-import {PureComponent} from 'react';
-export default class ControlPanel extends PureComponent {
- render() {
- const {startTime, endTime, onChangeDay, allDay, onChangeAllDay, selectedTime} = this.props;
- const day = 24 * 60 * 60 * 1000;
- const days = Math.round((endTime - startTime) / day);
-
- const _onChangeDay = evt => {
- const daysToAdd = evt.target.value;
- // add selected days to start time to calculate new time
- const newTime = startTime + daysToAdd * day;
- onChangeDay(newTime);
- };
-
- const formatTime = time => {
- const date = new Date(time);
- return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
- };
-
- return (
-
-
Heatmap
-
- Map showing earthquakes
-
- from {formatTime(startTime)} to {formatTime(endTime)} .
-
-
-
- All Days
- onChangeAllDay(evt.target.checked)}
- />
-
-
- Each Day: {formatTime(selectedTime)}
-
-
-
-
- Data source:{' '}
-
- earthquakes.geojson
-
-
-
-
- );
- }
+function formatTime(time) {
+ const date = new Date(time);
+ return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
}
+
+function ControlPanel(props) {
+ const {startTime, endTime, onChangeTime, allDays, onChangeAllDays, selectedTime} = props;
+ const day = 24 * 60 * 60 * 1000;
+ const days = Math.round((endTime - startTime) / day);
+ const selectedDay = Math.round((selectedTime - startTime) / day);
+
+ const onSelectDay = evt => {
+ const daysToAdd = evt.target.value;
+ // add selected days to start time to calculate new time
+ const newTime = startTime + daysToAdd * day;
+ onChangeTime(newTime);
+ };
+
+ return (
+
+
Heatmap
+
+ Map showing earthquakes
+
+ from {formatTime(startTime)} to {formatTime(endTime)} .
+
+
+
+ All Days
+ onChangeAllDays(evt.target.checked)}
+ />
+
+
+ Each Day: {formatTime(selectedTime)}
+
+
+
+
+ Data source:{' '}
+
+ earthquakes.geojson
+
+
+
+
+ );
+}
+
+export default React.memo(ControlPanel);
diff --git a/examples/interaction/README.md b/examples/interaction/README.md
index 977186cf..eb993d3b 100644
--- a/examples/interaction/README.md
+++ b/examples/interaction/README.md
@@ -1,7 +1,12 @@
-
-
-
-
-## Example: Interaction
+# Example: Interaction
This example showcases how to toggle/limit user interaction.
+
+## Usage
+
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
diff --git a/examples/interaction/src/app.js b/examples/interaction/src/app.js
index 18466870..3e10d583 100644
--- a/examples/interaction/src/app.js
+++ b/examples/interaction/src/app.js
@@ -1,91 +1,62 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState, useCallback} from 'react';
import {render} from 'react-dom';
-import MapGL, {Marker} from 'react-map-gl';
+import MapGL from 'react-map-gl';
import ControlPanel from './control-panel';
-import bartStations from './bart-station.json';
-
const MAPBOX_TOKEN = ''; // Set your mapbox token here
-import MARKER_STYLE from './marker-style';
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 37.729,
+ longitude: -122.36,
+ zoom: 11,
+ bearing: 0,
+ pitch: 50
+ });
+ const [interactionState, setInteractionState] = useState({});
+ const [settings, setSettings] = useState({
+ dragPan: true,
+ dragRotate: true,
+ scrollZoom: true,
+ touchZoom: true,
+ touchRotate: true,
+ keyboard: true,
+ doubleClickZoom: true,
+ minZoom: 0,
+ maxZoom: 20,
+ minPitch: 0,
+ maxPitch: 85
+ });
-export default class App extends Component {
- state = {
- viewport: {
- latitude: 37.729,
- longitude: -122.36,
- zoom: 11,
- bearing: 0,
- pitch: 50
- },
- interactionState: {},
- settings: {
- dragPan: true,
- dragRotate: true,
- scrollZoom: true,
- touchZoom: true,
- touchRotate: true,
- keyboard: true,
- doubleClickZoom: true,
- minZoom: 0,
- maxZoom: 20,
- minPitch: 0,
- maxPitch: 85
- }
- };
+ const updateSettings = useCallback(
+ (name, value) =>
+ setSettings(s => ({
+ ...s,
+ [name]: value
+ })),
+ []
+ );
- _onViewportChange = viewport => this.setState({viewport});
-
- _onInteractionStateChange = interactionState => this.setState({interactionState});
-
- _onSettingChange = (name, value) =>
- this.setState({
- settings: {...this.state.settings, [name]: value}
- });
-
- _renderMarker(station, i) {
- const {name, coordinates} = station;
- return (
-
-
- {name}
-
-
- );
- }
-
- render() {
- const {viewport, settings, interactionState} = this.state;
-
- return (
+ return (
+ <>
setInteractionState({...s})}
mapboxApiAccessToken={MAPBOX_TOKEN}
- >
-
- {bartStations.map(this._renderMarker)}
-
-
- );
- }
+ />
+
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/interaction/src/bart-station.json b/examples/interaction/src/bart-station.json
deleted file mode 100644
index 0da362a8..00000000
--- a/examples/interaction/src/bart-station.json
+++ /dev/null
@@ -1,46 +0,0 @@
-[
- {"name":"Lafayette (LAFY)","coordinates":[-122.123801,37.893394]},
- {"name":"12th St. Oakland City Center (12TH)","coordinates":[-122.271604,37.803664]},
- {"name":"16th St. Mission (16TH)","coordinates":[-122.419694,37.765062]},
- {"name":"19th St. Oakland (19TH)","coordinates":[-122.269029,37.80787]},
- {"name":"24th St. Mission (24TH)","coordinates":[-122.418466,37.752254]},
- {"name":"Ashby (ASHB)","coordinates":[-122.26978,37.853024]},
- {"name":"Balboa Park (BALB)","coordinates":[-122.447414,37.721981]},
- {"name":"Bay Fair (BAYF)","coordinates":[-122.126871,37.697185]},
- {"name":"Castro Valley (CAST)","coordinates":[-122.075567,37.690754]},
- {"name":"Civic Center/UN Plaza (CIVC)","coordinates":[-122.413756,37.779528]},
- {"name":"Colma (COLM)","coordinates":[-122.466233,37.684638]},
- {"name":"Coliseum/Oakland Airport (COLS)","coordinates":[-122.197273,37.754006]},
- {"name":"Concord (CONC)","coordinates":[-122.029095,37.973737]},
- {"name":"Daly City (DALY)","coordinates":[-122.469081,37.706121]},
- {"name":"Downtown Berkeley (DBRK)","coordinates":[-122.268045,37.869867]},
- {"name":"El Cerrito del Norte (DELN)","coordinates":[-122.317269,37.925655]},
- {"name":"Dublin/Pleasanton (DUBL)","coordinates":[-121.900367,37.701695]},
- {"name":"Embarcadero (EMBR)","coordinates":[-122.396742,37.792976]},
- {"name":"Fremont (FRMT)","coordinates":[-121.9764,37.557355]},
- {"name":"Fruitvale (FTVL)","coordinates":[-122.224274,37.774963]},
- {"name":"Glen Park (GLEN)","coordinates":[-122.434092,37.732921]},
- {"name":"Hayward (HAYW)","coordinates":[-122.087967,37.670399]},
- {"name":"Lake Merritt (LAKE)","coordinates":[-122.265609,37.797484]},
- {"name":"MacArthur (MCAR)","coordinates":[-122.267227,37.828415]},
- {"name":"Millbrae (MLBR)","coordinates":[-122.38666,37.599787]},
- {"name":"Montgomery St. (MONT)","coordinates":[-122.401407,37.789256]},
- {"name":"North Berkeley (NBRK)","coordinates":[-122.283451,37.87404]},
- {"name":"North Concord/Martinez (NCON)","coordinates":[-122.024597,38.003275]},
- {"name":"Orinda (ORIN)","coordinates":[-122.183791,37.878361]},
- {"name":"Pleasant Hill/Contra Costa Centre (PHIL)","coordinates":[-122.056013,37.928403]},
- {"name":"Pittsburg/Bay Point (PITT)","coordinates":[-121.945154,38.018914]},
- {"name":"El Cerrito Plaza (PLZA)","coordinates":[-122.299272,37.903059]},
- {"name":"Powell St. (POWL)","coordinates":[-122.406857,37.784991]},
- {"name":"Richmond (RICH)","coordinates":[-122.353165,37.936887]},
- {"name":"Rockridge (ROCK)","coordinates":[-122.251793,37.844601]},
- {"name":"San Leandro (SANL)","coordinates":[-122.161311,37.722619]},
- {"name":"San Bruno (SBRN)","coordinates":[-122.416038,37.637753]},
- {"name":"San Francisco Int'l Airport (SFIA)","coordinates":[-122.392612,37.616035]},
- {"name":"South Hayward (SHAY)","coordinates":[-122.057551,37.6348]},
- {"name":"South San Francisco (SSAN)","coordinates":[-122.444116,37.664174]},
- {"name":"Union City (UCTY)","coordinates":[-122.017867,37.591208]},
- {"name":"Walnut Creek (WCRK)","coordinates":[-122.067423,37.905628]},
- {"name":"West Dublin/Pleasanton (WDUB)","coordinates":[-121.928099,37.699759]},
- {"name":"West Oakland (WOAK)","coordinates":[-122.294582,37.804675]}
-]
\ No newline at end of file
diff --git a/examples/interaction/src/control-panel.js b/examples/interaction/src/control-panel.js
index 45c784ad..6c7889d1 100644
--- a/examples/interaction/src/control-panel.js
+++ b/examples/interaction/src/control-panel.js
@@ -1,100 +1,88 @@
import * as React from 'react';
-import {PureComponent} from 'react';
const camelPattern = /(^|[A-Z])[a-z]*/g;
+function formatSettingName(name) {
+ return name.match(camelPattern).join(' ');
+}
-export default class ControlPanel extends PureComponent {
- _formatSettingName(name) {
- return name.match(camelPattern).join(' ');
- }
+function Checkbox({name, value, onChange}) {
+ return (
+
+ {formatSettingName(name)}
+ onChange(name, evt.target.checked)} />
+
+ );
+}
- _renderCheckbox(name, value) {
- return (
-
- {this._formatSettingName(name)}
- this.props.onChange(name, evt.target.checked)}
- />
-
- );
- }
+function NumericInput({name, value, onChange}) {
+ return (
+
+ {formatSettingName(name)}
+ onChange(name, Number(evt.target.value))}
+ />
+
+ );
+}
- _renderNumericInput(name, value) {
- return (
-
- {this._formatSettingName(name)}
- this.props.onChange(name, Number(evt.target.value))}
- />
-
- );
- }
+function ControlPanel(props) {
+ const {settings, interactionState, onChange} = props;
- _renderSetting(name, value) {
+ const renderSetting = (name, value) => {
switch (typeof value) {
case 'boolean':
- return this._renderCheckbox(name, value);
+ return
;
case 'number':
- return this._renderNumericInput(name, value);
+ return
;
default:
return null;
}
- }
+ };
+
+ return (
+
+
Limit Map Interaction
+
Turn interactive features off/on.
+
+
+
+ {Object.keys(settings).map(name => renderSetting(name, settings[name]))}
+
+
- _renderInteractionStates({isDragging, isPanning, isRotating, isZooming, inTransition}) {
- return (
Dragging
- {isDragging && 'Yes'}
+ {interactionState.isDragging && 'Yes'}
Transition
- {inTransition && 'Yes'}
+ {interactionState.inTransition && 'Yes'}
Panning
- {isPanning && 'Yes'}
+ {interactionState.isPanning && 'Yes'}
Rotating
- {isRotating && 'Yes'}
+ {interactionState.isRotating && 'Yes'}
Zooming
- {isZooming && 'Yes'}
+ {interactionState.isZooming && 'Yes'}
- );
- }
-
- render() {
- const {settings, interactionState} = this.props;
-
- return (
-
-
Limit Map Interaction
-
Turn interactive features off/on.
-
-
-
- {Object.keys(settings).map(name => this._renderSetting(name, settings[name]))}
-
-
-
- {this._renderInteractionStates(interactionState)}
-
- );
- }
+
+ );
}
+
+export default React.memo(ControlPanel);
diff --git a/examples/interaction/src/marker-style.js b/examples/interaction/src/marker-style.js
deleted file mode 100644
index ab6546eb..00000000
--- a/examples/interaction/src/marker-style.js
+++ /dev/null
@@ -1,30 +0,0 @@
-export default `
-.station:before {
- content: ' ';
- display: inline-block;
- width: 8px;
- height: 8px;
- background: red;
- border-radius: 8px;
- margin: 0 8px;
-}
-.station {
- border-radius: 20px;
- padding-right: 12px;
- margin: -12px;
- color: transparent;
- line-height: 24px;
- font-size: 13px;
- white-space: nowrap;
-}
-.station span {
- display: none;
-}
-.station:hover {
- background: rgba(0,0,0,0.8);
- color: #fff;
-}
-.station:hover span {
- display: inline-block;
-}
-`;
diff --git a/examples/layers/README.md b/examples/layers/README.md
index 8ec6ef0a..405308e9 100644
--- a/examples/layers/README.md
+++ b/examples/layers/README.md
@@ -1,7 +1,12 @@
-
-
-
+# Example: Layers
-## Example: Layers
+This example showcases how to dynamically change layer styles and show/hide layers.
-This example showcases how to dynamically change layer styles and show/hide layers.
\ No newline at end of file
+## Usage
+
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
diff --git a/examples/layers/src/app.js b/examples/layers/src/app.js
index ca04be95..44d8dfcd 100644
--- a/examples/layers/src/app.js
+++ b/examples/layers/src/app.js
@@ -1,46 +1,35 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState} from 'react';
import {render} from 'react-dom';
import MapGL from 'react-map-gl';
import ControlPanel from './control-panel';
const MAPBOX_TOKEN = ''; // Set your mapbox token here
-export default class App extends Component {
- state = {
- mapStyle: '',
- viewport: {
- latitude: 37.805,
- longitude: -122.447,
- zoom: 15.5,
- bearing: 0,
- pitch: 0
- }
- };
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 37.805,
+ longitude: -122.447,
+ zoom: 15.5,
+ bearing: 0,
+ pitch: 0
+ });
+ const [mapStyle, setMapStyle] = useState('');
- _onViewportChange = viewport => this.setState({viewport});
-
- _onStyleChange = mapStyle => this.setState({mapStyle});
-
- render() {
- const {viewport, mapStyle} = this.state;
-
- return (
+ return (
+ <>
-
-
- );
- }
+ />
+
+
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/layers/src/control-panel.js b/examples/layers/src/control-panel.js
index fd185aad..85a772f9 100644
--- a/examples/layers/src/control-panel.js
+++ b/examples/layers/src/control-panel.js
@@ -1,9 +1,10 @@
import * as React from 'react';
-import {PureComponent} from 'react';
+import {useState, useEffect} from 'react';
import {fromJS} from 'immutable';
import MAP_STYLE from '../../map-style-basic-v8.json';
const defaultMapStyle = fromJS(MAP_STYLE);
+const defaultLayers = defaultMapStyle.get('layers');
const categories = ['labels', 'roads', 'buildings', 'parks', 'water', 'background'];
@@ -25,107 +26,87 @@ const colorClass = {
symbol: 'text-color'
};
-export default class StyleControls extends PureComponent {
- constructor(props) {
- super(props);
-
- this._defaultLayers = defaultMapStyle.get('layers');
-
- this.state = {
- visibility: {
- water: true,
- parks: true,
- buildings: true,
- roads: true,
- labels: true,
- background: true
- },
- color: {
- water: '#DBE2E6',
- parks: '#E6EAE9',
- buildings: '#c0c0c8',
- roads: '#ffffff',
- labels: '#78888a',
- background: '#EBF0F0'
+function getMapStyle({visibility, color}) {
+ const layers = defaultLayers
+ .filter(layer => {
+ const id = layer.get('id');
+ return categories.every(name => visibility[name] || !layerSelector[name].test(id));
+ })
+ .map(layer => {
+ const id = layer.get('id');
+ const type = layer.get('type');
+ const category = categories.find(name => layerSelector[name].test(id));
+ if (category && colorClass[type]) {
+ return layer.setIn(['paint', colorClass[type]], color[category]);
}
- };
- }
+ return layer;
+ });
- componentDidMount() {
- this._updateMapStyle(this.state);
- }
-
- _onColorChange(name, event) {
- const color = {...this.state.color, [name]: event.target.value};
- this.setState({color});
- this._updateMapStyle({...this.state, color});
- }
-
- _onVisibilityChange(name, event) {
- const visibility = {
- ...this.state.visibility,
- [name]: event.target.checked
- };
- this.setState({visibility});
- this._updateMapStyle({...this.state, visibility});
- }
-
- _updateMapStyle({visibility, color}) {
- const layers = this._defaultLayers
- .filter(layer => {
- const id = layer.get('id');
- return categories.every(name => visibility[name] || !layerSelector[name].test(id));
- })
- .map(layer => {
- const id = layer.get('id');
- const type = layer.get('type');
- const category = categories.find(name => layerSelector[name].test(id));
- if (category && colorClass[type]) {
- return layer.setIn(['paint', colorClass[type]], color[category]);
- }
- return layer;
- });
-
- this.props.onChange(defaultMapStyle.set('layers', layers));
- }
-
- _renderLayerControl(name) {
- const {visibility, color} = this.state;
-
- return (
-
- {name}
-
-
-
- );
- }
-
- render() {
- return (
-
-
Dynamic Styling
-
Dynamically show/hide map layers and change color with Immutable map style.
-
-
- {categories.map(name => this._renderLayerControl(name))}
-
- );
- }
+ return defaultMapStyle.set('layers', layers);
}
+
+function StyleControls(props) {
+ const [visibility, setVisibility] = useState({
+ water: true,
+ parks: true,
+ buildings: true,
+ roads: true,
+ labels: true,
+ background: true
+ });
+
+ const [color, setColor] = useState({
+ water: '#DBE2E6',
+ parks: '#E6EAE9',
+ buildings: '#c0c0c8',
+ roads: '#ffffff',
+ labels: '#78888a',
+ background: '#EBF0F0'
+ });
+
+ useEffect(() => {
+ props.onChange(getMapStyle({visibility, color}));
+ }, [visibility, color]);
+
+ const onColorChange = (name, value) => {
+ setColor({...color, [name]: value});
+ };
+
+ const onVisibilityChange = (name, value) => {
+ setVisibility({...visibility, [name]: value});
+ };
+
+ return (
+
+
Dynamic Styling
+
Dynamically show/hide map layers and change color with Immutable map style.
+
+
+ {categories.map(name => (
+
+ {name}
+ onVisibilityChange(name, evt.target.checked)}
+ />
+ onColorChange(name, evt.target.value)}
+ />
+
+ ))}
+
+ );
+}
+
+export default React.memo(StyleControls);
diff --git a/examples/locate-user/README.md b/examples/locate-user/README.md
index 9903942c..8a2fda34 100644
--- a/examples/locate-user/README.md
+++ b/examples/locate-user/README.md
@@ -1,12 +1,12 @@
-
-
-
+# Example: Locate User
-## Example: Locate User
+Demonstrates how to automatically locate the user and track their current location with react-map-gl.
-Demonstrates how to locate the user and track its current location with react-map-gl.
+## Usage
-```
- npm install
- npm start
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
```
diff --git a/examples/locate-user/src/app.js b/examples/locate-user/src/app.js
index ef27b17d..fb7b634c 100644
--- a/examples/locate-user/src/app.js
+++ b/examples/locate-user/src/app.js
@@ -1,5 +1,5 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState} from 'react';
import {render} from 'react-dom';
import MapGL, {GeolocateControl} from 'react-map-gl';
@@ -11,40 +11,34 @@ const geolocateStyle = {
left: 0,
margin: 10
};
+const positionOptions = {enableHighAccuracy: true};
-export default class App extends Component {
- state = {
- viewport: {
- latitude: 37.8,
- longitude: 96,
- zoom: 3,
- bearing: 0,
- pitch: 0
- }
- };
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 37.8,
+ longitude: 96,
+ zoom: 3,
+ bearing: 0,
+ pitch: 0
+ });
- _onViewportChange = viewport => this.setState({viewport});
-
- render() {
- const {viewport} = this.state;
-
- return (
-
-
-
- );
- }
+ return (
+
+
+
+ );
}
export function renderToDom(container) {
diff --git a/examples/reuse-map/README.md b/examples/reuse-map/README.md
index 71a79268..32012566 100644
--- a/examples/reuse-map/README.md
+++ b/examples/reuse-map/README.md
@@ -1,7 +1,12 @@
-
-
-
-
-## Example: Reuse Map
+# Example: Reuse Map
This example showcases how to reuse the same map without destroying it.
+
+## Usage
+
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
diff --git a/examples/reuse-map/app.css b/examples/reuse-map/app.css
index fde1682d..e2605e32 100644
--- a/examples/reuse-map/app.css
+++ b/examples/reuse-map/app.css
@@ -7,30 +7,10 @@ body {
height: 100vh;
}
-.control-panel {
- position: absolute;
- top: 0;
- right: 0;
- max-width: 320px;
- background: #fff;
- box-shadow: 0 2px 4px rgba(0,0,0,0.3);
- padding: 12px 24px;
+.toggle-btn {
+ position: fixed;
+ z-index: 1;
margin: 20px;
- font-size: 13px;
- line-height: 2;
- color: #6b6b76;
- text-transform: uppercase;
- outline: none;
-}
-
-label {
- display: inline-block;
- width: 160px;
-}
-
-input {
- margin-left: 20px;
- max-width: 60px;
}
/* marker */
diff --git a/examples/reuse-map/src/app.js b/examples/reuse-map/src/app.js
index 1bacbc78..0a8db09a 100644
--- a/examples/reuse-map/src/app.js
+++ b/examples/reuse-map/src/app.js
@@ -1,47 +1,31 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState} from 'react';
import {render} from 'react-dom';
import BartMap from './bart-map';
const LIGHT_STYLE = 'mapbox://styles/mapbox/light-v9';
const DARK_STYLE = 'mapbox://styles/mapbox/dark-v9';
-export default class App extends Component {
- state = {
- showMap: true,
- mapStyleLight: true
+export default function App() {
+ const [showMap, setShowMap] = useState(true);
+ const [mapStyle, setMapStyle] = useState(LIGHT_STYLE);
+
+ const toggleMap = () => {
+ setShowMap(!showMap);
+
+ if (showMap) {
+ setMapStyle(mapStyle === LIGHT_STYLE ? DARK_STYLE : LIGHT_STYLE);
+ }
};
- _toggleMap() {
- let {showMap, mapStyleLight} = this.state;
-
- showMap = !this.state.showMap;
- if (showMap) {
- mapStyleLight = !mapStyleLight;
- }
-
- this.setState({
- showMap,
- mapStyleLight
- });
- }
-
- render() {
- const {showMap, mapStyleLight} = this.state;
- const mapStyle = mapStyleLight ? LIGHT_STYLE : DARK_STYLE;
- if (showMap) {
- // eslint-disable-next-line no-console, no-undef
- console.warn(mapStyle);
- }
- return (
-
-
- Toggle Map
-
- {showMap && }
-
- );
- }
+ return (
+ <>
+
+ Toggle Map
+
+ {showMap &&
}
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/reuse-map/src/bart-map.js b/examples/reuse-map/src/bart-map.js
index 802e0598..8762a391 100644
--- a/examples/reuse-map/src/bart-map.js
+++ b/examples/reuse-map/src/bart-map.js
@@ -1,54 +1,41 @@
import * as React from 'react';
-import {Component} from 'react';
-import MapGL, {Marker} from '../../../src';
+import {useState} from 'react';
+import MapGL, {Marker} from 'react-map-gl';
import bartStations from '../../.data/bart-station.json';
const MAPBOX_TOKEN = ''; // Set your mapbox token here
-export default class BartMap extends Component {
- state = {
- viewState: {
- latitude: 37.729,
- longitude: -122.36,
- zoom: 11,
- bearing: 0,
- pitch: 50
- }
- };
-
- _onViewportChange = viewState => this.setState({viewState});
+export default function BartMap(props) {
+ const [viewport, setViewport] = useState({
+ latitude: 37.73,
+ longitude: -122.36,
+ zoom: 11,
+ bearing: 0,
+ pitch: 50
+ });
// eslint-disable-next-line
- _onMapLoad = event => console.log(event);
+ const onMapLoad = event => console.log(event);
- _renderMarker(station, i) {
- const {name, coordinates} = station;
- return (
-
-
- {name}
-
-
- );
- }
-
- render() {
- const {mapStyle} = this.props;
- const {viewState} = this.state;
- return (
-
- {bartStations.map(this._renderMarker)}
-
- );
- }
+ return (
+
+ {bartStations.map(({name, coordinates}, i) => (
+
+
+ {name}
+
+
+ ))}
+
+ );
}
diff --git a/examples/viewport-animation/README.md b/examples/viewport-animation/README.md
index c501ee2f..4b9d0f1c 100644
--- a/examples/viewport-animation/README.md
+++ b/examples/viewport-animation/README.md
@@ -1,7 +1,12 @@
-
-
-
-
-## Example: Viewport Animation
+# Example: Viewport Animation
This example showcases how to transition smoothly between one viewport to another.
+
+## Usage
+
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
+```
diff --git a/examples/viewport-animation/src/app.js b/examples/viewport-animation/src/app.js
index 14ca0d7b..7224fe58 100644
--- a/examples/viewport-animation/src/app.js
+++ b/examples/viewport-animation/src/app.js
@@ -1,5 +1,5 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState, useCallback} from 'react';
import {render} from 'react-dom';
import MapGL, {FlyToInterpolator} from 'react-map-gl';
@@ -7,54 +7,39 @@ import ControlPanel from './control-panel';
const MAPBOX_TOKEN = ''; // Set your mapbox token here
-export default class App extends Component {
- state = {
- viewport: {
- latitude: 37.7751,
- longitude: -122.4193,
- zoom: 11,
- bearing: 0,
- pitch: 0
- }
- };
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 37.7751,
+ longitude: -122.4193,
+ zoom: 11,
+ bearing: 0,
+ pitch: 0
+ });
- _onViewportChange = viewport =>
- this.setState({
- viewport: {...this.state.viewport, ...viewport}
- });
-
- _goToViewport = ({longitude, latitude}) => {
- this._onViewportChange({
+ const onSelectCity = useCallback(({longitude, latitude}) => {
+ setViewport({
longitude,
latitude,
zoom: 11,
transitionInterpolator: new FlyToInterpolator({speed: 1.2}),
transitionDuration: 'auto'
});
- };
+ }, []);
- render() {
- const {viewport, settings} = this.state;
-
- return (
-
-
-
-
- );
- }
+ return (
+ <>
+
+
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/viewport-animation/src/control-panel.js b/examples/viewport-animation/src/control-panel.js
index efd41c8b..ff1d3ec7 100644
--- a/examples/viewport-animation/src/control-panel.js
+++ b/examples/viewport-animation/src/control-panel.js
@@ -1,41 +1,36 @@
import * as React from 'react';
-import {PureComponent} from 'react';
import CITIES from '../../.data/cities.json';
-export default class ControlPanel extends PureComponent {
- _renderButton = (city, index) => {
- return (
-
-
this.props.onViewportChange(city)}
- />
-
{city.city}
+function ControlPanel(props) {
+ return (
+
+
Camera Transition
+
Smooth animate of the viewport.
+
- );
- };
+
- render() {
- return (
-
-
Camera Transition
-
Smooth animate of the viewport.
-
-
- View Code ↗
-
+ {CITIES.filter(city => city.state === 'California').map((city, index) => (
+
+ props.onSelectCity(city)}
+ />
+ {city.city}
-
-
- {CITIES.filter(city => city.state === 'California').map(this._renderButton)}
-
- );
- }
+ ))}
+
+ );
}
+
+export default React.memo(ControlPanel);
diff --git a/examples/zoom-to-bounds/README.md b/examples/zoom-to-bounds/README.md
index 120040ec..167d0ebc 100644
--- a/examples/zoom-to-bounds/README.md
+++ b/examples/zoom-to-bounds/README.md
@@ -1,12 +1,12 @@
-
-
-
-
-## Example: Zoom To Bounds
+# Example: Zoom To Bounds
Demonstrates how to zoom to a bounding box with react-map-gl.
-```
- npm install
- npm start
+## Usage
+
+To run this example, you need a [Mapbox token](http://visgl.github.io/react-map-gl/docs/get-started/mapbox-tokens). You can either set it as `MAPBOX_TOKEN` in `src/app.js`, or set a `MapboxAccessToken` environment variable in the command line.
+
+```bash
+npm i
+npm run start
```
diff --git a/examples/zoom-to-bounds/src/app.js b/examples/zoom-to-bounds/src/app.js
index 99675c08..9bc10820 100644
--- a/examples/zoom-to-bounds/src/app.js
+++ b/examples/zoom-to-bounds/src/app.js
@@ -1,5 +1,5 @@
import * as React from 'react';
-import {Component} from 'react';
+import {useState} from 'react';
import {render} from 'react-dom';
import MapGL, {LinearInterpolator, WebMercatorViewport} from 'react-map-gl';
import bbox from '@turf/bbox';
@@ -9,35 +9,23 @@ import MAP_STYLE from './map-style';
const TOKEN = ''; // Set your mapbox token here
-export default class App extends Component {
- constructor(props) {
- super(props);
- this.state = {
- viewport: {
- latitude: 37.785164,
- longitude: -122.4,
- zoom: 11,
- bearing: 0,
- pitch: 0
- },
- popupInfo: null
- };
+export default function App() {
+ const [viewport, setViewport] = useState({
+ latitude: 37.78,
+ longitude: -122.4,
+ zoom: 11,
+ bearing: 0,
+ pitch: 0
+ });
- this._map = React.createRef();
- }
-
- _updateViewport = viewport => {
- this.setState({viewport});
- };
-
- _onClick = event => {
+ const onClick = event => {
const feature = event.features[0];
if (feature) {
// calculate the bounding box of the feature
const [minLng, minLat, maxLng, maxLat] = bbox(feature);
// construct a viewport instance from the current state
- const viewport = new WebMercatorViewport(this.state.viewport);
- const {longitude, latitude, zoom} = viewport.fitBounds(
+ const vp = new WebMercatorViewport(viewport);
+ const {longitude, latitude, zoom} = vp.fitBounds(
[
[minLng, minLat],
[maxLng, maxLat]
@@ -47,40 +35,34 @@ export default class App extends Component {
}
);
- this.setState({
- viewport: {
- ...this.state.viewport,
- longitude,
- latitude,
- zoom,
- transitionInterpolator: new LinearInterpolator({
- around: [event.offsetCenter.x, event.offsetCenter.y]
- }),
- transitionDuration: 1000
- }
+ setViewport({
+ ...viewport,
+ longitude,
+ latitude,
+ zoom,
+ transitionInterpolator: new LinearInterpolator({
+ around: [event.offsetCenter.x, event.offsetCenter.y]
+ }),
+ transitionDuration: 1000
});
}
};
- render() {
- const {viewport} = this.state;
-
- return (
+ return (
+ <>
setViewport(v)}
mapboxApiAccessToken={TOKEN}
- >
-
-
- );
- }
+ />
+
+ >
+ );
}
export function renderToDom(container) {
diff --git a/examples/zoom-to-bounds/src/control-panel.js b/examples/zoom-to-bounds/src/control-panel.js
index 3391a10f..fa059d12 100644
--- a/examples/zoom-to-bounds/src/control-panel.js
+++ b/examples/zoom-to-bounds/src/control-panel.js
@@ -1,21 +1,20 @@
import * as React from 'react';
-import {PureComponent} from 'react';
-export default class ControlPanel extends PureComponent {
- render() {
- return (
-
-
Zoom to Bounding Box
-
Click on a San Fransisco Neighborhood to zoom in.
-
+function ControlPanel() {
+ return (
+
+
Zoom to Bounding Box
+
Click on a San Fransisco Neighborhood to zoom in.
+
- );
- }
+
+ );
}
+
+export default React.memo(ControlPanel);
diff --git a/website/static/style.css b/website/static/style.css
index d93c6a9e..1c19ae0d 100644
--- a/website/static/style.css
+++ b/website/static/style.css
@@ -62,7 +62,7 @@
margin: 24px;
padding: 12px 24px;
position: absolute;
- top: 0;
+ top: 60px;
right: 0;
outline: none;
cursor: auto;