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.

654 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. * TODO: The imageObj members should be moved to CircularImageBase.
  127. * It's the only place where they are required.
  128. *
  129. * @private
  130. */
  131. _load_images() {
  132. // Don't bother loading for nodes without images
  133. if (this.options.shape !== 'circularImage' && this.options.shape !== 'image') {
  134. return;
  135. }
  136. if (this.options.image === undefined) {
  137. throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
  138. }
  139. if (this.imagelist === undefined) {
  140. throw new Error("Internal Error: No images provided");
  141. }
  142. if (typeof this.options.image === 'string') {
  143. this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
  144. } else {
  145. if (this.options.image.unselected === undefined) {
  146. throw new Error("No unselected image provided");
  147. }
  148. this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
  149. if (this.options.image.selected !== undefined) {
  150. this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
  151. } else {
  152. this.imageObjAlt = undefined;
  153. }
  154. }
  155. }
  156. /**
  157. * Copy group option values into the node options.
  158. *
  159. * The group options override the global node options, so the copy of group options
  160. * must happen *after* the global node options have been set.
  161. *
  162. * This method must also be called also if the global node options have changed and the group options did not.
  163. *
  164. * @param {Object} parentOptions
  165. * @param {Object} newOptions new values for the options, currently only passed in for check
  166. * @param {Object} groupList
  167. */
  168. static updateGroupOptions(parentOptions, newOptions, groupList) {
  169. if (groupList === undefined) return; // No groups, nothing to do
  170. var group = parentOptions.group;
  171. // paranoia: the selected group is already merged into node options, check.
  172. if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
  173. throw new Error("updateGroupOptions: group values in options don't match.");
  174. }
  175. var hasGroup = (typeof group === 'number' || (typeof group === 'string' && group != ''));
  176. if (!hasGroup) return; // current node has no group, no need to merge
  177. var groupObj = groupList.get(group);
  178. // Skip merging of group font options into parent; these are required to be distinct for labels
  179. // TODO: It might not be a good idea either to merge the rest of the options, investigate this.
  180. util.selectiveNotDeepExtend(['font'], parentOptions, groupObj);
  181. // the color object needs to be completely defined.
  182. // Since groups can partially overwrite the colors, we parse it again, just in case.
  183. parentOptions.color = util.parseColor(parentOptions.color);
  184. }
  185. /**
  186. * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
  187. * Static so it can also be used by the handler.
  188. *
  189. * @param {Object} parentOptions
  190. * @param {Object} newOptions
  191. * @param {boolean} [allowDeletion=false]
  192. * @param {Object} [globalOptions={}]
  193. * @param {Object} [groupList]
  194. * @static
  195. */
  196. static parseOptions(parentOptions, newOptions, allowDeletion = false, globalOptions = {}, groupList) {
  197. var fields = [
  198. 'color',
  199. 'fixed',
  200. 'shadow'
  201. ];
  202. util.selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
  203. Node.checkMass(newOptions);
  204. // merge the shadow options into the parent.
  205. util.mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
  206. // individual shape newOptions
  207. if (newOptions.color !== undefined && newOptions.color !== null) {
  208. let parsedColor = util.parseColor(newOptions.color);
  209. util.fillIfDefined(parentOptions.color, parsedColor);
  210. }
  211. else if (allowDeletion === true && newOptions.color === null) {
  212. parentOptions.color = util.bridgeObject(globalOptions.color); // set the object back to the global options
  213. }
  214. // handle the fixed options
  215. if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
  216. if (typeof newOptions.fixed === 'boolean') {
  217. parentOptions.fixed.x = newOptions.fixed;
  218. parentOptions.fixed.y = newOptions.fixed;
  219. }
  220. else {
  221. if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {
  222. parentOptions.fixed.x = newOptions.fixed.x;
  223. }
  224. if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === 'boolean') {
  225. parentOptions.fixed.y = newOptions.fixed.y;
  226. }
  227. }
  228. }
  229. if (allowDeletion === true && newOptions.font === null) {
  230. parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
  231. }
  232. Node.updateGroupOptions(parentOptions, newOptions, groupList);
  233. // handle the scaling options, specifically the label part
  234. if (newOptions.scaling !== undefined) {
  235. util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
  236. }
  237. }
  238. /**
  239. *
  240. * @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: *}}
  241. */
  242. getFormattingValues() {
  243. let values = {
  244. color: this.options.color.background,
  245. borderWidth: this.options.borderWidth,
  246. borderColor: this.options.color.border,
  247. size: this.options.size,
  248. borderDashes: this.options.shapeProperties.borderDashes,
  249. borderRadius: this.options.shapeProperties.borderRadius,
  250. shadow: this.options.shadow.enabled,
  251. shadowColor: this.options.shadow.color,
  252. shadowSize: this.options.shadow.size,
  253. shadowX: this.options.shadow.x,
  254. shadowY: this.options.shadow.y
  255. };
  256. if (this.selected || this.hover) {
  257. if (this.chooser === true) {
  258. if (this.selected) {
  259. values.borderWidth *= 2;
  260. values.color = this.options.color.highlight.background;
  261. values.borderColor = this.options.color.highlight.border;
  262. values.shadow = this.options.shadow.enabled;
  263. } else if (this.hover) {
  264. values.color = this.options.color.hover.background;
  265. values.borderColor = this.options.color.hover.border;
  266. values.shadow = this.options.shadow.enabled;
  267. }
  268. } else if (typeof this.chooser === 'function') {
  269. this.chooser(values, this.options.id, this.selected, this.hover);
  270. if (values.shadow === false) {
  271. if ((values.shadowColor !== this.options.shadow.color) ||
  272. (values.shadowSize !== this.options.shadow.size) ||
  273. (values.shadowX !== this.options.shadow.x) ||
  274. (values.shadowY !== this.options.shadow.y)) {
  275. values.shadow = true;
  276. }
  277. }
  278. }
  279. } else {
  280. values.shadow = this.options.shadow.enabled;
  281. }
  282. return values;
  283. }
  284. /**
  285. *
  286. * @param {Object} options
  287. */
  288. updateLabelModule(options) {
  289. if (this.options.label === undefined || this.options.label === null) {
  290. this.options.label = '';
  291. }
  292. Node.updateGroupOptions(this.options, options, this.grouplist);
  293. //
  294. // Note:The prototype chain for this.options is:
  295. //
  296. // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
  297. // (also: this.globalOptions)
  298. //
  299. // Note that the prototypes are mentioned explicitly in the pile list below;
  300. // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
  301. // This is a good indication that the prototype usage of options is deficient.
  302. //
  303. var currentGroup = this.grouplist.get(this.options.group, false);
  304. let pile = [
  305. options, // new options
  306. this.options, // current node options, see comment above for prototype
  307. currentGroup, // group options, if any
  308. this.globalOptions, // Currently set global node options
  309. this.defaultOptions // Default global node options
  310. ];
  311. this.labelModule.update(this.options, pile);
  312. if (this.labelModule.baseSize !== undefined) {
  313. this.baseFontSize = this.labelModule.baseSize;
  314. }
  315. }
  316. /**
  317. *
  318. * @param {string} currentShape
  319. */
  320. updateShape(currentShape) {
  321. if (currentShape === this.options.shape && this.shape) {
  322. this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
  323. }
  324. else {
  325. // choose draw method depending on the shape
  326. switch (this.options.shape) {
  327. case 'box':
  328. this.shape = new Box(this.options, this.body, this.labelModule);
  329. break;
  330. case 'circle':
  331. this.shape = new Circle(this.options, this.body, this.labelModule);
  332. break;
  333. case 'circularImage':
  334. this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  335. break;
  336. case 'database':
  337. this.shape = new Database(this.options, this.body, this.labelModule);
  338. break;
  339. case 'diamond':
  340. this.shape = new Diamond(this.options, this.body, this.labelModule);
  341. break;
  342. case 'dot':
  343. this.shape = new Dot(this.options, this.body, this.labelModule);
  344. break;
  345. case 'ellipse':
  346. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  347. break;
  348. case 'icon':
  349. this.shape = new Icon(this.options, this.body, this.labelModule);
  350. break;
  351. case 'image':
  352. this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  353. break;
  354. case 'square':
  355. this.shape = new Square(this.options, this.body, this.labelModule);
  356. break;
  357. case 'hexagon':
  358. this.shape = new Hexagon(this.options, this.body, this.labelModule);
  359. break;
  360. case 'star':
  361. this.shape = new Star(this.options, this.body, this.labelModule);
  362. break;
  363. case 'text':
  364. this.shape = new Text(this.options, this.body, this.labelModule);
  365. break;
  366. case 'triangle':
  367. this.shape = new Triangle(this.options, this.body, this.labelModule);
  368. break;
  369. case 'triangleDown':
  370. this.shape = new TriangleDown(this.options, this.body, this.labelModule);
  371. break;
  372. default:
  373. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  374. break;
  375. }
  376. }
  377. this.needsRefresh();
  378. }
  379. /**
  380. * select this node
  381. */
  382. select() {
  383. this.selected = true;
  384. this.needsRefresh();
  385. }
  386. /**
  387. * unselect this node
  388. */
  389. unselect() {
  390. this.selected = false;
  391. this.needsRefresh();
  392. }
  393. /**
  394. * Reset the calculated size of the node, forces it to recalculate its size
  395. */
  396. needsRefresh() {
  397. this.shape.refreshNeeded = true;
  398. }
  399. /**
  400. * get the title of this node.
  401. * @return {string} title The title of the node, or undefined when no title
  402. * has been set.
  403. */
  404. getTitle() {
  405. return this.options.title;
  406. }
  407. /**
  408. * Calculate the distance to the border of the Node
  409. * @param {CanvasRenderingContext2D} ctx
  410. * @param {number} angle Angle in radians
  411. * @returns {number} distance Distance to the border in pixels
  412. */
  413. distanceToBorder(ctx, angle) {
  414. return this.shape.distanceToBorder(ctx,angle);
  415. }
  416. /**
  417. * Check if this node has a fixed x and y position
  418. * @return {boolean} true if fixed, false if not
  419. */
  420. isFixed() {
  421. return (this.options.fixed.x && this.options.fixed.y);
  422. }
  423. /**
  424. * check if this node is selecte
  425. * @return {boolean} selected True if node is selected, else false
  426. */
  427. isSelected() {
  428. return this.selected;
  429. }
  430. /**
  431. * Retrieve the value of the node. Can be undefined
  432. * @return {number} value
  433. */
  434. getValue() {
  435. return this.options.value;
  436. }
  437. /**
  438. * Get the current dimensions of the label
  439. *
  440. * @return {rect}
  441. */
  442. getLabelSize() {
  443. return this.labelModule.size();
  444. }
  445. /**
  446. * Adjust the value range of the node. The node will adjust it's size
  447. * based on its value.
  448. * @param {number} min
  449. * @param {number} max
  450. * @param {number} total
  451. */
  452. setValueRange(min, max, total) {
  453. if (this.options.value !== undefined) {
  454. var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
  455. var sizeDiff = this.options.scaling.max - this.options.scaling.min;
  456. if (this.options.scaling.label.enabled === true) {
  457. var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
  458. this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
  459. }
  460. this.options.size = this.options.scaling.min + scale * sizeDiff;
  461. }
  462. else {
  463. this.options.size = this.baseSize;
  464. this.options.font.size = this.baseFontSize;
  465. }
  466. this.updateLabelModule();
  467. }
  468. /**
  469. * Draw this node in the given canvas
  470. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  471. * @param {CanvasRenderingContext2D} ctx
  472. */
  473. draw(ctx) {
  474. let values = this.getFormattingValues();
  475. this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
  476. }
  477. /**
  478. * Update the bounding box of the shape
  479. * @param {CanvasRenderingContext2D} ctx
  480. */
  481. updateBoundingBox(ctx) {
  482. this.shape.updateBoundingBox(this.x,this.y,ctx);
  483. }
  484. /**
  485. * Recalculate the size of this node in the given canvas
  486. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  487. * @param {CanvasRenderingContext2D} ctx
  488. */
  489. resize(ctx) {
  490. let values = this.getFormattingValues();
  491. this.shape.resize(ctx, this.selected, this.hover, values);
  492. }
  493. /**
  494. * Determine all visual elements of this node instance, in which the given
  495. * point falls within the bounding shape.
  496. *
  497. * @param {point} point
  498. * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
  499. */
  500. getItemsOnPoint(point) {
  501. var ret = [];
  502. if (this.labelModule.visible()) {
  503. if (ComponentUtil.pointInRect(this.labelModule.getSize(), point)) {
  504. ret.push({nodeId:this.id, labelId:0});
  505. }
  506. }
  507. if (ComponentUtil.pointInRect(this.shape.boundingBox, point)) {
  508. ret.push({nodeId:this.id});
  509. }
  510. return ret;
  511. }
  512. /**
  513. * Check if this object is overlapping with the provided object
  514. * @param {Object} obj an object with parameters left, top, right, bottom
  515. * @return {boolean} True if location is located on node
  516. */
  517. isOverlappingWith(obj) {
  518. return (
  519. this.shape.left < obj.right &&
  520. this.shape.left + this.shape.width > obj.left &&
  521. this.shape.top < obj.bottom &&
  522. this.shape.top + this.shape.height > obj.top
  523. );
  524. }
  525. /**
  526. * Check if this object is overlapping with the provided object
  527. * @param {Object} obj an object with parameters left, top, right, bottom
  528. * @return {boolean} True if location is located on node
  529. */
  530. isBoundingBoxOverlappingWith(obj) {
  531. return (
  532. this.shape.boundingBox.left < obj.right &&
  533. this.shape.boundingBox.right > obj.left &&
  534. this.shape.boundingBox.top < obj.bottom &&
  535. this.shape.boundingBox.bottom > obj.top
  536. );
  537. }
  538. /**
  539. * Check valid values for mass
  540. *
  541. * The mass may not be negative or zero. If it is, reset to 1
  542. *
  543. * @param {object} options
  544. * @param {Node.id} id
  545. * @static
  546. */
  547. static checkMass(options, id) {
  548. if (options.mass !== undefined && options.mass <= 0) {
  549. let strId = '';
  550. if (id !== undefined) {
  551. strId = ' in node id: ' + id;
  552. }
  553. console.log('%cNegative or zero mass disallowed' + strId +
  554. ', setting mass to 1.' , printStyle);
  555. options.mass = 1;
  556. }
  557. }
  558. }
  559. export default Node;