d3.js - data on selection is stored after hard refresh

270 Views Asked by At

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)?

0

There are 0 best solutions below