d3js v5 + Topojson v3 关于加入 csv & json 的优化

d3js v5 + Topojson v3 Optimization about joining 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

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

这是一个 block 的日志记录。

我很确定我住的地方的带宽低于平均水平,而且变化很大;文件加载时间对我来说变化很大,低至 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)

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

Topojson.feature

Returns the GeoJSON Feature or FeatureCollection for the specified object in the given topology. If the specified object is a GeometryCollection, a FeatureCollection is returned, and each geometry in the collection is mapped to a Feature. Otherwise, a Feature is returned. The returned feature is a shallow copy of the source object: they may share identifiers, bounding boxes, properties and coordinates. (from the docs).

因此,每次我们使用 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

现在让我们看一下时间:

这是基于上述内容的更新 bl.ock,也有时间点。

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

进一步增强

几何体的预投影,见此

几何的简化,参见mapshaper.org(虽然我相信你已经这样做了)。

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