From f3752f68d17a0c3ee6ec23bcae7455e5eafdea8a Mon Sep 17 00:00:00 2001 From: Xintong Xia Date: Sun, 18 Aug 2019 17:15:30 -0700 Subject: [PATCH] Add draw control example (#868) --- examples/draw-polygon/README.md | 12 ++ examples/draw-polygon/app.css | 21 ++++ examples/draw-polygon/index.html | 17 +++ examples/draw-polygon/package.json | 27 +++++ examples/draw-polygon/src/app.js | 123 +++++++++++++++++++++ examples/draw-polygon/src/control-panel.js | 30 +++++ examples/draw-polygon/src/style.js | 49 ++++++++ examples/draw-polygon/webpack.config.js | 51 +++++++++ examples/main/constants/toc.js | 6 + 9 files changed, 336 insertions(+) create mode 100644 examples/draw-polygon/README.md create mode 100644 examples/draw-polygon/app.css create mode 100644 examples/draw-polygon/index.html create mode 100644 examples/draw-polygon/package.json create mode 100644 examples/draw-polygon/src/app.js create mode 100644 examples/draw-polygon/src/control-panel.js create mode 100644 examples/draw-polygon/src/style.js create mode 100644 examples/draw-polygon/webpack.config.js 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 } ];