diff --git a/documentation.yml b/documentation.yml index ae947208e..02907424f 100644 --- a/documentation.yml +++ b/documentation.yml @@ -1,8 +1,9 @@ toc: - graph.config - Graph - - Graph/helper - Graph/renderer + - Graph/builder + - Graph/helper - Graph/collapse-helper - Node - Node/helper diff --git a/src/components/graph/collapse.helper.js b/src/components/graph/collapse.helper.js index e5db340fe..24a5e734b 100644 --- a/src/components/graph/collapse.helper.js +++ b/src/components/graph/collapse.helper.js @@ -106,7 +106,7 @@ function computeNodeDegree(nodeId, linksMatrix = {}) { * @param {string} rootNodeId - node who's leafs we want to calculate. * @param {Object.} linksMatrix - an object containing a matrix of connections of the graph, for each nodeId, * there is an object that maps adjacent nodes ids (string) and their values (number). - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. * @param {boolean} config.directed - tells whether linksMatrix represents a directed graph or not. * @returns {Array.>} a list of leaf connections. * What is a leaf connection? A leaf connection is a link between some node A and other node B @@ -172,7 +172,7 @@ function toggleLinksConnections(d3Links, connectionMatrix) { * @param {Object.} linksMatrix - an object containing a matrix of connections of the graph, for each nodeId, * there is an object that maps adjacent nodes ids (string) and their values (number). * @param {Array.>} connections - connections to toggle on matrix. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. * @param {boolean} config.directed - tells whether linksMatrix represents a directed graph or not. * @returns {Object.} updated linksMatrix * @memberof Graph/collapse-helper diff --git a/src/components/graph/graph.builder.js b/src/components/graph/graph.builder.js new file mode 100644 index 000000000..e66a7228e --- /dev/null +++ b/src/components/graph/graph.builder.js @@ -0,0 +1,195 @@ +/** + * @module Graph/builder + * @description + * Offers a series of methods that isolate the way graph elements are built (nodes and links mainly). + */ +import CONST from "./graph.const"; + +import { buildLinkPathDefinition } from "../link/link.helper"; +import { getMarkerId } from "../marker/marker.helper"; + +/** + * Get the correct node opacity in order to properly make decisions based on context such as currently highlighted node. + * @param {Object} node - the node object for whom we will generate properties. + * @param {string} highlightedNode - same as {@link #graphrenderer|highlightedNode in renderGraph}. + * @param {Object} highlightedLink - same as {@link #graphrenderer|highlightedLink in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. + * @returns {number} the opacity value for the given node. + * @memberof Graph/builder + */ +function _getNodeOpacity(node, highlightedNode, highlightedLink, config) { + const highlight = + node.highlighted || + node.id === (highlightedLink && highlightedLink.source) || + node.id === (highlightedLink && highlightedLink.target); + const someNodeHighlighted = !!( + highlightedNode || + (highlightedLink && highlightedLink.source && highlightedLink.target) + ); + let opacity; + + if (someNodeHighlighted && config.highlightDegree === 0) { + opacity = highlight ? config.node.opacity : config.highlightOpacity; + } else if (someNodeHighlighted) { + opacity = highlight ? config.node.opacity : config.highlightOpacity; + } else { + opacity = config.node.opacity; + } + + return opacity; +} + +/** + * Build some Link properties based on given parameters. + * @param {Object} link - the link object for which we will generate properties. + * @param {Object.} nodes - same as {@link #graphrenderer|nodes in renderGraph}. + * @param {Object.} links - same as {@link #graphrenderer|links in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. + * @param {Function[]} linkCallbacks - same as {@link #graphrenderer|linkCallbacks in renderGraph}. + * @param {string} highlightedNode - same as {@link #graphrenderer|highlightedNode in renderGraph}. + * @param {Object} highlightedLink - same as {@link #graphrenderer|highlightedLink in renderGraph}. + * @param {number} transform - value that indicates the amount of zoom transformation. + * @returns {Object} returns an object that aggregates all props for creating respective Link component instance. + * @memberof Graph/builder + */ +function buildLinkProps(link, nodes, links, config, linkCallbacks, highlightedNode, highlightedLink, transform) { + const { source, target } = link; + const x1 = (nodes[source] && nodes[source].x) || 0; + const y1 = (nodes[source] && nodes[source].y) || 0; + const x2 = (nodes[target] && nodes[target].x) || 0; + const y2 = (nodes[target] && nodes[target].y) || 0; + + const d = buildLinkPathDefinition({ source: { x: x1, y: y1 }, target: { x: x2, y: y2 } }, config.link.type); + + let mainNodeParticipates = false; + + switch (config.highlightDegree) { + case 0: + break; + case 2: + mainNodeParticipates = true; + break; + default: + // 1st degree is the fallback behavior + mainNodeParticipates = source === highlightedNode || target === highlightedNode; + break; + } + + const reasonNode = mainNodeParticipates && nodes[source].highlighted && nodes[target].highlighted; + const reasonLink = + source === (highlightedLink && highlightedLink.source) && + target === (highlightedLink && highlightedLink.target); + const highlight = reasonNode || reasonLink; + + let opacity = config.link.opacity; + + if (highlightedNode || (highlightedLink && highlightedLink.source)) { + opacity = highlight ? config.link.opacity : config.highlightOpacity; + } + + let stroke = link.color || config.link.color; + + if (highlight) { + stroke = config.link.highlightColor === CONST.KEYWORDS.SAME ? config.link.color : config.link.highlightColor; + } + + let strokeWidth = config.link.strokeWidth * (1 / transform); + + if (config.link.semanticStrokeWidth) { + const linkValue = links[source][target] || links[target][source] || 1; + + strokeWidth += (linkValue * strokeWidth) / 10; + } + + const markerId = config.directed ? getMarkerId(highlight, transform, config) : null; + + return { + markerId, + d, + source, + target, + strokeWidth, + stroke, + mouseCursor: config.link.mouseCursor, + className: CONST.LINK_CLASS_NAME, + opacity, + onClickLink: linkCallbacks.onClickLink, + onRightClickLink: linkCallbacks.onRightClickLink, + onMouseOverLink: linkCallbacks.onMouseOverLink, + onMouseOutLink: linkCallbacks.onMouseOutLink, + }; +} + +/** + * Build some Node properties based on given parameters. + * @param {Object} node - the node object for whom we will generate properties. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. + * @param {Function[]} nodeCallbacks - same as {@link #graphrenderer|nodeCallbacks in renderGraph}. + * @param {string} highlightedNode - same as {@link #graphrenderer|highlightedNode in renderGraph}. + * @param {Object} highlightedLink - same as {@link #graphrenderer|highlightedLink in renderGraph}. + * @param {number} transform - value that indicates the amount of zoom transformation. + * @returns {Object} returns object that contain Link props ready to be feeded to the Link component. + * @memberof Graph/builder + */ +function buildNodeProps(node, config, nodeCallbacks = {}, highlightedNode, highlightedLink, transform) { + const highlight = + node.highlighted || + (node.id === (highlightedLink && highlightedLink.source) || + node.id === (highlightedLink && highlightedLink.target)); + const opacity = _getNodeOpacity(node, highlightedNode, highlightedLink, config); + let fill = node.color || config.node.color; + + if (highlight && config.node.highlightColor !== CONST.KEYWORDS.SAME) { + fill = config.node.highlightColor; + } + + let stroke = node.strokeColor || config.node.strokeColor; + + if (highlight && config.node.highlightStrokeColor !== CONST.KEYWORDS.SAME) { + stroke = config.node.highlightStrokeColor; + } + + let label = node[config.node.labelProperty] || node.id; + + if (typeof config.node.labelProperty === "function") { + label = config.node.labelProperty(node); + } + + const t = 1 / transform; + const nodeSize = node.size || config.node.size; + const fontSize = highlight ? config.node.highlightFontSize : config.node.fontSize; + const dx = fontSize * t + nodeSize / 100 + 1.5; + const strokeWidth = highlight ? config.node.highlightStrokeWidth : config.node.strokeWidth; + const svg = node.svg || config.node.svg; + const fontColor = node.fontColor || config.node.fontColor; + + return { + ...node, + className: CONST.NODE_CLASS_NAME, + cursor: config.node.mouseCursor, + cx: (node && node.x) || "0", + cy: (node && node.y) || "0", + fill, + fontColor, + fontSize: fontSize * t, + dx, + fontWeight: highlight ? config.node.highlightFontWeight : config.node.fontWeight, + id: node.id, + label, + onClickNode: nodeCallbacks.onClickNode, + onRightClickNode: nodeCallbacks.onRightClickNode, + onMouseOverNode: nodeCallbacks.onMouseOverNode, + onMouseOut: nodeCallbacks.onMouseOut, + opacity, + renderLabel: config.node.renderLabel, + size: nodeSize * t, + stroke, + strokeWidth: strokeWidth * t, + svg, + type: node.symbolType || config.node.symbolType, + viewGenerator: node.viewGenerator || config.node.viewGenerator, + overrideGlobalViewGenerator: !node.viewGenerator && node.svg, + }; +} + +export { buildLinkProps, buildNodeProps }; diff --git a/src/components/graph/graph.config.js b/src/components/graph/graph.config.js index ddb379726..dd354992c 100644 --- a/src/components/graph/graph.config.js +++ b/src/components/graph/graph.config.js @@ -46,19 +46,6 @@ * out of the box provide the look and feel of a directed graph and add directional semantic to links. You can see a sample in the image below. *
* - * @param {number} [height=400] - the height of the (svg) area where the graph will be rendered. - * @param {boolean} [nodeHighlightBehavior=false] - 🚅🚅🚅 when user mouse hovers a node that node and adjacent common - * connections will be highlighted (depending on the *highlightDegree* value). All the remaining nodes and links assume opacity value equal to **highlightOpacity**. - * @param {boolean} [linkHighlightBehavior=false] - 🚅🚅🚅 when the user mouse hovers some link that link and the correspondent nodes will be highlighted, this is a similar behavior - * to *nodeHighlightBehavior* but for links (just for historical reference this property was introduced in **v1.0.0**). - * @param {number} [highlightDegree=1] - **Possible values: 0, 1 or 2**. This value represents the range of the - * highlight behavior when some node is highlighted. If the value is set to **0** only the selected node will be - * highlighted. If the value is set to **1** the selected node and his 1st degree connections will be highlighted. If - * the value is set to **2** the selected node will be highlighted as well as the 1st and 2nd common degree connections. - * @param {number} [highlightOpacity=1] - this value is used to highlight nodes in the network. The lower - * the value the more the less highlighted nodes will be visible (related to *nodeHighlightBehavior*). - * @param {number} [maxZoom=8] - max zoom that can be performed against the graph. - * @param {number} [minZoom=0.1] - min zoom that can be performed against the graph. * @param {number} [focusZoom=1] - zoom that will be applied when the graph view is focused in a node. Its value must be between * *minZoom* and *maxZoom*. If the specified *focusZoom* is out of this range, *minZoom* or *maxZoom* will be applied instead. * **NOTE:** This animation is not trigger by default. In order to trigger it you need to pass down to `react-d3-graph` the @@ -75,6 +62,19 @@ * * * @param {number} [focusAnimationDuration=0.75] - duration (in seconds) for the animation that takes place when focusing the graph on a node. + * @param {number} [height=400] - the height of the (svg) area where the graph will be rendered. + * @param {boolean} [nodeHighlightBehavior=false] - 🚅🚅🚅 when user mouse hovers a node that node and adjacent common + * connections will be highlighted (depending on the *highlightDegree* value). All the remaining nodes and links assume opacity value equal to **highlightOpacity**. + * @param {boolean} [linkHighlightBehavior=false] - 🚅🚅🚅 when the user mouse hovers some link that link and the correspondent nodes will be highlighted, this is a similar behavior + * to *nodeHighlightBehavior* but for links (just for historical reference this property was introduced in **v1.0.0**). + * @param {number} [highlightDegree=1] - **Possible values: 0, 1 or 2**. This value represents the range of the + * highlight behavior when some node is highlighted. If the value is set to **0** only the selected node will be + * highlighted. If the value is set to **1** the selected node and his 1st degree connections will be highlighted. If + * the value is set to **2** the selected node will be highlighted as well as the 1st and 2nd common degree connections. + * @param {number} [highlightOpacity=1] - this value is used to highlight nodes in the network. The lower + * the value the more the less highlighted nodes will be visible (related to *nodeHighlightBehavior*). + * @param {number} [maxZoom=8] - max zoom that can be performed against the graph. + * @param {number} [minZoom=0.1] - min zoom that can be performed against the graph. * @param {boolean} [panAndZoom=false] - 🚅🚅🚅 pan and zoom effect when performing zoom in the graph, * a similar functionality may be consulted {@link https://bl.ocks.org/mbostock/2a39a768b1d4bc00a09650edef75ad39|here}. * @param {boolean} [staticGraph=false] - when setting this value to true the graph will be completely static, thus @@ -192,14 +192,14 @@ export default { automaticRearrangeAfterDropNode: false, collapsible: false, directed: false, + focusAnimationDuration: 0.75, + focusZoom: 1, height: 400, highlightDegree: 1, highlightOpacity: 1, linkHighlightBehavior: false, maxZoom: 8, minZoom: 0.1, - focusZoom: 1, - focusAnimationDuration: 0.75, nodeHighlightBehavior: false, panAndZoom: false, staticGraph: false, diff --git a/src/components/graph/graph.const.js b/src/components/graph/graph.const.js index 8f96a0662..fe93a9b53 100644 --- a/src/components/graph/graph.const.js +++ b/src/components/graph/graph.const.js @@ -2,7 +2,6 @@ import CONST from "../../const"; export default { COORDS_SEPARATOR: ",", - FORCE_IDEAL_STRENGTH: -100, // TODO: Expose as configurable, FORCE_X: 0.06, FORCE_Y: 0.06, GRAPH_CONTAINER_ID: "graph-container-zoomable", diff --git a/src/components/graph/graph.helper.js b/src/components/graph/graph.helper.js index 10bbb87ab..52202d9f6 100644 --- a/src/components/graph/graph.helper.js +++ b/src/components/graph/graph.helper.js @@ -1,4 +1,3 @@ -/*eslint max-lines: 0*/ /** * @module Graph/helper * @description @@ -32,8 +31,6 @@ import DEFAULT_CONFIG from "./graph.config"; import ERRORS from "../../err"; import utils from "../../utils"; -import { buildLinkPathDefinition } from "../link/link.helper"; -import { getMarkerId } from "../marker/marker.helper"; import { computeNodeDegree } from "./collapse.helper"; const NODE_PROPS_WHITELIST = ["id", "highlighted", "x", "y", "index", "vy", "vx"]; @@ -60,37 +57,6 @@ function _createForceSimulation(width, height, gravity) { .force("y", fry); } -/** - * Get the correct node opacity in order to properly make decisions based on context such as currently highlighted node. - * @param {Object} node - the node object for whom we will generate properties. - * @param {string} highlightedNode - same as {@link #renderGraph|highlightedNode in renderGraph}. - * @param {Object} highlightedLink - same as {@link #renderGraph|highlightedLink in renderGraph}. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. - * @returns {number} the opacity value for the given node. - * @memberof Graph/helper - */ -function _getNodeOpacity(node, highlightedNode, highlightedLink, config) { - const highlight = - node.highlighted || - node.id === (highlightedLink && highlightedLink.source) || - node.id === (highlightedLink && highlightedLink.target); - const someNodeHighlighted = !!( - highlightedNode || - (highlightedLink && highlightedLink.source && highlightedLink.target) - ); - let opacity; - - if (someNodeHighlighted && config.highlightDegree === 0) { - opacity = highlight ? config.node.opacity : config.highlightOpacity; - } else if (someNodeHighlighted) { - opacity = highlight ? config.node.opacity : config.highlightOpacity; - } else { - opacity = config.node.opacity; - } - - return opacity; -} - /** * Receives a matrix of the graph with the links source and target as concrete node instances and it transforms it * in a lightweight matrix containing only links with source and target being strings representative of some node id @@ -164,7 +130,7 @@ function _initializeNodes(graphNodes) { * @param {Object} link - input link. * @param {number} index - index of the input link. * @param {Array.} d3Links - all d3Links. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. * @param {Object} state - Graph component current state (same format as returned object on this function). * @returns {Object} a d3Link. * @memberof Graph/helper @@ -257,159 +223,6 @@ function _validateGraphData(data) { } } -/** - * Build some Link properties based on given parameters. - * @param {Object} link - the link object for which we will generate properties. - * @param {Object.} nodes - same as {@link #renderGraph|nodes in renderGraph}. - * @param {Object.} links - same as {@link #renderGraph|links in renderGraph}. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. - * @param {Function[]} linkCallbacks - same as {@link #renderGraph|linkCallbacks in renderGraph}. - * @param {string} highlightedNode - same as {@link #renderGraph|highlightedNode in renderGraph}. - * @param {Object} highlightedLink - same as {@link #renderGraph|highlightedLink in renderGraph}. - * @param {number} transform - value that indicates the amount of zoom transformation. - * @returns {Object} returns an object that aggregates all props for creating respective Link component instance. - * @memberof Graph/helper - */ -function buildLinkProps(link, nodes, links, config, linkCallbacks, highlightedNode, highlightedLink, transform) { - const { source, target } = link; - const x1 = (nodes[source] && nodes[source].x) || 0; - const y1 = (nodes[source] && nodes[source].y) || 0; - const x2 = (nodes[target] && nodes[target].x) || 0; - const y2 = (nodes[target] && nodes[target].y) || 0; - - const d = buildLinkPathDefinition({ source: { x: x1, y: y1 }, target: { x: x2, y: y2 } }, config.link.type); - - let mainNodeParticipates = false; - - switch (config.highlightDegree) { - case 0: - break; - case 2: - mainNodeParticipates = true; - break; - default: - // 1st degree is the fallback behavior - mainNodeParticipates = source === highlightedNode || target === highlightedNode; - break; - } - - const reasonNode = mainNodeParticipates && nodes[source].highlighted && nodes[target].highlighted; - const reasonLink = - source === (highlightedLink && highlightedLink.source) && - target === (highlightedLink && highlightedLink.target); - const highlight = reasonNode || reasonLink; - - let opacity = config.link.opacity; - - if (highlightedNode || (highlightedLink && highlightedLink.source)) { - opacity = highlight ? config.link.opacity : config.highlightOpacity; - } - - let stroke = link.color || config.link.color; - - if (highlight) { - stroke = config.link.highlightColor === CONST.KEYWORDS.SAME ? config.link.color : config.link.highlightColor; - } - - let strokeWidth = config.link.strokeWidth * (1 / transform); - - if (config.link.semanticStrokeWidth) { - const linkValue = links[source][target] || links[target][source] || 1; - - strokeWidth += (linkValue * strokeWidth) / 10; - } - - const markerId = config.directed ? getMarkerId(highlight, transform, config) : null; - - return { - markerId, - d, - source, - target, - strokeWidth, - stroke, - mouseCursor: config.link.mouseCursor, - className: CONST.LINK_CLASS_NAME, - opacity, - onClickLink: linkCallbacks.onClickLink, - onRightClickLink: linkCallbacks.onRightClickLink, - onMouseOverLink: linkCallbacks.onMouseOverLink, - onMouseOutLink: linkCallbacks.onMouseOutLink, - }; -} - -/** - * Build some Node properties based on given parameters. - * @param {Object} node - the node object for whom we will generate properties. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. - * @param {Function[]} nodeCallbacks - same as {@link #renderGraph|nodeCallbacks in renderGraph}. - * @param {string} highlightedNode - same as {@link #renderGraph|highlightedNode in renderGraph}. - * @param {Object} highlightedLink - same as {@link #renderGraph|highlightedLink in renderGraph}. - * @param {number} transform - value that indicates the amount of zoom transformation. - * @returns {Object} returns object that contain Link props ready to be feeded to the Link component. - * @memberof Graph/helper - */ -function buildNodeProps(node, config, nodeCallbacks = {}, highlightedNode, highlightedLink, transform) { - const highlight = - node.highlighted || - (node.id === (highlightedLink && highlightedLink.source) || - node.id === (highlightedLink && highlightedLink.target)); - const opacity = _getNodeOpacity(node, highlightedNode, highlightedLink, config); - let fill = node.color || config.node.color; - - if (highlight && config.node.highlightColor !== CONST.KEYWORDS.SAME) { - fill = config.node.highlightColor; - } - - let stroke = node.strokeColor || config.node.strokeColor; - - if (highlight && config.node.highlightStrokeColor !== CONST.KEYWORDS.SAME) { - stroke = config.node.highlightStrokeColor; - } - - let label = node[config.node.labelProperty] || node.id; - - if (typeof config.node.labelProperty === "function") { - label = config.node.labelProperty(node); - } - - const t = 1 / transform; - const nodeSize = node.size || config.node.size; - const fontSize = highlight ? config.node.highlightFontSize : config.node.fontSize; - const dx = fontSize * t + nodeSize / 100 + 1.5; - const strokeWidth = highlight ? config.node.highlightStrokeWidth : config.node.strokeWidth; - const svg = node.svg || config.node.svg; - const fontColor = node.fontColor || config.node.fontColor; - - return { - ...node, - className: CONST.NODE_CLASS_NAME, - cursor: config.node.mouseCursor, - cx: (node && node.x) || "0", - cy: (node && node.y) || "0", - fill, - fontColor, - fontSize: fontSize * t, - dx, - fontWeight: highlight ? config.node.highlightFontWeight : config.node.fontWeight, - id: node.id, - label, - onClickNode: nodeCallbacks.onClickNode, - onRightClickNode: nodeCallbacks.onRightClickNode, - onMouseOverNode: nodeCallbacks.onMouseOverNode, - onMouseOut: nodeCallbacks.onMouseOut, - opacity, - renderLabel: config.node.renderLabel, - size: nodeSize * t, - stroke, - strokeWidth: strokeWidth * t, - svg, - type: node.symbolType || config.node.symbolType, - viewGenerator: node.viewGenerator || config.node.viewGenerator, - overrideGlobalViewGenerator: !node.viewGenerator && node.svg, - }; -} - // list of properties that are of no interest when it comes to nodes and links comparison const NODE_PROPERTIES_DISCARD_TO_COMPARE = ["x", "y", "vx", "vy", "index"]; @@ -469,7 +282,7 @@ function checkForGraphConfigChanges(nextProps, currentState) { * Returns the transformation to apply in order to center the graph on the * selected node. * @param {Object} d3Node - node to focus the graph view on. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. * @returns {string} transform rule to apply. * @memberof Graph/helper */ @@ -492,7 +305,7 @@ function getCenterAndZoomTransformation(d3Node, config) { * @param {Object} props - Graph component props, object that holds data, id and config. * @param {Object} props.data - Data object holds links (array of **Link**) and nodes (array of **Node**). * @param {string} props.id - the graph id. - * @param {Object} props.config - same as {@link #renderGraph|config in renderGraph}. + * @param {Object} props.config - same as {@link #graphrenderer|config in renderGraph}. * @param {Object} state - Graph component current state (same format as returned object on this function). * @returns {Object} a fully (re)initialized graph state object. * @memberof Graph/helper @@ -580,8 +393,6 @@ function updateNodeHighlightedValue(nodes, links, config, id, value = false) { } export { - buildLinkProps, - buildNodeProps, checkForGraphConfigChanges, checkForGraphElementsChanges, getCenterAndZoomTransformation, diff --git a/src/components/graph/graph.renderer.jsx b/src/components/graph/graph.renderer.jsx index 6b6bb3a78..90cc08171 100644 --- a/src/components/graph/graph.renderer.jsx +++ b/src/components/graph/graph.renderer.jsx @@ -11,18 +11,18 @@ import { MARKERS, MARKER_SMALL_SIZE, MARKER_MEDIUM_OFFSET, MARKER_LARGE_OFFSET } import Link from "../link/Link"; import Node from "../node/Node"; import Marker from "../marker/Marker"; -import { buildLinkProps, buildNodeProps } from "./graph.helper"; +import { buildLinkProps, buildNodeProps } from "./graph.builder"; import { isNodeVisible } from "./collapse.helper"; /** * Build Link components given a list of links. - * @param {Object.} nodes - same as {@link #renderGraph|nodes in renderGraph}. + * @param {Object.} nodes - same as {@link #graphrenderer|nodes in renderGraph}. * @param {Array.} links - array of links {@link #Link|Link}. * @param {Array.} linksMatrix - array of links {@link #Link|Link}. - * @param {Object} config - same as {@link #renderGraph|config in renderGraph}. - * @param {Function[]} linkCallbacks - same as {@link #renderGraph|linkCallbacks in renderGraph}. - * @param {string} highlightedNode - same as {@link #renderGraph|highlightedNode in renderGraph}. - * @param {Object} highlightedLink - same as {@link #renderGraph|highlightedLink in renderGraph}. + * @param {Object} config - same as {@link #graphrenderer|config in renderGraph}. + * @param {Function[]} linkCallbacks - same as {@link #graphrenderer|linkCallbacks in renderGraph}. + * @param {string} highlightedNode - same as {@link #graphrenderer|highlightedNode in renderGraph}. + * @param {Object} highlightedLink - same as {@link #graphrenderer|highlightedLink in renderGraph}. * @param {number} transform - value that indicates the amount of zoom transformation. * @returns {Array.} returns the generated array of Link components. * @memberof Graph/helper diff --git a/test/graph/graph.builder.spec.js b/test/graph/graph.builder.spec.js new file mode 100644 index 000000000..26857821f --- /dev/null +++ b/test/graph/graph.builder.spec.js @@ -0,0 +1,247 @@ +import * as graphHelper from "../../src/components/graph/graph.builder"; + +import config from "../../src/components/graph/graph.config"; + +import utils from "../../src/utils"; +import * as linkHelper from "../../src/components/link/link.helper"; + +describe("Graph Helper", () => { + beforeAll(() => { + utils.isDeepEqual = jest.fn(); + utils.isEmptyObject = jest.fn(); + utils.merge = jest.fn(); + utils.throwErr = jest.fn(); + jest.spyOn(linkHelper, "buildLinkPathDefinition"); + }); + + describe("#buildLinkProps", () => { + let that = {}; + + beforeAll(() => { + that = { + config: { link: config.link }, + link: { source: "source", target: "target" }, + }; + }); + + describe("when building props for a link", () => { + test("should call buildLinkPathDefinition with expected parameters", () => { + graphHelper.buildLinkProps(that.link, {}, {}, that.config, [], undefined, undefined, 1); + + expect(linkHelper.buildLinkPathDefinition).toHaveBeenCalledWith( + { source: { x: 0, y: 0 }, target: { x: 0, y: 0 } }, + "STRAIGHT" + ); + }); + + describe("and no custom color is set", () => { + test("should return default color defined in link config", () => { + const props = graphHelper.buildLinkProps( + that.link, + {}, + {}, + that.config, + [], + undefined, + undefined, + 1 + ); + + expect(props.stroke).toEqual(that.config.link.color); + }); + }); + + describe("and custom color is set to green", () => { + test("should return green color in the props", () => { + const props = graphHelper.buildLinkProps( + { ...that.link, color: "green" }, + {}, + {}, + that.config, + [], + undefined, + undefined, + 1 + ); + + expect(props.stroke).toEqual("green"); + }); + }); + }); + }); + + describe("#buildNodeProps", () => { + let that = {}; + + beforeEach(() => { + const nodeConfig = Object.assign({}, config.node, { svg: "file.svg" }); + const linkConfig = Object.assign({}, config.link); + + that = { + config: { node: nodeConfig, link: linkConfig }, + node: { + id: "id", + x: 1, + y: 2, + color: "green", + highlighted: false, + symbolType: undefined, + }, + }; + }); + describe("when node to build is the highlightedNode", () => { + test("should return node props with proper highlight values", () => { + that.node.highlighted = true; + Object.assign(that.config.node, { + highlightColor: "red", + highlightFontSize: 12, + highlightFontWeight: "bold", + highlightStrokeColor: "yellow", + highlightStrokeWidth: 2, + }); + const props = graphHelper.buildNodeProps(that.node, that.config, undefined, "id", undefined, 1); + + expect(props).toEqual({ + ...that.node, + className: "node", + cursor: "pointer", + cx: 1, + cy: 2, + dx: 15.5, + fill: "red", + fontSize: 12, + fontWeight: "bold", + fontColor: "black", + id: "id", + label: "id", + onClickNode: undefined, + onRightClickNode: undefined, + onMouseOut: undefined, + onMouseOverNode: undefined, + opacity: 1, + renderLabel: true, + size: 200, + stroke: "yellow", + strokeWidth: 2, + svg: "file.svg", + type: "circle", + viewGenerator: null, + overrideGlobalViewGenerator: undefined, + }); + }); + }); + describe("when node to build is the highlightedLink target (or source)", () => { + describe("and highlight degree is 0", () => { + test("should properly build node props ()", () => { + that.config.highlightDegree = 0; + + const props = graphHelper.buildNodeProps( + that.node, + that.config, + undefined, + { + source: "some other id", + target: "id", + }, + undefined, + 1 + ); + + expect(props).toEqual({ + ...that.node, + className: "node", + cursor: "pointer", + cx: 1, + cy: 2, + dx: 11.5, + fill: "green", + fontSize: 8, + fontWeight: "normal", + fontColor: "black", + id: "id", + label: "id", + onClickNode: undefined, + onRightClickNode: undefined, + onMouseOut: undefined, + onMouseOverNode: undefined, + opacity: undefined, + renderLabel: true, + size: 200, + stroke: "none", + strokeWidth: 1.5, + svg: "file.svg", + type: "circle", + viewGenerator: null, + overrideGlobalViewGenerator: undefined, + }); + }); + }); + describe("and highlight degree is bigger then 0", () => { + test("should properly build node props", () => { + that.config.highlightDegree = 2; + + const props = graphHelper.buildNodeProps( + that.node, + that.config, + undefined, + { + source: "some other id", + target: "id", + }, + undefined, + 1 + ); + + expect(props).toEqual({ + ...that.node, + className: "node", + cursor: "pointer", + cx: 1, + cy: 2, + dx: 11.5, + fill: "green", + fontSize: 8, + fontWeight: "normal", + fontColor: "black", + id: "id", + label: "id", + onClickNode: undefined, + onRightClickNode: undefined, + onMouseOut: undefined, + onMouseOverNode: undefined, + opacity: undefined, + renderLabel: true, + size: 200, + stroke: "none", + strokeWidth: 1.5, + svg: "file.svg", + type: "circle", + viewGenerator: null, + overrideGlobalViewGenerator: undefined, + }); + }); + }); + }); + describe("and no custom strokeColor is set", () => { + test("should return the default strokeColor in the props", () => { + const props = graphHelper.buildNodeProps(that.node, that.config, undefined, undefined, undefined, 1); + + expect(props.stroke).toEqual("none"); + }); + }); + describe("and custom strokeColor is set to yellow", () => { + test("should return yellow strokeColor in the props", () => { + const props = graphHelper.buildNodeProps( + { ...that.node, strokeColor: "yellow" }, + that.config, + undefined, + undefined, + undefined, + 1 + ); + + expect(props.stroke).toEqual("yellow"); + }); + }); + }); +}); diff --git a/test/graph/graph.helper.spec.js b/test/graph/graph.helper.spec.js index 7947ec778..1bbef9807 100644 --- a/test/graph/graph.helper.spec.js +++ b/test/graph/graph.helper.spec.js @@ -1,9 +1,6 @@ import * as graphHelper from "../../src/components/graph/graph.helper"; -import config from "../../src/components/graph/graph.config"; - import utils from "../../src/utils"; -import * as linkHelper from "../../src/components/link/link.helper"; jest.mock("d3-force"); import { @@ -19,238 +16,6 @@ describe("Graph Helper", () => { utils.isEmptyObject = jest.fn(); utils.merge = jest.fn(); utils.throwErr = jest.fn(); - jest.spyOn(linkHelper, "buildLinkPathDefinition"); - }); - - describe("#buildLinkProps", () => { - let that = {}; - - beforeAll(() => { - that = { - config: { link: config.link }, - link: { source: "source", target: "target" }, - }; - }); - - describe("when building props for a link", () => { - test("should call buildLinkPathDefinition with expected parameters", () => { - graphHelper.buildLinkProps(that.link, {}, {}, that.config, [], undefined, undefined, 1); - - expect(linkHelper.buildLinkPathDefinition).toHaveBeenCalledWith( - { source: { x: 0, y: 0 }, target: { x: 0, y: 0 } }, - "STRAIGHT" - ); - }); - - describe("and no custom color is set", () => { - test("should return default color defined in link config", () => { - const props = graphHelper.buildLinkProps( - that.link, - {}, - {}, - that.config, - [], - undefined, - undefined, - 1 - ); - - expect(props.stroke).toEqual(that.config.link.color); - }); - }); - - describe("and custom color is set to green", () => { - test("should return green color in the props", () => { - const props = graphHelper.buildLinkProps( - { ...that.link, color: "green" }, - {}, - {}, - that.config, - [], - undefined, - undefined, - 1 - ); - - expect(props.stroke).toEqual("green"); - }); - }); - }); - }); - - describe("#buildNodeProps", () => { - let that = {}; - - beforeEach(() => { - const nodeConfig = Object.assign({}, config.node, { svg: "file.svg" }); - const linkConfig = Object.assign({}, config.link); - - that = { - config: { node: nodeConfig, link: linkConfig }, - node: { - id: "id", - x: 1, - y: 2, - color: "green", - highlighted: false, - symbolType: undefined, - }, - }; - }); - describe("when node to build is the highlightedNode", () => { - test("should return node props with proper highlight values", () => { - that.node.highlighted = true; - Object.assign(that.config.node, { - highlightColor: "red", - highlightFontSize: 12, - highlightFontWeight: "bold", - highlightStrokeColor: "yellow", - highlightStrokeWidth: 2, - }); - const props = graphHelper.buildNodeProps(that.node, that.config, undefined, "id", undefined, 1); - - expect(props).toEqual({ - ...that.node, - className: "node", - cursor: "pointer", - cx: 1, - cy: 2, - dx: 15.5, - fill: "red", - fontSize: 12, - fontWeight: "bold", - fontColor: "black", - id: "id", - label: "id", - onClickNode: undefined, - onRightClickNode: undefined, - onMouseOut: undefined, - onMouseOverNode: undefined, - opacity: 1, - renderLabel: true, - size: 200, - stroke: "yellow", - strokeWidth: 2, - svg: "file.svg", - type: "circle", - viewGenerator: null, - overrideGlobalViewGenerator: undefined, - }); - }); - }); - describe("when node to build is the highlightedLink target (or source)", () => { - describe("and highlight degree is 0", () => { - test("should properly build node props ()", () => { - that.config.highlightDegree = 0; - - const props = graphHelper.buildNodeProps( - that.node, - that.config, - undefined, - { - source: "some other id", - target: "id", - }, - undefined, - 1 - ); - - expect(props).toEqual({ - ...that.node, - className: "node", - cursor: "pointer", - cx: 1, - cy: 2, - dx: 11.5, - fill: "green", - fontSize: 8, - fontWeight: "normal", - fontColor: "black", - id: "id", - label: "id", - onClickNode: undefined, - onRightClickNode: undefined, - onMouseOut: undefined, - onMouseOverNode: undefined, - opacity: undefined, - renderLabel: true, - size: 200, - stroke: "none", - strokeWidth: 1.5, - svg: "file.svg", - type: "circle", - viewGenerator: null, - overrideGlobalViewGenerator: undefined, - }); - }); - }); - describe("and highlight degree is bigger then 0", () => { - test("should properly build node props", () => { - that.config.highlightDegree = 2; - - const props = graphHelper.buildNodeProps( - that.node, - that.config, - undefined, - { - source: "some other id", - target: "id", - }, - undefined, - 1 - ); - - expect(props).toEqual({ - ...that.node, - className: "node", - cursor: "pointer", - cx: 1, - cy: 2, - dx: 11.5, - fill: "green", - fontSize: 8, - fontWeight: "normal", - fontColor: "black", - id: "id", - label: "id", - onClickNode: undefined, - onRightClickNode: undefined, - onMouseOut: undefined, - onMouseOverNode: undefined, - opacity: undefined, - renderLabel: true, - size: 200, - stroke: "none", - strokeWidth: 1.5, - svg: "file.svg", - type: "circle", - viewGenerator: null, - overrideGlobalViewGenerator: undefined, - }); - }); - }); - }); - describe("and no custom strokeColor is set", () => { - test("should return the default strokeColor in the props", () => { - const props = graphHelper.buildNodeProps(that.node, that.config, undefined, undefined, undefined, 1); - - expect(props.stroke).toEqual("none"); - }); - }); - describe("and custom strokeColor is set to yellow", () => { - test("should return yellow strokeColor in the props", () => { - const props = graphHelper.buildNodeProps( - { ...that.node, strokeColor: "yellow" }, - that.config, - undefined, - undefined, - undefined, - 1 - ); - - expect(props.stroke).toEqual("yellow"); - }); - }); }); describe("#initializeGraphState", () => {