Skip to main content
Glama
sparkline.ts4.27 kB
import { ChartData, ChartResult } from '../types/index.js'; import { colorize } from '../utils/colors.js'; import { ASCII_CHARS, normalize, center } from '../utils/ascii.js'; export interface SparklineOptions { showMinMax?: boolean; fillChar?: string; } export function createSparkline(data: ChartData, options: SparklineOptions = {}): ChartResult { const { data: values, title, width = 40, color = 'white' } = data; const { showMinMax = true, fillChar } = options; if (values.length === 0) { throw new Error('Data array cannot be empty'); } const minValue = Math.min(...values); const maxValue = Math.max(...values); const valueRange = maxValue - minValue; // Calculate sparkline width (reserve space for min/max if shown) const sparklineWidth = showMinMax ? width - 20 : width; let sparkline = ''; // Generate sparkline using block characters if (fillChar) { // Use custom fill character for (let i = 0; i < Math.min(values.length, sparklineWidth); i++) { sparkline += fillChar; } } else { // Use gradient block characters const blocks = ASCII_CHARS.sparkBlocks; for (let i = 0; i < Math.min(values.length, sparklineWidth); i++) { const normalizedValue = valueRange === 0 ? 0.5 : normalize(values[i], minValue, maxValue); const blockIndex = Math.floor(normalizedValue * (blocks.length - 1)); sparkline += blocks[blockIndex]; } } // Add min/max values if requested if (showMinMax) { const minStr = minValue.toFixed(1); const maxStr = maxValue.toFixed(1); sparkline = `${minStr} ${sparkline} ${maxStr}`; } // Apply coloring if (color !== 'white') { sparkline = colorize(sparkline, color); } // Add title if provided let result = sparkline; if (title) { const titleLine = center(title, sparkline.length); result = titleLine + '\n' + sparkline; } return { chart: result, title, dimensions: { width: sparkline.length, height: title ? 2 : 1 } }; } export function createMultiSparkline(datasets: ChartData[], options: SparklineOptions = {}): ChartResult { // const { showMinMax = true } = options; if (datasets.length === 0) { throw new Error('At least one dataset is required'); } const maxWidth = Math.max(...datasets.map(d => d.width || 40)); let result = ''; for (let i = 0; i < datasets.length; i++) { const dataset = datasets[i]; const sparklineResult = createSparkline(dataset, options); const label = dataset.title || `Series ${i + 1}`; const labeledLine = `${label.padEnd(15)} ${sparklineResult.chart}`; result += labeledLine; if (i < datasets.length - 1) { result += '\n'; } } return { chart: result, dimensions: { width: maxWidth + 15, height: datasets.length } }; } export function createTrendSparkline(data: ChartData): ChartResult { const { data: values, title, width = 40, color = 'white' } = data; if (values.length < 2) { throw new Error('At least 2 values required for trend sparkline'); } let sparkline = ''; const trendChars = ['↓', '→', '↑']; for (let i = 1; i < Math.min(values.length, width); i++) { const current = values[i]; const previous = values[i - 1]; if (current > previous * 1.05) { // 5% threshold for up trend sparkline += trendChars[2]; // ↑ } else if (current < previous * 0.95) { // 5% threshold for down trend sparkline += trendChars[0]; // ↓ } else { sparkline += trendChars[1]; // → } } // Calculate overall trend const firstValue = values[0]; const lastValue = values[values.length - 1]; const overallTrend = lastValue > firstValue ? '📈' : lastValue < firstValue ? '📉' : '➡️'; sparkline += ` ${overallTrend}`; // Apply coloring if (color !== 'white') { sparkline = colorize(sparkline, color); } // Add title if provided let result = sparkline; if (title) { const titleLine = center(title, sparkline.length); result = titleLine + '\n' + sparkline; } return { chart: result, title, dimensions: { width: sparkline.length, height: title ? 2 : 1 } }; }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/gianlucamazza/mcp-ascii-charts'

If you have feedback or need assistance with the MCP directory API, please join our Discord server