0

I'm curious why my d3 canvas keeps data stored, even after I do a hard refresh of the browser. Now, if I 'zoom' on a g-element the dy, dx, w and h of it changes. Consequently, if I use a filter and rerender the icicle, the g elements have the same position as before, but the height and the width are as if it is freshly loaded. This leaves a lot of whitespace. With a bit of experimenting I found that d3 saves all the data bound to the g-elements somehow. I'm building this as the front-end of a Ruby on Rails project. I've tried to clear the selection with canvas.selectAll("svg > *") but it doesn't seem to work. I build the layout as follows:

w = 1200
h = 800
x = d3.scale.linear().range([0,w])
y = d3.scale.linear().range([0,h])

renderIcicle = ()->
  canvas = getCanvas('#canvas')
  url = "/icicle/data.json"
  renderOnData(url, canvas)

getCanvas = (id)->
  d3.select(id).select("svg").remove()
  canvas = d3.select(id).append("svg").attr("width", w).attr("height", h)
  return canvas

calculateLayout = (root)->
  partition = d3.layout.partition()
  data = partition.nodes(root)
  return data

d3.json url, (root)->
  data = calculateLayout(root)
  drawCanvas(canvas, data, root)

  $('#filter-button').click ->
    rerender()

  rerender = ()->
    clearCanvas(canvas)
    data = calculateLayout(root)
    drawCanvas(canvas, data, root)

  drawCanvas = (canvas, data, root)->
    g = canvas.selectAll("g").data(data)

    g.enter().append("g").attr("transform", (d) ->
      "translate(" + x(d.y) + "," + y(d.x) + ")"
    ).on("click", (d)->
      click(d)
    ).append("rect").attr("width", root.dy * kx).attr("height", (d)->
      d.dx * ky
    )

    g.exit().remove()

    click = (d)->
      kx = (if d.y then w - 40 else w) / (1 - d.y)
      ky = h / d.dx
      x.domain([d.y, 1]).range [(if d.y then 40 else 0), w ]
      y.domain [d.x, d.x + d.dx]

      t = g.transition().duration(750).attr("transform", (d)->
        "translate(" + x(d.y) + "," + y(d.x) + ")"
      )

      t.select("rect").attr("width", (d)->
        d.dy * kx
      ).attr "height", (d)->
        d.dx * ky

      t.select("text").attr("transform", (d)->
        "translate(" + (d.x + d.dx / 2) + "," + (d.y + d.dy / 2) + ")"
      ).style "opacity", (d)->
        (if d.dx * ky > 12 then 1 else 0)

      d3.event.stopPropagation()

      return

clearCanvas = (canvas)->
  canvas.selectAll("svg").remove()
  canvas.selectAll("g").remove()
  canvas.selectAll("rect").remove()
  canvas.selectAll("text").remove()

--------------------UPDATE--------------------
I solved my initial problem of d3 saving the width and height of the groups by setting the width and height equal to the width and height of the canvas.

.append("rect").attr("width", w).attr("height", h)

This is a very hacky way, but there is no whitespace anymore after rerendering the canvas. However, the problem that arises now is that some rectangles start overlapping others resulting in not all the data being shown. This is because it renders the items hierarchically and not based on x,y position. So my question still remains:

Does D3 cache data on elements (like width)?

jvdp
  • 149
  • 8
  • Not sure what you mean by "hard refresh". To clear the data associated with an element, you either have to delete it explicitly or remove the element. – Lars Kotthoff Oct 22 '14 at 10:52
  • Hard refresh is a browser refresh, i.e. ctrl + r in chrome. I added the clearCanvas function that I use to remove elements. – jvdp Oct 22 '14 at 11:00
  • You must be binding the data in another place then. If you remove an element that had data bound to it and then add a new element of the same type, it won't have any data bound to it. – Lars Kotthoff Oct 22 '14 at 11:04
  • The only place where data is being bound to it is in the first line of the drawCanvas() – jvdp Oct 22 '14 at 11:44
  • Could you provide a complete example that demonstrates the problem please? – Lars Kotthoff Oct 22 '14 at 12:23
  • I added all the code except for the fill and text code. If you see any oddities please let me know. The html code is just a div with id canvas and a filter button. – jvdp Oct 22 '14 at 12:57

0 Answers0