0

我使用 disease.sh API 和 Globe.gl 制作了 covid-19 数据可视化。

我努力解决性能问题,几分钟后屏幕冻结。

我在 google 上查看了 PageSeppe Insights,上面写着“减少第三方代码的影响第三方代码阻塞了主线程 25,690 毫秒”

它是globe.gl,免费图书馆。 https://unpkg.com/globe.gl@2.22.3/dist/globe.gl.min.js

如果有人给我建议以改进我,我将不胜感激。

var mycData = null;
var nowMode = "Active";
var myWorld = null;

window.onload = function() {
  //covid API data
  var url = 'https://disease.sh/v3/covid-19/countries?yesterday=yesterday';
  fetch(url)
  .then(function (data) {
    return data.json();
  })
  .then(function (cData) {

    mycData = cData;
    //Vaccination InformationGet!
    url = 'https://disease.sh/v3/covid-19/vaccine/coverage/countries?lastdays=2&fullData=true';
    fetch(url)
    .then(function (data) {
      return data.json();
    })
    .then(function (cData) {
      for(var i=0;i<mycData.length;i++){
        //console.log(mycData[i]);
        for(var ii=0;ii<cData.length;ii++){
          var Country = cData[ii].country;
          var VaccinationCount = cData[ii].timeline[0].total;
          if(Country == mycData[i].country){
            //console.log(Country + " => " + VaccinationCount);
            mycData[i].vaccination = VaccinationCount;
          }
        }
      }
      makeMap(mycData);
    });
  });
};

// document.getElementById("cases").addEventListener('click', function(){
//   nowMode = "Cases";
//   document.getElementById("CasesColor").style.display ="block";
//   document.getElementById("VaccinationColor").style.display ="none";
//   makeMap(mycData);
// });
document.getElementById("active").addEventListener('click', function(){
  nowMode = "Active";
  document.getElementById("CasesColor").style.display ="block";
  document.getElementById("VaccinationColor").style.display ="none";
  makeMap(mycData);
});

document.getElementById("vaccination").addEventListener('click', function(){
  nowMode = "Vaccination";
  document.getElementById("CasesColor").style.display ="none";
  document.getElementById("VaccinationColor").style.display ="block";
  makeMap(mycData);
});

