我使用这个mbostock示例作为指南,但它是在d3 v3中。我已经读到,在v4,选择已经改变,但这似乎不是我的问题,因为数据永远不会改变-这是一个静态图表(目前)。
我有一个对象数组,我希望为每个对象创建一个组(g
),并为该对象的每个field1
和field2
创建两个矩形(rect
),这些矩形与日期相关。我能够创建组,但是当我.data(d => d)
,而试图使矩形,输入组似乎是空的。
有人能解释一下这是为什么吗?
jsfield (not working)
UPDATE: jsfiddle (working) –感谢@gerardo-furtado
var models = [
{
"date":"2016-10-13T07:00:00.000Z",
"field1":19,
"field2":83
},
{
"date":"2016-10-14T07:00:00.000Z",
"field1":67,
"field2":93
},
{
"date":"2016-10-15T07:00:00.000Z",
"field1":10,
"field2":56
},
{
"date":"2016-10-16T07:00:00.000Z",
"field1":98,
"field2":43
}
];
models = models.map(i => {
i.date = new Date(i.date);
return i;
});
var container = d3.select('body'),
width = 500,
height = 300,
margin = {top: 30, right: 20, bottom: 30, left: 50},
barPadding = .2,
axisTicks = {qty: 5, outerSize: 0, dateFormat: '%m-%d'};
var svg = container
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
var xScale0 = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(barPadding);
var xScale1 = d3.scaleBand();
var yScale = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]);
var xAxis = d3.axisBottom(xScale0).tickFormat(d3.timeFormat(axisTicks.dateFormat)).tickSizeOuter(axisTicks.outerSize);
var yAxis = d3.axisLeft(yScale).ticks(axisTicks.qty).tickSizeOuter(axisTicks.outerSize);
xScale0.domain(models.map(d => d.date));
xScale1.domain(['field1', 'field2']).range([0, xScale0.bandwidth()]);
yScale.domain([0, d3.max(models, d => d.field1 > d.field2 ? d.field1 : d.field2)]);
var date = svg.selectAll(".date")
.data(models)
.enter().append("g")
.attr("class", "date")
.attr("transform", d => `translate(${xScale0(d.date)},0)`);
/* Add field1 bars */
var rect = date.selectAll(".bar")
.data(d => d) // FIXME: the .enter() group seems to contain nothing
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", d => { xScale1('field1') })
.attr("y", d => { yScale(d.field1) })
.attr("width", xScale1.bandwidth())
.attr("height", d => {
return height - margin.top - margin.bottom - yScale(d.field1)
});
/* Add field2 bars */
// var rect = date.selectAll(".bar")
// .data(d => d)
// .enter()
// .append("rect")
// .attr("class", "bar")
// .attr("x", d => { xScale1('field2') })
// .attr("y", d => { yScale(d.field2) })
// .attr("width", xScale1.bandwidth())
// .attr("height", d => {
// return height - margin.top - margin.bottom - yScale(d.field1)
// });
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0,${height - margin.top - margin.bottom})`)
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
在D3中,data
必须是数组。如果你看一下Bostock的例子,layers
是一个数组的数组。这是console.log(layers)
:
Array[4]
0:Array[58]
1:Array[58]
2:Array[58]
3:Array[58]
因此,由于layers
是数组的数组,当Bostock在后面的代码中这样写时:
.data(function(d) { return d; })
他正在传递一个数组给data
,这是有效的。
然而,在您的代码中,您在rect
的输入选择中将一个对象传递给data
:
对象{日期:星期四Oct 13 2016 18:00:00 GMT+1100, field1: 19, field2: 83}
解决方案:传递一个数组给data
。这是我做的唯一更改:
.data(d => [d])
现在你有了一个数组:
[{date: thococ13 2016 18:00:00 GMT+1100, field1: 19, field2: 83}]
这是你更新的小提琴:https://jsfiddle.net/96d3wtys/
PS:你必须调整y
和height
条