Compare commits

..

72 Commits

Author SHA1 Message Date
Sidharth Vinod
4f9cf4f9fc Merge branch 'develop' of https://github.com/mermaid-js/mermaid into xychart
* 'develop' of https://github.com/mermaid-js/mermaid: (546 commits)
  rebuild
  chore: Use string templates
  chore: Update docs
  chore: Fix docs
  chore: Add argos token to cypress config.
  chore: Remove cy.get('svg') calls
  chore: fix Argos parallel
  chore: Support local screenshot testing without applitools or argos
  chore: Skip checking drupal links
  chore: Remove reference screenshot generation from E2E
  chore: Remove cytoscape patch.
  chore(argos): disable matchImageSnapshot
  chore(argos): put parallel mode only when necessary
  chore(argos): setup parallel mode
  chore: setup Argos Visual Testing on E2E
  Fixed linters
  Added more specs for elk detector
  Fixed wrong elk detector, check only beginning of the line for diagram keywords
  Removed unused patch
  Fix cytoscape patch
  ...
2024-06-21 10:24:58 +05:30
Sidharth Vinod
9f375139d5 Merge pull request #5556 from OG-NI/bug/5555_xychart_incorrect_spacing
[XYChart] fixed incorrect spacing between data points
2024-06-21 03:39:47 +00:00
Ingo
0c49d2b84e Merge branch 'develop' into bug/5555_xychart_incorrect_spacing 2024-06-20 20:49:00 +02:00
OG-NI
42414e85d1 rebuild 2024-06-20 20:38:51 +02:00
Sidharth Vinod
1e43ad1ee3 Merge pull request #5520 from iansan5653/fix-sandbox-utf16
Fix `sandbox` mode with UTF-16 characters
2024-06-20 18:07:40 +00:00
Sidharth Vinod
cda41a1cdf Merge pull request #5209 from Ronid1/feature/4051_sequence_diagram-multi-directional-arrow
Feature/4051 sequence diagram multi directional arrow
2024-06-20 18:07:17 +00:00
Ronid1
1a199d630f Merge branch 'develop' of https://github.com/mermaid-js/mermaid into feature/4051_sequence_diagram-multi-directional-arrow 2024-06-20 10:25:42 -07:00
Sidharth Vinod
51c07163aa Merge branch 'develop' into pr/iansan5653/5520
* develop:
  chore: Update docs
  chore: Add argos token to cypress config.
  chore: Remove cy.get('svg') calls
  Explain line breaks in `sequenceDiagram.md`
  add integration test
  fix note z position
  Correct the System_Boundary stereotype
2024-06-20 22:48:45 +05:30
Sidharth Vinod
9bbd3cab3c chore: Use string templates 2024-06-20 22:48:28 +05:30
Sidharth Vinod
6f61a71dda Merge branch 'develop' into bug/5555_xychart_incorrect_spacing 2024-06-20 22:31:03 +05:30
Sidharth Vinod
3af4020cdc Merge pull request #5570 from abitrolly/patch-1
Explain line breaks in `sequenceDiagram.md`
2024-06-20 22:16:34 +05:30
Sidharth Vinod
d65e78f9e2 chore: Update docs 2024-06-20 22:15:52 +05:30
Sidharth Vinod
82b120e567 Merge branch 'develop' into patch-1 2024-06-20 22:14:38 +05:30
Nikolay Rozhkov
d95c159b1f Merge pull request #5243 from jonmcewen/c4-sys-boundary-stereotype
Correct the System_Boundary stereotype
2024-06-20 15:14:20 +00:00
Nikolay Rozhkov
c468319869 Merge branch 'develop' into c4-sys-boundary-stereotype 2024-06-20 17:36:02 +03:00
Sidharth Vinod
4b21e1e745 Merge pull request #5564 from Ronid1/bug/5525_sequence_diagram_fix_note_z_position
Bug/5525 sequence diagram fix note z position
2024-06-20 13:51:21 +00:00
Sidharth Vinod
fb1942c2cf Merge branch 'develop' into bug/5525_sequence_diagram_fix_note_z_position 2024-06-20 18:44:17 +05:30
Sidharth Vinod
81d8b9d02e chore: Fix docs 2024-06-20 18:41:11 +05:30
Sidharth Vinod
6db070197a Merge branch 'develop' into fix-sandbox-utf16 2024-06-20 18:35:29 +05:30
Sidharth Vinod
a331125187 Merge pull request #5586 from mermaid-js/sidv/cleanupCy
Cleanup Cypress tests
2024-06-20 13:04:42 +00:00
Sidharth Vinod
66bc461fa1 chore: Add argos token to cypress config.
This token is not sensitive, and is required for argos to run in fork PRs.
2024-06-20 18:26:19 +05:30
Sidharth Vinod
df72febc00 Merge pull request #5579 from mermaid-js/bug/5507_fixed-wrong-elk-detector
Fixed wrong ELK detector
2024-06-20 12:47:57 +00:00
Sidharth Vinod
5aced51f9e chore: Remove cy.get('svg') calls 2024-06-20 17:05:00 +05:30
Sidharth Vinod
fe9fbd8618 Merge pull request #5581 from gregberge/fix-argos-parallel
chore: fix Argos parallel
2024-06-20 16:15:36 +05:30
Greg Bergé
b031c6f182 chore: fix Argos parallel 2024-06-20 12:11:53 +02:00
Sidharth Vinod
dc51a8f182 Merge branch 'develop' into fix-sandbox-utf16 2024-06-20 14:48:39 +05:30
Nikolay Rozhkov
66cd0b9621 Fixed linters 2024-06-19 22:53:55 +03:00
Nikolay Rozhkov
6382dcf7c8 Added more specs for elk detector 2024-06-19 22:36:13 +03:00
Nikolay Rozhkov
5587011f75 Fixed wrong elk detector, check only beginning of the line for diagram keywords 2024-06-19 22:19:50 +03:00
Anatoli Babenia
c904c7d21a Explain line breaks in sequenceDiagram.md
Closes https://github.com/mermaid-js/mermaid/issues/4351
2024-06-15 12:29:30 +03:00
Ronid1
b285466130 add integration test 2024-06-06 18:33:55 -07:00
Ronid1
3754ac0872 fix note z position 2024-06-06 18:15:11 -07:00
Ronid1
83ca6897bd fix tests 2024-06-04 15:23:57 -07:00
Ronid1
d2d7f2bcb0 update arrow startx position 2024-06-04 15:10:50 -07:00
Ronid1
20f9abcc38 move arrowhead adjustment to buildMessageModel 2024-06-04 14:58:47 -07:00
Ronid1
0417a8ddff Merge branch 'develop' of https://github.com/mermaid-js/mermaid into feature/4051_sequence_diagram-multi-directional-arrow 2024-06-04 14:40:39 -07:00
OG-NI
46fe731379 fixed incorrect spacing, added e2e-test 2024-06-01 21:48:34 +02:00
Nikolay Rozhkov
0e63233845 Merge branch 'develop' into c4-sys-boundary-stereotype 2024-05-30 01:52:56 +03:00
Ian Sanders
e26dea6416 Format 2024-05-14 15:07:31 -04:00
Ian Sanders
3b2b8dacd8 Replace regex with contain match 2024-05-14 15:02:14 -04:00
Ian Sanders
df94d3994d Format 2024-05-14 14:34:10 -04:00
Ian Sanders
6f56d94c64 Fix test 2024-05-14 14:30:13 -04:00
Ian Sanders
56c4f10607 Add charset=UTF-8 2024-05-14 14:08:35 -04:00
Ian Sanders
dfa71317ad Encode string to UTF-8 before encoding to Base64 2024-05-14 13:57:32 -04:00
Ronid1
17fd681bdb fix arrow pointer x position 2024-04-24 12:53:40 -07:00
Ronid1
e852156b9f add bidirectional arrow to sequence diagram 2024-04-23 20:36:58 -07:00
Sidharth Vinod
90be8dedf6 Merge pull request #5167 from camueller/feature/xychart_multiple_datasets
xychart: support for multiple datasets added
2024-02-05 13:06:45 +05:30
Sidharth Vinod
8691874dbb Merge branch 'develop' into c4-sys-boundary-stereotype 2024-02-01 17:36:58 +05:30
Sidharth Vinod
f1490ff679 Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-31 17:09:56 +05:30
Axel Müller
25160d9688 axis calculation fixed for mix of line and bar charts 2024-01-27 17:11:40 +01:00
Axel Müller
533a921ef5 axis calculation fixed 2024-01-27 15:21:27 +01:00
Axel Müller
3bef03f568 Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-27 14:07:51 +01:00
Axel Müller
737f4f0cf3 axis calculation fixed 2024-01-27 14:06:30 +01:00
Jon McEwen
db92b5a219 Correct the System_Boundary stereotype 2024-01-26 16:15:12 +00:00
Axel Müller
71e5a2b3a3 Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-24 19:13:49 +01:00
Axel Müller
54f1435839 axis calculation fixed 2024-01-24 19:07:00 +01:00
Axel Müller
48a20c5cb8 more tests added 2024-01-22 15:59:33 +01:00
Axel Müller
5f4f1cc08d Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-20 10:25:55 +01:00
Axel Müller
da0a4ae37d multiple line charts fixed 2024-01-20 08:46:39 +01:00
Axel Müller
2972012059 use edge case for better coverage 2024-01-16 18:41:30 +01:00
Axel Müller
cf641ba4fd Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-16 18:17:32 +01:00
Axel Müller
39e5064019 Merge branch 'develop' into feature/xychart_multiple_datasets 2024-01-13 13:47:26 +01:00
Axel Müller
7830d0c4bf fix 0 values 2024-01-13 13:39:55 +01:00
Axel Müller
60d34bdc72 fix missing values 2024-01-13 13:30:18 +01:00
Axel Müller
3262a06a8e fix 0 values 2024-01-13 11:54:14 +01:00
Axel Müller
506314598e review findings 2024-01-13 07:39:58 +01:00
Axel Müller
25a9479acf documentation updated 2024-01-08 17:13:59 +01:00
Axel Müller
1273f440a8 e2e tests added 2024-01-08 16:41:53 +01:00
Axel Müller
e1d085925e parser fixed for > 2 datasets
some unit tests added
2024-01-07 17:10:36 +01:00
Axel Müller
39d175314c formatting fixed 2024-01-07 07:33:32 +01:00
Axel Müller
17426f0a97 unit tests fixed 2024-01-07 07:21:04 +01:00
Axel Müller
a36fa7cd2f support for multiple datasets added 2023-12-27 12:13:30 +01:00
42 changed files with 1115 additions and 781 deletions

