我尝试使用 d3.js 创建排序算法的可视化。为此,我想创建几个具有不同半径的圆,然后逐个交换它们作为排序算法的工作。为了做到这一点,我遇到了以下问题:当我更新与d3选择相关的数据然后尝试使用.data()
将其恢复时,我得到了未更改的数据(因为我没有更新它)。仅当我使用key
函数跟踪对象时才会出现此问题。
代码如下。如果单击"选中",您将在控制台中获得[1, 3, 2]
,这是正确的初始状态。如果您点击"执行",update
功能将被调用,圈子将根据新数据更改其位置。但是,如果你点击那么"检查"再次,您仍然按预期获得[1, 3, 2]
而不是[3, 2, 1]
。
所以,有两个问题:
function key(d) {
return d
}
function update(data) {
return d3.select("#picture")
.selectAll("circle")
.data(data, key)
.transition()
.attr("cx", function(d, i) {return (i+1)*50;});
}
$(function() {
d3.select("#picture")
.selectAll("circle")
.data([1, 3, 2], key)
.enter()
.append("circle")
.attr("cx", function(d, i) {return (i+1)*50;})
.attr("cy", 100)
.attr("r", function(d) {return (d+1)*10;})
.style("fill", "none")
.style("stroke", "steelblue");
$("#do_it").click(function() {
update([3, 2, 1]);
});
$("#check").click(function() {
console.log(d3.select("#picture")
.selectAll("circle").data());
});
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="check">check</button>
<button id="do_it">do</button><br/>
<svg id="picture" width=300 height=150></svg>
&#13;
答案 0 :(得分:2)
由于您使用了密钥,因此数据的顺序不会改变正好。如果您没有使用密钥,则订单会发生变化。
使用以下关系创建圆圈:
0
以1
为基准1
以3
为基准2
以2
为基准。 每个数据用作键,用于标识圆圈。更新数据时,此关系不会再次发生变化,因为您已设置密钥。
当您在更新(&#34;执行&#34;)功能后对数据进行console.log时,您无法获取有关圈子的新位置的数据。当你在更新后console.log数据时,事实上,你得到同样的东西:
0
以1
为基准1
以3
为基准2
以2
为基准。 这些不是圈子的位置,而是它们的创建顺序。
但是,如果在update
函数中放置console.log,则可以看到位置正在改变:
console.log("circle at position " + i + ", data: " + d)
检查演示,点击&#34;执行&#34;并查看与不同位置的圈子相关联的数据:
function key(d) {
return d
}
function update(data) {
return d3.select("#picture")
.selectAll("circle")
.data(data, key)
.transition()
.attr("cx", function(d, i) {
console.log("circle at position " + i + ", data: " + d)
return (i+1)*50;});
}
$(function() {
d3.select("#picture")
.selectAll("circle")
.data([1, 3, 2], key)
.enter()
.append("circle")
.attr("cx", function(d, i) {return (i+1)*50;})
.attr("cy", 100)
.attr("r", function(d) {return (d+1)*10;})
.style("fill", "none")
.style("stroke", "steelblue");
$("#do_it").click(function() {
update([3, 2, 1]);
});
$("#check").click(function() {
console.log(d3.select("#picture")
.selectAll("circle").data());
});
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="check">check</button>
<button id="do_it">do</button><br/>
<svg id="picture" width=300 height=150></svg>
&#13;
答案 1 :(得分:1)
Gerardo Furtado的回答解释了这种行为的原因,这里是我问题第二部分的答案:如何克服这一点。
我将元素的实际位置存储在其data-position
属性中,然后从该位置信息中恢复原始数据。
我不确定这是一个最优雅的解决方案,因此非常感谢评论和替代方案。
function key(d) {
return d
}
function update(data) {
return d3.select("#picture")
.selectAll("circle")
.data(data, key)
.transition()
.attr("cx", function(d, i) {
return (i + 1) * 50;
})
.attr("data-position", function(d, i) {
return i;
});
}
function get_data(initial_array) {
// BASED ON: http://stackoverflow.com/a/22118052/3025981
var indexes = []
d3.select("#picture")
.selectAll("circle").each(function(d, i) {
indexes.push(+d3.select(this).attr('data-position'))
});
// END BASED
var data = []
for (i = 0; i < initial_array.length; i++) {
data[indexes[i]] = initial_array[i];
}
return data;
}
$(function() {
initial_array = [1, 3, 2]
d3.select("#picture")
.selectAll("circle")
.data(initial_array, key)
.enter()
.append("circle")
.attr("cx", function(d, i) {
return (i + 1) * 50;
})
.attr("cy", 100)
.attr("r", function(d) {
return (d + 1) * 10;
})
.attr("data-position", function(d, i) {
return i;
})
.style("fill", "none")
.style("stroke", "steelblue");
$("#do_it").click(function() {
update([3, 2, 1]);
});
$("#check").click(function() {
console.log(get_data(initial_array));
});
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="check">check</button>
<button id="do_it">do</button>
<br/>
<svg id="picture" widht=300 height=300></svg>
&#13;