mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 06:19:24 +02:00
Merge branch 'develop' into 6638-sequence-diagram-additional-messages
This commit is contained in:
5
.changeset/chatty-lemons-stick.md
Normal file
5
.changeset/chatty-lemons-stick.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
chore: Remove the "-beta" suffix from the XYChart, Block, Sankey diagrams to reflect their stable status
|
5
.changeset/cold-sites-accept.md
Normal file
5
.changeset/cold-sites-accept.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Position the edge label in state diagram correctly relative to the edge
|
5
.changeset/empty-clouds-cry.md
Normal file
5
.changeset/empty-clouds-cry.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Apply correct dateFormat in Gantt chart to show only day when specified
|
5
.changeset/fuzzy-pears-cough.md
Normal file
5
.changeset/fuzzy-pears-cough.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: handle exclude dates properly in Gantt charts when using dateFormat: 'YYYY-MM-DD HH:mm:ss'
|
5
.changeset/gold-spiders-join.md
Normal file
5
.changeset/gold-spiders-join.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: fixed connection gaps in flowchart for roundedRect, stadium and diamond shape
|
9
.changeset/seven-papayas-film.md
Normal file
9
.changeset/seven-papayas-film.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
Add validation for negative values in pie charts:
|
||||
|
||||
Prevents crashes during parsing by validating values post-parsing.
|
||||
|
||||
Provides clearer, user-friendly error messages for invalid negative inputs.
|
5
.changeset/six-planets-rescue.md
Normal file
5
.changeset/six-planets-rescue.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: node border style for handdrawn shapes
|
5
.changeset/strong-dryers-pay.md
Normal file
5
.changeset/strong-dryers-pay.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: correctly render non-directional lines for '---' in block diagrams
|
2
.github/workflows/e2e-timings.yml
vendored
2
.github/workflows/e2e-timings.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and create pull request
|
||||
uses: peter-evans/create-pull-request@07cbaebb4bfc9c5d7db426ea5a5f585df29dd0a0
|
||||
uses: peter-evans/create-pull-request@1310d7dab503600742045e6fd4b84dda64352858
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
|
@@ -16,7 +16,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL2: should handle columns statement in sub-blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
id1["Hello"]
|
||||
block
|
||||
columns 3
|
||||
@@ -32,7 +32,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL3: should align block widths and handle columns statement in sub-blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
block
|
||||
columns 1
|
||||
id1
|
||||
@@ -48,7 +48,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL4: should align block widths and handle columns statements in deeper sub-blocks then 1 level', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 1
|
||||
block
|
||||
columns 1
|
||||
@@ -68,7 +68,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL5: should align block widths and handle columns statements in deeper sub-blocks then 1 level (alt)', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 1
|
||||
block
|
||||
id1
|
||||
@@ -87,7 +87,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL6: should handle block arrows and spece statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
space:3
|
||||
ida idb idc
|
||||
@@ -106,7 +106,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL7: should handle different types of edges', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
A space:5
|
||||
A --o B
|
||||
@@ -119,7 +119,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL8: should handle sub-blocks without columns statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 2
|
||||
C A B
|
||||
block
|
||||
@@ -133,7 +133,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
B space
|
||||
block
|
||||
@@ -147,7 +147,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL10: should handle edges from composite blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
B space
|
||||
block BL
|
||||
@@ -161,7 +161,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL11: should handle edges to composite blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
B space
|
||||
block BL
|
||||
@@ -175,7 +175,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL12: edges should handle labels', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A
|
||||
space
|
||||
A -- "apa" --> E
|
||||
@@ -186,7 +186,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL13: should handle block arrows in different directions', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
space blockArrowId1<["down"]>(down) space
|
||||
blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
|
||||
@@ -199,7 +199,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL14: should style statements and class statements', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A
|
||||
B
|
||||
classDef blue fill:#66f,stroke:#333,stroke-width:2px;
|
||||
@@ -212,7 +212,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL15: width alignment - D and E should share available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
block
|
||||
D
|
||||
E
|
||||
@@ -225,7 +225,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL16: width alignment - C should be as wide as the composite block', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
block
|
||||
A("This is the text")
|
||||
B
|
||||
@@ -238,7 +238,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL17: width alignment - blocks should be equal in width', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A("This is the text")
|
||||
B
|
||||
C
|
||||
@@ -249,7 +249,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL18: block types 1 - square, rounded and circle', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A["square"]
|
||||
B("rounded")
|
||||
C(("circle"))
|
||||
@@ -260,7 +260,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL19: block types 2 - odd, diamond and hexagon', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A>"rect_left_inv_arrow"]
|
||||
B{"diamond"}
|
||||
C{{"hexagon"}}
|
||||
@@ -271,7 +271,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL20: block types 3 - stadium', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A(["stadium"])
|
||||
`,
|
||||
{}
|
||||
@@ -280,7 +280,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL21: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A[/"lean right"/]
|
||||
B[\"lean left"\]
|
||||
C[/"trapezoid"\]
|
||||
@@ -292,7 +292,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL22: block types 1 - square, rounded and circle', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A["square"]
|
||||
B("rounded")
|
||||
C(("circle"))
|
||||
@@ -303,7 +303,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL23: sizing - it should be possible to make a block wider', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
A("rounded"):2
|
||||
B:2
|
||||
C
|
||||
@@ -314,7 +314,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL24: sizing - it should be possible to make a composite block wider', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
block:2
|
||||
A
|
||||
end
|
||||
@@ -326,7 +326,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL25: block in the middle with space on each side', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
space
|
||||
middle["In the middle"]
|
||||
@@ -337,7 +337,7 @@ describe('Block diagram', () => {
|
||||
});
|
||||
it('BL26: space and an edge', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 5
|
||||
A space B
|
||||
A --x B
|
||||
@@ -347,7 +347,7 @@ describe('Block diagram', () => {
|
||||
});
|
||||
it('BL27: block sizes for regular blocks', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
a["A wide one"] b:2 c:2 d
|
||||
`,
|
||||
@@ -356,7 +356,7 @@ describe('Block diagram', () => {
|
||||
});
|
||||
it('BL28: composite block with a set width - f should use the available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
@@ -370,7 +370,7 @@ describe('Block diagram', () => {
|
||||
|
||||
it('BL29: composite block with a set width - f and g should split the available space', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
`block
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
@@ -393,6 +393,17 @@ describe('Block diagram', () => {
|
||||
overflow:3
|
||||
short:1
|
||||
also_overflow:2
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('BL31: edge without arrow syntax should render with no arrowheads', () => {
|
||||
imgSnapshotTest(
|
||||
`block-beta
|
||||
a
|
||||
b
|
||||
a --- b
|
||||
`,
|
||||
{}
|
||||
);
|
||||
|
@@ -1113,6 +1113,37 @@ end
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Flowchart Node Shape Rendering', () => {
|
||||
it('should render a stadium-shaped node', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TB
|
||||
A(["Start"]) --> n1["Untitled Node"]
|
||||
A --> n2["Untitled Node"]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render a diamond-shaped node using shape config', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart BT
|
||||
n2["Untitled Node"] --> n1["Diamond"]
|
||||
n1@{ shape: diam}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render a rounded rectangle and a normal rectangle', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart BT
|
||||
n2["Untitled Node"] --> n1["Rounded Rectangle"]
|
||||
n3["Untitled Node"] --> n1
|
||||
n1@{ shape: rounded}
|
||||
n3@{ shape: rect}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('6617: Per Link Curve Styling using edge Ids', () => {
|
||||
imgSnapshotTest(
|
||||
|
@@ -565,6 +565,18 @@ describe('Gantt diagram', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render only the day when using dateFormat D', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title Test
|
||||
dateFormat D
|
||||
A :a, 1, 1d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: fix it
|
||||
//
|
||||
// This test is skipped deliberately
|
||||
@@ -647,6 +659,49 @@ describe('Gantt diagram', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram excluding a specific date in YYYY-MM-DD HH:mm:ss format', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD HH:mm:ss
|
||||
excludes 2025-07-07
|
||||
section Section
|
||||
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||
Another task:after a1, 20h
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram excluding saturday and sunday in YYYY-MM-DD HH:mm:ss format', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD HH:mm:ss
|
||||
excludes weekends
|
||||
weekend saturday
|
||||
section Section
|
||||
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||
Another task:after a1, 20h
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render a gantt diagram excluding friday and saturday in YYYY-MM-DD HH:mm:ss format', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD HH:mm:ss
|
||||
excludes weekends
|
||||
weekend friday
|
||||
section Section
|
||||
A task :a1, 2025-07-04 20:30:30, 2025-07-08 10:30:30
|
||||
Another task:after a1, 20h
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a semicolon in the title", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
@@ -82,4 +82,13 @@ describe('pie chart', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render pie slices only for non-zero values but shows all legends', () => {
|
||||
imgSnapshotTest(
|
||||
` pie title Pets adopted by volunteers
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 1
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -15,7 +15,7 @@ describe('Sankey Diagram', () => {
|
||||
describe('when given a linkColor', function () {
|
||||
this.beforeAll(() => {
|
||||
cy.wrap(
|
||||
`sankey-beta
|
||||
`sankey
|
||||
a,b,10
|
||||
`
|
||||
).as('graph');
|
||||
@@ -62,7 +62,7 @@ describe('Sankey Diagram', () => {
|
||||
this.beforeAll(() => {
|
||||
cy.wrap(
|
||||
`
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
a,b,8
|
||||
b,c,8
|
||||
|
@@ -602,6 +602,231 @@ State1 --> [*]
|
||||
--
|
||||
55
|
||||
}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render edge labels correctly', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
title: On The Way To Something Something DarkSide
|
||||
config:
|
||||
look: default
|
||||
theme: default
|
||||
---
|
||||
|
||||
stateDiagram-v2
|
||||
|
||||
state State1_____________
|
||||
{
|
||||
c0
|
||||
}
|
||||
|
||||
state State2_____________
|
||||
{
|
||||
c1
|
||||
}
|
||||
|
||||
state State3_____________
|
||||
{
|
||||
c7
|
||||
}
|
||||
|
||||
state State4_____________
|
||||
{
|
||||
c2
|
||||
}
|
||||
|
||||
state State5_____________
|
||||
{
|
||||
c3
|
||||
}
|
||||
|
||||
state State6_____________
|
||||
{
|
||||
c4
|
||||
}
|
||||
|
||||
state State7_____________
|
||||
{
|
||||
c5
|
||||
}
|
||||
|
||||
state State8_____________
|
||||
{
|
||||
c6
|
||||
}
|
||||
|
||||
|
||||
[*] --> State1_____________
|
||||
State1_____________ --> State2_____________ : Transition1_____
|
||||
State2_____________ --> State4_____________ : Transition2_____
|
||||
State2_____________ --> State3_____________ : Transition3_____
|
||||
State3_____________ --> State2_____________
|
||||
State4_____________ --> State2_____________ : Transition5_____
|
||||
State4_____________ --> State5_____________ : Transition6_____
|
||||
State5_____________ --> State6_____________ : Transition7_____
|
||||
State6_____________ --> State4_____________ : Transition8_____
|
||||
State2_____________ --> State7_____________ : Transition4_____
|
||||
State4_____________ --> State7_____________ : Transition4_____
|
||||
State5_____________ --> State7_____________ : Transition4_____
|
||||
State6_____________ --> State7_____________ : Transition4_____
|
||||
State7_____________ --> State1_____________ : Transition9_____
|
||||
State5_____________ --> State8_____________ : Transition10____
|
||||
State8_____________ --> State5_____________ : Transition11____
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render edge labels correctly with multiple transitions', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
title: Multiple Transitions
|
||||
config:
|
||||
look: default
|
||||
theme: default
|
||||
---
|
||||
|
||||
stateDiagram-v2
|
||||
|
||||
state State1_____________
|
||||
{
|
||||
c0
|
||||
}
|
||||
|
||||
state State2_____________
|
||||
{
|
||||
c1
|
||||
}
|
||||
|
||||
state State3_____________
|
||||
{
|
||||
c7
|
||||
}
|
||||
|
||||
state State4_____________
|
||||
{
|
||||
c2
|
||||
}
|
||||
|
||||
state State5_____________
|
||||
{
|
||||
c3
|
||||
}
|
||||
|
||||
state State6_____________
|
||||
{
|
||||
c4
|
||||
}
|
||||
|
||||
state State7_____________
|
||||
{
|
||||
c5
|
||||
}
|
||||
|
||||
state State8_____________
|
||||
{
|
||||
c6
|
||||
}
|
||||
|
||||
state State9_____________
|
||||
{
|
||||
c9
|
||||
}
|
||||
|
||||
[*] --> State1_____________
|
||||
State1_____________ --> State2_____________ : Transition1_____
|
||||
State2_____________ --> State4_____________ : Transition2_____
|
||||
State2_____________ --> State3_____________ : Transition3_____
|
||||
State3_____________ --> State2_____________
|
||||
State4_____________ --> State2_____________ : Transition5_____
|
||||
State4_____________ --> State5_____________ : Transition6_____
|
||||
State5_____________ --> State6_____________ : Transition7_____
|
||||
State6_____________ --> State4_____________ : Transition8_____
|
||||
State2_____________ --> State7_____________ : Transition4_____
|
||||
State4_____________ --> State7_____________ : Transition4_____
|
||||
State5_____________ --> State7_____________ : Transition4_____
|
||||
State6_____________ --> State7_____________ : Transition4_____
|
||||
State7_____________ --> State1_____________ : Transition9_____
|
||||
State5_____________ --> State8_____________ : Transition10____
|
||||
State8_____________ --> State5_____________ : Transition11____
|
||||
State9_____________ --> State8_____________ : Transition12____
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render edge labels correctly with multiple states', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
title: Multiple States
|
||||
config:
|
||||
look: default
|
||||
theme: default
|
||||
---
|
||||
|
||||
stateDiagram-v2
|
||||
|
||||
state State1_____________
|
||||
{
|
||||
c0
|
||||
}
|
||||
|
||||
state State2_____________
|
||||
{
|
||||
c1
|
||||
}
|
||||
|
||||
state State3_____________
|
||||
{
|
||||
c7
|
||||
}
|
||||
|
||||
state State4_____________
|
||||
{
|
||||
c2
|
||||
}
|
||||
|
||||
state State5_____________
|
||||
{
|
||||
c3
|
||||
}
|
||||
|
||||
state State6_____________
|
||||
{
|
||||
c4
|
||||
}
|
||||
|
||||
state State7_____________
|
||||
{
|
||||
c5
|
||||
}
|
||||
|
||||
state State8_____________
|
||||
{
|
||||
c6
|
||||
}
|
||||
|
||||
state State9_____________
|
||||
{
|
||||
c9
|
||||
}
|
||||
|
||||
state State10_____________
|
||||
{
|
||||
c10
|
||||
}
|
||||
|
||||
[*] --> State1_____________
|
||||
State1_____________ --> State2_____________ : Transition1_____
|
||||
State2_____________ --> State3_____________ : Transition2_____
|
||||
State3_____________ --> State4_____________ : Transition3_____
|
||||
State4_____________ --> State5_____________ : Transition4_____
|
||||
State5_____________ --> State6_____________ : Transition5_____
|
||||
State6_____________ --> State7_____________ : Transition6_____
|
||||
State7_____________ --> State8_____________ : Transition7_____
|
||||
State8_____________ --> State9_____________ : Transition8_____
|
||||
State9_____________ --> State10_____________ : Transition9_____
|
||||
`,
|
||||
{}
|
||||
);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe('XY Chart', () => {
|
||||
it('should render the simplest possible chart', () => {
|
||||
it('should render the simplest possible xy-beta chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
@@ -10,10 +10,19 @@ describe('XY Chart', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render the simplest possible xy chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart
|
||||
line [10, 30, 20]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should render a complete chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -26,7 +35,7 @@ describe('XY Chart', () => {
|
||||
it('Should render a chart without title', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
@@ -38,7 +47,7 @@ describe('XY Chart', () => {
|
||||
it('y-axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis 4000 --> 11000
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
@@ -50,7 +59,7 @@ describe('XY Chart', () => {
|
||||
it('Should render a chart without y-axis with different range', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
|
||||
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
|
||||
@@ -61,7 +70,7 @@ describe('XY Chart', () => {
|
||||
it('x axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 14000, 3200, 9200, 9900, 3400, 6000]
|
||||
line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
|
||||
@@ -72,7 +81,7 @@ describe('XY Chart', () => {
|
||||
it('Multiple plots can be rendered', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
line [23, 46, 77, 34]
|
||||
line [45, 32, 33, 12]
|
||||
bar [87, 54, 99, 85]
|
||||
@@ -86,7 +95,7 @@ describe('XY Chart', () => {
|
||||
it('Decimals and negative numbers are supported', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
y-axis -2.4 --> 3.5
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
`,
|
||||
@@ -104,7 +113,7 @@ describe('XY Chart', () => {
|
||||
height: 20
|
||||
plotReservedSpacePercent: 100
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
`,
|
||||
{}
|
||||
@@ -130,7 +139,7 @@ describe('XY Chart', () => {
|
||||
showTick: false
|
||||
showAxisLine: false
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
`,
|
||||
{}
|
||||
@@ -140,7 +149,7 @@ describe('XY Chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"xyChart": {"width": 1000, "height": 600, "titlePadding": 5, "titleFontSize": 10, "xAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "yAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "plotBorderWidth": 5, "chartOrientation": "horizontal", "plotReservedSpacePercent": 60 }}}%%
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -181,7 +190,7 @@ describe('XY Chart', () => {
|
||||
plotReservedSpacePercent: 60
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -202,7 +211,7 @@ describe('XY Chart', () => {
|
||||
yAxis:
|
||||
showTitle: false
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -223,7 +232,7 @@ describe('XY Chart', () => {
|
||||
yAxis:
|
||||
showLabel: false
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -244,7 +253,7 @@ describe('XY Chart', () => {
|
||||
yAxis:
|
||||
showTick: false
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -265,7 +274,7 @@ describe('XY Chart', () => {
|
||||
yAxis:
|
||||
showAxisLine: false
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -294,7 +303,7 @@ describe('XY Chart', () => {
|
||||
xAxisLineColor: "#87ceeb"
|
||||
plotColorPalette: "#008000, #faba63"
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -307,7 +316,7 @@ describe('XY Chart', () => {
|
||||
it('should use the correct distances between data points', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
x-axis 0 --> 2
|
||||
line [0, 1, 0, 1]
|
||||
bar [1, 0, 1, 0]
|
||||
@@ -325,7 +334,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -344,7 +353,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -357,7 +366,7 @@ describe('XY Chart', () => {
|
||||
it('should render vertical bar chart without labels by default', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -375,7 +384,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -393,7 +402,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Multiple Bar Plots"
|
||||
x-axis Categories [A, B, C]
|
||||
y-axis "Values" 0 --> 100
|
||||
@@ -412,7 +421,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Multiple Bar Plots"
|
||||
x-axis Categories [A, B, C]
|
||||
y-axis "Values" 0 --> 100
|
||||
@@ -430,7 +439,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Single Bar Chart"
|
||||
x-axis Categories [A]
|
||||
y-axis "Value" 0 --> 100
|
||||
@@ -449,7 +458,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Single Bar Chart"
|
||||
x-axis Categories [A]
|
||||
y-axis "Value" 0 --> 100
|
||||
@@ -467,7 +476,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Decimal and Negative Values"
|
||||
x-axis Categories [A, B, C]
|
||||
y-axis -10 --> 10
|
||||
@@ -486,7 +495,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Decimal and Negative Values"
|
||||
x-axis Categories [A, B, C]
|
||||
y-axis -10 --> 10
|
||||
@@ -504,7 +513,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan,b,c]
|
||||
y-axis "Revenue (in $)" 4000 --> 12000
|
||||
@@ -561,7 +570,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan,b,c]
|
||||
y-axis "Revenue (in $)" 4000 --> 12000
|
||||
@@ -615,7 +624,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s]
|
||||
y-axis "Revenue (in $)" 4000 --> 12000
|
||||
@@ -672,7 +681,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s]
|
||||
y-axis "Revenue (in $)" 4000 --> 12000
|
||||
@@ -726,7 +735,7 @@ describe('XY Chart', () => {
|
||||
xyChart:
|
||||
showDataLabel: true
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan]
|
||||
y-axis "Revenue (in $)" 3000 --> 12000
|
||||
@@ -783,7 +792,7 @@ describe('XY Chart', () => {
|
||||
showDataLabel: true
|
||||
chartOrientation: horizontal
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan]
|
||||
y-axis "Revenue (in $)" 3000 --> 12000
|
||||
|
35
cypress/platform/darshan.html
Normal file
35
cypress/platform/darshan.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Pie chart demos</h1>
|
||||
<pre class="mermaid">
|
||||
pie title Default text position: Animal adoption
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"dogs" : -60.67
|
||||
"rats" : 40.12
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -10,7 +10,7 @@
|
||||
<body>
|
||||
<h1>Block diagram demos</h1>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -26,7 +26,7 @@ columns 1
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
A1["square"]
|
||||
B1("rounded")
|
||||
C1(("circle"))
|
||||
@@ -36,7 +36,7 @@ block-beta
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
A1(["stadium"])
|
||||
A2[["subroutine"]]
|
||||
B1[("cylinder")]
|
||||
@@ -48,7 +48,7 @@ block-beta
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
@@ -57,7 +57,7 @@ block-beta
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
block:e:4
|
||||
columns 2
|
||||
f
|
||||
@@ -67,7 +67,7 @@ block-beta
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a:3
|
||||
block:e:3
|
||||
@@ -80,7 +80,7 @@ block-beta
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 4
|
||||
a b c d
|
||||
block:e:4
|
||||
@@ -97,19 +97,19 @@ flowchart LR
|
||||
X-- "a label" -->z
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 5
|
||||
A space B
|
||||
A --x B
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a["A wide one"] b:2 c:2 d
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a b c
|
||||
e:3
|
||||
@@ -117,7 +117,7 @@ columns 3
|
||||
</pre>
|
||||
|
||||
<pre id="diagram" class="mermaid">
|
||||
block-beta
|
||||
block
|
||||
|
||||
A1:3
|
||||
A2:1
|
||||
|
@@ -20,12 +20,14 @@
|
||||
width: 800
|
||||
nodeAlignment: left
|
||||
---
|
||||
sankey-beta
|
||||
Revenue,Expenses,10
|
||||
Revenue,Profit,10
|
||||
Expenses,Manufacturing,5
|
||||
Expenses,Tax,3
|
||||
Expenses,Research,2
|
||||
sankey
|
||||
a,b,8
|
||||
b,c,8
|
||||
c,d,8
|
||||
d,e,8
|
||||
|
||||
x,c,4
|
||||
c,y,4
|
||||
</pre>
|
||||
|
||||
<h2>Energy flow</h2>
|
||||
@@ -40,7 +42,7 @@
|
||||
linkColor: gradient
|
||||
nodeAlignment: justify
|
||||
---
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Agricultural 'waste',Bio-conversion,124.729
|
||||
Bio-conversion,Liquid,0.597
|
||||
|
@@ -16,7 +16,7 @@
|
||||
<body>
|
||||
<h1>XY Charts demos</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue (in $)"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -26,7 +26,7 @@
|
||||
<hr />
|
||||
<h1>XY Charts horizontal</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta horizontal
|
||||
xychart horizontal
|
||||
title "Basic xychart"
|
||||
x-axis "this is x axis" [category1, "category 2", category3, category4]
|
||||
y-axis yaxisText 10 --> 150
|
||||
@@ -36,7 +36,7 @@
|
||||
<hr />
|
||||
<h1>XY Charts only lines and bar</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
line [23, 46, 77, 34]
|
||||
line [45, 32, 33, 12]
|
||||
line [87, 54, 99, 85]
|
||||
@@ -48,13 +48,13 @@
|
||||
<hr />
|
||||
<h1>XY Charts with +ve and -ve numbers</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts Bar with multiple category</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Basic xychart with many categories"
|
||||
x-axis "this is x axis" [category1, "category 2", category3, category4, category5, category6, category7]
|
||||
y-axis yaxisText 10 --> 150
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<h1>XY Charts line with multiple category</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Line chart with many category"
|
||||
x-axis "this is x axis" [category1, "category 2", category3, category4, category5, category6, category7]
|
||||
y-axis yaxisText 10 --> 150
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<h1>XY Charts category with large text</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Basic xychart with many categories with category overlap"
|
||||
x-axis "this is x axis" [category1, "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.", category3, category4, category5, category6, category7]
|
||||
y-axis yaxisText 10 --> 150
|
||||
@@ -89,7 +89,7 @@ config:
|
||||
height: 20
|
||||
plotReservedSpacePercent: 100
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
</pre>
|
||||
|
||||
@@ -103,7 +103,7 @@ config:
|
||||
height: 20
|
||||
plotReservedSpacePercent: 100
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
</pre>
|
||||
|
||||
@@ -136,7 +136,7 @@ config:
|
||||
chartOrientation: horizontal
|
||||
plotReservedSpacePercent: 60
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -162,7 +162,7 @@ config:
|
||||
xAxisLineColor: "#87ceeb"
|
||||
plotColorPalette: "#008000, #faba63"
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
|
@@ -9,7 +9,7 @@
|
||||
## Introduction to Block Diagrams
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -26,7 +26,7 @@ columns 1
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -80,12 +80,12 @@ At its core, a block diagram consists of blocks representing different entities
|
||||
To create a simple block diagram with three blocks labeled 'a', 'b', and 'c', the syntax is as follows:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
a b c
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
a b c
|
||||
```
|
||||
|
||||
@@ -101,13 +101,13 @@ While simple block diagrams are linear and straightforward, more complex systems
|
||||
In scenarios where you need to distribute blocks across multiple columns, you can specify the number of columns and arrange the blocks accordingly. Here's how to create a block diagram with three columns and four blocks, where the fourth block appears in a second row:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a b c d
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a b c d
|
||||
```
|
||||
@@ -130,13 +130,13 @@ In more complex diagrams, you may need blocks that span multiple columns to emph
|
||||
To create a block diagram where one block spans across two columns, you can specify the desired width for each block:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
@@ -153,7 +153,7 @@ Composite blocks, or blocks within blocks, are an advanced feature in Mermaid's
|
||||
Creating a composite block involves defining a parent block and then nesting other blocks within it. Here's how to define a composite block with nested elements:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
D
|
||||
end
|
||||
@@ -161,7 +161,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
D
|
||||
end
|
||||
@@ -180,7 +180,7 @@ Mermaid also allows for dynamic adjustment of column widths based on the content
|
||||
In diagrams with varying block sizes, Mermaid automatically adjusts the column widths to fit the largest block in each column. Here's an example:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a:3
|
||||
block:group1:2
|
||||
@@ -195,7 +195,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a:3
|
||||
block:group1:2
|
||||
@@ -215,7 +215,7 @@ This example demonstrates how Mermaid dynamically adjusts the width of the colum
|
||||
In scenarios where you need to stack blocks horizontally, you can use column width to accomplish the task. Blocks can be arranged vertically by putting them in a single column. Here is how you can create a block diagram in which 4 blocks are stacked on top of each other:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
columns 1
|
||||
a["A label"] b c d
|
||||
@@ -223,7 +223,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
columns 1
|
||||
a["A label"] b c d
|
||||
@@ -247,12 +247,12 @@ Mermaid supports a range of block shapes to suit different diagramming needs, fr
|
||||
To create a block with round edges, which can be used to represent a softer or more flexible component:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1("This is the text in the box")
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1("This is the text in the box")
|
||||
```
|
||||
|
||||
@@ -261,12 +261,12 @@ block-beta
|
||||
A stadium-shaped block, resembling an elongated circle, can be used for components that are process-oriented:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1(["This is the text in the box"])
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1(["This is the text in the box"])
|
||||
```
|
||||
|
||||
@@ -275,12 +275,12 @@ block-beta
|
||||
For representing subroutines or contained processes, a block with double vertical lines is useful:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[["This is the text in the box"]]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1[["This is the text in the box"]]
|
||||
```
|
||||
|
||||
@@ -289,12 +289,12 @@ block-beta
|
||||
The cylindrical shape is ideal for representing databases or storage components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[("Database")]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1[("Database")]
|
||||
```
|
||||
|
||||
@@ -303,12 +303,12 @@ block-beta
|
||||
A circle can be used for centralized or pivotal components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1(("This is the text in the circle"))
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1(("This is the text in the circle"))
|
||||
```
|
||||
|
||||
@@ -319,36 +319,36 @@ For decision points, use a rhombus, and for unique or specialized processes, asy
|
||||
**Asymmetric**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1>"This is the text in the box"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1>"This is the text in the box"]
|
||||
```
|
||||
|
||||
**Rhombus**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1{"This is the text in the box"}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1{"This is the text in the box"}
|
||||
```
|
||||
|
||||
**Hexagon**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1{{"This is the text in the box"}}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1{{"This is the text in the box"}}
|
||||
```
|
||||
|
||||
@@ -357,7 +357,7 @@ block-beta
|
||||
Parallelogram and trapezoid shapes are perfect for inputs/outputs and transitional processes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[/"This is the text in the box"/]
|
||||
id2[\"This is the text in the box"\]
|
||||
A[/"Christmas"\]
|
||||
@@ -365,7 +365,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1[/"This is the text in the box"/]
|
||||
id2[\"This is the text in the box"\]
|
||||
A[/"Christmas"\]
|
||||
@@ -377,12 +377,12 @@ block-beta
|
||||
For highlighting critical or high-priority components, a double circle can be effective:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1((("This is the text in the circle")))
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1((("This is the text in the circle")))
|
||||
```
|
||||
|
||||
@@ -395,7 +395,7 @@ Mermaid also offers unique shapes like block arrows and space blocks for directi
|
||||
Block arrows can visually indicate direction or flow within a process:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
@@ -406,7 +406,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
@@ -421,14 +421,14 @@ block-beta
|
||||
Space blocks can be used to create intentional empty spaces in the diagram, which is useful for layout and readability:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a space b
|
||||
c d e
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a space b
|
||||
c d e
|
||||
@@ -437,12 +437,12 @@ block-beta
|
||||
or
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
ida space:3 idb idc
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
ida space:3 idb idc
|
||||
```
|
||||
|
||||
@@ -467,13 +467,13 @@ The most fundamental aspect of connecting blocks is the use of arrows or links.
|
||||
A simple link with an arrow can be created to show direction or flow from one block to another:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
```
|
||||
@@ -490,13 +490,13 @@ Example - Text with Links
|
||||
To add text to a link, the syntax includes the text within the link definition:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space:2 B
|
||||
A-- "X" -->B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A space:2 B
|
||||
A-- "X" -->B
|
||||
```
|
||||
@@ -506,7 +506,7 @@ This example show how to add descriptive text to the links, enhancing the inform
|
||||
Example - Edges and Styles:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -523,7 +523,7 @@ columns 1
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -552,7 +552,7 @@ Mermaid enables detailed styling of individual blocks, allowing you to apply var
|
||||
To apply custom styles to a block, you can use the `style` keyword followed by the block identifier and the desired CSS properties:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1 space id2
|
||||
id1("Start")-->id2("Stop")
|
||||
style id1 fill:#636,stroke:#333,stroke-width:4px
|
||||
@@ -560,7 +560,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
id1 space id2
|
||||
id1("Start")-->id2("Stop")
|
||||
style id1 fill:#636,stroke:#333,stroke-width:4px
|
||||
@@ -574,7 +574,7 @@ Mermaid enables applying styling to classes, which could make styling easier if
|
||||
#### Example - Styling a Single Class
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
classDef blue fill:#6e6ce6,stroke:#333,stroke-width:4px;
|
||||
@@ -583,7 +583,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
classDef blue fill:#6e6ce6,stroke:#333,stroke-width:4px;
|
||||
@@ -608,7 +608,7 @@ Combining the elements of structure, linking, and styling, we can create compreh
|
||||
Illustrating a simple software system architecture with interconnected components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Frontend blockArrowId6<[" "]>(right) Backend
|
||||
space:2 down<[" "]>(down)
|
||||
@@ -621,7 +621,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Frontend blockArrowId6<[" "]>(right) Backend
|
||||
space:2 down<[" "]>(down)
|
||||
@@ -640,7 +640,7 @@ This example shows a basic architecture with a frontend, backend, and database.
|
||||
Representing a business process flow with decision points and multiple stages:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Start(("Start")) space:2
|
||||
down<[" "]>(down) space:2
|
||||
@@ -653,7 +653,7 @@ block-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Start(("Start")) space:2
|
||||
down<[" "]>(down) space:2
|
||||
@@ -682,7 +682,7 @@ Understanding and avoiding common syntax errors is key to a smooth experience wi
|
||||
A common mistake is incorrect linking syntax, which can lead to unexpected results or broken diagrams:
|
||||
|
||||
```
|
||||
block-beta
|
||||
block
|
||||
A - B
|
||||
```
|
||||
|
||||
@@ -690,13 +690,13 @@ block-beta
|
||||
Ensure that links between blocks are correctly specified with arrows (--> or ---) to define the direction and type of connection. Also remember that one of the fundamentals for block diagram is to give the author full control of where the boxes are positioned so in the example you need to add a space between the boxes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A --> B
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A --> B
|
||||
```
|
||||
@@ -706,13 +706,13 @@ block-beta
|
||||
Applying styles in the wrong context or with incorrect syntax can lead to blocks not being styled as intended:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill#969;
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill#969;
|
||||
```
|
||||
@@ -721,14 +721,14 @@ Applying styles in the wrong context or with incorrect syntax can lead to blocks
|
||||
Correct the syntax by ensuring proper separation of style properties with commas and using the correct CSS property format:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill:#969,stroke:#333;
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill:#969,stroke:#333;
|
||||
|
||||
|
@@ -37,6 +37,11 @@ Drawing a pie chart is really simple in mermaid.
|
||||
- Followed by `:` colon as separator
|
||||
- Followed by `positive numeric value` (supported up to two decimal places)
|
||||
|
||||
**Note:**
|
||||
|
||||
> Pie chart values must be **positive numbers greater than zero**.\
|
||||
> **Negative values are not allowed** and will result in an error.
|
||||
|
||||
\[pie] \[showData] (OPTIONAL)
|
||||
\[title] \[titlevalue] (OPTIONAL)
|
||||
"\[datakey1]" : \[dataValue1]
|
||||
|
@@ -23,7 +23,7 @@ config:
|
||||
sankey:
|
||||
showValues: false
|
||||
---
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Agricultural 'waste',Bio-conversion,124.729
|
||||
Bio-conversion,Liquid,0.597
|
||||
@@ -101,7 +101,7 @@ config:
|
||||
sankey:
|
||||
showValues: false
|
||||
---
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Agricultural 'waste',Bio-conversion,124.729
|
||||
Bio-conversion,Liquid,0.597
|
||||
@@ -175,7 +175,7 @@ Wind,Electricity grid,289.366
|
||||
|
||||
## Syntax
|
||||
|
||||
The idea behind syntax is that a user types `sankey-beta` keyword first, then pastes raw CSV below and get the result.
|
||||
The idea behind syntax is that a user types `sankey` keyword first, then pastes raw CSV below and get the result.
|
||||
|
||||
It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.txt) with subtle **differences**:
|
||||
|
||||
@@ -187,7 +187,7 @@ It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.
|
||||
It is implied that 3 columns inside CSV should represent `source`, `target` and `value` accordingly:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
%% source,target,value
|
||||
Electricity grid,Over generation / exports,104.453
|
||||
@@ -196,7 +196,7 @@ Electricity grid,H2 conversion,27.14
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
%% source,target,value
|
||||
Electricity grid,Over generation / exports,104.453
|
||||
@@ -209,7 +209,7 @@ Electricity grid,H2 conversion,27.14
|
||||
CSV does not support empty lines without comma delimiters by default. But you can add them if needed:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Bio-conversion,Losses,26.862
|
||||
|
||||
@@ -219,7 +219,7 @@ Bio-conversion,Gas,81.144
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Bio-conversion,Losses,26.862
|
||||
|
||||
@@ -233,14 +233,14 @@ Bio-conversion,Gas,81.144
|
||||
If you need to have a comma, wrap it in double quotes:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, homes",193.026
|
||||
Pumped heat,"Heating and cooling, commercial",70.672
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, homes",193.026
|
||||
Pumped heat,"Heating and cooling, commercial",70.672
|
||||
@@ -251,14 +251,14 @@ Pumped heat,"Heating and cooling, commercial",70.672
|
||||
If you need to have double quote, put a pair of them inside quoted string:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, ""homes""",193.026
|
||||
Pumped heat,"Heating and cooling, ""commercial""",70.672
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, ""homes""",193.026
|
||||
Pumped heat,"Heating and cooling, ""commercial""",70.672
|
||||
|
@@ -13,7 +13,7 @@
|
||||
## Example
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -22,7 +22,7 @@ xychart-beta
|
||||
```
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -40,7 +40,7 @@ xychart-beta
|
||||
The chart can be drawn horizontal or vertical, default value is vertical.
|
||||
|
||||
```
|
||||
xychart-beta horizontal
|
||||
xychart horizontal
|
||||
...
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ The title is a short description of the chart and it will always render on top o
|
||||
#### Example
|
||||
|
||||
```
|
||||
xychart-beta
|
||||
xychart
|
||||
title "This is a simple example"
|
||||
...
|
||||
```
|
||||
@@ -98,10 +98,10 @@ A bar chart offers the capability to graphically depict bars.
|
||||
|
||||
#### Simplest example
|
||||
|
||||
The only two things required are the chart name (`xychart-beta`) and one data set. So you will be able to draw a chart with a simple config like
|
||||
The only two things required are the chart name (`xychart`) and one data set. So you will be able to draw a chart with a simple config like
|
||||
|
||||
```
|
||||
xychart-beta
|
||||
xychart
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
```
|
||||
|
||||
@@ -176,7 +176,7 @@ config:
|
||||
xyChart:
|
||||
titleColor: "#ff0000"
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -195,7 +195,7 @@ config:
|
||||
xyChart:
|
||||
titleColor: "#ff0000"
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
|
@@ -238,13 +238,15 @@ export function edgeTypeStr2Type(typeStr: string): string {
|
||||
}
|
||||
|
||||
export function edgeStrToEdgeData(typeStr: string): string {
|
||||
switch (typeStr.trim()) {
|
||||
case '--x':
|
||||
switch (typeStr.replace(/^[\s-]+|[\s-]+$/g, '')) {
|
||||
case 'x':
|
||||
return 'arrow_cross';
|
||||
case '--o':
|
||||
case 'o':
|
||||
return 'arrow_circle';
|
||||
default:
|
||||
case '>':
|
||||
return 'arrow_point';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-a
|
||||
const id = 'block';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*block-beta/.test(txt);
|
||||
return /^\s*block(-beta)?/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
|
@@ -36,10 +36,10 @@ CRLF \u000D\u000A
|
||||
|
||||
%%
|
||||
|
||||
"block-beta" { return 'BLOCK_DIAGRAM_KEY'; }
|
||||
"block"\s+ { yy.getLogger().debug('Found space-block'); return 'block';}
|
||||
"block"\n+ { yy.getLogger().debug('Found nl-block'); return 'block';}
|
||||
"block:" { yy.getLogger().debug('Found space-block'); return 'id-block';}
|
||||
"block-beta" { yy.getLogger().debug('Found block-beta'); return 'BLOCK_DIAGRAM_KEY'; }
|
||||
"block:" { yy.getLogger().debug('Found id-block'); return 'id-block'; }
|
||||
"block" { yy.getLogger().debug('Found block'); return 'BLOCK_DIAGRAM_KEY'; }
|
||||
|
||||
// \s*\%\%.* { yy.getLogger().debug('Found comment',yytext); }
|
||||
[\s]+ { yy.getLogger().debug('.', yytext); /* skip all whitespace */ }
|
||||
[\n]+ {yy.getLogger().debug('_', yytext); /* skip all whitespace */ }
|
||||
@@ -240,7 +240,7 @@ columnsStatement
|
||||
|
||||
blockStatement
|
||||
: id-block nodeStatement document end { yy.getLogger().debug('Rule: id-block statement : ', $2, $3); const id2 = yy.generateId(); $$ = { ...$2, type:'composite', children: $3 }; }
|
||||
| block document end { yy.getLogger().debug('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:'', children: $2 }; }
|
||||
| BLOCK_DIAGRAM_KEY document end { yy.getLogger().debug('Rule: blockStatement : ', $1, $2, $3); const id = yy.generateId(); $$ = { id, type:'composite', label:'', children: $2 }; }
|
||||
;
|
||||
|
||||
node
|
||||
|
@@ -23,7 +23,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[0].label).toBe('id');
|
||||
});
|
||||
it('a node with a square shape and a label', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id["A label"]
|
||||
`;
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[0].type).toBe('square');
|
||||
});
|
||||
it('a diagram with multiple nodes', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id1
|
||||
id2
|
||||
`;
|
||||
@@ -51,7 +51,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id1
|
||||
id2
|
||||
id3
|
||||
@@ -72,7 +72,7 @@ describe('Block diagram', function () {
|
||||
});
|
||||
|
||||
it('a node with a square shape and a label', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id["A label"]
|
||||
id2`;
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id1["first"] --> id2["second"]
|
||||
`;
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('Block diagram', function () {
|
||||
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
id1["first"] -- "a label" --> id2["second"]
|
||||
`;
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('Block diagram', function () {
|
||||
expect(edges[0].label).toBe('a label');
|
||||
});
|
||||
it('a diagram with column statements', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
`;
|
||||
@@ -127,7 +127,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram without column statements', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
block1["Block 1"]
|
||||
`;
|
||||
|
||||
@@ -137,7 +137,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram with auto column statements', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns auto
|
||||
block1["Block 1"]
|
||||
`;
|
||||
@@ -149,7 +149,7 @@ describe('Block diagram', function () {
|
||||
});
|
||||
|
||||
it('blocks next to each other', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
block2["Block 2"]
|
||||
@@ -163,7 +163,7 @@ describe('Block diagram', function () {
|
||||
});
|
||||
|
||||
it('blocks on top of each other', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
block2["Block 2"]
|
||||
@@ -177,7 +177,7 @@ describe('Block diagram', function () {
|
||||
});
|
||||
|
||||
it('compound blocks 2', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
bBlock["BBlock"]
|
||||
@@ -205,7 +205,7 @@ describe('Block diagram', function () {
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks of compound blocks', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
block
|
||||
@@ -240,7 +240,7 @@ describe('Block diagram', function () {
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks with title', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
block:compoundBlock["Compound block"]
|
||||
columns 1
|
||||
block2["Block 2"]
|
||||
@@ -265,7 +265,7 @@ describe('Block diagram', function () {
|
||||
expect(block2.type).toBe('square');
|
||||
});
|
||||
it('blocks mixed with compound blocks', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
|
||||
@@ -292,7 +292,7 @@ describe('Block diagram', function () {
|
||||
});
|
||||
|
||||
it('Arrow blocks', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 3
|
||||
block1["Block 1"]
|
||||
blockArrow<[" "]>(right)
|
||||
@@ -316,7 +316,7 @@ describe('Block diagram', function () {
|
||||
expect(blockArrow.directions).toContain('right');
|
||||
});
|
||||
it('Arrow blocks with multiple points', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 1
|
||||
A
|
||||
blockArrow<[" "]>(up, down)
|
||||
@@ -339,7 +339,7 @@ describe('Block diagram', function () {
|
||||
expect(blockArrow.directions).not.toContain('right');
|
||||
});
|
||||
it('blocks with different widths', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 3
|
||||
one["One Slot"]
|
||||
two["Two slots"]:2
|
||||
@@ -354,7 +354,7 @@ describe('Block diagram', function () {
|
||||
expect(two.widthInColumns).toBe(2);
|
||||
});
|
||||
it('empty blocks', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 3
|
||||
space
|
||||
middle["In the middle"]
|
||||
@@ -373,7 +373,7 @@ describe('Block diagram', function () {
|
||||
expect(middle.label).toBe('In the middle');
|
||||
});
|
||||
it('classDef statements applied to a block', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
classDef black color:#ffffff, fill:#000000;
|
||||
|
||||
mc["Memcache"]
|
||||
@@ -391,7 +391,7 @@ describe('Block diagram', function () {
|
||||
expect(black.styles[0]).toEqual('color:#ffffff');
|
||||
});
|
||||
it('style statements applied to a block', () => {
|
||||
const str = `block-beta
|
||||
const str = `block
|
||||
columns 1
|
||||
B["A wide one in the middle"]
|
||||
style B fill:#f9F,stroke:#333,stroke-width:4px
|
||||
@@ -426,9 +426,9 @@ columns 1
|
||||
|
||||
describe('prototype properties', function () {
|
||||
function validateProperty(prop: string) {
|
||||
expect(() => block.parse(`block-beta\n${prop}`)).not.toThrow();
|
||||
expect(() => block.parse(`block\n${prop}`)).not.toThrow();
|
||||
expect(() =>
|
||||
block.parse(`block-beta\nA; classDef ${prop} color:#ffffff,fill:#000000; class A ${prop}`)
|
||||
block.parse(`block\nA; classDef ${prop} color:#ffffff,fill:#000000; class A ${prop}`)
|
||||
).not.toThrow();
|
||||
}
|
||||
|
||||
|
@@ -33,13 +33,13 @@ function setupDompurifyHooks() {
|
||||
const TEMPORARY_ATTRIBUTE = 'data-temp-href-target';
|
||||
|
||||
DOMPurify.addHook('beforeSanitizeAttributes', (node) => {
|
||||
if (node instanceof Element && node.tagName === 'A' && node.hasAttribute('target')) {
|
||||
if (node.tagName === 'A' && node.hasAttribute('target')) {
|
||||
node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') ?? '');
|
||||
}
|
||||
});
|
||||
|
||||
DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
if (node instanceof Element && node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) ?? '');
|
||||
node.removeAttribute(TEMPORARY_ATTRIBUTE);
|
||||
if (node.getAttribute('target') === '_blank') {
|
||||
|
@@ -167,7 +167,10 @@ export const getTasks = function () {
|
||||
};
|
||||
|
||||
export const isInvalidDate = function (date, dateFormat, excludes, includes) {
|
||||
if (includes.includes(date.format(dateFormat.trim()))) {
|
||||
const formattedDate = date.format(dateFormat.trim());
|
||||
const dateOnly = date.format('YYYY-MM-DD');
|
||||
|
||||
if (includes.includes(formattedDate) || includes.includes(dateOnly)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
@@ -180,7 +183,7 @@ export const isInvalidDate = function (date, dateFormat, excludes, includes) {
|
||||
if (excludes.includes(date.format('dddd').toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
return excludes.includes(date.format(dateFormat.trim()));
|
||||
return excludes.includes(formattedDate) || excludes.includes(dateOnly);
|
||||
};
|
||||
|
||||
export const setWeekday = function (txt) {
|
||||
|
@@ -581,17 +581,11 @@ export const draw = function (text, id, version, diagObj) {
|
||||
|
||||
rectangles
|
||||
.append('rect')
|
||||
.attr('id', function (d) {
|
||||
return 'exclude-' + d.start.format('YYYY-MM-DD');
|
||||
})
|
||||
.attr('x', function (d) {
|
||||
return timeScale(d.start) + theSidePad;
|
||||
})
|
||||
.attr('id', (d) => 'exclude-' + d.start.format('YYYY-MM-DD'))
|
||||
.attr('x', (d) => timeScale(d.start.startOf('day')) + theSidePad)
|
||||
.attr('y', conf.gridLineStartPadding)
|
||||
.attr('width', function (d) {
|
||||
const renderEnd = d.end.add(1, 'day');
|
||||
return timeScale(renderEnd) - timeScale(d.start);
|
||||
})
|
||||
.attr('width', (d) => timeScale(d.end.endOf('day')) - timeScale(d.start.startOf('day')))
|
||||
|
||||
.attr('height', h - theTopPad - conf.gridLineStartPadding)
|
||||
.attr('transform-origin', function (d, i) {
|
||||
return (
|
||||
@@ -615,9 +609,20 @@ export const draw = function (text, id, version, diagObj) {
|
||||
* @param h
|
||||
*/
|
||||
function makeGrid(theSidePad, theTopPad, w, h) {
|
||||
const dateFormat = diagObj.db.getDateFormat();
|
||||
const userAxisFormat = diagObj.db.getAxisFormat();
|
||||
let axisFormat;
|
||||
if (userAxisFormat) {
|
||||
axisFormat = userAxisFormat;
|
||||
} else if (dateFormat === 'D') {
|
||||
axisFormat = '%d';
|
||||
} else {
|
||||
axisFormat = conf.axisFormat ?? '%Y-%m-%d';
|
||||
}
|
||||
|
||||
let bottomXAxis = axisBottom(timeScale)
|
||||
.tickSize(-h + theTopPad + conf.gridLineStartPadding)
|
||||
.tickFormat(timeFormat(diagObj.db.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
.tickFormat(timeFormat(axisFormat));
|
||||
|
||||
const reTickInterval = /^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/;
|
||||
const resultTickInterval = reTickInterval.exec(
|
||||
@@ -669,7 +674,7 @@ export const draw = function (text, id, version, diagObj) {
|
||||
if (diagObj.db.topAxisEnabled() || conf.topAxis) {
|
||||
let topXAxis = axisTop(timeScale)
|
||||
.tickSize(-h + theTopPad + conf.gridLineStartPadding)
|
||||
.tickFormat(timeFormat(diagObj.db.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
.tickFormat(timeFormat(axisFormat));
|
||||
|
||||
if (resultTickInterval !== null) {
|
||||
const every = resultTickInterval[1];
|
||||
|
@@ -139,6 +139,32 @@ describe('pie', () => {
|
||||
}).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it('should handle simple pie with zero slice value', async () => {
|
||||
await parser.parse(`pie title Default text position: Animal adoption
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"dogs" : 0
|
||||
"rats" : 40.12
|
||||
`);
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections.get('dogs')).toBe(0);
|
||||
expect(sections.get('rats')).toBe(40.12);
|
||||
});
|
||||
|
||||
it('should handle simple pie with negative slice value', async () => {
|
||||
await expect(async () => {
|
||||
await parser.parse(`pie title Default text position: Animal adoption
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"dogs" : -60.67
|
||||
"rats" : 40.12
|
||||
`);
|
||||
}).rejects.toThrowError(
|
||||
'"dogs" has invalid value: -60.67. Negative values are not allowed in pie charts. All slice values must be >= 0.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle unsafe properties', async () => {
|
||||
await expect(
|
||||
parser.parse(`pie title Unsafe props test
|
||||
|
@@ -34,6 +34,11 @@ const clear = (): void => {
|
||||
};
|
||||
|
||||
const addSection = ({ label, value }: D3Section): void => {
|
||||
if (value < 0) {
|
||||
throw new Error(
|
||||
`"${label}" has invalid value: ${value}. Negative values are not allowed in pie charts. All slice values must be >= 0.`
|
||||
);
|
||||
}
|
||||
if (!sections.has(label)) {
|
||||
sections.set(label, value);
|
||||
log.debug(`added new section: ${label}, with value: ${value}`);
|
||||
|
@@ -10,20 +10,14 @@ import { cleanAndMerge, parseFontSize } from '../../utils.js';
|
||||
import type { D3Section, PieDB, Sections } from './pieTypes.js';
|
||||
|
||||
const createPieArcs = (sections: Sections): d3.PieArcDatum<D3Section>[] => {
|
||||
// Compute the position of each group on the pie:
|
||||
const sum = [...sections.values()].reduce((acc, val) => acc + val, 0);
|
||||
|
||||
const pieData: D3Section[] = [...sections.entries()]
|
||||
.map((element: [string, number]): D3Section => {
|
||||
return {
|
||||
label: element[0],
|
||||
value: element[1],
|
||||
};
|
||||
})
|
||||
.sort((a: D3Section, b: D3Section): number => {
|
||||
return b.value - a.value;
|
||||
});
|
||||
const pie: d3.Pie<unknown, D3Section> = d3pie<D3Section>().value(
|
||||
(d3Section: D3Section): number => d3Section.value
|
||||
);
|
||||
.map(([label, value]) => ({ label, value }))
|
||||
.filter((d) => (d.value / sum) * 100 >= 1) // Remove values < 1%
|
||||
.sort((a, b) => b.value - a.value);
|
||||
|
||||
const pie: d3.Pie<unknown, D3Section> = d3pie<D3Section>().value((d) => d.value);
|
||||
return pie(pieData);
|
||||
};
|
||||
|
||||
@@ -89,13 +83,21 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
themeVariables.pie11,
|
||||
themeVariables.pie12,
|
||||
];
|
||||
let sum = 0;
|
||||
sections.forEach((section) => {
|
||||
sum += section;
|
||||
});
|
||||
|
||||
// Filter out arcs that would render as 0%
|
||||
const filteredArcs = arcs.filter((datum) => ((datum.data.value / sum) * 100).toFixed(0) !== '0');
|
||||
|
||||
// Set the color scale
|
||||
const color: d3.ScaleOrdinal<string, 12, never> = scaleOrdinal(myGeneratedColors);
|
||||
|
||||
// Build the pie chart: each part of the pie is a path that we build using the arc function.
|
||||
group
|
||||
.selectAll('mySlices')
|
||||
.data(arcs)
|
||||
.data(filteredArcs)
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('d', arcGenerator)
|
||||
@@ -104,15 +106,11 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
})
|
||||
.attr('class', 'pieCircle');
|
||||
|
||||
let sum = 0;
|
||||
sections.forEach((section) => {
|
||||
sum += section;
|
||||
});
|
||||
// Now add the percentage.
|
||||
// Use the centroid method to get the best coordinates.
|
||||
group
|
||||
.selectAll('mySlices')
|
||||
.data(arcs)
|
||||
.data(filteredArcs)
|
||||
.enter()
|
||||
.append('text')
|
||||
.text((datum: d3.PieArcDatum<D3Section>): string => {
|
||||
@@ -133,15 +131,20 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
.attr('class', 'pieTitleText');
|
||||
|
||||
// Add the legends/annotations for each section
|
||||
const allSectionData: D3Section[] = [...sections.entries()].map(([label, value]) => ({
|
||||
label,
|
||||
value,
|
||||
}));
|
||||
|
||||
const legend = group
|
||||
.selectAll('.legend')
|
||||
.data(color.domain())
|
||||
.data(allSectionData)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'legend')
|
||||
.attr('transform', (_datum, index: number): string => {
|
||||
const height = LEGEND_RECT_SIZE + LEGEND_SPACING;
|
||||
const offset = (height * color.domain().length) / 2;
|
||||
const offset = (height * allSectionData.length) / 2;
|
||||
const horizontal = 12 * LEGEND_RECT_SIZE;
|
||||
const vertical = index * height - offset;
|
||||
return 'translate(' + horizontal + ',' + vertical + ')';
|
||||
@@ -151,20 +154,18 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
.append('rect')
|
||||
.attr('width', LEGEND_RECT_SIZE)
|
||||
.attr('height', LEGEND_RECT_SIZE)
|
||||
.style('fill', color)
|
||||
.style('stroke', color);
|
||||
.style('fill', (d) => color(d.label))
|
||||
.style('stroke', (d) => color(d.label));
|
||||
|
||||
legend
|
||||
.data(arcs)
|
||||
.append('text')
|
||||
.attr('x', LEGEND_RECT_SIZE + LEGEND_SPACING)
|
||||
.attr('y', LEGEND_RECT_SIZE - LEGEND_SPACING)
|
||||
.text((datum: d3.PieArcDatum<D3Section>): string => {
|
||||
const { label, value } = datum.data;
|
||||
.text((d) => {
|
||||
if (db.getShowData()) {
|
||||
return `${label} [${value}]`;
|
||||
return `${d.label} [${d.value}]`;
|
||||
}
|
||||
return label;
|
||||
return d.label;
|
||||
});
|
||||
|
||||
const longestTextWidth = Math.max(
|
||||
|
@@ -27,6 +27,7 @@ TEXTDATA [\u0020-\u0021\u0023-\u002B\u002D-\u007E]
|
||||
%%
|
||||
|
||||
<INITIAL>"sankey-beta" { this.pushState('csv'); return 'SANKEY'; }
|
||||
<INITIAL>"sankey" { this.pushState('csv'); return 'SANKEY'; }
|
||||
<INITIAL,csv><<EOF>> { return 'EOF' } // match end of file
|
||||
<INITIAL,csv>({CRLF}|{LF}) { return 'NEWLINE' }
|
||||
<INITIAL,csv>{COMMA} { return 'COMMA' }
|
||||
|
@@ -13,7 +13,7 @@ describe('Sankey diagram', function () {
|
||||
sankey.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('parses csv', () => {
|
||||
it('parses csv with sankey-beta syntax', () => {
|
||||
const csv = path.resolve(__dirname, './energy.csv');
|
||||
const data = fs.readFileSync(csv, 'utf8');
|
||||
const graphDefinition = prepareTextForParsing(cleanupComments('sankey-beta\n\n ' + data));
|
||||
@@ -21,7 +21,15 @@ describe('Sankey diagram', function () {
|
||||
sankey.parser.parse(graphDefinition);
|
||||
});
|
||||
|
||||
it('allows __proto__ as id', function () {
|
||||
it('parses csv with sankey syntax', () => {
|
||||
const csv = path.resolve(__dirname, './energy.csv');
|
||||
const data = fs.readFileSync(csv, 'utf8');
|
||||
const graphDefinition = prepareTextForParsing(cleanupComments('sankey\n\n ' + data));
|
||||
|
||||
sankey.parser.parse(graphDefinition);
|
||||
});
|
||||
|
||||
it('allows __proto__ as id with sankey-beta syntax', function () {
|
||||
sankey.parser.parse(
|
||||
prepareTextForParsing(`sankey-beta
|
||||
__proto__,A,0.597
|
||||
@@ -29,5 +37,14 @@ describe('Sankey diagram', function () {
|
||||
`)
|
||||
);
|
||||
});
|
||||
|
||||
it('allows __proto__ as id with sankey syntax', function () {
|
||||
sankey.parser.parse(
|
||||
prepareTextForParsing(`sankey
|
||||
__proto__,A,0.597
|
||||
A,__proto__,0.403
|
||||
`)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,7 +3,7 @@ import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-a
|
||||
const id = 'sankey';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*sankey-beta/.test(txt);
|
||||
return /^\s*sankey(-beta)?/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
|
@@ -30,6 +30,7 @@
|
||||
<acc_descr_multiline>[^\}]* { return "acc_descr_multiline_value"; }
|
||||
|
||||
"xychart-beta" {return 'XYCHART';}
|
||||
"xychart" {return 'XYCHART';}
|
||||
(?:"vertical"|"horizontal") {return 'CHART_ORIENTATION'}
|
||||
|
||||
"x-axis" { this.pushState("axis_data"); return "X_AXIS"; }
|
||||
|
@@ -33,44 +33,44 @@ describe('Testing xychart jison file', () => {
|
||||
clearMocks();
|
||||
});
|
||||
|
||||
it('should throw error if xychart-beta text is not there', () => {
|
||||
const str = 'xychart-beta-1';
|
||||
it('should throw error if xychart text is not there', () => {
|
||||
const str = 'xychart-1';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
|
||||
it('should not throw error if only xychart is there', () => {
|
||||
const str = 'xychart-beta';
|
||||
const str = 'xychart';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
});
|
||||
|
||||
it('parse title of the chart within "', () => {
|
||||
const str = 'xychart-beta \n title "This is a title"';
|
||||
const str = 'xychart \n title "This is a title"';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('This is a title');
|
||||
});
|
||||
it('parse title of the chart without "', () => {
|
||||
const str = 'xychart-beta \n title oneLinertitle';
|
||||
const str = 'xychart \n title oneLinertitle';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('oneLinertitle');
|
||||
});
|
||||
|
||||
it('parse chart orientation', () => {
|
||||
const str = 'xychart-beta vertical';
|
||||
const str = 'xychart vertical';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
|
||||
});
|
||||
|
||||
it('parse chart orientation with spaces', () => {
|
||||
let str = 'xychart-beta horizontal ';
|
||||
let str = 'xychart horizontal ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
|
||||
|
||||
str = 'xychart-beta abc';
|
||||
str = 'xychart abc';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
|
||||
it('parse x-axis', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName\n';
|
||||
const str = 'xychart \nx-axis xAxisName\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
@@ -79,7 +79,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name without "', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName \n';
|
||||
const str = 'xychart \nx-axis xAxisName \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
@@ -88,7 +88,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name with "', () => {
|
||||
const str = 'xychart-beta \n x-axis "xAxisName has space"\n';
|
||||
const str = 'xychart \n x-axis "xAxisName has space"\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName has space',
|
||||
@@ -97,7 +97,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name with " with spaces', () => {
|
||||
const str = 'xychart-beta \n x-axis " xAxisName has space " \n';
|
||||
const str = 'xychart \n x-axis " xAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' xAxisName has space ',
|
||||
@@ -106,7 +106,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
|
||||
const str = 'xychart \nx-axis xAxisName 45.5 --> 33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
@@ -115,11 +115,11 @@ describe('Testing xychart jison file', () => {
|
||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
||||
});
|
||||
it('parse x-axis throw error for invalid range data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName aaa --> 33 \n';
|
||||
const str = 'xychart \nx-axis xAxisName aaa --> 33 \n';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse x-axis with axis name and range data with only decimal part', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> .34 \n';
|
||||
const str = 'xychart \nx-axis xAxisName 45.5 --> .34 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
@@ -129,7 +129,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis without axis name and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis 45.5 --> 1.34 \n';
|
||||
const str = 'xychart \nx-axis 45.5 --> 1.34 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
@@ -139,7 +139,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
||||
const str = 'xychart \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
@@ -155,7 +155,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis without axis name and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis [ "cat1" , cat2a ] \n ';
|
||||
const str = 'xychart \nx-axis [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
@@ -171,14 +171,14 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis throw error if unbalanced bracket', () => {
|
||||
let str = 'xychart-beta \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
|
||||
let str = 'xychart \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] ] \n ';
|
||||
str = 'xychart \nx-axis xAxisName [ "cat1" , cat2a ] ] \n ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 1', () => {
|
||||
const str = `xychart-beta \n x-axis "this is x axis" [category1, "category 2", category3]\n`;
|
||||
const str = `xychart \n x-axis "this is x axis" [category1, "category 2", category3]\n`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
@@ -189,8 +189,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 2', () => {
|
||||
const str =
|
||||
'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 , cat3] \n ';
|
||||
const str = 'xychart \nx-axis xAxisName [ "cat1 with space" , cat2 , cat3] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
@@ -202,7 +201,7 @@ describe('Testing xychart jison file', () => {
|
||||
|
||||
it('parse x-axis complete variant 3', () => {
|
||||
const str =
|
||||
'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 asdf , cat3] \n ';
|
||||
'xychart \nx-axis xAxisName [ "cat1 with space" , cat2 asdf , cat3] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
@@ -213,17 +212,17 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
|
||||
it('parse y-axis with axis name', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName\n';
|
||||
const str = 'xychart \ny-axis yAxisName\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
});
|
||||
it('parse y-axis with axis name with spaces', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName \n';
|
||||
const str = 'xychart \ny-axis yAxisName \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
});
|
||||
it('parse y-axis with axis name with "', () => {
|
||||
const str = 'xychart-beta \n y-axis "yAxisName has space"\n';
|
||||
const str = 'xychart \n y-axis "yAxisName has space"\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'yAxisName has space',
|
||||
@@ -231,7 +230,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with " and spaces', () => {
|
||||
const str = 'xychart-beta \n y-axis " yAxisName has space " \n';
|
||||
const str = 'xychart \n y-axis " yAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' yAxisName has space ',
|
||||
@@ -239,39 +238,39 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with range data', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> 33 \n';
|
||||
const str = 'xychart \ny-axis yAxisName 45.5 --> 33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
||||
});
|
||||
it('parse y-axis without axis name with range data', () => {
|
||||
const str = 'xychart-beta \ny-axis 45.5 --> 33 \n';
|
||||
const str = 'xychart \ny-axis 45.5 --> 33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: '', type: 'text' });
|
||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
||||
});
|
||||
it('parse y-axis with axis name with range data with only decimal part', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> .33 \n';
|
||||
const str = 'xychart \ny-axis yAxisName 45.5 --> .33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 0.33);
|
||||
});
|
||||
it('parse y-axis throw error for invalid number in range data', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> abc \n';
|
||||
const str = 'xychart \ny-axis yAxisName 45.5 --> abc \n';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse y-axis throws error if range data is passed', () => {
|
||||
const str = 'xychart-beta \ny-axis yAxisName [ 45.3, 33 ] \n';
|
||||
const str = 'xychart \ny-axis yAxisName [ 45.3, 33 ] \n';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse both axis at once', () => {
|
||||
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
});
|
||||
it('parse line Data', () => {
|
||||
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle', type: 'text' },
|
||||
@@ -282,7 +281,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
it('parse line Data with spaces and +,- symbols', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -292,8 +291,7 @@ describe('Testing xychart jison file', () => {
|
||||
);
|
||||
});
|
||||
it('parse line Data without title', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line [ +23 , -45 , 56.6 , .33] ';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n line [ +23 , -45 , 56.6 , .33] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -304,34 +302,32 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
it('parse line Data throws error unbalanced brackets', () => {
|
||||
let str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse line Data throws error if data is not provided', () => {
|
||||
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" ';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse line Data throws error if data is empty', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ ] ';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse line Data throws error if , is not in proper', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse line Data throws error if not number', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse bar Data', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6, .22]';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6, .22]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -342,7 +338,7 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
it('parse bar Data spaces and +,- symbol', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -352,8 +348,7 @@ describe('Testing xychart jison file', () => {
|
||||
);
|
||||
});
|
||||
it('parse bar Data without plot title', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar [ +23 , -45 , 56.6 ] ';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar [ +23 , -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -361,34 +356,34 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
it('parse bar should throw for unbalanced brackets', () => {
|
||||
let str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse bar should throw error if data is not provided', () => {
|
||||
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" ';
|
||||
const str = 'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse bar should throw error if data is empty', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse bar should throw error if comma is not proper', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse bar should throw error if number is not passed', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse multiple bar and line variant 1', () => {
|
||||
const str =
|
||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle1 [23, 45, 56.6] \n line lineTitle1 [11, 45.5, 67, 23] \n bar barTitle2 [13, 42, 56.89] \n line lineTitle2 [45, 99, 012]';
|
||||
'xychart\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle1 [23, 45, 56.6] \n line lineTitle1 [11, 45.5, 67, 23] \n bar barTitle2 [13, 42, 56.89] \n line lineTitle2 [45, 99, 012]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
@@ -411,8 +406,8 @@ describe('Testing xychart jison file', () => {
|
||||
});
|
||||
it('parse multiple bar and line variant 2', () => {
|
||||
const str = `
|
||||
xychart-beta horizontal
|
||||
title Basic xychart
|
||||
xychart horizontal
|
||||
title "Basic xychart"
|
||||
x-axis "this is x axis" [category1, "category 2", category3]
|
||||
y-axis yaxisText 10 --> 150
|
||||
bar barTitle1 [23, 45, 56.6]
|
||||
|
@@ -7,7 +7,7 @@ import type {
|
||||
const id = 'xychart';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*xychart-beta/.test(txt);
|
||||
return /^\s*xychart(-beta)?/.test(txt);
|
||||
};
|
||||
|
||||
const loader: DiagramLoader = async () => {
|
||||
|
@@ -8,7 +8,7 @@ outline: 'deep' # shows all h3 headings in outline in Vitepress
|
||||
## Introduction to Block Diagrams
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -62,7 +62,7 @@ At its core, a block diagram consists of blocks representing different entities
|
||||
To create a simple block diagram with three blocks labeled 'a', 'b', and 'c', the syntax is as follows:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
a b c
|
||||
```
|
||||
|
||||
@@ -78,7 +78,7 @@ While simple block diagrams are linear and straightforward, more complex systems
|
||||
In scenarios where you need to distribute blocks across multiple columns, you can specify the number of columns and arrange the blocks accordingly. Here's how to create a block diagram with three columns and four blocks, where the fourth block appears in a second row:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a b c d
|
||||
```
|
||||
@@ -101,7 +101,7 @@ In more complex diagrams, you may need blocks that span multiple columns to emph
|
||||
To create a block diagram where one block spans across two columns, you can specify the desired width for each block:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
@@ -118,7 +118,7 @@ Composite blocks, or blocks within blocks, are an advanced feature in Mermaid's
|
||||
Creating a composite block involves defining a parent block and then nesting other blocks within it. Here's how to define a composite block with nested elements:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
D
|
||||
end
|
||||
@@ -137,7 +137,7 @@ Mermaid also allows for dynamic adjustment of column widths based on the content
|
||||
In diagrams with varying block sizes, Mermaid automatically adjusts the column widths to fit the largest block in each column. Here's an example:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a:3
|
||||
block:group1:2
|
||||
@@ -157,7 +157,7 @@ This example demonstrates how Mermaid dynamically adjusts the width of the colum
|
||||
In scenarios where you need to stack blocks horizontally, you can use column width to accomplish the task. Blocks can be arranged vertically by putting them in a single column. Here is how you can create a block diagram in which 4 blocks are stacked on top of each other:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
block
|
||||
columns 1
|
||||
a["A label"] b c d
|
||||
@@ -181,7 +181,7 @@ Mermaid supports a range of block shapes to suit different diagramming needs, fr
|
||||
To create a block with round edges, which can be used to represent a softer or more flexible component:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1("This is the text in the box")
|
||||
```
|
||||
|
||||
@@ -190,7 +190,7 @@ block-beta
|
||||
A stadium-shaped block, resembling an elongated circle, can be used for components that are process-oriented:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1(["This is the text in the box"])
|
||||
```
|
||||
|
||||
@@ -199,7 +199,7 @@ block-beta
|
||||
For representing subroutines or contained processes, a block with double vertical lines is useful:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[["This is the text in the box"]]
|
||||
```
|
||||
|
||||
@@ -208,7 +208,7 @@ block-beta
|
||||
The cylindrical shape is ideal for representing databases or storage components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[("Database")]
|
||||
```
|
||||
|
||||
@@ -217,7 +217,7 @@ block-beta
|
||||
A circle can be used for centralized or pivotal components:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1(("This is the text in the circle"))
|
||||
```
|
||||
|
||||
@@ -228,21 +228,21 @@ For decision points, use a rhombus, and for unique or specialized processes, asy
|
||||
**Asymmetric**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1>"This is the text in the box"]
|
||||
```
|
||||
|
||||
**Rhombus**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1{"This is the text in the box"}
|
||||
```
|
||||
|
||||
**Hexagon**
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1{{"This is the text in the box"}}
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ block-beta
|
||||
Parallelogram and trapezoid shapes are perfect for inputs/outputs and transitional processes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1[/"This is the text in the box"/]
|
||||
id2[\"This is the text in the box"\]
|
||||
A[/"Christmas"\]
|
||||
@@ -263,7 +263,7 @@ block-beta
|
||||
For highlighting critical or high-priority components, a double circle can be effective:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1((("This is the text in the circle")))
|
||||
```
|
||||
|
||||
@@ -276,7 +276,7 @@ Mermaid also offers unique shapes like block arrows and space blocks for directi
|
||||
Block arrows can visually indicate direction or flow within a process:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
blockArrowId<["Label"]>(right)
|
||||
blockArrowId2<["Label"]>(left)
|
||||
blockArrowId3<["Label"]>(up)
|
||||
@@ -291,7 +291,7 @@ block-beta
|
||||
Space blocks can be used to create intentional empty spaces in the diagram, which is useful for layout and readability:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
a space b
|
||||
c d e
|
||||
@@ -300,7 +300,7 @@ block-beta
|
||||
or
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
ida space:3 idb idc
|
||||
```
|
||||
|
||||
@@ -325,7 +325,7 @@ The most fundamental aspect of connecting blocks is the use of arrows or links.
|
||||
A simple link with an arrow can be created to show direction or flow from one block to another:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
```
|
||||
@@ -342,7 +342,7 @@ Example - Text with Links
|
||||
To add text to a link, the syntax includes the text within the link definition:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space:2 B
|
||||
A-- "X" -->B
|
||||
```
|
||||
@@ -352,7 +352,7 @@ This example show how to add descriptive text to the links, enhancing the inform
|
||||
Example - Edges and Styles:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
db(("DB"))
|
||||
blockArrowId6<[" "]>(down)
|
||||
@@ -381,7 +381,7 @@ Mermaid enables detailed styling of individual blocks, allowing you to apply var
|
||||
To apply custom styles to a block, you can use the `style` keyword followed by the block identifier and the desired CSS properties:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
id1 space id2
|
||||
id1("Start")-->id2("Stop")
|
||||
style id1 fill:#636,stroke:#333,stroke-width:4px
|
||||
@@ -395,7 +395,7 @@ Mermaid enables applying styling to classes, which could make styling easier if
|
||||
#### Example - Styling a Single Class
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A-->B
|
||||
classDef blue fill:#6e6ce6,stroke:#333,stroke-width:4px;
|
||||
@@ -420,7 +420,7 @@ Combining the elements of structure, linking, and styling, we can create compreh
|
||||
Illustrating a simple software system architecture with interconnected components:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Frontend blockArrowId6<[" "]>(right) Backend
|
||||
space:2 down<[" "]>(down)
|
||||
@@ -439,7 +439,7 @@ This example shows a basic architecture with a frontend, backend, and database.
|
||||
Representing a business process flow with decision points and multiple stages:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 3
|
||||
Start(("Start")) space:2
|
||||
down<[" "]>(down) space:2
|
||||
@@ -468,7 +468,7 @@ Understanding and avoiding common syntax errors is key to a smooth experience wi
|
||||
A common mistake is incorrect linking syntax, which can lead to unexpected results or broken diagrams:
|
||||
|
||||
```
|
||||
block-beta
|
||||
block
|
||||
A - B
|
||||
```
|
||||
|
||||
@@ -476,7 +476,7 @@ block-beta
|
||||
Ensure that links between blocks are correctly specified with arrows (--> or ---) to define the direction and type of connection. Also remember that one of the fundamentals for block diagram is to give the author full control of where the boxes are positioned so in the example you need to add a space between the boxes:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A space B
|
||||
A --> B
|
||||
```
|
||||
@@ -486,7 +486,7 @@ block-beta
|
||||
Applying styles in the wrong context or with incorrect syntax can lead to blocks not being styled as intended:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill#969;
|
||||
```
|
||||
@@ -495,7 +495,7 @@ Applying styles in the wrong context or with incorrect syntax can lead to blocks
|
||||
Correct the syntax by ensuring proper separation of style properties with commas and using the correct CSS property format:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
A
|
||||
style A fill:#969,stroke:#333;
|
||||
|
||||
|
@@ -24,6 +24,11 @@ Drawing a pie chart is really simple in mermaid.
|
||||
- Followed by `:` colon as separator
|
||||
- Followed by `positive numeric value` (supported up to two decimal places)
|
||||
|
||||
**Note:**
|
||||
|
||||
> Pie chart values must be **positive numbers greater than zero**.
|
||||
> **Negative values are not allowed** and will result in an error.
|
||||
|
||||
[pie] [showData] (OPTIONAL)
|
||||
[title] [titlevalue] (OPTIONAL)
|
||||
"[datakey1]" : [dataValue1]
|
||||
|
@@ -18,7 +18,7 @@ config:
|
||||
sankey:
|
||||
showValues: false
|
||||
---
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Agricultural 'waste',Bio-conversion,124.729
|
||||
Bio-conversion,Liquid,0.597
|
||||
@@ -92,7 +92,7 @@ Wind,Electricity grid,289.366
|
||||
|
||||
## Syntax
|
||||
|
||||
The idea behind syntax is that a user types `sankey-beta` keyword first, then pastes raw CSV below and get the result.
|
||||
The idea behind syntax is that a user types `sankey` keyword first, then pastes raw CSV below and get the result.
|
||||
|
||||
It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.txt) with subtle **differences**:
|
||||
|
||||
@@ -104,7 +104,7 @@ It implements CSV standard as [described here](https://www.ietf.org/rfc/rfc4180.
|
||||
It is implied that 3 columns inside CSV should represent `source`, `target` and `value` accordingly:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
%% source,target,value
|
||||
Electricity grid,Over generation / exports,104.453
|
||||
@@ -117,7 +117,7 @@ Electricity grid,H2 conversion,27.14
|
||||
CSV does not support empty lines without comma delimiters by default. But you can add them if needed:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Bio-conversion,Losses,26.862
|
||||
|
||||
@@ -131,7 +131,7 @@ Bio-conversion,Gas,81.144
|
||||
If you need to have a comma, wrap it in double quotes:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, homes",193.026
|
||||
Pumped heat,"Heating and cooling, commercial",70.672
|
||||
@@ -142,7 +142,7 @@ Pumped heat,"Heating and cooling, commercial",70.672
|
||||
If you need to have double quote, put a pair of them inside quoted string:
|
||||
|
||||
```mermaid-example
|
||||
sankey-beta
|
||||
sankey
|
||||
|
||||
Pumped heat,"Heating and cooling, ""homes""",193.026
|
||||
Pumped heat,"Heating and cooling, ""commercial""",70.672
|
||||
|
@@ -7,7 +7,7 @@
|
||||
## Example
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
@@ -26,7 +26,7 @@ All text values that contain only one word can be written without `"`. If a text
|
||||
The chart can be drawn horizontal or vertical, default value is vertical.
|
||||
|
||||
```
|
||||
xychart-beta horizontal
|
||||
xychart horizontal
|
||||
...
|
||||
```
|
||||
|
||||
@@ -37,7 +37,7 @@ The title is a short description of the chart and it will always render on top o
|
||||
#### Example
|
||||
|
||||
```
|
||||
xychart-beta
|
||||
xychart
|
||||
title "This is a simple example"
|
||||
...
|
||||
```
|
||||
@@ -86,10 +86,10 @@ A bar chart offers the capability to graphically depict bars.
|
||||
|
||||
#### Simplest example
|
||||
|
||||
The only two things required are the chart name (`xychart-beta`) and one data set. So you will be able to draw a chart with a simple config like
|
||||
The only two things required are the chart name (`xychart`) and one data set. So you will be able to draw a chart with a simple config like
|
||||
|
||||
```
|
||||
xychart-beta
|
||||
xychart
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
```
|
||||
|
||||
@@ -164,7 +164,7 @@ config:
|
||||
xyChart:
|
||||
titleColor: "#ff0000"
|
||||
---
|
||||
xychart-beta
|
||||
xychart
|
||||
title "Sales Revenue"
|
||||
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
y-axis "Revenue (in $)" 4000 --> 11000
|
||||
|
@@ -755,6 +755,11 @@ graph TD;A--x|text including URL space|B;`)
|
||||
expectedType: 'xychart',
|
||||
content: 'x-axis "Attempts" 10000 --> 10000\ny-axis "Passing tests" 1 --> 1\nbar [1]',
|
||||
},
|
||||
{
|
||||
textDiagramType: 'xychart',
|
||||
expectedType: 'xychart',
|
||||
content: 'x-axis "Attempts" 10000 --> 10000\ny-axis "Passing tests" 1 --> 1\nbar [1]',
|
||||
},
|
||||
{ textDiagramType: 'requirementDiagram', expectedType: 'requirement' },
|
||||
{ textDiagramType: 'sequenceDiagram', expectedType: 'sequence' },
|
||||
{ textDiagramType: 'stateDiagram-v2', expectedType: 'stateDiagram' },
|
||||
|
@@ -637,6 +637,11 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
|
||||
log.info('arrowTypeEnd', edge.arrowTypeEnd);
|
||||
|
||||
addEdgeMarkers(svgPath, edge, url, id, diagramType, strokeColor);
|
||||
const midIndex = Math.floor(points.length / 2);
|
||||
const point = points[midIndex];
|
||||
if (!utils.isLabelCoordinateInPath(point, svgPath.attr('d'))) {
|
||||
pointsHasChanged = true;
|
||||
}
|
||||
|
||||
let paths = {};
|
||||
if (pointsHasChanged) {
|
||||
|
@@ -104,8 +104,23 @@ export const userNodeOverrides = (node: Node, options: any) => {
|
||||
seed: handDrawnSeed,
|
||||
strokeWidth: stylesMap.get('stroke-width')?.replace('px', '') || 1.3,
|
||||
fillLineDash: [0, 0],
|
||||
strokeLineDash: getStrokeDashArray(stylesMap.get('stroke-dasharray')),
|
||||
},
|
||||
options
|
||||
);
|
||||
return result;
|
||||
};
|
||||
|
||||
const getStrokeDashArray = (strokeDasharrayStyle?: string) => {
|
||||
if (!strokeDasharrayStyle) {
|
||||
return [0, 0];
|
||||
}
|
||||
const dashArray = strokeDasharrayStyle.trim().split(/\s+/).map(Number);
|
||||
if (dashArray.length === 1) {
|
||||
const val = isNaN(dashArray[0]) ? 0 : dashArray[0];
|
||||
return [val, val];
|
||||
}
|
||||
const first = isNaN(dashArray[0]) ? 0 : dashArray[0];
|
||||
const second = isNaN(dashArray[1]) ? 0 : dashArray[1];
|
||||
return [first, second];
|
||||
};
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
|
||||
import intersect from '../intersect/index.js';
|
||||
import type { Node } from '../../types.js';
|
||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import rough from 'roughjs';
|
||||
import { insertPolygonShape } from './insertPolygonShape.js';
|
||||
import type { D3Selection } from '../../../types.js';
|
||||
|
||||
export const createHexagonPathD = (
|
||||
@@ -29,42 +28,50 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
|
||||
node.labelStyle = labelStyles;
|
||||
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
|
||||
|
||||
const f = 4;
|
||||
const h = bbox.height + node.padding;
|
||||
const m = h / f;
|
||||
const w = bbox.width + 2 * m + node.padding;
|
||||
const points = [
|
||||
{ x: m, y: 0 },
|
||||
{ x: w - m, y: 0 },
|
||||
{ x: w, y: -h / 2 },
|
||||
{ x: w - m, y: -h },
|
||||
{ x: m, y: -h },
|
||||
{ x: 0, y: -h / 2 },
|
||||
];
|
||||
|
||||
let polygon: D3Selection<SVGGElement> | Awaited<ReturnType<typeof insertPolygonShape>>;
|
||||
const h = bbox.height + (node.padding ?? 0);
|
||||
const w = bbox.width + (node.padding ?? 0) * 2.5;
|
||||
const { cssStyles } = node;
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {});
|
||||
|
||||
if (node.look === 'handDrawn') {
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {});
|
||||
const pathData = createHexagonPathD(0, 0, w, h, m);
|
||||
const roughNode = rc.path(pathData, options);
|
||||
|
||||
polygon = shapeSvg
|
||||
.insert(() => roughNode, ':first-child')
|
||||
.attr('transform', `translate(${-w / 2}, ${h / 2})`);
|
||||
|
||||
if (cssStyles) {
|
||||
polygon.attr('style', cssStyles);
|
||||
}
|
||||
} else {
|
||||
polygon = insertPolygonShape(shapeSvg, w, h, points);
|
||||
if (node.look !== 'handDrawn') {
|
||||
options.roughness = 0;
|
||||
options.fillStyle = 'solid';
|
||||
}
|
||||
|
||||
if (nodeStyles) {
|
||||
polygon.attr('style', nodeStyles);
|
||||
let halfWidth = w / 2;
|
||||
const m = halfWidth / 6; // Margin for label
|
||||
halfWidth = halfWidth + m; // Adjusted half width for hexagon
|
||||
|
||||
const halfHeight = h / 2;
|
||||
|
||||
const fixedLength = halfHeight / 2;
|
||||
const deducedWidth = halfWidth - fixedLength;
|
||||
|
||||
const points = [
|
||||
{ x: -deducedWidth, y: -halfHeight },
|
||||
{ x: 0, y: -halfHeight },
|
||||
{ x: deducedWidth, y: -halfHeight },
|
||||
{ x: halfWidth, y: 0 },
|
||||
{ x: deducedWidth, y: halfHeight },
|
||||
{ x: 0, y: halfHeight },
|
||||
{ x: -deducedWidth, y: halfHeight },
|
||||
{ x: -halfWidth, y: 0 },
|
||||
];
|
||||
|
||||
const pathData = createPathFromPoints(points);
|
||||
const shapeNode = rc.path(pathData, options);
|
||||
|
||||
const polygon = shapeSvg.insert(() => shapeNode, ':first-child');
|
||||
polygon.attr('class', 'basic label-container');
|
||||
|
||||
if (cssStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', cssStyles);
|
||||
}
|
||||
|
||||
if (nodeStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', nodeStyles);
|
||||
}
|
||||
|
||||
node.width = w;
|
||||
|
@@ -25,6 +25,7 @@ export async function question<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
const w = bbox.width + node.padding;
|
||||
const h = bbox.height + node.padding;
|
||||
const s = w + h;
|
||||
const adjustment = 0.5;
|
||||
|
||||
const points = [
|
||||
{ x: s / 2, y: 0 },
|
||||
@@ -45,13 +46,14 @@ export async function question<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
|
||||
polygon = shapeSvg
|
||||
.insert(() => roughNode, ':first-child')
|
||||
.attr('transform', `translate(${-s / 2}, ${s / 2})`);
|
||||
.attr('transform', `translate(${-s / 2 + adjustment}, ${s / 2})`);
|
||||
|
||||
if (cssStyles) {
|
||||
polygon.attr('style', cssStyles);
|
||||
}
|
||||
} else {
|
||||
polygon = insertPolygonShape(shapeSvg, s, s, points);
|
||||
polygon.attr('transform', `translate(${-s / 2 + adjustment}, ${s / 2})`);
|
||||
}
|
||||
|
||||
if (nodeStyles) {
|
||||
|
@@ -1,18 +1,160 @@
|
||||
import type { Node, RectOptions } from '../../types.js';
|
||||
import { labelHelper, updateNodeBounds, getNodeClasses, createPathFromPoints } from './util.js';
|
||||
import intersect from '../intersect/index.js';
|
||||
import type { Node } from '../../types.js';
|
||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import rough from 'roughjs';
|
||||
import type { D3Selection } from '../../../types.js';
|
||||
import { drawRect } from './drawRect.js';
|
||||
|
||||
/**
|
||||
* Generates evenly spaced points along an elliptical arc connecting two points.
|
||||
*
|
||||
* @param x1 - x-coordinate of the start point of the arc
|
||||
* @param y1 - y-coordinate of the start point of the arc
|
||||
* @param x2 - x-coordinate of the end point of the arc
|
||||
* @param y2 - y-coordinate of the end point of the arc
|
||||
* @param rx - horizontal radius of the ellipse
|
||||
* @param ry - vertical radius of the ellipse
|
||||
* @param clockwise - direction of the arc; true for clockwise, false for counterclockwise
|
||||
* @returns Array of points `{ x, y }` along the elliptical arc
|
||||
*
|
||||
* @throws Error if the given radii are too small to draw an arc between the points
|
||||
*/
|
||||
export function generateArcPoints(
|
||||
x1: number,
|
||||
y1: number,
|
||||
x2: number,
|
||||
y2: number,
|
||||
rx: number,
|
||||
ry: number,
|
||||
clockwise: boolean
|
||||
) {
|
||||
const numPoints = 20;
|
||||
// Calculate midpoint
|
||||
const midX = (x1 + x2) / 2;
|
||||
const midY = (y1 + y2) / 2;
|
||||
|
||||
// Calculate the angle of the line connecting the points
|
||||
const angle = Math.atan2(y2 - y1, x2 - x1);
|
||||
|
||||
// Calculate transformed coordinates for the ellipse
|
||||
const dx = (x2 - x1) / 2;
|
||||
const dy = (y2 - y1) / 2;
|
||||
|
||||
// Scale to unit circle
|
||||
const transformedX = dx / rx;
|
||||
const transformedY = dy / ry;
|
||||
|
||||
// Calculate the distance between points on the unit circle
|
||||
const distance = Math.sqrt(transformedX ** 2 + transformedY ** 2);
|
||||
|
||||
// Check if the ellipse can be drawn with the given radii
|
||||
if (distance > 1) {
|
||||
throw new Error('The given radii are too small to create an arc between the points.');
|
||||
}
|
||||
|
||||
// Calculate the distance from the midpoint to the center of the ellipse
|
||||
const scaledCenterDistance = Math.sqrt(1 - distance ** 2);
|
||||
|
||||
// Calculate the center of the ellipse
|
||||
const centerX = midX + scaledCenterDistance * ry * Math.sin(angle) * (clockwise ? -1 : 1);
|
||||
const centerY = midY - scaledCenterDistance * rx * Math.cos(angle) * (clockwise ? -1 : 1);
|
||||
|
||||
// Calculate the start and end angles on the ellipse
|
||||
const startAngle = Math.atan2((y1 - centerY) / ry, (x1 - centerX) / rx);
|
||||
const endAngle = Math.atan2((y2 - centerY) / ry, (x2 - centerX) / rx);
|
||||
|
||||
// Adjust angles for clockwise/counterclockwise
|
||||
let angleRange = endAngle - startAngle;
|
||||
if (clockwise && angleRange < 0) {
|
||||
angleRange += 2 * Math.PI;
|
||||
}
|
||||
if (!clockwise && angleRange > 0) {
|
||||
angleRange -= 2 * Math.PI;
|
||||
}
|
||||
|
||||
// Generate points
|
||||
const points = [];
|
||||
for (let i = 0; i < numPoints; i++) {
|
||||
const t = i / (numPoints - 1);
|
||||
const angle = startAngle + t * angleRange;
|
||||
const x = centerX + rx * Math.cos(angle);
|
||||
const y = centerY + ry * Math.sin(angle);
|
||||
points.push({ x, y });
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
export async function roundedRect<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: Node
|
||||
) {
|
||||
const options = {
|
||||
rx: 5,
|
||||
ry: 5,
|
||||
classes: '',
|
||||
labelPaddingX: (node?.padding || 0) * 1,
|
||||
labelPaddingY: (node?.padding || 0) * 1,
|
||||
} as RectOptions;
|
||||
const { labelStyles, nodeStyles } = styles2String(node);
|
||||
node.labelStyle = labelStyles;
|
||||
const { shapeSvg, bbox } = await labelHelper(parent, node, getNodeClasses(node));
|
||||
|
||||
return drawRect(parent, node, options);
|
||||
const labelPaddingX = node?.padding ?? 0;
|
||||
const labelPaddingY = node?.padding ?? 0;
|
||||
|
||||
const w = (node?.width ? node?.width : bbox.width) + labelPaddingX * 2;
|
||||
const h = (node?.height ? node?.height : bbox.height) + labelPaddingY * 2;
|
||||
const radius = 5;
|
||||
const taper = 5; // Taper width for the rounded corners
|
||||
const { cssStyles } = node;
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {});
|
||||
|
||||
if (node.look !== 'handDrawn') {
|
||||
options.roughness = 0;
|
||||
options.fillStyle = 'solid';
|
||||
}
|
||||
|
||||
const points = [
|
||||
// Top edge (left to right)
|
||||
{ x: -w / 2 + taper, y: -h / 2 }, // Top-left corner start (1)
|
||||
{ x: w / 2 - taper, y: -h / 2 }, // Top-right corner start (2)
|
||||
|
||||
...generateArcPoints(w / 2 - taper, -h / 2, w / 2, -h / 2 + taper, radius, radius, true), // Top-left arc (2 to 3)
|
||||
|
||||
// Right edge (top to bottom)
|
||||
{ x: w / 2, y: -h / 2 + taper }, // Top-right taper point (3)
|
||||
{ x: w / 2, y: h / 2 - taper }, // Bottom-right taper point (4)
|
||||
|
||||
...generateArcPoints(w / 2, h / 2 - taper, w / 2 - taper, h / 2, radius, radius, true), // Top-left arc (4 to 5)
|
||||
|
||||
// Bottom edge (right to left)
|
||||
{ x: w / 2 - taper, y: h / 2 }, // Bottom-right corner start (5)
|
||||
{ x: -w / 2 + taper, y: h / 2 }, // Bottom-left corner start (6)
|
||||
|
||||
...generateArcPoints(-w / 2 + taper, h / 2, -w / 2, h / 2 - taper, radius, radius, true), // Top-left arc (4 to 5)
|
||||
|
||||
// Left edge (bottom to top)
|
||||
{ x: -w / 2, y: h / 2 - taper }, // Bottom-left taper point (7)
|
||||
{ x: -w / 2, y: -h / 2 + taper }, // Top-left taper point (8)
|
||||
...generateArcPoints(-w / 2, -h / 2 + taper, -w / 2 + taper, -h / 2, radius, radius, true), // Top-left arc (4 to 5)
|
||||
];
|
||||
|
||||
const pathData = createPathFromPoints(points);
|
||||
const shapeNode = rc.path(pathData, options);
|
||||
|
||||
const polygon = shapeSvg.insert(() => shapeNode, ':first-child');
|
||||
polygon.attr('class', 'basic label-container outer-path');
|
||||
|
||||
if (cssStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', cssStyles);
|
||||
}
|
||||
|
||||
if (nodeStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', nodeStyles);
|
||||
}
|
||||
|
||||
updateNodeBounds(node, polygon);
|
||||
|
||||
node.intersect = function (point) {
|
||||
const pos = intersect.polygon(node, points, point);
|
||||
return pos;
|
||||
};
|
||||
|
||||
return shapeSvg;
|
||||
}
|
||||
|
@@ -1,11 +1,15 @@
|
||||
import { labelHelper, updateNodeBounds, getNodeClasses } from './util.js';
|
||||
import {
|
||||
labelHelper,
|
||||
updateNodeBounds,
|
||||
getNodeClasses,
|
||||
generateCirclePoints,
|
||||
createPathFromPoints,
|
||||
} from './util.js';
|
||||
import intersect from '../intersect/index.js';
|
||||
import type { Node } from '../../types.js';
|
||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import rough from 'roughjs';
|
||||
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||
import type { D3Selection } from '../../../types.js';
|
||||
import { handleUndefinedAttr } from '../../../utils.js';
|
||||
|
||||
export const createStadiumPathD = (
|
||||
x: number,
|
||||
@@ -60,36 +64,44 @@ export async function stadium<T extends SVGGraphicsElement>(parent: D3Selection<
|
||||
const h = bbox.height + node.padding;
|
||||
const w = bbox.width + h / 4 + node.padding;
|
||||
|
||||
let rect;
|
||||
const radius = h / 2;
|
||||
const { cssStyles } = node;
|
||||
if (node.look === 'handDrawn') {
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {});
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
const options = userNodeOverrides(node, {});
|
||||
|
||||
const pathData = createRoundedRectPathD(-w / 2, -h / 2, w, h, h / 2);
|
||||
const roughNode = rc.path(pathData, options);
|
||||
|
||||
rect = shapeSvg.insert(() => roughNode, ':first-child');
|
||||
rect.attr('class', 'basic label-container').attr('style', handleUndefinedAttr(cssStyles));
|
||||
} else {
|
||||
rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
rect
|
||||
.attr('class', 'basic label-container')
|
||||
.attr('style', nodeStyles)
|
||||
.attr('rx', h / 2)
|
||||
.attr('ry', h / 2)
|
||||
.attr('x', -w / 2)
|
||||
.attr('y', -h / 2)
|
||||
.attr('width', w)
|
||||
.attr('height', h);
|
||||
if (node.look !== 'handDrawn') {
|
||||
options.roughness = 0;
|
||||
options.fillStyle = 'solid';
|
||||
}
|
||||
|
||||
updateNodeBounds(node, rect);
|
||||
const points = [
|
||||
{ x: -w / 2 + radius, y: -h / 2 },
|
||||
{ x: w / 2 - radius, y: -h / 2 },
|
||||
...generateCirclePoints(-w / 2 + radius, 0, radius, 50, 90, 270),
|
||||
{ x: w / 2 - radius, y: h / 2 },
|
||||
...generateCirclePoints(w / 2 - radius, 0, radius, 50, 270, 450),
|
||||
];
|
||||
|
||||
const pathData = createPathFromPoints(points);
|
||||
const shapeNode = rc.path(pathData, options);
|
||||
|
||||
const polygon = shapeSvg.insert(() => shapeNode, ':first-child');
|
||||
polygon.attr('class', 'basic label-container outer-path');
|
||||
|
||||
if (cssStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', cssStyles);
|
||||
}
|
||||
|
||||
if (nodeStyles && node.look !== 'handDrawn') {
|
||||
polygon.selectChildren('path').attr('style', nodeStyles);
|
||||
}
|
||||
|
||||
updateNodeBounds(node, polygon);
|
||||
|
||||
node.intersect = function (point) {
|
||||
return intersect.rect(node, point);
|
||||
const pos = intersect.polygon(node, points, point);
|
||||
return pos;
|
||||
};
|
||||
|
||||
return shapeSvg;
|
||||
|
@@ -884,6 +884,7 @@ export default {
|
||||
runFunc,
|
||||
entityDecode,
|
||||
insertTitle,
|
||||
isLabelCoordinateInPath,
|
||||
parseFontSize,
|
||||
InitIDGenerator,
|
||||
};
|
||||
@@ -960,3 +961,23 @@ export function handleUndefinedAttr(
|
||||
) {
|
||||
return attrValue ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the x or y coordinate of the edge label
|
||||
* appears in the given SVG path data string.
|
||||
*
|
||||
* @param point - The Point object with x and y properties to check.
|
||||
* @param dAttr - SVG path data string (the 'd' attribute of an SVG path element).
|
||||
* @returns - True if the rounded x or y coordinate of the edge label is found
|
||||
* in the sanitized path data string; otherwise, false.
|
||||
*/
|
||||
export function isLabelCoordinateInPath(point: Point, dAttr: string) {
|
||||
const roundedX = Math.round(point.x);
|
||||
const roundedY = Math.round(point.y);
|
||||
|
||||
const sanitizedD = dAttr.replace(/(\d+\.\d+)/g, (match) =>
|
||||
Math.round(parseFloat(match)).toString()
|
||||
);
|
||||
|
||||
return sanitizedD.includes(roundedX.toString()) || sanitizedD.includes(roundedY.toString());
|
||||
}
|
||||
|
@@ -12,5 +12,9 @@ entry Pie:
|
||||
;
|
||||
|
||||
PieSection:
|
||||
label=STRING ":" value=NUMBER EOL
|
||||
label=STRING ":" value=NUMBER_PIE EOL
|
||||
;
|
||||
|
||||
terminal FLOAT_PIE returns number: /-?[0-9]+\.[0-9]+(?!\.)/;
|
||||
terminal INT_PIE returns number: /-?(0|[1-9][0-9]*)(?!\.)/;
|
||||
terminal NUMBER_PIE returns number: FLOAT_PIE | INT_PIE;
|
Reference in New Issue
Block a user