diff --git a/src/components/EditorCanvas/Relationship.jsx b/src/components/EditorCanvas/Relationship.jsx index fd293543..cb772420 100644 --- a/src/components/EditorCanvas/Relationship.jsx +++ b/src/components/EditorCanvas/Relationship.jsx @@ -2,6 +2,7 @@ import { useRef } from "react"; import { Cardinality, darkBgTheme, + Notation, ObjectType, Tab, } from "../../data/constants"; @@ -10,6 +11,8 @@ import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks"; import { useTranslation } from "react-i18next"; import { SideSheet } from "@douyinfe/semi-ui"; import RelationshipInfo from "../EditorSidePanel/RelationshipsTab/RelationshipInfo"; +import { CrowOM, CrowOO, IDEFZM, DefaultNotation } from "./RelationshipFormat"; + const labelFontSize = 16; @@ -24,28 +27,70 @@ export default function Relationship({ data }) { const pathRef = useRef(); const labelRef = useRef(); - + const type = settings.notation === 'default' ? 0 : 10; + const relationshipType=(5,type); + let direction = 1; let cardinalityStart = "1"; let cardinalityEnd = "1"; + const formats = { + notation: { + default: { + one_to_one: DefaultNotation, + one_to_many: DefaultNotation, + many_to_one: DefaultNotation, + }, + crows_foot: { + one_to_one: CrowOO, + one_to_many: CrowOM, + many_to_one: CrowOM, + }, + idef1x: { + one_to_one: IDEFZM, + one_to_many: IDEFZM, + many_to_one: IDEFZM, + }, + } + } + + let format; switch (data.cardinality) { // the translated values are to ensure backwards compatibility case t(Cardinality.MANY_TO_ONE): case Cardinality.MANY_TO_ONE: - cardinalityStart = "n"; - cardinalityEnd = "1"; + if (settings.notation === Notation.DEFAULT) { + cardinalityStart = "n"; + cardinalityEnd = "1"; + } else { + cardinalityStart = "(1,*)"; + cardinalityEnd = "(1,1)"; + } + format = formats.notation[settings.notation].many_to_one; break; case t(Cardinality.ONE_TO_MANY): case Cardinality.ONE_TO_MANY: - cardinalityStart = "1"; - cardinalityEnd = "n"; + if (settings.notation === Notation.DEFAULT) { + cardinalityStart = "1"; + cardinalityEnd = "n"; + } else { + cardinalityStart = "(1,1)"; + cardinalityEnd = "(1,*)"; + } + format = formats.notation[settings.notation].one_to_many; break; case t(Cardinality.ONE_TO_ONE): case Cardinality.ONE_TO_ONE: - cardinalityStart = "1"; - cardinalityEnd = "1"; + if (settings.notation === Notation.DEFAULT) { + cardinalityStart = "1"; + cardinalityEnd = "1"; + } else { + cardinalityStart = "(1,1)"; + cardinalityEnd = "(1,1)"; + } + format = formats.notation[settings.notation].one_to_one; break; default: + format = formats.default.one_to_one; break; } @@ -61,8 +106,9 @@ export default function Relationship({ data }) { const cardinalityOffset = 28; + if (pathRef.current) { - const pathLength = pathRef.current.getTotalLength(); + const pathLength = pathRef.current.getTotalLength() - cardinalityOffset; const labelPoint = pathRef.current.getPointAtLength(pathLength / 2); labelX = labelPoint.x - (labelWidth ?? 0) / 2; @@ -71,8 +117,9 @@ export default function Relationship({ data }) { const point1 = pathRef.current.getPointAtLength(cardinalityOffset); cardinalityStartX = point1.x; cardinalityStartY = point1.y; + const point2 = pathRef.current.getPointAtLength( - pathLength - cardinalityOffset, + pathLength, ); cardinalityEndX = point2.x; cardinalityEndY = point2.y; @@ -101,6 +148,10 @@ export default function Relationship({ data }) { } }; + if ((settings.notation === Notation.CROWS_FOOT || settings.notation === Notation.IDEF1X) && cardinalityEndX < cardinalityStartX){ + direction = -1; + } + return ( <> @@ -123,9 +174,24 @@ export default function Relationship({ data }) { stroke="gray" className="group-hover:stroke-sky-700" fill="none" + strokeDasharray={relationshipType} strokeWidth={2} cursor="pointer" /> + {settings.showCardinality && ( + <> + {format( + pathRef, + cardinalityEndX, + cardinalityEndY, + cardinalityStartX, + cardinalityStartY, + direction, + cardinalityStart, + cardinalityEnd, + )} + + )} {settings.showRelationshipLabels && ( <> )} - {pathRef.current && settings.showCardinality && ( - <> - - - {cardinalityStart} - - - - {cardinalityEnd} - - - )} + + + + + + {cardinalityStart} + + + {cardinalityEnd} + + + + + ) + ) +} + +export function CrowOO( + pathRef, + cardinalityEndX, + cardinalityEndY, + cardinalityStartX, + cardinalityStartY, + direction, + cardinalitySart, + cardinalityEnd +) { + return( + pathRef && ( + <> + + + + + + + + {cardinalitySart} + + + {cardinalityEnd} + + + ) + ) +} + +export function DefaultNotation( + pathRef, + cardinalityEndX, + cardinalityEndY, cardinalityStartX, + cardinalityStartY, + cardinalityStart, + cardinalityEnd +) { + return( + pathRef && ( + <> + + + {cardinalityStart} + + + + {cardinalityEnd} + + + ) + ) +} + +export function IDEFZM( + pathRef, + cardinalityEndX, + cardinalityEndY, + cardinalityStartX, + cardinalityStartY, + direction, + cardinalityStart, + cardinalityEnd +) { + return( + pathRef && ( + <> + + + {cardinalityStart} + + + {cardinalityEnd} + + + ) + ) +} diff --git a/src/components/EditorCanvas/Table.jsx b/src/components/EditorCanvas/Table.jsx index 3a33652a..df25b63b 100644 --- a/src/components/EditorCanvas/Table.jsx +++ b/src/components/EditorCanvas/Table.jsx @@ -5,6 +5,7 @@ import { tableFieldHeight, tableHeaderHeight, tableColorStripHeight, + Notation, } from "../../data/constants"; import { IconEdit, @@ -16,7 +17,7 @@ import { import { Popover, Tag, Button, SideSheet } from "@douyinfe/semi-ui"; import { useLayout, useSettings, useDiagram, useSelect } from "../../hooks"; import TableInfo from "../EditorSidePanel/TablesTab/TableInfo"; -import { useTranslation } from "react-i18next"; +import { useTranslation} from "react-i18next"; import { dbToTypes } from "../../data/datatypes"; import { isRtl } from "../../i18n/utils/rtl"; import i18n from "../../i18n/i18n"; @@ -77,7 +78,7 @@ export default function Table(props) { .scrollIntoView({ behavior: "smooth" }); } }; - + const primaryKeyCount = tableData.fields.filter(field => field.primary).length; return ( <>
-
+
{tableData.name}
@@ -293,10 +322,50 @@ export default function Table(props) { function field(fieldData, index) { return (
{ if (!e.isPrimary) return; @@ -324,7 +393,11 @@ export default function Table(props) { } flex items-center gap-2 overflow-hidden`} >
diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index feef7a5b..caa3a66a 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -42,6 +42,7 @@ import { SIDESHEET, DB, IMPORT_FROM, + Notation, } from "../../data/constants"; import jsPDF from "jspdf"; import { useHotkeys } from "react-hotkeys-hook"; @@ -1323,6 +1324,26 @@ export default function ControlPanel({ showCardinality: !prev.showCardinality, })), }, + notation: { + children: [ + { + default_notation: () => { + setSettings((prev) => ({ ...prev, notation: Notation.DEFAULT })); + }, + }, + { + crows_foot_notation: () => { + setSettings((prev) => ({ ...prev, notation: Notation.CROWS_FOOT })); + }, + }, + { + idef1x_notation: () => { + setSettings((prev) => ({ ...prev, notation: Notation.IDEF1X })); + }, + }, + ], + function: () => {}, + }, show_relationship_labels: { state: settings.showRelationshipLabels ? ( diff --git a/src/context/SettingsContext.jsx b/src/context/SettingsContext.jsx index 19cd69ec..3da6fedd 100644 --- a/src/context/SettingsContext.jsx +++ b/src/context/SettingsContext.jsx @@ -1,6 +1,5 @@ import { createContext, useEffect, useState } from "react"; -import { tableWidth } from "../data/constants"; - +import { tableWidth, Notation } from "../data/constants"; const defaultSettings = { strictMode: false, showFieldSummary: true, @@ -11,6 +10,7 @@ const defaultSettings = { panning: true, showCardinality: true, showRelationshipLabels: true, + notation: Notation.DEFAULT, tableWidth: tableWidth, showDebugCoordinates: false, }; diff --git a/src/data/constants.js b/src/data/constants.js index 80020c1e..6e9b7a48 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -11,7 +11,11 @@ export const Cardinality = { ONE_TO_MANY: "one_to_many", MANY_TO_ONE: "many_to_one", }; - +export const Notation = { + DEFAULT: "default", + CROWS_FOOT: "crows_foot", + IDEF1X: "idef1x", +} export const Constraint = { NONE: "No action", RESTRICT: "Restrict", diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 472d86ab..a78eaf82 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -51,6 +51,10 @@ const en = { show_grid: "Show grid", show_datatype: "Show datatype", show_cardinality: "Show cardinality", + default_notation: "Default", + crows_foot_notation: "Crow's foot", + idef1x_notation: "IDEF1X", + notation: "Notation", theme: "Theme", light: "Light", dark: "Dark", diff --git a/src/i18n/locales/es.js b/src/i18n/locales/es.js index 38eaf3a3..ce576394 100644 --- a/src/i18n/locales/es.js +++ b/src/i18n/locales/es.js @@ -50,6 +50,10 @@ const es = { reset_view: "Restablecer vista", show_grid: "Mostrar cuadrícula", show_cardinality: "Mostrar cardinalidad", + notation: "Notación", + default_notation: "Notación predeterminada", + crows_foot_notation: "Notación Crow's Foot", + idef1x_notation: "Notación IDEF1X", theme: "Tema", light: "Claro", dark: "Oscuro",