React-leaflet: SVGOverlay component

Created on 1 Oct 2019  路  7Comments  路  Source: PaulLeCam/react-leaflet

Hi, I notice that this library doesn't contain a component for Leaflet's SVGOverlay. I made one for my own project - it's written in TypeScript but it would be fairly easy to port to JS/Flow and open a PR if you're interested.

To begin with, I tried to inherit from MapLayer, but I decided in the end that I preferred to render the svg container in the component, and inherit from MapComponent instead.

Happy to open a PR if you like, but as a starting point I'll leave the TS code here.

import { LatLngBounds, SVGOverlay as LeafletSVGOverlay } from "leaflet";
import React from "react";

import {
  LayerContainer,
  LeafletContext,
  LeafletProvider,
  MapComponent,
  MapLayerProps,
  withLeaflet
} from "react-leaflet";

type Props = {
  attribution?: string;
  bounds: LatLngBounds;
  opacity?: number;
  zIndex?: number;
} & MapLayerProps;

class SVGOverlay extends MapComponent<Props, LeafletSVGOverlay> {
  leafletElement: LeafletSVGOverlay;
  private container: SVGSVGElement;
  private contextValue: LeafletContext;

  constructor(props: Props) {
    super(props);
    this.bindContainer = this.bindContainer.bind(this);
  }

  get layerContainer(): LayerContainer {
    return this.props.leaflet.layerContainer;
  }

  createLeafletElement(props: Props) {
    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() {
    this.leafletElement = this.createLeafletElement(this.props);
    this.layerContainer.addLayer(this.leafletElement, "");

    this.contextValue = { ...this.props.leaflet, popupContainer: this.leafletElement };

    super.componentDidMount();
  }

  componentDidUpdate(prevProps: Props, prevState: {}) {
    super.componentDidUpdate(prevProps, prevState);

    this.updateLeafletElement(prevProps, this.props);
  }

  componentWillUnmount() {
    super.componentWillUnmount();
    this.layerContainer.removeLayer(this.leafletElement);
  }

  render() {
    const { children } = this.props;

    return (
      <svg ref={this.bindContainer}>
        {this.contextValue == null ? (
          <>{children}</>
        ) : (
          <LeafletProvider value={this.contextValue}>{children}</LeafletProvider>
        )}
      </svg>
    );
  }

  private bindContainer(ref: SVGSVGElement) {
    this.container = ref;
  }
}

export default withLeaflet<Props>(SVGOverlay);

All 7 comments

Hi, yes opening a PR for it would be nice, thanks!
If you open a PR, could you please include an example and the documentation for the added component?

I'm actually running into an issue with the component now: if it is unmounted before the map, I get a DOMException: "Node was not found". If I manage to fix the problem I'll open a PR!

I realised what I was doing wrong: rendering the svg with React and then passing it to Leaflet meant that both libraries were trying to take control of the same element. I just opened a pull request!

Now available in v2.5.0 thanks to your PR!

~This is still missing from the docs~, looks like it has docs but https://react-leaflet.js.org needs updating if I hadn't found this I would have ended up reimplementing it myself.

Sorry I forgot to sync the website docs, it's been fixed now.

Hi @fenech

I'm using this component and so far it is very useful!! But.. I'd really appreciate you look into this issues:

  1. https://github.com/PaulLeCam/react-leaflet/issues/761
  2. The className attribute does not update its value on re-render when it depends on a prop.
    Meaning... it does not work when you want to change it dynamically. (I've already tested my code on a regular div and it worked, so there's something wrong with SVGOverlay component).
Was this page helpful?
0 / 5 - 0 ratings