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.

219 lines
5.2 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. label: undefined,
  41. labelStyle: {
  42. fontColor: 'black',
  43. fontSize: 14, // px
  44. fontFace: 'verdana',
  45. fontFill: undefined,
  46. fontStrokeWidth: 0, // px
  47. fontStrokeColor: '#ffffff',
  48. scaleFontWithValue: false,
  49. fontSizeMin: 14,
  50. fontSizeMax: 30,
  51. fontSizeMaxVisible: 30,
  52. fontDrawThreshold: 3
  53. },
  54. value: 1,
  55. color: {
  56. border: '#2B7CE9',
  57. background: '#97C2FC',
  58. highlight: {
  59. border: '#2B7CE9',
  60. background: '#D2E5FF'
  61. },
  62. hover: {
  63. border: '#2B7CE9',
  64. background: '#D2E5FF'
  65. }
  66. },
  67. group: undefined,
  68. borderWidth: 1,
  69. borderWidthSelected: undefined,
  70. physics: true,
  71. hidden: false,
  72. icon: {
  73. iconFontFace: undefined, //'FontAwesome',
  74. code: undefined, //'\uf007',
  75. iconSize: undefined, //50,
  76. iconColor: undefined //'#aa00ff'
  77. }
  78. };
  79. util.extend(this.options, this.defaultOptions);
  80. }
  81. setOptions(options) {
  82. }
  83. /**
  84. * Set a data set with nodes for the network
  85. * @param {Array | DataSet | DataView} nodes The data containing the nodes.
  86. * @private
  87. */
  88. setData(nodes) {
  89. var oldNodesData = this.body.data.nodes;
  90. if (nodes instanceof DataSet || nodes instanceof DataView) {
  91. this.body.data.nodes = nodes;
  92. }
  93. else if (Array.isArray(nodes)) {
  94. this.body.data.nodes = new DataSet();
  95. this.body.data.nodes.add(nodes);
  96. }
  97. else if (!nodes) {
  98. this.body.data.nodes = new DataSet();
  99. }
  100. else {
  101. throw new TypeError('Array or DataSet expected');
  102. }
  103. if (oldNodesData) {
  104. // unsubscribe from old dataset
  105. util.forEach(this.nodesListeners, function (callback, event) {
  106. oldNodesData.off(event, callback);
  107. });
  108. }
  109. // remove drawn nodes
  110. this.body.nodes = {};
  111. if (this.body.data.nodes) {
  112. // subscribe to new dataset
  113. var me = this;
  114. util.forEach(this.nodesListeners, function (callback, event) {
  115. me.body.data.nodes.on(event, callback);
  116. });
  117. // draw all new nodes
  118. var ids = this.body.data.nodes.getIds();
  119. this.add(ids);
  120. }
  121. this.body.emitter.emit("_dataChanged");
  122. }
  123. /**
  124. * Add nodes
  125. * @param {Number[] | String[]} ids
  126. * @private
  127. */
  128. add(ids) {
  129. var id;
  130. var newNodes = [];
  131. for (var i = 0; i < ids.length; i++) {
  132. id = ids[i];
  133. var data = this.body.data.nodes.get(id);
  134. var node = new Node(data, this.images, this.groups, this.options);
  135. newNodes.push(node);
  136. this.body.nodes[id] = node; // note: this may replace an existing node
  137. }
  138. this.layoutEngine.positionInitially(newNodes);
  139. this.body.emitter.emit("_dataChanged");
  140. }
  141. /**
  142. * Update existing nodes, or create them when not yet existing
  143. * @param {Number[] | String[]} ids
  144. * @private
  145. */
  146. update(ids, changedData) {
  147. var nodes = this.body.nodes;
  148. var dataChanged = false;
  149. for (var i = 0; i < ids.length; i++) {
  150. var id = ids[i];
  151. var node = nodes[id];
  152. var data = changedData[i];
  153. if (node !== undefined) {
  154. // update node
  155. node.setOptions(data, this.constants);
  156. }
  157. else {
  158. dataChanged = true;
  159. // create node
  160. node = new Node(properties, this.images, this.groups, this.constants);
  161. nodes[id] = node;
  162. }
  163. }
  164. if (dataChanged === true) {
  165. this.body.emitter.emit("_dataChanged");
  166. }
  167. else {
  168. this.body.emitter.emit("_dataUpdated");
  169. }
  170. }
  171. /**
  172. * Remove existing nodes. If nodes do not exist, the method will just ignore it.
  173. * @param {Number[] | String[]} ids
  174. * @private
  175. */
  176. remove(ids) {
  177. var nodes = this.body.nodes;
  178. for (let i = 0; i < ids.length; i++) {
  179. var id = ids[i];
  180. delete nodes[id];
  181. }
  182. this.body.emitter.emit("_dataChanged");
  183. }
  184. create(properties) {
  185. return new Node(properties, this.images, this.groups, this.options)
  186. }
  187. }
  188. export default NodesHandler;