Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: classDiagram relation direction, and add docs #245

Merged
merged 1 commit into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/fair-poems-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'pintora-demo': patch
'@pintora/diagrams': patch
'@pintora/test-shared': patch
'pintora-website': patch
---

fix: classDiagram relation direction, and add docs
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ jspm_packages/

# dotenv environment variables file
.env
.envrc


# End of https://www.gitignore.io/api/node
Expand Down
29 changes: 29 additions & 0 deletions demo/cypress/e2e/class/class.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { stripStartEmptyLines } from '@pintora/test-shared'
import { makeSnapshotCases } from '../test-utils/render'

describe('Class Diagram', () => {
makeSnapshotCases([
{
description: 'Should render class diagram example',
code: stripStartEmptyLines(`
classDiagram
class Fruit {
float sweetness
-float age

float getAge()
}

class Apple {
}

%% There are so many kind of fruits
Fruit <|-- Apple
Fruit <|-- Kiwi
Fruit <|-- Banana

Container "1" *-- "many" Fruit : holds
`),
},
])
})
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ exports[`class parser can parse relationship between classes 1`] = `
"labelRight": null,
"left": "A1",
"relation": "INHERITANCE",
"reversed": true,
"right": "A2",
"type": "addRelation",
},
Expand All @@ -92,6 +93,7 @@ exports[`class parser can parse relationship between classes 1`] = `
"labelRight": null,
"left": "B1",
"relation": "COMPOSITION",
"reversed": true,
"right": "B2",
"type": "addRelation",
},
Expand All @@ -102,6 +104,7 @@ exports[`class parser can parse relationship between classes 1`] = `
"labelRight": null,
"left": "C1",
"relation": "AGGREGATION",
"reversed": true,
"right": "C2",
"type": "addRelation",
},
Expand All @@ -112,6 +115,7 @@ exports[`class parser can parse relationship between classes 1`] = `
"labelRight": null,
"left": "D1",
"relation": "ASSOCIATION",
"reversed": false,
"right": "D2",
"type": "addRelation",
},
Expand Down
19 changes: 12 additions & 7 deletions packages/pintora-diagrams/src/class/artist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,14 @@ class ClassDiagramDraw {
fontFamily: conf.fontFamily,
}

const startNodeId = r.reversed ? r.right : r.left
const ednNodeId = r.reversed ? r.left : r.right

let minlen = 1
if (r.label) {
labelDims = calculateTextDimensions(r.label, fontConfig)
minlen = Math.ceil(labelDims.height / conf.ranksep) + 1
const startNode = g.node(r.left)
const startNode = g.node(startNodeId)
const extraPad = (labelDims.width - startNode.width) / 2
if (extraPad > 0) {
// so label won't overlap
Expand Down Expand Up @@ -180,8 +183,10 @@ class ClassDiagramDraw {
})
relationGroupMark.children.push(rightLabelMark)
}
const startLabelMark = r.reversed ? rightLabelMark : leftLabelMark
const endLabelMark = r.reversed ? leftLabelMark : rightLabelMark

