首页 > 解决方案 > d3js v5 + Topojson v3 关于加入 csv & json 的优化

问题描述

为了制作地图,我需要直接在代码中将一些值从 csv 导入到 json 中。为了加载 json 和 csv 文件,我对 Promise 对象使用异步操作,并使用两个循环和一个公共键在 json 文件上添加新属性。

for (var i=0; i< fr[1].length;i++){
        var csvId = fr[1][i].codgeo;
        var csvValue1 = parseFloat(fr[1][i].value1);
        var csvValue0 = parseFloat(fr[1][i].value0);
        for (var j=0; j<topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features.length;j++){
          var jsonId = topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.codgeo;
          if (csvId === jsonId) {
            topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.value1 = csvValue1;
            topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.value0 = csvValue0;
            break;

一切正常,但在网络上显示地图需要时间。有没有办法优化地图的加载时间?

这是我的代码示例:https ://plnkr.co/edit/ccwIQzlefAbd53qnjCX9?p=preview

标签: javascriptd3.jstopojson

解决方案


我拿了你的 plunkr 并添加了一些时间点,运行了很多次,并获得了一些关于你的脚本花费时间的数据:

在此处输入图像描述

这是一个带有日志记录的

我很确定我住的地方的带宽低于平均水平,并且有很多可变性;文件加载时间对我来说有很大的变化,低至 500 毫秒,最高 1800 毫秒,其他一切都是一致的

让我们仔细看看您在问题中包含的数据操作阶段:

for (var i=0; i< fr[1].length;i++){
        var csvId = fr[1][i].codgeo;
        var csvValue1 = parseFloat(fr[1][i].value1);
        var csvValue0 = parseFloat(fr[1][i].value0);
        for (var j=0; j<topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features.length;j++){
          var jsonId = topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.codgeo;
          if (csvId === jsonId) {
            topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.value1 = csvValue1;
            topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8).features[j].properties.value0 = csvValue0;
            break;

根据我的统计,嵌套的 for 语句运行了大约 5,151 次。父 for 语句运行 101。这些不应更改,因为您的数据是固定的。为什么这些周期需要这么长时间?因为您每次都在调用 topojson.feature() 进行迭代:

如果我隔离这一行:

topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8)

我们可以看到,这实际上只需要几毫秒。

拓扑json.feature

返回给定拓扑中指定对象的 GeoJSON Feature 或 FeatureCollection。如果指定的对象是 GeometryCollection,则返回 FeatureCollection,并将集合中的每个几何图形映射到 Feature。否则,返回一个 Feature。返回的特征是源对象的浅拷贝:它们可能共享标识符、边界框、属性和坐标。(来自文档)。

因此,每次我们使用topojson.feature时,本质上都是将 topojson 转换为 geojson。我们不需要在 for 循环中这样做。让我们这样做一次:

  var featureCollection = topojson.feature(fr[0],fr[0].objects.dep_GEN_WGS84_UTF8);

  //Merge csv & json
  //Add properties from csv to json)
 for (var i=0; i< fr[1].length;i++){
    var csvId = fr[1][i].codgeo;
    var csvValue1 = parseFloat(fr[1][i].value1);
    var csvValue0 = parseFloat(fr[1][i].value0);
    for (var j=0; j<featureCollection.features.length;j++){
      var jsonId = featureCollection.features[j].properties.codgeo;
      if (csvId === jsonId) {
        featureCollection.features[j].properties.value1 = csvValue1;
        featureCollection.features[j].properties.value0 = csvValue0;
        break;
      }
    }
  }

当然,我们也必须更新渲染的代码部分以使用featureCollection变量,而不是 topojson

现在让我们看一下时间: 在此处输入图像描述

这是基于上述内容的更新块,也带有时间点。

不,我没有忘记包括操作时间,对我来说平均只有 1.5 毫秒。是的,我的带宽显示出可变性 - 但无论外部因素如何,花在其他操作上的时间显然应该更少

进一步增强

几何的预投影,请参阅此问题/答案

几何简化,请参阅mapshaper.org(尽管我相信您已经这样做了)。

从 csv 或 topojson 中删除不必要的属性 - 您是否真的在使用 topojson 中的人口字段,您是否需要在 topojson 中同时使用 libgeo 和 libgeo_m(例如:)"libgeo":"Puy-de-Dôme","libgeo_m":"PUY-DE-DÔME"


推荐阅读