How to use leaflet-polylinedecorator in react 16.4

2019-07-30 13:22发布

问题:

I'm trying to use the leaflet plugin polylinedecorator in react 16.4.1 (so without hooks). However, the only example I have been able to find on how to use this plugin in react is using hooks (see: How to use polylinedacorator with react leaflet), and I am unsure how I can adapt this to be able to use it in my code.

What I have so far is this polylinedecorator component:

import React, { Component } from "react";
import { Polyline } from "react-leaflet";
import L from "leaflet";
import "leaflet-polylinedecorator";

export default class PolylineDecorator extends Component {
  componentDidUpdate() {
    if (this.props.map) {
        const polyline = L.polyline(this.props.positions).addTo(this.props.map);

        L.polylineDecorator(polyline, {
            patterns: [
                {
                  offset: "100%",
                  repeat: 0,
                  symbol: L.Symbol.arrowHead({
                    pixelSize: 15,
                    polygon: false,
                    pathOptions: { stroke: true }
                  })
                }
              ]
        }).addTo(this.props.map);
    }
  }

  render() {
    return <></>;
  }
}

That I am using like this:

import React, { Component } from "react";
import { Polyline, LayerGroup } from "react-leaflet";
import PolylineDecorator from "./PolylineDecorator";

export default class RouteLayer extends Component {
  render() {
    const { beginLocations } = this.props;
    const locations = [];
    const differentLocations: [];

    beginLocations.forEach((location, index) => {
      // some filtering going on here and pushing the locations to one of the 
         two arrays (locations, differentLocations)
    });

    return (
      <LayerGroup>
        <PolylineDecorator
          map={this.props.map}
          positions={locations}
          color="#4e5c8d"
          interactive={false}
        />
        <PolylineDecorator
          map={this.props.map}
          positions={differentFloorLinesLocations}
          color="red"
          interactive={false}
        />
      </LayerGroup>
    );
  }
}

The RouteLayer is nested inside the map as follows (for simplicity some components are left out):

 <LeafletMap
     ref={r => {
       this.map = r;
       if (this.props.setRefMap) {
         this.props.setRefMap(r);
       }
     }}>
     <RouteLayer
        map={this.map ? this.map.leafletElement : null}
        locations={locations}
      />
 </LeafletMap>

Right now the polylines are drawn, however not quite as expected since the filtering doesn't seem to work (this filtering worked fine when I was just using polylines without the decorator). The arrows I am trying to decorate the lines with are showing up, so that's good. However, I'm not happy with how the PolylineDecorator class is looking right now, this doesn't seem like the correct way to do this. I'm also unsure if it is correct to pass the reference to the map in the way that I'm doing here. Any suggestions on how to make this work correctly are appreciated.

回答1:

For React version < 16.8 the following component demonstrates how to integrate L.polylineDecorator with React-Leaflet:

import React, { Component } from "react";
import { Polyline, withLeaflet } from "react-leaflet";
import L from "leaflet";
import "leaflet-polylinedecorator";

class PolylineDecorator extends Component {
  constructor(props) {
    super(props);
    this.polyRef = React.createRef();
  }
  componentDidMount() {
    const polyline = this.polyRef.current.leafletElement; //get native Leaflet polyline
    const { map } = this.polyRef.current.props.leaflet; //get native Leaflet map

    L.polylineDecorator(polyline, {
      patterns: this.props.patterns
    }).addTo(map);
  }

  render() {
    return <Polyline ref={this.polyRef} {...this.props} />;
  }
}

export default withLeaflet(PolylineDecorator);

Usage

export default class MyMap extends Component {
  render() {
    const { center, zoom } = this.props;

    const polyline = [[57, -19], [60, -12]];

    const arrow = [
      {
        offset: "100%",
        repeat: 0,
        symbol: L.Symbol.arrowHead({
          pixelSize: 15,
          polygon: false,
          pathOptions: { stroke: true }
        })
      }
    ];

    return (
      <Map center={center} zoom={zoom}>
        <TileLayer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png" />
        <PolylineDecorator patterns={arrow} positions={polyline} />
      </Map>
    );
  }
}

Here is a demo