简体   繁体   English

Leaflet JS map 上的数据未正确显示

[英]Data on Leaflet JS map not showing up correctly

I am building a Corona Virus tracker in React which displays data on a Choropleth Leaflet Map.我正在 React 中构建一个 Corona Virus 跟踪器,它显示 Choropleth Leaflet Map 上的数据。 I have a data.json file which contains polygon data to draw the borders for this map.我有一个 data.json 文件,其中包含用于绘制此 map 边界的多边形数据。 The idea is, add COVID data from an API to this data.json file, return this object, and pass it as a prop in the map component.想法是,将来自 API 的 COVID 数据添加到此 data.json 文件中,返回此 object,并将其作为 Z1D78DC8ED51244 组件中的 prop 传递。 In the map component, the countryLoad function is executed onEach feature in the GeoJSON component in the map.在 map 组件中,countryLoad function 对 map 中 GeoJSON 组件中的每个特征执行。 This displays the COVID data with each country colour coded based on the number of COVID cases.这会根据 COVID 病例的数量显示每个国家/地区颜色编码的 COVID 数据。 The problem is, sometimes the data doesn't load correctly and the map shows up as grey.问题是,有时数据无法正确加载,map 显示为灰色。

I have tried a number of things including adding a timeout which has made it work 80% of the time but it still doesn't work at times.我已经尝试了很多事情,包括添加一个超时,这使它在 80% 的时间内都可以工作,但有时它仍然无法工作。

World.js file: World.js 文件:

import React, { useState, useEffect } from "react";
import "./App.css";
import {
    Card,
    CardContent,
} from "@material-ui/core";

import Table from "./Table";
import { sortData} from "./Helper";
import Map from "./Map";
import { features } from "./data/countries.json";
import "leaflet/dist/leaflet.css";

const World = () => {

    const [countries, setCountries] = useState([]);
    const [mapCountries, setMapCountries] = useState([]);
    const [tableData, setTableData] = useState([]);
    const [casesType, setCasesType] = useState("cases");
    const [mapZoom, setMapZoom] = useState(3);
     
    
    

    const attachCovidData = () => {   //Attach covid data to newFeatures
        const newFeatures = [];

        for (let i = 0; i < features.length; i++) {
            newFeatures.push(features[i]);
        }

        for (let i = 0; i < newFeatures.length; i++) {
            const featureCountry = newFeatures[i];
            featureCountry.cases = 0;
            featureCountry.casesText = "";
            const covidCountry = tableData.find(
                (country) =>
                    country.countryInfo.iso3 === featureCountry.properties.ISO_A3
            );
            if (covidCountry != null) {
                let cases = covidCountry.cases;
                let deaths = covidCountry.deaths;
                featureCountry.cases = cases;
                featureCountry.opacityLevel = 0;
                if (featureCountry.cases < 50000) {
                    featureCountry.opacityLevel = 0.1;
                } else if (featureCountry.cases < 50000) {
                    featureCountry.opacityLevel = 0.2;
                } else if (
                    featureCountry.cases >= 50000 &&
                    featureCountry.cases < 100000
                ) {
                    featureCountry.opacityLevel = 0.3;
                } else if (
                    featureCountry.cases >= 100000 &&
                    featureCountry.cases < 250000
                ) {
                    featureCountry.opacityLevel = 0.4;
                } else if (
                    featureCountry.cases >= 250000 &&
                    featureCountry.cases < 500000
                ) {
                    featureCountry.opacityLevel = 0.5;
                } else if (
                    featureCountry.cases >= 500000 &&
                    featureCountry.cases < 1000000
                ) {
                    featureCountry.opacityLevel = 0.6;
                } else {
                    featureCountry.opacityLevel = 1;
                }
                featureCountry.deaths = deaths;
                featureCountry.casesText = "";
            }
        }
        console.log(newFeatures);
        return newFeatures;
    };



    useEffect(() => {
        const getCountriesData = async () => {
            fetch("https://disease.sh/v3/covid-19/countries")   // Get covid data
                .then((response) => response.json())
                .then((data) => {
                    const countries = data.map((country) => ({
                        name: country.country,
                        value: country.countryInfo.iso2,
                    }));
                    let sortedData = sortData(data);
                    setCountries(countries);

                    setMapCountries(data);
                    setTableData(sortedData);
                });
        };

        getCountriesData();
    }, []);



    return (
        <div className="app">
            <div className="app__left">
                <div className="app__header">
                    <h1>World Overview</h1>
                </div>
                <Map
                    countries={mapCountries}
                    casesType={casesType}
                    center={{ lat: 34.80746, lng: -40.4796 }}
                    zoom={mapZoom}
                    newFeatures={attachCovidData()}
                />
            </div>
            <Card style = {{marginTop: '50px'}} className="app__right">
                <CardContent>
                    <div className="app__information">
                        <h3>Total Cases</h3>
                        <Table countries={tableData} />
                    </div>
                </CardContent>
            </Card>
        </div>
    );
};

export default World;

Map.js file Map.js 文件

import React, { useState, useEffect } from "react";
import { MapContainer as LeafletMap, TileLayer, GeoJSON } from "react-leaflet";
import "./Map.css";
import "leaflet/dist/leaflet.css";

function Map({ countries, center, zoom, newFeatures }) {
    const [loadedMap, setLoadedMap] = useState(false);
    useEffect(() => {
        setTimeout(() => {
            setLoadedMap(true);
        }, 1000);
    }, []);
    
    const countryLoad= (country, layer) => {
        
            const name = country.properties.ADMIN;
            const confirmedCases = country.cases;
            const confirmedCasesCommas = confirmedCases
                .toString()
                .replace(/\B(?=(\d{3})+(?!\d))/g, ",");

            const confirmedDeaths = country.deaths;
            const opacityLevel = country.opacityLevel;
            console.log(confirmedCases);
            layer.options.fillColor = `rgba(0,0,255, ${country.opacityLevel}`;
            layer.bindPopup(`${name} ${confirmedCasesCommas} `);
        
    
    };
    console.log(newFeatures);

    const map = (
        <div className="map">
            <LeafletMap center={center} zoom={zoom}>
                <TileLayer
                    url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                    attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                />
                <GeoJSON
                    data={newFeatures}
                    style={{ weight: 0.7 }}
                    onEachFeature={countryLoad}
                />
            </LeafletMap>
            {console.log(countries)}
        </div>
    );


    
    

    return loadedMap?map:null;
}

export default Map;

The problem seems to be with rendering before getting the actual data from the endpoint.问题似乎在于从端点获取实际数据之前的渲染。

You will need to move the const [loadedMap, setLoadedMap] = useState(false);您需要移动const [loadedMap, setLoadedMap] = useState(false); logic to the World component and set the flag to true only after the endpoint has returned the data.逻辑到World组件并仅在端点返回数据后将标志设置为true

So wrap the map rendering ( in World component ) with所以包装 map 渲染(World组件中

{Boolean(mapCountries.length) && (<Map
    countries = { mapCountries }
    casesType = { casesType }
    center = {{ lat: 34.80746, lng: -40.4796 }}
    zoom = { mapZoom }
    newFeatures = { attachCovidData() }
/>)}

and remove the whole loadedMap from the Map component并从loadedMap组件中删除整个加载Map

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM