删除条形图的条,点击
Removing bar graph's bars, on click
我在d3.js中制作了条形图。我想要一种行为,即点击任何一个栏,该栏就会被删除。
我有一个函数,它根据索引删除数组元素并更新 DOM。
第一次点击工作正常,但在以后的点击中,我得到不同的索引值,并且其他一些栏被删除。知道为什么点击时索引值不正确吗?
<script>
var dataSet = [
{key:0, value: 10},
{key:1, value: 18},
{key:2, value: 13},
{key:3, value: 19},
{key:4, value: 21},
{key:5, value: 25}
];
var canvasWidth = 500, canvasHeight = 500;
var svg = d3.select('body').append('svg').attr('width',canvasWidth).attr('height',canvasHeight);
svg.append('rect').attr('width', "100%").attr('height', '100%').attr('fill', 'lightgrey').classed('bg',true);
// Bargraph
var barWidth = 20, padding = 1;
var barScale = d3.scale.linear()
.domain([ d3.min(dataSet,function(data){return data.value}), d3.max(dataSet,function(data){return data.value}) ])
.range ([ d3.min(dataSet,function(data){return data.value}), canvasHeight-padding])
// Create
var key = function(d) { return d.key; };
var barGraph = svg.selectAll('rect.bars').data(dataSet,key).enter().append('rect')
.attr('x', function(data,index){return (padding+barWidth)*index})
.attr('y', function(data){ return canvasHeight-barScale(data.value); })
.attr('width', barWidth)
.attr('height', function(data){ return barScale(data.value); })
.style('fill', 'teal')
.classed('bars',true)
// ---------- Here is the problem --------------------
.on('click',function(data,index){ console.log(index) ; removeElement(index) })
.on('mouseover',function(data){ })
// Exit some
function removeElement(index)
{
dataSet.splice( index , 1)
var updated = svg.selectAll('rect.bars').data(dataSet,key)
updated.exit()
.transition()
.duration(1000)
.attr('width', 0)
.remove()
.each('end',function()
{
svg.selectAll('rect.bars')
.transition()
.duration(1000)
.attr('x', function(data,index){return (padding+barWidth)*index})
})
}
</script>
可能是因为当您重新绑定数据 (var updated = ...
) 时,删除的栏仍然是选择的一部分,这会影响索引。
我认为最好的解决方案是使用 dataSet.indexOf(data)
在 dataSet
中查找 index
,而不是依赖传递到点击处理程序的 index
.
或者,如果将其添加到 .each('end',...)
处理程序中,您可以尝试查看以下任何一项是否有效:
- 再次重新绑定数据
- 在柱上调用
.order()
,如 svg.selectAll('rect.bars').order()
- 重新订阅点击事件,如
svg.selectAll('rect.bars').on('click',...)
我认为它是依赖索引和就地数组拼接的组合,这会导致 d3
数据绑定失效。
尝试:
dataSet = dataSet.filter(function(d,i){
return d.key != index;
});
var updated = svg.selectAll('rect.bars').data(dataSet,key)
例子here.
编辑
让我澄清一下,这不是拼接的就地性导致的,而是对索引移位的依赖。无论删除元素如何,点击处理程序仍然认为数据是它的旧索引。您可以在 console.log(index)
中见证这一点。这就是我上面的代码有效的原因。您不再依赖于按索引删除,而是按 d.key
删除,这是起始索引(点击记住的相同索引)。
另一种解决此问题的方法确实适用于拼接,是在数据更新时重新绑定事件处理程序。
function removeElement(index)
{
dataSet.splice(index, 1);
var updated = svg.selectAll('rect.bars')
.data(dataSet,key)
.on('click',function(data,index){ console.log(index) ; removeElement(index) });
updated.exit()....
看到这个example。
我在d3.js中制作了条形图。我想要一种行为,即点击任何一个栏,该栏就会被删除。
我有一个函数,它根据索引删除数组元素并更新 DOM。
第一次点击工作正常,但在以后的点击中,我得到不同的索引值,并且其他一些栏被删除。知道为什么点击时索引值不正确吗?
<script>
var dataSet = [
{key:0, value: 10},
{key:1, value: 18},
{key:2, value: 13},
{key:3, value: 19},
{key:4, value: 21},
{key:5, value: 25}
];
var canvasWidth = 500, canvasHeight = 500;
var svg = d3.select('body').append('svg').attr('width',canvasWidth).attr('height',canvasHeight);
svg.append('rect').attr('width', "100%").attr('height', '100%').attr('fill', 'lightgrey').classed('bg',true);
// Bargraph
var barWidth = 20, padding = 1;
var barScale = d3.scale.linear()
.domain([ d3.min(dataSet,function(data){return data.value}), d3.max(dataSet,function(data){return data.value}) ])
.range ([ d3.min(dataSet,function(data){return data.value}), canvasHeight-padding])
// Create
var key = function(d) { return d.key; };
var barGraph = svg.selectAll('rect.bars').data(dataSet,key).enter().append('rect')
.attr('x', function(data,index){return (padding+barWidth)*index})
.attr('y', function(data){ return canvasHeight-barScale(data.value); })
.attr('width', barWidth)
.attr('height', function(data){ return barScale(data.value); })
.style('fill', 'teal')
.classed('bars',true)
// ---------- Here is the problem --------------------
.on('click',function(data,index){ console.log(index) ; removeElement(index) })
.on('mouseover',function(data){ })
// Exit some
function removeElement(index)
{
dataSet.splice( index , 1)
var updated = svg.selectAll('rect.bars').data(dataSet,key)
updated.exit()
.transition()
.duration(1000)
.attr('width', 0)
.remove()
.each('end',function()
{
svg.selectAll('rect.bars')
.transition()
.duration(1000)
.attr('x', function(data,index){return (padding+barWidth)*index})
})
}
</script>
可能是因为当您重新绑定数据 (var updated = ...
) 时,删除的栏仍然是选择的一部分,这会影响索引。
我认为最好的解决方案是使用 dataSet.indexOf(data)
在 dataSet
中查找 index
,而不是依赖传递到点击处理程序的 index
.
或者,如果将其添加到 .each('end',...)
处理程序中,您可以尝试查看以下任何一项是否有效:
- 再次重新绑定数据
- 在柱上调用
.order()
,如svg.selectAll('rect.bars').order()
- 重新订阅点击事件,如
svg.selectAll('rect.bars').on('click',...)
我认为它是依赖索引和就地数组拼接的组合,这会导致 d3
数据绑定失效。
尝试:
dataSet = dataSet.filter(function(d,i){
return d.key != index;
});
var updated = svg.selectAll('rect.bars').data(dataSet,key)
例子here.
编辑
让我澄清一下,这不是拼接的就地性导致的,而是对索引移位的依赖。无论删除元素如何,点击处理程序仍然认为数据是它的旧索引。您可以在 console.log(index)
中见证这一点。这就是我上面的代码有效的原因。您不再依赖于按索引删除,而是按 d.key
删除,这是起始索引(点击记住的相同索引)。
另一种解决此问题的方法确实适用于拼接,是在数据更新时重新绑定事件处理程序。
function removeElement(index)
{
dataSet.splice(index, 1);
var updated = svg.selectAll('rect.bars')
.data(dataSet,key)
.on('click',function(data,index){ console.log(index) ; removeElement(index) });
updated.exit()....
看到这个example。