mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-10 02:49:40 +02:00
initial converting pie files
This commit is contained in:
@@ -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 };
|
@@ -3,9 +3,11 @@ import { imgSnapshotTest } from '../../helpers/util.js';
|
|||||||
describe('info diagram', () => {
|
describe('info diagram', () => {
|
||||||
it('should handle an info definition', () => {
|
it('should handle an info definition', () => {
|
||||||
imgSnapshotTest(`info`);
|
imgSnapshotTest(`info`);
|
||||||
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle an info definition with showInfo', () => {
|
it('should handle an info definition with showInfo', () => {
|
||||||
imgSnapshotTest(`info showInfo`);
|
imgSnapshotTest(`info showInfo`);
|
||||||
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -5,7 +5,7 @@ import er from '../diagrams/er/erDetector.js';
|
|||||||
import git from '../diagrams/git/gitGraphDetector.js';
|
import git from '../diagrams/git/gitGraphDetector.js';
|
||||||
import gantt from '../diagrams/gantt/ganttDetector.js';
|
import gantt from '../diagrams/gantt/ganttDetector.js';
|
||||||
import { info } from '../diagrams/info/infoDetector.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 quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js';
|
||||||
import requirement from '../diagrams/requirement/requirementDetector.js';
|
import requirement from '../diagrams/requirement/requirementDetector.js';
|
||||||
import sequence from '../diagrams/sequence/sequenceDetector.js';
|
import sequence from '../diagrams/sequence/sequenceDetector.js';
|
||||||
|
@@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
148
packages/mermaid/src/diagrams/pie/pie.spec.ts
Normal file
148
packages/mermaid/src/diagrams/pie/pie.spec.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// @ts-ignore - jison doesn't export types
|
||||||
|
import { parser } from './parser/pie.jison';
|
||||||
|
import { db } from './pieDb.js';
|
||||||
|
import { setConfig } from '../../config.js';
|
||||||
|
|
||||||
|
setConfig({
|
||||||
|
securityLevel: 'strict',
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pie chart', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
parser.yy = db;
|
||||||
|
parser.yy.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
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 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
|
||||||
|
`);
|
||||||
|
|
||||||
|
const title = db.getDiagramTitle();
|
||||||
|
expect(title).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
|
||||||
|
`);
|
||||||
|
|
||||||
|
const title = db.getDiagramTitle();
|
||||||
|
expect(title).toBe('a neat chart');
|
||||||
|
|
||||||
|
const accTitle = db.getAccTitle();
|
||||||
|
expect(accTitle).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
|
||||||
|
`);
|
||||||
|
|
||||||
|
const title = db.getDiagramTitle();
|
||||||
|
expect(title).toBe('a neat chart');
|
||||||
|
|
||||||
|
const description = db.getAccDescription();
|
||||||
|
expect(description).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
|
||||||
|
`);
|
||||||
|
|
||||||
|
const title = db.getDiagramTitle();
|
||||||
|
expect(title).toBe('a neat chart');
|
||||||
|
|
||||||
|
const description = db.getAccDescription();
|
||||||
|
expect(description).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();
|
||||||
|
});
|
||||||
|
});
|
@@ -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,
|
|
||||||
};
|
|
88
packages/mermaid/src/diagrams/pie/pieDb.ts
Normal file
88
packages/mermaid/src/diagrams/pie/pieDb.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { log } from '../../logger.js';
|
||||||
|
import { parseDirective as _parseDirective } from '../../directiveUtils.js';
|
||||||
|
import { getConfig } 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 { PieDiagramConfig } from '../../config.type.js';
|
||||||
|
|
||||||
|
export const DEFAULT_PIE_CONFIG: PieDiagramConfig = {
|
||||||
|
useMaxWidth: true,
|
||||||
|
useWidth: 1200,
|
||||||
|
textPosition: 0.75,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const DEFAULT_PIE_DB: 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: PieDiagramConfig = {
|
||||||
|
useWidth: DEFAULT_PIE_DB.config.useWidth,
|
||||||
|
useMaxWidth: DEFAULT_PIE_DB.config.useMaxWidth,
|
||||||
|
textPosition: DEFAULT_PIE_DB.config.textPosition,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseDirective: ParseDirectiveDefinition = (statement, context, type) => {
|
||||||
|
_parseDirective(this, statement, context, type);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addSection = (label: string, value: number): void => {
|
||||||
|
label = sanitizeText(label, getConfig());
|
||||||
|
if (sections[label] === undefined) {
|
||||||
|
sections[label] = value;
|
||||||
|
log.debug(`added new section: ${label}, with value: ${value}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSections = (): Sections => sections;
|
||||||
|
|
||||||
|
const setShowData = (toggle: boolean): void => {
|
||||||
|
showData = toggle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getShowData = (): boolean => showData;
|
||||||
|
|
||||||
|
const cleanupValue = (value: string): number => {
|
||||||
|
if (value.substring(0, 1) === ':') {
|
||||||
|
value = value.substring(1).trim();
|
||||||
|
return Number(value.trim());
|
||||||
|
} else {
|
||||||
|
return Number(value.trim());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear = (): void => {
|
||||||
|
sections = DEFAULT_PIE_DB.sections;
|
||||||
|
showData = DEFAULT_PIE_DB.showData;
|
||||||
|
commonClear();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const db: PieDb = {
|
||||||
|
clear,
|
||||||
|
getConfig: () => getConfig().pie,
|
||||||
|
parseDirective,
|
||||||
|
setDiagramTitle,
|
||||||
|
getDiagramTitle,
|
||||||
|
setAccTitle,
|
||||||
|
getAccTitle,
|
||||||
|
setAccDescription,
|
||||||
|
getAccDescription,
|
||||||
|
addSection,
|
||||||
|
getSections,
|
||||||
|
cleanupValue,
|
||||||
|
setShowData,
|
||||||
|
getShowData,
|
||||||
|
};
|
@@ -15,10 +15,8 @@ const loader: DiagramLoader = async () => {
|
|||||||
return { id, diagram };
|
return { id, diagram };
|
||||||
};
|
};
|
||||||
|
|
||||||
const plugin: ExternalDiagramDefinition = {
|
export const pie: ExternalDiagramDefinition = {
|
||||||
id,
|
id,
|
||||||
detector,
|
detector,
|
||||||
loader,
|
loader,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default plugin;
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { DiagramDefinition } from '../../diagram-api/types.js';
|
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||||
// @ts-ignore: TODO Fix ts errors
|
// @ts-ignore - jison doesn't export types
|
||||||
import parser from './parser/pie.jison';
|
import parser from './parser/pie.jison';
|
||||||
import db from './pieDb.js';
|
import { db } from './pieDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
import renderer from './pieRenderer.js';
|
import renderer from './pieRenderer.js';
|
||||||
|
|
||||||
|
@@ -1,80 +1,71 @@
|
|||||||
/** Created by AshishJ on 11-09-2019. */
|
// @ts-nocheck - placeholder to be handled
|
||||||
import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
|
import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||||
import * as configApi from '../../config.js';
|
import { getConfig } from '../../config.js';
|
||||||
import { parseFontSize } from '../../utils.js';
|
import { parseFontSize } from '../../utils.js';
|
||||||
|
import type { DrawDefinition, HTML, SVG } from '../../diagram-api/types.js';
|
||||||
let conf = configApi.getConfig();
|
import type { PieDb, Sections } from './pieTypes.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a Pie Chart with the data given in text.
|
* Draws a Pie Chart with the data given in text.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param text - pie chart code
|
||||||
* @param id
|
* @param id - diagram id
|
||||||
*/
|
*/
|
||||||
let width;
|
const draw: DrawDefinition = (txt, id, _version, diagObj) => {
|
||||||
const height = 450;
|
|
||||||
export const draw = (txt, id, _version, diagObj) => {
|
|
||||||
try {
|
try {
|
||||||
conf = configApi.getConfig();
|
log.debug('rendering pie chart\n' + txt);
|
||||||
log.debug('Rendering info diagram\n' + txt);
|
|
||||||
|
|
||||||
const securityLevel = configApi.getConfig().securityLevel;
|
const config = getConfig();
|
||||||
// Handle root and Document for when rendering in sandbox mode
|
let width: number | undefined = config.pie?.useWidth;
|
||||||
let sandboxElement;
|
const height = 450;
|
||||||
|
|
||||||
|
const { securityLevel } = config;
|
||||||
|
// handle root and document for when rendering in sandbox mode
|
||||||
|
let sandboxElement: HTML | undefined;
|
||||||
|
let document: Document | null | undefined;
|
||||||
if (securityLevel === 'sandbox') {
|
if (securityLevel === 'sandbox') {
|
||||||
sandboxElement = select('#i' + id);
|
sandboxElement = select('#i' + id);
|
||||||
|
document = sandboxElement.nodes()[0].contentDocument;
|
||||||
|
width = document?.parentElement?.offsetWidth;
|
||||||
}
|
}
|
||||||
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
|
// @ts-ignore - figure out how to assign HTML to document type
|
||||||
diagObj.db.clear();
|
const root: HTML =
|
||||||
|
sandboxElement !== undefined && document !== undefined && document !== null
|
||||||
|
? select(document)
|
||||||
|
: select('body');
|
||||||
|
|
||||||
|
// parse the Pie Chart definition
|
||||||
|
const db = diagObj.db as PieDb;
|
||||||
|
db.clear();
|
||||||
|
log.debug('parsing pie chart');
|
||||||
diagObj.parser.parse(txt);
|
diagObj.parser.parse(txt);
|
||||||
log.debug('Parsed info diagram');
|
|
||||||
const elem = doc.getElementById(id);
|
|
||||||
width = elem.parentElement.offsetWidth;
|
|
||||||
|
|
||||||
if (width === undefined) {
|
if (width === undefined) {
|
||||||
width = 1200;
|
width = 1200;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf.useWidth !== undefined) {
|
const diagram: SVG = root.select('#' + id);
|
||||||
width = conf.useWidth;
|
configureSvgSize(diagram, height, width, config.pie?.useMaxWidth || true);
|
||||||
}
|
|
||||||
if (conf.pie.useWidth !== undefined) {
|
|
||||||
width = conf.pie.useWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
const diagram = root.select('#' + id);
|
// set viewBox
|
||||||
configureSvgSize(diagram, height, width, conf.pie.useMaxWidth);
|
document?.parentElement?.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
||||||
|
|
||||||
// Set viewBox
|
// fetch the default direction, use TD if none was found
|
||||||
elem.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
const margin = 40;
|
||||||
|
const legendRectSize = 18;
|
||||||
|
const legendSpacing = 4;
|
||||||
|
|
||||||
// Fetch the default direction, use TD if none was found
|
const radius = Math.min(width, height) / 2 - margin;
|
||||||
var margin = 40;
|
|
||||||
var legendRectSize = 18;
|
|
||||||
var legendSpacing = 4;
|
|
||||||
|
|
||||||
var radius = Math.min(width, height) / 2 - margin;
|
const svg = diagram
|
||||||
|
|
||||||
var svg = diagram
|
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||||
|
|
||||||
var data = diagObj.db.getSections();
|
const themeVariables = config.themeVariables;
|
||||||
var sum = 0;
|
const myGeneratedColors = [
|
||||||
Object.keys(data).forEach(function (key) {
|
|
||||||
sum += data[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
const themeVariables = conf.themeVariables;
|
|
||||||
var myGeneratedColors = [
|
|
||||||
themeVariables.pie1,
|
themeVariables.pie1,
|
||||||
themeVariables.pie2,
|
themeVariables.pie2,
|
||||||
themeVariables.pie3,
|
themeVariables.pie3,
|
||||||
@@ -89,34 +80,41 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
themeVariables.pie12,
|
themeVariables.pie12,
|
||||||
];
|
];
|
||||||
|
|
||||||
const textPosition = conf.pie?.textPosition ?? 0.75;
|
const textPosition = config.pie?.textPosition ?? 0.75;
|
||||||
let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth);
|
let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth);
|
||||||
outerStrokeWidth ??= 2;
|
outerStrokeWidth ??= 2;
|
||||||
|
|
||||||
// Set the color scale
|
// Set the color scale
|
||||||
var color = scaleOrdinal().range(myGeneratedColors);
|
const color = scaleOrdinal().range(myGeneratedColors);
|
||||||
|
|
||||||
// Compute the position of each group on the pie:
|
const sections: Sections = db.getSections();
|
||||||
var pieData = Object.entries(data).map(function (el, idx) {
|
let sum = 0;
|
||||||
|
Object.keys(sections).forEach((key: string) => {
|
||||||
|
sum += sections[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// compute the position of each group on the pie:
|
||||||
|
const pieData = Object.entries(sections).map((el: [string, number], index: number) => {
|
||||||
return {
|
return {
|
||||||
order: idx,
|
order: index,
|
||||||
name: el[0],
|
name: el[0],
|
||||||
value: el[1],
|
value: el[1],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
var pie = d3pie()
|
const pie = d3pie()
|
||||||
.value(function (d) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
return d.value;
|
.value((d) => {
|
||||||
|
return d;
|
||||||
})
|
})
|
||||||
.sort(function (a, b) {
|
.sort((a, b) => {
|
||||||
// Sort slices in clockwise direction
|
// Sort slices in clockwise direction
|
||||||
return a.order - b.order;
|
return a.order - b.order;
|
||||||
});
|
});
|
||||||
var dataReady = pie(pieData);
|
const dataReady = pie(pieData);
|
||||||
|
|
||||||
// Shape helper to build arcs:
|
// Shape helper to build arcs:
|
||||||
var arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
const arcGenerator = arc().innerRadius(0).outerRadius(radius);
|
||||||
var labelArcGenerator = arc()
|
const labelArcGenerator = arc()
|
||||||
.innerRadius(radius * textPosition)
|
.innerRadius(radius * textPosition)
|
||||||
.outerRadius(radius * textPosition);
|
.outerRadius(radius * textPosition);
|
||||||
|
|
||||||
@@ -134,7 +132,8 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.enter()
|
.enter()
|
||||||
.append('path')
|
.append('path')
|
||||||
.attr('d', arcGenerator)
|
.attr('d', arcGenerator)
|
||||||
.attr('fill', function (d) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
|
.attr('fill', (d) => {
|
||||||
return color(d.data.name);
|
return color(d.data.name);
|
||||||
})
|
})
|
||||||
.attr('class', 'pieCircle');
|
.attr('class', 'pieCircle');
|
||||||
@@ -146,10 +145,12 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.data(dataReady)
|
.data(dataReady)
|
||||||
.enter()
|
.enter()
|
||||||
.append('text')
|
.append('text')
|
||||||
.text(function (d) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
|
.text((d) => {
|
||||||
return ((d.data.value / sum) * 100).toFixed(0) + '%';
|
return ((d.data.value / sum) * 100).toFixed(0) + '%';
|
||||||
})
|
})
|
||||||
.attr('transform', function (d) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
|
.attr('transform', (d) => {
|
||||||
return 'translate(' + labelArcGenerator.centroid(d) + ')';
|
return 'translate(' + labelArcGenerator.centroid(d) + ')';
|
||||||
})
|
})
|
||||||
.style('text-anchor', 'middle')
|
.style('text-anchor', 'middle')
|
||||||
@@ -157,23 +158,24 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
|
|
||||||
svg
|
svg
|
||||||
.append('text')
|
.append('text')
|
||||||
.text(diagObj.db.getDiagramTitle())
|
.text(db.getDiagramTitle())
|
||||||
.attr('x', 0)
|
.attr('x', 0)
|
||||||
.attr('y', -(height - 50) / 2)
|
.attr('y', -(height - 50) / 2)
|
||||||
.attr('class', 'pieTitleText');
|
.attr('class', 'pieTitleText');
|
||||||
|
|
||||||
// Add the legends/annotations for each section
|
// Add the legends/annotations for each section
|
||||||
var legend = svg
|
const legend = svg
|
||||||
.selectAll('.legend')
|
.selectAll('.legend')
|
||||||
.data(color.domain())
|
.data(color.domain())
|
||||||
.enter()
|
.enter()
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'legend')
|
.attr('class', 'legend')
|
||||||
.attr('transform', function (d, i) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
|
.attr('transform', (d, index: number) => {
|
||||||
const height = legendRectSize + legendSpacing;
|
const height = legendRectSize + legendSpacing;
|
||||||
const offset = (height * color.domain().length) / 2;
|
const offset = (height * color.domain().length) / 2;
|
||||||
const horizontal = 12 * legendRectSize;
|
const horizontal = 12 * legendRectSize;
|
||||||
const vertical = i * height - offset;
|
const vertical = index * height - offset;
|
||||||
return 'translate(' + horizontal + ',' + vertical + ')';
|
return 'translate(' + horizontal + ',' + vertical + ')';
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,19 +191,17 @@ export const draw = (txt, id, _version, diagObj) => {
|
|||||||
.append('text')
|
.append('text')
|
||||||
.attr('x', legendRectSize + legendSpacing)
|
.attr('x', legendRectSize + legendSpacing)
|
||||||
.attr('y', legendRectSize - legendSpacing)
|
.attr('y', legendRectSize - legendSpacing)
|
||||||
.text(function (d) {
|
// @ts-ignore: TODO Fix ts errors
|
||||||
if (diagObj.db.getShowData() || conf.showData || conf.pie.showData) {
|
.text((d) => {
|
||||||
|
if (db.getShowData()) {
|
||||||
return d.data.name + ' [' + d.data.value + ']';
|
return d.data.name + ' [' + d.data.value + ']';
|
||||||
} else {
|
} else {
|
||||||
return d.data.name;
|
return d.data.name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('Error while rendering info diagram');
|
log.error('error while rendering pie chart', e);
|
||||||
log.error(e);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export const renderer = { draw };
|
||||||
draw,
|
|
||||||
};
|
|
54
packages/mermaid/src/diagrams/pie/pieTypes.ts
Normal file
54
packages/mermaid/src/diagrams/pie/pieTypes.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
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 PieDb extends DiagramDB {
|
||||||
|
clear: () => void;
|
||||||
|
getConfig: () => PieDiagramConfig | undefined;
|
||||||
|
parseDirective: ParseDirectiveDefinition;
|
||||||
|
setDiagramTitle: (title: string) => void;
|
||||||
|
getDiagramTitle: () => string;
|
||||||
|
setAccTitle: (title: string) => void;
|
||||||
|
getAccTitle: () => string;
|
||||||
|
setAccDescription: (describetion: string) => void;
|
||||||
|
getAccDescription: () => string;
|
||||||
|
addSection: (label: string, value: number) => void;
|
||||||
|
cleanupValue: (value: string) => number;
|
||||||
|
getSections: () => Sections;
|
||||||
|
setShowData: (toggle: boolean) => void;
|
||||||
|
getShowData: () => boolean;
|
||||||
|
}
|
@@ -1,4 +1,6 @@
|
|||||||
const getStyles = (options) =>
|
import { PieStyleOptions } from './pieTypes.js';
|
||||||
|
|
||||||
|
const getStyles = (options: PieStyleOptions) =>
|
||||||
`
|
`
|
||||||
.pieCircle{
|
.pieCircle{
|
||||||
stroke: ${options.pieStrokeColor};
|
stroke: ${options.pieStrokeColor};
|
Reference in New Issue
Block a user