Severian's picture
Upload 7464 files
c211499
import * as d3 from 'd3';
import * as _ from 'lodash-es';
import { layout } from '../dagre/index.js';
import { arrows, setArrows } from './arrows.js';
import { createClusters, setCreateClusters } from './create-clusters.js';
import { createEdgeLabels, setCreateEdgeLabels } from './create-edge-labels.js';
import { createEdgePaths, setCreateEdgePaths } from './create-edge-paths.js';
import { createNodes, setCreateNodes } from './create-nodes.js';
import { positionClusters } from './position-clusters.js';
import { positionEdgeLabels } from './position-edge-labels.js';
import { positionNodes } from './position-nodes.js';
import { shapes, setShapes } from './shapes.js';
export { render };
// This design is based on http://bost.ocks.org/mike/chart/.
function render() {
var fn = function (svg, g) {
preProcessGraph(g);
var outputGroup = createOrSelectGroup(svg, 'output');
var clustersGroup = createOrSelectGroup(outputGroup, 'clusters');
var edgePathsGroup = createOrSelectGroup(outputGroup, 'edgePaths');
var edgeLabels = createEdgeLabels(createOrSelectGroup(outputGroup, 'edgeLabels'), g);
var nodes = createNodes(createOrSelectGroup(outputGroup, 'nodes'), g, shapes);
layout(g);
positionNodes(nodes, g);
positionEdgeLabels(edgeLabels, g);
createEdgePaths(edgePathsGroup, g, arrows);
var clusters = createClusters(clustersGroup, g);
positionClusters(clusters, g);
postProcessGraph(g);
};
fn.createNodes = function (value) {
if (!arguments.length) return createNodes;
setCreateNodes(value);
return fn;
};
fn.createClusters = function (value) {
if (!arguments.length) return createClusters;
setCreateClusters(value);
return fn;
};
fn.createEdgeLabels = function (value) {
if (!arguments.length) return createEdgeLabels;
setCreateEdgeLabels(value);
return fn;
};
fn.createEdgePaths = function (value) {
if (!arguments.length) return createEdgePaths;
setCreateEdgePaths(value);
return fn;
};
fn.shapes = function (value) {
if (!arguments.length) return shapes;
setShapes(value);
return fn;
};
fn.arrows = function (value) {
if (!arguments.length) return arrows;
setArrows(value);
return fn;
};
return fn;
}
var NODE_DEFAULT_ATTRS = {
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
rx: 0,
ry: 0,
shape: 'rect',
};
var EDGE_DEFAULT_ATTRS = {
arrowhead: 'normal',
curve: d3.curveLinear,
};
function preProcessGraph(g) {
g.nodes().forEach(function (v) {
var node = g.node(v);
if (!_.has(node, 'label') && !g.children(v).length) {
node.label = v;
}
if (_.has(node, 'paddingX')) {
_.defaults(node, {
paddingLeft: node.paddingX,
paddingRight: node.paddingX,
});
}
if (_.has(node, 'paddingY')) {
_.defaults(node, {
paddingTop: node.paddingY,
paddingBottom: node.paddingY,
});
}
if (_.has(node, 'padding')) {
_.defaults(node, {
paddingLeft: node.padding,
paddingRight: node.padding,
paddingTop: node.padding,
paddingBottom: node.padding,
});
}
_.defaults(node, NODE_DEFAULT_ATTRS);
_.each(['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'], function (k) {
node[k] = Number(node[k]);
});
// Save dimensions for restore during post-processing
if (_.has(node, 'width')) {
node._prevWidth = node.width;
}
if (_.has(node, 'height')) {
node._prevHeight = node.height;
}
});
g.edges().forEach(function (e) {
var edge = g.edge(e);
if (!_.has(edge, 'label')) {
edge.label = '';
}
_.defaults(edge, EDGE_DEFAULT_ATTRS);
});
}
function postProcessGraph(g) {
_.each(g.nodes(), function (v) {
var node = g.node(v);
// Restore original dimensions
if (_.has(node, '_prevWidth')) {
node.width = node._prevWidth;
} else {
delete node.width;
}
if (_.has(node, '_prevHeight')) {
node.height = node._prevHeight;
} else {
delete node.height;
}
delete node._prevWidth;
delete node._prevHeight;
});
}
function createOrSelectGroup(root, name) {
var selection = root.select('g.' + name);
if (selection.empty()) {
selection = root.append('g').attr('class', name);
}
return selection;
}