Files
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

781 lines
30 KiB
JavaScript
Raw Permalink 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";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _tslib = require("tslib");
var _g6Core = require("@antv/g6-core");
var _layout = require("../../layout");
var _layout2 = require("../../layout/worker/layout");
var _layoutConst = require("../../layout/worker/layoutConst");
var _gpu = require("../../util/gpu");
var _util = require("@antv/util");
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
// eslint-disable-next-line @typescript-eslint/no-implied-eval
var mockRaf = function mockRaf(cb) {
return setTimeout(cb, 16);
};
var mockCaf = function mockCaf(reqId) {
return clearTimeout(reqId);
};
var helper = {
// pollyfill
requestAnimationFrame: function requestAnimationFrame(callback) {
var fn = typeof window !== 'undefined' ? window.requestAnimationFrame || window.webkitRequestAnimationFrame || mockRaf : mockRaf;
return fn(callback);
},
cancelAnimationFrame: function cancelAnimationFrame(requestId) {
var fn = typeof window !== 'undefined' ? window.cancelAnimationFrame || window.webkitCancelAnimationFrame || mockCaf : mockCaf;
return fn(requestId);
}
};
var GPU_LAYOUT_NAMES = ['fruchterman', 'gForce'];
var LAYOUT_PIPES_ADJUST_NAMES = ['force', 'grid', 'circular'];
var LayoutController = /** @class */function (_super) {
(0, _tslib.__extends)(LayoutController, _super);
// the configurations of the layout
// private layoutCfg: any; // LayoutOptions
// the type name of the layout
// private layoutType: string;
// private data: GraphData;
// private layoutMethods: typeof Layout;
function LayoutController(graph) {
var _this = _super.call(this, graph) || this;
_this.graph = graph;
_this.layoutCfg = graph.get('layout') || {};
_this.layoutType = _this.getLayoutType();
_this.worker = null;
_this.workerData = {};
_this.initLayout();
return _this;
}
// eslint-disable-next-line class-methods-use-this
LayoutController.prototype.initLayout = function () {
// no data before rendering
};
// get layout worker and create one if not exists
LayoutController.prototype.getWorker = function () {
if (this.worker) {
return this.worker;
}
if (typeof Worker === 'undefined') {
// 如果当前浏览器不支持 web worker则不使用 web worker
console.warn('Web worker is not supported in current browser.');
this.worker = null;
} else {
this.worker = (0, _layout2.LayoutWorker)(this.layoutCfg.workerScriptURL);
}
return this.worker;
};
// stop layout worker
LayoutController.prototype.stopWorker = function () {
var workerData = this.workerData;
if (!this.worker) {
return;
}
this.worker.terminate();
this.worker = null;
// 重新开始新的布局之前先取消之前布局的requestAnimationFrame。
if (workerData.requestId) {
helper.cancelAnimationFrame(workerData.requestId);
workerData.requestId = null;
}
if (workerData.requestId2) {
helper.cancelAnimationFrame(workerData.requestId2);
workerData.requestId2 = null;
}
};
LayoutController.prototype.execLayoutMethod = function (layoutCfg, order) {
var _this = this;
return new Promise(function (reslove, reject) {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
var graph, layoutType, onTick_1, animate_1, isDefaultAnimateLayout_1, tick, enableTick, layoutMethod, onTick_2, tick, layoutData;
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
graph = this.graph;
if (!graph || graph.get('destroyed')) return [2 /*return*/];
layoutType = layoutCfg.type;
// 每个布局方法都需要注册
layoutCfg.onLayoutEnd = function () {
graph.emit('aftersublayout', {
type: layoutType
});
reslove();
};
// 若用户指定开启 gpu且当前浏览器支持 webgl且该算法存在 GPU 版本(目前仅支持 fruchterman 和 gForce使用 gpu 版本的布局
if (layoutType && this.isGPU) {
if (!hasGPUVersion(layoutType)) {
console.warn("The '".concat(layoutType, "' layout does not support GPU calculation for now, it will run in CPU."));
} else {
layoutType = "".concat(layoutType, "-gpu");
}
}
if (_g6Core.Util.isForce(layoutType)) {
onTick_1 = layoutCfg.onTick, animate_1 = layoutCfg.animate;
isDefaultAnimateLayout_1 = animate_1 === undefined && (layoutType === 'force' || layoutType === 'force2');
tick = function tick() {
if (onTick_1) {
onTick_1();
}
if (animate_1 || isDefaultAnimateLayout_1) graph.refreshPositions();
};
layoutCfg.tick = tick;
} else if (layoutType === 'comboForce' || layoutType === 'comboCombined') {
layoutCfg.comboTrees = graph.get('comboTrees');
}
enableTick = false;
try {
layoutMethod = new _layout.Layout[layoutType](layoutCfg);
if (this.layoutMethods[order]) {
this.layoutMethods[order].destroy();
}
this.layoutMethods[order] = layoutMethod;
} catch (e) {
console.warn("The layout method: '".concat(layoutType, "' does not exist! Please specify it first."));
reject();
}
// 是否需要迭代的方式完成布局。这里是来自布局对象的实例属性,是由布局的定义者在布局类定义的。
enableTick = layoutMethod.enableTick;
if (enableTick) {
onTick_2 = layoutCfg.onTick;
tick = function tick() {
if (onTick_2) {
onTick_2();
}
graph.refreshPositions();
};
layoutMethod.tick = tick;
}
layoutData = this.filterLayoutData(this.data, layoutCfg);
addLayoutOrder(layoutData, order);
layoutMethod.init(layoutData);
// 若存在节点没有位置信息,且没有设置 layout在 initPositions 中 random 给出了所有节点的位置,不需要再次执行 random 布局
// 所有节点都有位置信息,且指定了 layout则执行布局代表不是第一次进行布局
graph.emit('beforesublayout', {
type: layoutType
});
return [4 /*yield*/, layoutMethod.execute()];
case 1:
_a.sent();
if (layoutMethod.isCustomLayout && layoutCfg.onLayoutEnd) layoutCfg.onLayoutEnd();
return [2 /*return*/];
}
});
});
});
};
LayoutController.prototype.updateLayoutMethod = function (layoutMethod, layoutCfg) {
var _this = this;
return new Promise(function (reslove, reject) {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
var graph, layoutType, onTick_3, animate_2, isDefaultAnimateLayout_2, tick, layoutData;
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
graph = this.graph;
layoutType = layoutCfg === null || layoutCfg === void 0 ? void 0 : layoutCfg.type;
// 每个布局方法都需要注册
layoutCfg.onLayoutEnd = function () {
graph.emit('aftersublayout', {
type: layoutType
});
reslove();
};
if (_g6Core.Util.isForce(layoutType)) {
onTick_3 = layoutCfg.onTick, animate_2 = layoutCfg.animate;
isDefaultAnimateLayout_2 = animate_2 === undefined && (layoutType === 'force' || layoutType === 'force2');
tick = function tick() {
onTick_3 === null || onTick_3 === void 0 ? void 0 : onTick_3();
if (animate_2 || isDefaultAnimateLayout_2) graph.refreshPositions();
};
layoutCfg.tick = tick;
}
layoutData = this.filterLayoutData(this.data, layoutCfg);
layoutMethod.init(layoutData);
layoutMethod.updateCfg(layoutCfg);
graph.emit('beforesublayout', {
type: layoutType
});
return [4 /*yield*/, layoutMethod.execute()];
case 1:
_a.sent();
if (layoutMethod.isCustomLayout && layoutCfg.onLayoutEnd) layoutCfg.onLayoutEnd();
return [2 /*return*/];
}
});
});
});
};
/**
* @param {function} success callback
* @return {boolean} 是否使用web worker布局
*/
LayoutController.prototype.layout = function (success) {
var _this = this;
var _a;
var graph = this.graph;
if (!graph || graph.get('destroyed')) return;
this.data = this.setDataFromGraph();
var _b = this.data,
nodes = _b.nodes,
hiddenNodes = _b.hiddenNodes;
if (!nodes) {
return false;
}
var width = graph.get('width');
var height = graph.get('height');
var layoutCfg = {};
Object.assign(layoutCfg, {
width: width,
height: height,
center: [width / 2, height / 2]
}, this.layoutCfg);
this.layoutCfg = layoutCfg;
var layoutType = layoutCfg.type;
var prevHasNodes = false;
(_a = this.layoutMethods) === null || _a === void 0 ? void 0 : _a.forEach(function (method) {
var _a;
return prevHasNodes = !!((_a = method.nodes) === null || _a === void 0 ? void 0 : _a.length) || prevHasNodes;
});
var preLayoutTypes = this.destoryLayoutMethods();
graph.emit('beforelayout');
var start = Promise.resolve();
// 增量情况下(上一次的布局与当前布局一致),上一次有节点,使用 treakInit
if (prevHasNodes && layoutType && (preLayoutTypes === null || preLayoutTypes === void 0 ? void 0 : preLayoutTypes.length) === 1 && preLayoutTypes[0] === layoutType) {
this.tweakInit();
} else {
// 初始化位置,若配置了 preset则使用 preset 的参数生成布局作为预布局,否则使用 grid
start = this.initPositions(layoutCfg.center, nodes);
}
// init hidden nodes
var initHiddenPromise = this.initPositions(layoutCfg.center, hiddenNodes);
initHiddenPromise.then();
// 若用户指定开启 gpu且当前浏览器支持 webgl且该算法存在 GPU 版本(目前仅支持 fruchterman 和 gForce使用 gpu 版本的布局
this.isGPU = getGPUEnabled(layoutCfg, layoutType);
// 在 onAllLayoutEnd 中执行用户自定义 onLayoutEnd触发 afterlayout、更新节点位置、fitView/fitCenter、触发 afterrender
var onLayoutEnd = layoutCfg.onLayoutEnd,
layoutEndFormatted = layoutCfg.layoutEndFormatted,
adjust = layoutCfg.adjust;
if (!layoutEndFormatted) {
layoutCfg.layoutEndFormatted = true;
layoutCfg.onAllLayoutEnd = function () {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
// 执行用户自定义 onLayoutEnd
if (onLayoutEnd) {
onLayoutEnd(nodes);
}
// 更新节点位置
this.refreshLayout();
if (!(adjust && layoutCfg.pipes)) return [3 /*break*/, 2];
return [4 /*yield*/, this.adjustPipesBox(this.data, adjust)];
case 1:
_a.sent();
this.refreshLayout();
_a.label = 2;
case 2:
// 触发 afterlayout
graph.emit('afterlayout');
return [2 /*return*/];
}
});
});
};
}
this.stopWorker();
if (layoutCfg.workerEnabled && this.layoutWithWorker(this.data, success)) {
// 如果启用布局web worker并且浏览器支持web worker用web worker布局。否则回退到不用web worker布局。
return true;
}
var hasLayout = false;
if (layoutCfg.type) {
hasLayout = true;
start = start.then(function () {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
return [4 /*yield*/, this.execLayoutMethod(layoutCfg, 0)];
case 1:
return [2 /*return*/, _a.sent()];
}
});
});
});
} else if (layoutCfg.pipes) {
hasLayout = true;
layoutCfg.pipes.forEach(function (cfg, index) {
start = start.then(function () {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
return [4 /*yield*/, this.execLayoutMethod(cfg, index)];
case 1:
return [2 /*return*/, _a.sent()];
}
});
});
});
});
}
if (hasLayout) {
// 最后统一在外部调用onAllLayoutEnd
start.then(function () {
if (layoutCfg.onAllLayoutEnd) layoutCfg.onAllLayoutEnd();
// 在执行 execute 后立即执行 success且在 timeBar 中有 throttle可以防止 timeBar 监听 afterrender 进行 changeData 后 layout从而死循环
// 对于 force 一类布局完成后的 fitView 需要用户自己在 onLayoutEnd 中配置
if (success) success();
}).catch(function (error) {
console.warn('graph layout failed,', error);
});
} else {
// 无布局配置
graph.refreshPositions();
success === null || success === void 0 ? void 0 : success();
}
return false;
};
/**
* 增量数据初始化位置
*/
LayoutController.prototype.tweakInit = function () {
var _a = this,
data = _a.data,
graph = _a.graph;
var nodes = data.nodes,
edges = data.edges;
if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length)) return;
var positionMap = {};
nodes.forEach(function (node) {
var x = node.x,
y = node.y;
if (!isNaN(x) && !isNaN(y)) {
positionMap[node.id] = {
x: x,
y: y
};
// 有位置信息,则是原有节点,增加 mass
node.mass = node.mass || 2;
}
});
edges.forEach(function (edge) {
var source = edge.source,
target = edge.target;
var sourcePosition = positionMap[source];
var targetPosition = positionMap[target];
if (!sourcePosition && targetPosition) {
positionMap[source] = {
x: targetPosition.x + (Math.random() - 0.5) * 80,
y: targetPosition.y + (Math.random() - 0.5) * 80
};
} else if (!targetPosition && sourcePosition) {
positionMap[target] = {
x: sourcePosition.x + (Math.random() - 0.5) * 80,
y: sourcePosition.y + (Math.random() - 0.5) * 80
};
}
});
var width = graph.get('width');
var height = graph.get('height');
nodes.forEach(function (node) {
var position = positionMap[node.id] || {
x: width / 2 + (Math.random() - 0.5) * 20,
y: height / 2 + (Math.random() - 0.5) * 20
};
node.x = position.x;
node.y = position.y;
});
};
LayoutController.prototype.initWithPreset = function (hasPresetCallback, noPresetCallback) {
var _this = this;
return new Promise(function (resolve, reject) {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
var _a, layoutCfg, data, preset, isGPU, layoutType, presetLayout;
return (0, _tslib.__generator)(this, function (_b) {
switch (_b.label) {
case 0:
_a = this, layoutCfg = _a.layoutCfg, data = _a.data;
preset = layoutCfg.preset;
if (!(preset === null || preset === void 0 ? void 0 : preset.type) || !_layout.Layout[preset === null || preset === void 0 ? void 0 : preset.type]) {
noPresetCallback === null || noPresetCallback === void 0 ? void 0 : noPresetCallback();
resolve();
return [2 /*return*/, false];
}
isGPU = getGPUEnabled(preset, preset.type);
layoutType = isGPU ? "".concat(preset.type, "-gpu") : preset.type;
presetLayout = new _layout.Layout[layoutType](preset);
delete layoutCfg.preset;
presetLayout.init(data);
return [4 /*yield*/, presetLayout.execute()];
case 1:
_b.sent();
hasPresetCallback === null || hasPresetCallback === void 0 ? void 0 : hasPresetCallback();
resolve();
return [2 /*return*/, true];
}
});
});
});
};
/**
* layout with web worker
* @param {object} data graph data
* @return {boolean} 是否支持web worker
*/
LayoutController.prototype.layoutWithWorker = function (data, success) {
var _this = this;
var _a = this,
layoutCfg = _a.layoutCfg,
graph = _a.graph;
var worker = this.getWorker();
// 每次worker message event handler调用之间的共享数据会被修改。
var workerData = this.workerData;
if (!worker) {
return false;
}
workerData.requestId = null;
workerData.requestId2 = null;
workerData.currentTick = null;
workerData.currentTickData = null;
graph.emit('beforelayout');
var start = Promise.resolve();
var hasLayout = false;
if (layoutCfg.type) {
hasLayout = true;
start = start.then(function () {
return _this.runWebworker(worker, data, layoutCfg);
});
} else if (layoutCfg.pipes) {
hasLayout = true;
var _loop_1 = function _loop_1(cfg) {
start = start.then(function () {
return _this.runWebworker(worker, data, cfg);
});
};
for (var _i = 0, _b = layoutCfg.pipes; _i < _b.length; _i++) {
var cfg = _b[_i];
_loop_1(cfg);
}
}
if (hasLayout) {
// 最后统一在外部调用onAllLayoutEnd
start.then(function () {
if (layoutCfg.onAllLayoutEnd) layoutCfg.onAllLayoutEnd();
success === null || success === void 0 ? void 0 : success();
}).catch(function (error) {
console.error('layout failed', error);
});
}
return true;
};
LayoutController.prototype.runWebworker = function (worker, allData, layoutCfg) {
var _this = this;
var isGPU = this.isGPU;
var data = this.filterLayoutData(allData, layoutCfg);
var nodes = data.nodes,
edges = data.edges;
var offScreenCanvas = document.createElement('canvas');
var gpuWorkerAbility = isGPU && typeof window !== 'undefined' &&
// eslint-disable-next-line @typescript-eslint/dot-notation
window.navigator && !navigator["gpu"] &&
// WebGPU 还不支持 OffscreenCanvas
'OffscreenCanvas' in window && 'transferControlToOffscreen' in offScreenCanvas;
// NOTE: postMessage的message参数里面不能包含函数否则postMessage会报错
// 例如:'function could not be cloned'。
// 详情参考https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
// 所以这里需要把过滤layoutCfg里的函数字段过滤掉。
var filteredLayoutCfg = filterObject(layoutCfg, function (value) {
return typeof value !== 'function';
});
if (!gpuWorkerAbility) {
worker.postMessage({
type: _layoutConst.LAYOUT_MESSAGE.RUN,
nodes: nodes,
edges: edges,
layoutCfg: filteredLayoutCfg
});
} else {
var offscreen = offScreenCanvas.transferControlToOffscreen();
// filteredLayoutCfg.canvas = offscreen;
filteredLayoutCfg.type = "".concat(filteredLayoutCfg.type, "-gpu");
worker.postMessage({
type: _layoutConst.LAYOUT_MESSAGE.GPURUN,
nodes: nodes,
edges: edges,
layoutCfg: filteredLayoutCfg,
canvas: offscreen
}, [offscreen]);
}
return new Promise(function (reslove, reject) {
worker.onmessage = function (event) {
_this.handleWorkerMessage(reslove, reject, event, data, layoutCfg);
};
});
};
// success callback will be called when updating graph positions for the first time.
LayoutController.prototype.handleWorkerMessage = function (reslove, reject, event, data, layoutCfg) {
var _a = this,
graph = _a.graph,
workerData = _a.workerData;
var eventData = event.data;
var type = eventData.type;
var onTick = function onTick() {
if (layoutCfg.onTick) {
layoutCfg.onTick();
}
};
switch (type) {
case _layoutConst.LAYOUT_MESSAGE.TICK:
workerData.currentTick = eventData.currentTick;
workerData.currentTickData = eventData;
if (!workerData.requestId) {
workerData.requestId = helper.requestAnimationFrame(function requestId() {
updateLayoutPosition(data, eventData);
graph.refreshPositions();
onTick();
if (eventData.currentTick === eventData.totalTicks) {
// 如果是最后一次tick
reslove();
} else if (workerData.currentTick === eventData.totalTicks) {
// 注意这里workerData.currentTick可能已经不再是前面赋值时候的值了
// 因为在requestAnimationFrame等待时间里可能产生新的tick。
// 如果当前tick不是最后一次tick并且所有的tick消息都已发出来了那么需要用最后一次tick的数据再刷新一次。
workerData.requestId2 = helper.requestAnimationFrame(function requestId2() {
updateLayoutPosition(data, workerData.currentTickData);
graph.refreshPositions();
workerData.requestId2 = null;
onTick();
reslove();
});
}
workerData.requestId = null;
});
}
break;
case _layoutConst.LAYOUT_MESSAGE.END:
// 如果没有tick消息非力导布局
if (workerData.currentTick == null) {
updateLayoutPosition(data, eventData);
reslove();
}
break;
case _layoutConst.LAYOUT_MESSAGE.GPUEND:
// 如果没有tick消息非力导布局
if (workerData.currentTick == null) {
updateGPUWorkerLayoutPosition(data, eventData);
reslove();
}
break;
case _layoutConst.LAYOUT_MESSAGE.ERROR:
console.warn('Web-Worker layout error!', eventData.message);
reject();
break;
default:
reject();
break;
}
};
// 更新布局参数
LayoutController.prototype.updateLayoutCfg = function (cfg) {
var _this = this;
var _a = this,
graph = _a.graph,
layoutMethods = _a.layoutMethods;
if (!graph || graph.get('destroyed')) return;
// disableTriggerLayout 不触发重新布局,仅更新参数
var disableTriggerLayout = cfg.disableTriggerLayout,
otherCfg = (0, _tslib.__rest)(cfg, ["disableTriggerLayout"]);
var layoutCfg = (0, _util.mix)({}, this.layoutCfg, otherCfg);
this.layoutCfg = layoutCfg;
// disableTriggerLayout 不触发重新布局,仅更新参数
if (disableTriggerLayout) {
return;
}
if (!(layoutMethods === null || layoutMethods === void 0 ? void 0 : layoutMethods.length)) {
this.layout();
return;
}
this.data = this.setDataFromGraph();
this.stopWorker();
if (otherCfg.workerEnabled && this.layoutWithWorker(this.data, null)) {
// 如果启用布局web worker并且浏览器支持web worker用web worker布局。否则回退到不用web worker布局。
return;
}
graph.emit('beforelayout');
var start = Promise.resolve();
var hasLayout = false;
if ((layoutMethods === null || layoutMethods === void 0 ? void 0 : layoutMethods.length) === 1) {
hasLayout = true;
start = start.then(function () {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
return [4 /*yield*/, this.updateLayoutMethod(layoutMethods[0], layoutCfg)];
case 1:
return [2 /*return*/, _a.sent()];
}
});
});
});
} else if (layoutMethods === null || layoutMethods === void 0 ? void 0 : layoutMethods.length) {
hasLayout = true;
layoutMethods.forEach(function (layoutMethod, index) {
var currentCfg = layoutCfg.pipes[index];
start = start.then(function () {
return (0, _tslib.__awaiter)(_this, void 0, void 0, function () {
return (0, _tslib.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
return [4 /*yield*/, this.updateLayoutMethod(layoutMethod, currentCfg)];
case 1:
return [2 /*return*/, _a.sent()];
}
});
});
});
});
}
if (hasLayout) {
start.then(function () {
if (layoutCfg.onAllLayoutEnd) layoutCfg.onAllLayoutEnd();
}).catch(function (error) {
console.warn('layout failed', error);
});
}
};
LayoutController.prototype.adjustPipesBox = function (data, adjust) {
var _this = this;
return new Promise(function (resolve) {
var nodes = data.nodes;
if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length)) {
resolve();
}
if (!LAYOUT_PIPES_ADJUST_NAMES.includes(adjust)) {
console.warn("The adjust type ".concat(adjust, " is not supported yet, please assign it with 'force', 'grid', or 'circular'."));
resolve();
}
var layoutCfg = {
center: _this.layoutCfg.center,
nodeSize: function nodeSize(d) {
return Math.max(d.height, d.width);
},
preventOverlap: true,
onLayoutEnd: function onLayoutEnd() {}
};
// 计算出大单元
var _a = _this.getLayoutBBox(nodes),
groupNodes = _a.groupNodes,
layoutNodes = _a.layoutNodes;
var preNodes = (0, _util.clone)(layoutNodes);
// 根据大单元坐标的变化调整这里面每个小单元nodes
layoutCfg.onLayoutEnd = function () {
layoutNodes === null || layoutNodes === void 0 ? void 0 : layoutNodes.forEach(function (ele, index) {
var _a, _b, _c;
var dx = ele.x - ((_a = preNodes[index]) === null || _a === void 0 ? void 0 : _a.x);
var dy = ele.y - ((_b = preNodes[index]) === null || _b === void 0 ? void 0 : _b.y);
(_c = groupNodes[index]) === null || _c === void 0 ? void 0 : _c.forEach(function (n) {
n.x += dx;
n.y += dy;
});
});
resolve();
};
var layoutMethod = new _layout.Layout[adjust](layoutCfg);
layoutMethod.layout({
nodes: layoutNodes
});
});
};
LayoutController.prototype.destroy = function () {
this.destoryLayoutMethods();
var worker = this.worker;
if (worker) {
worker.terminate();
this.worker = null;
}
this.destroyed = true;
this.graph.set('layout', undefined);
this.layoutCfg = undefined;
this.layoutType = undefined;
this.layoutMethods = undefined;
this.graph = null;
};
return LayoutController;
}(_g6Core.AbstractLayout);
var _default = exports.default = LayoutController;
function updateLayoutPosition(data, layoutData) {
var nodes = data.nodes;
var layoutNodes = layoutData.nodes;
var nodeLength = nodes.length;
for (var i = 0; i < nodeLength; i++) {
var node = nodes[i];
node.x = layoutNodes[i].x;
node.y = layoutNodes[i].y;
}
}
function filterObject(collection, callback) {
var result = {};
if (collection && _typeof(collection) === 'object') {
Object.keys(collection).forEach(function (key) {
if (collection.hasOwnProperty(key) && callback(collection[key])) {
result[key] = collection[key];
}
});
return result;
}
return collection;
}
function updateGPUWorkerLayoutPosition(data, layoutData) {
var nodes = data.nodes;
var vertexEdgeData = layoutData.vertexEdgeData;
var nodeLength = nodes.length;
for (var i = 0; i < nodeLength; i++) {
var node = nodes[i];
var x = vertexEdgeData[4 * i];
var y = vertexEdgeData[4 * i + 1];
node.x = x;
node.y = y;
}
}
function addLayoutOrder(data, order) {
var _a;
if (!((_a = data === null || data === void 0 ? void 0 : data.nodes) === null || _a === void 0 ? void 0 : _a.length)) {
return;
}
var nodes = data.nodes;
nodes.forEach(function (node) {
node.layoutOrder = order;
});
}
function hasGPUVersion(layoutName) {
return GPU_LAYOUT_NAMES.includes(layoutName);
}
function getGPUEnabled(layoutCfg, layoutType) {
var type = layoutType;
// 防止用户直接用 -gpu 结尾指定布局
if (layoutType && layoutType.split('-')[1] === 'gpu') {
type = layoutType.split('-')[0];
layoutCfg.gpuEnabled = true;
}
var enableGPU = false;
if (layoutCfg.gpuEnabled) {
enableGPU = true;
// 打开下面语句将会导致 webworker 报找不到 window
if (!(0, _gpu.gpuDetector)().webgl) {
console.warn("Your browser does not support webGL or GPGPU. The layout will run in CPU.");
enableGPU = false;
}
}
// the layout does not support GPU, will run in CPU
if (enableGPU && !hasGPUVersion(type)) {
console.warn("The '".concat(type, "' layout does not support GPU calculation for now, it will run in CPU."));
enableGPU = false;
}
return enableGPU;
}