├── .babelrc
├── .gitignore
├── example
├── index.html
├── Checkboxes.js
├── css
│ └── default.css
└── index.js
├── Freedraw.jsx
├── LICENSE
├── package.json
├── README.md
└── Freedraw.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-react", "@babel/preset-env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | .parcel-cache/
13 | dist/
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React-Leaflet-Freedraw examples
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/example/Checkboxes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Checkbox = ({ type = 'checkbox', name, checked = false, onChange }) => (
4 |
5 | );
6 |
7 | const CheckboxContainer = (props) => (
8 | <>
9 | {props.checkboxes.map((item) => (
10 |
11 |
19 |
20 | ))}
21 | >
22 | );
23 |
24 | export default CheckboxContainer;
25 |
--------------------------------------------------------------------------------
/Freedraw.jsx:
--------------------------------------------------------------------------------
1 | import LeafletFreedraw from 'leaflet-freedraw';
2 | import { createLayerComponent } from '@react-leaflet/core';
3 |
4 | function createLeafletElement(props, context) {
5 | const instance = new LeafletFreedraw({ ...props });
6 | return { instance, context: { ...context, overlayContainer: instance } };
7 | }
8 |
9 | function updateLeafletElement(instance, props, prevProps) {
10 | if (props.mode !== prevProps.mode) {
11 | instance.mode(props.mode);
12 | }
13 | }
14 |
15 | const Freedraw = createLayerComponent(
16 | createLeafletElement,
17 | updateLeafletElement
18 | );
19 |
20 | export default Freedraw;
21 |
22 | export * from 'leaflet-freedraw';
23 |
--------------------------------------------------------------------------------
/example/css/default.css:
--------------------------------------------------------------------------------
1 | body,
2 | html {
3 | overflow: hidden;
4 | }
5 |
6 | a {
7 | color: dodgerblue;
8 | }
9 |
10 | .leaflet-container {
11 | height: 400px;
12 | width: 90%;
13 | margin: 0 auto;
14 | }
15 |
16 | path.leaflet-line {
17 | stroke: #50622b;
18 | stroke-width: 2;
19 | }
20 |
21 | div.leaflet-edge {
22 | background-color: #95bc59;
23 | box-shadow: 0 0 0 2px white, 0 0 10px rgba(0, 0, 0, 0.35);
24 | border-radius: 50%;
25 | cursor: move;
26 | outline: none;
27 | transition: background-color 0.25s;
28 | }
29 |
30 | div.leaflet-edge.disabled {
31 | pointer-events: none;
32 | background-color: #bbb;
33 | }
34 |
35 | path.leaflet-polygon {
36 | fill: #b4cd8a;
37 | stroke: #50622b;
38 | stroke-width: 2;
39 | fill-opacity: 0.75;
40 | }
41 |
42 | .map.mode-create {
43 | cursor: crosshair;
44 | }
45 |
46 | .checkboxContainer {
47 | display: flex;
48 | flex-direction: column;
49 | margin: 40px 40px;
50 | }
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Elango Bharathi Dhandapani and contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-leaflet-freedraw",
3 | "version": "3.0.1",
4 | "description": "React Component for freedraw",
5 | "main": "Freedraw.js",
6 | "scripts": {
7 | "start": "babel Freedraw.jsx > Freedraw.js",
8 | "example": "parcel example/index.html"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/elangobharathi/react-leaflet-freedraw.git"
13 | },
14 | "author": "Elango Bharathi Dhandapani",
15 | "license": "MIT",
16 | "keywords": [
17 | "react",
18 | "react-leaflet",
19 | "react-leaflet-v3",
20 | "freedraw",
21 | "leaflet-freedraw",
22 | "react-leaflet-freedraw"
23 | ],
24 | "peerDependencies": {
25 | "leaflet": "^1.3.3",
26 | "react-leaflet": "^3.1.0",
27 | "react": "^17.0.2",
28 | "react-dom": "^17.0.2"
29 | },
30 | "devDependencies": {
31 | "@babel/cli": "^7.13.16",
32 | "@babel/core": "^7.14.2",
33 | "@babel/preset-env": "^7.14.2",
34 | "@babel/preset-react": "^7.13.13",
35 | "parcel": "^2.0.0-beta.2",
36 | "leaflet": "^1.3.3",
37 | "react": "^17.0.2",
38 | "react-dom": "^17.0.2",
39 | "react-leaflet": "^3.1.0"
40 | },
41 | "dependencies": {
42 | "@react-leaflet/core": "^1.0.2",
43 | "leaflet-freedraw": "^2.13.3",
44 | "ramda": "^0.27.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-leaflet-freedraw
2 |
3 | Plugin for [react-leaflet v3](https://github.com/PaulLeCam/react-leaflet) to integrate [Leaflet.FreeDraw](https://github.com/Wildhoney/Leaflet.FreeDraw).
4 |
5 | Please checkout [codesandbox EXAMPLE](https://codesandbox.io/s/react-leaflet-freedraw-example-1fy3l?file=/src/App.js) using this package with some primary use cases.
6 |
7 | ## Install
8 |
9 | `npm install react-leaflet-freedraw --save`
10 |
11 | or
12 |
13 | `yarn add react-leaflet-freedraw`
14 |
15 | Make sure that you have the following peer dependencies installed.
16 |
17 | `npm install leaflet react-leaflet react react-dom --save`
18 |
19 | or
20 |
21 | `yarn add leaflet react-leaflet react react-dom`
22 |
23 | ## Getting started
24 |
25 | Please make sure that you go through [Leaflet.FreeDraw](https://github.com/Wildhoney/Leaflet.FreeDraw) readme before integrating this component.
26 |
27 | You need to wrap this component into MapContainer component and pass the options as shown below.
28 |
29 | ```javascript
30 | import React, { useRef } from 'react';
31 | import { MapContainer } from 'react-leaflet';
32 | import Freedraw, { ALL } from 'react-leaflet-freedraw';
33 |
34 | const Component = () => {
35 | const freedrawRef = useRef(null);
36 |
37 | return (
38 |
39 |
43 | console.log(
44 | 'markers drawn - latLngs',
45 | event.latLngs,
46 | 'Polygons:',
47 | freedrawRef.current.size()
48 | ),
49 | mode: (event) => console.log('mode changed', event),
50 | }}
51 | ref={freedrawRef}
52 | />
53 |
54 | );
55 | };
56 | ```
57 |
58 | It supports all the options mentioned in [Leaflet.FreeDraw](https://github.com/Wildhoney/Leaflet.FreeDraw).
59 |
60 | A detailed example of how to use this componenet is in the [example folder of this repo](https://github.com/elangobharathi/react-leaflet-freedraw/tree/master/example). To run the example,
61 |
62 | 1. Clone this repo
63 | 2. Run `npm i`
64 | 3. Run `npm run example`
65 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | useCallback,
3 | useEffect,
4 | useMemo,
5 | useReducer,
6 | useRef,
7 | } from 'react';
8 | import { render } from 'react-dom';
9 | import { MapContainer, TileLayer } from 'react-leaflet';
10 | import Freedraw, { CREATE, EDIT, DELETE, APPEND, ALL } from '../Freedraw';
11 | import CheckboxContainer from './Checkboxes';
12 |
13 | const intialState = [
14 | {
15 | id: 'create',
16 | label: 'Create',
17 | mode: CREATE,
18 | isChecked: true,
19 | },
20 | {
21 | id: 'edit',
22 | label: 'Edit Polygons',
23 | mode: EDIT,
24 | isChecked: true,
25 | },
26 | {
27 | id: 'attach-elbows',
28 | label: 'Attach Elbows',
29 | mode: APPEND,
30 | isChecked: true,
31 | },
32 | {
33 | id: 'delete',
34 | label: 'Delete',
35 | mode: DELETE,
36 | isChecked: true,
37 | },
38 | ];
39 |
40 | function reducer(state = intialState, event) {
41 | return state.map((control) => {
42 | if (control.id === event.target.name) {
43 | return {
44 | ...control,
45 | isChecked: event.target.checked,
46 | };
47 | }
48 | return {
49 | ...control,
50 | };
51 | });
52 | }
53 |
54 | function Example() {
55 | const [state, dispatch] = useReducer(reducer, intialState);
56 | const freedrawRef = useRef(null);
57 |
58 | const handleMarkersDraw = useCallback(
59 | (event) =>
60 | console.log(
61 | 'markers drawn - latLngs',
62 | event.latLngs,
63 | 'Polygons:',
64 | freedrawRef.current.size()
65 | ),
66 | []
67 | );
68 | const handleModeChange = useCallback(
69 | (event) => console.log('mode changed', event),
70 | []
71 | );
72 |
73 | const handlers = useMemo(
74 | () => ({
75 | markers: handleMarkersDraw,
76 | mode: handleModeChange,
77 | }),
78 | [handleMarkersDraw, handleModeChange]
79 | );
80 |
81 | const handleEscapeKey = useCallback((event) => {
82 | // Cancel the current FreeDraw action when the escape key is pressed.
83 | if (event.key === 'Escape') {
84 | freedrawRef.current.cancel();
85 | }
86 | }, []);
87 |
88 | useEffect(() => {
89 | window.addEventListener('keydown', handleEscapeKey);
90 | return () => window.removeEventListener('keydown', handleEscapeKey);
91 | }, [handleEscapeKey]);
92 |
93 | const mode = state.reduce((result, current) => {
94 | if (current.isChecked) {
95 | return result | current.mode;
96 | } else {
97 | return result ^ current.mode;
98 | }
99 | }, ALL);
100 |
101 | return (
102 |
103 |
109 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | );
120 | }
121 |
122 | render(, document.getElementById('app'));
123 |
--------------------------------------------------------------------------------
/Freedraw.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | var _exportNames = {};
9 | exports["default"] = void 0;
10 |
11 | var _leafletFreedraw = _interopRequireWildcard(require("leaflet-freedraw"));
12 |
13 | Object.keys(_leafletFreedraw).forEach(function (key) {
14 | if (key === "default" || key === "__esModule") return;
15 | if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
16 | if (key in exports && exports[key] === _leafletFreedraw[key]) return;
17 | Object.defineProperty(exports, key, {
18 | enumerable: true,
19 | get: function get() {
20 | return _leafletFreedraw[key];
21 | }
22 | });
23 | });
24 |
25 | var _core = require("@react-leaflet/core");
26 |
27 | function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
28 |
29 | function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
30 |
31 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
32 |
33 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
34 |
35 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
36 |
37 | function createLeafletElement(props, context) {
38 | var instance = new _leafletFreedraw["default"](_objectSpread({}, props));
39 | return {
40 | instance: instance,
41 | context: _objectSpread(_objectSpread({}, context), {}, {
42 | overlayContainer: instance
43 | })
44 | };
45 | }
46 |
47 | function updateLeafletElement(instance, props, prevProps) {
48 | if (props.mode !== prevProps.mode) {
49 | instance.mode(props.mode);
50 | }
51 | }
52 |
53 | var Freedraw = (0, _core.createLayerComponent)(createLeafletElement, updateLeafletElement);
54 | var _default = Freedraw;
55 | exports["default"] = _default;
56 |
57 |
--------------------------------------------------------------------------------