diff --git a/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.template.ts b/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.template.ts index 5c0220f8..9dd7b17f 100644 --- a/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.template.ts +++ b/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.template.ts @@ -186,7 +186,7 @@ const relationshipN = ({ path, line }: RelationshipPath) => > `; -export const relationshipShapeMap: Record< +const relationshipShapeMap: Record< number, (value: RelationshipPath) => DOMTemplateLiterals > = { @@ -198,3 +198,11 @@ export const relationshipShapeMap: Record< [0b0000000000000000000000000100000]: relationshipOne, [0b0000000000000000000000001000000]: relationshipN, }; + +export function relationshipShape( + relationshipType: number, + relationshipPath: RelationshipPath +): DOMTemplateLiterals | null { + const relationshipShapeTpl = relationshipShapeMap[relationshipType]; + return relationshipShapeTpl?.(relationshipPath) ?? null; +} diff --git a/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.ts b/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.ts index f226c533..c60449a5 100644 --- a/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.ts +++ b/packages/erd-editor/src/components/erd/canvas/canvas-svg/relationship/Relationship.ts @@ -4,7 +4,7 @@ import { StartRelationshipType } from '@/constants/schema'; import { Relationship as RelationshipType } from '@/internal-types'; import { getRelationshipPath } from '@/utils/draw-relationship/pathFinding'; -import { relationshipShapeMap } from './Relationship.template'; +import { relationshipShape } from './Relationship.template'; export type RelationshipProps = { relationship: RelationshipType; @@ -16,19 +16,25 @@ const Relationship: FC = (props, ctx) => { const { relationship, strokeWidth } = props; const relationshipPath = getRelationshipPath(relationship); const { path, line } = relationshipPath; - const relationshipShapeTpl = - relationshipShapeMap[relationship.relationshipType]; - const shape = relationshipShapeTpl - ? relationshipShapeTpl(relationshipPath) - : null; + const lines = path.path.d(); + const shape = relationshipShape( + relationship.relationshipType, + relationshipPath + ); return svg` - + ${lines.map( + ([a, b]) => + svg` + + ` + )} store.dispatchSync(undoActions.map(cloneAction)), - redo: () => store.dispatchSync(redoActions.map(cloneAction)), + undo: () => { + const timestamp = Date.now(); + store.dispatchSync(undoActions.map(cloneAction(timestamp))); + }, + redo: () => { + const timestamp = Date.now(); + store.dispatchSync(redoActions.map(cloneAction(timestamp))); + }, }); } -function cloneAction(action: AnyAction) { - return { +function cloneAction(timestamp: number) { + return (action: AnyAction) => ({ ...cloneDeep(action), - timestamp: Date.now(), - }; + timestamp, + }); } export const pushHistory = diff --git a/packages/erd-editor/src/engine/modules/table/generator.actions.ts b/packages/erd-editor/src/engine/modules/table/generator.actions.ts index 371c3fa9..7ff77894 100644 --- a/packages/erd-editor/src/engine/modules/table/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/table/generator.actions.ts @@ -1,3 +1,4 @@ +import { arrayHas } from '@dineug/shared'; import { nanoid } from 'nanoid'; import { ColumnOption } from '@/constants/schema'; @@ -10,7 +11,10 @@ import { } from '@/engine/modules/editor/atom.actions'; import { drawStartAddRelationshipAction$ } from '@/engine/modules/editor/generator.actions'; import { SelectType } from '@/engine/modules/editor/state'; -import { addRelationshipAction } from '@/engine/modules/relationship/atom.actions'; +import { + addRelationshipAction, + removeRelationshipAction, +} from '@/engine/modules/relationship/atom.actions'; import { addColumnAction, changeColumnCommentAction, @@ -55,18 +59,40 @@ export const addTableAction$ = (): GeneratorAction => }; export const removeTableAction$ = (id?: string): GeneratorAction => - function* ({ editor: { selectedMap } }) { + function* ({ + doc: { relationshipIds }, + editor: { selectedMap }, + collections, + }) { + // TODO: valid index + const relationships = query(collections) + .collection('relationshipEntities') + .selectByIds(relationshipIds); + if (id) { + const removeRelationships = relationships.filter( + ({ start, end }) => start.tableId === id || end.tableId === id + ); + for (const { id } of removeRelationships) { + yield removeRelationshipAction({ id }); + } yield removeTableAction({ id }); + return; } - const selectedTables = Object.entries(selectedMap).filter( - ([, type]) => type === SelectType.table + const selectedTableIds = Object.entries(selectedMap) + .filter(([, type]) => type === SelectType.table) + .map(([id]) => id); + const hasTableIds = arrayHas(selectedTableIds); + const removeRelationships = relationships.filter( + ({ start, end }) => hasTableIds(start.tableId) || hasTableIds(end.tableId) ); - // TODO: valid index, relationship - for (const [id] of selectedTables) { + for (const { id } of removeRelationships) { + yield removeRelationshipAction({ id }); + } + for (const id of selectedTableIds) { yield removeTableAction({ id }); } }; diff --git a/packages/erd-editor/src/engine/modules/tableColumn/generator.actions.ts b/packages/erd-editor/src/engine/modules/tableColumn/generator.actions.ts index 4da81989..7cc31f36 100644 --- a/packages/erd-editor/src/engine/modules/tableColumn/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/tableColumn/generator.actions.ts @@ -10,6 +10,7 @@ import { } from '@/engine/modules/editor/atom.actions'; import { FocusType, SelectType } from '@/engine/modules/editor/state'; import { getRemoveFirstColumnId } from '@/engine/modules/editor/utils/focus'; +import { removeRelationshipAction } from '@/engine/modules/relationship/atom.actions'; import { bHas } from '@/utils/bit'; import { query } from '@/utils/collection/query'; @@ -83,8 +84,11 @@ export const removeColumnAction$ = ( columnIds: string[] ): GeneratorAction => function* (state) { + // TODO: valid index const { + doc: { relationshipIds }, editor: { focusTable }, + collections, } = state; if (focusTable?.columnId) { @@ -106,7 +110,19 @@ export const removeColumnAction$ = ( } } - // TODO: valid index, relationship + const hasColumnIds = arrayHas(columnIds); + const relationships = query(collections) + .collection('relationshipEntities') + .selectByIds(relationshipIds) + .filter( + ({ start, end }) => + (start.tableId === tableId && start.columnIds.some(hasColumnIds)) || + (end.tableId === tableId && end.columnIds.some(hasColumnIds)) + ); + + for (const { id } of relationships) { + yield removeRelationshipAction({ id }); + } for (const columnId of columnIds) { yield removeColumnAction({ id: columnId, diff --git a/packages/erd-editor/src/utils/draw-relationship/index.ts b/packages/erd-editor/src/utils/draw-relationship/index.ts index 4c476b51..6e30f6da 100644 --- a/packages/erd-editor/src/utils/draw-relationship/index.ts +++ b/packages/erd-editor/src/utils/draw-relationship/index.ts @@ -32,6 +32,13 @@ export type DrawLine = { }; }; +export type PathPoint = { + M: Point; + L: Point; + Q: Point; + d(): Array<[Point, Point]>; +}; + export type Path = { M: Point; L: Point; @@ -72,7 +79,7 @@ export type Circle = { }; export type RelationshipPath = { - path: { path: Path; line: PathLine }; + path: { path: PathPoint; line: PathLine }; line: { line: Line; circle: Circle; startCircle: Circle }; }; diff --git a/packages/erd-editor/src/utils/draw-relationship/pathFinding.ts b/packages/erd-editor/src/utils/draw-relationship/pathFinding.ts index b05fd205..6c99d4f7 100644 --- a/packages/erd-editor/src/utils/draw-relationship/pathFinding.ts +++ b/packages/erd-editor/src/utils/draw-relationship/pathFinding.ts @@ -1,15 +1,14 @@ import { Direction } from '@/constants/schema'; import { Relationship, RelationshipPoint } from '@/internal-types'; import { - Circle, CIRCLE_HEIGHT, Line, LINE_HEIGHT, LINE_SIZE, - Path, PATH_END_HEIGHT, PATH_LINE_HEIGHT, PathLine, + PathPoint, RelationshipPath, } from '@/utils/draw-relationship'; @@ -25,7 +24,7 @@ export function getRelationshipPath( function getPath( start: RelationshipPoint, end: RelationshipPoint -): { path: Path; line: PathLine } { +): RelationshipPath['path'] { const line: PathLine = { start: { x1: start.x, @@ -40,11 +39,11 @@ function getPath( y2: end.y, }, }; - const path: Path = { + const path: PathPoint = { M: { x: 0, y: 0 }, L: { x: 0, y: 0 }, Q: { x: 0, y: 0 }, - d(): string { + d() { const distanceX = this.M.x - this.L.x; const distanceY = this.M.y - this.L.y; const distanceHalfX = distanceX / 2; @@ -54,22 +53,34 @@ function getPath( ? Math.abs(distanceHalfY) : Math.abs(distanceHalfX); - const addX1 = add(distanceX)(true)(subDistance); - const addY1 = add(distanceY)(true)(subDistance); - const addX2 = add(distanceX)(false)(subDistance); - const addY2 = add(distanceY)(false)(subDistance); + const add = createAdd(subDistance); + const addLeft = add(true); + const addRight = add(false); + + const addX1 = addLeft(distanceX); + const addY1 = addLeft(distanceY); + const addX2 = addRight(distanceX); + const addY2 = addRight(distanceY); const x1 = isAxisX ? this.M.x - distanceHalfX + addX1 : this.M.x; const y1 = isAxisX ? this.M.y : this.M.y - distanceHalfY + addY1; const x2 = isAxisX ? this.L.x + distanceHalfX + addX2 : this.L.x; const y2 = isAxisX ? this.L.y : this.L.y + distanceHalfY + addY2; - const pointStart = `M ${this.M.x} ${this.M.y}`; - const point1 = `L ${x1} ${y1}`; - const point2 = `L ${x2} ${y2}`; - const pointEnd = `L ${this.L.x} ${this.L.y}`; - - return `${pointStart} ${point1} ${point2} ${pointEnd}`; + return [ + [ + { x: this.M.x, y: this.M.y }, + { x: x1, y: y1 }, + ], + [ + { x: x1, y: y1 }, + { x: x2, y: y2 }, + ], + [ + { x: x2, y: y2 }, + { x: this.L.x, y: this.L.y }, + ], + ]; }, }; @@ -129,7 +140,7 @@ function getPath( function getLine( start: RelationshipPoint, end: RelationshipPoint -): { line: Line; circle: Circle; startCircle: Circle } { +): RelationshipPath['line'] { const line: Line = { start: { base: { @@ -295,8 +306,8 @@ function getLine( }; } -function add(distance: number) { - return (leftNegativeMul: boolean) => (value: number) => +function createAdd(value: number) { + return (leftNegativeMul: boolean) => (distance: number) => distance < 0 ? (leftNegativeMul ? -1 : 1) * value : (leftNegativeMul ? 1 : -1) * value;