almus-d3-graph
Version:
React component to build interactive and configurable graphs with d3 effortlessly
204 lines (185 loc) • 8.4 kB
JSX
/**
* @module Graph/renderer
* @description
* Offers a series of methods that isolate render logic for Graph component.
*/
import React from "react";
import CONST from "./graph.const";
import { MARKERS, MARKER_SMALL_SIZE, MARKER_MEDIUM_OFFSET, MARKER_LARGE_OFFSET } from "../marker/marker.const";
import Link from "../link/Link";
import Node from "../node/Node";
import Marker from "../marker/Marker";
import { buildLinkProps, buildNodeProps } from "./graph.builder";
import { isNodeVisible } from "./collapse.helper";
/**
* Build Link components given a list of links.
* @param {Object.<string, Object>} nodes - same as {@link #graphrenderer|nodes in renderGraph}.
* @param {Array.<Object>} links - array of links {@link #Link|Link}.
* @param {Array.<Object>} linksMatrix - array of links {@link #Link|Link}.
* @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.<Object>} returns the generated array of Link components.
* @memberof Graph/renderer
*/
function _renderLinks(nodes, links, linksMatrix, config, linkCallbacks, highlightedNode, highlightedLink, transform) {
let outLinks = links;
if (config.collapsible) {
outLinks = outLinks.filter(({ isHidden }) => !isHidden);
}
return outLinks.map(link => {
const { source, target } = link;
// FIXME: solve this source data inconsistency later
const sourceId = source.id !== undefined && source.id !== null ? source.id : source;
const targetId = target.id !== undefined && target.id !== null ? target.id : target;
const key = `${sourceId}${CONST.COORDS_SEPARATOR}${targetId}`;
const props = buildLinkProps(
{ ...link, source: `${sourceId}`, target: `${targetId}` },
nodes,
linksMatrix,
config,
linkCallbacks,
`${highlightedNode}`,
highlightedLink,
transform
);
return <Link key={key} id={key} {...props} />;
});
}
/**
* Function that builds Node components.
* @param {Object.<string, Object>} nodes - an object containing all nodes mapped by their id.
* @param {Function[]} nodeCallbacks - array of callbacks for used defined event handler for node interactions.
* @param {Object} config - an object containing rd3g consumer defined configurations {@link #config config} for the graph.
* @param {string} highlightedNode - this value contains a string that represents the some currently highlighted node.
* @param {Object} highlightedLink - this object contains a source and target property for a link that is highlighted at some point in time.
* @param {string} highlightedLink.source - id of source node for highlighted link.
* @param {string} highlightedLink.target - id of target node for highlighted link.
* @param {number} transform - value that indicates the amount of zoom transformation.
* @param {Object.<string, Object>} linksMatrix - the matrix of connections of the graph
* @returns {Array.<Object>} returns the generated array of node components
* @memberof Graph/renderer
*/
function _renderNodes(nodes, nodeCallbacks, config, highlightedNode, highlightedLink, transform, linksMatrix) {
let outNodes = Object.keys(nodes);
if (config.collapsible) {
outNodes = outNodes.filter(nodeId => isNodeVisible(nodeId, nodes, linksMatrix));
}
return outNodes.map(nodeId => {
const props = buildNodeProps(
Object.assign({}, nodes[nodeId], { id: `${nodeId}` }),
config,
nodeCallbacks,
highlightedNode,
highlightedLink,
transform
);
return <Node key={nodeId} {...props} />;
});
}
/**
* Builds graph defs (for now markers, but we could also have gradients for instance).
* NOTE: defs are static svg graphical objects, thus we only need to render them once, the result
* is cached on the 1st call and from there we simply return the cached jsx.
* @returns {Function} memoized build definitions function.
* @memberof Graph/renderer
*/
function _renderDefs() {
let cachedDefs;
return config => {
if (cachedDefs) {
return cachedDefs;
}
const small = MARKER_SMALL_SIZE;
const medium = small + (MARKER_MEDIUM_OFFSET * config.maxZoom) / 3;
const large = small + (MARKER_LARGE_OFFSET * config.maxZoom) / 3;
cachedDefs = (
<defs>
<Marker id={MARKERS.MARKER_S} refX={small} fill={config.link.color} />
<Marker id={MARKERS.MARKER_SH} refX={small} fill={config.link.highlightColor} />
<Marker id={MARKERS.MARKER_M} refX={medium} fill={config.link.color} />
<Marker id={MARKERS.MARKER_MH} refX={medium} fill={config.link.highlightColor} />
<Marker id={MARKERS.MARKER_L} refX={large} fill={config.link.color} />
<Marker id={MARKERS.MARKER_LH} refX={large} fill={config.link.highlightColor} />
</defs>
);
return cachedDefs;
};
}
/**
* Memoized reference for _renderDefs.
* @param {Object} config - an object containing rd3g consumer defined configurations {@link #config config} for the graph.
* @returns {Object} graph reusable objects [defs](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs).
* @memberof Graph/renderer
*/
const _memoizedRenderDefs = _renderDefs();
/**
* Method that actually is exported an consumed by Graph component in order to build all Nodes and Link
* components.
* @param {Object.<string, Object>} nodes - an object containing all nodes mapped by their id.
* @param {Function[]} nodeCallbacks - array of callbacks for used defined event handler for node interactions.
* @param {Array.<Object>} links - array of links {@link #Link|Link}.
* @param {Object.<string, 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).
* ```javascript
* // links example
* {
* "Androsynth": {
* "Chenjesu": 1,
* "Ilwrath": 1,
* "Mycon": 1,
* "Spathi": 1,
* "Umgah": 1,
* "VUX": 1,
* "Guardian": 1
* },
* "Chenjesu": {
* "Androsynth": 1,
* "Mycon": 1,
* "Spathi": 1,
* "Umgah": 1,
* "VUX": 1,
* "Broodhmome": 1
* },
* ...
* }
* ```
* @param {Function[]} linkCallbacks - array of callbacks for used defined event handler for link interactions.
* @param {Object} config - an object containing rd3g consumer defined configurations {@link #config config} for the graph.
* @param {string} highlightedNode - this value contains a string that represents the some currently highlighted node.
* @param {Object} highlightedLink - this object contains a source and target property for a link that is highlighted at some point in time.
* @param {string} highlightedLink.source - id of source node for highlighted link.
* @param {string} highlightedLink.target - id of target node for highlighted link.
* @param {number} transform - value that indicates the amount of zoom transformation.
* @returns {Object} returns an object containing the generated nodes and links that form the graph.
* @memberof Graph/renderer
*/
function renderGraph(
nodes,
nodeCallbacks,
links,
linksMatrix,
linkCallbacks,
config,
highlightedNode,
highlightedLink,
transform
) {
return {
nodes: _renderNodes(nodes, nodeCallbacks, config, highlightedNode, highlightedLink, transform, linksMatrix),
links: _renderLinks(
nodes,
links,
linksMatrix,
config,
linkCallbacks,
highlightedNode,
highlightedLink,
transform
),
defs: _memoizedRenderDefs(config),
};
}
export { renderGraph };