mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-05 11:11:13 +00:00
95 lines
2.5 KiB
JavaScript
95 lines
2.5 KiB
JavaScript
import debug from 'debug';
|
|
import { createSelector } from 'reselect';
|
|
import { Map as makeMap } from 'immutable';
|
|
import timely from 'timely';
|
|
|
|
import { EDGE_ID_SEPARATOR } from '../constants/naming';
|
|
import { doLayout } from '../charts/nodes-layout';
|
|
|
|
const log = debug('scope:nodes-chart');
|
|
|
|
|
|
const stateWidthSelector = state => state.width;
|
|
const stateHeightSelector = state => state.height;
|
|
const inputNodesSelector = (_, props) => props.nodes;
|
|
const propsMarginsSelector = (_, props) => props.margins;
|
|
const forceRelayoutSelector = (_, props) => props.forceRelayout;
|
|
const topologyIdSelector = (_, props) => props.topologyId;
|
|
const topologyOptionsSelector = (_, props) => props.topologyOptions;
|
|
|
|
|
|
function initEdgesFromNodes(nodes) {
|
|
let edges = makeMap();
|
|
|
|
nodes.forEach((node, nodeId) => {
|
|
const adjacency = node.get('adjacency');
|
|
if (adjacency) {
|
|
adjacency.forEach((adjacent) => {
|
|
const edge = [nodeId, adjacent];
|
|
const edgeId = edge.join(EDGE_ID_SEPARATOR);
|
|
|
|
if (!edges.has(edgeId)) {
|
|
const source = edge[0];
|
|
const target = edge[1];
|
|
if (nodes.has(source) && nodes.has(target)) {
|
|
edges = edges.set(edgeId, makeMap({
|
|
id: edgeId,
|
|
value: 1,
|
|
source,
|
|
target
|
|
}));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
return edges;
|
|
}
|
|
|
|
const layoutOptionsSelector = createSelector(
|
|
[
|
|
stateWidthSelector,
|
|
stateHeightSelector,
|
|
propsMarginsSelector,
|
|
forceRelayoutSelector,
|
|
topologyIdSelector,
|
|
topologyOptionsSelector,
|
|
],
|
|
(width, height, margins, forceRelayout, topologyId, topologyOptions) => (
|
|
{ width, height, margins, forceRelayout, topologyId, topologyOptions }
|
|
)
|
|
);
|
|
|
|
export const graphLayout = createSelector(
|
|
[
|
|
inputNodesSelector,
|
|
layoutOptionsSelector,
|
|
],
|
|
(nodes, options) => {
|
|
// If the graph is empty, skip computing the layout.
|
|
if (nodes.size === 0) {
|
|
return {
|
|
layoutNodes: makeMap(),
|
|
layoutEdges: makeMap(),
|
|
};
|
|
}
|
|
|
|
const edges = initEdgesFromNodes(nodes);
|
|
const timedLayouter = timely(doLayout);
|
|
const graph = timedLayouter(nodes, edges, options);
|
|
|
|
// NOTE: We probably shouldn't log anything in a
|
|
// computed property, but this is still useful.
|
|
log(`graph layout calculation took ${timedLayouter.time}ms`);
|
|
|
|
const layoutEdges = graph.edges;
|
|
const layoutNodes = graph.nodes.map(node => makeMap({
|
|
x: node.get('x'),
|
|
y: node.get('y'),
|
|
}));
|
|
|
|
return { layoutNodes, layoutEdges };
|
|
}
|
|
);
|