⚗️ Add radar renderer tests

This commit is contained in:
Thomas Di Cizerone
2025-03-16 22:04:30 +01:00
parent 5d1b27132a
commit bb5a7a585e
5 changed files with 124 additions and 22 deletions

View File

@@ -1,6 +1,11 @@
import { it, describe, expect } from 'vitest';
import { db } from './db.js';
import { parser } from './parser.js';
import { renderer, relativeRadius, closedRoundCurve } from './renderer.js';
import { Diagram } from '../../Diagram.js';
import mermaidAPI from '../../mermaidAPI.js';
import { a } from 'vitest/dist/chunks/suite.qtkXWc6R.js';
import { buildRadarStyleOptions } from './styles.js';
const {
clear,
@@ -135,10 +140,6 @@ describe('radar diagrams', () => {
curve mycurve{1,2,3}
`;
await expect(parser.parse(str)).resolves.not.toThrow();
// TODO: ✨ Fix this test
// expect(getConfig().marginTop).toBe(80);
// expect(getConfig().axisLabelFactor).toBe(1.25);
});
it('should parse radar diagram with theme override', async () => {
@@ -149,8 +150,6 @@ describe('radar diagrams', () => {
curve mycurve{1,2,3}
`;
await expect(parser.parse(str)).resolves.not.toThrow();
// TODO: ✨ Add tests for theme override
});
it('should handle radar diagram with radar style override', async () => {
@@ -161,7 +160,99 @@ describe('radar diagrams', () => {
curve mycurve{1,2,3}
`;
await expect(parser.parse(str)).resolves.not.toThrow();
});
// TODO: ✨ Add tests for style override
describe('renderer', () => {
describe('relativeRadius', () => {
it('should calculate relative radius', () => {
expect(relativeRadius(5, 0, 10, 100)).toBe(50);
});
it('should handle min value', () => {
expect(relativeRadius(0, 0, 10, 100)).toBe(0);
});
it('should handle max value', () => {
expect(relativeRadius(10, 0, 10, 100)).toBe(100);
});
it('should clip values below min', () => {
expect(relativeRadius(-5, 0, 10, 100)).toBe(0);
});
it('should clip values above max', () => {
expect(relativeRadius(15, 0, 10, 100)).toBe(100);
});
it('should handle negative min', () => {
expect(relativeRadius(5, -10, 10, 100)).toBe(75);
});
});
describe('closedRoundCurve', () => {
it('should construct a polygon if tension is 0', () => {
const points = [
{ x: 0, y: 0 },
{ x: 100, y: 0 },
{ x: 100, y: 100 },
{ x: 0, y: 100 },
];
const tension = 0;
const path = closedRoundCurve(points, tension);
expect(path).toMatchInlineSnapshot(
`"M0,0 C0,0 100,0 100,0 C100,0 100,100 100,100 C100,100 0,100 0,100 C0,100 0,0 0,0 Z"`
);
});
it('should construct a simple round curve', () => {
const points = [
{ x: 0, y: 0 },
{ x: 100, y: 100 },
];
const tension = 0.5;
const path = closedRoundCurve(points, tension);
expect(path).toMatchInlineSnapshot(`"M0,0 C0,0 100,100 100,100 C100,100 0,0 0,0 Z"`);
});
it('should construct a closed round curve', () => {
const points = [
{ x: 0, y: 0 },
{ x: 100, y: 0 },
{ x: 100, y: 100 },
{ x: 0, y: 100 },
];
const tension = 0.5;
const path = closedRoundCurve(points, tension);
expect(path).toMatchInlineSnapshot(
`"M0,0 C50,-50 50,-50 100,0 C150,50 150,50 100,100 C50,150 50,150 0,100 C-50,50 -50,50 0,0 Z"`
);
});
});
describe('draw', () => {
it('should draw a simple radar diagram', async () => {
const str = `radar-beta
axis A,B,C
curve mycurve{1,2,3}`;
await mermaidAPI.parse(str);
const diagram = await Diagram.fromText(str);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
});
it('should draw a complex radar diagram', async () => {
const str = `radar-beta
title Radar diagram
accTitle: Radar accTitle
accDescr: Radar accDescription
axis A["Axis A"], B["Axis B"] ,C["Axis C"]
curve mycurve["My Curve"]{1,2,3}
curve mycurve2["My Curve 2"]{ C: 1, A: 2, B: 3 }
graticule polygon
`;
await mermaidAPI.parse(str);
const diagram = await Diagram.fromText(str);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
});
});
});
});

View File

@@ -118,7 +118,6 @@ const drawAxes = (
}
};
export const renderer: DiagramRenderer = { draw };
function drawCurves(
g: SVGGroup,
axes: RadarAxis[],
@@ -159,12 +158,17 @@ function drawCurves(
});
}
function relativeRadius(value: number, minValue: number, maxValue: number, radius: number): number {
export function relativeRadius(
value: number,
minValue: number,
maxValue: number,
radius: number
): number {
const clippedValue = Math.min(Math.max(value, minValue), maxValue);
return (radius * (clippedValue - minValue)) / (maxValue - minValue);
}
function closedRoundCurve(points: { x: number; y: number }[], tension: number): string {
export function closedRoundCurve(points: { x: number; y: number }[], tension: number): string {
// Catmull-Rom spline helper function
const numPoints = points.length;
let d = `M${points[0].x},${points[0].y}`;
@@ -224,3 +228,5 @@ function drawLegend(
.text(curve.label);
});
}
export const renderer: DiagramRenderer = { draw };

View File

@@ -30,12 +30,18 @@ const genIndexStyles = (
return sections;
};
export const styles: DiagramStylesProvider = ({ radar }: { radar?: RadarStyleOptions } = {}) => {
export const buildRadarStyleOptions = (radar?: RadarStyleOptions) => {
const defaultThemeVariables = getThemeVariables();
const currentConfig = getConfigAPI();
const themeVariables = cleanAndMerge(defaultThemeVariables, currentConfig.themeVariables);
const radarOptions: RadarStyleOptions = cleanAndMerge(themeVariables.radar, radar);
return { themeVariables, radarOptions };
};
export const styles: DiagramStylesProvider = ({ radar }: { radar?: RadarStyleOptions } = {}) => {
const { themeVariables, radarOptions } = buildRadarStyleOptions(radar);
return `
.radarTitle {
font-size: ${themeVariables.fontSize};

View File

@@ -28,16 +28,16 @@ export interface RadarDB extends DiagramDBBase<RadarDiagramConfig> {
}
export interface RadarStyleOptions {
axisColor: string;
axisStrokeWidth: number;
axisLabelFontSize: number;
curveOpacity: number;
curveStrokeWidth: number;
graticuleColor: string;
graticuleOpacity: number;
graticuleStrokeWidth: number;
legendBoxSize: number;
legendFontSize: number;
axisColor?: string;
axisStrokeWidth?: number;
axisLabelFontSize?: number;
curveOpacity?: number;
curveStrokeWidth?: number;
graticuleColor?: string;
graticuleOpacity?: number;
graticuleStrokeWidth?: number;
legendBoxSize?: number;
legendFontSize?: number;
}
export interface RadarData {

View File

@@ -1679,7 +1679,6 @@ Alice->Bob: Hello Bob, how are you?`;
const diagram = await Diagram.fromText(str);
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
const { bounds, models } = diagram.renderer.bounds.getBounds();
expect(bounds.startx).toBe(0);
expect(bounds.starty).toBe(0);