Nodes.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* *
  2. *
  3. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4. *
  5. * */
  6. 'use strict';
  7. import H from '../Core/Globals.js';
  8. import Point from '../Core/Series/Point.js';
  9. import Series from '../Core/Series/Series.js';
  10. import U from '../Core/Utilities.js';
  11. var defined = U.defined, extend = U.extend, find = U.find, pick = U.pick;
  12. var NodesMixin = H.NodesMixin = {
  13. /* eslint-disable valid-jsdoc */
  14. /**
  15. * Create a single node that holds information on incoming and outgoing
  16. * links.
  17. * @private
  18. */
  19. createNode: function (id) {
  20. /**
  21. * @private
  22. */
  23. function findById(nodes, id) {
  24. return find(nodes, function (node) {
  25. return node.id === id;
  26. });
  27. }
  28. var node = findById(this.nodes, id), PointClass = this.pointClass, options;
  29. if (!node) {
  30. options = this.options.nodes && findById(this.options.nodes, id);
  31. node = (new PointClass()).init(this, extend({
  32. className: 'highcharts-node',
  33. isNode: true,
  34. id: id,
  35. y: 1 // Pass isNull test
  36. }, options));
  37. node.linksTo = [];
  38. node.linksFrom = [];
  39. node.formatPrefix = 'node';
  40. node.name = node.name || node.options.id || ''; // for use in formats
  41. // Mass is used in networkgraph:
  42. node.mass = pick(
  43. // Node:
  44. node.options.mass, node.options.marker && node.options.marker.radius,
  45. // Series:
  46. this.options.marker && this.options.marker.radius,
  47. // Default:
  48. 4);
  49. /**
  50. * Return the largest sum of either the incoming or outgoing links.
  51. * @private
  52. */
  53. node.getSum = function () {
  54. var sumTo = 0, sumFrom = 0;
  55. node.linksTo.forEach(function (link) {
  56. sumTo += link.weight;
  57. });
  58. node.linksFrom.forEach(function (link) {
  59. sumFrom += link.weight;
  60. });
  61. return Math.max(sumTo, sumFrom);
  62. };
  63. /**
  64. * Get the offset in weight values of a point/link.
  65. * @private
  66. */
  67. node.offset = function (point, coll) {
  68. var offset = 0;
  69. for (var i = 0; i < node[coll].length; i++) {
  70. if (node[coll][i] === point) {
  71. return offset;
  72. }
  73. offset += node[coll][i].weight;
  74. }
  75. };
  76. // Return true if the node has a shape, otherwise all links are
  77. // outgoing.
  78. node.hasShape = function () {
  79. var outgoing = 0;
  80. node.linksTo.forEach(function (link) {
  81. if (link.outgoing) {
  82. outgoing++;
  83. }
  84. });
  85. return (!node.linksTo.length ||
  86. outgoing !== node.linksTo.length);
  87. };
  88. this.nodes.push(node);
  89. }
  90. return node;
  91. },
  92. /**
  93. * Extend generatePoints by adding the nodes, which are Point objects
  94. * but pushed to the this.nodes array.
  95. */
  96. generatePoints: function () {
  97. var chart = this.chart, nodeLookup = {};
  98. Series.prototype.generatePoints.call(this);
  99. if (!this.nodes) {
  100. this.nodes = []; // List of Point-like node items
  101. }
  102. this.colorCounter = 0;
  103. // Reset links from previous run
  104. this.nodes.forEach(function (node) {
  105. node.linksFrom.length = 0;
  106. node.linksTo.length = 0;
  107. node.level = node.options.level;
  108. });
  109. // Create the node list and set up links
  110. this.points.forEach(function (point) {
  111. if (defined(point.from)) {
  112. if (!nodeLookup[point.from]) {
  113. nodeLookup[point.from] = this.createNode(point.from);
  114. }
  115. nodeLookup[point.from].linksFrom.push(point);
  116. point.fromNode = nodeLookup[point.from];
  117. // Point color defaults to the fromNode's color
  118. if (chart.styledMode) {
  119. point.colorIndex = pick(point.options.colorIndex, nodeLookup[point.from].colorIndex);
  120. }
  121. else {
  122. point.color =
  123. point.options.color || nodeLookup[point.from].color;
  124. }
  125. }
  126. if (defined(point.to)) {
  127. if (!nodeLookup[point.to]) {
  128. nodeLookup[point.to] = this.createNode(point.to);
  129. }
  130. nodeLookup[point.to].linksTo.push(point);
  131. point.toNode = nodeLookup[point.to];
  132. }
  133. point.name = point.name || point.id; // for use in formats
  134. }, this);
  135. // Store lookup table for later use
  136. this.nodeLookup = nodeLookup;
  137. },
  138. // Destroy all nodes on setting new data
  139. setData: function () {
  140. if (this.nodes) {
  141. this.nodes.forEach(function (node) {
  142. node.destroy();
  143. });
  144. this.nodes.length = 0;
  145. }
  146. Series.prototype.setData.apply(this, arguments);
  147. },
  148. // Destroy alll nodes and links
  149. destroy: function () {
  150. // Nodes must also be destroyed (#8682, #9300)
  151. this.data = []
  152. .concat(this.points || [], this.nodes);
  153. return Series.prototype.destroy.apply(this, arguments);
  154. },
  155. /**
  156. * When hovering node, highlight all connected links. When hovering a link,
  157. * highlight all connected nodes.
  158. */
  159. setNodeState: function (state) {
  160. var args = arguments, others = this.isNode ? this.linksTo.concat(this.linksFrom) :
  161. [this.fromNode, this.toNode];
  162. if (state !== 'select') {
  163. others.forEach(function (linkOrNode) {
  164. if (linkOrNode && linkOrNode.series) {
  165. Point.prototype.setState.apply(linkOrNode, args);
  166. if (!linkOrNode.isNode) {
  167. if (linkOrNode.fromNode.graphic) {
  168. Point.prototype.setState.apply(linkOrNode.fromNode, args);
  169. }
  170. if (linkOrNode.toNode && linkOrNode.toNode.graphic) {
  171. Point.prototype.setState.apply(linkOrNode.toNode, args);
  172. }
  173. }
  174. }
  175. });
  176. }
  177. Point.prototype.setState.apply(this, args);
  178. }
  179. /* eslint-enable valid-jsdoc */
  180. };
  181. export default NodesMixin;