Refactor component configuration and diagram management
- Removed the component configuration from `componentConfig.ts` to streamline the codebase. - Introduced a new `diagram.json` file to define the initial structure for diagrams. - Created a `diagramManager.ts` to handle diagram data, including loading, saving, and validating diagram structures. - Updated `ProjectView.vue` to integrate the new diagram management system, including handling component selection and property updates. - Enhanced the component property management to support dynamic attributes and improved error handling. - Added functions for managing connections between components within the diagram.
This commit is contained in:
@@ -33,16 +33,18 @@ interface Props {
|
||||
strokeColor?: string;
|
||||
strokeWidth?: number;
|
||||
isActive?: boolean;
|
||||
routingMode?: 'auto' | 'orthogonal' | 'direct';
|
||||
routingMode?: 'auto' | 'orthogonal' | 'direct' | 'path';
|
||||
// 针脚引用属性
|
||||
startComponentId?: string;
|
||||
startPinLabel?: string;
|
||||
startPinId?: string;
|
||||
endComponentId?: string;
|
||||
endPinLabel?: string;
|
||||
endPinId?: string;
|
||||
// 添加约束属性
|
||||
constraint?: string;
|
||||
// 显示标签
|
||||
showLabel?: boolean;
|
||||
// 路径命令 - 对应diagram.json中的线放置迷你语言
|
||||
pathCommands?: string[];
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -81,9 +83,168 @@ const labelPosition = computed(() => {
|
||||
});
|
||||
|
||||
const pathData = computed(() => {
|
||||
return calculateOrthogonalPath(props.startX, props.startY, props.endX, props.endY);
|
||||
// 如果有路径命令,使用路径布线模式
|
||||
if (props.routingMode === 'path' && props.pathCommands && props.pathCommands.length > 0) {
|
||||
return calculatePathFromCommands(
|
||||
props.startX,
|
||||
props.startY,
|
||||
props.endX,
|
||||
props.endY,
|
||||
props.pathCommands
|
||||
);
|
||||
}
|
||||
// 否则使用正交路径
|
||||
return calculateOrthogonalPath(props.startX, props.startY, props.endX, props.endY);
|
||||
});
|
||||
|
||||
function calculatePathFromCommands(
|
||||
startX: number,
|
||||
startY: number,
|
||||
endX: number,
|
||||
endY: number,
|
||||
commands: string[]
|
||||
) {
|
||||
// 找到分隔符索引,通常是 "*"
|
||||
const splitterIndex = commands.indexOf('*');
|
||||
if (splitterIndex === -1) {
|
||||
// 如果没有分隔符,回退到正交路径
|
||||
return calculateOrthogonalPath(startX, startY, endX, endY);
|
||||
}
|
||||
|
||||
// 分割命令为起点和终点两部分
|
||||
const startCommands = commands.slice(0, splitterIndex);
|
||||
const endCommands = commands.slice(splitterIndex + 1).reverse();
|
||||
|
||||
// 从起点开始生成路径
|
||||
let currentX = startX;
|
||||
let currentY = startY;
|
||||
|
||||
// 处理起点路径命令
|
||||
const pathPoints: [number, number][] = [[currentX, currentY]];
|
||||
|
||||
// 解析并执行起点命令
|
||||
for (const cmd of startCommands) {
|
||||
const { newX, newY } = executePathCommand(currentX, currentY, cmd);
|
||||
currentX = newX;
|
||||
currentY = newY;
|
||||
pathPoints.push([currentX, currentY]);
|
||||
}
|
||||
|
||||
// 从终点开始反向处理
|
||||
let endCurrentX = endX;
|
||||
let endCurrentY = endY;
|
||||
|
||||
// 保存终点路径点,最后会反转
|
||||
const endPathPoints: [number, number][] = [[endCurrentX, endCurrentY]];
|
||||
|
||||
// 解析并执行终点命令(反向)
|
||||
for (const cmd of endCommands) {
|
||||
const { newX, newY } = executePathCommand(endCurrentX, endCurrentY, cmd);
|
||||
endCurrentX = newX;
|
||||
endCurrentY = newY;
|
||||
endPathPoints.push([endCurrentX, endCurrentY]);
|
||||
}
|
||||
|
||||
// 反转终点路径点并去掉第一个(终点)
|
||||
const reversedEndPoints = endPathPoints.slice(1).reverse();
|
||||
|
||||
// 将两部分路径连接起来
|
||||
const allPoints = [...pathPoints, ...reversedEndPoints];
|
||||
|
||||
// 如果起点和终点路径没有连接上,添加连接线段
|
||||
if (allPoints.length >= 2) {
|
||||
const startFinalPoint = allPoints[pathPoints.length - 1];
|
||||
const endFirstPoint = allPoints[pathPoints.length];
|
||||
if (startFinalPoint && endFirstPoint &&
|
||||
(startFinalPoint[0] !== endFirstPoint[0] || startFinalPoint[1] !== endFirstPoint[1])) {
|
||||
// 添加连接点 - 这里使用正交连接
|
||||
const middlePoints = generateOrthogonalConnection(
|
||||
startFinalPoint[0], startFinalPoint[1],
|
||||
endFirstPoint[0], endFirstPoint[1]
|
||||
);
|
||||
|
||||
// 将起点路径、连接路径和终点路径拼接起来
|
||||
allPoints.splice(pathPoints.length, 0, ...middlePoints);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成SVG路径
|
||||
if (allPoints.length < 2) {
|
||||
return `M ${startX} ${startY} L ${endX} ${endY}`;
|
||||
}
|
||||
|
||||
let pathStr = `M ${allPoints[0][0]} ${allPoints[0][1]}`;
|
||||
for (let i = 1; i < allPoints.length; i++) {
|
||||
pathStr += ` L ${allPoints[i][0]} ${allPoints[i][1]}`;
|
||||
}
|
||||
|
||||
return pathStr;
|
||||
}
|
||||
|
||||
// 执行单个路径命令
|
||||
function executePathCommand(x: number, y: number, command: string): { newX: number; newY: number } {
|
||||
// 解析命令,例如 "down10", "right20", "downright5" 等
|
||||
if (command.startsWith('right')) {
|
||||
const distance = parseInt(command.substring(5), 10) || 10;
|
||||
return { newX: x + distance, newY: y };
|
||||
} else if (command.startsWith('left')) {
|
||||
const distance = parseInt(command.substring(4), 10) || 10;
|
||||
return { newX: x - distance, newY: y };
|
||||
} else if (command.startsWith('down')) {
|
||||
if (command.startsWith('downright')) {
|
||||
const distance = parseInt(command.substring(9), 10) || 10;
|
||||
return { newX: x + distance, newY: y + distance };
|
||||
} else if (command.startsWith('downleft')) {
|
||||
const distance = parseInt(command.substring(8), 10) || 10;
|
||||
return { newX: x - distance, newY: y + distance };
|
||||
} else {
|
||||
const distance = parseInt(command.substring(4), 10) || 10;
|
||||
return { newX: x, newY: y + distance };
|
||||
}
|
||||
} else if (command.startsWith('up')) {
|
||||
if (command.startsWith('upright')) {
|
||||
const distance = parseInt(command.substring(7), 10) || 10;
|
||||
return { newX: x + distance, newY: y - distance };
|
||||
} else if (command.startsWith('upleft')) {
|
||||
const distance = parseInt(command.substring(6), 10) || 10;
|
||||
return { newX: x - distance, newY: y - distance };
|
||||
} else {
|
||||
const distance = parseInt(command.substring(2), 10) || 10;
|
||||
return { newX: x, newY: y - distance };
|
||||
}
|
||||
}
|
||||
|
||||
// 默认情况下不移动
|
||||
return { newX: x, newY: y };
|
||||
}
|
||||
|
||||
// 生成两点之间的正交连接点
|
||||
function generateOrthogonalConnection(x1: number, y1: number, x2: number, y2: number): [number, number][] {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
|
||||
if (dx === 0 || dy === 0) {
|
||||
// 如果在同一水平或垂直线上,不需要额外点
|
||||
return [];
|
||||
}
|
||||
|
||||
// 选择先水平移动还是先垂直移动
|
||||
const middlePoints: [number, number][] = [];
|
||||
|
||||
if (Math.abs(dx) > Math.abs(dy)) {
|
||||
// 先水平后垂直
|
||||
middlePoints.push([x1 + dx / 2, y1]);
|
||||
middlePoints.push([x1 + dx / 2, y2]);
|
||||
} else {
|
||||
// 先垂直后水平
|
||||
middlePoints.push([x1, y1 + dy / 2]);
|
||||
middlePoints.push([x2, y1 + dy / 2]);
|
||||
}
|
||||
|
||||
return middlePoints;
|
||||
}
|
||||
|
||||
// 计算正交路径
|
||||
function calculateOrthogonalPath(startX: number, startY: number, endX: number, endY: number) {
|
||||
// 计算两点之间的水平和垂直距离
|
||||
const dx = endX - startX;
|
||||
@@ -145,13 +306,12 @@ watch(() => props.constraint, (newConstraint, oldConstraint) => {
|
||||
});
|
||||
|
||||
// 暴露方法,用于获取这条连线的信息
|
||||
defineExpose({ id: props.id,
|
||||
getInfo: () => ({
|
||||
defineExpose({ id: props.id, getInfo: () => ({
|
||||
id: props.id,
|
||||
startComponentId: props.startComponentId,
|
||||
startPinLabel: props.startPinLabel,
|
||||
startPinId: props.startPinId,
|
||||
endComponentId: props.endComponentId,
|
||||
endPinLabel: props.endPinLabel,
|
||||
endPinId: props.endPinId,
|
||||
constraint: props.constraint
|
||||
}),
|
||||
// 更新连线位置
|
||||
|
||||
Reference in New Issue
Block a user