|
@@ -1,10 +1,11 @@
|
|
|
define(["d3"], function (d3) {
|
|
|
var margin = 200
|
|
|
+ var NODE_RADIUS = 15
|
|
|
+ var LINE_RADIUS = 12
|
|
|
|
|
|
return function (config, linkScale, sidebar, router) {
|
|
|
var self = this
|
|
|
- var svg, canvas, ctx, screenRect
|
|
|
- var svgNodes, svgLinks
|
|
|
+ var canvas, ctx, screenRect
|
|
|
var nodesDict, linksDict
|
|
|
var zoomBehavior
|
|
|
var force
|
|
@@ -18,6 +19,8 @@ define(["d3"], function (d3) {
|
|
|
var nodes = []
|
|
|
var unknownNodes = []
|
|
|
|
|
|
+ var draggedNode
|
|
|
+
|
|
|
var LINK_DISTANCE = 70
|
|
|
|
|
|
function graphDiameter(nodes) {
|
|
@@ -42,20 +45,39 @@ define(["d3"], function (d3) {
|
|
|
return d.o.id
|
|
|
}
|
|
|
|
|
|
- function dragstart(d) {
|
|
|
+ function dragstart() {
|
|
|
+ var e = translateXY(d3.mouse(el))
|
|
|
+
|
|
|
+ var nodes = intNodes.filter(function (d) {
|
|
|
+ return distancePoint(e, d) < NODE_RADIUS
|
|
|
+ })
|
|
|
+
|
|
|
+ if (nodes.length === 0)
|
|
|
+ return
|
|
|
+
|
|
|
+ draggedNode = nodes[0]
|
|
|
d3.event.sourceEvent.stopPropagation()
|
|
|
- d.fixed |= 2
|
|
|
+ d3.event.sourceEvent.preventDefault()
|
|
|
+ draggedNode.fixed |= 2
|
|
|
}
|
|
|
|
|
|
- function dragmove(d) {
|
|
|
- d.px = d3.event.x
|
|
|
- d.py = d3.event.y
|
|
|
- force.resume()
|
|
|
+ function dragmove() {
|
|
|
+ if (draggedNode) {
|
|
|
+ var e = translateXY(d3.mouse(el))
|
|
|
+
|
|
|
+ draggedNode.px = e.x
|
|
|
+ draggedNode.py = e.y
|
|
|
+ force.resume()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- function dragend(d) {
|
|
|
- d3.event.sourceEvent.stopPropagation()
|
|
|
- d.fixed &= 1
|
|
|
+ function dragend() {
|
|
|
+ if (draggedNode) {
|
|
|
+ d3.event.sourceEvent.stopPropagation()
|
|
|
+ d3.event.sourceEvent.preventDefault()
|
|
|
+ draggedNode.fixed &= 1
|
|
|
+ draggedNode = undefined
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
var draggableNode = d3.behavior.drag()
|
|
@@ -112,9 +134,6 @@ define(["d3"], function (d3) {
|
|
|
right: (canvas.width - translate[0]) / scale,
|
|
|
bottom: (canvas.height - translate[1]) / scale}
|
|
|
|
|
|
- svg.attr("transform", "translate(" + translate + ") " +
|
|
|
- "scale(" + scale + ")")
|
|
|
-
|
|
|
redraw()
|
|
|
}
|
|
|
|
|
@@ -183,38 +202,6 @@ define(["d3"], function (d3) {
|
|
|
panzoomTo([0, 0], force.size())
|
|
|
}
|
|
|
|
|
|
- function updateLinks(vis, data) {
|
|
|
- var link = vis.selectAll("line")
|
|
|
- .data(data, function (d) { return d.o.id })
|
|
|
-
|
|
|
- link.exit().remove()
|
|
|
-
|
|
|
- link.enter().append("line")
|
|
|
- .on("click", function (d) {
|
|
|
- if (!d3.event.defaultPrevented)
|
|
|
- router.link(d.o)()
|
|
|
- })
|
|
|
-
|
|
|
- return link
|
|
|
- }
|
|
|
-
|
|
|
- function updateNodes(vis, data) {
|
|
|
- var node = vis.selectAll("circle")
|
|
|
- .data(data, function(d) { return d.o.id })
|
|
|
-
|
|
|
- node.exit().remove()
|
|
|
-
|
|
|
- node.enter().append("circle")
|
|
|
- .attr("r", 12)
|
|
|
- .on("click", function (d) {
|
|
|
- if (!d3.event.defaultPrevented)
|
|
|
- router.node(d.o.node)()
|
|
|
- })
|
|
|
- .call(draggableNode)
|
|
|
-
|
|
|
- return node
|
|
|
- }
|
|
|
-
|
|
|
function drawLabel(d) {
|
|
|
var sum = d.neighbours.reduce(function (a, b) {
|
|
|
return [a[0] + b.x, a[1] + b.y]
|
|
@@ -354,14 +341,6 @@ define(["d3"], function (d3) {
|
|
|
|
|
|
function tickEvent() {
|
|
|
redraw()
|
|
|
-
|
|
|
- svgLinks.attr("x1", function(d) { return d.source.x })
|
|
|
- .attr("y1", function(d) { return d.source.y })
|
|
|
- .attr("x2", function(d) { return d.target.x })
|
|
|
- .attr("y2", function(d) { return d.target.y })
|
|
|
-
|
|
|
- svgNodes.attr("cx", function (d) { return d.x })
|
|
|
- .attr("cy", function (d) { return d.y })
|
|
|
}
|
|
|
|
|
|
function resizeCanvas() {
|
|
@@ -375,6 +354,68 @@ define(["d3"], function (d3) {
|
|
|
redraw()
|
|
|
}
|
|
|
|
|
|
+ function distance(a, b) {
|
|
|
+ return Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)
|
|
|
+ }
|
|
|
+
|
|
|
+ function distancePoint(a, b) {
|
|
|
+ return Math.sqrt(distance(a, b))
|
|
|
+ }
|
|
|
+
|
|
|
+ function distanceLink(p, a, b) {
|
|
|
+ /* http://stackoverflow.com/questions/849211 */
|
|
|
+
|
|
|
+ var l2 = distance(a, b)
|
|
|
+
|
|
|
+ if (l2 === 0)
|
|
|
+ return distance(p, a)
|
|
|
+
|
|
|
+ var t = ((p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y)) / l2
|
|
|
+
|
|
|
+ if (t < 0)
|
|
|
+ return distance(p, a)
|
|
|
+
|
|
|
+ if (t > 1)
|
|
|
+ return distance(p, b)
|
|
|
+
|
|
|
+ return Math.sqrt(distance(p, { x: a.x + t * (b.x - a.x),
|
|
|
+ y: a.y + t * (b.y - a.y) }))
|
|
|
+ }
|
|
|
+
|
|
|
+ function translateXY(d) {
|
|
|
+ var translate = zoomBehavior.translate()
|
|
|
+ var scale = zoomBehavior.scale()
|
|
|
+
|
|
|
+ return {x: (d[0] - translate[0]) / scale,
|
|
|
+ y: (d[1] - translate[1]) / scale
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function onClick() {
|
|
|
+ if (d3.event.defaultPrevented)
|
|
|
+ return
|
|
|
+
|
|
|
+ var e = translateXY(d3.mouse(el))
|
|
|
+
|
|
|
+ var nodes = intNodes.filter(function (d) {
|
|
|
+ return distancePoint(e, d) < NODE_RADIUS
|
|
|
+ })
|
|
|
+
|
|
|
+ if (nodes.length > 0) {
|
|
|
+ router.node(nodes[0].o.node)()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var links = intLinks.filter(function (d) {
|
|
|
+ return distanceLink(e, d.source, d.target) < LINE_RADIUS
|
|
|
+ })
|
|
|
+
|
|
|
+ if (links.length > 0) {
|
|
|
+ router.link(links[0].o)()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
el = document.createElement("div")
|
|
|
el.classList.add("graph")
|
|
|
self.div = el
|
|
@@ -384,15 +425,13 @@ define(["d3"], function (d3) {
|
|
|
.on("zoom", panzoom)
|
|
|
.translate([sidebar.getWidth(), 0])
|
|
|
|
|
|
- canvas = d3.select(el).append("canvas").node()
|
|
|
-
|
|
|
- svg = d3.select(el).append("svg")
|
|
|
- .attr("pointer-events", "all")
|
|
|
- .call(zoomBehavior)
|
|
|
- .append("g")
|
|
|
-
|
|
|
- var visLinks = svg.append("g")
|
|
|
- var visNodes = svg.append("g")
|
|
|
+ canvas = d3.select(el)
|
|
|
+ .call(zoomBehavior)
|
|
|
+ .append("canvas")
|
|
|
+ .attr("pointer-events", "all")
|
|
|
+ .on("click", onClick)
|
|
|
+ .call(draggableNode)
|
|
|
+ .node()
|
|
|
|
|
|
ctx = canvas.getContext("2d")
|
|
|
|
|
@@ -512,9 +551,6 @@ define(["d3"], function (d3) {
|
|
|
})
|
|
|
})
|
|
|
|
|
|
- svgLinks = updateLinks(visLinks, intLinks)
|
|
|
- svgNodes = updateNodes(visNodes, intNodes)
|
|
|
-
|
|
|
nodes = intNodes.filter(function (d) { return d.o.node })
|
|
|
unknownNodes = intNodes.filter(function (d) { return !d.o.node })
|
|
|
|
|
@@ -570,7 +606,6 @@ define(["d3"], function (d3) {
|
|
|
force.stop()
|
|
|
canvas.remove()
|
|
|
force = null
|
|
|
- svg = null
|
|
|
}
|
|
|
|
|
|
return self
|