javascript - 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
解决方案
我拿了你的 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"
?
推荐阅读
- python - Python 类自变量未转移到函数 (discord.py)
- sql - 是否可以使用标准 SQL 在 Google BigQuery 中安排查询,以便日期范围在运行时每天递增?
- android - 发布大型请求时如何解决来自 Timimg Out 的改造写入
- apache-spark - 我们将使用 pyspark 来构建项目吗?
- php - 如何在整个会话中为访客用户分配唯一 ID
- tensorflow - 在 tf.keras.metrics.Recall 中使用 thesholds 参数
- django - 我正在尝试更新嵌套序列化程序,它给了我一个错误 paper_description 与此 id 已经存在?
- ios - 如何生成带有特殊字符“¿”的code128条码?
- pyspark - 两个数据帧的火花连接操作
- opentap-proj - 将 TestStep 的输出传递给另一个 TestStep