function makeMap(cData){
  const colorScale = d3.scaleSequentialSqrt(d3.interpolateYlOrRd);
  const getVal = feat => feat.properties.GDP_MD_EST / Math.max(1e5, feat.properties.POP_EST);

  fetch('https://raw.githubusercontent.com/vasturiano/globe.gl/master/example/datasets/ne_110m_admin_0_countries.geojson').then(res => res.json()).then(countries =>

  // fetch('js/countries.geojson').then(res => res.json()).then(countries =>

  {
    const maxVal = Math.max(...countries.features.map(getVal));
    colorScale.domain([0, maxVal]);

    //adding api data to properties match with ISO_A2
    //adjusting data which is not matched, data for -99
    for(var i=0;i<countries.features.length;i++){

      switch(countries.features[i].properties.ADMIN){
        case "France":
          countries.features[i].properties.ISO_A2 = "FR";
          break;
        case "Norway":
          countries.features[i].properties.ISO_A2 = "NO";
          break;
        case "Somaliland":
          countries.features[i].properties.ISO_A2 = "SO";
          break;
        case "Turkmenistan":
          countries.features[i].properties.ISO_A2 = "TR";
          break;
      }

      var cExists = false;
      //insert data into array
      for(var ii=0;ii<cData.length;ii++){
        if(countries.features[i].properties.ISO_A2 == cData[ii].countryInfo.iso2){
          cExists = true;
          var c_data = cData[ii];
          countries.features[i].properties["flag"] = c_data.countryInfo.flag; // flag
          countries.features[i].properties["cases"]          = c_data.cases;
          countries.features[i].properties["deaths"]         = c_data.deaths;
          countries.features[i].properties["recovered"]      = c_data.recovered;
          countries.features[i].properties["active"]         = c_data.active;
          countries.features[i].properties["casesPerOneMillion"] = c_data.casesPerOneMillion;
          countries.features[i].properties["vaccination"] = c_data.vaccination;


          switch(nowMode){
            // case "Cases":
            //   countries.features[i].properties["bgColor"]   = getColor(c_data.cases);
            //   break;
            case "Active":
              countries.features[i].properties["bgColor"]   = getColor(c_data.active);
              break;
            case "Vaccination":
              countries.features[i].properties["bgColor"]   = getColorVaccination(c_data.vaccination);
              break;
          }
        }
      }
    }

    if(myWorld != null) myWorld = null;
    myWorld = Globe()
      .globeImageUrl('https://unpkg.com/three-globe@2.18.1/example/img/earth-night.jpg')
      .backgroundColor('#232946')
      .lineHoverPrecision(0)
      .polygonsData(countries.features.filter(d => d.properties.ISO_A2 !== 'AQ'))
      .polygonAltitude(0.06)
      .polygonCapColor(d =>  d.properties.bgColor)
      .polygonSideColor(() => 'rgba(255, 215, 0, 0.15)') //shadow to globe
      .polygonStrokeColor(() => '#111')
      .polygonLabel(({ properties: d }) => `
      <div class="info-board">
      <span class="flag"><img src="${d.flag}" class="flag"></span>
      <span class="country">${d.ADMIN}</span>
      <hr class="hr-info">
      <div class="info-title-top">Active: ${d.deaths.toLocaleString()} </div>
      <div class="info-title">Total Cases: ${d.cases.toLocaleString()} </div>
      <div class="info-title">Total Recovered: ${d.recovered.toLocaleString()} </div>
      <div class="info-title">Total Deaths: ${d.deaths.toLocaleString()} </div>
      <div class="info-title">Cases Per Million: ${d.casesPerOneMillion.toLocaleString()}</div>
      <hr class="hr-info2">
      <div class="info-title-v">Vaccination: ${d.vaccination.toLocaleString()}</div>
      </div>
    `)

 // (${d.ISO_A2}) if add iso_a2 code to display

      .onPolygonHover(hoverD => myWorld
      .polygonAltitude(d => d === hoverD ? 0.15 : 0.06) //hover height
        //.polygonCapColor(d => d === hoverD ? '#edfaef' : colorScale(getVal(d))) // hover color
      )

      // .polygonsTransitionDuration(3000)

      // .showGlobe(true)


    (document.getElementById('globeViz'))

     // Add auto-rotation
     myWorld.controls().autoRotate = false;
     myWorld.controls().autoRotateSpeed = 0.3;

      // responsive
      window.addEventListener('resize', (event) => {
      myWorld.width([event.target.innerWidth])
      myWorld.height([event.target.innerHeight])
      });

  });
}


function getColor(d) {
    return d > 10000000 ? '#800026' :
            d > 5000000 ? '#BD0026' :
            d > 1000000 ? '#E31A1C' :
            d >  500000 ? '#FC4E2A' :
            d >  100000 ? '#FD8D3C' :
            d >   50000 ? '#FEB24C' :
            d >   10000 ? '#FED976' :
                           '#FFEDA0';
  }


function getColorVaccination(d) {
  return d > 10000000 ? '#084081' :
         d > 5000000 ? '#0868ac' :
         d > 1000000 ? '#2b8cbe' :
         d > 500000 ? '#4eb3d3' :
         d > 100000 ? '#7bccc4' :
         d > 50000 ? '#a8ddb5' :
         d > 10000 ? '#ccebc5' :
         '#e0f3db';
}
html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
html,
body {
  /* z-index: 999; */
  margin: 0;
  padding: 0;
  background: #232946;
  overflow: hidden;
  height: 100%;
  font-family: 'Space Mono', monospace !important;
}

h1 {
  font-weight: 700;
  font-size: 34px;
  margin-top:10px;
  margin-bottom:0px;
  color:#fff;
}

@media only screen and (min-width: 600px) and (max-width: 992px) {
  h1 {
    font-weight: 700;
    font-size: 28px;
    margin-top:40px;
    }
}

@media only screen and (max-width: 599px) {
  h1 {
    font-weight: 600;
    font-size: 20px;
    margin-top:40px;
    }
}


h3 {
  font-weight: 500;
  font-size: 26px;
  margin-top:3px;
  margin-bottom:0px;
  color:#fff;
}


