import { DEFAULT_CHART_OPTIONS } from "./options"; import type { BarChartMetrics } from "./types/BarChartMetrics"; import type { BarChartOptions, ResolvedBarChartOptions, } from "./types/BarChartOptions"; import { getItemNames, resolveBarChartOptions, validateBarChartMetrics, } from "./utils/BarChartUtil"; import { createLegend, createTitle, createYAxis } from "./utils/ChartUtil"; /** * Default bar chart options */ export const DEFAULT_BAR_CHART_OPTIONS: BarChartOptions = { ...DEFAULT_CHART_OPTIONS, barPadding: 0.2, barGroupPadding: 0.4, }; /** * Creates the SVG bars for the bar chart * @param metrics - The data for the bar chart * @param config - Resolved bar chart options * @returns SVG string for the bars */ const createBars = ( metrics: BarChartMetrics, config: ResolvedBarChartOptions, ): string => { // Initialize SVG string let svg = ""; // Pre-compute values const itemsArray = getItemNames(metrics); const groupNames = Object.keys(metrics); const maxValue = config.maxValue; const chartWidth = config.width - config.margin.left - config.margin.right; const chartHeight = config.height - config.margin.top - config.margin.bottom; const groupWidth = chartWidth / groupNames.length; const barWidth = (groupWidth * (1 - config.barGroupPadding)) / itemsArray.length; groupNames.forEach((group, groupIndex) => { const groupX = groupIndex * groupWidth; // Add group name below the x-axis svg += ` ${group}\n`; itemsArray.forEach((item, itemIndex) => { const value = metrics[group][item] || 0; const barHeight = (value / maxValue) * chartHeight; const barX = groupX + (config.barGroupPadding * groupWidth) / 2 + itemIndex * barWidth; const barY = chartHeight - barHeight; const colorIndex = itemIndex % config.colors.length; // Draw the bar svg += ` \n`; // Add the value on top of or inside the bar if (config.showValues) { const formattedValue = config.formatValue(value); if (barHeight > config.fontSize * 2) { svg += ` ${formattedValue}\n`; } else { svg += ` ${formattedValue}\n`; } } }); }); return svg; }; /** * Generates an SVG bar chart from given metrics * @param metrics - The data for the bar chart * @param options - Optional configuration for the chart * @returns SVG string representing the bar chart */ export const generateBarChart = ( metrics: BarChartMetrics, options: Partial = {}, ): string => { // Validate input validateBarChartMetrics(metrics); // Resolve options const config = resolveBarChartOptions(options, metrics); // Create the SVG content let svg = `\n`; // Add a white background rectangle svg += ` \n`; // Add a title svg += createTitle(config); // Create a group for the chart content with a transform to account for margins svg += ` \n`; // Draw the y-axis and grid lines svg += createYAxis(config, config.maxValue); // Draw the bars svg += createBars(metrics, config); // Draw the legend const items = getItemNames(metrics); svg += createLegend(config, items); // Close the group and SVG svg += " \n"; return svg; };