|
@@ -0,0 +1,153 @@
|
|
|
+Layout = function(){
|
|
|
+
|
|
|
+
|
|
|
+ this.autolayout = function()
|
|
|
+ {
|
|
|
+
|
|
|
+ //sets for nodes and edges
|
|
|
+ var nodes = [];
|
|
|
+ var links = [];
|
|
|
+
|
|
|
+ //mapping between uris and nodes
|
|
|
+ var nodes2uris = {};
|
|
|
+ var uris2nodes = {};
|
|
|
+
|
|
|
+ //radius between nodes
|
|
|
+ var radius = 0;
|
|
|
+
|
|
|
+ //for computing the centre of the nodes
|
|
|
+ var centreX = 0;
|
|
|
+ var centreY = 0;
|
|
|
+
|
|
|
+ //keep track of the sources and targets for edges
|
|
|
+ //there are edges between nodes and associations
|
|
|
+ var edgeSource = {};
|
|
|
+ var edgeTarget = {};
|
|
|
+
|
|
|
+ var i = 0;
|
|
|
+ for( var uri in __icons ){
|
|
|
+
|
|
|
+ //ignore link iconsmoveEdgeHead
|
|
|
+ var is_link = false;
|
|
|
+ for (var edgeId in __edges){
|
|
|
+ var edgeuri = __edgeId2linkuri(edgeId);
|
|
|
+ if (edgeuri == uri){
|
|
|
+ is_link = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (is_link){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var icon = __icons[uri]['icon'];
|
|
|
+
|
|
|
+
|
|
|
+ //get x and y, and add to the centre calculation
|
|
|
+ var x = parseFloat(icon.getAttr('__x'));
|
|
|
+ var y = parseFloat(icon.getAttr('__y'));
|
|
|
+
|
|
|
+ centreX = centreX + x;
|
|
|
+ centreY = centreY + y;
|
|
|
+
|
|
|
+ //determine the maximum radius of a node
|
|
|
+ var bbox = icon.getBBox();
|
|
|
+ radius = Math.max(radius, bbox.width, bbox.height);
|
|
|
+
|
|
|
+ //create the node
|
|
|
+ var n = {index: i, x:x, y:y};
|
|
|
+ nodes.push(n);
|
|
|
+
|
|
|
+ //keep the mapping
|
|
|
+ nodes2uris[n.index] = uri;
|
|
|
+ uris2nodes[uri] = n.index;
|
|
|
+
|
|
|
+ i = i + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ //find centre of the nodes for the layout
|
|
|
+ centreX = centreX / nodes.length;
|
|
|
+ centreY = centreY / nodes.length;
|
|
|
+
|
|
|
+
|
|
|
+ //create the edges
|
|
|
+ for (var edge in __edges){
|
|
|
+
|
|
|
+ var start = __edges[edge]['start'];
|
|
|
+ var end = __edges[edge]['end'];
|
|
|
+
|
|
|
+ var source = uris2nodes[start];
|
|
|
+ var target = uris2nodes[end];
|
|
|
+
|
|
|
+ //associations are composed of two edges
|
|
|
+ //so record the node IDs at either end
|
|
|
+ //TODO: Replaceable with var linkIn = __edgeId2ends(edgeId)[0];?
|
|
|
+ if (source == undefined){
|
|
|
+ edgeTarget[start] = target;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target == undefined){
|
|
|
+ edgeSource[end] = source;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //for each association, create the link in the force graph
|
|
|
+ for (var assoc in edgeSource) {
|
|
|
+
|
|
|
+ var s = edgeSource[assoc];
|
|
|
+ var t = edgeTarget[assoc];
|
|
|
+
|
|
|
+ links.push({source: s, target: t})
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //init the simulation
|
|
|
+ var simulation = d3.forceSimulation(nodes)
|
|
|
+ .force("charge", d3.forceManyBody().strength(10))
|
|
|
+ .force("link", d3.forceLink(links).distance(20).strength(1).iterations(10))
|
|
|
+ .force("collide", d3.forceCollide(radius))
|
|
|
+ .force("center", d3.forceCenter(centreX, centreY))
|
|
|
+ ;
|
|
|
+
|
|
|
+ //stop the simulation (as we're not visualizing it)
|
|
|
+ simulation.stop();
|
|
|
+
|
|
|
+ //progress the simulation
|
|
|
+ for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
|
|
|
+ simulation.tick();
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var i = 0; i < nodes.length; i++){
|
|
|
+
|
|
|
+ var n = nodes[i];
|
|
|
+ var uri = nodes2uris[n.index];
|
|
|
+
|
|
|
+
|
|
|
+ var icon = __icons[uri]['icon'];
|
|
|
+ var bbox = icon.getBBox();
|
|
|
+
|
|
|
+ //restrict to stay in the canvas
|
|
|
+ var x = (n.x > bbox.width)?n.x:bbox.width;
|
|
|
+ var y = (n.y > bbox.height)?n.y:bbox.height;
|
|
|
+
|
|
|
+ //move each icon
|
|
|
+ //TODO: should move edges as well,
|
|
|
+ //but moving the two nodes at each end of the edge
|
|
|
+ //double moves the edge ends, with one overwriting
|
|
|
+ //the other.
|
|
|
+ //would have to break apart
|
|
|
+ //functions in geometry_utils or query_response to be
|
|
|
+ //able to move ends of edges independently
|
|
|
+ __select([uri]);
|
|
|
+ GeometryUtils.initSelectionTransformationPreviewOverlay(bbox.x,bbox.y);
|
|
|
+ GeometryUtils.previewSelectionTranslation(x, y);
|
|
|
+ GeometryUtils.transformSelection();
|
|
|
+
|
|
|
+ GeometryUtils.hideTransformationPreviewOverlay();
|
|
|
+ __select();
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ return this;
|
|
|
+}();
|