From 26749bf7aa4b58894cffb0cec383adef86cd1ea5 Mon Sep 17 00:00:00 2001 From: Tom Fenech Date: Wed, 16 Oct 2019 11:10:26 +0200 Subject: [PATCH] Add SVGOverlay component --- docs/components.md | 12 +++++ docs/examples.md | 1 + example/components/app.js | 3 ++ example/components/svg-overlay.js | 23 +++++++++ src/SVGOverlay.js | 86 +++++++++++++++++++++++++++++++ src/index.js | 1 + src/types.js | 19 +++++++ 7 files changed, 145 insertions(+) create mode 100644 example/components/svg-overlay.js create mode 100644 src/SVGOverlay.js diff --git a/docs/components.md b/docs/components.md index 3f2a59a5..0662cecd 100644 --- a/docs/components.md +++ b/docs/components.md @@ -32,6 +32,7 @@ You can check out the [event handling example](https://github.com/PaulLeCam/reac - [Vector Layers](#vector-layers) - [Circle](#circle) - [CircleMarker](#circlemarker) + - [SVGOverlay](#svgoverlay) - [Polyline](#polyline) - [Polygon](#polygon) - [Rectangle](#rectangle) @@ -319,6 +320,17 @@ properties. - `radius: number` (optional) - `attribution: string` (optional) +### SVGOverlay + +[🍃 Leaflet reference](https://leafletjs.com/reference-1.5.0.html#svgoverlay) • [🔍 Source](https://github.com/PaulLeCam/react-leaflet/blob/master/src/SVGOverlay.js) + +**Dynamic properties** + +- `bounds: bounds` (required) +- `opacity: number` (optional) +- `zIndex: number` (optional) +- `attribution: string` (optional) + ### Polyline [🍃 Leaflet reference](http://leafletjs.com/reference-1.5.0.html#polyline) • [🔍 Source](https://github.com/PaulLeCam/react-leaflet/blob/master/src/Polyline.js) diff --git a/docs/examples.md b/docs/examples.md index 872fd239..69e506c9 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -9,6 +9,7 @@ Different examples are available in the [example folder](https://github.com/Paul - [Event handling](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/events.js) - [Viewport usage](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/viewport.js) - [Vector layers (Rectangle, Circle, etc.)](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/vector-layers.js) +- [SVG Overlay](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/svg-overlay.js) - [Other layers (LayerGroup, FeatureGroup)](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/other-layers.js) - [Tooltips](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/tooltip.js) - [Custom zoom control](https://github.com/PaulLeCam/react-leaflet/blob/master/example/components/zoom-control.js) diff --git a/example/components/app.js b/example/components/app.js index dbbbd726..47b28edb 100644 --- a/example/components/app.js +++ b/example/components/app.js @@ -20,6 +20,7 @@ import PaneExample from './pane' import WMSTileLayerExample from './wms-tile-layer' import VideoOverlayExample from './video-overlay' import CustomIcons from './custom-icons' +import SVGOverlayExample from './svg-overlay' Leaflet.Icon.Default.imagePath = '//cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.4/images/' @@ -37,6 +38,8 @@ const App = () => (

Vector layers

+

SVG Overlay

+

Other layers

GeoJSON with Popup

diff --git a/example/components/svg-overlay.js b/example/components/svg-overlay.js new file mode 100644 index 00000000..9f342d15 --- /dev/null +++ b/example/components/svg-overlay.js @@ -0,0 +1,23 @@ +// @flow + +import React, { Component } from 'react' +import { Map, SVGOverlay } from '../../src' + +const center = [51.505, -0.09] +const rectangle = [[51.49, -0.08], [51.5, -0.06]] + +export default class SVGOverlayExample extends Component<{}> { + render() { + return ( + + + + + + text + + + + ) + } +} diff --git a/src/SVGOverlay.js b/src/SVGOverlay.js new file mode 100644 index 00000000..721785bf --- /dev/null +++ b/src/SVGOverlay.js @@ -0,0 +1,86 @@ +// @flow + +import { Layer, SVGOverlay as LeafletSVGOverlay } from 'leaflet' +import { createPortal } from 'react-dom' + +import type { LeafletContext, SVGOverlayProps } from './types' +import { withLeaflet } from './context' +import MapComponent from './MapComponent' + +type LeafletElement = LeafletSVGOverlay +type Props = SVGOverlayProps + +export class SVGOverlay extends MapComponent { + contextValue: ?LeafletContext + leafletElement: LeafletElement + container: ?Element + + constructor(props: Props) { + super(props) + this.leafletElement = this.createLeafletElement(props) + } + + get layerContainer(): Layer { + return this.props.leaflet.layerContainer || this.props.leaflet.map + } + + createLeafletElement(_props: Props): LeafletElement { + this.container = document.createElementNS( + 'http://www.w3.org/2000/svg', + 'svg', + ) + return new LeafletSVGOverlay( + this.container, + _props.bounds, + this.getOptions(_props), + ) + } + + updateLeafletElement(_fromProps: Props, _toProps: Props) { + if (_toProps.bounds !== _fromProps.bounds) { + this.leafletElement.setBounds(_toProps.bounds) + } + if (_toProps.opacity !== _fromProps.opacity) { + this.leafletElement.setOpacity(_toProps.opacity) + } + if (_toProps.zIndex !== _fromProps.zIndex) { + this.leafletElement.setZIndex(_toProps.zIndex) + } + } + + componentDidMount() { + super.componentDidMount() + this.layerContainer.addLayer(this.leafletElement) + } + + componentDidUpdate(prevProps: Props) { + super.componentDidUpdate(prevProps) + + if (this.props.attribution !== prevProps.attribution) { + const { map } = this.props.leaflet + if (map != null && map.attributionControl != null) { + map.attributionControl.removeAttribution(prevProps.attribution) + map.attributionControl.addAttribution(this.props.attribution) + } + } + + this.updateLeafletElement(prevProps, this.props) + } + + componentWillUnmount() { + super.componentWillUnmount() + this.layerContainer.removeLayer(this.leafletElement) + this.container = null + } + + render() { + const { children } = this.props + if (children == null || this.container == null) { + return null + } + + return createPortal(children, this.container) + } +} + +export default withLeaflet(SVGOverlay) diff --git a/src/index.js b/src/index.js index dba08c52..085ce39d 100644 --- a/src/index.js +++ b/src/index.js @@ -46,6 +46,7 @@ export { default as Polyline } from './Polyline' export { default as Popup } from './Popup' export { default as Rectangle } from './Rectangle' export { default as ScaleControl } from './ScaleControl' +export { default as SVGOverlay } from './SVGOverlay' export { default as TileLayer } from './TileLayer' export { default as Tooltip } from './Tooltip' export { default as VideoOverlay } from './VideoOverlay' diff --git a/src/types.js b/src/types.js index f53eabb2..8114d262 100644 --- a/src/types.js +++ b/src/types.js @@ -92,6 +92,19 @@ export type DivOverlayOptions = { onOpen?: () => void, } +export type CrossOrigin = boolean | string + +export type ImageOverlayOptions = { + opacity?: number, + alt?: string, + interactive?: boolean, + attribution?: string, + crossOrigin?: CrossOrigin, + errorOverlayUrl?: string, + zIndex?: number, + className?: string, +} + export type LeafletProps = { leaflet: LeafletContext } export type MapControlProps = { @@ -111,3 +124,9 @@ export type MapLayerProps = { export type GridLayerProps = MapLayerProps & GridLayerOptions export type PathProps = MapLayerProps & PathOptions + +export type SVGOverlayProps = MapComponentProps & + ImageOverlayOptions & { + bounds: LatLngBounds, + children?: Node, + }