mirror of
https://github.com/visgl/react-map-gl.git
synced 2026-01-18 15:54:22 +00:00
Add draw control example (#868)
This commit is contained in:
parent
515c575687
commit
f3752f68d1
12
examples/draw-polygon/README.md
Normal file
12
examples/draw-polygon/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
<div align="center">
|
||||
<img src="https://avatars3.githubusercontent.com/u/2105791?v=3&s=200" />
|
||||
</div>
|
||||
|
||||
## 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
|
||||
```
|
||||
21
examples/draw-polygon/app.css
Normal file
21
examples/draw-polygon/app.css
Normal file
@ -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;
|
||||
}
|
||||
17
examples/draw-polygon/index.html
Normal file
17
examples/draw-polygon/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8' />
|
||||
<title>react-map-gl Example</title>
|
||||
<link rel="stylesheet" type="text/css" href="app.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<!--use mapbox button icon css-->
|
||||
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.css" type="text/css">
|
||||
<script src='app.js'></script>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
App.renderToDom(document.getElementById('map'));
|
||||
</script>
|
||||
</html>
|
||||
27
examples/draw-polygon/package.json
Normal file
27
examples/draw-polygon/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
123
examples/draw-polygon/src/app.js
Normal file
123
examples/draw-polygon/src/app.js
Normal file
@ -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 (
|
||||
<div className="mapboxgl-ctrl-top-right">
|
||||
<div className="mapboxgl-ctrl-group mapboxgl-ctrl">
|
||||
<button
|
||||
className="mapbox-gl-draw_ctrl-draw-btn mapbox-gl-draw_polygon"
|
||||
title="Polygon tool (p)"
|
||||
onClick={() => this.setState({mode: EditorModes.DRAW_POLYGON})}
|
||||
/>
|
||||
<button
|
||||
className="mapbox-gl-draw_ctrl-draw-btn mapbox-gl-draw_trash"
|
||||
title="Delete"
|
||||
onClick={this._onDelete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
_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 <ControlPanel polygon={polygon} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {viewport, mode, selectedFeatureId, features} = this.state;
|
||||
return (
|
||||
<MapGL
|
||||
{...viewport}
|
||||
ref={_ => (this._mapRef = _)}
|
||||
width="100%"
|
||||
height="100%"
|
||||
mapStyle="mapbox://styles/mapbox/satellite-v9"
|
||||
mapboxApiAccessToken={TOKEN}
|
||||
onViewportChange={this._updateViewport}
|
||||
>
|
||||
<Editor
|
||||
style={{width: '100%', height: '100%'}}
|
||||
clickRadius={12}
|
||||
mode={mode}
|
||||
features={features}
|
||||
selectedFeatureId={selectedFeatureId}
|
||||
onSelect={this._onSelect}
|
||||
onUpdate={this._onUpdate}
|
||||
getEditHandleShape={'circle'}
|
||||
getFeatureStyle={getFeatureStyle}
|
||||
getEditHandleStyle={getEditHandleStyle}
|
||||
/>
|
||||
{this._renderDrawTools()}
|
||||
{this._renderControlPanel()}
|
||||
</MapGL>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function renderToDom(container) {
|
||||
render(<App />, container);
|
||||
}
|
||||
30
examples/draw-polygon/src/control-panel.js
Normal file
30
examples/draw-polygon/src/control-panel.js
Normal file
@ -0,0 +1,30 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import area from '@turf/area';
|
||||
const defaultContainer = ({children}) => (
|
||||
<div className="mapboxgl-ctrl-top-left control-panel">{children}</div>
|
||||
);
|
||||
|
||||
export default class ControlPanel extends PureComponent {
|
||||
render() {
|
||||
const Container = this.props.containerComponent || defaultContainer;
|
||||
const polygon = this.props.polygon;
|
||||
const polygonArea = polygon && area(polygon);
|
||||
return (
|
||||
<Container>
|
||||
<h3>Draw Polygon</h3>
|
||||
{polygon && (
|
||||
<p>
|
||||
{polygonArea} <br />
|
||||
square meters
|
||||
</p>
|
||||
)}
|
||||
<a
|
||||
href="https://github.com/uber/react-map-gl/tree/master/examples/draw-polygon"
|
||||
target="_new"
|
||||
>
|
||||
View Code ↗
|
||||
</a>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
49
examples/draw-polygon/src/style.js
Normal file
49
examples/draw-polygon/src/style.js
Normal file
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
51
examples/draw-polygon/webpack.config.js
Normal file
51
examples/draw-polygon/webpack.config.js
Normal file
@ -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;
|
||||
@ -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
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user