vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.9 KiB

  1. /**
  2. * Created by Alex on 3/4/2015.
  3. */
  4. var util = require("../../util");
  5. var DataSet = require('../../DataSet');
  6. var DataView = require('../../DataView');
  7. var Node = require("./components/nodes/NodeMain");
  8. class NodesHandler {
  9. constructor(body, images, groups, layoutEngine) {
  10. this.body = body;
  11. this.images = images;
  12. this.groups = groups;
  13. this.layoutEngine = layoutEngine;
  14. // create the node API in the body container
  15. this.body.functions.createNode = this.create.bind(this);
  16. this.nodesListeners = {
  17. 'add': (event, params) => {this.add(params.items);},
  18. 'update': (event, params) => {this.update(params.items, params.data);},
  19. 'remove': (event, params) => {this.remove(params.items);}
  20. };
  21. this.options = {};
  22. this.defaultOptions = {
  23. customScalingFunction: function (min,max,total,value) {
  24. if (max == min) {
  25. return 0.5;
  26. }
  27. else {
  28. var scale = 1 / (max - min);
  29. return Math.max(0,(value - min)*scale);
  30. }
  31. },
  32. mass: 1,
  33. radiusMin: 10,
  34. radiusMax: 30,
  35. radius: 10,
  36. shape: 'ellipse',
  37. image: undefined,
  38. widthMin: 16, // px
  39. widthMax: 64, // px
  40. fontColor: 'black',
  41. fontSize: 14, // px
  42. fontFace: 'verdana',
  43. fontFill: undefined,
  44. fontStrokeWidth: 0, // px
  45. fontStrokeColor: '#ffffff',
  46. fontDrawThreshold: 3,
  47. scaleFontWithValue: false,
  48. fontSizeMin: 14,
  49. fontSizeMax: 30,
  50. fontSizeMaxVisible: 30,
  51. value: 1,
  52. level: -1,
  53. color: {
  54. border: '#2B7CE9',
  55. background: '#97C2FC',
  56. highlight: {
  57. border: '#2B7CE9',
  58. background: '#D2E5FF'
  59. },
  60. hover: {
  61. border: '#2B7CE9',
  62. background: '#D2E5FF'
  63. }
  64. },
  65. group: undefined,
  66. borderWidth: 1,
  67. borderWidthSelected: undefined,
  68. physics: true,
  69. hidden: false
  70. };
  71. util.extend(this.options, this.defaultOptions);
  72. }
  73. setOptions(options) {
  74. }
  75. /**
  76. * Set a data set with nodes for the network
  77. * @param {Array | DataSet | DataView} nodes The data containing the nodes.
  78. * @private
  79. */
  80. setData(nodes) {
  81. var oldNodesData = this.body.data.nodes;
  82. if (nodes instanceof DataSet || nodes instanceof DataView) {
  83. this.body.data.nodes = nodes;
  84. }
  85. else if (Array.isArray(nodes)) {
  86. this.body.data.nodes = new DataSet();
  87. this.body.data.nodes.add(nodes);
  88. }
  89. else if (!nodes) {
  90. this.body.data.nodes = new DataSet();
  91. }
  92. else {
  93. throw new TypeError('Array or DataSet expected');
  94. }
  95. if (oldNodesData) {
  96. // unsubscribe from old dataset
  97. util.forEach(this.nodesListeners, function (callback, event) {
  98. oldNodesData.off(event, callback);
  99. });
  100. }
  101. // remove drawn nodes
  102. this.body.nodes = {};
  103. if (this.body.data.nodes) {
  104. // subscribe to new dataset
  105. var me = this;
  106. util.forEach(this.nodesListeners, function (callback, event) {
  107. me.body.data.nodes.on(event, callback);
  108. });
  109. // draw all new nodes
  110. var ids = this.body.data.nodes.getIds();
  111. this.add(ids);
  112. }
  113. this.body.emitter.emit("_dataChanged");
  114. }
  115. /**
  116. * Add nodes
  117. * @param {Number[] | String[]} ids
  118. * @private
  119. */
  120. add(ids) {
  121. var id;
  122. var newNodes = [];
  123. for (var i = 0; i < ids.length; i++) {
  124. id = ids[i];
  125. var data = this.body.data.nodes.get(id);
  126. var node = new Node(data, this.images, this.groups, this.options);
  127. newNodes.push(node);
  128. this.body.nodes[id] = node; // note: this may replace an existing node
  129. }
  130. this.layoutEngine.positionInitially(newNodes);
  131. this.body.emitter.emit("_dataChanged");
  132. }
  133. /**
  134. * Update existing nodes, or create them when not yet existing
  135. * @param {Number[] | String[]} ids
  136. * @private
  137. */
  138. update(ids, changedData) {
  139. var nodes = this.body.nodes;
  140. var dataChanged = false;
  141. for (var i = 0; i < ids.length; i++) {
  142. var id = ids[i];
  143. var node = nodes[id];
  144. var data = changedData[i];
  145. if (node !== undefined) {
  146. // update node
  147. node.setOptions(data, this.constants);
  148. }
  149. else {
  150. dataChanged = true;
  151. // create node
  152. node = new Node(properties, this.images, this.groups, this.constants);
  153. nodes[id] = node;
  154. }
  155. }
  156. if (dataChanged === true) {
  157. this.body.emitter.emit("_dataChanged");
  158. }
  159. else {
  160. this.body.emitter.emit("_dataUpdated");
  161. }
  162. }
  163. /**
  164. * Remove existing nodes. If nodes do not exist, the method will just ignore it.
  165. * @param {Number[] | String[]} ids
  166. * @private
  167. */
  168. remove(ids) {
  169. var nodes = this.body.nodes;
  170. for (let i = 0; i < ids.length; i++) {
  171. var id = ids[i];
  172. delete nodes[id];
  173. }
  174. this.body.emitter.emit("_dataChanged");
  175. }
  176. create(properties) {
  177. return new Node(properties, this.images, this.groups, this.options)
  178. }
  179. }
  180. export default NodesHandler;