@xiaomengqiang/charts
Version:
hcharts library for web visualization
214 lines (208 loc) • 6.35 kB
JavaScript
import dagre from './dagre.js';
import { isObject, isNumber } from '../../util/type.js';
/**
* Copyright (c) 2024 - present OpenTiny HUICharts Authors.
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
var VALID_DIRECTIONS = ['LR',
// left to right
'RL',
// right to left
'TB',
// top to bottom
'BT',
// bottom to top
'H',
// horizontal
'V' // vertical
];
var VDirection = ['TB', 'BT', 'V'];
var NODE_WIDTH = 50;
var NODE_HEIGHT = 50;
/**
* 根据传入数据的 nodes 和 edges 计算出绘制流程图需要的位置信息
* 包括节点位置和边的位置
*/
var Layout = /*#__PURE__*/function () {
function Layout(data, option, containerSize) {
this.data = void 0;
this.data = data;
// 执行位置算法
this.doLayout(data, option);
// 将整个图移动到container中心, 将节点位置同步到this.data.nodes和this.data.edges中
this.revisePosn(containerSize, option.position);
}
/**
* 执行位置算法
*/
var _proto = Layout.prototype;
_proto.doLayout = function doLayout(data, options) {
data.nodes.forEach(function (v, i) {
if (i === 0) {
NODE_WIDTH = v.width;
NODE_HEIGHT = v.height;
} else {
if (v.width > NODE_WIDTH) {
NODE_WIDTH = v.width;
}
if (v.height > NODE_HEIGHT) {
NODE_HEIGHT = v.height;
}
}
});
var g = new dagre.graphlib.Graph();
g.setDefaultEdgeLabel(function () {
return {};
});
g.setGraph({
rankdir: options.direction || VALID_DIRECTIONS[0],
nodesep: (VDirection.includes(options.direction) ? options.hGap : options.vGap) || 50,
ranksep: (VDirection.includes(options.direction) ? options.vGap : options.hGap) || 50
});
// TODO:此处要缺少计算level的算法
// 对于跨level的node链接,需要在level中间添加虚拟节点,以完善节点布局
// 计算出所有edges边数据
var edges = [];
data.edges.forEach(function (item) {
var source = data.nodes.find(function (node) {
return node.id === item.source;
});
var target = data.nodes.find(function (node) {
return node.id === item.target;
});
edges.push({
source: item.source,
target: item.target,
sourceLevel: source.level,
targetLevel: target.level
});
});
// 获取跨level的边数据
var specialEdges = edges.filter(function (item) {
return item.targetLevel - item.sourceLevel > 1;
});
// 从edges中删除跨level的连线数据
specialEdges.forEach(function (item) {
var index = -1;
data.edges.forEach(function (edge, i) {
if (edge.source === item.source && edge.target === item.target) {
index = i;
}
});
data.edges.splice(index, 1);
});
// 根据跨level的连线增加虚拟节点和虚拟连线
specialEdges.forEach(function (item) {
var id = 'virtual_' + item.target + '_' + item.source;
data.nodes.push({
id: id,
width: NODE_WIDTH,
height: NODE_HEIGHT,
innerWidth: NODE_WIDTH,
innerHeight: NODE_HEIGHT
});
data.edges.push({
source: item.source,
target: id
});
data.edges.push({
source: id,
target: item.target
});
});
// 给dagre赋值、执行布局算法
data.nodes.forEach(function (node) {
g.setNode(node.id, {
id: node.id,
level: node.level,
width: node.width,
height: node.height
});
});
data.edges.forEach(function (edge) {
g.setEdge(edge.source, edge.target);
});
dagre.layout(g);
var nodes = [];
g.nodes().forEach(function (node) {
var coord = g.node(node);
var obj = {
id: coord.id,
level: coord.level,
x: coord.x,
y: coord.y
};
nodes.push(obj);
});
nodes.forEach(function (node) {
var current = data.nodes.find(function (item) {
return item.id === node.id;
});
if (current) {
current.x = node.x;
current.y = node.y;
}
});
// 用户自定义node位置修正
data.nodes.forEach(function (node) {
if (node.offset) {
node.offset(node);
}
});
};
/**
* 1. 将图移动到container中心
* 2. 将节点位置和连线位置同步到this.data中
*/
_proto.revisePosn = function revisePosn(containerSize, position) {
var _this = this;
var minX = 99999;
var maxX = -99999;
var minY = 99999;
var maxY = -99999;
this.data.nodes.forEach(function (node) {
if (minX > node.x) {
minX = node.x;
}
if (minY > node.y) {
minY = node.y;
}
if (maxX < node.x + node.width) {
maxX = node.x + node.width;
}
if (maxY < node.y + node.height) {
maxY = node.y + node.height;
}
});
// 默认居中显示
var reviseX = containerSize.width / 2 - (maxX + minX) / 2;
var reviseY = containerSize.height / 2 - (maxY + minY) / 2;
var hasPosition = false;
if (position && isObject(position)) {
hasPosition = true;
var topVal = position.top;
var leftVal = position.left;
reviseY = isNumber(topVal) ? topVal : topVal.includes('px') ? Number.parseInt(topVal) : containerSize.height * (Number.parseFloat(topVal) / 100);
reviseX = isNumber(leftVal) ? leftVal : leftVal.includes('px') ? Number.parseInt(leftVal) : containerSize.width * (Number.parseFloat(leftVal) / 100);
}
var revise = {
x: reviseX,
y: reviseY
};
this.data.nodesObj = {};
this.data.nodes.forEach(function (node) {
node.x = node.x + revise.x - (hasPosition ? 25 : 0) - node.width / 2;
node.y = node.y + revise.y - (hasPosition ? 25 : 0) - node.height / 2;
_this.data.nodesObj[node.id] = node;
});
};
return Layout;
}();
export { Layout as default };