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.

655 lines
21 KiB

Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
9 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
Network: Fix handling of multi-fonts (#3486) * The next fix on Travis unit test failure This is the next escalation on the war against the Travis unit tests failing (which came into being by yours truly). By accident, I could recreate the unit test failure on my development machine. This led to a more directed effort to squash the bug. The insight here is that test `(window === undefined)` fails, but `(typeof window === 'undefined`)` succeeds. This undoubtedly has to do with the special status `window` has as a global object. Changes: - Added check on presence of `window` in `Canvas._requestNextFrame()`, fixed local source errors. - Added catch clause in `CanvasRendered._determinePixelRatio()` - small fix: raised timeout for the network `worldCup2014` unit test * Preliminary refactoring in utils.js * Added unit tests for extend routines, commenting and small fixes * More unit tests for extend routines * - Completed unit tests for extend routines in - Small fixes and cleanup in `util.js` - Removed `util.protoExtend()`, not used anywhere * Added unit tests for known font options * Interim save before trying out another proto chain strategy * Fixed problem in first example #3408 * Removed silly file that shouldn't be there * Added unit test for multi-fonts * Comment edits * Verufy unit tests, small adjustments for groups * Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP! * Further tweaks to get unit tests working * All unit tests passing * Fixes due to linting * Small edits * Removed prototype handling from font pile * Fixes during testing examples of #3408 * Added unit test for edge labels, small fixes * Added unit tests for shorthand string fonts; some tests still failing * All unit tests pass * Removed Label.parseOptions() * Completed shorthand font tests, code cleanup, fixed choosify for edges * Addressed review comments * Addressed review comments, cleanup
7 years ago
9 years ago
9 years ago
  1. var util = require('../../../util');
  2. var Label = require('./shared/Label').default;
  3. var ComponentUtil = require('./shared/ComponentUtil').default;
  4. var Box = require('./nodes/shapes/Box').default;
  5. var Circle = require('./nodes/shapes/Circle').default;
  6. var CircularImage = require('./nodes/shapes/CircularImage').default;
  7. var Database = require('./nodes/shapes/Database').default;
  8. var Diamond = require('./nodes/shapes/Diamond').default;
  9. var Dot = require('./nodes/shapes/Dot').default;
  10. var Ellipse = require('./nodes/shapes/Ellipse').default;
  11. var Icon = require('./nodes/shapes/Icon').default;
  12. var Image = require('./nodes/shapes/Image').default;
  13. var Square = require('./nodes/shapes/Square').default;
  14. var Hexagon = require('./nodes/shapes/Hexagon').default;
  15. var Star = require('./nodes/shapes/Star').default;
  16. var Text = require('./nodes/shapes/Text').default;
  17. var Triangle = require('./nodes/shapes/Triangle').default;
  18. var TriangleDown = require('./nodes/shapes/TriangleDown').default;
  19. var { printStyle } = require("../../../shared/Validator");
  20. /**
  21. * A node. A node can be connected to other nodes via one or multiple edges.
  22. */
  23. class Node {
  24. /**
  25. *
  26. * @param {object} options An object containing options for the node. All
  27. * options are optional, except for the id.
  28. * {number} id Id of the node. Required
  29. * {string} label Text label for the node
  30. * {number} x Horizontal position of the node
  31. * {number} y Vertical position of the node
  32. * {string} shape Node shape
  33. * {string} image An image url
  34. * {string} title A title text, can be HTML
  35. * {anytype} group A group name or number
  36. *
  37. * @param {Object} body Shared state of current network instance
  38. * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
  39. * @param {Groups} grouplist A list with groups. Needed for retrieving group options
  40. * @param {Object} globalOptions Current global node options; these serve as defaults for the node instance
  41. * @param {Object} defaultOptions Global default options for nodes; note that this is also the prototype
  42. * for parameter `globalOptions`.
  43. */
  44. constructor(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
  45. this.options = util.bridgeObject(globalOptions);
  46. this.globalOptions = globalOptions;
  47. this.defaultOptions = defaultOptions;
  48. this.body = body;
  49. this.edges = []; // all edges connected to this node
  50. // set defaults for the options
  51. this.id = undefined;
  52. this.imagelist = imagelist;
  53. this.grouplist = grouplist;
  54. // state options
  55. this.x = undefined;
  56. this.y = undefined;
  57. this.baseSize = this.options.size;
  58. this.baseFontSize = this.options.font.size;
  59. this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
  60. this.selected = false;
  61. this.hover = false;
  62. this.labelModule = new Label(this.body, this.options, false /* Not edge label */);
  63. this.setOptions(options);
  64. }
  65. /**
  66. * Attach a edge to the node
  67. * @param {Edge} edge
  68. */
  69. attachEdge(edge) {
  70. if (this.edges.indexOf(edge) === -1) {
  71. this.edges.push(edge);
  72. }
  73. }
  74. /**
  75. * Detach a edge from the node
  76. *
  77. * @param {Edge} edge
  78. */
  79. detachEdge(edge) {
  80. var index = this.edges.indexOf(edge);
  81. if (index != -1) {
  82. this.edges.splice(index, 1);
  83. }
  84. }
  85. /**
  86. * Set or overwrite options for the node
  87. *
  88. * @param {Object} options an object with options
  89. * @returns {null|boolean}
  90. */
  91. setOptions(options) {
  92. let currentShape = this.options.shape;
  93. if (!options) {
  94. return; // Note that the return value will be 'undefined'! This is OK.
  95. }
  96. // basic options
  97. if (options.id !== undefined) {this.id = options.id;}
  98. if (this.id === undefined) {
  99. throw new Error("Node must have an id");
  100. }
  101. Node.checkMass(options, this.id);
  102. // set these options locally
  103. // clear x and y positions
  104. if (options.x !== undefined) {
  105. if (options.x === null) {this.x = undefined; this.predefinedPosition = false;}
  106. else {this.x = parseInt(options.x); this.predefinedPosition = true;}
  107. }
  108. if (options.y !== undefined) {
  109. if (options.y === null) {this.y = undefined; this.predefinedPosition = false;}
  110. else {this.y = parseInt(options.y); this.predefinedPosition = true;}
  111. }
  112. if (options.size !== undefined) {this.baseSize = options.size;}
  113. if (options.value !== undefined) {options.value = parseFloat(options.value);}
  114. // this transforms all shorthands into fully defined options
  115. Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
  116. let pile = [options, this.options, this.defaultOptions];
  117. this.chooser = ComponentUtil.choosify('node', pile);
  118. this._load_images();
  119. this.updateLabelModule(options);
  120. this.updateShape(currentShape);
  121. return (options.hidden !== undefined || options.physics !== undefined);
  122. }
  123. /**
  124. * Load the images from the options, for the nodes that need them.
  125. *
  126. * Images are always loaded, even if they are not used in the current shape.
  127. * The user may switch to an image shape later on.
  128. *
  129. * @private
  130. */
  131. _load_images() {
  132. if (this.options.shape === 'circularImage' || this.options.shape === 'image') {
  133. if (this.options.image === undefined) {
  134. throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
  135. }
  136. }
  137. if (this.options.image === undefined) {
  138. return;
  139. }
  140. if (this.imagelist === undefined) {
  141. throw new Error("Internal Error: No images provided");
  142. }
  143. if (typeof this.options.image === 'string') {
  144. this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
  145. } else {
  146. if (this.options.image.unselected === undefined) {
  147. throw new Error("No unselected image provided");
  148. }
  149. this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
  150. if (this.options.image.selected !== undefined) {
  151. this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
  152. } else {
  153. this.imageObjAlt = undefined;
  154. }
  155. }
  156. }
  157. /**
  158. * Copy group option values into the node options.
  159. *
  160. * The group options override the global node options, so the copy of group options
  161. * must happen *after* the global node options have been set.
  162. *
  163. * This method must also be called also if the global node options have changed and the group options did not.
  164. *
  165. * @param {Object} parentOptions
  166. * @param {Object} newOptions new values for the options, currently only passed in for check
  167. * @param {Object} groupList
  168. */
  169. static updateGroupOptions(parentOptions, newOptions, groupList) {
  170. if (groupList === undefined) return; // No groups, nothing to do
  171. var group = parentOptions.group;
  172. // paranoia: the selected group is already merged into node options, check.
  173. if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
  174. throw new Error("updateGroupOptions: group values in options don't match.");
  175. }
  176. var hasGroup = (typeof group === 'number' || (typeof group === 'string' && group != ''));
  177. if (!hasGroup) return; // current node has no group, no need to merge
  178. var groupObj = groupList.get(group);
  179. // Skip merging of group font options into parent; these are required to be distinct for labels
  180. // TODO: It might not be a good idea either to merge the rest of the options, investigate this.
  181. util.selectiveNotDeepExtend(['font'], parentOptions, groupObj);
  182. // the color object needs to be completely defined.
  183. // Since groups can partially overwrite the colors, we parse it again, just in case.
  184. parentOptions.color = util.parseColor(parentOptions.color);
  185. }
  186. /**
  187. * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
  188. * Static so it can also be used by the handler.
  189. *
  190. * @param {Object} parentOptions
  191. * @param {Object} newOptions
  192. * @param {boolean} [allowDeletion=false]
  193. * @param {Object} [globalOptions={}]
  194. * @param {Object} [groupList]
  195. * @static
  196. */
  197. static parseOptions(parentOptions, newOptions, allowDeletion = false, globalOptions = {}, groupList) {
  198. var fields = [
  199. 'color',
  200. 'fixed',
  201. 'shadow'
  202. ];
  203. util.selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
  204. Node.checkMass(newOptions);
  205. // merge the shadow options into the parent.
  206. util.mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
  207. // individual shape newOptions
  208. if (newOptions.color !== undefined && newOptions.color !== null) {
  209. let parsedColor = util.parseColor(newOptions.color);
  210. util.fillIfDefined(parentOptions.color, parsedColor);
  211. }
  212. else if (allowDeletion === true && newOptions.color === null) {
  213. parentOptions.color = util.bridgeObject(globalOptions.color); // set the object back to the global options
  214. }
  215. // handle the fixed options
  216. if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
  217. if (typeof newOptions.fixed === 'boolean') {
  218. parentOptions.fixed.x = newOptions.fixed;
  219. parentOptions.fixed.y = newOptions.fixed;
  220. }
  221. else {
  222. if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {
  223. parentOptions.fixed.x = newOptions.fixed.x;
  224. }
  225. if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === 'boolean') {
  226. parentOptions.fixed.y = newOptions.fixed.y;
  227. }
  228. }
  229. }
  230. if (allowDeletion === true && newOptions.font === null) {
  231. parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
  232. }
  233. Node.updateGroupOptions(parentOptions, newOptions, groupList);
  234. // handle the scaling options, specifically the label part
  235. if (newOptions.scaling !== undefined) {
  236. util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
  237. }
  238. }
  239. /**
  240. *
  241. * @returns {{color: *, borderWidth: *, borderColor: *, size: *, borderDashes: (boolean|Array|allOptions.nodes.shapeProperties.borderDashes|{boolean, array}), borderRadius: (number|allOptions.nodes.shapeProperties.borderRadius|{number}|Array), shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *}}
  242. */
  243. getFormattingValues() {
  244. let values = {
  245. color: this.options.color.background,
  246. borderWidth: this.options.borderWidth,
  247. borderColor: this.options.color.border,
  248. size: this.options.size,
  249. borderDashes: this.options.shapeProperties.borderDashes,
  250. borderRadius: this.options.shapeProperties.borderRadius,
  251. shadow: this.options.shadow.enabled,
  252. shadowColor: this.options.shadow.color,
  253. shadowSize: this.options.shadow.size,
  254. shadowX: this.options.shadow.x,
  255. shadowY: this.options.shadow.y
  256. };
  257. if (this.selected || this.hover) {
  258. if (this.chooser === true) {
  259. if (this.selected) {
  260. values.borderWidth *= 2;
  261. values.color = this.options.color.highlight.background;
  262. values.borderColor = this.options.color.highlight.border;
  263. values.shadow = this.options.shadow.enabled;
  264. } else if (this.hover) {
  265. values.color = this.options.color.hover.background;
  266. values.borderColor = this.options.color.hover.border;
  267. values.shadow = this.options.shadow.enabled;
  268. }
  269. } else if (typeof this.chooser === 'function') {
  270. this.chooser(values, this.options.id, this.selected, this.hover);
  271. if (values.shadow === false) {
  272. if ((values.shadowColor !== this.options.shadow.color) ||
  273. (values.shadowSize !== this.options.shadow.size) ||
  274. (values.shadowX !== this.options.shadow.x) ||
  275. (values.shadowY !== this.options.shadow.y)) {
  276. values.shadow = true;
  277. }
  278. }
  279. }
  280. } else {
  281. values.shadow = this.options.shadow.enabled;
  282. }
  283. return values;
  284. }
  285. /**
  286. *
  287. * @param {Object} options
  288. */
  289. updateLabelModule(options) {
  290. if (this.options.label === undefined || this.options.label === null) {
  291. this.options.label = '';
  292. }
  293. Node.updateGroupOptions(this.options, options, this.grouplist);
  294. //
  295. // Note:The prototype chain for this.options is:
  296. //
  297. // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
  298. // (also: this.globalOptions)
  299. //
  300. // Note that the prototypes are mentioned explicitly in the pile list below;
  301. // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
  302. // This is a good indication that the prototype usage of options is deficient.
  303. //
  304. var currentGroup = this.grouplist.get(this.options.group, false);
  305. let pile = [
  306. options, // new options
  307. this.options, // current node options, see comment above for prototype
  308. currentGroup, // group options, if any
  309. this.globalOptions, // Currently set global node options
  310. this.defaultOptions // Default global node options
  311. ];
  312. this.labelModule.update(this.options, pile);
  313. if (this.labelModule.baseSize !== undefined) {
  314. this.baseFontSize = this.labelModule.baseSize;
  315. }
  316. }
  317. /**
  318. *
  319. * @param {string} currentShape
  320. */
  321. updateShape(currentShape) {
  322. if (currentShape === this.options.shape && this.shape) {
  323. this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
  324. }
  325. else {
  326. // choose draw method depending on the shape
  327. switch (this.options.shape) {
  328. case 'box':
  329. this.shape = new Box(this.options, this.body, this.labelModule);
  330. break;
  331. case 'circle':
  332. this.shape = new Circle(this.options, this.body, this.labelModule);
  333. break;
  334. case 'circularImage':
  335. this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  336. break;
  337. case 'database':
  338. this.shape = new Database(this.options, this.body, this.labelModule);
  339. break;
  340. case 'diamond':
  341. this.shape = new Diamond(this.options, this.body, this.labelModule);
  342. break;
  343. case 'dot':
  344. this.shape = new Dot(this.options, this.body, this.labelModule);
  345. break;
  346. case 'ellipse':
  347. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  348. break;
  349. case 'icon':
  350. this.shape = new Icon(this.options, this.body, this.labelModule);
  351. break;
  352. case 'image':
  353. this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  354. break;
  355. case 'square':
  356. this.shape = new Square(this.options, this.body, this.labelModule);
  357. break;
  358. case 'hexagon':
  359. this.shape = new Hexagon(this.options, this.body, this.labelModule);
  360. break;
  361. case 'star':
  362. this.shape = new Star(this.options, this.body, this.labelModule);
  363. break;
  364. case 'text':
  365. this.shape = new Text(this.options, this.body, this.labelModule);
  366. break;
  367. case 'triangle':
  368. this.shape = new Triangle(this.options, this.body, this.labelModule);
  369. break;
  370. case 'triangleDown':
  371. this.shape = new TriangleDown(this.options, this.body, this.labelModule);
  372. break;
  373. default:
  374. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  375. break;
  376. }
  377. }
  378. this.needsRefresh();
  379. }
  380. /**
  381. * select this node
  382. */
  383. select() {
  384. this.selected = true;
  385. this.needsRefresh();
  386. }
  387. /**
  388. * unselect this node
  389. */
  390. unselect() {
  391. this.selected = false;
  392. this.needsRefresh();
  393. }
  394. /**
  395. * Reset the calculated size of the node, forces it to recalculate its size
  396. */
  397. needsRefresh() {
  398. this.shape.refreshNeeded = true;
  399. }
  400. /**
  401. * get the title of this node.
  402. * @return {string} title The title of the node, or undefined when no title
  403. * has been set.
  404. */
  405. getTitle() {
  406. return this.options.title;
  407. }
  408. /**
  409. * Calculate the distance to the border of the Node
  410. * @param {CanvasRenderingContext2D} ctx
  411. * @param {number} angle Angle in radians
  412. * @returns {number} distance Distance to the border in pixels
  413. */
  414. distanceToBorder(ctx, angle) {
  415. return this.shape.distanceToBorder(ctx,angle);
  416. }
  417. /**
  418. * Check if this node has a fixed x and y position
  419. * @return {boolean} true if fixed, false if not
  420. */
  421. isFixed() {
  422. return (this.options.fixed.x && this.options.fixed.y);
  423. }
  424. /**
  425. * check if this node is selecte
  426. * @return {boolean} selected True if node is selected, else false
  427. */
  428. isSelected() {
  429. return this.selected;
  430. }
  431. /**
  432. * Retrieve the value of the node. Can be undefined
  433. * @return {number} value
  434. */
  435. getValue() {
  436. return this.options.value;
  437. }
  438. /**
  439. * Get the current dimensions of the label
  440. *
  441. * @return {rect}
  442. */
  443. getLabelSize() {
  444. return this.labelModule.size();
  445. }
  446. /**
  447. * Adjust the value range of the node. The node will adjust it's size
  448. * based on its value.
  449. * @param {number} min
  450. * @param {number} max
  451. * @param {number} total
  452. */
  453. setValueRange(min, max, total) {
  454. if (this.options.value !== undefined) {
  455. var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
  456. var sizeDiff = this.options.scaling.max - this.options.scaling.min;
  457. if (this.options.scaling.label.enabled === true) {
  458. var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
  459. this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
  460. }
  461. this.options.size = this.options.scaling.min + scale * sizeDiff;
  462. }
  463. else {
  464. this.options.size = this.baseSize;
  465. this.options.font.size = this.baseFontSize;
  466. }
  467. this.updateLabelModule();
  468. }
  469. /**
  470. * Draw this node in the given canvas
  471. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  472. * @param {CanvasRenderingContext2D} ctx
  473. */
  474. draw(ctx) {
  475. let values = this.getFormattingValues();
  476. this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
  477. }
  478. /**
  479. * Update the bounding box of the shape
  480. * @param {CanvasRenderingContext2D} ctx
  481. */
  482. updateBoundingBox(ctx) {
  483. this.shape.updateBoundingBox(this.x,this.y,ctx);
  484. }
  485. /**
  486. * Recalculate the size of this node in the given canvas
  487. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  488. * @param {CanvasRenderingContext2D} ctx
  489. */
  490. resize(ctx) {
  491. let values = this.getFormattingValues();
  492. this.shape.resize(ctx, this.selected, this.hover, values);
  493. }
  494. /**
  495. * Determine all visual elements of this node instance, in which the given
  496. * point falls within the bounding shape.
  497. *
  498. * @param {point} point
  499. * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
  500. */
  501. getItemsOnPoint(point) {
  502. var ret = [];
  503. if (this.labelModule.visible()) {
  504. if (ComponentUtil.pointInRect(this.labelModule.getSize(), point)) {
  505. ret.push({nodeId:this.id, labelId:0});
  506. }
  507. }
  508. if (ComponentUtil.pointInRect(this.shape.boundingBox, point)) {
  509. ret.push({nodeId:this.id});
  510. }
  511. return ret;
  512. }
  513. /**
  514. * Check if this object is overlapping with the provided object
  515. * @param {Object} obj an object with parameters left, top, right, bottom
  516. * @return {boolean} True if location is located on node
  517. */
  518. isOverlappingWith(obj) {
  519. return (
  520. this.shape.left < obj.right &&
  521. this.shape.left + this.shape.width > obj.left &&
  522. this.shape.top < obj.bottom &&
  523. this.shape.top + this.shape.height > obj.top
  524. );
  525. }
  526. /**
  527. * Check if this object is overlapping with the provided object
  528. * @param {Object} obj an object with parameters left, top, right, bottom
  529. * @return {boolean} True if location is located on node
  530. */
  531. isBoundingBoxOverlappingWith(obj) {
  532. return (
  533. this.shape.boundingBox.left < obj.right &&
  534. this.shape.boundingBox.right > obj.left &&
  535. this.shape.boundingBox.top < obj.bottom &&
  536. this.shape.boundingBox.bottom > obj.top
  537. );
  538. }
  539. /**
  540. * Check valid values for mass
  541. *
  542. * The mass may not be negative or zero. If it is, reset to 1
  543. *
  544. * @param {object} options
  545. * @param {Node.id} id
  546. * @static
  547. */
  548. static checkMass(options, id) {
  549. if (options.mass !== undefined && options.mass <= 0) {
  550. let strId = '';
  551. if (id !== undefined) {
  552. strId = ' in node id: ' + id;
  553. }
  554. console.log('%cNegative or zero mass disallowed' + strId +
  555. ', setting mass to 1.' , printStyle);
  556. options.mass = 1;
  557. }
  558. }
  559. }
  560. export default Node;