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.

232 lines
5.4 KiB

9 years ago
9 years ago
  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. import Node from "./components/Node";
  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. borderWidth: 1,
  24. borderWidthSelected: undefined,
  25. color: {
  26. border: '#2B7CE9',
  27. background: '#97C2FC',
  28. highlight: {
  29. border: '#2B7CE9',
  30. background: '#D2E5FF'
  31. },
  32. hover: {
  33. border: '#2B7CE9',
  34. background: '#D2E5FF'
  35. }
  36. },
  37. fixed: {
  38. x:false,
  39. y:false
  40. },
  41. font: {
  42. color: '#343434',
  43. size: 14, // px
  44. face: 'arial',
  45. background: 'none',
  46. stroke: 0, // px
  47. strokeColor: 'white',
  48. align: 'horizontal'
  49. },
  50. group: undefined,
  51. hidden: false,
  52. icon: {
  53. fontFace: undefined, //'FontAwesome',
  54. code: undefined, //'\uf007',
  55. size: undefined, //50,
  56. color: undefined //'#aa00ff'
  57. },
  58. image: undefined, // --> URL
  59. label: undefined,
  60. mass: 1,
  61. physics: true,
  62. scaling: {
  63. min: 10,
  64. max: 40,
  65. label: {
  66. enabled: true,
  67. min: 14,
  68. max: 30,
  69. maxVisible: 30,
  70. drawThreshold: 3
  71. },
  72. customScalingFunction: function (min,max,total,value) {
  73. if (max == min) {
  74. return 0.5;
  75. }
  76. else {
  77. var scale = 1 / (max - min);
  78. return Math.max(0,(value - min)*scale);
  79. }
  80. }
  81. },
  82. shape: 'ellipse',
  83. size: 10,
  84. value: 1
  85. };
  86. util.extend(this.options, this.defaultOptions);
  87. this.setOptions(options);
  88. }
  89. setOptions(options) {
  90. if (options) {
  91. util.selectiveNotDeepExtend(['color'], this.options, options);
  92. if (options.color) {
  93. this.options.color = util.parseColor(options.color);
  94. }
  95. }
  96. }
  97. /**
  98. * Set a data set with nodes for the network
  99. * @param {Array | DataSet | DataView} nodes The data containing the nodes.
  100. * @private
  101. */
  102. setData(nodes) {
  103. var oldNodesData = this.body.data.nodes;
  104. if (nodes instanceof DataSet || nodes instanceof DataView) {
  105. this.body.data.nodes = nodes;
  106. }
  107. else if (Array.isArray(nodes)) {
  108. this.body.data.nodes = new DataSet();
  109. this.body.data.nodes.add(nodes);
  110. }
  111. else if (!nodes) {
  112. this.body.data.nodes = new DataSet();
  113. }
  114. else {
  115. throw new TypeError('Array or DataSet expected');
  116. }
  117. if (oldNodesData) {
  118. // unsubscribe from old dataset
  119. util.forEach(this.nodesListeners, function (callback, event) {
  120. oldNodesData.off(event, callback);
  121. });
  122. }
  123. // remove drawn nodes
  124. this.body.nodes = {};
  125. if (this.body.data.nodes) {
  126. // subscribe to new dataset
  127. var me = this;
  128. util.forEach(this.nodesListeners, function (callback, event) {
  129. me.body.data.nodes.on(event, callback);
  130. });
  131. // draw all new nodes
  132. var ids = this.body.data.nodes.getIds();
  133. this.add(ids);
  134. }
  135. this.body.emitter.emit("_dataChanged");
  136. }
  137. /**
  138. * Add nodes
  139. * @param {Number[] | String[]} ids
  140. * @private
  141. */
  142. add(ids) {
  143. var id;
  144. var newNodes = [];
  145. for (var i = 0; i < ids.length; i++) {
  146. id = ids[i];
  147. var properties = this.body.data.nodes.get(id);
  148. var node = this.create(properties);;
  149. newNodes.push(node);
  150. this.body.nodes[id] = node; // note: this may replace an existing node
  151. }
  152. this.layoutEngine.positionInitially(newNodes);
  153. this.body.emitter.emit("_dataChanged");
  154. }
  155. /**
  156. * Update existing nodes, or create them when not yet existing
  157. * @param {Number[] | String[]} ids
  158. * @private
  159. */
  160. update(ids, changedData) {
  161. var nodes = this.body.nodes;
  162. var dataChanged = false;
  163. for (var i = 0; i < ids.length; i++) {
  164. var id = ids[i];
  165. var node = nodes[id];
  166. var data = changedData[i];
  167. if (node !== undefined) {
  168. // update node
  169. node.setOptions(data, this.constants);
  170. }
  171. else {
  172. dataChanged = true;
  173. // create node
  174. node = this.create(properties);
  175. nodes[id] = node;
  176. }
  177. }
  178. if (dataChanged === true) {
  179. this.body.emitter.emit("_dataChanged");
  180. }
  181. else {
  182. this.body.emitter.emit("_dataUpdated");
  183. }
  184. }
  185. /**
  186. * Remove existing nodes. If nodes do not exist, the method will just ignore it.
  187. * @param {Number[] | String[]} ids
  188. * @private
  189. */
  190. remove(ids) {
  191. var nodes = this.body.nodes;
  192. for (let i = 0; i < ids.length; i++) {
  193. var id = ids[i];
  194. delete nodes[id];
  195. }
  196. this.body.emitter.emit("_dataChanged");
  197. }
  198. create(properties, constructorClass = Node) {
  199. return new constructorClass(properties, this.body, this.images, this.groups, this.options)
  200. }
  201. }
  202. export default NodesHandler;