diff --git a/examples/draw-polygon/README.md b/examples/draw-polygon/README.md
new file mode 100644
index 00000000..294fff64
--- /dev/null
+++ b/examples/draw-polygon/README.md
@@ -0,0 +1,12 @@
+
+

+
+
+## Example: Draw Polygon
+
+Demonstrates how to use [`react-map-gl-draw`](https://github.com/uber/nebula.gl/tree/master/modules/react-map-gl-draw) to draw polygons with react-map-gl.
+
+```
+ yarn
+ yarn start-local
+```
diff --git a/examples/draw-polygon/app.css b/examples/draw-polygon/app.css
new file mode 100644
index 00000000..bc6d19b7
--- /dev/null
+++ b/examples/draw-polygon/app.css
@@ -0,0 +1,21 @@
+body {
+ margin: 0;
+ background: #000;
+}
+#map {
+ width: 100vw;
+ height: 100vh;
+}
+
+.control-panel {
+ max-width: 320px;
+ background: #fff;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.3);
+ padding: 12px 24px;
+ margin: 20px;
+ font-size: 13px;
+ line-height: 2;
+ color: #6b6b76;
+ text-transform: uppercase;
+ outline: none;
+}
diff --git a/examples/draw-polygon/index.html b/examples/draw-polygon/index.html
new file mode 100644
index 00000000..3506f5a3
--- /dev/null
+++ b/examples/draw-polygon/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+ react-map-gl Example
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/draw-polygon/package.json b/examples/draw-polygon/package.json
new file mode 100644
index 00000000..e4f6d66a
--- /dev/null
+++ b/examples/draw-polygon/package.json
@@ -0,0 +1,27 @@
+{
+ "scripts": {
+ "start": "webpack-dev-server --progress --hot --open",
+ "start-local": "webpack-dev-server --env.local --progress --hot --open"
+ },
+ "dependencies": {
+ "react": "^16.3.0",
+ "react-dom": "^16.3.0",
+ "react-map-gl": "^5.0.0",
+ "react-map-gl-draw": "^0.14.9",
+ "styled-components": "^4.3.2",
+ "@turf/area": "^6.0.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.0.0",
+ "@babel/preset-env": "^7.0.0",
+ "@babel/preset-react": "^7.0.0",
+ "babel-loader": "^8.0.0",
+ "webpack": "^4.20.0",
+ "webpack-cli": "^3.1.2",
+ "webpack-dev-server": "^3.1.0"
+ },
+ "resolutions": {
+ "@turf/difference": "6.0.1"
+ }
+}
diff --git a/examples/draw-polygon/src/app.js b/examples/draw-polygon/src/app.js
new file mode 100644
index 00000000..000de4a0
--- /dev/null
+++ b/examples/draw-polygon/src/app.js
@@ -0,0 +1,123 @@
+import React, {Component} from 'react';
+import {render} from 'react-dom';
+import MapGL from 'react-map-gl';
+import {Editor, EditorModes} from 'react-map-gl-draw';
+
+import ControlPanel from './control-panel';
+import {getFeatureStyle, getEditHandleStyle} from './style';
+
+const TOKEN = ''; // Set your mapbox token here
+
+export default class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ viewport: {
+ longitude: -91.874,
+ latitude: 42.76,
+ zoom: 12
+ },
+ mode: EditorModes.READ_ONLY,
+ features: [],
+ selectedFeatureId: null
+ };
+ this._mapRef = null;
+ }
+
+ _updateViewport = viewport => {
+ this.setState({viewport});
+ };
+
+ _onSelect = ({selectedFeatureId}) => {
+ this.setState({selectedFeatureId});
+ };
+
+ _onDelete = () => {
+ const selectedIndex = this._getSelectedFeatureIndex();
+ if (selectedIndex >= 0) {
+ const newFeatures = [...this.state.features];
+ newFeatures.splice(selectedIndex, 1);
+ this.setState({features: newFeatures, selectedFeatureId: null});
+ }
+ };
+
+ _onUpdate = features => {
+ this.setState({
+ features,
+ mode: EditorModes.EDITING
+ });
+ };
+
+ _getSelectedFeatureIndex = () => {
+ const {selectedFeatureId} = this.state;
+ if (selectedFeatureId === null || selectedFeatureId === undefined) {
+ return -1;
+ }
+
+ return this.state.features.findIndex(f => f.properties.id === selectedFeatureId);
+ };
+
+ _renderDrawTools = () => {
+ // copy from mapbox
+ return (
+
+
+
+
+ );
+ };
+
+ _renderControlPanel = () => {
+ const features = this.state.features;
+ let featureIndex = this._getSelectedFeatureIndex();
+ if (featureIndex < 0) {
+ featureIndex = features.length - 1;
+ }
+ const polygon = features && features.length ? features[featureIndex] : null;
+ return ;
+ };
+
+ render() {
+ const {viewport, mode, selectedFeatureId, features} = this.state;
+ return (
+ (this._mapRef = _)}
+ width="100%"
+ height="100%"
+ mapStyle="mapbox://styles/mapbox/satellite-v9"
+ mapboxApiAccessToken={TOKEN}
+ onViewportChange={this._updateViewport}
+ >
+
+ {this._renderDrawTools()}
+ {this._renderControlPanel()}
+
+ );
+ }
+}
+
+export function renderToDom(container) {
+ render(, container);
+}
diff --git a/examples/draw-polygon/src/control-panel.js b/examples/draw-polygon/src/control-panel.js
new file mode 100644
index 00000000..3f067fd6
--- /dev/null
+++ b/examples/draw-polygon/src/control-panel.js
@@ -0,0 +1,30 @@
+import React, {PureComponent} from 'react';
+import area from '@turf/area';
+const defaultContainer = ({children}) => (
+ {children}
+);
+
+export default class ControlPanel extends PureComponent {
+ render() {
+ const Container = this.props.containerComponent || defaultContainer;
+ const polygon = this.props.polygon;
+ const polygonArea = polygon && area(polygon);
+ return (
+
+ Draw Polygon
+ {polygon && (
+
+ {polygonArea}
+ square meters
+
+ )}
+
+ View Code ↗
+
+
+ );
+ }
+}
diff --git a/examples/draw-polygon/src/style.js b/examples/draw-polygon/src/style.js
new file mode 100644
index 00000000..8a73c0cf
--- /dev/null
+++ b/examples/draw-polygon/src/style.js
@@ -0,0 +1,49 @@
+import {RenderStates} from 'react-map-gl-draw';
+
+export function getEditHandleStyle({feature, state}) {
+ switch (state) {
+ case RenderStates.SELECTED:
+ case RenderStates.HOVERED:
+ case RenderStates.UNCOMMITTED:
+ return {
+ fill: 'rgb(251, 176, 59)',
+ fillOpacity: 1,
+ stroke: 'rgb(255, 255, 255)',
+ strokeWidth: 2,
+ r: 7
+ };
+
+ default:
+ return {
+ fill: 'rgb(251, 176, 59)',
+ fillOpacity: 1,
+ stroke: 'rgb(255, 255, 255)',
+ strokeWidth: 2,
+ r: 5
+ };
+ }
+}
+
+export function getFeatureStyle({feature, index, state}) {
+ switch (state) {
+ case RenderStates.SELECTED:
+ case RenderStates.HOVERED:
+ case RenderStates.UNCOMMITTED:
+ case RenderStates.CLOSING:
+ return {
+ stroke: 'rgb(251, 176, 59)',
+ strokeWidth: 2,
+ fill: 'rgb(251, 176, 59)',
+ fillOpacity: 0.3,
+ strokeDasharray: '4,2'
+ };
+
+ default:
+ return {
+ stroke: 'rgb(60, 178, 208)',
+ strokeWidth: 2,
+ fill: 'rgb(60, 178, 208)',
+ fillOpacity: 0.1
+ };
+ }
+}
diff --git a/examples/draw-polygon/webpack.config.js b/examples/draw-polygon/webpack.config.js
new file mode 100644
index 00000000..015eabd7
--- /dev/null
+++ b/examples/draw-polygon/webpack.config.js
@@ -0,0 +1,51 @@
+// NOTE: To use this example standalone (e.g. outside of repo)
+// delete the local development overrides at the bottom of this file
+
+// avoid destructuring for older Node version support
+const resolve = require('path').resolve;
+const webpack = require('webpack');
+
+const BABEL_CONFIG = {
+ presets: ['@babel/env', '@babel/react'],
+ plugins: ['@babel/proposal-class-properties']
+};
+
+const config = {
+ mode: 'development',
+
+ entry: {
+ app: resolve('./src/app.js')
+ },
+
+ devServer: {
+ contentBase: [resolve(__dirname), resolve(__dirname, './static')]
+ },
+
+ output: {
+ library: 'App'
+ },
+
+ module: {
+ rules: [
+ {
+ // Compile ES2015 using babel
+ test: /\.js$/,
+ include: [resolve('.')],
+ exclude: [/node_modules/],
+ use: [
+ {
+ loader: 'babel-loader',
+ options: BABEL_CONFIG
+ }
+ ]
+ }
+ ]
+ },
+
+ // Optional: Enables reading mapbox token from environment variable
+ plugins: [new webpack.EnvironmentPlugin(['MapboxAccessToken'])]
+};
+
+// Enables bundling against src in this repo rather than the installed version
+module.exports = env =>
+ env && env.local ? require('../webpack.config.local')(config)(env) : config;
diff --git a/examples/main/constants/toc.js b/examples/main/constants/toc.js
index 1e434ad4..396d3184 100644
--- a/examples/main/constants/toc.js
+++ b/examples/main/constants/toc.js
@@ -18,6 +18,7 @@ import Layers from '../../layers/src/app';
import ViewportAnimation from '../../viewport-animation/src/app';
import ZoomToBounds from '../../zoom-to-bounds/src/app';
import Heatmap from '../../heatmap/src/app';
+import DrawPolygon from '../../draw-polygon/src/app';
export const BASIC_EXAMPLES = 'basicExamples';
export const STANDALONE_EXAMPLES = 'standalonExamples';
@@ -85,6 +86,11 @@ export const standaloneExamples = [
path: 'heatmap',
name: 'Heatmap',
component: Heatmap
+ },
+ {
+ path: 'drawPolygon',
+ name: 'DrawPolygon',
+ component: DrawPolygon
}
];