UNPKG

@antv/g6

Version:

A Graph Visualization Framework in JavaScript

244 lines 10.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isComboLayout = isComboLayout; exports.isTreeLayout = isTreeLayout; exports.isPositionSpecified = isPositionSpecified; exports.isPreLayout = isPreLayout; exports.layoutMapping2GraphData = layoutMapping2GraphData; exports.layoutAdapter = layoutAdapter; exports.invokeLayoutMethod = invokeLayoutMethod; exports.getLayoutProperty = getLayoutProperty; const graphlib_1 = require("@antv/graphlib"); const util_1 = require("@antv/util"); const constants_1 = require("../constants"); const base_layout_1 = require("../layouts/base-layout"); const id_1 = require("./id"); const point_1 = require("./point"); /** * <zh/> 判断是否是 combo 布局 * * <en/> Determine if it is a combo layout * @param options - <zh/> 布局配置项 | <en/> Layout options * @returns <zh/> 是否是 combo 布局 | <en/> Whether it is a combo layout */ function isComboLayout(options) { const { type } = options; if (['comboCombined', 'comboForce'].includes(type)) return true; if (type === 'antv-dagre' && options.sortByCombo) return true; return false; } /** * <zh/> 判断是否是树图布局 * * <en/> Determine if it is a tree layout * @param options - <zh/> 布局配置项 | <en/> Layout options * @returns <zh/> 是否是树图布局 | <en/> Whether it is a tree layout */ function isTreeLayout(options) { const { type } = options; return ['compact-box', 'mindmap', 'dendrogram', 'indented'].includes(type); } /** * <zh/> 数据中是否指定了位置 * * <en/> Is the position specified in the data * @param data - <zh/> 数据 | <en/> Data * @returns <zh/> 是否指定了位置 | <en/> Is the position specified */ function isPositionSpecified(data) { return (0, util_1.isNumber)(data.x) && (0, util_1.isNumber)(data.y); } /** * <zh/> 是否是前布局 * * <en/> Is pre-layout * @remarks * <zh/> 前布局是指在初始化元素前计算布局,适用于一些布局需要提前计算位置的场景。 * * <en/> Pre-layout refers to calculating the layout before initializing the elements, which is suitable for some layouts that need to calculate the position in advance. * @param options - <zh/> 布局配置项 | <en/> Layout options * @returns <zh/> 是否是前布局 | <en/> Is it a pre-layout */ function isPreLayout(options) { return !Array.isArray(options) && (options === null || options === void 0 ? void 0 : options.preLayout); } /** * <zh/> 将图布局结果转换为 G6 数据 * * <en/> Convert the layout result to G6 data * @param layoutMapping - <zh/> 布局映射 | <en/> Layout mapping * @returns <zh/> G6 数据 | <en/> G6 data */ function layoutMapping2GraphData(layoutMapping) { const { nodes, edges } = layoutMapping; const data = { nodes: [], edges: [], combos: [] }; nodes.forEach((nodeLike) => { const target = nodeLike.data._isCombo ? data.combos : data.nodes; const { x, y, z = 0 } = nodeLike.data; target === null || target === void 0 ? void 0 : target.push({ id: nodeLike.id, style: { x, y, z }, }); }); edges.forEach((edge) => { const { id, source, target, data: { points = [], controlPoints = points.slice(1, points.length - 1) }, } = edge; data.edges.push({ id: id, source: source, target: target, style: Object.assign({}, ((controlPoints === null || controlPoints === void 0 ? void 0 : controlPoints.length) ? { controlPoints: controlPoints.map(point_1.parsePoint) } : {})), }); }); return data; } /** * <zh/> 将 @antv/layout 布局适配为 G6 布局 * * <en/> Adapt @antv/layout layout to G6 layout * @param Ctor - <zh/> 布局类 | <en/> Layout class * @param context - <zh/> 运行时上下文 | <en/> Runtime context * @returns <zh/> G6 布局类 | <en/> G6 layout class */ function layoutAdapter(Ctor, context) { class AdaptLayout extends base_layout_1.BaseLayout { constructor(context, options) { super(context, options); this.instance = new Ctor({}); this.id = this.instance.id; if ('stop' in this.instance && 'tick' in this.instance) { const instance = this.instance; this.stop = instance.stop.bind(instance); this.tick = (iterations) => { const tickResult = instance.tick(iterations); return layoutMapping2GraphData(tickResult); }; } } execute(model, options) { return __awaiter(this, void 0, void 0, function* () { return layoutMapping2GraphData(yield this.instance.execute(this.graphData2LayoutModel(model), this.transformOptions((0, util_1.deepMix)({}, this.options, options)))); }); } transformOptions(options) { const { onTick } = options; if (!onTick) return options; options.onTick = (data) => onTick(layoutMapping2GraphData(data)); return options; } graphData2LayoutModel(data) { const { nodes = [], edges = [], combos = [] } = data; const nodesToLayout = nodes.map((datum) => { const id = (0, id_1.idOf)(datum); const { data, style, combo } = datum, rest = __rest(datum, ["data", "style", "combo"]); const result = { id, data: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, data), { data }), (combo ? { parentId: combo } : {})), { style }), rest), }; // 一些布局会从 data 中读取位置信息 if (style === null || style === void 0 ? void 0 : style.x) Object.assign(result.data, { x: style.x }); if (style === null || style === void 0 ? void 0 : style.y) Object.assign(result.data, { y: style.y }); if (style === null || style === void 0 ? void 0 : style.z) Object.assign(result.data, { z: style.z }); return result; }); const nodesIdMap = new Map(nodesToLayout.map((node) => [node.id, node])); const edgesToLayout = edges .filter((edge) => { const { source, target } = edge; return nodesIdMap.has(source) && nodesIdMap.has(target); }) .map((edge) => { const { source, target, data, style } = edge; return { id: (0, id_1.idOf)(edge), source, target, data: Object.assign({}, data), style: Object.assign({}, style) }; }); const combosToLayout = combos.map((combo) => { return { id: (0, id_1.idOf)(combo), data: Object.assign({ _isCombo: true }, combo.data), style: Object.assign({}, combo.style) }; }); const layoutModel = new graphlib_1.Graph({ nodes: [...nodesToLayout, ...combosToLayout], edges: edgesToLayout, }); if (context.model.model.hasTreeStructure(constants_1.COMBO_KEY)) { layoutModel.attachTreeStructure(constants_1.COMBO_KEY); // 同步层级关系 / Synchronize hierarchical relationships nodesToLayout.forEach((node) => { const parent = context.model.model.getParent(node.id, constants_1.COMBO_KEY); if (parent && layoutModel.hasNode(parent.id)) { layoutModel.setParent(node.id, parent.id, constants_1.COMBO_KEY); } }); } return layoutModel; } } return AdaptLayout; } /** * <zh/> 调用布局成员方法 * * <en/> Call layout member methods * @remarks * <zh/> 提供一种通用的调用方式来调用 G6 布局和 \@antv/layout 布局上的方法 * * <en/> Provide a common way to call methods on G6 layout and \@antv/layout layout * @param layout - <zh/> 布局实例 | <en/> Layout instance * @param method - <zh/> 方法名 | <en/> Method name * @param args - <zh/> 参数 | <en/> Arguments * @returns <zh/> 返回值 | <en/> Return value */ function invokeLayoutMethod(layout, method, ...args) { if (method in layout) { return layout[method](...args); } // invoke AdaptLayout method if ('instance' in layout) { const instance = layout.instance; if (method in instance) return instance[method](...args); } return null; } /** * <zh/> 获取布局成员属性 * * <en/> Get layout member properties * @param layout - <zh/> 布局实例 | <en/> Layout instance * @param name - <zh/> 属性名 | <en/> Property name * @returns <zh/> 返回值 | <en/> Return value */ function getLayoutProperty(layout, name) { if (name in layout) return layout[name]; if ('instance' in layout) { const instance = layout.instance; if (name in instance) return instance[name]; } return null; } //# sourceMappingURL=layout.js.map