View File

@@ -131,7 +131,7 @@ jobs:
VITEST_COVERAGE: true VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }} CYPRESS_COMMIT: ${{ github.sha }}
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }} ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
ARGOS_PARALLEL: ${{ env.CYPRESS_RECORD_KEY != '' }} ARGOS_PARALLEL: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
ARGOS_PARALLEL_TOTAL: 4 ARGOS_PARALLEL_TOTAL: 4
ARGOS_PARALLEL_INDEX: ${{ matrix.containers }} ARGOS_PARALLEL_INDEX: ${{ matrix.containers }}

View File

@@ -21,13 +21,11 @@ export default eyesPlugin(
}); });
// copy any needed variables from process.env to config.env // copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false; 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) { if (config.env.useArgos) {
// Argos
registerArgosTask(on, config, { registerArgosTask(on, config, {
uploadToArgos: !!process.env.CI, token: 'fc3a35cf5200db928d65b2047861582d9444032b',
token: process.env.ARGOS_TOKEN,
}); });
} else { } else {
addMatchImageSnapshotPlugin(on, config); addMatchImageSnapshotPlugin(on, config);

View File

@@ -119,7 +119,6 @@ describe('Configuration', () => {
const url = 'http://localhost:9000/regression/issue-1874.html'; const url = 'http://localhost:9000/regression/issue-1874.html';
cy.visit(url); cy.visit(url);
cy.window().should('have.property', 'rendered', true); cy.window().should('have.property', 'rendered', true);
cy.get('svg').should('be.visible');
verifyScreenshot( verifyScreenshot(
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives' 'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
); );

View File

@@ -10,7 +10,6 @@ describe('XSS', () => {
cy.wait(1000).then(() => { cy.wait(1000).then(() => {
cy.get('.mermaid').should('exist'); cy.get('.mermaid').should('exist');
}); });
cy.get('svg');
}); });
it('should not allow tags in the css', () => { it('should not allow tags in the css', () => {

View File

@@ -30,7 +30,6 @@ describe('C4 diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render a simple C4Container diagram', () => { it('should render a simple C4Container diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -50,7 +49,6 @@ describe('C4 diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render a simple C4Component diagram', () => { it('should render a simple C4Component diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -69,7 +67,6 @@ describe('C4 diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render a simple C4Dynamic diagram', () => { it('should render a simple C4Dynamic diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -93,7 +90,6 @@ describe('C4 diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render a simple C4Deployment diagram', () => { it('should render a simple C4Deployment diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -117,6 +113,5 @@ describe('C4 diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
}); });

View File

@@ -32,7 +32,6 @@ describe('Class diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('2: should render a simple class diagrams with cardinality', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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', () => { 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)', () => { // it('17: should render a class diagram when useMaxWidth is true (default)', () => {
@@ -421,7 +405,6 @@ describe('Class diagram', () => {
`, `,
{ logLevel: 1 } { logLevel: 1 }
); );
cy.get('svg');
}); });
it('should render class diagram with newlines in title', () => { it('should render class diagram with newlines in title', () => {
@@ -439,7 +422,6 @@ describe('Class diagram', () => {
+quack() +quack()
} }
`); `);
cy.get('svg');
}); });
it('should render class diagram with many newlines in title', () => { it('should render class diagram with many newlines in title', () => {

View File

@@ -218,7 +218,6 @@ describe('Entity Relationship Diagram', () => {
`, `,
{ loglevel: 1 } { loglevel: 1 }
); );
cy.get('svg');
}); });
it('should render entities with keys', () => { it('should render entities with keys', () => {

View File

@@ -8,7 +8,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render a complete quadrant chart', () => { it('should render a complete quadrant chart', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -30,7 +29,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render without points', () => { it('should render without points', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -46,7 +44,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should able to render y-axix on right side', () => { it('should able to render y-axix on right side', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -63,7 +60,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should able to render x-axix on bottom', () => { it('should able to render x-axix on bottom', () => {
imgSnapshotTest( 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', () => { it('should able to render x-axix on bottom and y-axis on right', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -97,7 +92,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should render without title', () => { it('should render without title', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -112,7 +106,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should use all the config', () => { it('should use all the config', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -135,7 +128,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should use all the theme variable', () => { it('should use all the theme variable', () => {
imgSnapshotTest( 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', () => { it('should render x-axis labels in the center, if x-axis has two labels', () => {
imgSnapshotTest( 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', () => { it('should render y-axis labels in the center, if y-axis has two labels', () => {
imgSnapshotTest( 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', () => { it('should render both axes labels on the left and bottom, if both axes have only one label', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -224,7 +213,6 @@ describe('Quadrant Chart', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('it should render data points with styles', () => { 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', () => { it('it should render data points with styles + classes', () => {

View File

@@ -44,6 +44,5 @@ describe('Requirement diagram', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
}); });

View File

@@ -1,4 +1,4 @@
/// <reference types="Cypress" /> // <reference types="Cypress" />
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
@@ -68,6 +68,19 @@ context('Sequence diagram', () => {
{ sequence: { actorFontFamily: 'courier' } } { 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', () => { it('should handle different line breaks', () => {
imgSnapshotTest( 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', () => { it('should render long messages from an actor to the left to one to the right', () => {
imgSnapshotTest( imgSnapshotTest(
` `

View File

@@ -8,7 +8,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 1, fontFamily: 'courier' } { logLevel: 1, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a simple state diagrams', () => { it('v2 should render a simple state diagrams', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -20,7 +19,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a long descriptions instead of id when available', () => { it('v2 should render a long descriptions instead of id when available', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -32,7 +30,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a long descriptions with additional descriptions', () => { it('v2 should render a long descriptions with additional descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -44,7 +41,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a single state with short descriptions', () => { it('v2 should render a single state with short descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -55,7 +51,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a transition descriptions with new lines', () => { it('v2 should render a transition descriptions with new lines', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -69,7 +64,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a state with a note', () => { it('v2 should render a state with a note', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -83,7 +77,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a state with on the left side when so specified', () => { it('v2 should render a state with on the left side when so specified', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -97,7 +90,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a state with a note together with another state', () => { it('v2 should render a state with a note together with another state', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -113,7 +105,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a note with multiple lines in it', () => { it('v2 should render a note with multiple lines in it', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -156,7 +147,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a simple state diagrams 2', () => { it('v2 should render a simple state diagrams 2', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -169,7 +159,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a simple state diagrams with labels', () => { it('v2 should render a simple state diagrams with labels', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -185,7 +174,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render state descriptions', () => { it('v2 should render state descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -198,7 +186,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render composite states', () => { it('v2 should render composite states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -217,7 +204,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render multiple composite states', () => { it('v2 should render multiple composite states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -287,7 +273,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render concurrency states', () => { it('v2 should render concurrency states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -311,7 +296,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('v2 should render a state with states in it', () => { it('v2 should render a state with states in it', () => {
imgSnapshotTest( imgSnapshotTest(

View File

@@ -10,7 +10,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a long descriptions instead of id when available', () => { it('should render a long descriptions instead of id when available', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -22,7 +21,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a long descriptions with additional descriptions', () => { it('should render a long descriptions with additional descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -34,7 +32,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a single state with short descriptions', () => { it('should render a single state with short descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -45,7 +42,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a transition descriptions with new lines', () => { it('should render a transition descriptions with new lines', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -59,7 +55,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a state with a note', () => { it('should render a state with a note', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -73,7 +68,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a state with on the left side when so specified', () => { it('should render a state with on the left side when so specified', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -87,7 +81,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a state with a note together with another state', () => { it('should render a state with a note together with another state', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -103,7 +96,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a note with multiple lines in it', () => { it('should render a note with multiple lines in it', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -146,7 +138,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a simple state diagrams 2', () => { it('should render a simple state diagrams 2', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -159,7 +150,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a simple state diagrams with labels', () => { it('should render a simple state diagrams with labels', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -175,7 +165,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render state descriptions', () => { it('should render state descriptions', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -188,7 +177,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render composite states', () => { it('should render composite states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -207,7 +195,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render multiple composit states', () => { it('should render multiple composit states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -277,7 +264,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render concurrency states', () => { it('should render concurrency states', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -301,7 +287,6 @@ describe('State diagram', () => {
`, `,
{ logLevel: 0, fontFamily: 'courier' } { logLevel: 0, fontFamily: 'courier' }
); );
cy.get('svg');
}); });
it('should render a state with states in it', () => { it('should render a state with states in it', () => {
imgSnapshotTest( imgSnapshotTest(

View File

@@ -10,7 +10,6 @@ describe('themeCSS balancing, it', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
it('should not allow unbalanced CSS definitions 2', () => { it('should not allow unbalanced CSS definitions 2', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -21,7 +20,6 @@ describe('themeCSS balancing, it', () => {
`, `,
{} {}
); );
cy.get('svg');
}); });
}); });
@@ -45,7 +43,6 @@ describe('Pie Chart', () => {
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a flowchart diagram', () => { it('should render a flowchart diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -70,7 +67,6 @@ describe('Pie Chart', () => {
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a new flowchart diagram', () => { it('should render a new flowchart diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -96,7 +92,6 @@ describe('Pie Chart', () => {
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a sequence diagram', () => { it('should render a sequence diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -125,7 +120,6 @@ describe('Pie Chart', () => {
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a class diagram', () => { it('should render a class diagram', () => {
@@ -175,7 +169,6 @@ describe('Pie Chart', () => {
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a state diagram', () => { it('should render a state diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -210,7 +203,6 @@ stateDiagram
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a state diagram (v2)', () => { it('should render a state diagram (v2)', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -245,7 +237,6 @@ stateDiagram-v2
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a er diagram', () => { it('should render a er diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -266,7 +257,6 @@ erDiagram
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a user journey diagram', () => { it('should render a user journey diagram', () => {
imgSnapshotTest( imgSnapshotTest(
@@ -287,7 +277,6 @@ erDiagram
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
it('should render a gantt diagram', () => { it('should render a gantt diagram', () => {
cy.clock(new Date('2014-01-06').getTime()); cy.clock(new Date('2014-01-06').getTime());
@@ -326,7 +315,6 @@ erDiagram
`, `,
{ theme } { theme }
); );
cy.get('svg');
}); });
}); });
}); });

View File

@@ -1,19 +1,19 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
describe('XY Chart', () => { describe('XY Chart', () => {
it('should render the simplest possible chart', () => { describe('single dataset', () => {
imgSnapshotTest( it('should render the simplest possible chart', () => {
` imgSnapshotTest(
`
xychart-beta xychart-beta
line [10, 30, 20] line [10, 30, 20]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Should render a complete chart', () => {
it('Should render a complete chart', () => { imgSnapshotTest(
imgSnapshotTest( `
`
xychart-beta xychart-beta
title "Sales Revenue" title "Sales Revenue"
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] 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] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
}); });
it('Should render a chart without title', () => { it('Should render a chart without title', () => {
imgSnapshotTest( imgSnapshotTest(
` `
xychart-beta xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis "Revenue (in $)" 4000 --> 11000 y-axis "Revenue (in $)" 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('y-axis title not required', () => {
it('y-axis title not required', () => { imgSnapshotTest(
imgSnapshotTest( `
`
xychart-beta xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]
y-axis 4000 --> 11000 y-axis 4000 --> 11000
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] 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', () => {
it('Should render a chart without y-axis with different range', () => { imgSnapshotTest(
imgSnapshotTest( `
`
xychart-beta xychart-beta
x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] 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] 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] line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('x axis title not required', () => {
it('x axis title not required', () => { imgSnapshotTest(
imgSnapshotTest( `
`
xychart-beta xychart-beta
x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] 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] 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] line [2000, 7000, 6500, 9200, 9500, 7500, 11000, 10200, 3200, 8500, 7000, 8800]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Decimals and negative numbers are supported', () => {
it('Multiple plots can be rendered', () => { imgSnapshotTest(
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(
`
xychart-beta xychart-beta
y-axis -2.4 --> 3.5 y-axis -2.4 --> 3.5
line [+1.3, .6, 2.4, -.34] line [+1.3, .6, 2.4, -.34]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render spark line with "plotReservedSpacePercent"', () => {
it('Render spark line with "plotReservedSpacePercent"', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
theme: dark theme: dark
@@ -114,13 +94,12 @@ describe('XY Chart', () => {
xychart-beta xychart-beta
line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800] line [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render spark bar without displaying other property', () => {
it('Render spark bar without displaying other property', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
theme: dark theme: dark
@@ -141,13 +120,12 @@ describe('XY Chart', () => {
xychart-beta xychart-beta
bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800] bar [5000, 9000, 7500, 6200, 9500, 5500, 11000, 8200, 9200, 9500, 7000, 8800]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Should use all the config from directive', () => {
it('Should use all the config from directive', () => { imgSnapshotTest(
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 }}}%% %%{init: {"xyChart": {"width": 1000, "height": 600, "titlePadding": 5, "titleFontSize": 10, "xAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "yAxis": {"labelFontSize": "20", "labelPadding": 10, "titleFontSize": 30, "titlePadding": 20, "tickLength": 10, "tickWidth": 5}, "plotBorderWidth": 5, "chartOrientation": "horizontal", "plotReservedSpacePercent": 60 }}}%%
xychart-beta xychart-beta
title "Sales Revenue" title "Sales Revenue"
@@ -156,13 +134,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Should use all the config from yaml', () => {
it('Should use all the config from yaml', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
theme: forest theme: forest
@@ -197,13 +174,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render with show axis title false', () => {
it('Render with show axis title false', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
xyChart: xyChart:
@@ -219,13 +195,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render with show axis label false', () => {
it('Render with show axis label false', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
xyChart: xyChart:
@@ -241,13 +216,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render with show axis tick false', () => {
it('Render with show axis tick false', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
xyChart: xyChart:
@@ -263,13 +237,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render with show axis line false', () => {
it('Render with show axis line false', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
xyChart: xyChart:
@@ -285,13 +258,12 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]
`, `,
{} {}
); );
cy.get('svg'); });
}); it('Render all the theme color', () => {
it('Render all the theme color', () => { imgSnapshotTest(
imgSnapshotTest( `
`
--- ---
config: config:
themeVariables: themeVariables:
@@ -315,8 +287,110 @@ describe('XY Chart', () => {
bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] 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] 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');
});
});
}); });
}); });

View File

@@ -52,7 +52,7 @@
line [+1.3, .6, 2.4, -.34] line [+1.3, .6, 2.4, -.34]
</pre> </pre>
<h1>XY Charts Bar with multiple category</h1> <h1>XY Charts bar with single dataset</h1>
<pre class="mermaid"> <pre class="mermaid">
xychart-beta xychart-beta
title "Basic xychart with many categories" title "Basic xychart with many categories"
@@ -61,7 +61,28 @@
bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99] bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99]
</pre> </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"> <pre class="mermaid">
xychart-beta xychart-beta
title "Line chart with many category" title "Line chart with many category"
@@ -70,7 +91,7 @@
line "sample line" [52, 96, 35, 10, 87, 34, 67, 99] line "sample line" [52, 96, 35, 10, 87, 34, 67, 99]
</pre> </pre>
<h1>XY Charts category with large text</h1> <h1>XY Charts bar with large text</h1>
<pre class="mermaid"> <pre class="mermaid">
xychart-beta xychart-beta
title "Basic xychart with many categories with category overlap" title "Basic xychart with many categories with category overlap"

View File

@@ -19,4 +19,4 @@ The `parseError` function will not be called.
#### Defined in #### 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)

View File

@@ -18,4 +18,4 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
#### Defined in #### 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)

View File

@@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
#### Defined in #### 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 #### 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 #### 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)

View File

@@ -26,7 +26,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
#### Defined in #### 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 ## Variables
@@ -155,7 +155,7 @@ the cleaned up svgCode
#### Defined in #### 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 #### 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 #### 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 #### 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` `string`
- the code with the iFrame that now contains the svgCode - the code with the iFrame that now contains the svgCode
TODO replace btoa(). Replace with buf.toString('base64')?
#### Defined in #### Defined in

View File

@@ -206,18 +206,20 @@ Messages can be of two displayed either solid or with a dotted line.
[Actor][Arrow][Actor]:Message text [Actor][Arrow][Actor]:Message text
``` ```
There are six types of arrows currently supported: There are ten types of arrows currently supported:
| Type | Description | | Type | Description |
| ------ | ------------------------------------------------ | | -------- | ------------------------------------------------------------------------ |
| `->` | Solid line without arrow | | `->` | Solid line without arrow |
| `-->` | Dotted line without arrow | | `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead | | `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead | | `-->>` | Dotted line with arrowhead |
| `-x` | Solid line with a cross at the end | | `<<->>` | Solid line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
| `--x` | Dotted line with a cross at the end. | | `<<-->>` | Dotted line with bidirectional arrowheads (v\<MERMAID_RELEASE_VERSION>+) |
| `-)` | Solid line with an open arrow at the end (async) | | `-x` | Solid line with a cross at the end |
| `--)` | Dotted line with a open arrow at the end (async) | | `--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 ## Activations
@@ -304,17 +306,35 @@ sequenceDiagram
Note over Alice,John: A typical interaction 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 ```mermaid-example
sequenceDiagram 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 Note over Alice,John: A typical interaction<br/>But now in two lines
``` ```
```mermaid ```mermaid
sequenceDiagram 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 Note over Alice,John: A typical interaction<br/>But now in two lines
``` ```

View File

@@ -6,12 +6,54 @@
# XY Chart # 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. > 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 ## 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 ```mermaid-example
xychart-beta xychart-beta
title "Sales Revenue" title "Sales Revenue"

View File

@@ -39,6 +39,26 @@ describe('flowchart-elk detector', () => {
).toBe(true); ).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', () => { it('should detect flowchart-elk', () => {
expect(detector('flowchart-elk')).toBe(true); expect(detector('flowchart-elk')).toBe(true);
}); });

View File

@@ -11,7 +11,7 @@ const detector: DiagramDetector = (txt, config): boolean => {
// If diagram explicitly states flowchart-elk // If diagram explicitly states flowchart-elk
/^\s*flowchart-elk/.test(txt) || /^\s*flowchart-elk/.test(txt) ||
// If a flowchart/graph diagram has their default renderer set to elk // 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; return true;
} }

View File

@@ -256,7 +256,7 @@ boundaryStartStatement
boundaryStart boundaryStart
: ENTERPRISE_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;} : 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;} | BOUNDARY attributes {yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {$2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;} | CONTAINER_BOUNDARY attributes {$2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {yy.addDeploymentNode('node', ...$2); $$=$2;} | NODE attributes {yy.addDeploymentNode('node', ...$2); $$=$2;}

View File

@@ -33,7 +33,7 @@
"actor" { this.begin('ID'); return 'participant_actor'; } "actor" { this.begin('ID'); return 'participant_actor'; }
"create" return 'create'; "create" return 'create';
"destroy" { this.begin('ID'); return 'destroy'; } "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>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; } <ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
"loop" { this.begin('LINE'); return 'loop'; } "loop" { this.begin('LINE'); return 'loop'; }
@@ -73,9 +73,11 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
"off" return 'off'; "off" return 'off';
"," return ','; "," return ',';
";" return 'NEWLINE'; ";" return 'NEWLINE';
[^\+\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } [^\+\<->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\<->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
"->>" return 'SOLID_ARROW'; "->>" return 'SOLID_ARROW';
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
"-->>" return 'DOTTED_ARROW'; "-->>" return 'DOTTED_ARROW';
"<<-->>" return 'BIDIRECTIONAL_DOTTED_ARROW';
"->" return 'SOLID_OPEN_ARROW'; "->" return 'SOLID_OPEN_ARROW';
"-->" return 'DOTTED_OPEN_ARROW'; "-->" return 'DOTTED_OPEN_ARROW';
\-[x] return 'SOLID_CROSS'; \-[x] return 'SOLID_CROSS';
@@ -310,7 +312,9 @@ signaltype
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; } : SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; } | DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; } | SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; } | DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; } | SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; } | DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
| SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; } | SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; }

View File

@@ -328,6 +328,8 @@ export const LINETYPE = {
BREAK_START: 30, BREAK_START: 30,
BREAK_END: 31, BREAK_END: 31,
PAR_OVER_START: 32, PAR_OVER_START: 32,
BIDIRECTIONAL_SOLID: 33,
BIDIRECTIONAL_DOTTED: 34,
}; };
export const ARROWTYPE = { export const ARROWTYPE = {

View File

@@ -516,6 +516,36 @@ Alice->>Bob:Hello Bob, how are you?`;
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED); 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 () => { it('should handle actor activation', async () => {
const str = ` const str = `
sequenceDiagram sequenceDiagram

View File

@@ -436,7 +436,8 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
type === diagObj.db.LINETYPE.DOTTED || type === diagObj.db.LINETYPE.DOTTED ||
type === diagObj.db.LINETYPE.DOTTED_CROSS || type === diagObj.db.LINETYPE.DOTTED_CROSS ||
type === diagObj.db.LINETYPE.DOTTED_POINT || 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.style('stroke-dasharray', '3, 3');
line.attr('class', 'messageLine1'); 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) { if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
line.attr('marker-end', 'url(' + url + '#arrowhead)'); 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) { if (type === diagObj.db.LINETYPE.SOLID_POINT || type === diagObj.db.LINETYPE.DOTTED_POINT) {
line.attr('marker-end', 'url(' + url + '#filled-head)'); 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.DOTTED_CROSS,
diagObj.db.LINETYPE.SOLID_POINT, diagObj.db.LINETYPE.SOLID_POINT,
diagObj.db.LINETYPE.DOTTED_POINT, diagObj.db.LINETYPE.DOTTED_POINT,
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
].includes(msg.type) ].includes(msg.type)
) { ) {
sequenceIndex = sequenceIndex + sequenceIndexStep; sequenceIndex = sequenceIndex + sequenceIndexStep;
@@ -1416,6 +1426,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
diagObj.db.LINETYPE.DOTTED_CROSS, diagObj.db.LINETYPE.DOTTED_CROSS,
diagObj.db.LINETYPE.SOLID_POINT, diagObj.db.LINETYPE.SOLID_POINT,
diagObj.db.LINETYPE.DOTTED_POINT, diagObj.db.LINETYPE.DOTTED_POINT,
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
].includes(msg.type) ].includes(msg.type)
) { ) {
return {}; return {};
@@ -1423,7 +1435,7 @@ const buildMessageModel = function (msg, actors, diagObj) {
const [fromLeft, fromRight] = activationBounds(msg.from, actors); const [fromLeft, fromRight] = activationBounds(msg.from, actors);
const [toLeft, toRight] = activationBounds(msg.to, actors); const [toLeft, toRight] = activationBounds(msg.to, actors);
const isArrowToRight = fromLeft <= toLeft; const isArrowToRight = fromLeft <= toLeft;
const startx = isArrowToRight ? fromRight : fromLeft; let startx = isArrowToRight ? fromRight : fromLeft;
let stopx = isArrowToRight ? toLeft : toRight; let stopx = isArrowToRight ? toLeft : toRight;
// As the line width is considered, the left and right values will be off by 2. // 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)) { if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
stopx += adjustValue(3); 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]; const allBounds = [fromLeft, fromRight, toLeft, toRight];

View File

@@ -415,11 +415,11 @@ const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
const center = actor.x + actor.width / 2; const center = actor.x + actor.width / 2;
const centerY = actorY + 80; const centerY = actorY + 80;
elem.lower(); const line = elem.append('g').lower();
if (!isFooter) { if (!isFooter) {
actorCnt++; actorCnt++;
elem line
.append('line') .append('line')
.attr('id', 'actor' + actorCnt) .attr('id', 'actor' + actorCnt)
.attr('x1', center) .attr('x1', center)
@@ -735,7 +735,7 @@ export const insertArrowHead = function (elem) {
.attr('markerUnits', 'userSpaceOnUse') .attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 12) .attr('markerWidth', 12)
.attr('markerHeight', 12) .attr('markerHeight', 12)
.attr('orient', 'auto') .attr('orient', 'auto-start-reverse')
.append('path') .append('path')
.attr('d', 'M -1 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead .attr('d', 'M -1 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead
}; };

View File

@@ -0,0 +1,5 @@
/*eslint-disable no-restricted-syntax */
export enum PlotType {
BAR = 'bar',
LINE = 'line',
}

View File

@@ -3,7 +3,7 @@ import type { Axis } from '../axis/index.js';
export class BarPlot { export class BarPlot {
constructor( constructor(
private barData: BarPlotData, private barData: BarPlotData[],
private boundingRect: BoundingRect, private boundingRect: BoundingRect,
private xAxis: Axis, private xAxis: Axis,
private yAxis: Axis, private yAxis: Axis,
@@ -12,49 +12,85 @@ export class BarPlot {
) {} ) {}
getDrawableElement(): DrawableElem[] { getDrawableElement(): DrawableElem[] {
const finalData: [number, number][] = this.barData.data.map((d) => [ const offset = new Array(this.barData[0].data.length).fill(0);
this.xAxis.getScaleValue(d[0]), const enlarge = new Array(this.barData[0].data.length).fill(0);
this.yAxis.getScaleValue(d[1]), 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 = const barWidth =
Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) * Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
(1 - barPaddingPercent); (1 - barPaddingPercent);
const barWidthHalf = barWidth / 2; const barWidthHalf = barWidth / 2;
if (this.orientation === 'horizontal') { if (this.orientation === 'horizontal') {
return [ return {
{ groupTexts: ['plot', `bar-plot-${this.plotIndex}-${dataIndex}`],
groupTexts: ['plot', `bar-plot-${this.plotIndex}`],
type: 'rect', type: 'rect',
data: finalData.map((data) => ({ data: finalData.map((data, index) => {
x: this.boundingRect.x, const adjustForAxisOuterPadding = dataIndex > 0 ? this.yAxis.getAxisOuterPadding() : 0;
y: data[0] - barWidthHalf, let x = offset[index] + this.boundingRect.x;
height: barWidth, let width = data[1] - this.boundingRect.x - adjustForAxisOuterPadding;
width: data[1] - this.boundingRect.x, if (enlarge[index] > 0) {
fill: this.barData.fill, x -= enlarge[index];
strokeWidth: 0, width += enlarge[index];
strokeFill: this.barData.fill, enlarge[index] = 0;
})), offset[index] -= adjustForAxisOuterPadding;
}, }
]; offset[index] += width;
} if (barData.data[index][1] === 0 && enlarge[index] === 0) {
return [ enlarge[index] = width;
{ }
groupTexts: ['plot', `bar-plot-${this.plotIndex}`], 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', type: 'rect',
data: finalData.map((data) => ({ data: finalData.map((data, index) => {
x: data[0] - barWidthHalf, const adjustForAxisOuterPadding = dataIndex > 0 ? this.yAxis.getAxisOuterPadding() : 0;
y: data[1], const y = data[1] - offset[index] + adjustForAxisOuterPadding;
width: barWidth, let height =
height: this.boundingRect.y + this.boundingRect.height - data[1], this.boundingRect.y + this.boundingRect.height - data[1] - adjustForAxisOuterPadding;
fill: this.barData.fill, if (enlarge[index] > 0) {
strokeWidth: 0, height += enlarge[index];
strokeFill: this.barData.fill, 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,
};
}),
};
});
} }
} }

View File

@@ -6,11 +6,14 @@ import type {
Point, Point,
XYChartThemeConfig, XYChartThemeConfig,
XYChartConfig, XYChartConfig,
BarPlotData,
LinePlotData,
} from '../../interfaces.js'; } from '../../interfaces.js';
import type { Axis } from '../axis/index.js'; import type { Axis } from '../axis/index.js';
import type { ChartComponent } from '../../interfaces.js'; import type { ChartComponent } from '../../interfaces.js';
import { LinePlot } from './linePlot.js'; import { LinePlot } from './linePlot.js';
import { BarPlot } from './barPlot.js'; import { BarPlot } from './barPlot.js';
import { PlotType } from './PlotType.js';
export interface Plot extends ChartComponent { export interface Plot extends ChartComponent {
setAxes(xAxis: Axis, yAxis: Axis): void; setAxes(xAxis: Axis, yAxis: Axis): void;
@@ -55,34 +58,35 @@ export class BasePlot implements Plot {
throw Error('Axes must be passed to render Plots'); throw Error('Axes must be passed to render Plots');
} }
const drawableElem: DrawableElem[] = []; const drawableElem: DrawableElem[] = [];
for (const [i, plot] of this.chartData.plots.entries()) { const linePlots = this.chartData.plots.filter(
switch (plot.type) { (plot) => plot.type === PlotType.LINE
case 'line': ) as LinePlotData[];
{ const barPlots = this.chartData.plots.filter(
const linePlot = new LinePlot( (plot) => plot.type === PlotType.BAR
plot, ) as BarPlotData[];
this.xAxis,
this.yAxis, let plotIndex = 0;
this.chartConfig.chartOrientation, if (linePlots.length) {
i const linePlot = new LinePlot(
); linePlots,
drawableElem.push(...linePlot.getDrawableElement()); this.xAxis,
} this.yAxis,
break; this.chartConfig.chartOrientation,
case 'bar': plotIndex
{ );
const barPlot = new BarPlot( drawableElem.push(...linePlot.getDrawableElement());
plot, }
this.boundingRect, if (barPlots.length) {
this.xAxis, const barPlot = new BarPlot(
this.yAxis, barPlots,
this.chartConfig.chartOrientation, this.boundingRect,
i this.xAxis,
); this.yAxis,
drawableElem.push(...barPlot.getDrawableElement()); this.chartConfig.chartOrientation,
} plotIndex
break; );
} drawableElem.push(...barPlot.getDrawableElement());
plotIndex++;
} }
return drawableElem; return drawableElem;
} }

View File

@@ -4,7 +4,7 @@ import type { Axis } from '../axis/index.js';
export class LinePlot { export class LinePlot {
constructor( constructor(
private plotData: LinePlotData, private plotData: LinePlotData[],
private xAxis: Axis, private xAxis: Axis,
private yAxis: Axis, private yAxis: Axis,
private orientation: XYChartConfig['chartOrientation'], private orientation: XYChartConfig['chartOrientation'],
@@ -12,36 +12,40 @@ export class LinePlot {
) {} ) {}
getDrawableElement(): DrawableElem[] { getDrawableElement(): DrawableElem[] {
const finalData: [number, number][] = this.plotData.data.map((d) => [ const drawables: DrawableElem[] = [];
this.xAxis.getScaleValue(d[0]), this.plotData.forEach((plotData, dataIndex) => {
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 [
{ {
groupTexts: ['plot', `line-plot-${this.plotIndex}`], const finalData: [number, number][] = plotData.data.map((d) => [
type: 'path', this.xAxis.getScaleValue(d[0]),
data: [ this.yAxis.getScaleValue(d[1]),
{ ]);
path,
strokeFill: this.plotData.strokeFill, let path: string | null;
strokeWidth: this.plotData.strokeWidth, 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;
} }
} }

View File

@@ -1,3 +1,5 @@
import { PlotType } from './components/plot/PlotType.js';
export interface XYChartAxisThemeConfig { export interface XYChartAxisThemeConfig {
titleColor: string; titleColor: string;
labelColor: string; labelColor: string;
@@ -28,14 +30,14 @@ export interface ChartComponent {
export type SimplePlotDataType = [string, number][]; export type SimplePlotDataType = [string, number][];
export interface LinePlotData { export interface LinePlotData {
type: 'line'; type: PlotType.LINE;
strokeFill: string; strokeFill: string;
strokeWidth: number; strokeWidth: number;
data: SimplePlotDataType; data: SimplePlotDataType;
} }
export interface BarPlotData { export interface BarPlotData {
type: 'bar'; type: PlotType.BAR;
fill: string; fill: string;
data: SimplePlotDataType; data: SimplePlotDataType;
} }
@@ -43,7 +45,7 @@ export interface BarPlotData {
export type PlotData = LinePlotData | BarPlotData; export type PlotData = LinePlotData | BarPlotData;
export function isBarPlot(data: PlotData): data is BarPlotData { export function isBarPlot(data: PlotData): data is BarPlotData {
return data.type === 'bar'; return data.type === PlotType.BAR;
} }
export interface BandAxisDataType { export interface BandAxisDataType {

View File

@@ -33,384 +33,388 @@ describe('Testing xychart jison file', () => {
clearMocks(); clearMocks();
}); });
it('should throw error if xychart-beta text is not there', () => { describe('single dataset', () => {
const str = 'xychart-beta-1'; it('should throw error if xychart-beta text is not there', () => {
expect(parserFnConstructor(str)).toThrow(); 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',
}); });
});
it('parse x-axis with axis name without "', () => { it('should not throw error if only xychart is there', () => {
const str = 'xychart-beta \nx-axis xAxisName \n'; const str = 'xychart-beta';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
text: 'xAxisName',
type: 'text',
}); });
});
it('parse x-axis with axis name with "', () => { it('parse title of the chart within "', () => {
const str = 'xychart-beta \n x-axis "xAxisName has space"\n'; const str = 'xychart-beta \n title "This is a title"';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('This is a title');
text: 'xAxisName has space', });
type: 'text', 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', () => { it('parse chart orientation', () => {
const str = 'xychart-beta \n x-axis " xAxisName has space " \n'; const str = 'xychart-beta vertical';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
text: ' xAxisName has space ',
type: 'text',
}); });
});
it('parse x-axis with axis name and range data', () => { it('parse chart orientation with spaces', () => {
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n'; let str = 'xychart-beta horizontal ';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
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', () => { str = 'xychart-beta abc';
const str = 'xychart-beta \nx-axis 45.5 --> 1.34 \n'; expect(parserFnConstructor(str)).toThrow();
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', () => { it('parse x-axis', () => {
const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n '; const str = 'xychart-beta \nx-axis xAxisName\n';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
text: 'xAxisName', text: 'xAxisName',
type: 'text',
});
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
{
text: 'cat1',
type: 'text', 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([
{ it('parse x-axis with axis name without "', () => {
text: 'cat1', const str = 'xychart-beta \nx-axis xAxisName \n';
expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
text: 'xAxisName',
type: 'text', 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', () => { it('parse x-axis with axis name with "', () => {
const str = 'xychart-beta \n y-axis " yAxisName has space " \n'; const str = 'xychart-beta \n x-axis "xAxisName has space"\n';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
text: ' yAxisName has space ', text: 'xAxisName has space',
type: 'text', type: 'text',
});
}); });
});
it('parse y-axis with axis name with range data', () => { it('parse x-axis with axis name with " with spaces', () => {
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> 33 \n'; const str = 'xychart-beta \n x-axis " xAxisName has space " \n';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33); text: ' xAxisName has space ',
}); type: 'text',
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' }); it('parse x-axis with axis name and range data', () => {
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33); const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
}); expect(parserFnConstructor(str)).not.toThrow();
it('parse y-axis with axis name with range data with only decimal part', () => { expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> .33 \n'; text: 'xAxisName',
expect(parserFnConstructor(str)).not.toThrow(); type: 'text',
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); });
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 0.33); expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 33);
}); });
it('parse y-axis throw error for invalid number in range data', () => { it('parse x-axis throw error for invalid range data', () => {
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> abc \n'; const str = 'xychart-beta \nx-axis xAxisName aaa --> 33 \n';
expect(parserFnConstructor(str)).toThrow(); expect(parserFnConstructor(str)).toThrow();
}); });
it('parse y-axis throws error if range data is passed', () => { it('parse x-axis with axis name and range data with only decimal part', () => {
const str = 'xychart-beta \ny-axis yAxisName [ 45.3, 33 ] \n'; const str = 'xychart-beta \nx-axis xAxisName 45.5 --> .34 \n';
expect(parserFnConstructor(str)).toThrow(); expect(parserFnConstructor(str)).not.toThrow();
}); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
it('parse both axis at once', () => { text: 'xAxisName',
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n'; type: 'text',
expect(parserFnConstructor(str)).not.toThrow(); });
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 0.34);
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); });
});
it('parse line Data', () => { it('parse x-axis without axisname and range data', () => {
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]'; const str = 'xychart-beta \nx-axis 45.5 --> 1.34 \n';
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setLineData).toHaveBeenCalledWith( expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
{ text: 'lineTitle', type: 'text' }, text: '',
[23, 45, 56.6] type: 'text',
); });
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 1.34);
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); });
});
it('parse line Data with spaces and +,- symbols', () => { it('parse x-axis with axis name and category data', () => {
const str = const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] '; expect(parserFnConstructor(str)).not.toThrow();
expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); text: 'xAxisName',
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); type: 'text',
expect(mockDB.setLineData).toHaveBeenCalledWith( });
{ text: 'lineTitle with space', type: 'text' }, expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
[23, -45, 56.6] {
); text: 'cat1',
}); type: 'text',
it('parse line Data without title', () => { },
const str = { text: 'cat2a', type: 'text' },
'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' }); it('parse x-axis without axisname and category data', () => {
expect(mockDB.setLineData).toHaveBeenCalledWith( const str = 'xychart-beta \nx-axis [ "cat1" , cat2a ] \n ';
{ text: '', type: 'text' }, expect(parserFnConstructor(str)).not.toThrow();
[23, -45, 56.6, 0.33] expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
); text: '',
}); type: 'text',
it('parse line Data throws error unbalanced brackets', () => { });
let str = expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 [ -45 , 56.6 ] '; {
expect(parserFnConstructor(str)).toThrow(); text: 'cat1',
str = type: 'text',
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 ] 56.6 ] '; },
expect(parserFnConstructor(str)).toThrow(); { text: 'cat2a', type: 'text' },
}); ]);
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 x-axis throw error if unbalanced bracket', () => {
}); let str = 'xychart-beta \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
it('parse line Data throws error if data is empty', () => { expect(parserFnConstructor(str)).toThrow();
const str = str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] ] \n ';
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ ] '; expect(parserFnConstructor(str)).toThrow();
expect(parserFnConstructor(str)).toThrow(); });
});
it('parse line Data throws error if , is not in proper', () => { it('parse x-axis complete variant 1', () => {
const str = const str = `xychart-beta \n x-axis "this is x axis" [category1, "category 2", category3]\n`;
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , , -45 , 56.6 ] '; expect(parserFnConstructor(str)).not.toThrow();
expect(parserFnConstructor(str)).toThrow(); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
}); expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
it('parse line Data throws error if not number', () => { { text: 'category1', type: 'text' },
const str = { text: 'category 2', type: 'text' },
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] '; { text: 'category3', type: 'text' },
expect(parserFnConstructor(str)).toThrow(); ]);
}); });
it('parse bar Data', () => {
const str = it('parse x-axis complete variant 2', () => {
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6, .22]'; const str =
expect(parserFnConstructor(str)).not.toThrow(); 'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 , cat3] \n ';
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
expect(mockDB.setBarData).toHaveBeenCalledWith( expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
{ text: 'barTitle', type: 'text' }, { text: 'cat1 with space', type: 'text' },
[23, 45, 56.6, 0.22] { text: 'cat2', type: 'text' },
); { text: 'cat3', type: 'text' },
}); ]);
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 ] '; it('parse x-axis complete variant 3', () => {
expect(parserFnConstructor(str)).not.toThrow(); const str =
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); 'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 asdf , cat3] \n ';
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setBarData).toHaveBeenCalledWith( expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
{ text: 'barTitle with space', type: 'text' }, expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
[23, -45, 56.6] { text: 'cat1 with space', type: 'text' },
); { text: 'cat2asdf', type: 'text' },
}); { text: 'cat3', type: 'text' },
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(); it('parse y-axis with axis name', () => {
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); const str = 'xychart-beta \ny-axis yAxisName\n';
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setBarData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
}); });
it('parse bar should throw for unbalanced brackets', () => { it('parse y-axis with axis name with spaces', () => {
let str = const str = 'xychart-beta \ny-axis yAxisName \n';
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 [ -45 , 56.6 ] '; expect(parserFnConstructor(str)).not.toThrow();
expect(parserFnConstructor(str)).toThrow(); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
str = });
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 ] 56.6 ] '; it('parse y-axis with axis name with "', () => {
expect(parserFnConstructor(str)).toThrow(); const str = 'xychart-beta \n y-axis "yAxisName has space"\n';
}); expect(parserFnConstructor(str)).not.toThrow();
it('parse bar should throw error if data is not provided', () => { expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" '; text: 'yAxisName has space',
expect(parserFnConstructor(str)).toThrow(); type: 'text',
}); });
it('parse bar should throw error if data is empty', () => { });
const str = it('parse y-axis with axis name with " and spaces', () => {
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ ] '; const str = 'xychart-beta \n y-axis " yAxisName has space " \n';
expect(parserFnConstructor(str)).toThrow(); expect(parserFnConstructor(str)).not.toThrow();
}); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
it('parse bar should throw error if comma is not proper', () => { text: ' yAxisName has space ',
const str = type: 'text',
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , , -45 , 56.6 ] '; });
expect(parserFnConstructor(str)).toThrow(); });
}); it('parse y-axis with axis name with range data', () => {
it('parse bar should throw error if number is not passed', () => { const str = 'xychart-beta \ny-axis yAxisName 45.5 --> 33 \n';
const str = expect(parserFnConstructor(str)).not.toThrow();
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] '; expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
expect(parserFnConstructor(str)).toThrow(); expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
}); });
it('parse multiple bar and line variant 1', () => { it('parse y-axis without axisname with range data', () => {
const str = const str = 'xychart-beta \ny-axis 45.5 --> 33 \n';
'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(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: '', type: 'text' });
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' }); expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' }); });
expect(mockDB.setBarData).toHaveBeenCalledWith( it('parse y-axis with axis name with range data with only decimal part', () => {
{ text: 'barTitle1', type: 'text' }, const str = 'xychart-beta \ny-axis yAxisName 45.5 --> .33 \n';
[23, 45, 56.6] expect(parserFnConstructor(str)).not.toThrow();
); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
expect(mockDB.setBarData).toHaveBeenCalledWith( expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 0.33);
{ text: 'barTitle2', type: 'text' }, });
[13, 42, 56.89] it('parse y-axis throw error for invalid number in range data', () => {
); const str = 'xychart-beta \ny-axis yAxisName 45.5 --> abc \n';
expect(mockDB.setLineData).toHaveBeenCalledWith( expect(parserFnConstructor(str)).toThrow();
{ text: 'lineTitle1', type: 'text' }, });
[11, 45.5, 67, 23] it('parse y-axis throws error if range data is passed', () => {
); const str = 'xychart-beta \ny-axis yAxisName [ 45.3, 33 ] \n';
expect(mockDB.setLineData).toHaveBeenCalledWith( expect(parserFnConstructor(str)).toThrow();
{ text: 'lineTitle2', type: 'text' }, });
[45, 99, 12] it('parse both axis at once', () => {
); const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n';
}); expect(parserFnConstructor(str)).not.toThrow();
it('parse multiple bar and line variant 2', () => { expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
const str = ` 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 xychart-beta horizontal
title Basic xychart title Basic xychart
x-axis "this is x axis" [category1, "category 2", category3] 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] line lineTitle1 [11, 45.5, 67, 23]
bar barTitle2 [13, 42, 56.89] bar barTitle2 [13, 42, 56.89]
line lineTitle2 [45, 99, 012]`; line lineTitle2 [45, 99, 012]`;
expect(parserFnConstructor(str)).not.toThrow(); expect(parserFnConstructor(str)).not.toThrow();
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yaxisText', type: 'text' }); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yaxisText', type: 'text' });
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(10, 150); expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(10, 150);
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' }); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([ expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
{ text: 'category1', type: 'text' }, { text: 'category1', type: 'text' },
{ text: 'category 2', type: 'text' }, { text: 'category 2', type: 'text' },
{ text: 'category3', type: 'text' }, { text: 'category3', type: 'text' },
]); ]);
expect(mockDB.setBarData).toHaveBeenCalledWith( expect(mockDB.setBarData).toHaveBeenCalledWith(
{ text: 'barTitle1', type: 'text' }, { text: 'barTitle1', type: 'text' },
[23, 45, 56.6] [23, 45, 56.6]
); );
expect(mockDB.setBarData).toHaveBeenCalledWith( expect(mockDB.setBarData).toHaveBeenCalledWith(
{ text: 'barTitle2', type: 'text' }, { text: 'barTitle2', type: 'text' },
[13, 42, 56.89] [13, 42, 56.89]
); );
expect(mockDB.setLineData).toHaveBeenCalledWith( expect(mockDB.setLineData).toHaveBeenCalledWith(
{ text: 'lineTitle1', type: 'text' }, { text: 'lineTitle1', type: 'text' },
[11, 45.5, 67, 23] [11, 45.5, 67, 23]
); );
expect(mockDB.setLineData).toHaveBeenCalledWith( expect(mockDB.setLineData).toHaveBeenCalledWith(
{ text: 'lineTitle2', type: 'text' }, { text: 'lineTitle2', type: 'text' },
[45, 99, 12] [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]
);
});
}); });
}); });

View File

@@ -22,6 +22,7 @@ import type {
} from './chartBuilder/interfaces.js'; } from './chartBuilder/interfaces.js';
import { isBandAxisData, isLinearAxisData } from './chartBuilder/interfaces.js'; import { isBandAxisData, isLinearAxisData } from './chartBuilder/interfaces.js';
import type { Group } from '../../diagram-api/types.js'; import type { Group } from '../../diagram-api/types.js';
import { PlotType } from './chartBuilder/components/plot/PlotType.js';
let plotIndex = 0; let plotIndex = 0;
@@ -34,6 +35,8 @@ let plotColorPalette = xyChartThemeConfig.plotColorPalette.split(',').map((color
let hasSetXAxis = false; let hasSetXAxis = false;
let hasSetYAxis = false; let hasSetYAxis = false;
let dataSets: number[][] = [];
interface NormalTextType { interface NormalTextType {
type: 'text'; type: 'text';
text: string; text: string;
@@ -57,7 +60,7 @@ function getChartDefaultData(): XYChartData {
yAxis: { yAxis: {
type: 'linear', type: 'linear',
title: '', title: '',
min: Infinity, min: 0,
max: -Infinity, max: -Infinity,
}, },
xAxis: { 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 // this function does not set `hasSetYAxis` as there can be multiple data so we should calculate the range accordingly
function setYAxisRangeFromPlotData(data: number[]) { function setYAxisRangeFromPlotData(data: number[], plotType: PlotType) {
const minValue = Math.min(...data); const sum = new Array(data.length).fill(0);
const maxValue = Math.max(...data); if (plotType === PlotType.BAR) {
const prevMinValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.min : Infinity; dataSets.push(data);
const prevMaxValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.max : -Infinity; for (let i = 0; i < data.length; i++) {
for (const entry of dataSets) {
sum[i] += entry[i];
}
}
}
xyChartData.yAxis = { xyChartData.yAxis = {
type: 'linear', type: 'linear',
title: xyChartData.yAxis.title, title: xyChartData.yAxis.title,
min: Math.min(prevMinValue, minValue), min: isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.min : Math.min(...sum),
max: Math.max(prevMaxValue, maxValue), max: Math.max(...sum),
}; };
} }
function transformDataWithoutCategory(data: number[]): SimplePlotDataType { function transformDataWithoutCategory(data: number[], plotType: PlotType): SimplePlotDataType {
let retData: SimplePlotDataType = []; let retData: SimplePlotDataType = [];
if (data.length === 0) { if (data.length === 0) {
return retData; return retData;
@@ -133,22 +142,22 @@ function transformDataWithoutCategory(data: number[]): SimplePlotDataType {
setXAxisRangeData(Math.min(prevMinValue, 1), Math.max(prevMaxValue, data.length)); setXAxisRangeData(Math.min(prevMinValue, 1), Math.max(prevMaxValue, data.length));
} }
if (!hasSetYAxis) { if (!hasSetYAxis) {
setYAxisRangeFromPlotData(data); setYAxisRangeFromPlotData(data, plotType);
} }
if (isBandAxisData(xyChartData.xAxis)) { 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)) { if (isLinearAxisData(xyChartData.xAxis)) {
const min = xyChartData.xAxis.min; const min = xyChartData.xAxis.min;
const max = xyChartData.xAxis.max; const max = xyChartData.xAxis.max;
const step = (max - min + 1) / data.length; const step = (max - min) / (data.length - 1);
const categories: string[] = []; const categories: string[] = [];
for (let i = min; i <= max; i += step) { for (let i = min; i <= max; i += step) {
categories.push(`${i}`); categories.push(`${i}`);
} }
retData = categories.map((c, i) => [c, data[i]]); retData = categories.map((c, i) => [c, data[i] ?? 0]);
} }
return retData; return retData;
@@ -159,9 +168,9 @@ function getPlotColorFromPalette(plotIndex: number): string {
} }
function setLineData(title: NormalTextType, data: number[]) { function setLineData(title: NormalTextType, data: number[]) {
const plotData = transformDataWithoutCategory(data); const plotData = transformDataWithoutCategory(data, PlotType.LINE);
xyChartData.plots.push({ xyChartData.plots.push({
type: 'line', type: PlotType.LINE,
strokeFill: getPlotColorFromPalette(plotIndex), strokeFill: getPlotColorFromPalette(plotIndex),
strokeWidth: 2, strokeWidth: 2,
data: plotData, data: plotData,
@@ -170,9 +179,9 @@ function setLineData(title: NormalTextType, data: number[]) {
} }
function setBarData(title: NormalTextType, data: number[]) { function setBarData(title: NormalTextType, data: number[]) {
const plotData = transformDataWithoutCategory(data); const plotData = transformDataWithoutCategory(data, PlotType.BAR);
xyChartData.plots.push({ xyChartData.plots.push({
type: 'bar', type: PlotType.BAR,
fill: getPlotColorFromPalette(plotIndex), fill: getPlotColorFromPalette(plotIndex),
data: plotData, data: plotData,
}); });
@@ -204,6 +213,7 @@ const clear = function () {
plotColorPalette = xyChartThemeConfig.plotColorPalette.split(',').map((color) => color.trim()); plotColorPalette = xyChartThemeConfig.plotColorPalette.split(',').map((color) => color.trim());
hasSetXAxis = false; hasSetXAxis = false;
hasSetYAxis = false; hasSetYAxis = false;
dataSets = [];
}; };
export default { export default {

View File

@@ -141,18 +141,20 @@ Messages can be of two displayed either solid or with a dotted line.
[Actor][Arrow][Actor]:Message text [Actor][Arrow][Actor]:Message text
``` ```
There are six types of arrows currently supported: There are ten types of arrows currently supported:
| Type | Description | | Type | Description |
| ------ | ------------------------------------------------ | | -------- | ----------------------------------------------------------------------- |
| `->` | Solid line without arrow | | `->` | Solid line without arrow |
| `-->` | Dotted line without arrow | | `-->` | Dotted line without arrow |
| `->>` | Solid line with arrowhead | | `->>` | Solid line with arrowhead |
| `-->>` | Dotted line with arrowhead | | `-->>` | Dotted line with arrowhead |
| `-x` | Solid line with a cross at the end | | `<<->>` | Solid line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
| `--x` | Dotted line with a cross at the end. | | `<<-->>` | Dotted line with bidirectional arrowheads (v<MERMAID_RELEASE_VERSION>+) |
| `-)` | Solid line with an open arrow at the end (async) | | `-x` | Solid line with a cross at the end |
| `--)` | Dotted line with a open arrow at the end (async) | | `--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 ## Activations
@@ -205,11 +207,22 @@ sequenceDiagram
Note over Alice,John: A typical interaction 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 ```mermaid-example
sequenceDiagram 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 Note over Alice,John: A typical interaction<br/>But now in two lines
``` ```

View File

@@ -1,11 +1,35 @@
# XY Chart # 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. > 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 ## 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 ```mermaid-example
xychart-beta xychart-beta
title "Sales Revenue" title "Sales Revenue"

View File

@@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
[Error: Parse error on line 2: [Error: Parse error on line 2:
...equenceDiagramAlice:->Bob: Hello Bob, h... ...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']
`); `);
}); });

View File

@@ -69,6 +69,7 @@ vi.mock('stylis', () => {
import { compile, serialize } from 'stylis'; import { compile, serialize } from 'stylis';
import { decodeEntities, encodeEntities } from './utils.js'; import { decodeEntities, encodeEntities } from './utils.js';
import { Diagram } from './Diagram.js'; import { Diagram } from './Diagram.js';
import { toBase64 } from './utils/base64.js';
/** /**
* @see https://vitest.dev/guide/mocking.html Mock part of a module * @see https://vitest.dev/guide/mocking.html Mock part of a module
@@ -176,7 +177,7 @@ describe('mermaidAPI', () => {
}); });
describe('putIntoIFrame', () => { 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', () => { it('uses the default SVG iFrame height is used if no svgElement given', () => {
const result = putIntoIFrame(inputSvgCode); 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>', () => { 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 base64encodedSrc = toBase64(`<body style="margin:0">${inputSvgCode}</body>`);
const expectedRegExp = new RegExp('src="data:text/html;base64,' + base64encodedSrc + '"'); const expectedSrc = `src="data:text/html;charset=UTF-8;base64,${base64encodedSrc}"`;
const result = putIntoIFrame(inputSvgCode); const result = putIntoIFrame(inputSvgCode);
expect(result).toMatch(expectedRegExp); expect(result).toContain(expectedSrc);
}); });
it('uses the height and appends px from the svgElement given', () => { it('uses the height and appends px from the svgElement given', () => {

View File

@@ -31,6 +31,7 @@ import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.
import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js'; import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js';
import { preprocessDiagram } from './preprocess.js'; import { preprocessDiagram } from './preprocess.js';
import { decodeEntities } from './utils.js'; import { decodeEntities } from './utils.js';
import { toBase64 } from './utils/base64.js';
const MAX_TEXTLENGTH = 50_000; const MAX_TEXTLENGTH = 50_000;
const MAX_TEXTLENGTH_EXCEEDED_MSG = const MAX_TEXTLENGTH_EXCEEDED_MSG =
@@ -248,14 +249,13 @@ export const cleanUpSvgCode = (
* @param svgCode - the svg code to put inside the iFrame * @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 * @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 * @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 => { export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => {
const height = svgElement?.viewBox?.baseVal?.height const height = svgElement?.viewBox?.baseVal?.height
? svgElement.viewBox.baseVal.height + 'px' ? svgElement.viewBox.baseVal.height + 'px'
: IFRAME_HEIGHT; : IFRAME_HEIGHT;
const base64encodedSrc = btoa('<body style="' + IFRAME_BODY_STYLE + '">' + svgCode + '</body>'); const base64encodedSrc = toBase64(`<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}"> 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_NOT_SUPPORTED_MSG}
</iframe>`; </iframe>`;
}; };

View 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);
}