g.setEdge(r.left, r.right, {
g.setEdge(startNodeId, ednNodeId, {
label: r.relation,
minlen,
onLayout: (data: BaseEdgeData) => {
Expand Down Expand Up @@ -235,13 +240,13 @@ class ClassDiagramDraw {

// draw label beside intersection of node and line
const LABEL_X_OFFSET = 5
if (leftLabelMark) {
if (startLabelMark) {
const startIntersectionPoint = data.points[2]
safeAssign(leftLabelMark.attrs, movePointPosition(startIntersectionPoint, { x: LABEL_X_OFFSET, y: 0 }))
safeAssign(startLabelMark.attrs, movePointPosition(startIntersectionPoint, { x: LABEL_X_OFFSET, y: 0 }))
}

if (rightLabelMark) {
safeAssign(rightLabelMark.attrs, movePointPosition(lastPoint, { x: LABEL_X_OFFSET, y: 0 }))
if (endLabelMark) {
safeAssign(endLabelMark.attrs, movePointPosition(lastPoint, { x: LABEL_X_OFFSET, y: 0 }))
}
},
})
Expand Down Expand Up @@ -273,7 +278,7 @@ type EntitySection = {
*/
class EntityMarkBuilder {
group: Group = makeEmptyGroup()
rowPadding = 5
rowPadding = 8
/** y offset inside entity */
curY = 0
curHeight = 0
Expand Down
4 changes: 4 additions & 0 deletions packages/pintora-diagrams/src/class/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export type ClassRelation = {
labelLeft?: string
labelRight?: string
dashed?: boolean
/**
* normally we draw the relation from left to right, if reversed is true, we draw the relation from right to left
*/
reversed?: boolean
}

type Access = 'public' | 'private' | 'protected'
Expand Down
25 changes: 16 additions & 9 deletions packages/pintora-diagrams/src/class/parser/classDiagram.ne
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ memberLabelStatement ->
relationStatement ->
classInRelation textInQuote:? relation textInQuote:? classInRelation (%WS:* %COLON %WS:* words):? {%
function(d) {
let relationRaw = { type: d[2], dashed: false }
let relationRaw = { type: d[2], dashed: false, reversed: false }
let labelLeft = d[1]
let labelRight = d[3]
if (d[2].type) {
Expand All @@ -207,6 +207,7 @@ relationStatement ->
labelRight,
label,
dashed: Boolean(relationRaw.dashed),
reversed: Boolean(relationRaw.reversed)
} as Action
}
%}
Expand All @@ -215,16 +216,22 @@ classInRelation ->
%VALID_TEXT {% (d) => ({ name: tv(d[0])}) %}

relation ->
"<|--" {% (d) => { return { type: Relation.INHERITANCE } } %}
| "<|.." {% (d) => { return { type: Relation.INHERITANCE, dashed: true } } %}
| "*--" {% (d) => { return { type: Relation.COMPOSITION } } %}
| "*.." {% (d) => { return { type: Relation.COMPOSITION, dashed: true } } %}
| "o--" {% (d) => { return { type: Relation.AGGREGATION } } %}
| "o.." {% (d) => { return { type: Relation.AGGREGATION, dashed: true } } %}
"<|--" {% (d) => { return { type: Relation.INHERITANCE, reversed: true } } %}
| "<|.." {% (d) => { return { type: Relation.INHERITANCE, reversed: true, dashed: true } } %}
| "--|>" {% (d) => { return { type: Relation.INHERITANCE } } %}
| "..|>" {% (d) => { return { type: Relation.INHERITANCE, dashed: true } } %}
| "*--" {% (d) => { return { type: Relation.COMPOSITION, reversed: true } } %}
| "*.." {% (d) => { return { type: Relation.COMPOSITION, reversed: true, dashed: true } } %}
| "--*" {% (d) => { return { type: Relation.COMPOSITION } } %}
| "..*" {% (d) => { return { type: Relation.COMPOSITION, dashed: true } } %}
| "o--" {% (d) => { return { type: Relation.AGGREGATION, reversed: true } } %}
| "o.." {% (d) => { return { type: Relation.AGGREGATION, reversed: true, dashed: true } } %}
| "--o" {% (d) => { return { type: Relation.AGGREGATION } } %}
| "..o" {% (d) => { return { type: Relation.AGGREGATION, dashed: true } } %}
| "-->" {% (d) => { return { type: Relation.ASSOCIATION } } %}
| "..>" {% (d) => { return { type: Relation.ASSOCIATION, dashed: true } } %}
| "<--" {% (d) => { return { type: Relation.ASSOCIATION } } %}
| "<.." {% (d) => { return { type: Relation.ASSOCIATION } } %}
| "<--" {% (d) => { return { type: Relation.ASSOCIATION, reversed: true } } %}
| "<.." {% (d) => { return { type: Relation.ASSOCIATION, reversed: true, dashed: true } } %}
| "--" {% (d) => { return { type: Relation.LINK } } %}
| ".." {% (d) => { return { type: Relation.LINK, dashed: true } } %}

Expand Down
21 changes: 14 additions & 7 deletions packages/test-shared/src/data/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,17 +327,24 @@ export const classExample: DiagramExample = {
description: 'Sample for a classDiagram',
code: stripStartEmptyLines(`
classDiagram
class Fruit {
<<interface>>
float sweetness
-float age

class Fruit {
float sweetness
}
float getAge()
}

class Apple {
}
class Apple {
float softness
{static} Apple fromString(str)
}

Fruit <|-- Apple
%% There are so many kind of fruits
Fruit <|-- Apple
Fruit <|-- Banana

Container "1" *-- "many" Fruit : holds
Fruit "many" --* "1" Bag: packed into
`),
}

Expand Down
31 changes: 31 additions & 0 deletions website/docs/configuration/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,37 @@ export type DOTConf = {
}
```

### class

Config for class diagram. For more detail, check the [latest code](https://github.com/hikerpig/pintora/blob/master/packages/pintora-diagrams/src/class/config.ts).

```ts
export type ClassConf = {
diagramPadding: number

layoutDirection: string
ranksep: number
nodesep: number
edgesep: number
edgeType: EdgeType

entityBackground: string
entityBorderColor: string
entityBodyBackground: string
entityTextColor: string
labelBackground: string
relationLineColor: string
relationTextColor: string

entityRadius: number

fontSize: number
fontWeight: MarkAttrs['fontWeight']
fontFamily: string
}
```


## Override config by directive

If you don't have the access to add JS script into the page or in the Node.js module, it's also possible to override some configs of the builtin diagrams through the `@param` or `@config` directive.
Expand Down
54 changes: 51 additions & 3 deletions website/docs/diagrams/class-diagram.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ title: Class Diagram

```pintora play
classDiagram

class Fruit {
<<interface>>
float sweetness
-float age

float getAge()
}

class Apple {
float softness
{static} Apple fromString(str)
}

%% There are so many kind of fruits
Fruit <|-- Apple
Fruit <|-- Kiwi
Fruit <|-- Banana

Container "1" *-- "many" Fruit : holds
Fruit "many" --* "1" Bag: packed into
```

## Define a class
Expand Down Expand Up @@ -58,6 +62,30 @@ Define member visibility with these symbols. The notaiton is optional but it sho
- `-` private
- `~` package/internal

## Class annotations

You can annotate classes with markers to provide additional metadata about the class. This can give a clearer indication about its nature. Some common annotations include:

- `<<interface>>` To represent an interface class
- `<<enumeration>>` To represent an enum

Annotations are defined within the opening `<<` and closing `>>`. There are two ways to add an annotation to a class:

```pintora play
classDiagram
class Shape
<<interface>> Shape
Shape : vertices
Shape : draw()

class Color {
<<enumeration>>
Red
Green
Blue
}
```

## Relations between classes

You can define relations between classes using following symbols :
Expand Down Expand Up @@ -86,7 +114,7 @@ classO .. classP

### Label on relations

It is possible to add a label on the relation, using `:`, followed by the text of the label.
You can add a label on the relation, using `:`, followed by the text of the label.

Also, you can use double-quotes `""` on each side of the relation for cardinality.

Expand All @@ -96,3 +124,23 @@ classDiagram
classC o-- classD : aggregation
classE --> "1" classF
```

## Override config

You can override diagarm config through `@param` directive.

All available configs can be seen in the [Config page](../configuration/config.md#class).

```pintora play
classDiagram
@param entityBackground #61afef

class Animal {
}

class Dog {
void bark()
}

Animal <|-- Dog
```
Loading