layout.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. Layout = function(){
  2. this.autolayout = function()
  3. {
  4. //sets for nodes and edges
  5. var nodes = [];
  6. var links = [];
  7. //mapping between uris and nodes
  8. var nodes2uris = {};
  9. var uris2nodes = {};
  10. //radius between nodes
  11. var radius = 0;
  12. //for computing the centre of the nodes
  13. var centreX = 0;
  14. var centreY = 0;
  15. //keep track of the sources and targets for edges
  16. //there are edges between nodes and associations
  17. var edgeSource = {};
  18. var edgeTarget = {};
  19. var i = 0;
  20. for( var uri in __icons ){
  21. //ignore link iconsmoveEdgeHead
  22. var is_link = false;
  23. for (var edgeId in __edges){
  24. var edgeuri = __edgeId2linkuri(edgeId);
  25. if (edgeuri == uri){
  26. is_link = true;
  27. break;
  28. }
  29. }
  30. if (is_link){
  31. continue;
  32. }
  33. var icon = __icons[uri]['icon'];
  34. //get x and y, and add to the centre calculation
  35. var x = parseFloat(icon.getAttr('__x'));
  36. var y = parseFloat(icon.getAttr('__y'));
  37. centreX = centreX + x;
  38. centreY = centreY + y;
  39. //determine the maximum radius of a node
  40. var bbox = icon.getBBox();
  41. radius = Math.max(radius, bbox.width, bbox.height);
  42. //create the node
  43. var n = {index: i, x:x, y:y};
  44. nodes.push(n);
  45. //keep the mapping
  46. nodes2uris[n.index] = uri;
  47. uris2nodes[uri] = n.index;
  48. i = i + 1;
  49. }
  50. //find centre of the nodes for the layout
  51. centreX = centreX / nodes.length;
  52. centreY = centreY / nodes.length;
  53. //create the edges
  54. for (var edge in __edges){
  55. var start = __edges[edge]['start'];
  56. var end = __edges[edge]['end'];
  57. var source = uris2nodes[start];
  58. var target = uris2nodes[end];
  59. //associations are composed of two edges
  60. //so record the node IDs at either end
  61. //TODO: Replaceable with var linkIn = __edgeId2ends(edgeId)[0];?
  62. if (source == undefined){
  63. edgeTarget[start] = target;
  64. }
  65. if (target == undefined){
  66. edgeSource[end] = source;
  67. }
  68. }
  69. //for each association, create the link in the force graph
  70. for (var assoc in edgeSource) {
  71. var s = edgeSource[assoc];
  72. var t = edgeTarget[assoc];
  73. links.push({source: s, target: t});
  74. }
  75. //init the simulation
  76. var simulation = d3.forceSimulation(nodes)
  77. .force("charge", d3.forceManyBody().strength(10))
  78. .force("link", d3.forceLink(links).distance(20).strength(1).iterations(10))
  79. .force("collide", d3.forceCollide(radius))
  80. .force("center", d3.forceCenter(centreX, centreY))
  81. ;
  82. //stop the simulation (as we're not visualizing it)
  83. simulation.stop();
  84. //progress the simulation
  85. for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
  86. simulation.tick();
  87. }
  88. for (var i = 0; i < nodes.length; i++){
  89. var n = nodes[i];
  90. var uri = nodes2uris[n.index];
  91. var icon = __icons[uri]['icon'];
  92. var bbox = icon.getBBox();
  93. //restrict to stay in the canvas
  94. var x = (n.x > bbox.width)?n.x:bbox.width;
  95. var y = (n.y > bbox.height)?n.y:bbox.height;
  96. //move each icon
  97. //TODO: should move edges as well,
  98. //but moving the two nodes at each end of the edge
  99. //double moves the edge ends, with one overwriting
  100. //the other.
  101. //would have to break apart
  102. //functions in geometry_utils or query_response to be
  103. //able to move ends of edges independently
  104. __select([uri]);
  105. GeometryUtils.initSelectionTransformationPreviewOverlay(bbox.x,bbox.y);
  106. GeometryUtils.previewSelectionTranslation(x, y);
  107. GeometryUtils.transformSelection();
  108. GeometryUtils.hideTransformationPreviewOverlay();
  109. __select();
  110. }
  111. };
  112. return this;
  113. }();