Working in d3, I’ve got a function call that correctly draws a bar chart, but it doesn’t update it correctly. Here’s the important part of my code:
# Drawing Elements
@svg = d3.select(@s).append('svg').attr('width',@w).attr('height',@h)
@rects = @svg.selectAll('rect')
@labels = @svg.selectAll('text')
drawRects: (data) ->
rects = @rects.data(data)
rects.enter().append('rect')
rects.exit().remove()
rects.attr('x', (d,i) => this.xScale(i) )
.attr('y', (d) => @h - this.yScale(d) )
.attr('width', @w / @data.length - @pad)
.attr('height', (d) => this.yScale(d) )
.attr('fill','#FFC05C')
drawLabels: (data) ->
labels = @labels.data(data)
labels.enter().append('text')
labels.exit().remove()
labels.text( (d) -> d )
.attr('text-anchor','middle')
.attr('x', (d,i) => this.xScale(i) + ((@w / @data.length - @pad)/2) )
.attr('y', (d) => @h - this.yScale(d) + 15 )
.attr('fill','white')
update: (data) ->
this.drawRects(data)
this.drawLabels(data)
When I initially set the graph I create some data (in this case an array of 20 numbers) and call the draw methods:
data = [1..20]
this.drawRects(data)
this.drawLabels(data)
The graphs are drawn correctly.
However, if these methods are called a second time, to update the data, the new data is placed in the DOM, but the old data is left behind as well, so it’s just making a whole new set of elements.
What am I doing wrong here that’s keeping .exit() from removing the old DOM elements?
You need to reselect the
rectandtextelements and assign them the new data:In your code you always assign the new data to the old (empty)
@rectand (empty)@labelscollections. And the data will be treated as “entered” for these empty collections and thus new elements will be created and nothing will be removed.