diff --git a/cypress/integration/rendering/newShapes.spec.ts b/cypress/integration/rendering/newShapes.spec.ts index d2f3a7111..4e382f829 100644 --- a/cypress/integration/rendering/newShapes.spec.ts +++ b/cypress/integration/rendering/newShapes.spec.ts @@ -1,7 +1,7 @@ import { imgSnapshotTest } from '../../helpers/util.ts'; -const looks = ['classic', 'handDrawn'] as const; -const directions = ['TB', 'BT', 'LR', 'RL'] as const; +const looks = ['classic'] as const; +const directions = ['TB'] as const; const newShapesSet1 = [ 'triangle', 'slopedRect', @@ -36,19 +36,13 @@ const newShapesSet4 = [ const newShapesSet5 = [ 'linedWaveEdgedRect', 'taggedWaveEdgedRectangle', - 'curlyBraces', + 'curlyBraceLeft', 'curvedTrapezoid', 'waveRectangle', ] as const; // Aggregate all shape sets into a single array -const newShapesSets = [ - newShapesSet1, - newShapesSet2, - newShapesSet3, - newShapesSet4, - newShapesSet5, -] as const; +const newShapesSets = [newShapesSet2] as const; looks.forEach((look) => { directions.forEach((direction) => { diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md index 7efc5497b..83532233d 100644 --- a/docs/syntax/flowchart.md +++ b/docs/syntax/flowchart.md @@ -298,6 +298,608 @@ flowchart TD id1(((This is the text in the circle))) ``` +## Expanded Node Shapes in Mermaid Flowcharts + +Mermaid introduces 30 new shapes to enhance the flexibility and precision of flowchart creation. These new shapes provide more options to represent processes, decisions, events, data storage visually, and other elements within your flowcharts, improving clarity and semantic meaning. + +New Syntax for Shape Definition + +Mermaid now supports a general syntax for defining shape types to accommodate the growing number of shapes. This syntax allows you to assign specific shapes to nodes using a clear and flexible format: + +``` +A@{ shape: rect }@ +``` + +This syntax creates a node A as a rectangle. It renders in the same way as `A["A"]`, or `A`. + +### Complete List of New Shapes + +Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases: + +| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** | +| ------------------------- | --------------------------- | --------------- | ------------------------------ | ---------------------------------------- | +| **Process** | Rectangle | `rect` | Standard process shape | `proc`, `process` | +| **Event** | Rounded Rectangle | `rounded` | Represents an event | `event` | +| **Terminal Point** | Stadium | `stadium` | Terminal point | `term`, `pill` | +| **Subprocess** | Framed Rectangle | `fr` | Subprocess | `subproc`, `framed-rectangle` | +| **Database** | Cylinder | `cyl` | Database storage | `db`, `cylinder` | +| **Start** | Circle | `circle` | Starting point | | +| **Odd** | Odd | `odd` | Odd shape | | +| **Decision** | Diamond | `diam` | Decision-making step | `decision`, `diamond` | +| **Prepare Conditional** | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` | +| **Data Input/Output** | Lean Right | `l-r` | Represents input or output | `lean-right`, `in-out` | +| **Data Input/Output** | Lean Left | `l-l` | Represents output or input | `lean-left`, `out-in` | +| **Priority Action** | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid-bottom` | +| **Manual Operation** | Trapezoid Base Top | `trap-t` | Represents a manual task | `manual`, `trapezoid-top` | +| **Stop** | Double Circle | `dc` | Represents a stop point | `double-circle` | +| **Text Block** | Text Block | `text` | Text block | - | +| **Card** | Notched Rectangle | `notched-rect` | Represents a card | `card`, `notch-rect` | +| **Lined/Shaded Process** | Lined Rectangle | `lined-rect` | Lined process shape | `lined-proc` | +| **Start** | Small Circle | `sm-circ` | Small starting point | `start`, `small-circle` | +| **Stop** | Framed Circle | `framed-circle` | Stop point | `stop`, `framed-circle` | +| **Fork/Join** | Long Rectangle | `fork` | Fork or join in process flow | `join`, `long-rect` | +| **Collate** | Hourglass | `hourglass` | Represents a collate operation | - | +| **Comment** | Curly Brace | `brace` | Adds a comment | `comment` | +| **Com Link** | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` | +| **Document** | Wave-Edged Rectangle | `we-rect` | Represents a document | `doc`, `wave-edge-rect` | +| **Delay** | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rect` | +| **Direct Access Storage** | Tilted Cylinder | `t-cyl` | Direct access storage | `das`, `tilted-cylinder` | +| **Disk Storage** | Lined Cylinder | `l-cyl` | Disk storage | `disk`, `lined-cylinder` | +| **Display** | Curved Trapezoid | `cur-trap` | Represents a display | `disp`, `curved-trapezoid` | +| **Divided Process** | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-rectangle` | +| **Extract** | Small Triangle | `sm-tri` | Extraction process | `extract`, `small-triangle` | +| **Internal Storage** | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` | +| **Junction** | Filled Circle | `fc` | Junction point | `junction`, `filled-circle` | +| **Lined Document** | Lined Wave-Edged Rectangle | `lin-we-rect` | Lined document | `lin-doc`, `lined-wave-edged-rect` | +| **Loop Limit** | Trapezoidal Pentagon | `not-pent` | Loop limit step | `loop-limit`, `notched-pentagon` | +| **Manual File** | Flipped Triangle | `flip-tria` | Manual file operation | `manual-file`, `flipped-triangle` | +| **Manual Input** | Sloped Rectangle | `sloped-rect` | Manual input step | `manual-input`, `sloped-rectangle` | +| **Multi-Document** | Multi-Wave-Edged Rectangle | `mul-we-rect` | Multiple documents | `mul-doc`, `multi-wave-edged-rectangle` | +| **Multi-Process** | Multi-Rect | `mul-rect` | Multiple processes | `mul-proc`, `multi-rect` | +| **Paper Tape** | Flag | `flag` | Paper tape | `paper-tape`, \`\` | +| **Stored Data** | Bow Tie Rectangle | `bt-rect` | Stored data | `stored-data`, `bow-tie-rect` | +| **Summary** | Crossed Circle | `cross-circle` | Summary | `summary`, `crossed-circle` | +| **Tagged Document** | Tagged Wave-Edged Rectangle | `tag-we-rect` | Tagged document | `tag-doc`, `tagged-wave-edged-rectangle` | +| **Tagged Process** | Tagged Rectangle | `tag-rect` | Tagged process | `tag-proc`, `tagged-rect` | + +### Example Flowchart with New Shapes + +Here’s an example flowchart that utilizes some of the newly introduced shapes: + +```mermaid-example +flowchart RL + A5@{ shape: manual-file, label: "File Handling"}@ + B5@{ shape: manual-input, label: "User Input"}@ + C5@{ shape: mul-doc, label: "Multiple Documents"}@ + D5@{ shape: mul-proc, label: "Process Automation"}@ + E5@{ shape: paper-tape, label: "Paper Records"}@ +``` + +```mermaid +flowchart RL + A5@{ shape: manual-file, label: "File Handling"}@ + B5@{ shape: manual-input, label: "User Input"}@ + C5@{ shape: mul-doc, label: "Multiple Documents"}@ + D5@{ shape: mul-proc, label: "Process Automation"}@ + E5@{ shape: paper-tape, label: "Paper Records"}@ +``` + +### Process + +```mermaid-example +flowchart TD + A@{ shape: rect, label: "This is a process" }@ +``` + +```mermaid +flowchart TD + A@{ shape: rect, label: "This is a process" }@ +``` + +### Event + +```mermaid-example +flowchart TD + A@{ shape: rounded, label: "This is an event" }@ +``` + +```mermaid +flowchart TD + A@{ shape: rounded, label: "This is an event" }@ +``` + +### Terminal Point (Stadium) + +```mermaid-example +flowchart TD + A@{ shape: stadium, label: "Terminal point" }@ +``` + +```mermaid +flowchart TD + A@{ shape: stadium, label: "Terminal point" }@ +``` + +### Subprocess + +```mermaid-example +flowchart TD + A@{ shape: fr, label: "This is a subprocess" }@ +``` + +```mermaid +flowchart TD + A@{ shape: fr, label: "This is a subprocess" }@ +``` + +### Database (Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: cyl, label: "Database" }@ +``` + +```mermaid +flowchart TD + A@{ shape: cyl, label: "Database" }@ +``` + +### Start (Circle) + +```mermaid-example +flowchart TD + A@{ shape: circle, label: "Start" }@ +``` + +```mermaid +flowchart TD + A@{ shape: circle, label: "Start" }@ +``` + +### Odd + +```mermaid-example +flowchart TD + A@{ shape: odd, label: "Odd shape" }@ +``` + +```mermaid +flowchart TD + A@{ shape: odd, label: "Odd shape" }@ +``` + +### Decision (Diamond) + +```mermaid-example +flowchart TD + A@{ shape: diamond, label: "Decision" }@ +``` + +```mermaid +flowchart TD + A@{ shape: diamond, label: "Decision" }@ +``` + +### Prepare Conditional (Hexagon) + +```mermaid-example +flowchart TD + A@{ shape: hex, label: "Prepare conditional" }@ +``` + +```mermaid +flowchart TD + A@{ shape: hex, label: "Prepare conditional" }@ +``` + +### Data Input/Output (Lean Right) + +```mermaid-example +flowchart TD + A@{ shape: l-r, label: "Input/Output" }@ +``` + +```mermaid +flowchart TD + A@{ shape: l-r, label: "Input/Output" }@ +``` + +### Data Input/Output (Lean Left) + +```mermaid-example +flowchart TD + A@{ shape: l-l, label: "Output/Input" }@ +``` + +```mermaid +flowchart TD + A@{ shape: l-l, label: "Output/Input" }@ +``` + +### Priority Action (Trapezoid Base Bottom) + +```mermaid-example +flowchart TD + A@{ shape: trap-b, label: "Priority action" }@ +``` + +```mermaid +flowchart TD + A@{ shape: trap-b, label: "Priority action" }@ +``` + +### Manual Operation (Trapezoid Base Top) + +```mermaid-example +flowchart TD + A@{ shape: trap-t, label: "Manual operation" }@ +``` + +```mermaid +flowchart TD + A@{ shape: trap-t, label: "Manual operation" }@ +``` + +### Stop (Double Circle) + +```mermaid-example +flowchart TD + A@{ shape: dc, label: "Stop" }@ +``` + +```mermaid +flowchart TD + A@{ shape: dc, label: "Stop" }@ +``` + +### Text Block + +```mermaid-example +flowchart TD + A@{ shape: text, label: "This is a text block" }@ +``` + +```mermaid +flowchart TD + A@{ shape: text, label: "This is a text block" }@ +``` + +### Card (Notched Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: notched-rect, label: "Card" }@ +``` + +```mermaid +flowchart TD + A@{ shape: notched-rect, label: "Card" }@ +``` + +### Lined/Shaded Process + +```mermaid-example +flowchart TD + A@{ shape: lined-rect, label: "Lined process" }@ +``` + +```mermaid +flowchart TD + A@{ shape: lined-rect, label: "Lined process" }@ +``` + +### Start (Small Circle) + +```mermaid-example +flowchart TD + A@{ shape: sm-circ, label: "Small start" }@ +``` + +```mermaid +flowchart TD + A@{ shape: sm-circ, label: "Small start" }@ +``` + +### Stop (Framed Circle) + +```mermaid-example +flowchart TD + A@{ shape: framed-circle, label: "Stop" }@ +``` + +```mermaid +flowchart TD + A@{ shape: framed-circle, label: "Stop" }@ +``` + +### Fork/Join (Long Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: fork, label: "Fork or Join" }@ +``` + +```mermaid +flowchart TD + A@{ shape: fork, label: "Fork or Join" }@ +``` + +### Collate (Hourglass) + +```mermaid-example +flowchart TD + A@{ shape: hourglass, label: "Collate" }@ +``` + +```mermaid +flowchart TD + A@{ shape: hourglass, label: "Collate" }@ +``` + +### Comment (Curly Brace) + +```mermaid-example +flowchart TD + A@{ shape: brace, label: "Comment" }@ +``` + +```mermaid +flowchart TD + A@{ shape: brace, label: "Comment" }@ +``` + +### Com Link (Lightning Bolt) + +```mermaid-example +flowchart TD + A@{ shape: bolt, label: "Communication link" }@ +``` + +```mermaid +flowchart TD + A@{ shape: bolt, label: "Communication link" }@ +``` + +### Document (Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: we-rect, label: "Document" }@ +``` + +```mermaid +flowchart TD + A@{ shape: we-rect, label: "Document" }@ +``` + +### Delay (Half-Rounded Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: delay, label: "Delay" }@ +``` + +```mermaid +flowchart TD + A@{ shape: delay, label: "Delay" }@ +``` + +### Direct Access Storage (Tilted Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: t-cyl, label: "Direct access storage" }@ +``` + +```mermaid +flowchart TD + A@{ shape: t-cyl, label: "Direct access storage" }@ +``` + +### Disk Storage (Lined Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: l-cyl, label: "Disk storage" }@ +``` + +```mermaid +flowchart TD + A@{ shape: l-cyl, label: "Disk storage" }@ +``` + +### Display (Curved Trapezoid) + +```mermaid-example +flowchart TD + A@{ shape: cur-trap, label: "Display" }@ +``` + +```mermaid +flowchart TD + A@{ shape: cur-trap, label: "Display" }@ +``` + +### Divided Process (Divided Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: div-rect, label: "Divided process" }@ +``` + +```mermaid +flowchart TD + A@{ shape: div-rect, label: "Divided process" }@ +``` + +### Extract (Small Triangle) + +```mermaid-example +flowchart TD + A@{ shape: sm-tri, label: "Extract" }@ +``` + +```mermaid +flowchart TD + A@{ shape: sm-tri, label: "Extract" }@ +``` + +### Internal Storage (Window Pane) + +```mermaid-example +flowchart TD + A@{ shape: win-pane, label: "Internal storage" }@ +``` + +```mermaid +flowchart TD + A@{ shape: win-pane, label: "Internal storage" }@ +``` + +### Junction (Filled Circle) + +```mermaid-example +flowchart TD + A@{ shape: fc, label: "Junction" }@ +``` + +```mermaid +flowchart TD + A@{ shape: fc, label: "Junction" }@ +``` + +### Lined Document (Lined Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: lin-we-rect, label: "Lined document" }@ +``` + +```mermaid +flowchart TD + A@{ shape: lin-we-rect, label: "Lined document" }@ +``` + +### Loop Limit (Trapezoidal Pentagon) + +```mermaid-example +flowchart TD + A@{ shape: not-pent, label: "Loop limit" }@ +``` + +```mermaid +flowchart TD + A@{ shape: not-pent, label: "Loop limit" }@ +``` + +### Manual File (Flipped Triangle) + +```mermaid-example +flowchart TD + A@{ shape: flip-tria, label: "Manual file" }@ +``` + +```mermaid +flowchart TD + A@{ shape: flip-tria, label: "Manual file" }@ +``` + +### Manual Input (Sloped Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: sloped-rect, label: "Manual input" }@ +``` + +```mermaid +flowchart TD + A@{ shape: sloped-rect, label: "Manual input" }@ +``` + +### Multi-Document (Multi-Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: mul-we-rect, label: "Multiple documents" }@ +``` + +```mermaid +flowchart TD + A@{ shape: mul-we-rect, label: "Multiple documents" }@ +``` + +### Multi-Process (Multi-Rect) + +```mermaid-example +flowchart TD + A@{ shape: mul-rect, label: "Multiple processes" }@ +``` + +```mermaid +flowchart TD + A@{ shape: mul-rect, label: "Multiple processes" }@ +``` + +### Paper Tape (Flag) + +```mermaid-example +flowchart TD + A@{ shape: flag, label: "Paper tape" }@ +``` + +```mermaid +flowchart TD + A@{ shape: flag, label: "Paper tape" }@ +``` + +### Stored Data (Bow Tie Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: bt-rect, label: "Stored data" }@ +``` + +```mermaid +flowchart TD + A@{ shape: bt-rect, label: "Stored data" }@ +``` + +### Summary (Crossed Circle) + +```mermaid-example +flowchart TD + A@{ shape: cross-circle, label: "Summary" }@ +``` + +```mermaid +flowchart TD + A@{ shape: cross-circle, label: "Summary" }@ +``` + +### Tagged Document (Tagged Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: tag-we-rect, label: "Tagged document" }@ +``` + +```mermaid +flowchart TD + A@{ shape: tag-we-rect, label: "Tagged document" }@ +``` + +### Tagged Process (Tagged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: tag-rect, label: "Tagged process" }@ +``` + +```mermaid +flowchart TD + A@{ shape: tag-rect, label: "Tagged process" }@ +``` + ## Links between nodes Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link. diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index 5adb54ada..5571dcea9 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -1,6 +1,6 @@ { "name": "@mermaid-chart/mermaid", - "version": "11.1.0-b.3", + "version": "11.1.0-b.4", "description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.", "type": "module", "module": "./dist/mermaid.core.mjs", diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md index acffbc693..dffe23d9e 100644 --- a/packages/mermaid/src/docs/syntax/flowchart.md +++ b/packages/mermaid/src/docs/syntax/flowchart.md @@ -194,6 +194,384 @@ flowchart TD id1(((This is the text in the circle))) ``` +## Expanded Node Shapes in Mermaid Flowcharts + +Mermaid introduces 30 new shapes to enhance the flexibility and precision of flowchart creation. These new shapes provide more options to represent processes, decisions, events, data storage visually, and other elements within your flowcharts, improving clarity and semantic meaning. + +New Syntax for Shape Definition + +Mermaid now supports a general syntax for defining shape types to accommodate the growing number of shapes. This syntax allows you to assign specific shapes to nodes using a clear and flexible format: + +``` +A@{ shape: rect }@ +``` + +This syntax creates a node A as a rectangle. It renders in the same way as `A["A"]`, or `A`. + +### Complete List of New Shapes + +Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases: + +| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** | +| ------------------------- | --------------------------- | --------------- | ------------------------------ | ---------------------------------------- | +| **Process** | Rectangle | `rect` | Standard process shape | `proc`, `process` | +| **Event** | Rounded Rectangle | `rounded` | Represents an event | `event` | +| **Terminal Point** | Stadium | `stadium` | Terminal point | `term`, `pill` | +| **Subprocess** | Framed Rectangle | `fr` | Subprocess | `subproc`, `framed-rectangle` | +| **Database** | Cylinder | `cyl` | Database storage | `db`, `cylinder` | +| **Start** | Circle | `circle` | Starting point | | +| **Odd** | Odd | `odd` | Odd shape | | +| **Decision** | Diamond | `diam` | Decision-making step | `decision`, `diamond` | +| **Prepare Conditional** | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` | +| **Data Input/Output** | Lean Right | `l-r` | Represents input or output | `lean-right`, `in-out` | +| **Data Input/Output** | Lean Left | `l-l` | Represents output or input | `lean-left`, `out-in` | +| **Priority Action** | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid-bottom` | +| **Manual Operation** | Trapezoid Base Top | `trap-t` | Represents a manual task | `manual`, `trapezoid-top` | +| **Stop** | Double Circle | `dc` | Represents a stop point | `double-circle` | +| **Text Block** | Text Block | `text` | Text block | - | +| **Card** | Notched Rectangle | `notched-rect` | Represents a card | `card`, `notch-rect` | +| **Lined/Shaded Process** | Lined Rectangle | `lined-rect` | Lined process shape | `lined-proc` | +| **Start** | Small Circle | `sm-circ` | Small starting point | `start`, `small-circle` | +| **Stop** | Framed Circle | `framed-circle` | Stop point | `stop`, `framed-circle` | +| **Fork/Join** | Long Rectangle | `fork` | Fork or join in process flow | `join`, `long-rect` | +| **Collate** | Hourglass | `hourglass` | Represents a collate operation | - | +| **Comment** | Curly Brace | `brace` | Adds a comment | `comment` | +| **Com Link** | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` | +| **Document** | Wave-Edged Rectangle | `we-rect` | Represents a document | `doc`, `wave-edge-rect` | +| **Delay** | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rect` | +| **Direct Access Storage** | Tilted Cylinder | `t-cyl` | Direct access storage | `das`, `tilted-cylinder` | +| **Disk Storage** | Lined Cylinder | `l-cyl` | Disk storage | `disk`, `lined-cylinder` | +| **Display** | Curved Trapezoid | `cur-trap` | Represents a display | `disp`, `curved-trapezoid` | +| **Divided Process** | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-rectangle` | +| **Extract** | Small Triangle | `sm-tri` | Extraction process | `extract`, `small-triangle` | +| **Internal Storage** | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` | +| **Junction** | Filled Circle | `fc` | Junction point | `junction`, `filled-circle` | +| **Lined Document** | Lined Wave-Edged Rectangle | `lin-we-rect` | Lined document | `lin-doc`, `lined-wave-edged-rect` | +| **Loop Limit** | Trapezoidal Pentagon | `not-pent` | Loop limit step | `loop-limit`, `notched-pentagon` | +| **Manual File** | Flipped Triangle | `flip-tria` | Manual file operation | `manual-file`, `flipped-triangle` | +| **Manual Input** | Sloped Rectangle | `sloped-rect` | Manual input step | `manual-input`, `sloped-rectangle` | +| **Multi-Document** | Multi-Wave-Edged Rectangle | `mul-we-rect` | Multiple documents | `mul-doc`, `multi-wave-edged-rectangle` | +| **Multi-Process** | Multi-Rect | `mul-rect` | Multiple processes | `mul-proc`, `multi-rect` | +| **Paper Tape** | Flag | `flag` | Paper tape | `paper-tape`, `` | +| **Stored Data** | Bow Tie Rectangle | `bt-rect` | Stored data | `stored-data`, `bow-tie-rect` | +| **Summary** | Crossed Circle | `cross-circle` | Summary | `summary`, `crossed-circle` | +| **Tagged Document** | Tagged Wave-Edged Rectangle | `tag-we-rect` | Tagged document | `tag-doc`, `tagged-wave-edged-rectangle` | +| **Tagged Process** | Tagged Rectangle | `tag-rect` | Tagged process | `tag-proc`, `tagged-rect` | + +### Example Flowchart with New Shapes + +Here’s an example flowchart that utilizes some of the newly introduced shapes: + +```mermaid-example +flowchart RL + A5@{ shape: manual-file, label: "File Handling"}@ + B5@{ shape: manual-input, label: "User Input"}@ + C5@{ shape: mul-doc, label: "Multiple Documents"}@ + D5@{ shape: mul-proc, label: "Process Automation"}@ + E5@{ shape: paper-tape, label: "Paper Records"}@ +``` + +### Process + +```mermaid-example +flowchart TD + A@{ shape: rect, label: "This is a process" }@ +``` + +### Event + +```mermaid-example +flowchart TD + A@{ shape: rounded, label: "This is an event" }@ +``` + +### Terminal Point (Stadium) + +```mermaid-example +flowchart TD + A@{ shape: stadium, label: "Terminal point" }@ +``` + +### Subprocess + +```mermaid-example +flowchart TD + A@{ shape: fr, label: "This is a subprocess" }@ +``` + +### Database (Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: cyl, label: "Database" }@ +``` + +### Start (Circle) + +```mermaid-example +flowchart TD + A@{ shape: circle, label: "Start" }@ +``` + +### Odd + +```mermaid-example +flowchart TD + A@{ shape: odd, label: "Odd shape" }@ +``` + +### Decision (Diamond) + +```mermaid-example +flowchart TD + A@{ shape: diamond, label: "Decision" }@ +``` + +### Prepare Conditional (Hexagon) + +```mermaid-example +flowchart TD + A@{ shape: hex, label: "Prepare conditional" }@ +``` + +### Data Input/Output (Lean Right) + +```mermaid-example +flowchart TD + A@{ shape: l-r, label: "Input/Output" }@ +``` + +### Data Input/Output (Lean Left) + +```mermaid-example +flowchart TD + A@{ shape: l-l, label: "Output/Input" }@ +``` + +### Priority Action (Trapezoid Base Bottom) + +```mermaid-example +flowchart TD + A@{ shape: trap-b, label: "Priority action" }@ +``` + +### Manual Operation (Trapezoid Base Top) + +```mermaid-example +flowchart TD + A@{ shape: trap-t, label: "Manual operation" }@ +``` + +### Stop (Double Circle) + +```mermaid-example +flowchart TD + A@{ shape: dc, label: "Stop" }@ +``` + +### Text Block + +```mermaid-example +flowchart TD + A@{ shape: text, label: "This is a text block" }@ +``` + +### Card (Notched Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: notched-rect, label: "Card" }@ +``` + +### Lined/Shaded Process + +```mermaid-example +flowchart TD + A@{ shape: lined-rect, label: "Lined process" }@ +``` + +### Start (Small Circle) + +```mermaid-example +flowchart TD + A@{ shape: sm-circ, label: "Small start" }@ +``` + +### Stop (Framed Circle) + +```mermaid-example +flowchart TD + A@{ shape: framed-circle, label: "Stop" }@ +``` + +### Fork/Join (Long Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: fork, label: "Fork or Join" }@ +``` + +### Collate (Hourglass) + +```mermaid-example +flowchart TD + A@{ shape: hourglass, label: "Collate" }@ +``` + +### Comment (Curly Brace) + +```mermaid-example +flowchart TD + A@{ shape: brace, label: "Comment" }@ +``` + +### Com Link (Lightning Bolt) + +```mermaid-example +flowchart TD + A@{ shape: bolt, label: "Communication link" }@ +``` + +### Document (Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: we-rect, label: "Document" }@ +``` + +### Delay (Half-Rounded Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: delay, label: "Delay" }@ +``` + +### Direct Access Storage (Tilted Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: t-cyl, label: "Direct access storage" }@ +``` + +### Disk Storage (Lined Cylinder) + +```mermaid-example +flowchart TD + A@{ shape: l-cyl, label: "Disk storage" }@ +``` + +### Display (Curved Trapezoid) + +```mermaid-example +flowchart TD + A@{ shape: cur-trap, label: "Display" }@ +``` + +### Divided Process (Divided Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: div-rect, label: "Divided process" }@ +``` + +### Extract (Small Triangle) + +```mermaid-example +flowchart TD + A@{ shape: sm-tri, label: "Extract" }@ +``` + +### Internal Storage (Window Pane) + +```mermaid-example +flowchart TD + A@{ shape: win-pane, label: "Internal storage" }@ +``` + +### Junction (Filled Circle) + +```mermaid-example +flowchart TD + A@{ shape: fc, label: "Junction" }@ +``` + +### Lined Document (Lined Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: lin-we-rect, label: "Lined document" }@ +``` + +### Loop Limit (Trapezoidal Pentagon) + +```mermaid-example +flowchart TD + A@{ shape: not-pent, label: "Loop limit" }@ +``` + +### Manual File (Flipped Triangle) + +```mermaid-example +flowchart TD + A@{ shape: flip-tria, label: "Manual file" }@ +``` + +### Manual Input (Sloped Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: sloped-rect, label: "Manual input" }@ +``` + +### Multi-Document (Multi-Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: mul-we-rect, label: "Multiple documents" }@ +``` + +### Multi-Process (Multi-Rect) + +```mermaid-example +flowchart TD + A@{ shape: mul-rect, label: "Multiple processes" }@ +``` + +### Paper Tape (Flag) + +```mermaid-example +flowchart TD + A@{ shape: flag, label: "Paper tape" }@ +``` + +### Stored Data (Bow Tie Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: bt-rect, label: "Stored data" }@ +``` + +### Summary (Crossed Circle) + +```mermaid-example +flowchart TD + A@{ shape: cross-circle, label: "Summary" }@ +``` + +### Tagged Document (Tagged Wave-Edged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: tag-we-rect, label: "Tagged document" }@ +``` + +### Tagged Process (Tagged Rectangle) + +```mermaid-example +flowchart TD + A@{ shape: tag-rect, label: "Tagged process" }@ +``` + ## Links between nodes Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link. diff --git a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js index 7badf463b..3b9c7cc8d 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js +++ b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js @@ -48,6 +48,8 @@ import { multiWaveEdgedRectangle } from './shapes/multiWaveEdgedRectangle.js'; import { windowPane } from './shapes/windowPane.js'; import { linedWaveEdgedRect } from './shapes/linedWaveEdgedRect.js'; import { taggedWaveEdgedRectangle } from './shapes/taggedWaveEdgedRectangle.js'; +import { curlyBraceLeft } from './shapes/curlyBraceLeft.js'; +import { curlyBraceRight } from './shapes/curlyBraceRight.js'; import { curlyBraces } from './shapes/curlyBraces.js'; //Use these names as the left side to render shapes. @@ -64,17 +66,19 @@ const shapes = { // Rectangles rectWithTitle, - rect: rectWithTitle, - process: rectWithTitle, - proc: rectWithTitle, roundedRect, rounded: roundedRect, event: roundedRect, squareRect, + rectangle: squareRect, + rect: squareRect, + process: squareRect, + proc: squareRect, stadium, pill: stadium, term: stadium, windowPane, + 'window-pane': windowPane, 'win-pane': windowPane, 'internal-storage': windowPane, dividedRectangle, @@ -112,10 +116,11 @@ const shapes = { // Circles circle, doublecircle, + 'double-circle': doublecircle, dc: doublecircle, crossedCircle, - 'crossed-circ': crossedCircle, - 'cross-circ': crossedCircle, + 'crossed-circle': crossedCircle, + 'cross-circle': crossedCircle, summary: crossedCircle, filledCircle, 'filled-circle': filledCircle, @@ -154,7 +159,7 @@ const shapes = { 'manual-file': flippedTriangle, trapezoidalPentagon, 'notched-pentagon': trapezoidalPentagon, - 'not-pen': trapezoidalPentagon, + 'not-pent': trapezoidalPentagon, 'loop-limit': trapezoidalPentagon, //wave Edged Rectangles @@ -164,6 +169,7 @@ const shapes = { flag: waveRectangle, 'paper-tape': waveRectangle, waveEdgedRectangle, + 'wave-edge-rect': waveEdgedRectangle, 'wave-rect': waveEdgedRectangle, 'we-rect': waveEdgedRectangle, doc: waveEdgedRectangle, @@ -176,8 +182,9 @@ const shapes = { 'lin-we-rect': linedWaveEdgedRect, 'lin-doc': linedWaveEdgedRect, taggedWaveEdgedRectangle, - 'tagged-wave-edged-rect': taggedWaveEdgedRectangle, + 'tagged-wave-edged-rectangle': taggedWaveEdgedRectangle, 'tag-we-rect': taggedWaveEdgedRectangle, + 'tag-doc': taggedWaveEdgedRectangle, // Custom Rectangles bowTieRect, @@ -194,15 +201,16 @@ const shapes = { card, 'notched-rect': card, 'notch-rect': card, - lean_right, + 'lean-right': lean_right, 'l-r': lean_right, 'in-out': lean_right, - lean_left, + 'lean-left': lean_left, 'l-l': lean_left, 'out-in': lean_left, // Miscellaneous forkJoin, + 'long-rect': forkJoin, fork: forkJoin, join: forkJoin, choice, @@ -211,14 +219,18 @@ const shapes = { anchor, diamond: question, lightningBolt, + 'lightning-bolt': lightningBolt, bolt: lightningBolt, 'com-link': lightningBolt, - curlyBraces, - brace: curlyBraces, - comment: curlyBraces, + curlyBraceLeft, + 'brace-l': curlyBraceLeft, + comment: curlyBraceLeft, hourglass, odd: rect_left_inv_arrow, labelRect, + curlyBraceRight, + 'brace-r': curlyBraceRight, + curlyBraces, }; const nodeElems = new Map(); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts new file mode 100644 index 000000000..cd9d7f14e --- /dev/null +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceLeft.ts @@ -0,0 +1,114 @@ +import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; +import intersect from '../intersect/index.js'; +import type { Node } from '$root/rendering-util/types.d.ts'; +import { + styles2String, + userNodeOverrides, +} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; +import rough from 'roughjs'; + +function generateCirclePoints( + centerX: number, + centerY: number, + radius: number, + numPoints = 100, + startAngle = 0, + endAngle = 180 +) { + const points = []; + + // Convert angles to radians + const startAngleRad = (startAngle * Math.PI) / 180; + const endAngleRad = (endAngle * Math.PI) / 180; + + // Calculate the angle range in radians + const angleRange = endAngleRad - startAngleRad; + + // Calculate the angle step + const angleStep = angleRange / (numPoints - 1); + + for (let i = 0; i < numPoints; i++) { + const angle = startAngleRad + i * angleStep; + const x = centerX + radius * Math.cos(angle); + const y = centerY + radius * Math.sin(angle); + points.push({ x: -x, y: -y }); + } + + return points; +} + +export const curlyBraceLeft = async (parent: SVGAElement, node: Node) => { + const { labelStyles, nodeStyles } = styles2String(node); + node.labelStyle = labelStyles; + const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node)); + const w = bbox.width + (node.padding ?? 0); + const h = bbox.height + (node.padding ?? 0); + const radius = Math.max(5, h * 0.1); + + const { cssStyles } = node; + + const points = [ + ...generateCirclePoints(w / 2, -h / 2, radius, 30, -90, 0), + { x: -w / 2 - radius, y: radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: -h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + ]; + + const rectPoints = [ + { x: w / 2, y: -h / 2 - radius }, + { x: -w / 2, y: -h / 2 - radius }, + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: -w / 2 - radius, y: -radius }, + ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + { x: -w / 2, y: h / 2 + radius }, + { x: w / 2, y: h / 2 + radius }, + ]; + + // @ts-ignore - rough is not typed + const rc = rough.svg(shapeSvg); + const options = userNodeOverrides(node, { fill: 'none' }); + + if (node.look !== 'handDrawn') { + options.roughness = 0; + options.fillStyle = 'solid'; + } + const curlyBraceLeftPath = createPathFromPoints(points); + const newCurlyBracePath = curlyBraceLeftPath.replace('Z', ''); + const curlyBraceLeftNode = rc.path(newCurlyBracePath, options); + const rectPath = createPathFromPoints(rectPoints); + const rectShape = rc.path(rectPath, { ...options }); + const curlyBraceLeftShape = shapeSvg.insert('g', ':first-child'); + curlyBraceLeftShape.insert(() => rectShape, ':first-child').attr('stroke-opacity', 0); + curlyBraceLeftShape.insert(() => curlyBraceLeftNode, ':first-child'); + curlyBraceLeftShape.attr('class', 'text'); + + if (cssStyles && node.look !== 'handDrawn') { + curlyBraceLeftShape.selectAll('path').attr('style', cssStyles); + } + + if (nodeStyles && node.look !== 'handDrawn') { + curlyBraceLeftShape.selectAll('path').attr('style', nodeStyles); + } + + curlyBraceLeftShape.attr('transform', `translate(${radius}, 0)`); + + label.attr( + 'transform', + `translate(${-w / 2 + radius - (bbox.x - (bbox.left ?? 0))},${-h / 2 + (node.padding ?? 0) / 2 - (bbox.y - (bbox.top ?? 0))})` + ); + + updateNodeBounds(node, curlyBraceLeftShape); + + node.intersect = function (point) { + const pos = intersect.polygon(node, rectPoints, point); + + return pos; + }; + + return shapeSvg; +}; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts new file mode 100644 index 000000000..87787b311 --- /dev/null +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraceRight.ts @@ -0,0 +1,114 @@ +import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js'; +import intersect from '../intersect/index.js'; +import type { Node } from '$root/rendering-util/types.d.ts'; +import { + styles2String, + userNodeOverrides, +} from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; +import rough from 'roughjs'; + +function generateCirclePoints( + centerX: number, + centerY: number, + radius: number, + numPoints = 100, + startAngle = 0, + endAngle = 180 +) { + const points = []; + + // Convert angles to radians + const startAngleRad = (startAngle * Math.PI) / 180; + const endAngleRad = (endAngle * Math.PI) / 180; + + // Calculate the angle range in radians + const angleRange = endAngleRad - startAngleRad; + + // Calculate the angle step + const angleStep = angleRange / (numPoints - 1); + + for (let i = 0; i < numPoints; i++) { + const angle = startAngleRad + i * angleStep; + const x = centerX + radius * Math.cos(angle); + const y = centerY + radius * Math.sin(angle); + points.push({ x, y }); + } + + return points; +} + +export const curlyBraceRight = async (parent: SVGAElement, node: Node) => { + const { labelStyles, nodeStyles } = styles2String(node); + node.labelStyle = labelStyles; + const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node)); + const w = bbox.width + (node.padding ?? 0); + const h = bbox.height + (node.padding ?? 0); + const radius = Math.max(5, h * 0.1); + + const { cssStyles } = node; + + const points = [ + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: w / 2 + radius, y: -radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: w / 2 + radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + ]; + + const rectPoints = [ + { x: -w / 2, y: -h / 2 - radius }, + { x: w / 2, y: -h / 2 - radius }, + ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), + { x: w / 2 + radius, y: -radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: w / 2 + radius, y: h / 2 }, + ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), + { x: w / 2, y: h / 2 + radius }, + { x: -w / 2, y: h / 2 + radius }, + ]; + + // @ts-ignore - rough is not typed + const rc = rough.svg(shapeSvg); + const options = userNodeOverrides(node, { fill: 'none' }); + + if (node.look !== 'handDrawn') { + options.roughness = 0; + options.fillStyle = 'solid'; + } + const curlyBraceRightPath = createPathFromPoints(points); + const newCurlyBracePath = curlyBraceRightPath.replace('Z', ''); + const curlyBraceRightNode = rc.path(newCurlyBracePath, options); + const rectPath = createPathFromPoints(rectPoints); + const rectShape = rc.path(rectPath, { ...options }); + const curlyBraceRightShape = shapeSvg.insert('g', ':first-child'); + curlyBraceRightShape.insert(() => rectShape, ':first-child').attr('stroke-opacity', 0); + curlyBraceRightShape.insert(() => curlyBraceRightNode, ':first-child'); + curlyBraceRightShape.attr('class', 'text'); + + if (cssStyles && node.look !== 'handDrawn') { + curlyBraceRightShape.selectAll('path').attr('style', cssStyles); + } + + if (nodeStyles && node.look !== 'handDrawn') { + curlyBraceRightShape.selectAll('path').attr('style', nodeStyles); + } + + curlyBraceRightShape.attr('transform', `translate(${-radius}, 0)`); + + label.attr( + 'transform', + `translate(${-w / 2 + (node.padding ?? 0) / 2 - (bbox.x - (bbox.left ?? 0))},${-h / 2 + (node.padding ?? 0) / 2 - (bbox.y - (bbox.top ?? 0))})` + ); + + updateNodeBounds(node, curlyBraceRightShape); + + node.intersect = function (point) { + const pos = intersect.polygon(node, rectPoints, point); + + return pos; + }; + + return shapeSvg; +}; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts index ea294e862..384c05e8a 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/curlyBraces.ts @@ -31,7 +31,7 @@ function generateCirclePoints( const angle = startAngleRad + i * angleStep; const x = centerX + radius * Math.cos(angle); const y = centerY + radius * Math.sin(angle); - points.push({ x, y }); + points.push({ x: -x, y: -y }); } return points; @@ -43,30 +43,45 @@ export const curlyBraces = async (parent: SVGAElement, node: Node) => { const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node)); const w = bbox.width + (node.padding ?? 0); const h = bbox.height + (node.padding ?? 0); - const radius = w * 0.05; + const radius = Math.max(5, h * 0.1); const { cssStyles } = node; - const points = [ - ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), - { x: w / 2 + radius, y: -radius }, - ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270), - ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180), - { x: w / 2 + radius, y: h / 2 }, + const leftCurlyBracePoints = [ + ...generateCirclePoints(w / 2, -h / 2, radius, 30, -90, 0), + { x: -w / 2 - radius, y: radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: -h / 2 }, ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), ]; + const rightCurlyBracePoints = [ + ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180), + { x: w / 2 - radius / 2, y: radius }, + ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90), + ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0), + { x: w / 2 - radius / 2, y: -radius }, + ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270), + ]; + const rectPoints = [ - { x: -w / 2, y: -h / 2 - radius }, { x: w / 2, y: -h / 2 - radius }, + { x: -w / 2, y: -h / 2 - radius }, ...generateCirclePoints(w / 2, -h / 2, radius, 20, -90, 0), - { x: w / 2 + radius, y: -radius }, - ...generateCirclePoints(w / 2 + w * 0.1, -radius, radius, 20, -180, -270), - ...generateCirclePoints(w / 2 + w * 0.1, radius, radius, 20, -90, -180), - { x: w / 2 + radius, y: h / 2 }, + { x: -w / 2 - radius, y: -radius }, + ...generateCirclePoints(w / 2 + radius * 2, -radius, radius, 20, -180, -270), + ...generateCirclePoints(w / 2 + radius * 2, radius, radius, 20, -90, -180), + { x: -w / 2 - radius, y: h / 2 }, ...generateCirclePoints(w / 2, h / 2, radius, 20, 0, 90), - { x: w / 2, y: h / 2 + radius }, { x: -w / 2, y: h / 2 + radius }, + { x: w / 2 - radius - radius / 2, y: h / 2 + radius }, + ...generateCirclePoints(-w / 2 + radius + radius / 2, -h / 2, radius, 20, -90, -180), + { x: w / 2 - radius / 2, y: radius }, + ...generateCirclePoints(-w / 2 - radius / 2, -radius, radius, 20, 0, 90), + ...generateCirclePoints(-w / 2 - radius / 2, radius, radius, 20, -90, 0), + { x: w / 2 - radius / 2, y: -radius }, + ...generateCirclePoints(-w / 2 + radius + radius / 2, h / 2, radius, 30, -180, -270), ]; // @ts-ignore - rough is not typed @@ -77,32 +92,36 @@ export const curlyBraces = async (parent: SVGAElement, node: Node) => { options.roughness = 0; options.fillStyle = 'solid'; } - const bowTieRectPath = createPathFromPoints(points); - const newCurlyBracePath = bowTieRectPath.replace('Z', ''); - const curlyBracePath = rc.path(newCurlyBracePath, options); + const leftCurlyBracePath = createPathFromPoints(leftCurlyBracePoints); + const newLeftCurlyBracePath = leftCurlyBracePath.replace('Z', ''); + const leftCurlyBraceNode = rc.path(newLeftCurlyBracePath, options); + const rightCurlyBracePath = createPathFromPoints(rightCurlyBracePoints); + const newRightCurlyBracePath = rightCurlyBracePath.replace('Z', ''); + const rightCurlyBraceNode = rc.path(newRightCurlyBracePath, options); const rectPath = createPathFromPoints(rectPoints); const rectShape = rc.path(rectPath, { ...options }); - const bowTieRectShape = shapeSvg.insert('g', ':first-child'); - bowTieRectShape.insert(() => rectShape, ':first-child').attr('stroke-opacity', 0); - bowTieRectShape.insert(() => curlyBracePath, ':first-child'); - bowTieRectShape.attr('class', 'text'); + const curlyBracesShape = shapeSvg.insert('g', ':first-child'); + curlyBracesShape.insert(() => rectShape, ':first-child').attr('stroke-opacity', 0); + curlyBracesShape.insert(() => leftCurlyBraceNode, ':first-child'); + curlyBracesShape.insert(() => rightCurlyBraceNode, ':first-child'); + curlyBracesShape.attr('class', 'text'); if (cssStyles && node.look !== 'handDrawn') { - bowTieRectShape.selectAll('path').attr('style', cssStyles); + curlyBracesShape.selectAll('path').attr('style', cssStyles); } if (nodeStyles && node.look !== 'handDrawn') { - bowTieRectShape.selectAll('path').attr('style', nodeStyles); + curlyBracesShape.selectAll('path').attr('style', nodeStyles); } - bowTieRectShape.attr('transform', `translate(${-radius}, 0)`); + curlyBracesShape.attr('transform', `translate(${radius - radius / 4}, 0)`); label.attr( 'transform', - `translate(${-w / 2 - (bbox.x - (bbox.left ?? 0))},${-h / 2 + (node.padding ?? 0) / 2 - (bbox.y - (bbox.top ?? 0))})` + `translate(${-w / 2 + (node.padding ?? 0) / 2 - (bbox.x - (bbox.left ?? 0))},${-h / 2 + (node.padding ?? 0) / 2 - (bbox.y - (bbox.top ?? 0))})` ); - updateNodeBounds(node, bowTieRectShape); + updateNodeBounds(node, curlyBracesShape); node.intersect = function (point) { const pos = intersect.polygon(node, rectPoints, point); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts index bf39b4bab..78a373f7b 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/filledCircle.ts @@ -5,6 +5,7 @@ import type { SVG } from '$root/diagram-api/types.js'; import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; import rough from 'roughjs'; import intersect from '../intersect/index.js'; +import { getConfig } from '$root/config.js'; export const filledCircle = (parent: SVG, node: Node) => { node.label = ''; @@ -17,20 +18,21 @@ export const filledCircle = (parent: SVG, node: Node) => { // @ts-ignore - rough is not typed const rc = rough.svg(shapeSvg); - const options = userNodeOverrides(node, {}); + const { themeVariables } = getConfig(); + const { nodeBorder } = themeVariables; + const options = userNodeOverrides(node, { fillStyle: 'solid' }); if (node.look !== 'handDrawn') { options.roughness = 0; - options.fillStyle = 'solid'; } const circleNode = rc.circle(0, 0, radius * 2, options); const filledCircle = shapeSvg.insert(() => circleNode, ':first-child'); - filledCircle.attr('class', 'basic label-container'); + filledCircle.selectAll('path').attr('style', `fill: ${nodeBorder} !important;`); - if (cssStyles && node.look !== 'handDrawn') { + if (cssStyles && cssStyles.length > 0 && node.look !== 'handDrawn') { filledCircle.selectAll('path').attr('style', cssStyles); } diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/hourglass.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/hourglass.ts index cf2c2ef89..aeeb1607c 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/hourglass.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/hourglass.ts @@ -8,8 +8,10 @@ import rough from 'roughjs'; export const hourglass = async (parent: SVGAElement, node: Node) => { node.label = ''; const { shapeSvg } = await labelHelper(parent, node, getNodeClasses(node)); - const w = 100; - const h = 100; + + const w = Math.max(30, node?.width ?? 0); + const h = Math.max(30, node?.height ?? 0); + const { cssStyles } = node; // @ts-ignore - rough is not typed const rc = rough.svg(shapeSvg); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/lightningBolt.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/lightningBolt.ts index e1b6a31f1..8dee6de78 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/lightningBolt.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/lightningBolt.ts @@ -13,9 +13,9 @@ export const lightningBolt = (parent: SVG, node: Node) => { .attr('class', getNodeClasses(node)) .attr('id', node.domId ?? node.id); const { cssStyles } = node; - const height = 80; - const width = 80; - const gap = 16; + const width = Math.max(35, node?.width ?? 0); + const height = Math.max(35, node?.height ?? 0); + const gap = 7; const points = [ { x: width, y: 0 }, diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/linedCylinder.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/linedCylinder.ts index 25fffbf9c..04f403e6a 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/linedCylinder.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/linedCylinder.ts @@ -97,7 +97,7 @@ export const linedCylinder = async (parent: SVGAElement, node: Node) => { Math.abs(pos.y - (node.y ?? 0)) > (node.height ?? 0) / 2 - ry)) ) { let y = ry * ry * (1 - (x * x) / (rx * rx)); - if (y != 0) { + if (y > 0) { y = Math.sqrt(y); } y = ry - y; diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/trapezoidalPentagon.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/trapezoidalPentagon.ts index 0f883d048..7bd9e620c 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/trapezoidalPentagon.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/trapezoidalPentagon.ts @@ -14,9 +14,11 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => { const nodePadding = node.padding ?? 0; const labelPaddingX = node.look === 'neo' ? nodePadding * 2 : nodePadding; const labelPaddingY = node.look === 'neo' ? nodePadding * 1 : nodePadding; - const widthMultiplier = bbox.width < 40 ? 3 : 1.25; - const w = Math.max((bbox.width + labelPaddingX) * widthMultiplier, node?.width ?? 0); - const h = Math.max(bbox.height + labelPaddingY, node?.height ?? 0); + + const minWidth = 60, + minHeight = 20; + const w = Math.max(minWidth, bbox.width + (labelPaddingX ?? 0) * 2, node?.width ?? 0); + const h = Math.max(minHeight, bbox.height + (labelPaddingY ?? 0) * 2, node?.height ?? 0); const { cssStyles } = node; // @ts-ignore - rough is not typed @@ -28,16 +30,13 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => { options.fillStyle = 'solid'; } - const topOffset = 30; - const slopeHeight = 15; - const points = [ - { x: topOffset, y: 0 }, - { x: w - topOffset, y: 0 }, - { x: w, y: slopeHeight }, - { x: w, y: h }, - { x: 0, y: h }, - { x: 0, y: slopeHeight }, + { x: (-w / 2) * 0.8, y: -h / 2 }, + { x: (w / 2) * 0.8, y: -h / 2 }, + { x: w / 2, y: (-h / 2) * 0.6 }, + { x: w / 2, y: h / 2 }, + { x: -w / 2, y: h / 2 }, + { x: -w / 2, y: (-h / 2) * 0.6 }, ]; const pathData = createPathFromPoints(points); @@ -54,8 +53,6 @@ export const trapezoidalPentagon = async (parent: SVGAElement, node: Node) => { polygon.selectChildren('path').attr('style', nodeStyles); } - polygon.attr('transform', `translate(${-w / 2}, ${-h / 2})`); - updateNodeBounds(node, polygon); node.intersect = function (point) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/triangle.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/triangle.ts index 2bb0f82f6..e6f1d9955 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/triangle.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/triangle.ts @@ -8,11 +8,14 @@ import { } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; import rough from 'roughjs'; import { createPathFromPoints } from './util.js'; +import { evaluate } from '$root/diagrams/common/common.js'; +import { getConfig } from '$root/diagram-api/diagramAPI.js'; export const triangle = async (parent: SVGAElement, node: Node): Promise => { const { labelStyles, nodeStyles } = styles2String(node); node.labelStyle = labelStyles; const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node)); + const useHtmlLabels = evaluate(getConfig().flowchart?.htmlLabels); const nodePadding = node.padding ?? 0; const labelPaddingX = node.look === 'neo' ? nodePadding * 2 : nodePadding; @@ -57,7 +60,7 @@ export const triangle = async (parent: SVGAElement, node: Node): Promise