d3 v5绘制简单的折线图,并使用promise映射/投射到数字

时间:2018-12-10 06:24:49

标签: d3.js

在使用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的一元+转换为数字。

1 个答案:

答案 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