如果我有一个JSON对象数组.D3如何确定哪一组进入enter()?
如果我有一个对象数组,如下所示:
var data = [
{label:'a', value:1},
{label:'b', value:3},
{label:'c', value:2}
]
Run Code Online (Sandbox Code Playgroud)
然后我将它绑定到选择:
var bars = vis.selectAll("rect.bar")
.data(data)
Run Code Online (Sandbox Code Playgroud)
该enter集现在包含所有这些数据.如果我现在更改数据:
var data = [
{label:'a', value:99},
{label:'c', value:2}
{label:'b', value:3},
]
Run Code Online (Sandbox Code Playgroud)
D3如何判断哪些值是更新,移动还是新的?它是在对象身份上完成的吗?有没有办法让它使用标签字段来填充输入集?
如果我正确理解您的问题,您想知道D3如何将给定对象与给定DOM元素相关联.
默认情况下,如果您未设置键功能(更多内容如下),则对象将按其顺序关联.根据API:
...数据中的第一个数据分配给第一个选定元素,第二个数据分配给第二个选定元素,依此类推.
让我们在下面的例子中看到这一点.第一个数组是这样的:
var data = [{
label: 'a',
value: 1
}, {
label: 'b',
value: 3
}, {
label: 'c',
value: 2
}];
Run Code Online (Sandbox Code Playgroud)
第二个数组也有3个对象.但要注意变化:第一个是标签c,第三个是标签a.他们被交换:
var data2 = [{
label: 'c',
value: 99
}, {
label: 'b',
value: 2
}, {
label: 'a',
value: 3
}];
Run Code Online (Sandbox Code Playgroud)
因此,相对于a第一个数据的条形将获得c第二个数据中的值.查看演示,单击按钮:
var svg = d3.select("svg");
var data = [{
label: 'a',
value: 1
}, {
label: 'b',
value: 3
}, {
label: 'c',
value: 2
}];
var data2 = [{
label: 'c',
value: 99
}, {
label: 'b',
value: 2
}, {
label: 'a',
value: 3
}];
var xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([0, 260]);
var yScale = d3.scaleBand()
.domain(data.map(d => d.label))
.range([10, 140])
.padding(0.3);
var rects = svg.selectAll("foo")
.data(data)
.enter()
.append("rect");
rects.attr("x", 40)
.attr("y", d => yScale(d.label))
.attr("height", yScale.bandwidth)
.attr("width", d => xScale(d.value))
.attr("fill", "teal");
d3.axisLeft(yScale)(svg.append("g").attr("transform", "translate(40,0)"))
d3.select("button").on("click", function() {
xScale.domain([0, d3.max(data2, d => d.value)]);
rects.data(data2);
rects.transition()
.duration(1000)
.attr("width", d => xScale(d.value))
})Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.min.js"></script>
<button>Click</button>
<br>
<svg></svg>Run Code Online (Sandbox Code Playgroud)
如您所见,单击按钮后的图表显然不正确.
为了避免这种情况,确保先前绑定到标签的DOM元素在数据数组更改时a仍将绑定到该标签a,我们必须使用键函数:
可以指定关键函数来控制将哪个数据分配给哪个元素,替换默认的索引连接.为每个选定的元素评估此关键函数,按顺序传递当前数据(d),当前索引(i)和当前组(节点),并将其作为当前DOM元素(nodes [i]) .然后还为数据中的每个新数据评估关键函数,传递当前数据(d),当前索引(i)和组的新数据,并将其作为组的父DOM元素.给定键的数据被分配给具有匹配键的元素.如果多个元素具有相同的键,则将重复的元素放入出口选择中; 如果多个数据具有相同的密钥,则将重复数据放入输入选择中.
在您的情况下,这将是关键功能:
.data(data, d => d.label)
//key-------^
Run Code Online (Sandbox Code Playgroud)
检查完全相同的代码,但具有关键功能:
var svg = d3.select("svg");
var data = [{
label: 'a',
value: 1
}, {
label: 'b',
value: 3
}, {
label: 'c',
value: 2
}];
var data2 = [{
label: 'c',
value: 99
}, {
label: 'b',
value: 2
}, {
label: 'a',
value: 3
}];
var xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.range([0, 260]);
var yScale = d3.scaleBand()
.domain(data.map(d => d.label))
.range([10, 140])
.padding(0.3);
var rects = svg.selectAll("foo")
.data(data, d => d.label)
.enter()
.append("rect");
rects.attr("x", 40)
.attr("y", d => yScale(d.label))
.attr("height", yScale.bandwidth)
.attr("width", d => xScale(d.value))
.attr("fill", "teal");
d3.axisLeft(yScale)(svg.append("g").attr("transform", "translate(40,0)"))
d3.select("button").on("click", function() {
xScale.domain([0, d3.max(data2, d => d.value)]);
rects.data(data2, d => d.label);
rects.transition()
.duration(1000)
.attr("width", d => xScale(d.value))
})Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.min.js"></script>
<button>Click</button>
<br>
<svg></svg>Run Code Online (Sandbox Code Playgroud)
你可以看到,尽管新数据数组中的对象顺序不同(c第三个,现在c是第一个),这没关系,因为D3将数据绑定到每个DOM元素,同时考虑到该label物业.
| 归档时间: |
|
| 查看次数: |
247 次 |
| 最近记录: |