class Spawn:
	def __init__ (self, width, height):
		self.width, self.height, self.spacing = self.fill = width, height, 100, d3.scale.category20 ()

		self.svg = d3.select ('body'
		) .append ('svg'
		) .attr ('width', self.width
		) .attr ('height', self.height
		) .on ('mousemove', self.mousemove
		) .on ('mousedown', self.mousedown)
		
		self.svg.append ('rect'
		) .attr ('width', self.width
		) .attr ('height', self.height)

		self.cursor = self.svg.append ('circle'
		) .attr ('r', self.spacing
		) .attr ('transform', 'translate ({}, {})' .format (self.width / 2, self.height / 2)
		) .attr ('class', 'cursor')

		self.force = d3.layout.force (
		) .size ([self.width, self.height]
		) .nodes ([{}]
		) .linkDistance (self.spacing
		) .charge (-1000
		) .on ('tick', self.tick)		

		self.nodes, self.links, self.node, self.link = self.force.nodes (), self.force.links (), self.svg.selectAll ('.node'), self.svg.selectAll ('.link')
		
		self.restart ()
		
	def mousemove (self):
		self.cursor.attr ('transform', 'translate (' + d3.mouse (self.svg.node ()) + ')')

	def mousedown (self):
		def pushLink (target):
			x, y = target.x - node.x, target.y - node.y
			if Math.sqrt (x * x + y * y) < self.spacing:
				spawn.links.push ({'source': node, 'target': target})
				
		point = d3.mouse (self.svg.node ())
		node = {'x': point [0], 'y': point [1]}
		self.nodes.push (node)
		self.nodes.forEach (pushLink)
		self.restart ()		
			
	def tick (self):
		self.link.attr ('x1', lambda d: d.source.x
		) .attr ('y1', lambda d: d.source.y
		) .attr ('x2', lambda d: d.target.x
		) .attr ('y2', lambda d: d.target.y)
			
		self.node.attr ('cx', lambda d: d.x
		) .attr ('cy', lambda d: d.y)

	def restart (self):
		self.link = self.link.data (self.links)
		
		self.link.enter (
		) .insert ('line', '.node'
		) .attr('class', 'link')

		self.node = self.node.data (self.nodes)
			
		self.node.enter (
		) .insert ('circle', '.cursor'
		) .attr ('class', 'node'
		) .attr ('r', 7
		) .call (self.force.drag)

		self.force.start ()

spawn = Spawn (window.innerWidth, window.innerHeight)
