123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- 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;
- }();
|