       voronoiPatches
         .on('mouseover', (d) ->
           d.active = true
-          d.fixed = true
-          force.start()
+
+          scaleD = (other) ->
+            selectedPos = [xScale(d.x), yScale(d.y)]
+            pos = [xScale(other.x), yScale(other.y)]
+            diff = vSub(pos, selectedPos)
+            dist = vNorm(diff)
+            theShift = outerRadius*shift(outerRadius/2)(dist/outerRadius)
+            _.object ['x','y'], vAdd(pos, vScale(theShift/dist, diff))
+
+          xScaleD = (d) -> scaleD(d).x
+          yScaleD = (d) -> scaleD(d).y
+
+          duration = 500
+          n = nodes.length
+
+          angle = (doc, other) ->
+            diff = vSub([doc.x, doc.y], [other.x, other.y])
+            unitDiff = vScale(1/vNorm(diff), diff)
+            alpha = Math.acos(vDot([0, 1], unitDiff)) / Math.PI * 180
+            alpha = if diff[0] <= 0 then alpha else 360 - alpha
+
+          node
+            .sort((doc, other) ->
+              # sort by distance to selected
+              d3.descending(euclideanDistance([d.x, d.y], [doc.x, doc.y]), euclideanDistance([d.x, d.y], [other.x, other.y])))
+            .transition()
+              .duration((doc, i) ->
+                duration)
+              .delay((doc, i) -> # calculate angle to basis vector
+                return 0 if doc == d
+                dist = euclideanDistance([xScale(d.x), yScale(d.y)], [xScale(doc.x), yScale(doc.y)])
+                # distDelay = d3.scale.linear().domain([0, minSide]).range([0, duration])(dist)
+                console.log dist, gaussian(outerRadius*3, 2)(dist)*1000
+                gaussian(outerRadius*3, 2)(dist)*1000 # works pretty well... FIXME to many magic numbers
+              )
+              .attr 'transform', (d) ->
+                'translate(' + xScaleD(d) + ',' + yScaleD(d) + ')'
+
+          # force.start()
           updateActive()
         )
         .on('mouseout', (d) ->
           d.active = false
-          d.fixed = false
+          # d.fixed = false
           updateActive()
         )
 
+      # x + sign(x)*2(1-sigmoid(|x|))
+      shift = (offset) -> (x) ->
+        if x < 1e-10
+          0
+        else
+          Math.sign(x)*2*(1-sigmoid(Math.abs(x)-offset))
+
       calculateVoronoiThrottled = _.throttle(calculateVoronoi, 200)
 
       force.on 'tick', ->
+        console.log 'tick'
+        # smooth the layout change with inertia
+        rate = 0.8
+        smooth = (previous, next) -> (1 - rate) * previous + rate * next
+        xScale.domain(_.zipWith(xScale.domain(), d3.extent(nodes, (n) -> n.x), smooth))
+        yScale.domain(_.zipWith(yScale.domain(), d3.extent(nodes, (n) -> n.y), smooth))
+
         # link.attr('x1', (d) ->
-        #   d.source.x
+        #   xScale d.source.x
         # ).attr('y1', (d) ->
-        #   d.source.y
+        #   yScale d.source.y
         # ).attr('x2', (d) ->
-        #   d.target.x
+        #   xScale d.target.x
         # ).attr 'y2', (d) ->
-        #   d.target.y
+        #   yScale d.target.y
+
         node.attr 'transform', (d) ->
-          'translate(' + d.x + ',' + d.y + ')'
+          'translate(' + xScaleD(d) + ',' + yScaleD(d) + ')'
 
         hulls.attr "d", (d) ->
           [party, articles] = d

        .outerRadius(outerRadius)
      force
        .linkDistance((l) -> l.distance)
        .charge((n) -> if n.active then -150 else -30) # fush nodes away from selected node
        # TODO try friction based on mouse distance
        .nodes(nodes)
        .links(links)
        .start()

      # voronoi
      voronoi = d3.geom.voronoi().x((n) -> n.x).y((n) -> n.y)
      calculateVoronoi = ->
        _.zipWith(nodes, voronoi(nodes), (node, patch) -> node.voronoiArea = patch)
      calculateVoronoi()

      # hulls
      hulls = svg.selectAll('.hull').data(_.pairs(byParty)).enter().append('path').attr('class', (d) -> [party, articles] = d; "hull #{party}")
      hull = d3.geom.hull().x((node) -> node.x).y((node) -> node.y)
      hullArea = d3.svg.line().x((n) -> n.x).y((n) -> n.y).interpolate('linear-closed')
      updateActive = ->
        node.sort((d, o) -> +d.active * 2 - 1) # map true, false to 1 and -1
        voronoiPatches.classed('active', (d) -> d.active)
        _.delay -> node.classed('active', (d) -> d.active) # delay to ensure css animations still work

      # link = svg.selectAll('.link').data(links).enter().append('line').attr('class', 'link')
      node = svg.selectAll('.node').data(nodes).enter().append('g').attr('class', (d) -> 'node ' + d.predictedLabel).call(force.drag)
      node.append('circle').attr('class', 'selectionIndicator').attr('cx', 0).attr('cy', 0).attr('r', circleSize * 4)
      titles = node.append('g').attr('class', 'title')
      titles

    height = 800
    diag = Math.sqrt(width**2+height**2)
    minSide = Math.min(width, height)
    border = 100
    xScale = d3.scale.linear().range([border, width-border])
    yScale = d3.scale.linear().range([border, height-border])
    xScaleD = (doc) -> xScale(doc.x)
    yScaleD = (doc) -> yScale(doc.y)

    svg = d3.select(elem[0]).append('svg')
      .attr('width', width)
      .attr('height', height)
    force = d3.layout.force()
      # .gravity(.1)
      # .charge(-30)
      .size([width, height])
    # preparing the pies
    pie = d3.layout.pie()
