Source: js/update.js

  1. 'use strict';
  2. /**
  3. * Create a transition if necessary.
  4. * @private
  5. * @param {D3Selection} selection
  6. * @param {string} type duration = options.transition[type]
  7. * @param {string} name
  8. * @returns {ge.GraphEditor}
  9. * @see [d3.transition]{@link https://github.com/d3/d3-transition/blob/master/README.md#api-reference}
  10. */
  11. ge.GraphEditor.prototype.transition = function transition(selection, type, name) {
  12. var duration = this.options.transition[type];
  13. if(!duration) {
  14. return selection;
  15. }
  16. /*if(this.state.simulation) {
  17. return selection;
  18. }*/
  19. return selection
  20. .transition(name)
  21. .duration(duration);
  22. };
  23. /*ge.GraphEditor.prototype.getNodeSize = function getNodeSize(node) {
  24. if(node.title === node.prevTitle) {
  25. return false;
  26. }
  27. node.prevTitle = node.title;
  28. this.tmpText.text(node.title);
  29. var bbox = this.tmpText.node().getBBox();
  30. var width;
  31. var words = node.title.split(/\s+/);
  32. if(words.length <= 1) {
  33. width = bbox.width;
  34. }
  35. else {
  36. width = Math.sqrt(bbox.width * bbox.height);
  37. var line = '';
  38. var lineWidth, prevLineWidth = 0, maxLineWidth = 0;
  39. var lines = 0;
  40. var i = 0;
  41. while(i < words.length) {
  42. if(line === '') {
  43. line = words[i];
  44. this.tmpText.text(line);
  45. prevLineWidth = this.tmpText.node().getComputedTextLength();
  46. ++i;
  47. }
  48. else {
  49. line = line.concat(' ', words[i]);
  50. this.tmpText.text(line);
  51. lineWidth = this.tmpText.node().getComputedTextLength();
  52. if(lineWidth > width) {
  53. maxLineWidth = Math.max(maxLineWidth, prevLineWidth);
  54. ++lines;
  55. line = '';
  56. }
  57. else {
  58. prevLineWidth = lineWidth;
  59. ++i;
  60. }
  61. }
  62. }
  63. width = Math.max(
  64. maxLineWidth,
  65. prevLineWidth,
  66. bbox.height * lines * 1.5
  67. );
  68. }
  69. width = Math.max(width, this.options.node.size.min);
  70. node.textSize = width;
  71. node.textSize += 2 * (node.textSize % 2) + this.options.node.border;
  72. node.textOffset = Math.floor(-node.textSize / 2);
  73. node.size = node.textSize / 1.4142;
  74. return true;
  75. };*/
  76. /**
  77. * Handle graph SVG element resize.
  78. * @returns {ge.GraphEditor}
  79. */
  80. ge.GraphEditor.prototype.resized = function resized() {
  81. this.updateExtent();
  82. this.zoom.translateTo(this.container, 0, 0);
  83. return this;
  84. };
  85. /**
  86. * Update force simulation.
  87. * @private
  88. * @returns {ge.GraphEditor}
  89. */
  90. ge.GraphEditor.prototype.updateSimulation = function updateSimulation() {
  91. if(this.state.simulation) {
  92. this.state.simulation = this.options.simulation
  93. .create.call(
  94. this,
  95. this.state.simulation,
  96. this.data.nodes,
  97. this.data.links
  98. )
  99. .alpha(1);
  100. }
  101. return this;
  102. };
  103. /**
  104. * Update bounding box.
  105. * @private
  106. * @param {Node} [node] Moved node.
  107. * @returns {ge.GraphEditor}
  108. */
  109. ge.GraphEditor.prototype.updateBBox = function updateBBox(node) {
  110. var data = this.data.nodes;
  111. var padding = this.options.bbox.padding;
  112. if(node === undefined) {
  113. var left = d3.min(data, function(d) { return d.x; });
  114. var up = d3.min(data, function(d) { return d.y; });
  115. var right = d3.max(data, function(d) { return d.x + d.width; });
  116. var down = d3.max(data, function(d) { return d.y + d.height; });
  117. this.bbox[0][0] = (left || 0) - padding;
  118. this.bbox[1][0] = (right || 0) + padding;
  119. this.bbox[0][1] = (up || 0) - padding;
  120. this.bbox[1][1] = (down || 0) + padding;
  121. }
  122. else {
  123. //console.log(node.x, node.y, node.width, node.height, padding);
  124. this.bbox[0][0] = Math.min(this.bbox[0][0], node.x - padding);
  125. this.bbox[0][1] = Math.min(this.bbox[0][1], node.y - padding);
  126. this.bbox[1][0] = Math.max(
  127. this.bbox[1][0],
  128. node.x + node.width + padding
  129. );
  130. this.bbox[1][1] = Math.max(
  131. this.bbox[1][1],
  132. node.y + node.height + padding
  133. );
  134. }
  135. this.updateExtent();
  136. this.zoom.translateExtent(this.bbox);
  137. return this;
  138. };
  139. /**
  140. * Update zoom behavior extent.
  141. * @private
  142. * @returns {ge.GraphEditor}
  143. */
  144. ge.GraphEditor.prototype.updateExtent = function updateExtent() {
  145. var bbox = this.svg.node().getBoundingClientRect();
  146. var extent = [
  147. [ 0, 0 ],
  148. [ bbox.width, bbox.height ]
  149. ];
  150. this.zoom.extent(extent);
  151. return this;
  152. };
  153. /**
  154. * Update a link.
  155. * @param {Reference} link Changed link.
  156. * @returns {ge.GraphEditor}
  157. */
  158. ge.GraphEditor.prototype.updateLink = function updateLink(link) {
  159. var self = this;
  160. var transition = function(selection) {
  161. return self.transition(selection, 'drag', 'update-link');
  162. };
  163. link = self.getElement(link);
  164. var def = d3.select(link.datum().defSelector);
  165. ge.Link.updateSelection(link, def, self.options.link, transition);
  166. return this;
  167. };
  168. /**
  169. * Update a node. If it was moved or resized, update its links.
  170. * @param {Reference} node Changed node.
  171. * @returns {ge.GraphEditor}
  172. */
  173. ge.GraphEditor.prototype.updateNode = function updateNode(node) {
  174. var self = this;
  175. node = this.getElement(node);
  176. var d = node.datum();
  177. var prevTransform = node.attr('transform');
  178. var nextTransform = 'translate('.concat(d.x, ',', d.y, ')');
  179. var prevWidth = d.width;
  180. var prevHeight = d.height;
  181. var transition = function(selection) {
  182. return self.transition(selection, 'drag', 'update-node');
  183. };
  184. ge.Node.updateSelection(node, transition, this.textSize);
  185. if(nextTransform !== prevTransform
  186. || d.width !== prevWidth
  187. || d.height !== prevHeight) {
  188. node = d;
  189. var updateLink = function(d) {
  190. return d.source === node || d.target === node;
  191. };
  192. var defs = this.defs.filter(updateLink);
  193. var links = this.links.filter(updateLink);
  194. ge.Link.updateSelection(links, defs, self.options.link, transition);
  195. /*transition(defs)
  196. .attr('d', function() { return d.shape.path(d); });
  197. transition(links.select('path'))
  198. .attr('d', function(d) { return d.path; });
  199. var offset = opt.link.text.offset;
  200. var anchor = opt.link.text.anchor;
  201. transition(links.select('textPath'))
  202. .attr('startOffset', function(d) { return offset[d.flip]; })
  203. .attr('text-anchor', function(d) { return anchor[d.flip]; });*/
  204. this.updateBBox(node);
  205. }
  206. return this;
  207. };
  208. /*ge.GraphEditor.prototype.updateSize = function updateSize(nodes, links) {
  209. nodes = nodes || this.nodes;
  210. links = links || this.links;
  211. var opt = this.options;
  212. var sizeScale = this.state.sizeScale;
  213. links.style('stroke-width', function(d) {
  214. return d.size * sizeScale + 'px';
  215. });
  216. links.select('text')
  217. .style(
  218. 'stroke-width',
  219. opt.textStrokeWidth * sizeScale + 'px'
  220. )
  221. .style(
  222. 'font-size',
  223. opt.linkFontSize * sizeScale + 'px'
  224. );
  225. nodes.select('circle')
  226. .attr('r', function(d) { return d.size * sizeScale; })
  227. .style(
  228. 'stroke-width',
  229. opt.nodeStrokeWidth * sizeScale + 'px'
  230. );
  231. nodes.select('text')
  232. .style(
  233. 'font-size',
  234. opt.fontSize * sizeScale + 'px'
  235. )
  236. .style(
  237. 'stroke-width',
  238. opt.textStrokeWidth * sizeScale + 'px'
  239. );
  240. return this;
  241. };*/
  242. /**
  243. * Update everything.
  244. * @param {boolean} [simulation=false] True if called from the simulation tick handler.
  245. * @returns {ge.GraphEditor}
  246. */
  247. ge.GraphEditor.prototype.update = function update(simulation) {
  248. var self = this;
  249. var opt = this.options;
  250. var ttype = simulation ? 'simulation' : 'drag';
  251. var transition = function(selection) {
  252. return self.transition(selection, ttype, 'update');
  253. };
  254. this.nodes = this.nodes.data(this.data.nodes, ge.id);
  255. this.nodes.exit().remove();
  256. var newNodes = this.nodes.enter()
  257. .append('g')
  258. .classed(opt.css.node, true);
  259. ge.Node.initSelection(newNodes);
  260. this.nodes = newNodes.merge(this.nodes);
  261. ge.Node.updateSelection(this.nodes, transition, this.textSize);
  262. this.nodeEvents(newNodes);
  263. this.defs = this.defs.data(this.data.links, ge.id);
  264. this.defs.exit().remove();
  265. var newDefs = this.defs.enter().append('path');
  266. this.links = this.links.data(this.data.links, ge.id);
  267. this.links.exit().remove();
  268. var newLinks = this.links.enter()
  269. .append('g')
  270. .classed(opt.css.link, true);
  271. ge.Link.initSelection(newLinks, newDefs, opt.link);
  272. this.links = this.links.merge(newLinks);
  273. this.defs = this.defs.merge(newDefs);
  274. ge.Link.updateSelection(this.links, this.defs, opt.link, transition);
  275. this.linkEvents(newLinks);
  276. //this.updateSize(newNodes, newLinks);
  277. this.updateBBox();
  278. if(!simulation) {
  279. this.updateSimulation();
  280. this.selectNode(this.state.selectedNode, true);
  281. }
  282. return this;
  283. };