Files
lan-manager/web/node_modules/@antv/layout/lib/layout/circular.js
openclaw 0a5f6a8047 Initial commit: Lan-manager project code
- Go backend (server/)
- Frontend (web/, server/static/)
- Database and deployment files
- Scripts and docs

Co-Authored-By: 狸花猫/Claude-Qwen3.6-Plus 🐾
2026-04-20 00:52:58 +08:00

337 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
/**
* @fileOverview random layout
* @author shiwu.wyy@antfin.com
*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CircularLayout = void 0;
var base_1 = require("./base");
var util_1 = require("../util");
function initHierarchy(nodes, edges, nodeMap, directed) {
nodes.forEach(function (_, i) {
nodes[i].children = [];
nodes[i].parent = [];
});
if (directed) {
edges.forEach(function (e) {
var source = (0, util_1.getEdgeTerminal)(e, 'source');
var target = (0, util_1.getEdgeTerminal)(e, 'target');
var sourceIdx = 0;
if (source) {
sourceIdx = nodeMap[source];
}
var targetIdx = 0;
if (target) {
targetIdx = nodeMap[target];
}
var child = nodes[sourceIdx].children;
var parent = nodes[targetIdx].parent;
child.push(nodes[targetIdx].id);
parent.push(nodes[sourceIdx].id);
});
}
else {
edges.forEach(function (e) {
var source = (0, util_1.getEdgeTerminal)(e, 'source');
var target = (0, util_1.getEdgeTerminal)(e, 'target');
var sourceIdx = 0;
if (source) {
sourceIdx = nodeMap[source];
}
var targetIdx = 0;
if (target) {
targetIdx = nodeMap[target];
}
var sourceChildren = nodes[sourceIdx].children;
var targetChildren = nodes[targetIdx].children;
sourceChildren.push(nodes[targetIdx].id);
targetChildren.push(nodes[sourceIdx].id);
});
}
}
function connect(a, b, edges) {
var m = edges.length;
for (var i = 0; i < m; i++) {
var source = (0, util_1.getEdgeTerminal)(edges[i], 'source');
var target = (0, util_1.getEdgeTerminal)(edges[i], 'target');
if ((a.id === source && b.id === target) ||
(b.id === source && a.id === target)) {
return true;
}
}
return false;
}
function compareDegree(a, b) {
var aDegree = a.degree;
var bDegree = b.degree;
if (aDegree < bDegree) {
return -1;
}
if (aDegree > bDegree) {
return 1;
}
return 0;
}
/**
* 圆形布局
*/
var CircularLayout = /** @class */ (function (_super) {
__extends(CircularLayout, _super);
function CircularLayout(options) {
var _this = _super.call(this) || this;
/** 固定半径,若设置了 radius则 startRadius 与 endRadius 不起效 */
_this.radius = null;
/** 节点大小,配合 nodeSpacing一起用于计算 radius。若不配置节点大小默认为 30 */
_this.nodeSize = undefined;
/** 起始半径 */
_this.startRadius = null;
/** 终止半径 */
_this.endRadius = null;
/** 起始角度 */
_this.startAngle = 0;
/** 终止角度 */
_this.endAngle = 2 * Math.PI;
/** 是否顺时针 */
_this.clockwise = true;
/** 节点在环上分成段数(几个段将均匀分布),在 endRadius - startRadius != 0 时生效 */
_this.divisions = 1;
/** 节点在环上排序的依据,可选: 'topology', 'degree', 'null' */
_this.ordering = null;
/** how many 2*pi from first to last nodes */
_this.angleRatio = 1;
_this.nodes = [];
_this.edges = [];
_this.nodeMap = {};
_this.degrees = [];
_this.width = 300;
_this.height = 300;
_this.updateCfg(options);
return _this;
}
CircularLayout.prototype.getDefaultCfg = function () {
return {
radius: null,
startRadius: null,
endRadius: null,
startAngle: 0,
endAngle: 2 * Math.PI,
clockwise: true,
divisions: 1,
ordering: null,
angleRatio: 1
};
};
/**
* 执行布局
*/
CircularLayout.prototype.execute = function () {
var _a;
var self = this;
var nodes = self.nodes;
var edges = self.edges;
var n = nodes.length;
if (n === 0) {
if (self.onLayoutEnd)
self.onLayoutEnd();
return;
}
if (!self.width && typeof window !== "undefined") {
self.width = window.innerWidth;
}
if (!self.height && typeof window !== "undefined") {
self.height = window.innerHeight;
}
if (!self.center) {
self.center = [self.width / 2, self.height / 2];
}
var center = self.center;
if (n === 1) {
nodes[0].x = center[0];
nodes[0].y = center[1];
if (self.onLayoutEnd)
self.onLayoutEnd();
return;
}
var radius = self.radius, startRadius = self.startRadius, endRadius = self.endRadius;
var divisions = self.divisions, startAngle = self.startAngle, endAngle = self.endAngle, angleRatio = self.angleRatio, ordering = self.ordering, clockwise = self.clockwise, paramNodeSpacing = self.nodeSpacing, paramNodeSize = self.nodeSize;
var angleStep = (endAngle - startAngle) / n;
// layout
var nodeMap = {};
nodes.forEach(function (node, i) {
nodeMap[node.id] = i;
});
self.nodeMap = nodeMap;
var degrees = (0, util_1.getDegree)(nodes.length, nodeMap, edges);
self.degrees = degrees;
if (paramNodeSpacing) {
var nodeSpacing_1 = (0, util_1.getFuncByUnknownType)(10, paramNodeSpacing);
var nodeSize_1 = (0, util_1.getFuncByUnknownType)(10, paramNodeSize);
var maxNodeSize_1 = -Infinity;
nodes.forEach(function (node) {
var nSize = nodeSize_1(node);
if (maxNodeSize_1 < nSize)
maxNodeSize_1 = nSize;
});
var length_1 = 0;
nodes.forEach(function (node, i) {
if (i === 0)
length_1 += (maxNodeSize_1 || 10);
else
length_1 += (nodeSpacing_1(node) || 0) + (maxNodeSize_1 || 10);
});
radius = length_1 / (2 * Math.PI);
}
else if (!radius && !startRadius && !endRadius) {
radius = self.height > self.width ? self.width / 2 : self.height / 2;
}
else if (!startRadius && endRadius) {
startRadius = endRadius;
}
else if (startRadius && !endRadius) {
endRadius = startRadius;
}
var astep = angleStep * angleRatio;
var layoutNodes = [];
if (ordering === "topology") {
// layout according to the topology
layoutNodes = self.topologyOrdering();
}
else if (ordering === "topology-directed") {
// layout according to the topology
layoutNodes = self.topologyOrdering(true);
}
else if (ordering === "degree") {
// layout according to the descent order of degrees
layoutNodes = self.degreeOrdering();
}
else {
// layout according to the original order in the data.nodes
layoutNodes = nodes;
}
var divN = Math.ceil(n / divisions); // node number in each division
for (var i = 0; i < n; ++i) {
var r = radius;
if (!r && startRadius !== null && endRadius !== null) {
r = startRadius + (i * (endRadius - startRadius)) / (n - 1);
}
if (!r) {
r = 10 + (i * 100) / (n - 1);
}
var angle = startAngle +
(i % divN) * astep +
((2 * Math.PI) / divisions) * Math.floor(i / divN);
if (!clockwise) {
angle =
endAngle -
(i % divN) * astep -
((2 * Math.PI) / divisions) * Math.floor(i / divN);
}
layoutNodes[i].x = center[0] + Math.cos(angle) * r;
layoutNodes[i].y = center[1] + Math.sin(angle) * r;
layoutNodes[i].weight = degrees[i].all;
}
(_a = self.onLayoutEnd) === null || _a === void 0 ? void 0 : _a.call(self);
return {
nodes: layoutNodes,
edges: this.edges
};
};
/**
* 根据节点的拓扑结构排序
* @return {array} orderedNodes 排序后的结果
*/
CircularLayout.prototype.topologyOrdering = function (directed) {
if (directed === void 0) { directed = false; }
var self = this;
var degrees = self.degrees;
var edges = self.edges;
var nodes = self.nodes;
var cnodes = (0, util_1.clone)(nodes);
var nodeMap = self.nodeMap;
var orderedCNodes = [cnodes[0]];
var resNodes = [nodes[0]];
var pickFlags = [];
var n = nodes.length;
pickFlags[0] = true;
initHierarchy(cnodes, edges, nodeMap, directed);
var k = 0;
cnodes.forEach(function (cnode, i) {
if (i !== 0) {
if ((i === n - 1 ||
degrees[i].all !== degrees[i + 1].all ||
connect(orderedCNodes[k], cnode, edges)) &&
!pickFlags[i]) {
orderedCNodes.push(cnode);
resNodes.push(nodes[nodeMap[cnode.id]]);
pickFlags[i] = true;
k++;
}
else {
var children = orderedCNodes[k].children;
var foundChild = false;
for (var j = 0; j < children.length; j++) {
var childIdx = nodeMap[children[j]];
if (degrees[childIdx].all === degrees[i].all && !pickFlags[childIdx]) {
orderedCNodes.push(cnodes[childIdx]);
resNodes.push(nodes[nodeMap[cnodes[childIdx].id]]);
pickFlags[childIdx] = true;
foundChild = true;
break;
}
}
var ii = 0;
while (!foundChild) {
if (!pickFlags[ii]) {
orderedCNodes.push(cnodes[ii]);
resNodes.push(nodes[nodeMap[cnodes[ii].id]]);
pickFlags[ii] = true;
foundChild = true;
}
ii++;
if (ii === n) {
break;
}
}
}
}
});
return resNodes;
};
/**
* 根据节点度数大小排序
* @return {array} orderedNodes 排序后的结果
*/
CircularLayout.prototype.degreeOrdering = function () {
var self = this;
var nodes = self.nodes;
var orderedNodes = [];
var degrees = self.degrees;
nodes.forEach(function (node, i) {
node.degree = degrees[i].all;
orderedNodes.push(node);
});
orderedNodes.sort(compareDegree);
return orderedNodes;
};
CircularLayout.prototype.getType = function () {
return "circular";
};
return CircularLayout;
}(base_1.Base));
exports.CircularLayout = CircularLayout;
//# sourceMappingURL=circular.js.map