├── .babelrc ├── .gitignore ├── LICENSE ├── package.json ├── div-icon.js ├── README.md └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015", 5 | "stage-0" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Joel 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-leaflet-div-icon", 3 | "version": "1.1.0", 4 | "description": "marker that will use children as the content if the marker.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "babel div-icon.js > index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/jgimbel/react-leaflet-div-icon.git" 13 | }, 14 | "author": "Joel Gimbel ", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/jgimbel/react-leaflet-div-icon/issues" 18 | }, 19 | "homepage": "https://github.com/jgimbel/react-leaflet-div-icon#readme", 20 | "devDependencies": { 21 | "babel-cli": "^6.9.0", 22 | "babel-preset-es2015": "^6.9.0", 23 | "babel-preset-react": "^6.23.0", 24 | "babel-preset-stage-0": "^6.5.0" 25 | }, 26 | "peerDependencies": { 27 | "leaflet": "^1.3.0", 28 | "react": "^0.14.0 || ^15.0.0 || ^16.0.0-rc", 29 | "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0-rc", 30 | "react-leaflet": "^2.0.0" 31 | }, 32 | "dependencies": { 33 | "prop-types": "^15.5.10" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /div-icon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { DivIcon, marker } from 'leaflet'; 4 | import { MapLayer, withLeaflet, LeafletProvider } from 'react-leaflet'; 5 | import PropTypes from 'prop-types'; 6 | 7 | export class Divicon extends MapLayer { 8 | static propTypes = { 9 | opacity: PropTypes.number, 10 | zIndexOffset: PropTypes.number, 11 | } 12 | 13 | constructor(props){ 14 | super(props) 15 | super.componentDidMount(); 16 | } 17 | 18 | // See https://github.com/PaulLeCam/react-leaflet/issues/275 19 | createLeafletElement(newProps) { 20 | const { map: _map, layerContainer: _lc, position, ...props } = newProps; 21 | this.icon = new DivIcon(props); 22 | const m = marker(position, { icon: this.icon, ...props }); 23 | this.contextValue = { ...props.leaflet, popupContainer: m } 24 | return m 25 | } 26 | 27 | updateLeafletElement(fromProps, toProps) { 28 | if (toProps.position !== fromProps.position) { 29 | this.leafletElement.setLatLng(toProps.position); 30 | } 31 | if (toProps.zIndexOffset !== fromProps.zIndexOffset) { 32 | this.leafletElement.setZIndexOffset(toProps.zIndexOffset); 33 | } 34 | if (toProps.opacity !== fromProps.opacity) { 35 | this.leafletElement.setOpacity(toProps.opacity); 36 | } 37 | if (toProps.draggable !== fromProps.draggable) { 38 | if (toProps.draggable) { 39 | this.leafletElement.dragging.enable(); 40 | } 41 | else { 42 | this.leafletElement.dragging.disable(); 43 | } 44 | } 45 | } 46 | 47 | componentDidUpdate(fromProps) { 48 | this.updateLeafletElement(fromProps, this.props); 49 | } 50 | 51 | render() { 52 | const container = this.leafletElement._icon; 53 | if (container) { 54 | return ReactDOM.createPortal( 55 | {this.props.children} 56 | , container) 57 | } 58 | else { 59 | return null 60 | } 61 | } 62 | } 63 | 64 | export default withLeaflet(Divicon) 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-leaflet-div-icon 2 | This extends the L.DivIcon class for react-leaflet. It allows a user to render some jsx onto the map, and control its position via the `position` prop. 3 | 4 | ##Installation 5 | 6 | ```sh 7 | npm install --save react-leaflet-div-icon 8 | ``` 9 | 10 | ##Options 11 | 12 | props are pass directly to [DivIcon](http://leafletjs.com/reference.html#divicon) and [Marker](http://leafletjs.com/reference.html#marker). 13 | 14 | ##Usage 15 | 16 | make sure to edit the default `.leaflet-div-icon` class from its default back border, white background when using this. 17 | ```js 18 | import React, { Component } from 'react'; 19 | import { Map, TileLayer, Marker, Popup } from 'react-leaflet'; 20 | import DivIcon from 'react-leaflet-div-icon'; 21 | export default class UserLocationExample extends Component { 22 | constructor() { 23 | super(); 24 | this.mapRef = React.createRef() 25 | this.state = { 26 | hasLocation: false, 27 | latlng: { 28 | lat: 51.505, 29 | lng: -0.09, 30 | }, 31 | }; 32 | } 33 | 34 | handleClick = () => { 35 | this.mapRef.current.leafletElement.locate(); 36 | } 37 | 38 | handleLocationFound = (e) => { 39 | this.setState({ 40 | hasLocation: true, 41 | latlng: e.latlng, 42 | }); 43 | } 44 | 45 | render() { 46 | const marker = this.state.hasLocation 47 | ? ( 48 | 49 | 51 | 52 | 53 | 54 | ) 55 | : null; 56 | 57 | return ( 58 | this.handleClick()} 62 | onLocationfound={(e) => this.handleLocationFound(e)} 63 | ref={this.mapRef} 64 | zoom={13}> 65 | 69 | {marker} 70 | 71 | ); 72 | } 73 | } 74 | 75 | ``` 76 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.Divicon = undefined; 7 | 8 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 9 | 10 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 11 | 12 | var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; 13 | 14 | var _react = require('react'); 15 | 16 | var _react2 = _interopRequireDefault(_react); 17 | 18 | var _reactDom = require('react-dom'); 19 | 20 | var _reactDom2 = _interopRequireDefault(_reactDom); 21 | 22 | var _leaflet = require('leaflet'); 23 | 24 | var _reactLeaflet = require('react-leaflet'); 25 | 26 | var _propTypes = require('prop-types'); 27 | 28 | var _propTypes2 = _interopRequireDefault(_propTypes); 29 | 30 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 31 | 32 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 33 | 34 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 35 | 36 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 37 | 38 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 39 | 40 | var Divicon = exports.Divicon = function (_MapLayer) { 41 | _inherits(Divicon, _MapLayer); 42 | 43 | function Divicon(props) { 44 | _classCallCheck(this, Divicon); 45 | 46 | var _this = _possibleConstructorReturn(this, (Divicon.__proto__ || Object.getPrototypeOf(Divicon)).call(this, props)); 47 | 48 | _get(Divicon.prototype.__proto__ || Object.getPrototypeOf(Divicon.prototype), 'componentDidMount', _this).call(_this); 49 | return _this; 50 | } 51 | 52 | // See https://github.com/PaulLeCam/react-leaflet/issues/275 53 | 54 | 55 | _createClass(Divicon, [{ 56 | key: 'createLeafletElement', 57 | value: function createLeafletElement(newProps) { 58 | var _map = newProps.map, 59 | _lc = newProps.layerContainer, 60 | position = newProps.position, 61 | props = _objectWithoutProperties(newProps, ['map', 'layerContainer', 'position']); 62 | 63 | this.icon = new _leaflet.DivIcon(props); 64 | var m = (0, _leaflet.marker)(position, _extends({ icon: this.icon }, props)); 65 | this.contextValue = _extends({}, props.leaflet, { popupContainer: m }); 66 | return m; 67 | } 68 | }, { 69 | key: 'updateLeafletElement', 70 | value: function updateLeafletElement(fromProps, toProps) { 71 | if (toProps.position !== fromProps.position) { 72 | this.leafletElement.setLatLng(toProps.position); 73 | } 74 | if (toProps.zIndexOffset !== fromProps.zIndexOffset) { 75 | this.leafletElement.setZIndexOffset(toProps.zIndexOffset); 76 | } 77 | if (toProps.opacity !== fromProps.opacity) { 78 | this.leafletElement.setOpacity(toProps.opacity); 79 | } 80 | if (toProps.draggable !== fromProps.draggable) { 81 | if (toProps.draggable) { 82 | this.leafletElement.dragging.enable(); 83 | } else { 84 | this.leafletElement.dragging.disable(); 85 | } 86 | } 87 | } 88 | }, { 89 | key: 'componentDidUpdate', 90 | value: function componentDidUpdate(fromProps) { 91 | this.updateLeafletElement(fromProps, this.props); 92 | } 93 | }, { 94 | key: 'render', 95 | value: function render() { 96 | var container = this.leafletElement._icon; 97 | if (container) { 98 | return _reactDom2.default.createPortal(_react2.default.createElement( 99 | _reactLeaflet.LeafletProvider, 100 | { value: this.contextValue }, 101 | this.props.children 102 | ), container); 103 | } else { 104 | return null; 105 | } 106 | } 107 | }]); 108 | 109 | return Divicon; 110 | }(_reactLeaflet.MapLayer); 111 | 112 | Divicon.propTypes = { 113 | opacity: _propTypes2.default.number, 114 | zIndexOffset: _propTypes2.default.number 115 | }; 116 | exports.default = (0, _reactLeaflet.withLeaflet)(Divicon); 117 | 118 | --------------------------------------------------------------------------------