fix(diagram): align multi-schema export positions with canvas
This commit is contained in:
4 files changed
+135
-13
No files matched your search
@@ -1843,7 +1843,9 @@ function currentDiagramSvg(): string {
|
||||
|
||||
prepareTableDiagramExportGeometry();
|
||||
|
||||
const exportTables = canvasVisibleTables.value;
|
||||
// Positions are keyed by the diagram table id (`getTableKey`), which is schema-qualified in
|
||||
// multi-schema mode; hand that id to the exporter so cards are not all drawn at the origin.
|
||||
const exportTables = canvasVisibleTables.value.map((table) => ({ ...table, diagramKey: getTableKey(table) }));
|
||||
const exportRelationships = canvasVisibleRelationships.value;
|
||||
const layers = exportSvgLayers();
|
||||
const geometryInput = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { EngineeringDiagram, EngineeringEntityNode } from "@/lib/diagram/engineeringDiagram";
|
||||
import type { DiagramPosition, DiagramRelationship, DiagramTable } from "@/lib/diagram/erDiagram";
|
||||
import { isDroppedColumn, type DiagramPosition, type DiagramRelationship, type DiagramTable } from "@/lib/diagram/erDiagram";
|
||||
import { pickHandles } from "@/lib/diagram/vue-flow-adapter";
|
||||
import { pointAlongPolyline, pointsToSvgPath, type Point } from "@/lib/diagram/edge-obstacle-router";
|
||||
import { CARD_BOTTOM_PADDING, CARD_HEADER_HEIGHT, CARD_WIDTH, COLUMN_ROW_HEIGHT, MARGIN } from "@/lib/diagram/diagram-constants";
|
||||
@@ -25,8 +25,27 @@ export interface DiagramSvgLayer {
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table plus the id the canvas positions it by.
|
||||
*
|
||||
* Diagram positions are keyed by the diagram table id (`getTableKey`), which is
|
||||
* schema-qualified once more than one schema is selected. Export code used to look positions
|
||||
* up by the bare table name, so in multi-schema mode every card silently fell back to
|
||||
* `{ x: 0, y: 0 }` and the whole diagram was exported stacked on the origin (issue #9445).
|
||||
*/
|
||||
export type DiagramSvgTable = DiagramTable & { diagramKey?: string };
|
||||
|
||||
function tableExportKey(table: DiagramSvgTable): string {
|
||||
return table.diagramKey || table.name;
|
||||
}
|
||||
|
||||
/** Columns the card actually renders: pending-drop columns are hidden on the canvas too. */
|
||||
function tableExportColumns(table: DiagramTable): DiagramTable["columns"] {
|
||||
return table.columns.filter((column) => !isDroppedColumn(table, column.name));
|
||||
}
|
||||
|
||||
export interface TableDiagramSvgOptions {
|
||||
tables: DiagramTable[];
|
||||
tables: DiagramSvgTable[];
|
||||
relationships: DiagramRelationship[];
|
||||
positions: Record<string, DiagramPosition>;
|
||||
relationshipPaths: Record<string, string>;
|
||||
@@ -112,7 +131,7 @@ function orthogonalPointsBetweenTables(sourcePos: DiagramPosition, targetPos: Di
|
||||
type RelationshipGeometryInput = {
|
||||
relationships: DiagramRelationship[];
|
||||
positions: Record<string, DiagramPosition>;
|
||||
tables: DiagramTable[];
|
||||
tables: DiagramSvgTable[];
|
||||
waypoints?: Record<string, Point[]>;
|
||||
cardWidth?: number;
|
||||
cardHeaderHeight?: number;
|
||||
@@ -130,7 +149,14 @@ export function buildTableRelationshipPolylines(input: RelationshipGeometryInput
|
||||
columnRowHeight: input.columnRowHeight ?? COLUMN_ROW_HEIGHT,
|
||||
cardBottomPadding: input.cardBottomPadding ?? CARD_BOTTOM_PADDING,
|
||||
};
|
||||
const heightByName = new Map(input.tables.map((t) => [t.name, svgCardHeight(t.columns.length, metrics)]));
|
||||
// Relationships address tables by their diagram id, cards by their table; index both so the
|
||||
// routed edges match the drawn card heights in multi-schema mode too.
|
||||
const heightByName = new Map<string, number>();
|
||||
for (const table of input.tables) {
|
||||
const height = svgCardHeight(tableExportColumns(table).length, metrics);
|
||||
heightByName.set(tableExportKey(table), height);
|
||||
heightByName.set(table.name, height);
|
||||
}
|
||||
const polylines: Record<string, Point[]> = {};
|
||||
|
||||
for (const rel of input.relationships) {
|
||||
@@ -163,7 +189,7 @@ export function buildTableRelationshipPaths(input: RelationshipGeometryInput): R
|
||||
|
||||
/** Compute canvas size that fits tables + layers + relationship polylines with padding. */
|
||||
export function computeTableDiagramCanvas(
|
||||
tables: DiagramTable[],
|
||||
tables: DiagramSvgTable[],
|
||||
positions: Record<string, DiagramPosition>,
|
||||
options: {
|
||||
cardWidth: number;
|
||||
@@ -194,8 +220,8 @@ export function computeTableDiagramCanvas(
|
||||
}
|
||||
|
||||
for (const table of tables) {
|
||||
const pos = positions[table.name] ?? { x: 0, y: 0 };
|
||||
const height = svgCardHeight(table.columns.length, options);
|
||||
const pos = positions[tableExportKey(table)] ?? positions[table.name] ?? { x: 0, y: 0 };
|
||||
const height = svgCardHeight(tableExportColumns(table).length, options);
|
||||
expand(pos.x, pos.y, pos.x + options.cardWidth, pos.y + height);
|
||||
}
|
||||
|
||||
@@ -276,22 +302,28 @@ export function buildTableDiagramSvg(options: TableDiagramSvgOptions): string {
|
||||
parts.push("</g>");
|
||||
|
||||
for (const table of options.tables) {
|
||||
const position = options.positions[table.name] ?? { x: 0, y: 0 };
|
||||
const height = svgCardHeight(table.columns.length, options);
|
||||
const position = options.positions[tableExportKey(table)] ?? options.positions[table.name] ?? { x: 0, y: 0 };
|
||||
const columns = tableExportColumns(table);
|
||||
const height = svgCardHeight(columns.length, options);
|
||||
const showSchema = Boolean(table.schema) && tableExportKey(table) !== table.name;
|
||||
const nameY = options.cardHeaderHeight / 2 + (showSchema ? 6 : 0);
|
||||
parts.push(`<g transform="translate(${svgNumber(position.x)} ${svgNumber(position.y)})">`);
|
||||
parts.push(`<rect width="${options.cardWidth}" height="${svgNumber(height)}" rx="6" fill="#ffffff" stroke="#d4d4d8"/>`);
|
||||
parts.push(`<rect width="${options.cardWidth}" height="${options.cardHeaderHeight}" rx="6" fill="#f4f4f5"/>`);
|
||||
parts.push(`<path d="M 0 ${options.cardHeaderHeight} H ${options.cardWidth}" stroke="#e4e4e7"/>`);
|
||||
parts.push(svgText(table.name, 36, options.cardHeaderHeight / 2, { size: 13, weight: "600" }));
|
||||
if (showSchema) {
|
||||
parts.push(svgText(table.schema ?? "", 36, options.cardHeaderHeight / 2 - 6, { size: 10, fill: "#71717a", family: "Menlo, Consolas, monospace" }));
|
||||
}
|
||||
parts.push(svgText(table.name, 36, nameY, { size: 13, weight: "600" }));
|
||||
parts.push(
|
||||
svgText(String(table.columns.length), options.cardWidth - 18, options.cardHeaderHeight / 2, {
|
||||
svgText(String(columns.length), options.cardWidth - 18, options.cardHeaderHeight / 2, {
|
||||
size: 10,
|
||||
anchor: "end",
|
||||
fill: "#52525b",
|
||||
}),
|
||||
);
|
||||
|
||||
table.columns.forEach((column, index) => {
|
||||
columns.forEach((column, index) => {
|
||||
const rowTop = options.cardHeaderHeight + index * options.columnRowHeight;
|
||||
const rowCenter = rowTop + options.columnRowHeight / 2;
|
||||
parts.push(`<path d="M 0 ${svgNumber(rowTop)} H ${options.cardWidth}" stroke="#f0f0f1"/>`);
|
||||
|
||||
Reference in new issue
Block a user