mirror of
https://github.com/dbgate/dbgate
synced 2024-11-08 04:35:58 +00:00
diagram add references positioning
This commit is contained in:
parent
22054cad12
commit
6e50979045
@ -305,12 +305,13 @@
|
|||||||
...newTables.map(x => ({
|
...newTables.map(x => ({
|
||||||
...x,
|
...x,
|
||||||
designerId: uuidv1(),
|
designerId: uuidv1(),
|
||||||
|
needsArrange: true,
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddTableReferences = table => {
|
const handleAddTableReferences = async table => {
|
||||||
if (!dbInfo) return;
|
if (!dbInfo) return;
|
||||||
const db = $dbInfo;
|
const db = $dbInfo;
|
||||||
if (!db) return;
|
if (!db) return;
|
||||||
@ -318,6 +319,10 @@
|
|||||||
return getTablesWithReferences(db, table, current);
|
return getTablesWithReferences(db, table, current);
|
||||||
});
|
});
|
||||||
updateFromDbInfo();
|
updateFromDbInfo();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
const rect = (domTables[table.designerId] as any)?.getRect();
|
||||||
|
arrange(true, false, rect ? { x: (rect.left + rect.right) / 2, y: (rect.top + rect.bottom) / 2 } : null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const performAutoActions = async db => {
|
const performAutoActions = async db => {
|
||||||
@ -466,13 +471,18 @@
|
|||||||
return settings?.canArrange;
|
return settings?.canArrange;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function arrange(skipUndoChain = false) {
|
export function arrange(skipUndoChain = false, arrangeAll = true, circleMiddle = { x: 0, y: 0 }) {
|
||||||
const graph = new GraphDefinition();
|
const graph = new GraphDefinition();
|
||||||
for (const table of value?.tables || []) {
|
for (const table of value?.tables || []) {
|
||||||
const domTable = domTables[table.designerId] as any;
|
const domTable = domTables[table.designerId] as any;
|
||||||
if (!domTable) continue;
|
if (!domTable) continue;
|
||||||
const rect = domTable.getRect();
|
const rect = domTable.getRect();
|
||||||
graph.addNode(table.designerId, rect.right - rect.left, rect.bottom - rect.top);
|
graph.addNode(
|
||||||
|
table.designerId,
|
||||||
|
rect.right - rect.left,
|
||||||
|
rect.bottom - rect.top,
|
||||||
|
arrangeAll || table.needsArrange ? null : { x: rect.left + rect.right / 2, y: rect.top + rect.bottom / 2 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const reference of value?.references) {
|
for (const reference of value?.references) {
|
||||||
@ -481,7 +491,7 @@
|
|||||||
|
|
||||||
graph.initialize();
|
graph.initialize();
|
||||||
|
|
||||||
const layout = GraphLayout.createCircle(graph).springyAlg().doMoveSteps().fixViewBox();
|
const layout = GraphLayout.createCircle(graph, circleMiddle).springyAlg().doMoveSteps().fixViewBox();
|
||||||
|
|
||||||
callChange(current => {
|
callChange(current => {
|
||||||
return {
|
return {
|
||||||
@ -492,10 +502,14 @@
|
|||||||
return node
|
return node
|
||||||
? {
|
? {
|
||||||
...table,
|
...table,
|
||||||
|
needsArrange: false,
|
||||||
left: node.x - node.node.width / 2,
|
left: node.x - node.node.width / 2,
|
||||||
top: node.y - node.node.height / 2,
|
top: node.y - node.node.height / 2,
|
||||||
}
|
}
|
||||||
: table;
|
: {
|
||||||
|
...table,
|
||||||
|
needsArrange: false,
|
||||||
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}, skipUndoChain);
|
}, skipUndoChain);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { IBoxBounds, rectangleDistance, rectangleIntersectArea, Vector2D } from './designerMath';
|
import { IBoxBounds, IPoint, rectangleDistance, rectangleIntersectArea, Vector2D } from './designerMath';
|
||||||
|
|
||||||
const MIN_NODE_DISTANCE = 50;
|
const MIN_NODE_DISTANCE = 50;
|
||||||
const SPRING_LENGTH = 100;
|
const SPRING_LENGTH = 100;
|
||||||
@ -18,7 +18,13 @@ const SCORE_ASPECT_RATIO = 1.6;
|
|||||||
class GraphNode {
|
class GraphNode {
|
||||||
neightboors: GraphNode[] = [];
|
neightboors: GraphNode[] = [];
|
||||||
radius: number;
|
radius: number;
|
||||||
constructor(public graph: GraphDefinition, public designerId: string, public width: number, public height: number) {}
|
constructor(
|
||||||
|
public graph: GraphDefinition,
|
||||||
|
public designerId: string,
|
||||||
|
public width: number,
|
||||||
|
public height: number,
|
||||||
|
public fixedPosition: IPoint
|
||||||
|
) {}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.radius = Math.sqrt((this.width * this.width) / 4 + (this.height * this.height) / 4);
|
this.radius = Math.sqrt((this.width * this.width) / 4 + (this.height * this.height) / 4);
|
||||||
@ -43,8 +49,8 @@ export class GraphDefinition {
|
|||||||
nodes: { [designerId: string]: GraphNode } = {};
|
nodes: { [designerId: string]: GraphNode } = {};
|
||||||
edges: GraphEdge[] = [];
|
edges: GraphEdge[] = [];
|
||||||
|
|
||||||
addNode(designerId: string, width: number, height: number) {
|
addNode(designerId: string, width: number, height: number, fixedPosition: IPoint) {
|
||||||
this.nodes[designerId] = new GraphNode(this, designerId, width, height);
|
this.nodes[designerId] = new GraphNode(this, designerId, width, height, fixedPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEdge(sourceId: string, targetId: string) {
|
addEdge(sourceId: string, targetId: string) {
|
||||||
@ -94,6 +100,7 @@ class LayoutNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
translate(dx: number, dy: number) {
|
translate(dx: number, dy: number) {
|
||||||
|
if (this.node.fixedPosition) return this;
|
||||||
return new LayoutNode(this.node, this.x + dx, this.y + dy);
|
return new LayoutNode(this.node, this.x + dx, this.y + dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,14 +206,18 @@ export class GraphLayout {
|
|||||||
|
|
||||||
constructor(public graph: GraphDefinition) {}
|
constructor(public graph: GraphDefinition) {}
|
||||||
|
|
||||||
static createCircle(graph: GraphDefinition): GraphLayout {
|
static createCircle(graph: GraphDefinition, middle: IPoint = { x: 0, y: 0 }): GraphLayout {
|
||||||
const res = new GraphLayout(graph);
|
const res = new GraphLayout(graph);
|
||||||
if (_.isEmpty(graph.nodes)) return res;
|
if (_.isEmpty(graph.nodes)) return res;
|
||||||
|
|
||||||
const addedNodes = new Set<string>();
|
const addedNodes = new Set<string>();
|
||||||
const circleSortedNodes: GraphNode[] = [];
|
const circleSortedNodes: GraphNode[] = [];
|
||||||
|
|
||||||
addNodeNeighboors(_.values(graph.nodes), circleSortedNodes, addedNodes);
|
addNodeNeighboors(
|
||||||
|
_.values(graph.nodes).filter(x => !x.fixedPosition),
|
||||||
|
circleSortedNodes,
|
||||||
|
addedNodes
|
||||||
|
);
|
||||||
const nodeRadius = _.max(circleSortedNodes.map(x => x.radius));
|
const nodeRadius = _.max(circleSortedNodes.map(x => x.radius));
|
||||||
const nodeCount = circleSortedNodes.length;
|
const nodeCount = circleSortedNodes.length;
|
||||||
const radius = (nodeCount * nodeRadius) / (2 * Math.PI) + nodeRadius;
|
const radius = (nodeCount * nodeRadius) / (2 * Math.PI) + nodeRadius;
|
||||||
@ -214,9 +225,18 @@ export class GraphLayout {
|
|||||||
let angle = 0;
|
let angle = 0;
|
||||||
const dangle = (2 * Math.PI) / circleSortedNodes.length;
|
const dangle = (2 * Math.PI) / circleSortedNodes.length;
|
||||||
for (const node of circleSortedNodes) {
|
for (const node of circleSortedNodes) {
|
||||||
res.nodes[node.designerId] = new LayoutNode(node, Math.sin(angle) * radius, Math.cos(angle) * radius);
|
res.nodes[node.designerId] = new LayoutNode(
|
||||||
|
node,
|
||||||
|
middle.x + Math.sin(angle) * radius,
|
||||||
|
middle.y + Math.cos(angle) * radius
|
||||||
|
);
|
||||||
angle += dangle;
|
angle += dangle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const node of _.values(graph.nodes).filter(x => x.fixedPosition)) {
|
||||||
|
res.nodes[node.designerId] = new LayoutNode(node, node.fixedPosition.x, node.fixedPosition.y);
|
||||||
|
}
|
||||||
|
|
||||||
res.fillEdges();
|
res.fillEdges();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -289,6 +309,7 @@ export class GraphLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tryMoveNode(node: LayoutNode): GraphLayout[] {
|
tryMoveNode(node: LayoutNode): GraphLayout[] {
|
||||||
|
if (node.node.fixedPosition) return [];
|
||||||
return [
|
return [
|
||||||
this.changePositions(x => (x == node ? node.translate(MOVE_STEP, 0) : x)),
|
this.changePositions(x => (x == node ? node.translate(MOVE_STEP, 0) : x)),
|
||||||
this.changePositions(x => (x == node ? node.translate(-MOVE_STEP, 0) : x)),
|
this.changePositions(x => (x == node ? node.translate(-MOVE_STEP, 0) : x)),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
interface IPoint {
|
export interface IPoint {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user