How do I force leaflet to update the map?

2019-05-24 03:15发布

问题:

I'm running into issues as I am using Leaflet together with React, the issue being that Leaflet wants to control the DOM rendering as well, as far as I've researched.

Right now, the countries will correctly be colored with the specific color code corresponding with the backend information(range of 1-->100). However, it is updated every minute. Upon update, the country color will not change. It will however if you hover the mouse over a given country, which is a bit weird.

Here's my source code:

import React from 'react';
import L from 'leaflet';
import countries from './countries.js';


var Worldmap = React.createClass({

    render: function() {

        if(!this.props.data)
            return <div> loading world map ..  </div>;

        let dataratio = this.props.data; // Props from main component
        let size = Object.keys(dataratio).length; // Do we have data?

        if(size > 1) { // If we do have data, ..

            let dataratioToArr = Object.keys(dataratio).map(data => [ data, dataratio[data]]); // Conv. map to multidimensional array

            let featuresArr = countries.features; // array of all countries in array features from countries.js

            for(let i = 0; i < featuresArr.length; i++) // i = 178(no. of countries)
                for(let j = 0; j < dataratioToArr.length; j++) // j = no. of countries we have with dataratio > 1 from backend
                    if(dataratioToArr[j][0] == featuresArr[i].id) // If ISO-3 compliant ID of country(f.e. "USA") matches, push a "data" property to countries.js
                        featuresArr[i].properties.data = dataratioToArr[j][1];
        }

        return(
            <div id="leafletmap" style={{width: "100%", height: "80%", border: "2px solid black" }} />
        )
    },

    componentDidMount : function() {
        let geolocation =  [];
        // Retrieve geoloc coordinates
        navigator.geolocation.getCurrentPosition(function(position) {
            let lat = position.coords.latitude;
            let lon = position.coords.longitude;

            if(lat != null && lon != null) // If we can get latitude and longitude, reset geolocation and push values.
                geolocation.length = 0;
            geolocation.push(lat, lon);
            if(!lat || !lon) // If we can't get latitude or longitude, set a default value.
                geolocation = [0,0];

            let map = L.map('leafletmap').setView(geolocation, 3); // ([coordinates], zoomlevel)

            let info = L.control();

            info.onAdd = function (map) {
                this._div = L.DomUtil.create('div', 'info');
                this.update();
                return this._div;
            };

            info.update = function (props) {
                this._div.innerHTML = '<h4>Data ratio</h4>' +  (props ?
                    '<b>' + props.name + '</b><br />' + props.data + ' ratio'
                        : 'Hover over a country');
            };

            info.addTo(map);


            function getColor(d) {
                return d > 90 ? '#4a1486' :
                    d > 75  ? '#6a51a3' :
                        d > 50  ? '#807dba' :
                            d > 25  ? '#9e9ac8' :
                                d > 15   ? '#bcbddc' :
                                    d > 5   ? '#dadaeb' :
                                        d > 1   ? '#f2f0f7' :
                                            '#D3D3D3'; // Default color of data doesn't exist or is 0.
            }


            function style(feature) {
                return {
                    weight: 2,
                    opacity: 1,
                    color: 'white',
                    fillOpacity: 1,
                    fillColor: getColor(feature.properties.data)
                };
            }

            function highlightFeature(e) {
                let layer = e.target;

                layer.setStyle({
                    weight: 5,
                    color: '#666',
                    fillOpacity: 0.7
                });

                if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
                    layer.bringToFront();
                }

                info.update(layer.feature.properties);
            }

            let geojson;

            function resetHighlight(e) {
                geojson.resetStyle(e.target);
                info.update();
            }

            function zoomToFeature(e) {
                map.fitBounds(e.target.getBounds());
            }

            function onEachFeature(feature, layer) {
                layer.on({
                    mouseover: highlightFeature,
                    mouseout: resetHighlight,
                    click: zoomToFeature
                });
            }


            geojson = L.geoJson(countries, { // from import
                style: style,
                onEachFeature: onEachFeature
            }).addTo(map);

            let legend = L.control({position: 'bottomright'});

            legend.onAdd = function (map) {

                let div = L.DomUtil.create('div', 'info legend'),
                    grades = [1, 5, 15, 25, 50, 75, 90],
                    labels = [],
                    from, to;

                for (let i = 0; i < grades.length; i++) {
                    from = grades[i];
                    to = grades[i + 1];

                    labels.push(
                        '<i style="background:' + getColor(from + 1) + '"></i> ' +
                        from + (to ? '&ndash;' + to : '+'));
                }

                div.innerHTML = labels.join('<br>');
                return div;
            };

            legend.addTo(map);
        });

    }
});

export default Worldmap

How do I force leaflet to redraw or refresh the map upon a new this.props.data being received?

I tried using componentDidUpdate where I basically would do map.remove(), but then I run into scoping issues between the different components.. It's all loaded in componentDidMount and if you call the leaflet map again it will say it's already initialized.

回答1:

To extend my comment. You need to clear the layer and and re-add data to your map. It's possible that in your case you will need to change how you access the map and geojson processing but I'm giving you the general solution here.

   componentDidMount(){
      var map = this.map = L.map('leafletmap');
   } 


   componentWillReceiveProps(nextProps) {
      if (nextProps.data !== this.props.data) {
       this.map.clearLayers();
      }
   } 


  componentDidUpdate(prevProps,prevState) {
      if (prevProps.data !== this.props.data) {
          this.map.addData(geojsonData);
       }
   }