p {
  margin-bottom: 10px;
  color:#fff;
}

hr{
border: 1px solid rgba(153, 153, 153, 0.1);
}

section {
  position: absolute;
  top: 2%;
  text-align: center;
  width: 100%;
  color: rgba(255, 255, 255, 1.0);
  z-index: 999;
}

@media only screen and (max-width: 992px) {
  section {
    position: absolute;
    top: 0%;
    text-align: center;
    width: 100%;
    color: rgba(255, 255, 255, 1.0);
    z-index: 99;
  }
}


section2 {
  position: absolute;
  top: 20%;
  padding: 0 20px;
  max-width: 300px;
  width: 100%;
  color: rgba(255, 255, 255, 1.0);
  line-height: 1.5;
  z-index: 99;
}

@media only screen and (max-width: 992px) {
  section2 {
    position: absolute;
    top: 15%;
    left:15%;
    padding: 0 20px;
    width: 100%;
    color: rgba(255, 255, 255, 1.0);
    z-index: 1;
    }
}


section3 {
  position: absolute;
  bottom: 3%;
  padding: 0 20px;
  max-width: 400px;
  width: 100%;
  color: rgba(255, 255, 255, 1.0);
  z-index: 99;
  line-height: 1.5;
}

@media only screen and (max-width: 992px) {
  section3 {
    display:none;
    }
}



#globeViz{
  margin-top: 30px;
}

.list{
 margin-left:5px;
}

.info-board{
  font-family: 'Space Mono', monospace;
  background-color:rgba(0, 0, 0, 0.7);
  color:#fff;
  padding:20px;
  margin:20px;
  border: 1px solid white;
  border-radius: 15px;
  display:inline-block;
  white-space: nowrap;
  z-index: 9999 !important;
}

@media only screen and (max-width: 992px) {
  .info-board {
    width: 100%;
    background-color:rgba(0, 0, 0, 0.9);
    color:#fff;
    padding:10px;
    margin:10px;
    border: 1px solid white;
    border-radius: 15px;
    /* display:inline-block; */
    white-space: nowrap;
    z-index: 9999;
  }
}

.flag {
  text-align: left;
  border-radius: 10px;
  display: inline-block;
  box-shadow: 0px 0px 20px -5px rgba(0, 0, 0, 0.8);
  padding-bottom:3px;
  margin-right:20px;
  margin-left:10px;
  margin-bottom:8px;
  background-position: center ;
  width:70px;
  height:45px;
  vertical-align: middle;
}

.country{
  font-size:30px;
  text-transform: uppercase;
    vertical-align: sub;
}

.info-title-top{
 font-size:18px;
 margin-top: 20px;
 margin-right:20px;
 margin-left:20px;
}

.info-title{
 font-size:18px;
 margin-top: 10px;
 margin-right:20px;
 margin-left:20px;
}

.info-title-v{
 color:#33ffff;;
 font-size:18px;
 margin-top: 10px;
 margin-bottom: 10px;
 margin-right:20px;
 margin-left:20px;
}

.new{
  font-size:14px;
  margin-left:0px;
}

.hr-info{
  border:none;
  border-top:1px dashed #fff;
  height:1px;
  width:90%;
}

.hr-info2{
  border:none;
  border-top:1px dashed #fff;
  height:1px;
  width:90%;
  margin-top:20px;
  margin-bottom:10px;

}

.red{
  color:rgba(255, 99, 132);
}

.blue{
   color:rgba(51,255,255, 0.9);
}

@media only screen and (max-width: 992px) {

  .country{
    font-size:24px;
    text-transform: uppercase;
    vertical-align: sub;
  }

  .info-title-top{
   font-size:14px;
   margin-top: 16px;
   margin-right:10px;
   margin-left:10px;
  }

  .info-title{
    font-size:14px;
   margin-top: 10px;
   margin-right:10px;
   margin-left:10px;
  }

  .info-title-v{
   color:#33ffff;;
   font-size:14px;
   margin-top: 10px;
   margin-bottom: 10px;
   margin-right:10px;
   margin-left:10px;
  }

  .new{
    font-size:12px;
    margin-left:0px;
  }
}


/*====== list ======*/

