@antv/g2plot
Version:
An interactive and responsive charting library
187 lines • 6.94 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.chordLayout = exports.getDefaultOptions = void 0;
/*
* for Arc Diagram (edges without weight) / Chord Diagram (edges with source and target weight)
* graph data required (nodes, edges)
*/
var util_1 = require("@antv/util");
var DEFAULT_OPTIONS = {
y: 0,
nodeWidthRatio: 0.05,
weight: false,
nodePaddingRatio: 0.1,
id: function (node) { return node.id; },
source: function (edge) { return edge.source; },
target: function (edge) { return edge.target; },
sourceWeight: function (edge) { return edge.value || 1; },
targetWeight: function (edge) { return edge.value || 1; },
sortBy: null, // optional, id | weight | frequency | {function}
};
/**
* 处理节点的value、edges
* @param nodeById
* @param edges
* @param options
*/
function processGraph(nodeById, edges, options) {
(0, util_1.forIn)(nodeById, function (node, id) {
// in edges, out edges
node.inEdges = edges.filter(function (edge) { return "".concat(options.target(edge)) === "".concat(id); });
node.outEdges = edges.filter(function (edge) { return "".concat(options.source(edge)) === "".concat(id); });
// frequency
node.edges = node.outEdges.concat(node.inEdges);
node.frequency = node.edges.length;
// weight
node.value = 0;
node.inEdges.forEach(function (edge) {
node.value += options.targetWeight(edge);
});
node.outEdges.forEach(function (edge) {
node.value += options.sourceWeight(edge);
});
});
}
/**
* 节点排序
* @param nodes
* @param options
*/
function sortNodes(nodes, options) {
var sortMethods = {
weight: function (a, b) { return b.value - a.value; },
frequency: function (a, b) { return b.frequency - a.frequency; },
id: function (a, b) { return "".concat(options.id(a)).localeCompare("".concat(options.id(b))); },
};
var method = sortMethods[options.sortBy];
if (!method && (0, util_1.isFunction)(options.sortBy)) {
method = options.sortBy;
}
if (method) {
nodes.sort(method);
}
}
function layoutNodes(nodes, options) {
var len = nodes.length;
if (!len) {
throw new TypeError("Invalid nodes: it's empty!");
}
if (options.weight) {
var nodePaddingRatio_1 = options.nodePaddingRatio;
if (nodePaddingRatio_1 < 0 || nodePaddingRatio_1 >= 1) {
throw new TypeError('Invalid nodePaddingRatio: it must be in range [0, 1)!');
}
var margin_1 = nodePaddingRatio_1 / (2 * len);
var nodeWidthRatio_1 = options.nodeWidthRatio;
if (nodeWidthRatio_1 <= 0 || nodeWidthRatio_1 >= 1) {
throw new TypeError('Invalid nodeWidthRatio: it must be in range (0, 1)!');
}
var totalValue_1 = 0;
nodes.forEach(function (node) {
totalValue_1 += node.value;
});
nodes.forEach(function (node) {
node.weight = node.value / totalValue_1;
node.width = node.weight * (1 - nodePaddingRatio_1);
node.height = nodeWidthRatio_1;
});
nodes.forEach(function (node, index) {
// x
var deltaX = 0;
for (var i = index - 1; i >= 0; i--) {
deltaX += nodes[i].width + 2 * margin_1;
}
var minX = (node.minX = margin_1 + deltaX);
var maxX = (node.maxX = node.minX + node.width);
var minY = (node.minY = options.y - nodeWidthRatio_1 / 2);
var maxY = (node.maxY = minY + nodeWidthRatio_1);
node.x = [minX, maxX, maxX, minX];
node.y = [minY, minY, maxY, maxY];
/* points
* 3---2
* | |
* 0---1
*/
// node.x = minX + 0.5 * node.width;
// node.y = options.y;
});
}
else {
var deltaX_1 = 1 / len;
nodes.forEach(function (node, index) {
node.x = (index + 0.5) * deltaX_1;
node.y = options.y;
});
}
return nodes;
}
function locatingEdges(nodeById, edges, options) {
if (options.weight) {
var valueById_1 = {};
(0, util_1.forIn)(nodeById, function (node, id) {
valueById_1[id] = node.value;
});
edges.forEach(function (edge) {
var sId = options.source(edge);
var tId = options.target(edge);
var sNode = nodeById[sId];
var tNode = nodeById[tId];
if (sNode && tNode) {
var sValue = valueById_1[sId];
var currentSValue = options.sourceWeight(edge);
var sStart = sNode.minX + ((sNode.value - sValue) / sNode.value) * sNode.width;
var sEnd = sStart + (currentSValue / sNode.value) * sNode.width;
valueById_1[sId] -= currentSValue;
var tValue = valueById_1[tId];
var currentTValue = options.targetWeight(edge);
var tStart = tNode.minX + ((tNode.value - tValue) / tNode.value) * tNode.width;
var tEnd = tStart + (currentTValue / tNode.value) * tNode.width;
valueById_1[tId] -= currentTValue;
var y = options.y;
edge.x = [sStart, sEnd, tStart, tEnd];
edge.y = [y, y, y, y];
// 将edge的source与target的id换为 sourceNode与targetNode
edge.source = sNode;
edge.target = tNode;
}
});
}
else {
edges.forEach(function (edge) {
var sNode = nodeById[options.source(edge)];
var tNode = nodeById[options.target(edge)];
if (sNode && tNode) {
edge.x = [sNode.x, tNode.x];
edge.y = [sNode.y, tNode.y];
// 将edge的source与target的id换为 sourceNode与targetNode
edge.source = sNode;
edge.target = tNode;
}
});
}
return edges;
}
function getDefaultOptions(options) {
return (0, util_1.assign)({}, DEFAULT_OPTIONS, options);
}
exports.getDefaultOptions = getDefaultOptions;
function chordLayout(chordLayoutOptions, chordLayoutInputData) {
var options = getDefaultOptions(chordLayoutOptions);
var nodeById = {};
var nodes = chordLayoutInputData.nodes;
var links = chordLayoutInputData.links;
nodes.forEach(function (node) {
var id = options.id(node);
nodeById[id] = node;
});
processGraph(nodeById, links, options);
sortNodes(nodes, options);
var outputNodes = layoutNodes(nodes, options);
var outputLinks = locatingEdges(nodeById, links, options);
return {
nodes: outputNodes,
links: outputLinks,
};
}
exports.chordLayout = chordLayout;
//# sourceMappingURL=chord.js.map
;