mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch 'develop' into next
* develop: (56 commits) chore: Add comments on redirectMaps remove `chart` from `pie.spec.ts` description Update docs change `defaultConfig` type to `RequiredDeep` and use it in `pieDb` use `DiagramStylesProvider` in `pieStyles.ts` remove `setConfig` and `resetConfig` in pie add `structuredClone` in pie `getConfig` cleanAndMerge pieConfig remove cleanClone feat: Add cleanAndMerge and tests chore: Rename utils.spec.ts move db assignment from `beforeEach` to `beforeAll` create `structuredCleanClone` helper function add more types to pieRenderer add `resetConfig` to `clear` in pieDb rename `reset` to `resetConfig` use `structedClone` in `pieDb` remove `PieDiagramConfig` and import generated one remove unnecessary lines in pie files remove unused `HTML` import in pieRenderer ...
This commit is contained in:
commit
fd731c5ccd
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Mocked pie (picChart) diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
8
__mocks__/pieRenderer.ts
Normal file
8
__mocks__/pieRenderer.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Mocked pie (picChart) diagram renderer
|
||||
*/
|
||||
import { vi } from 'vitest';
|
||||
|
||||
const draw = vi.fn().mockImplementation(() => '');
|
||||
|
||||
export const renderer = { draw };
|
@ -1,89 +1,85 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe('Pie Chart', () => {
|
||||
describe('pie chart', () => {
|
||||
it('should render a simple pie diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`pie title Sports in Sweden
|
||||
"Bandy": 40
|
||||
"Ice-Hockey": 80
|
||||
"Football": 90
|
||||
`
|
||||
pie title Sports in Sweden
|
||||
"Bandy" : 40
|
||||
"Ice-Hockey" : 80
|
||||
"Football" : 90
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a simple pie diagram with long labels', () => {
|
||||
imgSnapshotTest(
|
||||
`pie title NETFLIX
|
||||
"Time spent looking for movie": 90
|
||||
"Time spent watching it": 10
|
||||
`
|
||||
pie title NETFLIX
|
||||
"Time spent looking for movie" : 90
|
||||
"Time spent watching it" : 10
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a simple pie diagram with capital letters for labels', () => {
|
||||
imgSnapshotTest(
|
||||
`pie title What Voldemort doesn't have?
|
||||
"FRIENDS": 2
|
||||
"FAMILY": 3
|
||||
"NOSE": 45
|
||||
`
|
||||
pie title What Voldemort doesn't have?
|
||||
"FRIENDS" : 2
|
||||
"FAMILY" : 3
|
||||
"NOSE" : 45
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a pie diagram when useMaxWidth is true (default)', () => {
|
||||
renderGraph(
|
||||
`
|
||||
pie title Sports in Sweden
|
||||
"Bandy" : 40
|
||||
"Ice-Hockey" : 80
|
||||
"Football" : 90
|
||||
`pie title Sports in Sweden
|
||||
"Bandy": 40
|
||||
"Ice-Hockey": 80
|
||||
"Football": 90
|
||||
`,
|
||||
{ pie: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
// expect(svg).to.have.attr('height');
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
// expect(height).to.eq(450);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.eq(984);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a pie diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
`
|
||||
pie title Sports in Sweden
|
||||
"Bandy" : 40
|
||||
"Ice-Hockey" : 80
|
||||
"Football" : 90
|
||||
`pie title Sports in Sweden
|
||||
"Bandy": 40
|
||||
"Ice-Hockey": 80
|
||||
"Football": 90
|
||||
`,
|
||||
{ pie: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// expect(height).to.eq(450);
|
||||
expect(width).to.eq(984);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
it('should render a pie diagram when textPosition is set', () => {
|
||||
|
||||
it('should render a pie diagram when textPosition is setted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
pie
|
||||
"Dogs": 50
|
||||
"Cats": 25
|
||||
`,
|
||||
`pie
|
||||
"Dogs": 50
|
||||
"Cats": 25
|
||||
`,
|
||||
{ logLevel: 1, pie: { textPosition: 0.9 } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render a pie diagram with showData', () => {
|
||||
imgSnapshotTest(
|
||||
`pie showData
|
||||
"Dogs": 50
|
||||
"Cats": 25
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
@ -7,7 +7,6 @@
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
@ -17,37 +16,32 @@
|
||||
<h1>Pie chart demos</h1>
|
||||
<pre class="mermaid">
|
||||
pie title Pets adopted by volunteers
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 15
|
||||
accTitle: simple pie char demo
|
||||
accDescr: pie chart with 3 sections: dogs, cats, rats. Most are dogs.
|
||||
"Dogs": 386
|
||||
"Cats": 85
|
||||
"Rats": 15
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
%%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
|
||||
pie
|
||||
title Key elements in Product X
|
||||
%%{init: {"pie": {"textPosition": 0.9}, "themeVariables": {"pieOuterStrokeWidth": "5px"}}}%%
|
||||
pie
|
||||
title Key elements in Product X
|
||||
accTitle: Key elements in Product X
|
||||
accDescr: This is a pie chart showing the key elements in Product X.
|
||||
"Calcium" : 42.96
|
||||
"Potassium" : 50.05
|
||||
"Magnesium" : 10.01
|
||||
"Iron" : 5
|
||||
accDescr: This is a pie chart showing the key elements in Product X.
|
||||
"Calcium": 42.96
|
||||
"Potassium": 50.05
|
||||
"Magnesium": 10.01
|
||||
"Iron": 5
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
// themeCSS: '.node rect { fill: red; }',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
// flowchart: { curve: 'basis' },
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -14,13 +14,13 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:266](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L266)
|
||||
[defaultConfig.ts:268](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L268)
|
||||
|
||||
---
|
||||
|
||||
### default
|
||||
|
||||
• `Const` **default**: `Partial`<`MermaidConfig`>
|
||||
• `Const` **default**: `RequiredDeep`<`MermaidConfig`>
|
||||
|
||||
Default mermaid configuration options.
|
||||
|
||||
@ -30,4 +30,4 @@ Non-JSON JS default values are listed in this file, e.g. functions, or
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:16](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L16)
|
||||
[defaultConfig.ts:18](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L18)
|
||||
|
@ -82,7 +82,9 @@
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-sankey": "^0.12.1",
|
||||
"@types/d3-scale": "^4.0.3",
|
||||
"@types/d3-selection": "^3.0.5",
|
||||
"@types/d3-shape": "^3.1.1",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
@ -111,6 +113,7 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"start-server-and-test": "^2.0.0",
|
||||
"type-fest": "^4.1.0",
|
||||
"typedoc": "^0.24.5",
|
||||
"typedoc-plugin-markdown": "^3.15.2",
|
||||
"typescript": "^5.0.4",
|
||||
|
@ -1,5 +1,7 @@
|
||||
import type { RequiredDeep } from 'type-fest';
|
||||
|
||||
import theme from './themes/index.js';
|
||||
import { type MermaidConfig } from './config.type.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
|
||||
// Uses our custom Vite jsonSchemaPlugin to load only the default values from
|
||||
// our JSON Schema
|
||||
@ -13,7 +15,7 @@ import defaultConfigJson from './schemas/config.schema.yaml?only-defaults=true';
|
||||
* Non-JSON JS default values are listed in this file, e.g. functions, or
|
||||
* `undefined` (explicitly set so that `configKeys` finds them).
|
||||
*/
|
||||
const config: Partial<MermaidConfig> = {
|
||||
const config: RequiredDeep<MermaidConfig> = {
|
||||
...defaultConfigJson,
|
||||
// Set, even though they're `undefined` so that `configKeys` finds these keys
|
||||
// TODO: Should we replace these with `null` so that they can go in the JSON Schema?
|
||||
@ -232,7 +234,7 @@ const config: Partial<MermaidConfig> = {
|
||||
},
|
||||
pie: {
|
||||
...defaultConfigJson.pie,
|
||||
useWidth: undefined,
|
||||
useWidth: 984,
|
||||
},
|
||||
requirement: {
|
||||
...defaultConfigJson.requirement,
|
||||
|
@ -5,7 +5,7 @@ import er from '../diagrams/er/erDetector.js';
|
||||
import git from '../diagrams/git/gitGraphDetector.js';
|
||||
import gantt from '../diagrams/gantt/ganttDetector.js';
|
||||
import { info } from '../diagrams/info/infoDetector.js';
|
||||
import pie from '../diagrams/pie/pieDetector.js';
|
||||
import { pie } from '../diagrams/pie/pieDetector.js';
|
||||
import quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js';
|
||||
import requirement from '../diagrams/requirement/requirementDetector.js';
|
||||
import sequence from '../diagrams/sequence/sequenceDetector.js';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Diagram } from '../Diagram.js';
|
||||
import type { MermaidConfig } from '../config.type.js';
|
||||
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
|
||||
import type * as d3 from 'd3';
|
||||
|
||||
export interface InjectUtils {
|
||||
@ -16,11 +16,19 @@ export interface InjectUtils {
|
||||
* Generic Diagram DB that may apply to any diagram type.
|
||||
*/
|
||||
export interface DiagramDB {
|
||||
// config
|
||||
getConfig?: () => BaseDiagramConfig | undefined;
|
||||
|
||||
// db
|
||||
clear?: () => void;
|
||||
setDiagramTitle?: (title: string) => void;
|
||||
setDisplayMode?: (title: string) => void;
|
||||
getDiagramTitle?: () => string;
|
||||
setAccTitle?: (title: string) => void;
|
||||
getAccTitle?: () => string;
|
||||
setAccDescription?: (describetion: string) => void;
|
||||
getAccDescription?: () => string;
|
||||
|
||||
setDisplayMode?: (title: string) => void;
|
||||
bindFunctions?: (element: Element) => void;
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
name,amounts
|
||||
Foo, 33
|
||||
Rishab, 12
|
||||
Alexis, 41
|
||||
Tom, 16
|
||||
Courtney, 59
|
||||
Christina, 38
|
||||
Jack, 21
|
||||
Mickey, 25
|
||||
Paul, 30
|
|
@ -1,132 +0,0 @@
|
||||
import pieDb from '../pieDb.js';
|
||||
import pie from './pie.jison';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing pie', function () {
|
||||
beforeEach(function () {
|
||||
pie.parser.yy = pieDb;
|
||||
pie.parser.yy.clear();
|
||||
});
|
||||
it('should handle very simple pie', function () {
|
||||
const res = pie.parser.parse(`pie
|
||||
"ash" : 100
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(100);
|
||||
});
|
||||
it('should handle simple pie', function () {
|
||||
const res = pie.parser.parse(`pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
});
|
||||
it('should handle simple pie with comments', function () {
|
||||
const res = pie.parser.parse(`pie
|
||||
%% comments
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
});
|
||||
|
||||
it('should handle simple pie with a directive', function () {
|
||||
const res = pie.parser.parse(`%%{init: {'logLevel':0}}%%
|
||||
pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
});
|
||||
|
||||
it('should handle simple pie with a title', function () {
|
||||
const res = pie.parser.parse(`pie title a 60/40 pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const title = pieDb.getDiagramTitle();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
expect(title).toBe('a 60/40 pie');
|
||||
});
|
||||
|
||||
it('should handle simple pie without an acc description (accDescr)', function () {
|
||||
const res = pie.parser.parse(`pie title a neat chart
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = pieDb.getSections();
|
||||
const title = pieDb.getDiagramTitle();
|
||||
const description = pieDb.getAccDescription();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
expect(title).toBe('a neat chart');
|
||||
expect(description).toBe('');
|
||||
});
|
||||
|
||||
it('should handle simple pie with an acc description (accDescr)', function () {
|
||||
const res = pie.parser.parse(`pie title a neat chart
|
||||
accDescr: a neat description
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = pieDb.getSections();
|
||||
const title = pieDb.getDiagramTitle();
|
||||
const description = pieDb.getAccDescription();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
expect(title).toBe('a neat chart');
|
||||
expect(description).toBe('a neat description');
|
||||
});
|
||||
it('should handle simple pie with a multiline acc description (accDescr)', function () {
|
||||
const res = pie.parser.parse(`pie title a neat chart
|
||||
accDescr {
|
||||
a neat description
|
||||
on multiple lines
|
||||
}
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = pieDb.getSections();
|
||||
const title = pieDb.getDiagramTitle();
|
||||
const description = pieDb.getAccDescription();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60);
|
||||
expect(title).toBe('a neat chart');
|
||||
expect(description).toBe('a neat description\non multiple lines');
|
||||
});
|
||||
|
||||
it('should handle simple pie with positive decimal', function () {
|
||||
const res = pie.parser.parse(`pie
|
||||
"ash" : 60.67
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = pieDb.getSections();
|
||||
const section1 = sections['ash'];
|
||||
expect(section1).toBe(60.67);
|
||||
});
|
||||
|
||||
it('should handle simple pie with negative decimal', function () {
|
||||
expect(() => {
|
||||
pie.parser.parse(`pie
|
||||
"ash" : 60.67
|
||||
"bat" : 40..12
|
||||
`);
|
||||
}).toThrowError();
|
||||
});
|
||||
});
|
180
packages/mermaid/src/diagrams/pie/pie.spec.ts
Normal file
180
packages/mermaid/src/diagrams/pie/pie.spec.ts
Normal file
@ -0,0 +1,180 @@
|
||||
// @ts-ignore: JISON doesn't support types
|
||||
import { parser } from './parser/pie.jison';
|
||||
import { DEFAULT_PIE_DB, db } from './pieDb.js';
|
||||
import { setConfig } from '../../config.js';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('pie', () => {
|
||||
beforeAll(() => {
|
||||
parser.yy = db;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
parser.yy.clear();
|
||||
});
|
||||
|
||||
describe('parse', () => {
|
||||
it('should handle very simple pie', () => {
|
||||
parser.parse(`pie
|
||||
"ash": 100
|
||||
`);
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(100);
|
||||
});
|
||||
|
||||
it('should handle simple pie', () => {
|
||||
parser.parse(`pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with showData', () => {
|
||||
parser.parse(`pie showData
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
expect(db.getShowData()).toBeTruthy();
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with comments', () => {
|
||||
parser.parse(`pie
|
||||
%% comments
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with a directive', () => {
|
||||
parser.parse(`%%{init: {'logLevel':0}}%%
|
||||
pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with a title', () => {
|
||||
parser.parse(`pie title a 60/40 pie
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
expect(db.getDiagramTitle()).toBe('a 60/40 pie');
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with an acc title (accTitle)', () => {
|
||||
parser.parse(`pie title a neat chart
|
||||
accTitle: a neat acc title
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
expect(db.getDiagramTitle()).toBe('a neat chart');
|
||||
|
||||
expect(db.getAccTitle()).toBe('a neat acc title');
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with an acc description (accDescr)', () => {
|
||||
parser.parse(`pie title a neat chart
|
||||
accDescr: a neat description
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
expect(db.getDiagramTitle()).toBe('a neat chart');
|
||||
|
||||
expect(db.getAccDescription()).toBe('a neat description');
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with a multiline acc description (accDescr)', () => {
|
||||
parser.parse(`pie title a neat chart
|
||||
accDescr {
|
||||
a neat description
|
||||
on multiple lines
|
||||
}
|
||||
"ash" : 60
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
expect(db.getDiagramTitle()).toBe('a neat chart');
|
||||
|
||||
expect(db.getAccDescription()).toBe('a neat description\non multiple lines');
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with positive decimal', () => {
|
||||
parser.parse(`pie
|
||||
"ash" : 60.67
|
||||
"bat" : 40
|
||||
`);
|
||||
|
||||
const sections = db.getSections();
|
||||
expect(sections['ash']).toBe(60.67);
|
||||
expect(sections['bat']).toBe(40);
|
||||
});
|
||||
|
||||
it('should handle simple pie with negative decimal', () => {
|
||||
expect(() => {
|
||||
parser.parse(`pie
|
||||
"ash" : -60.67
|
||||
"bat" : 40.12
|
||||
`);
|
||||
}).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('config', () => {
|
||||
it.todo('setConfig', () => {
|
||||
// db.setConfig({ useWidth: 850, useMaxWidth: undefined });
|
||||
|
||||
const config = db.getConfig();
|
||||
expect(config.useWidth).toBe(850);
|
||||
expect(config.useMaxWidth).toBeTruthy();
|
||||
});
|
||||
|
||||
it('getConfig', () => {
|
||||
expect(db.getConfig()).toStrictEqual(DEFAULT_PIE_DB.config);
|
||||
});
|
||||
|
||||
it.todo('resetConfig', () => {
|
||||
// db.setConfig({ textPosition: 0 });
|
||||
// db.resetConfig();
|
||||
expect(db.getConfig().textPosition).toStrictEqual(DEFAULT_PIE_DB.config.textPosition);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,69 +0,0 @@
|
||||
import { log } from '../../logger.js';
|
||||
import mermaidAPI from '../../mermaidAPI.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import common from '../common/common.js';
|
||||
import {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
|
||||
let sections = {};
|
||||
let showData = false;
|
||||
|
||||
export const parseDirective = function (statement, context, type) {
|
||||
mermaidAPI.parseDirective(this, statement, context, type);
|
||||
};
|
||||
|
||||
const addSection = function (id, value) {
|
||||
id = common.sanitizeText(id, configApi.getConfig());
|
||||
if (sections[id] === undefined) {
|
||||
sections[id] = value;
|
||||
log.debug('Added new section :', id);
|
||||
}
|
||||
};
|
||||
const getSections = () => sections;
|
||||
|
||||
const setShowData = function (toggle) {
|
||||
showData = toggle;
|
||||
};
|
||||
|
||||
const getShowData = function () {
|
||||
return showData;
|
||||
};
|
||||
|
||||
const cleanupValue = function (value) {
|
||||
if (value.substring(0, 1) === ':') {
|
||||
value = value.substring(1).trim();
|
||||
return Number(value.trim());
|
||||
} else {
|
||||
return Number(value.trim());
|
||||
}
|
||||
};
|
||||
|
||||
const clear = function () {
|
||||
sections = {};
|
||||
showData = false;
|
||||
commonClear();
|
||||
};
|
||||
|
||||
export default {
|
||||
parseDirective,
|
||||
getConfig: () => configApi.getConfig().pie,
|
||||
addSection,
|
||||
getSections,
|
||||
cleanupValue,
|
||||
clear,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
setShowData,
|
||||
getShowData,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
};
|
84
packages/mermaid/src/diagrams/pie/pieDb.ts
Normal file
84
packages/mermaid/src/diagrams/pie/pieDb.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { log } from '../../logger.js';
|
||||
import { parseDirective as _parseDirective } from '../../directiveUtils.js';
|
||||
import { getConfig as commonGetConfig } from '../../config.js';
|
||||
import { sanitizeText } from '../common/common.js';
|
||||
import {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
import type { ParseDirectiveDefinition } from '../../diagram-api/types.js';
|
||||
import type { PieFields, PieDB, Sections } from './pieTypes.js';
|
||||
import type { RequiredDeep } from 'type-fest';
|
||||
import type { PieDiagramConfig } from '../../config.type.js';
|
||||
import DEFAULT_CONFIG from '../../defaultConfig.js';
|
||||
|
||||
export const DEFAULT_PIE_CONFIG: Required<PieDiagramConfig> = DEFAULT_CONFIG.pie;
|
||||
|
||||
export const DEFAULT_PIE_DB: RequiredDeep<PieFields> = {
|
||||
sections: {},
|
||||
showData: false,
|
||||
config: DEFAULT_PIE_CONFIG,
|
||||
} as const;
|
||||
|
||||
let sections: Sections = DEFAULT_PIE_DB.sections;
|
||||
let showData: boolean = DEFAULT_PIE_DB.showData;
|
||||
const config: Required<PieDiagramConfig> = structuredClone(DEFAULT_PIE_CONFIG);
|
||||
|
||||
const getConfig = (): Required<PieDiagramConfig> => structuredClone(config);
|
||||
|
||||
const parseDirective: ParseDirectiveDefinition = (statement, context, type) => {
|
||||
_parseDirective(this, statement, context, type);
|
||||
};
|
||||
|
||||
const clear = (): void => {
|
||||
sections = structuredClone(DEFAULT_PIE_DB.sections);
|
||||
showData = DEFAULT_PIE_DB.showData;
|
||||
commonClear();
|
||||
};
|
||||
|
||||
const addSection = (label: string, value: number): void => {
|
||||
label = sanitizeText(label, commonGetConfig());
|
||||
if (sections[label] === undefined) {
|
||||
sections[label] = value;
|
||||
log.debug(`added new section: ${label}, with value: ${value}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getSections = (): Sections => sections;
|
||||
|
||||
const cleanupValue = (value: string): number => {
|
||||
if (value.substring(0, 1) === ':') {
|
||||
value = value.substring(1).trim();
|
||||
}
|
||||
return Number(value.trim());
|
||||
};
|
||||
|
||||
const setShowData = (toggle: boolean): void => {
|
||||
showData = toggle;
|
||||
};
|
||||
|
||||
const getShowData = (): boolean => showData;
|
||||
|
||||
export const db: PieDB = {
|
||||
getConfig,
|
||||
|
||||
parseDirective,
|
||||
clear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setAccDescription,
|
||||
getAccDescription,
|
||||
|
||||
addSection,
|
||||
getSections,
|
||||
cleanupValue,
|
||||
setShowData,
|
||||
getShowData,
|
||||
};
|
@ -15,10 +15,8 @@ const loader: DiagramLoader = async () => {
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
export const pie: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore: JISON doesn't support types
|
||||
import parser from './parser/pie.jison';
|
||||
import db from './pieDb.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './pieRenderer.js';
|
||||
import { db } from './pieDb.js';
|
||||
import styles from './pieStyles.js';
|
||||
import { renderer } from './pieRenderer.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
|
@ -1,204 +0,0 @@
|
||||
/** Created by AshishJ on 11-09-2019. */
|
||||
import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import { parseFontSize } from '../../utils.js';
|
||||
|
||||
let conf = configApi.getConfig();
|
||||
|
||||
/**
|
||||
* Draws a Pie Chart with the data given in text.
|
||||
*
|
||||
* @param text
|
||||
* @param id
|
||||
*/
|
||||
let width;
|
||||
const height = 450;
|
||||
export const draw = (txt, id, _version, diagObj) => {
|
||||
try {
|
||||
conf = configApi.getConfig();
|
||||
log.debug('Rendering info diagram\n' + txt);
|
||||
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the Pie Chart definition
|
||||
const elem = doc.getElementById(id);
|
||||
width = elem.parentElement.offsetWidth;
|
||||
|
||||
if (width === undefined) {
|
||||
width = 1200;
|
||||
}
|
||||
|
||||
if (conf.useWidth !== undefined) {
|
||||
width = conf.useWidth;
|
||||
}
|
||||
if (conf.pie.useWidth !== undefined) {
|
||||
width = conf.pie.useWidth;
|
||||
}
|
||||
|
||||
const diagram = root.select('#' + id);
|
||||
configureSvgSize(diagram, height, width, conf.pie.useMaxWidth);
|
||||
|
||||
// Set viewBox
|
||||
elem.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
var margin = 40;
|
||||
var legendRectSize = 18;
|
||||
var legendSpacing = 4;
|
||||
|
||||
var radius = Math.min(width, height) / 2 - margin;
|
||||
|
||||
var svg = diagram
|
||||
.append('g')
|
||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
var data = diagObj.db.getSections();
|
||||
var sum = 0;
|
||||
Object.keys(data).forEach(function (key) {
|
||||
sum += data[key];
|
||||
});
|
||||
|
||||
const themeVariables = conf.themeVariables;
|
||||
var myGeneratedColors = [
|
||||
themeVariables.pie1,
|
||||
themeVariables.pie2,
|
||||
themeVariables.pie3,
|
||||
themeVariables.pie4,
|
||||
themeVariables.pie5,
|
||||
themeVariables.pie6,
|
||||
themeVariables.pie7,
|
||||
themeVariables.pie8,
|
||||
themeVariables.pie9,
|
||||
themeVariables.pie10,
|
||||
themeVariables.pie11,
|
||||
themeVariables.pie12,
|
||||
];
|
||||
|
||||
const textPosition = conf.pie?.textPosition ?? 0.75;
|
||||
let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth);
|
||||
outerStrokeWidth ??= 2;
|
||||
|
||||
// Set the color scale
|
||||
var color = scaleOrdinal().range(myGeneratedColors);
|
||||
|
||||
// Compute the position of each group on the pie:
|
||||
var pieData = Object.entries(data).map(function (el, idx) {
|
||||
return {
|
||||
order: idx,
|
||||
name: el[0],
|
||||
value: el[1],
|
||||
};
|
||||
});
|
||||
var pie = d3pie()
|
||||
.value(function (d) {
|
||||
return d.value;
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
// Sort slices in clockwise direction
|
||||
return a.order - b.order;
|
||||
});
|
||||
var dataReady = pie(pieData);
|
||||
|
||||
// Shape helper to build arcs:
|
||||
var arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
||||
var labelArcGenerator = arc()
|
||||
.innerRadius(radius * textPosition)
|
||||
.outerRadius(radius * textPosition);
|
||||
|
||||
svg
|
||||
.append('circle')
|
||||
.attr('cx', 0)
|
||||
.attr('cy', 0)
|
||||
.attr('r', radius + outerStrokeWidth / 2)
|
||||
.attr('class', 'pieOuterCircle');
|
||||
|
||||
// Build the pie chart: each part of the pie is a path that we build using the arc function.
|
||||
svg
|
||||
.selectAll('mySlices')
|
||||
.data(dataReady)
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('d', arcGenerator)
|
||||
.attr('fill', function (d) {
|
||||
return color(d.data.name);
|
||||
})
|
||||
.attr('class', 'pieCircle');
|
||||
|
||||
// Now add the percentage.
|
||||
// Use the centroid method to get the best coordinates.
|
||||
svg
|
||||
.selectAll('mySlices')
|
||||
.data(dataReady)
|
||||
.enter()
|
||||
.append('text')
|
||||
.text(function (d) {
|
||||
return ((d.data.value / sum) * 100).toFixed(0) + '%';
|
||||
})
|
||||
.attr('transform', function (d) {
|
||||
return 'translate(' + labelArcGenerator.centroid(d) + ')';
|
||||
})
|
||||
.style('text-anchor', 'middle')
|
||||
.attr('class', 'slice');
|
||||
|
||||
svg
|
||||
.append('text')
|
||||
.text(diagObj.db.getDiagramTitle())
|
||||
.attr('x', 0)
|
||||
.attr('y', -(height - 50) / 2)
|
||||
.attr('class', 'pieTitleText');
|
||||
|
||||
// Add the legends/annotations for each section
|
||||
var legend = svg
|
||||
.selectAll('.legend')
|
||||
.data(color.domain())
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'legend')
|
||||
.attr('transform', function (d, i) {
|
||||
const height = legendRectSize + legendSpacing;
|
||||
const offset = (height * color.domain().length) / 2;
|
||||
const horizontal = 12 * legendRectSize;
|
||||
const vertical = i * height - offset;
|
||||
return 'translate(' + horizontal + ',' + vertical + ')';
|
||||
});
|
||||
|
||||
legend
|
||||
.append('rect')
|
||||
.attr('width', legendRectSize)
|
||||
.attr('height', legendRectSize)
|
||||
.style('fill', color)
|
||||
.style('stroke', color);
|
||||
|
||||
legend
|
||||
.data(dataReady)
|
||||
.append('text')
|
||||
.attr('x', legendRectSize + legendSpacing)
|
||||
.attr('y', legendRectSize - legendSpacing)
|
||||
.text(function (d) {
|
||||
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
|
||||
return d.data.name + ' [' + d.data.value + ']';
|
||||
} else {
|
||||
return d.data.name;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('Error while rendering info diagram');
|
||||
log.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
179
packages/mermaid/src/diagrams/pie/pieRenderer.ts
Normal file
179
packages/mermaid/src/diagrams/pie/pieRenderer.ts
Normal file
@ -0,0 +1,179 @@
|
||||
import d3, { scaleOrdinal, pie as d3pie, arc } from 'd3';
|
||||
|
||||
import { log } from '../../logger.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
import { cleanAndMerge, parseFontSize } from '../../utils.js';
|
||||
import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
|
||||
import type { D3Sections, PieDB, Sections } from './pieTypes.js';
|
||||
import type { MermaidConfig, PieDiagramConfig } from '../../config.type.js';
|
||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||
|
||||
const createPieArcs = (sections: Sections): d3.PieArcDatum<D3Sections>[] => {
|
||||
// Compute the position of each group on the pie:
|
||||
const pieData: D3Sections[] = Object.entries(sections).map(
|
||||
(element: [string, number]): D3Sections => {
|
||||
return {
|
||||
label: element[0],
|
||||
value: element[1],
|
||||
};
|
||||
}
|
||||
);
|
||||
const pie: d3.Pie<unknown, D3Sections> = d3pie<D3Sections>().value(
|
||||
(d3Section: D3Sections): number => d3Section.value
|
||||
);
|
||||
return pie(pieData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a Pie Chart with the data given in text.
|
||||
*
|
||||
* @param text - pie chart code
|
||||
* @param id - diagram id
|
||||
* @param _version - MermaidJS version from package.json.
|
||||
* @param diagObj - A standard diagram containing the DB and the text and type etc of the diagram.
|
||||
*/
|
||||
export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
log.debug('rendering pie chart\n' + text);
|
||||
|
||||
const db = diagObj.db as PieDB;
|
||||
const globalConfig: MermaidConfig = getConfig();
|
||||
const pieConfig: Required<PieDiagramConfig> = cleanAndMerge(db.getConfig(), globalConfig.pie);
|
||||
|
||||
const height = 450;
|
||||
// TODO: remove document width
|
||||
const width: number =
|
||||
document.getElementById(id)?.parentElement?.offsetWidth ?? pieConfig.useWidth;
|
||||
const svg: SVG = selectSvgElement(id);
|
||||
// Set viewBox
|
||||
svg.attr('viewBox', `0 0 ${width} ${height}`);
|
||||
configureSvgSize(svg, height, width, pieConfig.useMaxWidth);
|
||||
|
||||
const MARGIN = 40;
|
||||
const LEGEND_RECT_SIZE = 18;
|
||||
const LEGEND_SPACING = 4;
|
||||
|
||||
const group: Group = svg.append('g');
|
||||
group.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
const { themeVariables } = globalConfig;
|
||||
let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth);
|
||||
outerStrokeWidth ??= 2;
|
||||
|
||||
const textPosition: number = pieConfig.textPosition;
|
||||
const radius: number = Math.min(width, height) / 2 - MARGIN;
|
||||
// Shape helper to build arcs:
|
||||
const arcGenerator: d3.Arc<unknown, d3.PieArcDatum<D3Sections>> = arc<
|
||||
d3.PieArcDatum<D3Sections>
|
||||
>()
|
||||
.innerRadius(0)
|
||||
.outerRadius(radius);
|
||||
const labelArcGenerator: d3.Arc<unknown, d3.PieArcDatum<D3Sections>> = arc<
|
||||
d3.PieArcDatum<D3Sections>
|
||||
>()
|
||||
.innerRadius(radius * textPosition)
|
||||
.outerRadius(radius * textPosition);
|
||||
|
||||
group
|
||||
.append('circle')
|
||||
.attr('cx', 0)
|
||||
.attr('cy', 0)
|
||||
.attr('r', radius + outerStrokeWidth / 2)
|
||||
.attr('class', 'pieOuterCircle');
|
||||
|
||||
const sections: Sections = db.getSections();
|
||||
const arcs: d3.PieArcDatum<D3Sections>[] = createPieArcs(sections);
|
||||
|
||||
const myGeneratedColors = [
|
||||
themeVariables.pie1,
|
||||
themeVariables.pie2,
|
||||
themeVariables.pie3,
|
||||
themeVariables.pie4,
|
||||
themeVariables.pie5,
|
||||
themeVariables.pie6,
|
||||
themeVariables.pie7,
|
||||
themeVariables.pie8,
|
||||
themeVariables.pie9,
|
||||
themeVariables.pie10,
|
||||
themeVariables.pie11,
|
||||
themeVariables.pie12,
|
||||
];
|
||||
// Set the color scale
|
||||
const color: d3.ScaleOrdinal<string, 12, never> = scaleOrdinal(myGeneratedColors);
|
||||
|
||||
// Build the pie chart: each part of the pie is a path that we build using the arc function.
|
||||
group
|
||||
.selectAll('mySlices')
|
||||
.data(arcs)
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('d', arcGenerator)
|
||||
.attr('fill', (datum: d3.PieArcDatum<D3Sections>) => {
|
||||
return color(datum.data.label);
|
||||
})
|
||||
.attr('class', 'pieCircle');
|
||||
|
||||
let sum = 0;
|
||||
Object.keys(sections).forEach((key: string): void => {
|
||||
sum += sections[key];
|
||||
});
|
||||
// Now add the percentage.
|
||||
// Use the centroid method to get the best coordinates.
|
||||
group
|
||||
.selectAll('mySlices')
|
||||
.data(arcs)
|
||||
.enter()
|
||||
.append('text')
|
||||
.text((datum: d3.PieArcDatum<D3Sections>): string => {
|
||||
return ((datum.data.value / sum) * 100).toFixed(0) + '%';
|
||||
})
|
||||
.attr('transform', (datum: d3.PieArcDatum<D3Sections>): string => {
|
||||
return 'translate(' + labelArcGenerator.centroid(datum) + ')';
|
||||
})
|
||||
.style('text-anchor', 'middle')
|
||||
.attr('class', 'slice');
|
||||
|
||||
group
|
||||
.append('text')
|
||||
.text(db.getDiagramTitle())
|
||||
.attr('x', 0)
|
||||
.attr('y', -(height - 50) / 2)
|
||||
.attr('class', 'pieTitleText');
|
||||
|
||||
// Add the legends/annotations for each section
|
||||
const legend = group
|
||||
.selectAll('.legend')
|
||||
.data(color.domain())
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'legend')
|
||||
.attr('transform', (_datum, index: number): string => {
|
||||
const height = LEGEND_RECT_SIZE + LEGEND_SPACING;
|
||||
const offset = (height * color.domain().length) / 2;
|
||||
const horizontal = 12 * LEGEND_RECT_SIZE;
|
||||
const vertical = index * height - offset;
|
||||
return 'translate(' + horizontal + ',' + vertical + ')';
|
||||
});
|
||||
|
||||
legend
|
||||
.append('rect')
|
||||
.attr('width', LEGEND_RECT_SIZE)
|
||||
.attr('height', LEGEND_RECT_SIZE)
|
||||
.style('fill', color)
|
||||
.style('stroke', color);
|
||||
|
||||
legend
|
||||
.data(arcs)
|
||||
.append('text')
|
||||
.attr('x', LEGEND_RECT_SIZE + LEGEND_SPACING)
|
||||
.attr('y', LEGEND_RECT_SIZE - LEGEND_SPACING)
|
||||
.text((datum: d3.PieArcDatum<D3Sections>): string => {
|
||||
const { label, value } = datum.data;
|
||||
if (db.getShowData()) {
|
||||
return `${label} [${value}]`;
|
||||
}
|
||||
return label;
|
||||
});
|
||||
};
|
||||
|
||||
export const renderer = { draw };
|
@ -1,4 +1,7 @@
|
||||
const getStyles = (options) =>
|
||||
import type { DiagramStylesProvider } from '../../diagram-api/types.js';
|
||||
import type { PieStyleOptions } from './pieTypes.js';
|
||||
|
||||
const getStyles: DiagramStylesProvider = (options: PieStyleOptions) =>
|
||||
`
|
||||
.pieCircle{
|
||||
stroke: ${options.pieStrokeColor};
|
64
packages/mermaid/src/diagrams/pie/pieTypes.ts
Normal file
64
packages/mermaid/src/diagrams/pie/pieTypes.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import type { PieDiagramConfig } from '../../config.type.js';
|
||||
import type { DiagramDB, ParseDirectiveDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
export interface PieFields {
|
||||
sections: Sections;
|
||||
showData: boolean;
|
||||
config: PieDiagramConfig;
|
||||
}
|
||||
|
||||
export interface PieStyleOptions {
|
||||
fontFamily: string;
|
||||
pie1: string;
|
||||
pie2: string;
|
||||
pie3: string;
|
||||
pie4: string;
|
||||
pie5: string;
|
||||
pie6: string;
|
||||
pie7: string;
|
||||
pie8: string;
|
||||
pie9: string;
|
||||
pie10: string;
|
||||
pie11: string;
|
||||
pie12: string;
|
||||
pieTitleTextSize: string;
|
||||
pieTitleTextColor: string;
|
||||
pieSectionTextSize: string;
|
||||
pieSectionTextColor: string;
|
||||
pieLegendTextSize: string;
|
||||
pieLegendTextColor: string;
|
||||
pieStrokeColor: string;
|
||||
pieStrokeWidth: string;
|
||||
pieOuterStrokeWidth: string;
|
||||
pieOuterStrokeColor: string;
|
||||
pieOpacity: string;
|
||||
}
|
||||
|
||||
export type Sections = Record<string, number>;
|
||||
|
||||
export interface D3Sections {
|
||||
label: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface PieDB extends DiagramDB {
|
||||
// config
|
||||
getConfig: () => Required<PieDiagramConfig>;
|
||||
|
||||
// common db
|
||||
parseDirective: ParseDirectiveDefinition;
|
||||
clear: () => void;
|
||||
setDiagramTitle: (title: string) => void;
|
||||
getDiagramTitle: () => string;
|
||||
setAccTitle: (title: string) => void;
|
||||
getAccTitle: () => string;
|
||||
setAccDescription: (describetion: string) => void;
|
||||
getAccDescription: () => string;
|
||||
|
||||
// diagram db
|
||||
addSection: (label: string, value: number) => void;
|
||||
getSections: () => Sections;
|
||||
cleanupValue: (value: string) => number;
|
||||
setShowData: (toggle: boolean) => void;
|
||||
getShowData: () => boolean;
|
||||
}
|
@ -24,6 +24,9 @@ const getBaseFile = (url: URL): Redirect => {
|
||||
return { path, id };
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to redirect old documentation pages to corresponding new pages.
|
||||
*/
|
||||
const idRedirectMap: Record<string, string> = {
|
||||
'8.6.0_docs': '',
|
||||
accessibility: 'config/theming',
|
||||
@ -68,6 +71,9 @@ const idRedirectMap: Record<string, string> = {
|
||||
'user-journey': 'syntax/userJourney',
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to redirect pages that have been moved in the vitepress site.
|
||||
*/
|
||||
const urlRedirectMap: Record<string, string> = {
|
||||
'/misc/faq.html': 'configure/faq.html',
|
||||
'/syntax/c4c.html': 'syntax/c4.html',
|
||||
|
@ -21,7 +21,7 @@ import flowchartElk from './diagrams/flowchart/elk/styles.js';
|
||||
import er from './diagrams/er/styles.js';
|
||||
import git from './diagrams/git/styles.js';
|
||||
import gantt from './diagrams/gantt/styles.js';
|
||||
import pie from './diagrams/pie/styles.js';
|
||||
import pie from './diagrams/pie/pieStyles.js';
|
||||
import requirement from './diagrams/requirement/styles.js';
|
||||
import sequence from './diagrams/sequence/styles.js';
|
||||
import state from './diagrams/state/styles.js';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { vi } from 'vitest';
|
||||
import utils from './utils.js';
|
||||
import utils, { cleanAndMerge } from './utils.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import { detectType } from './diagram-api/detectType.js';
|
||||
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
||||
@ -10,51 +10,51 @@ addDiagrams();
|
||||
|
||||
describe('when assignWithDepth: should merge objects within objects', function () {
|
||||
it('should handle simple, depth:1 types (identity)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = { foo: 'bar', bar: 0 };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: 0 };
|
||||
const config_1 = { foo: 'bar', bar: 0 };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle simple, depth:1 types (dst: undefined)', function () {
|
||||
let config_0 = undefined;
|
||||
let config_1 = { foo: 'bar', bar: 0 };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = undefined;
|
||||
const config_1 = { foo: 'bar', bar: 0 };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle simple, depth:1 types (src: undefined)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = undefined;
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: 0 };
|
||||
const config_1 = undefined;
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_0);
|
||||
});
|
||||
it('should handle simple, depth:1 types (merge)', function () {
|
||||
let config_0 = { foo: 'bar', bar: 0 };
|
||||
let config_1 = { foo: 'foo' };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: 0 };
|
||||
const config_1 = { foo: 'foo' };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({ foo: 'foo', bar: 0 });
|
||||
});
|
||||
it('should handle depth:2 types (dst: orphan)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let config_1 = { foo: 'bar' };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
const config_1 = { foo: 'bar' };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_0);
|
||||
});
|
||||
it('should handle depth:2 types (dst: object, src: simple type)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let config_1 = { foo: 'foo', bar: 'should NOT clobber' };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
const config_1 = { foo: 'foo', bar: 'should NOT clobber' };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({ foo: 'foo', bar: { foo: 'bar' } });
|
||||
});
|
||||
it('should handle depth:2 types (src: orphan)', function () {
|
||||
let config_0 = { foo: 'bar' };
|
||||
let config_1 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar' };
|
||||
const config_1 = { foo: 'bar', bar: { foo: 'bar' } };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual(config_1);
|
||||
});
|
||||
it('should handle depth:2 types (merge)', function () {
|
||||
let config_0 = { foo: 'bar', bar: { foo: 'bar' }, boofar: 1 };
|
||||
let config_1 = { foo: 'foo', bar: { bar: 0 }, foobar: 'foobar' };
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const config_0 = { foo: 'bar', bar: { foo: 'bar' }, boofar: 1 };
|
||||
const config_1 = { foo: 'foo', bar: { bar: 0 }, foobar: 'foobar' };
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'bar', bar: 0 },
|
||||
@ -63,17 +63,17 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
});
|
||||
});
|
||||
it('should handle depth:3 types (merge with clobber because assignWithDepth::depth == 2)', function () {
|
||||
let config_0 = {
|
||||
const config_0 = {
|
||||
foo: 'bar',
|
||||
bar: { foo: 'bar', bar: { foo: { message: 'this', willbe: 'clobbered' } } },
|
||||
boofar: 1,
|
||||
};
|
||||
let config_1 = {
|
||||
const config_1 = {
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = assignWithDepth(config_0, config_1);
|
||||
const result = assignWithDepth(config_0, config_1);
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
|
||||
@ -82,7 +82,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
});
|
||||
});
|
||||
it('should handle depth:3 types (merge with clobber because assignWithDepth::depth == 1)', function () {
|
||||
let config_0 = {
|
||||
const config_0 = {
|
||||
foo: 'bar',
|
||||
bar: {
|
||||
foo: 'bar',
|
||||
@ -90,12 +90,12 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
},
|
||||
boofar: 1,
|
||||
};
|
||||
let config_1 = {
|
||||
const config_1 = {
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = assignWithDepth(config_0, config_1, { depth: 1 });
|
||||
const result = assignWithDepth(config_0, config_1, { depth: 1 });
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
@ -104,17 +104,17 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
});
|
||||
});
|
||||
it('should handle depth:3 types (merge with no clobber because assignWithDepth::depth == 3)', function () {
|
||||
let config_0 = {
|
||||
const config_0 = {
|
||||
foo: 'bar',
|
||||
bar: { foo: 'bar', bar: { foo: { message: '', willbe: 'present' } } },
|
||||
boofar: 1,
|
||||
};
|
||||
let config_1 = {
|
||||
const config_1 = {
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
|
||||
foobar: 'foobar',
|
||||
};
|
||||
let result = assignWithDepth(config_0, config_1, { depth: 3 });
|
||||
const result = assignWithDepth(config_0, config_1, { depth: 3 });
|
||||
expect(result).toEqual({
|
||||
foo: 'foo',
|
||||
bar: { foo: 'foo', bar: { foo: { message: 'this', willbe: 'present' } } },
|
||||
@ -125,8 +125,8 @@ describe('when assignWithDepth: should merge objects within objects', function (
|
||||
});
|
||||
describe('when memoizing', function () {
|
||||
it('should return the same value', function () {
|
||||
const fib = memoize(
|
||||
function (n, x, canary) {
|
||||
const fib: any = memoize(
|
||||
function (n: number, x: string, canary: { flag: boolean }) {
|
||||
canary.flag = true;
|
||||
if (n < 2) {
|
||||
return 1;
|
||||
@ -260,7 +260,7 @@ describe('when formatting urls', function () {
|
||||
it('should handle links', function () {
|
||||
const url = 'https://mermaid-js.github.io/mermaid/#/';
|
||||
|
||||
let config = { securityLevel: 'loose' };
|
||||
const config = { securityLevel: 'loose' };
|
||||
let result = utils.formatUrl(url, config);
|
||||
expect(result).toEqual(url);
|
||||
|
||||
@ -271,7 +271,7 @@ describe('when formatting urls', function () {
|
||||
it('should handle anchors', function () {
|
||||
const url = '#interaction';
|
||||
|
||||
let config = { securityLevel: 'loose' };
|
||||
const config = { securityLevel: 'loose' };
|
||||
let result = utils.formatUrl(url, config);
|
||||
expect(result).toEqual(url);
|
||||
|
||||
@ -282,7 +282,7 @@ describe('when formatting urls', function () {
|
||||
it('should handle mailto', function () {
|
||||
const url = 'mailto:user@user.user';
|
||||
|
||||
let config = { securityLevel: 'loose' };
|
||||
const config = { securityLevel: 'loose' };
|
||||
let result = utils.formatUrl(url, config);
|
||||
expect(result).toEqual(url);
|
||||
|
||||
@ -293,7 +293,7 @@ describe('when formatting urls', function () {
|
||||
it('should handle other protocols', function () {
|
||||
const url = 'notes://do-your-thing/id';
|
||||
|
||||
let config = { securityLevel: 'loose' };
|
||||
const config = { securityLevel: 'loose' };
|
||||
let result = utils.formatUrl(url, config);
|
||||
expect(result).toEqual(url);
|
||||
|
||||
@ -304,7 +304,7 @@ describe('when formatting urls', function () {
|
||||
it('should handle scripts', function () {
|
||||
const url = 'javascript:alert("test")';
|
||||
|
||||
let config = { securityLevel: 'loose' };
|
||||
const config = { securityLevel: 'loose' };
|
||||
let result = utils.formatUrl(url, config);
|
||||
expect(result).toEqual(url);
|
||||
|
||||
@ -425,6 +425,42 @@ describe('when parsing font sizes', function () {
|
||||
});
|
||||
|
||||
it('handles unparseable input', function () {
|
||||
// @ts-expect-error Explicitly testing unparsable input
|
||||
expect(utils.parseFontSize({ fontSize: 14 })).toEqual([undefined, undefined]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cleanAndMerge', () => {
|
||||
test('should merge objects', () => {
|
||||
expect(cleanAndMerge({ a: 1, b: 2 }, { b: 3 })).toEqual({ a: 1, b: 3 });
|
||||
expect(cleanAndMerge({ a: 1 }, { a: 2 })).toEqual({ a: 2 });
|
||||
});
|
||||
|
||||
test('should remove undefined values', () => {
|
||||
expect(cleanAndMerge({ a: 1, b: 2 }, { b: undefined })).toEqual({ a: 1, b: 2 });
|
||||
expect(cleanAndMerge({ a: 1, b: 2 }, { a: 2, b: undefined })).toEqual({ a: 2, b: 2 });
|
||||
expect(cleanAndMerge({ a: 1, b: { c: 2 } }, { a: 2, b: undefined })).toEqual({
|
||||
a: 2,
|
||||
b: { c: 2 },
|
||||
});
|
||||
// @ts-expect-error Explicitly testing different type
|
||||
expect(cleanAndMerge({ a: 1, b: { c: 2 } }, { a: 2, b: { c: undefined } })).toEqual({
|
||||
a: 2,
|
||||
b: { c: 2 },
|
||||
});
|
||||
});
|
||||
|
||||
test('should create deep copies of object', () => {
|
||||
const input: { a: number; b?: number } = { a: 1 };
|
||||
const output = cleanAndMerge(input, { b: 2 });
|
||||
expect(output).toEqual({ a: 1, b: 2 });
|
||||
output.b = 3;
|
||||
expect(input).toEqual({ a: 1 });
|
||||
|
||||
const inputDeep = { a: { b: 1 } };
|
||||
const outputDeep = cleanAndMerge(inputDeep, { a: { b: 2 } });
|
||||
expect(outputDeep).toEqual({ a: { b: 2 } });
|
||||
outputDeep.a.b = 3;
|
||||
expect(inputDeep).toEqual({ a: { b: 1 } });
|
||||
});
|
||||
});
|
@ -31,6 +31,7 @@ import { detectType } from './diagram-api/detectType.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import { MermaidConfig } from './config.type.js';
|
||||
import memoize from 'lodash-es/memoize.js';
|
||||
import merge from 'lodash-es/merge.js';
|
||||
|
||||
export const ZERO_WIDTH_SPACE = '\u200b';
|
||||
|
||||
@ -802,7 +803,7 @@ export const calculateTextDimensions: (
|
||||
);
|
||||
|
||||
export const initIdGenerator = class iterator {
|
||||
constructor(deterministic, seed) {
|
||||
constructor(deterministic, seed?: any) {
|
||||
this.deterministic = deterministic;
|
||||
// TODO: Seed is only used for length?
|
||||
this.seed = seed;
|
||||
@ -994,12 +995,17 @@ export const parseFontSize = (fontSize: string | number | undefined): [number?,
|
||||
}
|
||||
};
|
||||
|
||||
export function cleanAndMerge<T>(defaultData: T, data?: Partial<T>): T {
|
||||
return merge({}, defaultData, data);
|
||||
}
|
||||
|
||||
export default {
|
||||
assignWithDepth,
|
||||
wrapLabel,
|
||||
calculateTextHeight,
|
||||
calculateTextWidth,
|
||||
calculateTextDimensions,
|
||||
cleanAndMerge,
|
||||
detectInit,
|
||||
detectDirective,
|
||||
isSubstringInArray,
|
||||
|
84
pnpm-lock.yaml
generated
84
pnpm-lock.yaml
generated
@ -196,7 +196,7 @@ importers:
|
||||
dependencies:
|
||||
'@braintree/sanitize-url':
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
version: 6.0.2
|
||||
cytoscape:
|
||||
specifier: ^3.23.0
|
||||
version: 3.23.0
|
||||
@ -264,6 +264,9 @@ importers:
|
||||
'@types/d3-selection':
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
'@types/d3-shape':
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
'@types/dompurify':
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
@ -348,6 +351,9 @@ importers:
|
||||
start-server-and-test:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
type-fest:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
typedoc:
|
||||
specifier: ^0.24.5
|
||||
version: 0.24.5(typescript@5.0.4)
|
||||
@ -374,7 +380,7 @@ importers:
|
||||
dependencies:
|
||||
'@braintree/sanitize-url':
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
version: 6.0.2
|
||||
cytoscape:
|
||||
specifier: ^3.23.0
|
||||
version: 3.23.0
|
||||
@ -466,6 +472,58 @@ importers:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
|
||||
packages/mermaid/src/vitepress:
|
||||
dependencies:
|
||||
'@vueuse/core':
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0(vue@3.3.4)
|
||||
jiti:
|
||||
specifier: ^1.18.2
|
||||
version: 1.18.2
|
||||
vue:
|
||||
specifier: ^3.2.47
|
||||
version: 3.3.4
|
||||
devDependencies:
|
||||
'@iconify-json/carbon':
|
||||
specifier: ^1.1.16
|
||||
version: 1.1.16
|
||||
'@unocss/reset':
|
||||
specifier: ^0.55.0
|
||||
version: 0.55.0
|
||||
'@vite-pwa/vitepress':
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0(vite-plugin-pwa@0.16.0)
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1(vite@4.3.9)(vue@3.3.4)
|
||||
fast-glob:
|
||||
specifier: ^3.2.12
|
||||
version: 3.2.12
|
||||
https-localhost:
|
||||
specifier: ^4.7.1
|
||||
version: 4.7.1
|
||||
pathe:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
unocss:
|
||||
specifier: ^0.55.0
|
||||
version: 0.55.0(postcss@8.4.27)(rollup@2.79.1)(vite@4.3.9)
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.25.0
|
||||
version: 0.25.0(rollup@2.79.1)(vue@3.3.4)
|
||||
vite:
|
||||
specifier: ^4.3.9
|
||||
version: 4.3.9(@types/node@18.16.0)
|
||||
vite-plugin-pwa:
|
||||
specifier: ^0.16.0
|
||||
version: 0.16.0(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0)
|
||||
vitepress:
|
||||
specifier: 1.0.0-rc.4
|
||||
version: 1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0)
|
||||
workbox-window:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
|
||||
tests/webpack:
|
||||
dependencies:
|
||||
'@mermaid-js/mermaid-example-diagram':
|
||||
@ -2265,8 +2323,8 @@ packages:
|
||||
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
|
||||
dev: true
|
||||
|
||||
/@braintree/sanitize-url@6.0.1:
|
||||
resolution: {integrity: sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==}
|
||||
/@braintree/sanitize-url@6.0.2:
|
||||
resolution: {integrity: sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==}
|
||||
dev: false
|
||||
|
||||
/@colors/colors@1.5.0:
|
||||
@ -3634,7 +3692,7 @@ packages:
|
||||
'@types/node': 18.16.0
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.6.2
|
||||
ci-info: 3.8.0
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.10
|
||||
jest-changed-files: 29.5.0
|
||||
@ -4301,8 +4359,8 @@ packages:
|
||||
'@types/d3-path': 1.0.9
|
||||
dev: true
|
||||
|
||||
/@types/d3-shape@3.1.0:
|
||||
resolution: {integrity: sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==}
|
||||
/@types/d3-shape@3.1.1:
|
||||
resolution: {integrity: sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==}
|
||||
dependencies:
|
||||
'@types/d3-path': 3.0.0
|
||||
dev: true
|
||||
@ -4359,7 +4417,7 @@ packages:
|
||||
'@types/d3-scale': 4.0.3
|
||||
'@types/d3-scale-chromatic': 3.0.0
|
||||
'@types/d3-selection': 3.0.5
|
||||
'@types/d3-shape': 3.1.0
|
||||
'@types/d3-shape': 3.1.1
|
||||
'@types/d3-time': 3.0.0
|
||||
'@types/d3-time-format': 4.0.0
|
||||
'@types/d3-timer': 3.0.0
|
||||
@ -6613,11 +6671,6 @@ packages:
|
||||
engines: {node: '>=6.0'}
|
||||
dev: true
|
||||
|
||||
/ci-info@3.6.2:
|
||||
resolution: {integrity: sha512-lVZdhvbEudris15CLytp2u6Y0p5EKfztae9Fqa189MfNmln9F33XuH69v5fvNfiRN5/0eAUz2yJL3mo+nhaRKg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/ci-info@3.8.0:
|
||||
resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -14733,6 +14786,11 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/type-fest@4.1.0:
|
||||
resolution: {integrity: sha512-VJGJVepayd8OWavP+rgXt4i3bfLk+tSomTV7r4mca2XD/oTCWnkJlNkpXavkxdmtU2aKdAmFGeHvoQutOVHCZg==}
|
||||
engines: {node: '>=16'}
|
||||
dev: true
|
||||
|
||||
/type-is@1.6.18:
|
||||
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
Loading…
x
Reference in New Issue
Block a user