mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-27 03:09:43 +02:00
Compare commits
72 Commits
sidv/FixSn
...
xychart
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4f9cf4f9fc | ||
![]() |
9f375139d5 | ||
![]() |
0c49d2b84e | ||
![]() |
42414e85d1 | ||
![]() |
1e43ad1ee3 | ||
![]() |
cda41a1cdf | ||
![]() |
1a199d630f | ||
![]() |
51c07163aa | ||
![]() |
9bbd3cab3c | ||
![]() |
6f61a71dda | ||
![]() |
3af4020cdc | ||
![]() |
d65e78f9e2 | ||
![]() |
82b120e567 | ||
![]() |
d95c159b1f | ||
![]() |
c468319869 | ||
![]() |
4b21e1e745 | ||
![]() |
fb1942c2cf | ||
![]() |
81d8b9d02e | ||
![]() |
6db070197a | ||
![]() |
a331125187 | ||
![]() |
66bc461fa1 | ||
![]() |
df72febc00 | ||
![]() |
5aced51f9e | ||
![]() |
fe9fbd8618 | ||
![]() |
b031c6f182 | ||
![]() |
dc51a8f182 | ||
![]() |
66cd0b9621 | ||
![]() |
6382dcf7c8 | ||
![]() |
5587011f75 | ||
![]() |
c904c7d21a | ||
![]() |
b285466130 | ||
![]() |
3754ac0872 | ||
![]() |
83ca6897bd | ||
![]() |
d2d7f2bcb0 | ||
![]() |
20f9abcc38 | ||
![]() |
0417a8ddff | ||
![]() |
46fe731379 | ||
![]() |
0e63233845 | ||
![]() |
e26dea6416 | ||
![]() |
3b2b8dacd8 | ||
![]() |
df94d3994d | ||
![]() |
6f56d94c64 | ||
![]() |
56c4f10607 | ||
![]() |
dfa71317ad | ||
![]() |
17fd681bdb | ||
![]() |
e852156b9f | ||
![]() |
90be8dedf6 | ||
![]() |
8691874dbb | ||
![]() |
f1490ff679 | ||
![]() |
25160d9688 | ||
![]() |
533a921ef5 | ||
![]() |
3bef03f568 | ||
![]() |
737f4f0cf3 | ||
![]() |
db92b5a219 | ||
![]() |
71e5a2b3a3 | ||
![]() |
54f1435839 | ||
![]() |
48a20c5cb8 | ||
![]() |
5f4f1cc08d | ||
![]() |
da0a4ae37d | ||
![]() |
2972012059 | ||
![]() |
cf641ba4fd | ||
![]() |
39e5064019 | ||
![]() |
7830d0c4bf | ||
![]() |
60d34bdc72 | ||
![]() |
3262a06a8e | ||
![]() |
506314598e | ||
![]() |
25a9479acf | ||
![]() |
1273f440a8 | ||
![]() |
e1d085925e | ||
![]() |
39d175314c | ||
![]() |
17426f0a97 | ||
![]() |
a36fa7cd2f |
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
@@ -131,7 +131,7 @@ jobs:
|
||||
VITEST_COVERAGE: true
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
|
||||
ARGOS_PARALLEL: ${{ env.CYPRESS_RECORD_KEY != '' }}
|
||||
ARGOS_PARALLEL: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
ARGOS_PARALLEL_TOTAL: 4
|
||||
ARGOS_PARALLEL_INDEX: ${{ matrix.containers }}
|
||||
|
||||
|
@@ -21,13 +21,11 @@ export default eyesPlugin(
|
||||
});
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
config.env.useArgos = !!process.env.ARGOS_TOKEN;
|
||||
config.env.useArgos = !!process.env.CI;
|
||||
|
||||
if (config.env.useArgos) {
|
||||
// Argos
|
||||
registerArgosTask(on, config, {
|
||||
uploadToArgos: !!process.env.CI,
|
||||
token: process.env.ARGOS_TOKEN,
|
||||
token: 'fc3a35cf5200db928d65b2047861582d9444032b',
|
||||
});
|
||||
} else {
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
|
@@ -119,7 +119,6 @@ describe('Configuration', () => {
|
||||
const url = 'http://localhost:9000/regression/issue-1874.html';
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('svg').should('be.visible');
|
||||
verifyScreenshot(
|
||||
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
|
||||
);
|
||||
|
@@ -10,7 +10,6 @@ describe('XSS', () => {
|
||||
cy.wait(1000).then(() => {
|
||||
cy.get('.mermaid').should('exist');
|
||||
});
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should not allow tags in the css', () => {
|
||||
|
@@ -30,7 +30,6 @@ describe('C4 diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Container diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -50,7 +49,6 @@ describe('C4 diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Component diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -69,7 +67,6 @@ describe('C4 diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Dynamic diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -93,7 +90,6 @@ describe('C4 diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple C4Deployment diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -117,6 +113,5 @@ describe('C4 diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
@@ -32,7 +32,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('2: should render a simple class diagrams with cardinality', () => {
|
||||
@@ -61,7 +60,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('3: should render a simple class diagram with different visibilities', () => {
|
||||
@@ -79,7 +77,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('4: should render a simple class diagram with comments', () => {
|
||||
@@ -109,7 +106,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('5: should render a simple class diagram with abstract method', () => {
|
||||
@@ -121,7 +117,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('6: should render a simple class diagram with static method', () => {
|
||||
@@ -133,7 +128,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('7: should render a simple class diagram with Generic class', () => {
|
||||
@@ -153,7 +147,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('8: should render a simple class diagram with Generic class and relations', () => {
|
||||
@@ -174,7 +167,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('9: should render a simple class diagram with clickable link', () => {
|
||||
@@ -196,7 +188,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('10: should render a simple class diagram with clickable callback', () => {
|
||||
@@ -218,7 +209,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('11: should render a simple class diagram with return type on method', () => {
|
||||
@@ -233,7 +223,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('12: should render a simple class diagram with generic types', () => {
|
||||
@@ -249,7 +238,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('13: should render a simple class diagram with css classes applied', () => {
|
||||
@@ -267,7 +255,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('14: should render a simple class diagram with css classes applied directly', () => {
|
||||
@@ -283,7 +270,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('15: should render a simple class diagram with css classes applied to multiple classes', () => {
|
||||
@@ -298,7 +284,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('16: should render multiple class diagrams', () => {
|
||||
@@ -351,7 +336,6 @@ describe('Class diagram', () => {
|
||||
],
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
// it('17: should render a class diagram when useMaxWidth is true (default)', () => {
|
||||
@@ -421,7 +405,6 @@ describe('Class diagram', () => {
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render class diagram with newlines in title', () => {
|
||||
@@ -439,7 +422,6 @@ describe('Class diagram', () => {
|
||||
+quack()
|
||||
}
|
||||
`);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render class diagram with many newlines in title', () => {
|
||||
|
@@ -218,7 +218,6 @@ describe('Entity Relationship Diagram', () => {
|
||||
`,
|
||||
{ loglevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with keys', () => {
|
||||
|
@@ -8,7 +8,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a complete quadrant chart', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -30,7 +29,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render without points', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -46,7 +44,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render y-axix on right side', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -63,7 +60,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render x-axix on bottom', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -80,7 +76,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render x-axix on bottom and y-axis on right', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -97,7 +92,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render without title', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -112,7 +106,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should use all the config', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -135,7 +128,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should use all the theme variable', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -158,7 +150,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render x-axis labels in the center, if x-axis has two labels', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -180,7 +171,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render y-axis labels in the center, if y-axis has two labels', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -202,7 +192,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render both axes labels on the left and bottom, if both axes have only one label', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -224,7 +213,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('it should render data points with styles', () => {
|
||||
@@ -249,7 +237,6 @@ describe('Quadrant Chart', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('it should render data points with styles + classes', () => {
|
||||
|
@@ -44,6 +44,5 @@ describe('Requirement diagram', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/// <reference types="Cypress" />
|
||||
// <reference types="Cypress" />
|
||||
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
@@ -68,6 +68,19 @@ context('Sequence diagram', () => {
|
||||
{ sequence: { actorFontFamily: 'courier' } }
|
||||
);
|
||||
});
|
||||
it('should render bidirectional arrows', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice<<->>John: Hello John, how are you?
|
||||
Alice<<-->>John: Hi Alice, I can hear you!
|
||||
John<<->>Alice: This also works the other way
|
||||
John<<-->>Alice: Yes
|
||||
Alice->John: Test
|
||||
John->>Alice: Still works
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should handle different line breaks', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@@ -464,6 +477,18 @@ context('Sequence diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render notes over actors and participant', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
participant Charlie
|
||||
note over Alice: some note
|
||||
note over Charlie: other note
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render long messages from an actor to the left to one to the right', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
@@ -8,7 +8,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 1, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a simple state diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -20,7 +19,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a long descriptions instead of id when available', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -32,7 +30,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a long descriptions with additional descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -44,7 +41,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a single state with short descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -55,7 +51,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a transition descriptions with new lines', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -69,7 +64,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a state with a note', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -83,7 +77,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a state with on the left side when so specified', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -97,7 +90,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a state with a note together with another state', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -113,7 +105,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a note with multiple lines in it', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -156,7 +147,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a simple state diagrams 2', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -169,7 +159,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a simple state diagrams with labels', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -185,7 +174,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render state descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -198,7 +186,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render composite states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -217,7 +204,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render multiple composite states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -287,7 +273,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render concurrency states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -311,7 +296,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('v2 should render a state with states in it', () => {
|
||||
imgSnapshotTest(
|
||||
|
@@ -10,7 +10,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a long descriptions instead of id when available', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -22,7 +21,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a long descriptions with additional descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -34,7 +32,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a single state with short descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -45,7 +42,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a transition descriptions with new lines', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -59,7 +55,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state with a note', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -73,7 +68,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state with on the left side when so specified', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -87,7 +81,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state with a note together with another state', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -103,7 +96,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a note with multiple lines in it', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -146,7 +138,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple state diagrams 2', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -159,7 +150,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a simple state diagrams with labels', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -175,7 +165,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render state descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -188,7 +177,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render composite states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -207,7 +195,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render multiple composit states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -277,7 +264,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render concurrency states', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -301,7 +287,6 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ logLevel: 0, fontFamily: 'courier' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state with states in it', () => {
|
||||
imgSnapshotTest(
|
||||
|
@@ -10,7 +10,6 @@ describe('themeCSS balancing, it', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should not allow unbalanced CSS definitions 2', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -21,7 +20,6 @@ describe('themeCSS balancing, it', () => {
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +43,6 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a flowchart diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -70,7 +67,6 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a new flowchart diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -96,7 +92,6 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a sequence diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -125,7 +120,6 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a class diagram', () => {
|
||||
@@ -175,7 +169,6 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -210,7 +203,6 @@ stateDiagram
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a state diagram (v2)', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -245,7 +237,6 @@ stateDiagram-v2
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a er diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -266,7 +257,6 @@ erDiagram
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a user journey diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@@ -287,7 +277,6 @@ erDiagram
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a gantt diagram', () => {
|
||||
cy.clock(new Date('2014-01-06').getTime());
|
||||
@@ -326,7 +315,6 @@ erDiagram
|
||||
`,
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe('XY Chart', () => {
|
||||
it('should render the simplest possible chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
describe('single dataset', () => {
|
||||
it('should render the simplest possible chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
line [10, 30, 20]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Should render a complete chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should render a complete chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
|
||||
@@ -21,88 +21,68 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should render a chart without title', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should render a chart without title', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
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]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('y-axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('y-axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
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]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Should render a chart without y-axis with different range', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should render a chart without y-axis with different range', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
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]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('x axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('x axis title not required', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
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]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Multiple plots can be rendered', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
line [23, 46, 77, 34]
|
||||
line [45, 32, 33, 12]
|
||||
bar [87, 54, 99, 85]
|
||||
line [78, 88, 22, 4]
|
||||
line [22, 29, 75, 33]
|
||||
bar [52, 96, 35, 10]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Decimals and negative numbers are supported', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Decimals and negative numbers are supported', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
y-axis -2.4 --> 3.5
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render spark line with "plotReservedSpacePercent"', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render spark line with "plotReservedSpacePercent"', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
theme: dark
|
||||
@@ -114,13 +94,12 @@ describe('XY Chart', () => {
|
||||
xychart-beta
|
||||
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render spark bar without displaying other property', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render spark bar without displaying other property', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
theme: dark
|
||||
@@ -141,13 +120,12 @@ describe('XY Chart', () => {
|
||||
xychart-beta
|
||||
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Should use all the config from directive', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should use all the config from directive', () => {
|
||||
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
|
||||
title "Sales Revenue"
|
||||
@@ -156,13 +134,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Should use all the config from yaml', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Should use all the config from yaml', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
theme: forest
|
||||
@@ -197,13 +174,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render with show axis title false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render with show axis title false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
@@ -219,13 +195,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render with show axis label false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render with show axis label false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
@@ -241,13 +216,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render with show axis tick false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render with show axis tick false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
@@ -263,13 +237,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render with show axis line false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render with show axis line false', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
xyChart:
|
||||
@@ -285,13 +258,12 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Render all the theme color', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('Render all the theme color', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
---
|
||||
config:
|
||||
themeVariables:
|
||||
@@ -315,8 +287,110 @@ describe('XY Chart', () => {
|
||||
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple datasets', () => {
|
||||
describe('vertical', () => {
|
||||
it('should render bar diagram for 3 datasets', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [0, 20, 40, 30]
|
||||
bar "cats" [20, 40, 0, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render line diagram for 3 datasets', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
line "dogs" [0, 20, 40, 30]
|
||||
line "cats" [20, 40, 0, 30]
|
||||
line "birds" [30, 60, 50, 30]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a mix of multiple bar and line plots', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta
|
||||
line [23, 46, 77, 34]
|
||||
line [45, 32, 33, 12]
|
||||
bar [87, 54, 99, 85]
|
||||
line [78, 88, 22, 4]
|
||||
line [22, 29, 75, 33]
|
||||
bar [52, 96, 35, 10]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
||||
describe('horizontal', () => {
|
||||
it('should render bar diagram for 3 datasets', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta horizontal
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [0, 20, 40, 30]
|
||||
bar "cats" [20, 40, 0, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render line diagram for 3 datasets', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta horizontal
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
line "dogs" [0, 20, 40, 30]
|
||||
line "cats" [20, 40, 0, 30]
|
||||
line "birds" [30, 60, 50, 30]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a mix of multiple bar and line plots', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
xychart-beta horizontal
|
||||
line [23, 46, 77, 34]
|
||||
line [45, 32, 33, 12]
|
||||
bar [87, 54, 99, 85]
|
||||
line [78, 88, 22, 4]
|
||||
line [22, 29, 75, 33]
|
||||
bar [52, 96, 35, 10]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -52,7 +52,7 @@
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts Bar with multiple category</h1>
|
||||
<h1>XY Charts bar with single dataset</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with many categories"
|
||||
@@ -61,7 +61,28 @@
|
||||
bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts line with multiple category</h1>
|
||||
<h1>XY Charts bar with multiple datasets</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
bar "dogs" [0, 60, 40, 30]
|
||||
bar "cats" [20, 40, 50, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts bar horizontal with multiple datasets</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta horizontal
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [0, 60, 40, 30]
|
||||
bar "cats" [20, 40, 50, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts line single dataset</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Line chart with many category"
|
||||
@@ -70,7 +91,7 @@
|
||||
line "sample line" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts category with large text</h1>
|
||||
<h1>XY Charts bar with large text</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with many categories with category overlap"
|
||||
|
@@ -19,4 +19,4 @@ The `parseError` function will not be called.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64)
|
||||
[mermaidAPI.ts:65](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L65)
|
||||
|
@@ -18,4 +18,4 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L71)
|
||||
[mermaidAPI.ts:72](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L72)
|
||||
|
@@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L94)
|
||||
[mermaidAPI.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L95)
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L84)
|
||||
[mermaidAPI.ts:85](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L85)
|
||||
|
||||
---
|
||||
|
||||
@@ -63,4 +63,4 @@ The svg code for the rendered graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80)
|
||||
[mermaidAPI.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L81)
|
||||
|
@@ -26,7 +26,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L74)
|
||||
[mermaidAPI.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L75)
|
||||
|
||||
## Variables
|
||||
|
||||
@@ -155,7 +155,7 @@ the cleaned up svgCode
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L222)
|
||||
[mermaidAPI.ts:223](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L223)
|
||||
|
||||
---
|
||||
|
||||
@@ -180,7 +180,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:153](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L153)
|
||||
[mermaidAPI.ts:154](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L154)
|
||||
|
||||
---
|
||||
|
||||
@@ -203,7 +203,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L199)
|
||||
[mermaidAPI.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L200)
|
||||
|
||||
---
|
||||
|
||||
@@ -230,7 +230,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:138](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L138)
|
||||
[mermaidAPI.ts:139](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L139)
|
||||
|
||||
---
|
||||
|
||||
@@ -252,7 +252,6 @@ Put the svgCode into an iFrame. Return the iFrame code
|
||||
`string`
|
||||
|
||||
- the code with the iFrame that now contains the svgCode
|
||||
TODO replace btoa(). Replace with buf.toString('base64')?
|
||||
|
||||
#### Defined in
|
||||
|
||||
|
@@ -206,18 +206,20 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
There are six types of arrows currently supported:
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| ------ | ------------------------------------------------ |
|
||||
| `->` | Solid line without arrow |
|
||||
| `-->` | Dotted line without arrow |
|
||||
| `->>` | Solid line with arrowhead |
|
||||
| `-->>` | Dotted line with arrowhead |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
| Type | Description |
|
||||
| -------- | ------------------------------------------------------------------------ |
|
||||
| `->` | Solid line without arrow |
|
||||
| `-->` | Dotted line without arrow |
|
||||
| `->>` | Solid line with arrowhead |
|
||||
| `-->>` | Dotted line with arrowhead |
|
||||
| `<<->>` | Solid line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
|
||||
| `<<-->>` | Dotted line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
## Activations
|
||||
|
||||
@@ -304,17 +306,35 @@ sequenceDiagram
|
||||
Note over Alice,John: A typical interaction
|
||||
```
|
||||
|
||||
It is also possible to add a line break (applies to text input in general):
|
||||
## Line breaks
|
||||
|
||||
Line break can be added to Note and Message:
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
Alice->John: Hello John, how are you?
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
Alice->John: Hello John, how are you?
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
Line breaks in Actor names requires aliases:
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice as Alice<br/>Johnson
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice as Alice<br/>Johnson
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
|
@@ -6,12 +6,54 @@
|
||||
|
||||
# XY Chart
|
||||
|
||||
> In the context of mermaid-js, the XY chart is a comprehensive charting module that encompasses various types of charts that utilize both x-axis and y-axis for data representation. Presently, it includes two fundamental chart types: the bar chart and the line chart. These charts are designed to visually display and analyze data that involve two numerical variables.
|
||||
> In the context of mermaid-js, the XY chart is a comprehensive charting module that encompasses various types of charts that utilize both x-axis and y-axis for data representation. Presently, it includes two fundamental chart types: the bar chart and the line chart. These charts are designed to display one or more datasets containing categories of data.
|
||||
|
||||
> It's important to note that while the current implementation of mermaid-js includes these two chart types, the framework is designed to be dynamic and adaptable. Therefore, it has the capacity for expansion and the inclusion of additional chart types in the future. This means that users can expect an evolving suite of charting options within the XY chart module, catering to various data visualization needs as new chart types are introduced over time.
|
||||
|
||||
## Example
|
||||
|
||||
### bar chart displaying single dataset
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
x-axis [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]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
x-axis [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]
|
||||
```
|
||||
|
||||
### bar chart displaying 3 datasets
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [40, 20, 40, 30]
|
||||
bar "cats" [20, 40, 50, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [40, 20, 40, 30]
|
||||
bar "cats" [20, 40, 50, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
```
|
||||
|
||||
### combined bar/line chart displaying 2 datasets
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
|
@@ -39,6 +39,26 @@ describe('flowchart-elk detector', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
// The error from the issue was reproduced with mindmap, so this is just an example
|
||||
// what matters is the keyword somewhere inside graph definition
|
||||
it('should check only the beginning of the line in search of keywords', () => {
|
||||
expect(
|
||||
detector('mindmap ["Descendant node in flowchart"]', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
detector('mindmap ["Descendant node in graph"]', {
|
||||
flowchart: {
|
||||
defaultRenderer: 'elk',
|
||||
},
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect flowchart-elk', () => {
|
||||
expect(detector('flowchart-elk')).toBe(true);
|
||||
});
|
||||
|
@@ -11,7 +11,7 @@ const detector: DiagramDetector = (txt, config): boolean => {
|
||||
// If diagram explicitly states flowchart-elk
|
||||
/^\s*flowchart-elk/.test(txt) ||
|
||||
// If a flowchart/graph diagram has their default renderer set to elk
|
||||
(/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
(/^\s*(flowchart|graph)/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@@ -256,7 +256,7 @@ boundaryStartStatement
|
||||
|
||||
boundaryStart
|
||||
: ENTERPRISE_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
|
||||
| SYSTEM_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
|
||||
| SYSTEM_BOUNDARY attributes {$2.splice(2, 0, 'SYSTEM'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
|
||||
| BOUNDARY attributes {yy.addPersonOrSystemBoundary(...$2); $$=$2;}
|
||||
| CONTAINER_BOUNDARY attributes {$2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
|
||||
| NODE attributes {yy.addDeploymentNode('node', ...$2); $$=$2;}
|
||||
|
@@ -33,7 +33,7 @@
|
||||
"actor" { this.begin('ID'); return 'participant_actor'; }
|
||||
"create" return 'create';
|
||||
"destroy" { this.begin('ID'); return 'destroy'; }
|
||||
<ID>[^\->:\n,;]+?([\-]*[^\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ID>[^\<->\->:\n,;]+?([\-]*[^\<->\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
@@ -73,9 +73,11 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
"off" return 'off';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^\+\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
[^\+\<->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\<->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
"<<-->>" return 'BIDIRECTIONAL_DOTTED_ARROW';
|
||||
"->" return 'SOLID_OPEN_ARROW';
|
||||
"-->" return 'DOTTED_OPEN_ARROW';
|
||||
\-[x] return 'SOLID_CROSS';
|
||||
@@ -310,7 +312,9 @@ signaltype
|
||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
|
||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
|
||||
| SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; }
|
||||
|
@@ -328,6 +328,8 @@ export const LINETYPE = {
|
||||
BREAK_START: 30,
|
||||
BREAK_END: 31,
|
||||
PAR_OVER_START: 32,
|
||||
BIDIRECTIONAL_SOLID: 33,
|
||||
BIDIRECTIONAL_DOTTED: 34,
|
||||
};
|
||||
|
||||
export const ARROWTYPE = {
|
||||
|
@@ -516,6 +516,36 @@ Alice->>Bob:Hello Bob, how are you?`;
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
});
|
||||
it('should handle bidirectional arrow messages', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice<<->>Bob:Hello Bob, how are you?`;
|
||||
|
||||
await mermaidAPI.parse(str);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Alice').description).toBe('Alice');
|
||||
expect(actors.get('Bob').description).toBe('Bob');
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.BIDIRECTIONAL_SOLID);
|
||||
});
|
||||
it('should handle bidirectional dotted arrow messages', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice<<-->>Bob:Hello Bob, how are you?`;
|
||||
|
||||
await mermaidAPI.parse(str);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Alice').description).toBe('Alice');
|
||||
expect(actors.get('Bob').description).toBe('Bob');
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.BIDIRECTIONAL_DOTTED);
|
||||
});
|
||||
it('should handle actor activation', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
|
@@ -436,7 +436,8 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.DOTTED ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_OPEN
|
||||
type === diagObj.db.LINETYPE.DOTTED_OPEN ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||
) {
|
||||
line.style('stroke-dasharray', '3, 3');
|
||||
line.attr('class', 'messageLine1');
|
||||
@@ -462,6 +463,13 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#arrowhead)');
|
||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||
}
|
||||
if (type === diagObj.db.LINETYPE.SOLID_POINT || type === diagObj.db.LINETYPE.DOTTED_POINT) {
|
||||
line.attr('marker-end', 'url(' + url + '#filled-head)');
|
||||
}
|
||||
@@ -1036,6 +1044,8 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
diagObj.db.LINETYPE.SOLID_POINT,
|
||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
sequenceIndex = sequenceIndex + sequenceIndexStep;
|
||||
@@ -1416,6 +1426,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
diagObj.db.LINETYPE.SOLID_POINT,
|
||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
return {};
|
||||
@@ -1423,7 +1435,7 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
const [fromLeft, fromRight] = activationBounds(msg.from, actors);
|
||||
const [toLeft, toRight] = activationBounds(msg.to, actors);
|
||||
const isArrowToRight = fromLeft <= toLeft;
|
||||
const startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
@@ -1462,6 +1474,17 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
|
||||
stopx += adjustValue(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten start position of bidirectional arrow to accommodate for second arrowhead
|
||||
*/
|
||||
if (
|
||||
[diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID, diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(
|
||||
msg.type
|
||||
)
|
||||
) {
|
||||
startx -= adjustValue(3);
|
||||
}
|
||||
}
|
||||
|
||||
const allBounds = [fromLeft, fromRight, toLeft, toRight];
|
||||
|
@@ -415,11 +415,11 @@ const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 80;
|
||||
|
||||
elem.lower();
|
||||
const line = elem.append('g').lower();
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
elem
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
@@ -735,7 +735,7 @@ export const insertArrowHead = function (elem) {
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto')
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M -1 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
@@ -0,0 +1,5 @@
|
||||
/*eslint-disable no-restricted-syntax */
|
||||
export enum PlotType {
|
||||
BAR = 'bar',
|
||||
LINE = 'line',
|
||||
}
|
@@ -3,7 +3,7 @@ import type { Axis } from '../axis/index.js';
|
||||
|
||||
export class BarPlot {
|
||||
constructor(
|
||||
private barData: BarPlotData,
|
||||
private barData: BarPlotData[],
|
||||
private boundingRect: BoundingRect,
|
||||
private xAxis: Axis,
|
||||
private yAxis: Axis,
|
||||
@@ -12,49 +12,85 @@ export class BarPlot {
|
||||
) {}
|
||||
|
||||
getDrawableElement(): DrawableElem[] {
|
||||
const finalData: [number, number][] = this.barData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
const offset = new Array(this.barData[0].data.length).fill(0);
|
||||
const enlarge = new Array(this.barData[0].data.length).fill(0);
|
||||
return this.barData.map((barData, dataIndex) => {
|
||||
const finalData: [number, number][] = barData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
|
||||
const barPaddingPercent = 0.05;
|
||||
const barPaddingPercent = 0.05;
|
||||
|
||||
const barWidth =
|
||||
Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
|
||||
(1 - barPaddingPercent);
|
||||
const barWidthHalf = barWidth / 2;
|
||||
const barWidth =
|
||||
Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
|
||||
(1 - barPaddingPercent);
|
||||
const barWidthHalf = barWidth / 2;
|
||||
|
||||
if (this.orientation === 'horizontal') {
|
||||
return [
|
||||
{
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}`],
|
||||
if (this.orientation === 'horizontal') {
|
||||
return {
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}-${dataIndex}`],
|
||||
type: 'rect',
|
||||
data: finalData.map((data) => ({
|
||||
x: this.boundingRect.x,
|
||||
y: data[0] - barWidthHalf,
|
||||
height: barWidth,
|
||||
width: data[1] - this.boundingRect.x,
|
||||
fill: this.barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: this.barData.fill,
|
||||
})),
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}`],
|
||||
data: finalData.map((data, index) => {
|
||||
const adjustForAxisOuterPadding = dataIndex > 0 ? this.yAxis.getAxisOuterPadding() : 0;
|
||||
let x = offset[index] + this.boundingRect.x;
|
||||
let width = data[1] - this.boundingRect.x - adjustForAxisOuterPadding;
|
||||
if (enlarge[index] > 0) {
|
||||
x -= enlarge[index];
|
||||
width += enlarge[index];
|
||||
enlarge[index] = 0;
|
||||
offset[index] -= adjustForAxisOuterPadding;
|
||||
}
|
||||
offset[index] += width;
|
||||
if (barData.data[index][1] === 0 && enlarge[index] === 0) {
|
||||
enlarge[index] = width;
|
||||
}
|
||||
if (barData.data[index][1] === 0) {
|
||||
width = 0;
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y: data[0] - barWidthHalf,
|
||||
height: barWidth,
|
||||
width,
|
||||
fill: barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: barData.fill,
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
return {
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}-${dataIndex}`],
|
||||
type: 'rect',
|
||||
data: finalData.map((data) => ({
|
||||
x: data[0] - barWidthHalf,
|
||||
y: data[1],
|
||||
width: barWidth,
|
||||
height: this.boundingRect.y + this.boundingRect.height - data[1],
|
||||
fill: this.barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: this.barData.fill,
|
||||
})),
|
||||
},
|
||||
];
|
||||
data: finalData.map((data, index) => {
|
||||
const adjustForAxisOuterPadding = dataIndex > 0 ? this.yAxis.getAxisOuterPadding() : 0;
|
||||
const y = data[1] - offset[index] + adjustForAxisOuterPadding;
|
||||
let height =
|
||||
this.boundingRect.y + this.boundingRect.height - data[1] - adjustForAxisOuterPadding;
|
||||
if (enlarge[index] > 0) {
|
||||
height += enlarge[index];
|
||||
enlarge[index] = 0;
|
||||
offset[index] -= adjustForAxisOuterPadding;
|
||||
}
|
||||
offset[index] += height;
|
||||
if (barData.data[index][1] === 0 && enlarge[index] === 0) {
|
||||
enlarge[index] = height;
|
||||
}
|
||||
if (barData.data[index][1] === 0) {
|
||||
height = 0;
|
||||
}
|
||||
return {
|
||||
x: data[0] - barWidthHalf,
|
||||
y,
|
||||
width: barWidth,
|
||||
height,
|
||||
fill: barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: barData.fill,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -6,11 +6,14 @@ import type {
|
||||
Point,
|
||||
XYChartThemeConfig,
|
||||
XYChartConfig,
|
||||
BarPlotData,
|
||||
LinePlotData,
|
||||
} from '../../interfaces.js';
|
||||
import type { Axis } from '../axis/index.js';
|
||||
import type { ChartComponent } from '../../interfaces.js';
|
||||
import { LinePlot } from './linePlot.js';
|
||||
import { BarPlot } from './barPlot.js';
|
||||
import { PlotType } from './PlotType.js';
|
||||
|
||||
export interface Plot extends ChartComponent {
|
||||
setAxes(xAxis: Axis, yAxis: Axis): void;
|
||||
@@ -55,34 +58,35 @@ export class BasePlot implements Plot {
|
||||
throw Error('Axes must be passed to render Plots');
|
||||
}
|
||||
const drawableElem: DrawableElem[] = [];
|
||||
for (const [i, plot] of this.chartData.plots.entries()) {
|
||||
switch (plot.type) {
|
||||
case 'line':
|
||||
{
|
||||
const linePlot = new LinePlot(
|
||||
plot,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
i
|
||||
);
|
||||
drawableElem.push(...linePlot.getDrawableElement());
|
||||
}
|
||||
break;
|
||||
case 'bar':
|
||||
{
|
||||
const barPlot = new BarPlot(
|
||||
plot,
|
||||
this.boundingRect,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
i
|
||||
);
|
||||
drawableElem.push(...barPlot.getDrawableElement());
|
||||
}
|
||||
break;
|
||||
}
|
||||
const linePlots = this.chartData.plots.filter(
|
||||
(plot) => plot.type === PlotType.LINE
|
||||
) as LinePlotData[];
|
||||
const barPlots = this.chartData.plots.filter(
|
||||
(plot) => plot.type === PlotType.BAR
|
||||
) as BarPlotData[];
|
||||
|
||||
let plotIndex = 0;
|
||||
if (linePlots.length) {
|
||||
const linePlot = new LinePlot(
|
||||
linePlots,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
plotIndex
|
||||
);
|
||||
drawableElem.push(...linePlot.getDrawableElement());
|
||||
}
|
||||
if (barPlots.length) {
|
||||
const barPlot = new BarPlot(
|
||||
barPlots,
|
||||
this.boundingRect,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
plotIndex
|
||||
);
|
||||
drawableElem.push(...barPlot.getDrawableElement());
|
||||
plotIndex++;
|
||||
}
|
||||
return drawableElem;
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import type { Axis } from '../axis/index.js';
|
||||
|
||||
export class LinePlot {
|
||||
constructor(
|
||||
private plotData: LinePlotData,
|
||||
private plotData: LinePlotData[],
|
||||
private xAxis: Axis,
|
||||
private yAxis: Axis,
|
||||
private orientation: XYChartConfig['chartOrientation'],
|
||||
@@ -12,36 +12,40 @@ export class LinePlot {
|
||||
) {}
|
||||
|
||||
getDrawableElement(): DrawableElem[] {
|
||||
const finalData: [number, number][] = this.plotData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
|
||||
let path: string | null;
|
||||
if (this.orientation === 'horizontal') {
|
||||
path = line()
|
||||
.y((d) => d[0])
|
||||
.x((d) => d[1])(finalData);
|
||||
} else {
|
||||
path = line()
|
||||
.x((d) => d[0])
|
||||
.y((d) => d[1])(finalData);
|
||||
}
|
||||
if (!path) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
const drawables: DrawableElem[] = [];
|
||||
this.plotData.forEach((plotData, dataIndex) => {
|
||||
{
|
||||
groupTexts: ['plot', `line-plot-${this.plotIndex}`],
|
||||
type: 'path',
|
||||
data: [
|
||||
{
|
||||
path,
|
||||
strokeFill: this.plotData.strokeFill,
|
||||
strokeWidth: this.plotData.strokeWidth,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const finalData: [number, number][] = plotData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
|
||||
let path: string | null;
|
||||
if (this.orientation === 'horizontal') {
|
||||
path = line()
|
||||
.y((d) => d[0])
|
||||
.x((d) => d[1])(finalData);
|
||||
} else {
|
||||
path = line()
|
||||
.x((d) => d[0])
|
||||
.y((d) => d[1])(finalData);
|
||||
}
|
||||
if (!path) {
|
||||
return [];
|
||||
}
|
||||
drawables.push({
|
||||
groupTexts: ['plot', `line-plot-${this.plotIndex}-${dataIndex}`],
|
||||
type: 'path',
|
||||
data: [
|
||||
{
|
||||
path,
|
||||
strokeFill: plotData.strokeFill,
|
||||
strokeWidth: plotData.strokeWidth,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
return drawables;
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { PlotType } from './components/plot/PlotType.js';
|
||||
|
||||
export interface XYChartAxisThemeConfig {
|
||||
titleColor: string;
|
||||
labelColor: string;
|
||||
@@ -28,14 +30,14 @@ export interface ChartComponent {
|
||||
export type SimplePlotDataType = [string, number][];
|
||||
|
||||
export interface LinePlotData {
|
||||
type: 'line';
|
||||
type: PlotType.LINE;
|
||||
strokeFill: string;
|
||||
strokeWidth: number;
|
||||
data: SimplePlotDataType;
|
||||
}
|
||||
|
||||
export interface BarPlotData {
|
||||
type: 'bar';
|
||||
type: PlotType.BAR;
|
||||
fill: string;
|
||||
data: SimplePlotDataType;
|
||||
}
|
||||
@@ -43,7 +45,7 @@ export interface BarPlotData {
|
||||
export type PlotData = LinePlotData | BarPlotData;
|
||||
|
||||
export function isBarPlot(data: PlotData): data is BarPlotData {
|
||||
return data.type === 'bar';
|
||||
return data.type === PlotType.BAR;
|
||||
}
|
||||
|
||||
export interface BandAxisDataType {
|
||||
|
@@ -33,384 +33,388 @@ describe('Testing xychart jison file', () => {
|
||||
clearMocks();
|
||||
});
|
||||
|
||||
it('should throw error if xychart-beta text is not there', () => {
|
||||
const str = 'xychart-beta-1';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
|
||||
it('should not throw error if only xychart is there', () => {
|
||||
const str = 'xychart-beta';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
});
|
||||
|
||||
it('parse title of the chart within "', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('oneLinertitle');
|
||||
});
|
||||
|
||||
it('parse chart orientation', () => {
|
||||
const str = 'xychart-beta vertical';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
|
||||
});
|
||||
|
||||
it('parse chart orientation with spaces', () => {
|
||||
let str = 'xychart-beta horizontal ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
|
||||
|
||||
str = 'xychart-beta abc';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
|
||||
it('parse x-axis', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
describe('single dataset', () => {
|
||||
it('should throw error if xychart-beta text is not there', () => {
|
||||
const str = 'xychart-beta-1';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name without "', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
it('should not throw error if only xychart is there', () => {
|
||||
const str = 'xychart-beta';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name with "', () => {
|
||||
const str = 'xychart-beta \n x-axis "xAxisName has space"\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName has space',
|
||||
type: 'text',
|
||||
it('parse title of the chart within "', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('oneLinertitle');
|
||||
});
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name with " with spaces', () => {
|
||||
const str = 'xychart-beta \n x-axis " xAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' xAxisName has space ',
|
||||
type: 'text',
|
||||
it('parse chart orientation', () => {
|
||||
const str = 'xychart-beta vertical';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
|
||||
});
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 0.34);
|
||||
});
|
||||
it('parse chart orientation with spaces', () => {
|
||||
let str = 'xychart-beta horizontal ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
|
||||
|
||||
it('parse x-axis without axisname and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis 45.5 --> 1.34 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
type: 'text',
|
||||
str = 'xychart-beta abc';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 1.34);
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{
|
||||
text: 'cat1',
|
||||
it('parse x-axis', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
},
|
||||
{ text: 'cat2a', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis without axisname and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{
|
||||
text: 'cat1',
|
||||
|
||||
it('parse x-axis with axis name without "', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
},
|
||||
{ text: 'cat2a', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis throw error if unbalanced bracket', () => {
|
||||
let str = 'xychart-beta \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str = 'xychart-beta \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`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{ text: 'category1', type: 'text' },
|
||||
{ text: 'category 2', type: 'text' },
|
||||
{ text: 'category3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 2', () => {
|
||||
const str =
|
||||
'xychart-beta \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([
|
||||
{ text: 'cat1 with space', type: 'text' },
|
||||
{ text: 'cat2', type: 'text' },
|
||||
{ text: 'cat3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 3', () => {
|
||||
const str =
|
||||
'xychart-beta \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([
|
||||
{ text: 'cat1 with space', type: 'text' },
|
||||
{ text: 'cat2asdf', type: 'text' },
|
||||
{ text: 'cat3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse y-axis with axis name', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'yAxisName has space',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with " and spaces', () => {
|
||||
const str = 'xychart-beta \n y-axis " yAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' yAxisName has space ',
|
||||
type: 'text',
|
||||
|
||||
it('parse x-axis with axis name with "', () => {
|
||||
const str = 'xychart-beta \n x-axis "xAxisName has space"\n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName has space',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with range data', () => {
|
||||
const str = 'xychart-beta \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 axisname with range data', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse both axis at once', () => {
|
||||
const str = 'xychart-beta\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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle with space', type: 'text' },
|
||||
[23, -45, 56.6]
|
||||
);
|
||||
});
|
||||
it('parse line Data without title', () => {
|
||||
const str =
|
||||
'xychart-beta\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' });
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: '', type: 'text' },
|
||||
[23, -45, 56.6, 0.33]
|
||||
);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\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" ';
|
||||
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" [ ] ';
|
||||
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 ] ';
|
||||
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 ] ';
|
||||
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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle', type: 'text' },
|
||||
[23, 45, 56.6, 0.22]
|
||||
);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle with space', type: 'text' },
|
||||
[23, -45, 56.6]
|
||||
);
|
||||
});
|
||||
it('parse bar Data without plot title', () => {
|
||||
const str =
|
||||
'xychart-beta\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' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\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" ';
|
||||
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" [ ] ';
|
||||
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 ] ';
|
||||
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 ] ';
|
||||
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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle1', type: 'text' },
|
||||
[11, 45.5, 67, 23]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle2', type: 'text' },
|
||||
[45, 99, 12]
|
||||
);
|
||||
});
|
||||
it('parse multiple bar and line variant 2', () => {
|
||||
const str = `
|
||||
|
||||
it('parse x-axis with axis name with " with spaces', () => {
|
||||
const str = 'xychart-beta \n x-axis " xAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' xAxisName has space ',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 0.34);
|
||||
});
|
||||
|
||||
it('parse x-axis without axisname and range data', () => {
|
||||
const str = 'xychart-beta \nx-axis 45.5 --> 1.34 \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 1.34);
|
||||
});
|
||||
|
||||
it('parse x-axis with axis name and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'xAxisName',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{
|
||||
text: 'cat1',
|
||||
type: 'text',
|
||||
},
|
||||
{ text: 'cat2a', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis without axisname and category data', () => {
|
||||
const str = 'xychart-beta \nx-axis [ "cat1" , cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||
text: '',
|
||||
type: 'text',
|
||||
});
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{
|
||||
text: 'cat1',
|
||||
type: 'text',
|
||||
},
|
||||
{ text: 'cat2a', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis throw error if unbalanced bracket', () => {
|
||||
let str = 'xychart-beta \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str = 'xychart-beta \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`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{ text: 'category1', type: 'text' },
|
||||
{ text: 'category 2', type: 'text' },
|
||||
{ text: 'category3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 2', () => {
|
||||
const str =
|
||||
'xychart-beta \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([
|
||||
{ text: 'cat1 with space', type: 'text' },
|
||||
{ text: 'cat2', type: 'text' },
|
||||
{ text: 'cat3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse x-axis complete variant 3', () => {
|
||||
const str =
|
||||
'xychart-beta \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([
|
||||
{ text: 'cat1 with space', type: 'text' },
|
||||
{ text: 'cat2asdf', type: 'text' },
|
||||
{ text: 'cat3', type: 'text' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('parse y-axis with axis name', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: 'yAxisName has space',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with " and spaces', () => {
|
||||
const str = 'xychart-beta \n y-axis " yAxisName has space " \n';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||
text: ' yAxisName has space ',
|
||||
type: 'text',
|
||||
});
|
||||
});
|
||||
it('parse y-axis with axis name with range data', () => {
|
||||
const str = 'xychart-beta \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 axisname with range data', () => {
|
||||
const str = 'xychart-beta \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';
|
||||
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';
|
||||
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';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
});
|
||||
it('parse both axis at once', () => {
|
||||
const str = 'xychart-beta\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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle with space', type: 'text' },
|
||||
[23, -45, 56.6]
|
||||
);
|
||||
});
|
||||
it('parse line Data without title', () => {
|
||||
const str =
|
||||
'xychart-beta\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' });
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: '', type: 'text' },
|
||||
[23, -45, 56.6, 0.33]
|
||||
);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\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" ';
|
||||
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" [ ] ';
|
||||
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 ] ';
|
||||
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 ] ';
|
||||
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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle', type: 'text' },
|
||||
[23, 45, 56.6, 0.22]
|
||||
);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle with space', type: 'text' },
|
||||
[23, -45, 56.6]
|
||||
);
|
||||
});
|
||||
it('parse bar Data without plot title', () => {
|
||||
const str =
|
||||
'xychart-beta\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' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]);
|
||||
});
|
||||
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 ] ';
|
||||
expect(parserFnConstructor(str)).toThrow();
|
||||
str =
|
||||
'xychart-beta\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" ';
|
||||
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" [ ] ';
|
||||
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 ] ';
|
||||
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 ] ';
|
||||
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]';
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle1', type: 'text' },
|
||||
[11, 45.5, 67, 23]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle2', type: 'text' },
|
||||
[45, 99, 12]
|
||||
);
|
||||
});
|
||||
it('parse multiple bar and line variant 2', () => {
|
||||
const str = `
|
||||
xychart-beta horizontal
|
||||
title Basic xychart
|
||||
x-axis "this is x axis" [category1, "category 2", category3]
|
||||
@@ -419,30 +423,81 @@ describe('Testing xychart jison file', () => {
|
||||
line lineTitle1 [11, 45.5, 67, 23]
|
||||
bar barTitle2 [13, 42, 56.89]
|
||||
line lineTitle2 [45, 99, 012]`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yaxisText', type: 'text' });
|
||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(10, 150);
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{ text: 'category1', type: 'text' },
|
||||
{ text: 'category 2', type: 'text' },
|
||||
{ text: 'category3', type: 'text' },
|
||||
]);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle1', type: 'text' },
|
||||
[11, 45.5, 67, 23]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle2', type: 'text' },
|
||||
[45, 99, 12]
|
||||
);
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yaxisText', type: 'text' });
|
||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(10, 150);
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||
{ text: 'category1', type: 'text' },
|
||||
{ text: 'category 2', type: 'text' },
|
||||
{ text: 'category3', type: 'text' },
|
||||
]);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle1', type: 'text' },
|
||||
[11, 45.5, 67, 23]
|
||||
);
|
||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||
{ text: 'lineTitle2', type: 'text' },
|
||||
[45, 99, 12]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple datasets', () => {
|
||||
it('parse 2 datasets', () => {
|
||||
const str = `xychart-beta
|
||||
x-axis xAxisName
|
||||
y-axis yAxisName
|
||||
bar "barTitle1" [23, 45, 56.6]
|
||||
bar "barTitle2" [13, 42, 56.89]`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
});
|
||||
|
||||
it('parse 3 datasets', () => {
|
||||
const str = `xychart-beta
|
||||
x-axis xAxisName
|
||||
y-axis yAxisName
|
||||
bar "barTitle1" [23, 45, 56.6]
|
||||
bar "barTitle2" [13, 42, 56.89]
|
||||
bar "barTitle3" [18, 37, 56.1]`;
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||
expect(mockDB.setBarData).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
{ text: 'barTitle1', type: 'text' },
|
||||
[23, 45, 56.6]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
{ text: 'barTitle2', type: 'text' },
|
||||
[13, 42, 56.89]
|
||||
);
|
||||
expect(mockDB.setBarData).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
{ text: 'barTitle3', type: 'text' },
|
||||
[18, 37, 56.1]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -22,6 +22,7 @@ import type {
|
||||
} from './chartBuilder/interfaces.js';
|
||||
import { isBandAxisData, isLinearAxisData } from './chartBuilder/interfaces.js';
|
||||
import type { Group } from '../../diagram-api/types.js';
|
||||
import { PlotType } from './chartBuilder/components/plot/PlotType.js';
|
||||
|
||||
let plotIndex = 0;
|
||||
|
||||
@@ -34,6 +35,8 @@ let plotColorPalette = xyChartThemeConfig.plotColorPalette.split(',').map((color
|
||||
let hasSetXAxis = false;
|
||||
let hasSetYAxis = false;
|
||||
|
||||
let dataSets: number[][] = [];
|
||||
|
||||
interface NormalTextType {
|
||||
type: 'text';
|
||||
text: string;
|
||||
@@ -57,7 +60,7 @@ function getChartDefaultData(): XYChartData {
|
||||
yAxis: {
|
||||
type: 'linear',
|
||||
title: '',
|
||||
min: Infinity,
|
||||
min: 0,
|
||||
max: -Infinity,
|
||||
},
|
||||
xAxis: {
|
||||
@@ -109,20 +112,26 @@ function setYAxisRangeData(min: number, max: number) {
|
||||
}
|
||||
|
||||
// this function does not set `hasSetYAxis` as there can be multiple data so we should calculate the range accordingly
|
||||
function setYAxisRangeFromPlotData(data: number[]) {
|
||||
const minValue = Math.min(...data);
|
||||
const maxValue = Math.max(...data);
|
||||
const prevMinValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.min : Infinity;
|
||||
const prevMaxValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.max : -Infinity;
|
||||
function setYAxisRangeFromPlotData(data: number[], plotType: PlotType) {
|
||||
const sum = new Array(data.length).fill(0);
|
||||
if (plotType === PlotType.BAR) {
|
||||
dataSets.push(data);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
for (const entry of dataSets) {
|
||||
sum[i] += entry[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xyChartData.yAxis = {
|
||||
type: 'linear',
|
||||
title: xyChartData.yAxis.title,
|
||||
min: Math.min(prevMinValue, minValue),
|
||||
max: Math.max(prevMaxValue, maxValue),
|
||||
min: isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.min : Math.min(...sum),
|
||||
max: Math.max(...sum),
|
||||
};
|
||||
}
|
||||
|
||||
function transformDataWithoutCategory(data: number[]): SimplePlotDataType {
|
||||
function transformDataWithoutCategory(data: number[], plotType: PlotType): SimplePlotDataType {
|
||||
let retData: SimplePlotDataType = [];
|
||||
if (data.length === 0) {
|
||||
return retData;
|
||||
@@ -133,22 +142,22 @@ function transformDataWithoutCategory(data: number[]): SimplePlotDataType {
|
||||
setXAxisRangeData(Math.min(prevMinValue, 1), Math.max(prevMaxValue, data.length));
|
||||
}
|
||||
if (!hasSetYAxis) {
|
||||
setYAxisRangeFromPlotData(data);
|
||||
setYAxisRangeFromPlotData(data, plotType);
|
||||
}
|
||||
|
||||
if (isBandAxisData(xyChartData.xAxis)) {
|
||||
retData = xyChartData.xAxis.categories.map((c, i) => [c, data[i]]);
|
||||
retData = xyChartData.xAxis.categories.map((c, i) => [c, data[i] ?? 0]);
|
||||
}
|
||||
|
||||
if (isLinearAxisData(xyChartData.xAxis)) {
|
||||
const min = xyChartData.xAxis.min;
|
||||
const max = xyChartData.xAxis.max;
|
||||
const step = (max - min + 1) / data.length;
|
||||
const step = (max - min) / (data.length - 1);
|
||||
const categories: string[] = [];
|
||||
for (let i = min; i <= max; i += step) {
|
||||
categories.push(`${i}`);
|
||||
}
|
||||
retData = categories.map((c, i) => [c, data[i]]);
|
||||
retData = categories.map((c, i) => [c, data[i] ?? 0]);
|
||||
}
|
||||
|
||||
return retData;
|
||||
@@ -159,9 +168,9 @@ function getPlotColorFromPalette(plotIndex: number): string {
|
||||
}
|
||||
|
||||
function setLineData(title: NormalTextType, data: number[]) {
|
||||
const plotData = transformDataWithoutCategory(data);
|
||||
const plotData = transformDataWithoutCategory(data, PlotType.LINE);
|
||||
xyChartData.plots.push({
|
||||
type: 'line',
|
||||
type: PlotType.LINE,
|
||||
strokeFill: getPlotColorFromPalette(plotIndex),
|
||||
strokeWidth: 2,
|
||||
data: plotData,
|
||||
@@ -170,9 +179,9 @@ function setLineData(title: NormalTextType, data: number[]) {
|
||||
}
|
||||
|
||||
function setBarData(title: NormalTextType, data: number[]) {
|
||||
const plotData = transformDataWithoutCategory(data);
|
||||
const plotData = transformDataWithoutCategory(data, PlotType.BAR);
|
||||
xyChartData.plots.push({
|
||||
type: 'bar',
|
||||
type: PlotType.BAR,
|
||||
fill: getPlotColorFromPalette(plotIndex),
|
||||
data: plotData,
|
||||
});
|
||||
@@ -204,6 +213,7 @@ const clear = function () {
|
||||
plotColorPalette = xyChartThemeConfig.plotColorPalette.split(',').map((color) => color.trim());
|
||||
hasSetXAxis = false;
|
||||
hasSetYAxis = false;
|
||||
dataSets = [];
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@@ -141,18 +141,20 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
There are six types of arrows currently supported:
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| ------ | ------------------------------------------------ |
|
||||
| `->` | Solid line without arrow |
|
||||
| `-->` | Dotted line without arrow |
|
||||
| `->>` | Solid line with arrowhead |
|
||||
| `-->>` | Dotted line with arrowhead |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
| Type | Description |
|
||||
| -------- | ----------------------------------------------------------------------- |
|
||||
| `->` | Solid line without arrow |
|
||||
| `-->` | Dotted line without arrow |
|
||||
| `->>` | Solid line with arrowhead |
|
||||
| `-->>` | Dotted line with arrowhead |
|
||||
| `<<->>` | Solid line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
|
||||
| `<<-->>` | Dotted line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
## Activations
|
||||
|
||||
@@ -205,11 +207,22 @@ sequenceDiagram
|
||||
Note over Alice,John: A typical interaction
|
||||
```
|
||||
|
||||
It is also possible to add a line break (applies to text input in general):
|
||||
## Line breaks
|
||||
|
||||
Line break can be added to Note and Message:
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
Alice->John: Hello John, how are you?
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
Line breaks in Actor names requires aliases:
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice as Alice<br/>Johnson
|
||||
Alice->John: Hello John,<br/>how are you?
|
||||
Note over Alice,John: A typical interaction<br/>But now in two lines
|
||||
```
|
||||
|
||||
|
@@ -1,11 +1,35 @@
|
||||
# XY Chart
|
||||
|
||||
> In the context of mermaid-js, the XY chart is a comprehensive charting module that encompasses various types of charts that utilize both x-axis and y-axis for data representation. Presently, it includes two fundamental chart types: the bar chart and the line chart. These charts are designed to visually display and analyze data that involve two numerical variables.
|
||||
> In the context of mermaid-js, the XY chart is a comprehensive charting module that encompasses various types of charts that utilize both x-axis and y-axis for data representation. Presently, it includes two fundamental chart types: the bar chart and the line chart. These charts are designed to display one or more datasets containing categories of data.
|
||||
|
||||
> It's important to note that while the current implementation of mermaid-js includes these two chart types, the framework is designed to be dynamic and adaptable. Therefore, it has the capacity for expansion and the inclusion of additional chart types in the future. This means that users can expect an evolving suite of charting options within the XY chart module, catering to various data visualization needs as new chart types are introduced over time.
|
||||
|
||||
## Example
|
||||
|
||||
### bar chart displaying single dataset
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
x-axis [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]
|
||||
```
|
||||
|
||||
### bar chart displaying 3 datasets
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4]
|
||||
y-axis Animals 0 --> 160
|
||||
bar "dogs" [40, 20, 40, 30]
|
||||
bar "cats" [20, 40, 50, 30]
|
||||
bar "birds" [30, 60, 50, 30]
|
||||
```
|
||||
|
||||
### combined bar/line chart displaying 2 datasets
|
||||
|
||||
```mermaid-example
|
||||
xychart-beta
|
||||
title "Sales Revenue"
|
||||
|
@@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
|
||||
[Error: Parse error on line 2:
|
||||
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
||||
----------------------^
|
||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
`);
|
||||
});
|
||||
|
||||
|
@@ -69,6 +69,7 @@ vi.mock('stylis', () => {
|
||||
import { compile, serialize } from 'stylis';
|
||||
import { decodeEntities, encodeEntities } from './utils.js';
|
||||
import { Diagram } from './Diagram.js';
|
||||
import { toBase64 } from './utils/base64.js';
|
||||
|
||||
/**
|
||||
* @see https://vitest.dev/guide/mocking.html Mock part of a module
|
||||
@@ -176,7 +177,7 @@ describe('mermaidAPI', () => {
|
||||
});
|
||||
|
||||
describe('putIntoIFrame', () => {
|
||||
const inputSvgCode = 'this is the SVG code';
|
||||
const inputSvgCode = 'this is the SVG code ⛵';
|
||||
|
||||
it('uses the default SVG iFrame height is used if no svgElement given', () => {
|
||||
const result = putIntoIFrame(inputSvgCode);
|
||||
@@ -199,11 +200,10 @@ describe('mermaidAPI', () => {
|
||||
});
|
||||
|
||||
it('sets src to base64 version of <body style="IFRAME_SVG_BODY_STYLE">svgCode<//body>', () => {
|
||||
const base64encodedSrc = btoa('<body style="' + 'margin:0' + '">' + inputSvgCode + '</body>');
|
||||
const expectedRegExp = new RegExp('src="data:text/html;base64,' + base64encodedSrc + '"');
|
||||
|
||||
const base64encodedSrc = toBase64(`<body style="margin:0">${inputSvgCode}</body>`);
|
||||
const expectedSrc = `src="data:text/html;charset=UTF-8;base64,${base64encodedSrc}"`;
|
||||
const result = putIntoIFrame(inputSvgCode);
|
||||
expect(result).toMatch(expectedRegExp);
|
||||
expect(result).toContain(expectedSrc);
|
||||
});
|
||||
|
||||
it('uses the height and appends px from the svgElement given', () => {
|
||||
|
@@ -31,6 +31,7 @@ import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.
|
||||
import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js';
|
||||
import { preprocessDiagram } from './preprocess.js';
|
||||
import { decodeEntities } from './utils.js';
|
||||
import { toBase64 } from './utils/base64.js';
|
||||
|
||||
const MAX_TEXTLENGTH = 50_000;
|
||||
const MAX_TEXTLENGTH_EXCEEDED_MSG =
|
||||
@@ -248,14 +249,13 @@ export const cleanUpSvgCode = (
|
||||
* @param svgCode - the svg code to put inside the iFrame
|
||||
* @param svgElement - the d3 node that has the current svgElement so we can get the height from it
|
||||
* @returns - the code with the iFrame that now contains the svgCode
|
||||
* TODO replace btoa(). Replace with buf.toString('base64')?
|
||||
*/
|
||||
export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => {
|
||||
const height = svgElement?.viewBox?.baseVal?.height
|
||||
? svgElement.viewBox.baseVal.height + 'px'
|
||||
: IFRAME_HEIGHT;
|
||||
const base64encodedSrc = btoa('<body style="' + IFRAME_BODY_STYLE + '">' + svgCode + '</body>');
|
||||
return `<iframe style="width:${IFRAME_WIDTH};height:${height};${IFRAME_STYLES}" src="data:text/html;base64,${base64encodedSrc}" sandbox="${IFRAME_SANDBOX_OPTS}">
|
||||
const base64encodedSrc = toBase64(`<body style="${IFRAME_BODY_STYLE}">${svgCode}</body>`);
|
||||
return `<iframe style="width:${IFRAME_WIDTH};height:${height};${IFRAME_STYLES}" src="data:text/html;charset=UTF-8;base64,${base64encodedSrc}" sandbox="${IFRAME_SANDBOX_OPTS}">
|
||||
${IFRAME_NOT_SUPPORTED_MSG}
|
||||
</iframe>`;
|
||||
};
|
||||
|
6
packages/mermaid/src/utils/base64.ts
Normal file
6
packages/mermaid/src/utils/base64.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function toBase64(str: string) {
|
||||
// ref: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
|
||||
const utf8Bytes = new TextEncoder().encode(str);
|
||||
const utf8Str = Array.from(utf8Bytes, (byte) => String.fromCodePoint(byte)).join('');
|
||||
return btoa(utf8Str);
|
||||
}
|
Reference in New Issue
Block a user