.legend .legend-title {
    text-align: left;
    margin-bottom: 10px;
    font-weight: bold;
    font-size: 80%;
}
.legend .legend-scale ul {
    margin: 0;
    padding: 0;
    float: left;
    list-style: none;
}
.legend .legend-scale ul li {
    display: block;
    float: left;
    width: 40px;
    margin-bottom: 6px;
    text-align: center;
    font-size: 60%;
    list-style: none;
}
.legend ul.legend-labels li span {
    display: block;
    float: left;
    height: 15px;
    width: 40px;
}
.legend .legend-source {
    font-size: 70%;
    color: #999;
    text-align: left;
    clear: both;
}
.legend a {
    color: #777;
}

.legend-set{
    /* margin-top:40px; */
    margin-left:25px;
}

@media only screen and (max-width: 992px) {
.legend-set {
    display:none;
    }
}

.card1 {
  width:100%;
  padding: 20px 15px;
  border-radius: 10px;
  box-shadow: 0 1px 10px 0 rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(221, 221, 221, 0.1);
}

@media only screen and (max-width: 992px) {
.card1 {
  width:100%;
  padding: 10px 15px;
  border-radius: 10px;
  box-shadow: 0 1px 10px 0 rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(221, 221, 221, 0.1);
  z-index: -1
}
}

.switch-menu {
    display: inline-block;
    margin-bottom:  10px ;
  }

    @media only screen and (max-width: 992px) {
        .switch-menu {
                display: inline-block;
                padding:  0px;
            }
    }

  hr.none-m {
    margin-bottom: 15px!important;
      }

  @media only screen and (max-width: 992px) {
    .none-m {
        display: none;
      }
  }


.icon{
  width:37px;
  height:37px;
  margin-right: 10px;
  vertical-align: text-bottom;
}

.card2 {
  width:100%;
  margin-top:30px;
  padding: 10px 15px;
  border-radius: 10px;
  box-shadow: 0 1px 10px 0 rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(221, 221, 221, 0.1);
  z-index: 100;
}

.card3 {
  width:100%;
  margin-top:30px;
  padding: 10px 15px;
  border-radius: 10px;
  box-shadow: 0 1px 10px 0 rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(221, 221, 221, 0.1);
  z-index: 100;
}

.card4 {
  width:100%;
  margin-top:30px;
  padding: 10px 8px 10px 8px;
  border-radius: 10px;
  box-shadow: 0 1px 10px 0 rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(221, 221, 221, 0.1);
  z-index: 100;
}


hr.mt{
  margin-top: 10px!important;
}

.chart-area {
  position: relative;
  height: 100%;
  width: 100%;
  margin-top:7px;
}

.casetitle{
    font-size: 22px;
  text-align: center;
  margin-bottom: 10px
}

.c-no{
  text-align: center;
  margin:10px 0px;
  color:rgba(255, 99, 132);
  font-size: 24px;
  font-weight: 100;
}


.v-no{
  text-align: center;
  margin:10px 0px;
  color:rgba(51,255,255,1.0);
  font-size: 24px;
  font-weight: 100;x
}

/* ***drag suggestion*** */

.drag{
text-align: center;
color:rgba(255, 255, 255, 0.2);
margin-bottom: 0px;
}

@media only screen and (max-width: 992px) {
.drag {
  display: none;
 }
}

.left-m {
    display: inline-block;
    padding:  10px;
    animation: move 1s linear infinite;
  }

    @media only screen and (max-width: 992px) {
        .left-m {
                display: inline-block;
                padding:  0px;
            }
    }

  .center-m {
      display: inline-block;
      padding:  10px;
    }

    @media only screen and (max-width: 992px) {
        .center-m {
                display: inline-block;
                padding:  0px;
            }
    }

    .right-m {
        display: inline-block;
        padding:  10px;
        animation: move1 1s linear infinite;

      }

        @media only screen and (max-width: 992px) {
            .right-m {
                    display: inline-block;
                    padding:  0px;
                }
        }


      @keyframes move {
        50% {
          transform: translateX(-10px);
          opacity: 0.5;
        }
        100% {
          transform: translateX(-10px);
          opacity: 0;
        }
      }

      @keyframes move1 {
        50% {
          transform: translateX(10px);
          opacity: 0.5;
        }
        100% {
          transform: translateX(10px);
          opacity: 0;
        }
      }


    .mb-3{
      margin-bottom:30px;
    }


