在使用v3多年之后,我终于决定采用d3 v5语法。看了一些教程和示例之后,v5语法确实让我赞叹不已。可读性大大提高,并且似乎更容易集成多个数据源。
令我沮丧的是,尽管我敬畏它,但我无法完全使用新的Promise
语法从头开始构建视觉效果。这是我的简单图形:(请注意,出于本文的目的,我正在使用硬编码数据,并且我已经注释掉了我实际使用的.csv()
调用。它在功能上应该仍然相同)< / p>
var margins = {top:50, right:50, bottom:50, left:50};
var width = window.innerWidth - margins.left - margins.right;
var height = window.innerHeight - margins.top - margins.bottom;
var sampleData = [
{'y':32, 'x':1},
{'y':20, 'x':2},
{'y':19, 'x':3},
{'y':12, 'x':4},
{'y':15, 'x':5},
{'y':19, 'x':6},
{'y':22, 'x':7},
{'y':26, 'x':8},
{'y':31, 'x':9},
{'y':36, 'x':10}
];
//var dataset = d3.csv("my-data.csv").then(function(data)
// {return data;
// });
var dataset = sampleData.then(function(data)
{return data;
});
var svg = d3.select('body').append('svg').attr('id','svg').attr('height','100%').attr('width','100%');
var myLine = dataset.then(function(data) {
Promise.all(data.map(function(d) {return {X:+d.x, Y:+d.y}}))//ensure numeric parsing
var xScale = d3.scaleLinear()
.domain(d3.extent(data, function(d) { return d.X; }))
.range([0,width]);
var yScale = d3.scaleLinear()
.domain(d3.extent(data, function(d) {return d.Y; }))
.range([height,0]);
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var line = d3.line()
.x(function(d) {return xScale(d.x); })
.y(function(d) {return yScale(d.y); });
var svg = d3.select('body').append('svg').attr('id','svg').attr('height','100%').attr('width','100%');
var graphGroup = svg.append('g')
.attr('transform',"translate("+margins.left+","+margins.top+")");
graphGroup.append('path')
.attr('d', function(d) {return line(data); });
graphGroup.append('g')
.attr('class', 'axis x')
.attr('transform', "translate(0,"+height+")")
.call(xAxis);
graphgroup.append('g')
.attr('class', 'axis y')
.call(yAxis);
});
我在控制台中收到此错误:
未捕获的TypeError:sampleData。则不是函数
我认为Promise.all()
和.then()
并不总是对真正简单的数据可视化有利,但是我仍然想知道为什么我不能使上面的脚本输出最少的行图形。从那时起,希望我可以慢慢地离开训练轮,并在v5中找到自己的步伐。
我特别困惑如何使用带有Promise的一元+
转换为数字。
答案 0 :(得分:1)
尽管在使用Promises时有很多曲折,但事实证明,要使用d3-fetch模块来移植代码以使用已弃用的d3-request模块所需的实际更改极少。宽松地说,要使您的代码(或任何v5之前的版本)适应新的d3-fetch模块,您只需将回调从一种方法移至另一种方法。因此,前
d3.dsv(url, callback);
现在成为
d3.dsv(url).then(callback);
唯一要注意的是检查回调的签名是否与.then
所期望的签名匹配。但是,只有在您的回调使用两个参数来处理错误时,这才有意义:
function callback(error, data) {
// Handle error
if (error) throw error;
// Manipulate data
}
使用Promises可以将其分为两个单独的方法:
function onFullfilled(data) {
// Manipulate data
}
function onRejected(error) {
// Handle error
}
这些回调可以通过两种方式使用:
// 1.
d3.dsv(url).then(onFullfilled, onRejected);
// 2.
d3.dsv(url).then(onFullfilled).catch(onRejected);
另一个重要的一点是,您不能从回调中返回数据(请注意臭名昭著的"How do I return the response from an asynchronous call?"!)。 d3.dsv
现在返回一个Promise,而不是您的数据;您必须处理回调中的数据。但是,如果您更加熟练地使用Promises,则可以看看await
运算符,它使您可以等待Promise及其实现的价值。尽管这是ECMAScript 2017(ES8)语法,但已经看到了广泛使用的browser support。
这是一般情况,现在对于您的代码:sampleData
是一个Array
对象,它当然没有.then()
方法,因此也就出错了。要使代码正常工作,除了取消注释带有d3.dsv
的行并将注释中的相关代码处理数据放入回调之外,没有什么要做。
如果您真的想对硬编码数据进行离线模拟,则可以使用Promise.resolve()
,它会返回一个已解决且具有给定值的Promise。就您而言,而不是
d3.csv("my-data.csv")
.then(function(data) { });
您可以使用
Promise.resolve(sampleDate)
.then(function(data) { }); // Same handler as above