   updateNode: (selection, type) =>
     [x, y, _] = selection.datum()
     @updatePoint [x, y], type
-    selection.attr 'class', type # skip the rendering step
+    @draw()
 
 class Annotations
-  constructor: (@grid, open, closed, paths, previous, @start, @goal, @current, forced) ->
+  constructor: (@grid) ->
+    @defineArrowheads()
+
+  update: (open, closed, paths, previous, @start, @goal, @current, forced) =>
     @open = open or []
     @closed = closed or []
     @paths = paths or []
     @previous = previous or []
     @forced = forced or []
-    @defineArrowheads()
+    @draw()
+
+  reset: =>
+    @open = @closed = @paths = @previous = @forced = []
+    @start = @goal = @current = null
+    @draw()
 
   draw: =>
-    @drawPaths @paths, 'current'
-    @drawPaths @previous, 'previous'
-    @drawSquares @closed, 'closed'
-    @drawSquares @open, 'open'
-    @drawSquares @forced, 'forced'
-    @drawSquares _.compact([@current]), 'current'
-    @drawSquares _.compact([@start]), 'start'
-    @drawSquares _.compact([@goal]), 'goal'
-
-  drawPaths: (pairs, kind) =>
-    paths = @grid.annotationSelection.selectAll("line.#{kind}")
-      .data(pairs, JSON.stringify)
+    @drawSquares()
+    @drawPaths()
+
+  drawPaths: =>
+    data = []
+    data.push [pair, 'current'] for pair in @paths
+    data.push [pair, 'previous'] for pair in @previous
+
+    paths = @grid.annotationSelection.selectAll("line")
+      .data(data, (d, i) -> JSON.stringify d[0])
 
     paths.enter()
       .append('line')


    open = []
    if $el.data('open')?
      open = _.map(@expandList($el.data('open')), @pointFromOffset)

    closed = []
    if $el.data('closed')?
      closed = _.map(@expandList($el.data('closed')), @pointFromOffset)

    forced = []
    if $el.data('forced')?
      forced = _.map(@expandList($el.data('forced')), @pointFromOffset)

    start = if $el.data('start')? then @pointFromOffset parseInt $el.data('start')
    goal = if $el.data('goal')? then @pointFromOffset parseInt $el.data('goal')
    current = if $el.data('current')? then @pointFromOffset parseInt $el.data('current')

    @map = new Map @grid, points, start, goal
    @annotations = new Annotations @grid, open, closed,
      paths, previous, start, goal, current, forced

    $el.show()
    @map.draw()
    @annotations.draw()

  pointFromOffset: (offset) =>
    [offset % @grid.width, Math.floor(offset / @grid.width)]

  expandList: (list) ->
    parts = _.map "#{list}".split(","), (part) ->

      .attr('y1', (d, i) => @lineSegment(d)[1])
      .attr('x2', (d, i) => @lineSegment(d)[2])
      .attr('y2', (d, i) => @lineSegment(d)[3])
    paths
      .attr('class', (d, i) -> d[1])
      .attr('marker-end', (d, i) -> "url(#arrowhead-#{d[1]})")
    paths.exit().remove()

  drawSquares: =>
    points = [] # first one wins if there's a duplicate
    points.push [@current[0], @current[1], 'current'] if @current
    points.push [@start[0], @start[1], 'start'] if @start
    points.push [@goal[0], @goal[1], 'goal'] if @goal
    points.push [x,y,'forced'] for [x, y] in @forced
    points.push [x,y,'open'] for [x, y] in @open
    points.push [x,y,'closed'] for [x, y] in @closed

    squares = @grid.annotationSelection.selectAll("rect")
      .data(points, (d, i) -> JSON.stringify [d[0],d[1]])
    squares.enter()
      .append('rect')
      .attr('x', (d, i) => @grid.size * d[0])
      .attr('y', (d, i) => @grid.size * d[1])
      .attr('width', @grid.size)
      .attr('height', @grid.size)
    squares.attr('class', (d, i) -> d[2])
    squares.exit().remove()

  # path goes from center of node to a little before the center of the next
  # returns [ x1, y1, x2, y2 ]
  lineSegment: (d) =>
    [ [x1, y1], [x2, y2] ] = d[0]
    dx = x2 - x1
    dy = y2 - y1
    a = Math.sqrt((dx * dx) + (dy * dy))