@media only screen and (max-width: 992px) {
.title {
    padding-top: 10px;
    }
}


.mobile{
  display:none;
}

@media only screen and (max-width: 992px) {
  .mobile {
    display:block;
    margin-top:15px;
    }

  hr.toggle-menu{
    margin-top: 30px!important;
  }
}

  /*** pop up ***/
.main{
  margin: 10px;
}

p {
  margin-bottom: 10px;
}

.red{
  color:rgba(255, 99, 132);
}

.blue{
   color:#17a2b8;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Covid-19 3D Data Visualisation</title>
  <link rel="stylesheet" href="globe.css">
  <link rel="preconnect" href="https://fonts.gstatic.com">
  <link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">


</head>
<body>

  <div id="globeViz"></div>

  <section>

     <h1 class="title">Covid-19 Active Cases 3D Map</h1>

    <div class="drag">
    <div class="left-m">
     <<<
    </div>

    <div class="center-m">
      Drag to Rotate and Zoom
    </div>

    <div class="right-m">
       >>>
    </div>
        </div>
  </section>

  <section2>
    <form class="card1">
      <h3 class="none-m"><img src="img/covid.png" alt="covid" class="icon">Covid-19</h3>

      <hr class="none-m">
        <!-- <div class="switch-menu">
          <label id="cases" class="list">
            <input name="group1" type="radio" style="transform:scale(1.5);"checked />
            <span>Total Cases</span>
          </label>
        </div> -->
        <div class="switch-menu">
          <label id="active" class="list">
            <input name="group1" type="radio" style="transform:scale(1.5);" checked />
            <span>Active Cases</span>
          </label>
        </div>
          <hr class="mt none-m">
        <h3 class="none-m"><img src="img/vaccine.png" alt="vaccination" class="icon">Vaccination</h3>
              <hr class="none-m">
        <div class="switch-menu">
          <label id="vaccination" class="list">
            <input name="group1" type="radio" style="transform:scale(1.5);" />
            <span>Total Vaccination</span>
          </label>
        </div>
      </form>
  </section2>

  <section3>
    <div class="legend-set">
    <div class="legend mt-3">
      <div class='legend-scale'>

        <ul class='legend-labels' id="CasesColor">
          <div class="legend-title2">
            Covid-19 Active Cases
          </div>
          <li><span style='background:#FFEDA0;'></span>&gt; 30K</li>
          <li><span style='background:#FED976;'></span>&gt; 50K</li>
          <li><span style='background:#FEB24C;'></span>&gt; 70K</li>
          <li><span style='background:#FD8D3C;'></span>&gt; 100K</li>
          <li><span style='background:#FC4E2A;'></span>&gt; 500K</li>
          <li><span style='background:#E31A1C;'></span>&gt; 1M</li>
          <li><span style='background:#800026;'></span>&lt; 1M+</li>
        </ul>


        <ul class='legend-labels' id="VaccinationColor" style="display:none;">
          <div class="legend-title2">
            Covid-19 Vaccination
          </div>
          <li><span style='background:#ccebc5;'></span>&gt; 30K</li>
          <li><span style='background:#a8ddb5;'></span>&gt; 50K</li>
          <li><span style='background:#7bccc4;'></span>&gt; 70K</li>
          <li><span style='background:#4eb3d3;'></span>&gt; 100K</li>
          <li><span style='background:#2b8cbe;'></span>&gt; 500K</li>
          <li><span style='background:#0868ac;'></span>&gt; 1M</li>
          <li><span style='background:#084081;'></span>&lt; 1M+</li>
        </ul>

      </div>
      <div class='legend-source'>
        Source: <a href="https://corona.lmao.ninja/">disease.sh - Open Disease Data</a>
      </div>
    </div>
    </div>
  </section3>


<script type="text/javascript"  src="js/d3.min.js"></script>
<script src="https://unpkg.com/globe.gl"></script>
<script type="text/javascript" src="js/globe.js"></script>


</body>
</html>

4

0 回答 0