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.

274 lines
6.7 KiB

9 years ago
  1. var util = require("../../util");
  2. var DataSet = require('../../DataSet');
  3. var DataView = require('../../DataView');
  4. import Node from "./components/Node";
  5. import Label from "./components/shared/Label";
  6. class NodesHandler {
  7. constructor(body, images, groups, layoutEngine) {
  8. this.body = body;
  9. this.images = images;
  10. this.groups = groups;
  11. this.layoutEngine = layoutEngine;
  12. // create the node API in the body container
  13. this.body.functions.createNode = this.create.bind(this);
  14. this.nodesListeners = {
  15. 'add': (event, params) => {this.add(params.items);},
  16. 'update': (event, params) => {this.update(params.items, params.data);},
  17. 'remove': (event, params) => {this.remove(params.items);}
  18. };
  19. this.options = {};
  20. this.defaultOptions = {
  21. borderWidth: 1,
  22. borderWidthSelected: undefined,
  23. brokenImage:undefined,
  24. color: {
  25. border: '#2B7CE9',
  26. background: '#97C2FC',
  27. highlight: {
  28. border: '#2B7CE9',
  29. background: '#D2E5FF'
  30. },
  31. hover: {
  32. border: '#2B7CE9',
  33. background: '#D2E5FF'
  34. }
  35. },
  36. fixed: {
  37. x:false,
  38. y:false
  39. },
  40. font: {
  41. color: '#343434',
  42. size: 14, // px
  43. face: 'arial',
  44. background: 'none',
  45. stroke: 0, // px
  46. strokeColor: '#ffffff',
  47. align: 'horizontal'
  48. },
  49. group: undefined,
  50. hidden: false,
  51. icon: {
  52. face: 'FontAwesome', //'FontAwesome',
  53. code: undefined, //'\uf007',
  54. size: 50, //50,
  55. color:'#2B7CE9' //'#aa00ff'
  56. },
  57. image: undefined, // --> URL
  58. label: undefined,
  59. level: undefined,
  60. mass: 1,
  61. physics: true,
  62. scaling: {
  63. min: 10,
  64. max: 30,
  65. label: {
  66. enabled: false,
  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. shadow:{
  83. enabled: false,
  84. size:10,
  85. x:5,
  86. y:5
  87. },
  88. shape: 'ellipse',
  89. size: 25,
  90. title: undefined,
  91. value: undefined,
  92. x: undefined,
  93. y: undefined
  94. };
  95. util.extend(this.options, this.defaultOptions);
  96. }
  97. setOptions(options) {
  98. if (options !== undefined) {
  99. Node.parseOptions(this.options, options);
  100. // update the shape in all nodes
  101. if (options.shape !== undefined) {
  102. for (let nodeId in this.body.nodes) {
  103. if (this.body.nodes.hasOwnProperty(nodeId)) {
  104. this.body.nodes[nodeId].updateShape();
  105. }
  106. }
  107. }
  108. // update the shape size in all nodes
  109. if (options.font !== undefined) {
  110. Label.parseOptions(this.options.font,options);
  111. for (let nodeId in this.body.nodes) {
  112. if (this.body.nodes.hasOwnProperty(nodeId)) {
  113. this.body.nodes[nodeId].updateLabelModule();
  114. this.body.nodes[nodeId]._reset();
  115. }
  116. }
  117. }
  118. // update the shape size in all nodes
  119. if (options.size !== undefined) {
  120. for (let nodeId in this.body.nodes) {
  121. if (this.body.nodes.hasOwnProperty(nodeId)) {
  122. this.body.nodes[nodeId]._reset();
  123. }
  124. }
  125. }
  126. // update the state of the variables if needed
  127. if (options.hidden !== undefined || options.physics !== undefined) {
  128. this.body.emitter.emit('_dataChanged');
  129. }
  130. }
  131. }
  132. /**
  133. * Set a data set with nodes for the network
  134. * @param {Array | DataSet | DataView} nodes The data containing the nodes.
  135. * @private
  136. */
  137. setData(nodes, doNotEmit = false) {
  138. var oldNodesData = this.body.data.nodes;
  139. if (nodes instanceof DataSet || nodes instanceof DataView) {
  140. this.body.data.nodes = nodes;
  141. }
  142. else if (Array.isArray(nodes)) {
  143. this.body.data.nodes = new DataSet();
  144. this.body.data.nodes.add(nodes);
  145. }
  146. else if (!nodes) {
  147. this.body.data.nodes = new DataSet();
  148. }
  149. else {
  150. throw new TypeError('Array or DataSet expected');
  151. }
  152. if (oldNodesData) {
  153. // unsubscribe from old dataset
  154. util.forEach(this.nodesListeners, function (callback, event) {
  155. oldNodesData.off(event, callback);
  156. });
  157. }
  158. // remove drawn nodes
  159. this.body.nodes = {};
  160. if (this.body.data.nodes) {
  161. // subscribe to new dataset
  162. var me = this;
  163. util.forEach(this.nodesListeners, function (callback, event) {
  164. me.body.data.nodes.on(event, callback);
  165. });
  166. // draw all new nodes
  167. var ids = this.body.data.nodes.getIds();
  168. this.add(ids, true);
  169. }
  170. if (doNotEmit === false) {
  171. this.body.emitter.emit("_dataChanged");
  172. }
  173. }
  174. /**
  175. * Add nodes
  176. * @param {Number[] | String[]} ids
  177. * @private
  178. */
  179. add(ids, doNotEmit = false) {
  180. var id;
  181. var newNodes = [];
  182. for (var i = 0; i < ids.length; i++) {
  183. id = ids[i];
  184. var properties = this.body.data.nodes.get(id);
  185. var node = this.create(properties);;
  186. newNodes.push(node);
  187. this.body.nodes[id] = node; // note: this may replace an existing node
  188. }
  189. this.layoutEngine.positionInitially(newNodes);
  190. if (doNotEmit === false) {
  191. this.body.emitter.emit("_dataChanged");
  192. }
  193. }
  194. /**
  195. * Update existing nodes, or create them when not yet existing
  196. * @param {Number[] | String[]} ids
  197. * @private
  198. */
  199. update(ids, changedData) {
  200. var nodes = this.body.nodes;
  201. var dataChanged = false;
  202. for (var i = 0; i < ids.length; i++) {
  203. var id = ids[i];
  204. var node = nodes[id];
  205. var data = changedData[i];
  206. if (node !== undefined) {
  207. // update node
  208. node.setOptions(data, this.constants);
  209. }
  210. else {
  211. dataChanged = true;
  212. // create node
  213. node = this.create(properties);
  214. nodes[id] = node;
  215. }
  216. }
  217. if (dataChanged === true) {
  218. this.body.emitter.emit("_dataChanged");
  219. }
  220. else {
  221. this.body.emitter.emit("_dataUpdated");
  222. }
  223. }
  224. /**
  225. * Remove existing nodes. If nodes do not exist, the method will just ignore it.
  226. * @param {Number[] | String[]} ids
  227. * @private
  228. */
  229. remove(ids) {
  230. var nodes = this.body.nodes;
  231. for (let i = 0; i < ids.length; i++) {
  232. var id = ids[i];
  233. delete nodes[id];
  234. }
  235. this.body.emitter.emit("_dataChanged");
  236. }
  237. create(properties, constructorClass = Node) {
  238. return new constructorClass(properties, this.body, this.images, this.groups, this.options)
  239. }
  240. }
  241. export default NodesHandler;