Sparkline Cards
render_sparkline_chartRender a grid of sparkline cards showing current values and trend lines for quick metric comparisons.
Instructions
Standalone sparkline card grid. Prefer using KPI cards with sparkline[] inside render_dashboard instead for a cleaner integrated look.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Chart title | |
| data | Yes | Array of sparkline card items | |
| theme | No | Theme preset: boardroom, corporate, sales-floor, golden-treasury, clinical, startup, ops-control, tokyo-midnight, zen-garden, consultant, black-tron, black-elegance, black-matrix, forest-amber, forest-earth, sky-light, sky-ocean, sky-twilight, gray-hf, gray-copilot | |
| palette | No | Override palette only (mix-and-match) | |
| typography | No | Override typography: professional, luxury, cyberpunk, editorial, mono, bold, system, techno | |
| effects | No | Override effects: none, subtle, shimmer, neon, energetic |
Implementation Reference
- src/charts/sparkline.ts:47-99 (handler)The main handler function for the render_sparkline_chart tool. Creates a sparkline card-based chart with SVG sparklines, color theming, click events, and export/refresh buttons.
export function renderSparklineChart(container: HTMLElement, payload: SparklineData): void { const theme = resolveTheme(payload.theme, { palette: payload.palette, typography: payload.typography, effects: payload.effects, }); if (theme) applyTheme(container, theme); const shimmer = theme?.effects.shimmerTitle ? " shimmer-text" : ""; const colors = resolveColors(undefined, payload.data.length); const cards = payload.data.map((item, i) => { const color = colors[i % colors.length]; const isGood = item.good !== undefined ? item.good : true; const changeClass = isGood ? "sparkline-card__change--good" : "sparkline-card__change--bad"; return ` <div class="sparkline-card" data-idx="${i}"> <div class="sparkline-card__header"> <span class="sparkline-card__label">${escapeHtml(item.label)}</span> ${item.change ? `<span class="sparkline-card__change ${changeClass}">${escapeHtml(item.change)}</span>` : ""} </div> <div class="sparkline-card__value">${escapeHtml(String(item.value))}</div> ${buildSparkSVG(item.sparkline, color)} </div> `; }).join(""); container.className = "chart-view"; container.innerHTML = ` <div class="card chart-card"> <div class="chart-card__header"> <div><div class="chart-card__title${shimmer}">${escapeHtml(payload.title)}</div></div> </div> <div class="chart-card__body chart-card__body--css"> <div class="sparkline-grid">${cards}</div> </div> </div> `; container.querySelectorAll<HTMLElement>(".sparkline-card").forEach((el) => { el.style.cursor = "pointer"; el.addEventListener("click", () => { const idx = parseInt(el.dataset.idx ?? "0", 10); const item = payload.data[idx]; sendClickMessage(`[Sparkline] "${payload.title}" - ${item.label}: ${item.value}`); }); }); const card = container.querySelector<HTMLElement>(".chart-card")!; addHtmlExportButton(card, payload.title); addRefreshButton(card, () => (window as any).__mcpRefresh?.()); } - src/charts/sparkline.ts:12-20 (schema)TypeScript interface SparklineData defining the input schema: type (sparkline), title, data array of SparklineItem (label, value, change, sparkline numbers, good), plus optional theme/palette/typography/effects.
interface SparklineData { type: "sparkline"; title: string; data: SparklineItem[]; theme?: string; palette?: string; typography?: string; effects?: string; } - src/charts/sparkline.ts:101-101 (registration)Registration call: registerChart('sparkline', 'render_sparkline_chart', renderSparklineChart) which enters the chart into the global registry under the tool name 'render_sparkline_chart'.
registerChart("sparkline", "render_sparkline_chart", renderSparklineChart); - src/charts/sparkline.ts:22-45 (helper)Helper function buildSparkSVG that generates an inline SVG from a numeric array and a color string, producing a sparkline with a line path and filled area.
function buildSparkSVG(data: number[], color: string): string { if (data.length === 0) return ""; const w = 120; const h = 32; const min = Math.min(...data); const max = Math.max(...data); const range = max - min || 1; const points = data.map((v, i) => { const x = (i / (data.length - 1)) * w; const y = h - ((v - min) / range) * (h - 4) - 2; return `${x},${y}`; }); const linePath = `M${points.join(" L")}`; const areaPath = `${linePath} L${w},${h} L0,${h} Z`; return ` <svg class="sparkline-card__svg" viewBox="0 0 ${w} ${h}" preserveAspectRatio="none"> <path class="sparkline-card__area" d="${areaPath}" fill="${color}" /> <path class="sparkline-card__path" d="${linePath}" stroke="${color}" /> </svg> `; } - src/app.ts:75-95 (handler)General renderFromData function that looks up the chart entry by type (e.g., 'sparkline') and calls its render method. This is the dispatch point that invokes renderSparklineChart.
function renderFromData(data: any): void { if (!data?.type) { root.innerHTML = `<div class="loading">No chart data received.</div>`; reportSize(); return; } try { const entry = getChartEntry(data.type); if (entry) { entry.render(root, data); } else { root.innerHTML = `<div class="loading">Unknown chart type: ${escapeHtml(String(data.type))}</div>`; } reportSize(); } catch (err) { console.error("Render error:", err); root.innerHTML = `<div class="loading">Error rendering chart. Check console.</div>`; reportSize(); } }