最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I force leaflet to update the map? - Stack Overflow

programmeradmin0浏览0评论

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 ponent
        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 pliant 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" }} />
        )
    },

    ponentDidMount : 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 ponentDidUpdate where I basically would do map.remove(), but then I run into scoping issues between the different ponents.. It's all loaded in ponentDidMount and if you call the leaflet map again it will say it's already initialized.

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 ponent
        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 pliant 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" }} />
        )
    },

    ponentDidMount : 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 ponentDidUpdate where I basically would do map.remove(), but then I run into scoping issues between the different ponents.. It's all loaded in ponentDidMount and if you call the leaflet map again it will say it's already initialized.

Share Improve this question asked Mar 21, 2017 at 11:46 cbllcbll 7,28929 gold badges79 silver badges124 bronze badges 1
  • 1 try to use React-Leaflet that will make the management of react life cycles and the map easier github./PaulLeCam/react-leaflet But as a possible solution direction in your case you should clearLayers on each new data update in ponentWillReceiveProps(nextProps) { if (nextProps.data !== this.props.data) { youMapRef.clearLayers(); } } – Alex Parij Commented Mar 21, 2017 at 13:25
Add a ment  | 

1 Answer 1

Reset to default 3

To extend my ment. 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.

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


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


  ponentDidUpdate(prevProps,prevState) {
      if (prevProps.data !== this.props.data) {
          this.map.addData(geojsonData);
       }
   }
发布评论

评论列表(0)

  1. 暂无评论