Gráficos y Estadísticas chartsvgzero-dependencygaugekpigoalprogress
Gauge Chart
Indicador semicircular de progreso hacia un objetivo con el valor siempre visible como texto.
Vista Previa en Vivo
November
$73.4k 73% of $100k goal
View data
| Metric | Value | Goal | % of goal |
|---|---|---|---|
| Monthly sales goal | $73.4k | $100k | 73.4% |
Uso
Copia y pega este código directamente en tu página de Astro:
astro
---
import { GaugeChart } from 'astro-component-kit/charts';
---
<GaugeChart title="Sales goal" value={73400} max={100000} prefix="$" label="of $100k goal" /> ---
import { GaugeChart } from 'astro-component-kit/charts';
---
<GaugeChart title="Sales goal" value={73400} max={100000} prefix="$" label="of $100k goal" /> Instalación Manual
Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/lib/GaugeChart.astro:
astro
---
/**
* GaugeChart — Semicircular progress gauge for a single KPI against a goal,
* with the number and % of goal always shown as text.
*
* @param {number} value - Current value.
* @param {number} max - Goal / maximum.
* @param {string} label - Caption under the number.
* @param {string} prefix - Value prefix.
* @param {string} suffix - Value suffix.
* @param {string} color - Arc color.
* @param {string} variant - Card style (glass|solid|ghost).
* @param {string} size - Density (sm|md|lg).
*/
import ChartFrame from './ChartFrame.astro';
import { arcStroke, formatValue } from './chart-utils';
interface Props {
title?: string;
subtitle?: string;
value?: number;
max?: number;
label?: string;
prefix?: string;
suffix?: string;
color?: string;
variant?: 'glass' | 'solid' | 'ghost';
size?: 'sm' | 'md' | 'lg';
className?: string;
}
const {
title = 'Monthly sales goal',
subtitle = 'November',
value = 73400,
max = 100000,
label = 'of $100k goal',
prefix = '$',
suffix = '',
color = 'var(--chart-1, #3987e5)',
variant = 'glass',
size = 'md',
className = '',
} = Astro.props;
const W = 260;
const H = 150;
const cx = W / 2;
const cy = 132;
const r = 108;
const pct = Math.max(0, Math.min(1, value / (max || 1)));
const a0 = -Math.PI / 2;
const a1 = Math.PI / 2;
const fmt = (v: number) => formatValue(v, prefix, suffix);
---
<ChartFrame
title={title}
subtitle={subtitle}
variant={variant}
size={size}
className={className}
table={{ headers: ['Metric', 'Value', 'Goal', '% of goal'], rows: [[title, fmt(value), fmt(max), `${(pct * 100).toFixed(1)}%`]] }}
>
<div class="gc" role="meter" aria-valuemin={0} aria-valuemax={max} aria-valuenow={value} aria-label={`${title}: ${fmt(value)} ${label}, ${(pct * 100).toFixed(0)}%`}>
<svg viewBox={`0 0 ${W} ${H}`} aria-hidden="true">
<path d={arcStroke(cx, cy, r, a0, a1)} fill="none" stroke="rgb(var(--ink-rgb, 255 255 255) / 0.07)" stroke-width="18" stroke-linecap="round" />
{pct > 0 && <path class="gc__arc" d={arcStroke(cx, cy, r, a0, a0 + Math.PI * pct)} fill="none" stroke={color} stroke-width="18" stroke-linecap="round" />}
<text class="cf-label" x={cx - r} y={H - 2} text-anchor="middle">0</text>
<text class="cf-label" x={cx + r} y={H - 2} text-anchor="middle">{fmt(max)}</text>
</svg>
<div class="gc__center">
<span class="gc__value">{fmt(value)}</span>
<span class="gc__label">{(pct * 100).toFixed(0)}% {label}</span>
</div>
</div>
</ChartFrame>
<style>
.gc {
position: relative;
max-width: 340px;
margin: 0 auto;
}
.gc__arc {
stroke-dasharray: 400;
stroke-dashoffset: 400;
animation: gc-draw 1.1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes gc-draw { to { stroke-dashoffset: 0; } }
.gc__center {
position: absolute;
left: 0;
right: 0;
bottom: 6%;
display: flex;
flex-direction: column;
align-items: center;
}
.gc__value {
font-size: clamp(1.5rem, 5vw, 2rem);
font-weight: 750;
color: var(--c-text-1, #fff);
font-variant-numeric: tabular-nums;
line-height: 1.1;
}
.gc__label { font-size: 0.75rem; color: var(--c-text-2, #a3a3a3); }
@media (prefers-reduced-motion: reduce) {
.gc__arc { animation: none; stroke-dashoffset: 0; }
}
</style> ---
/**
* GaugeChart — Semicircular progress gauge for a single KPI against a goal,
* with the number and % of goal always shown as text.
*
* @param {number} value - Current value.
* @param {number} max - Goal / maximum.
* @param {string} label - Caption under the number.
* @param {string} prefix - Value prefix.
* @param {string} suffix - Value suffix.
* @param {string} color - Arc color.
* @param {string} variant - Card style (glass|solid|ghost).
* @param {string} size - Density (sm|md|lg).
*/
import ChartFrame from './ChartFrame.astro';
import { arcStroke, formatValue } from './chart-utils';
interface Props {
title?: string;
subtitle?: string;
value?: number;
max?: number;
label?: string;
prefix?: string;
suffix?: string;
color?: string;
variant?: 'glass' | 'solid' | 'ghost';
size?: 'sm' | 'md' | 'lg';
className?: string;
}
const {
title = 'Monthly sales goal',
subtitle = 'November',
value = 73400,
max = 100000,
label = 'of $100k goal',
prefix = '$',
suffix = '',
color = 'var(--chart-1, #3987e5)',
variant = 'glass',
size = 'md',
className = '',
} = Astro.props;
const W = 260;
const H = 150;
const cx = W / 2;
const cy = 132;
const r = 108;
const pct = Math.max(0, Math.min(1, value / (max || 1)));
const a0 = -Math.PI / 2;
const a1 = Math.PI / 2;
const fmt = (v: number) => formatValue(v, prefix, suffix);
---
<ChartFrame
title={title}
subtitle={subtitle}
variant={variant}
size={size}
className={className}
table={{ headers: ['Metric', 'Value', 'Goal', '% of goal'], rows: [[title, fmt(value), fmt(max), `${(pct * 100).toFixed(1)}%`]] }}
>
<div class="gc" role="meter" aria-valuemin={0} aria-valuemax={max} aria-valuenow={value} aria-label={`${title}: ${fmt(value)} ${label}, ${(pct * 100).toFixed(0)}%`}>
<svg viewBox={`0 0 ${W} ${H}`} aria-hidden="true">
<path d={arcStroke(cx, cy, r, a0, a1)} fill="none" stroke="rgb(var(--ink-rgb, 255 255 255) / 0.07)" stroke-width="18" stroke-linecap="round" />
{pct > 0 && <path class="gc__arc" d={arcStroke(cx, cy, r, a0, a0 + Math.PI * pct)} fill="none" stroke={color} stroke-width="18" stroke-linecap="round" />}
<text class="cf-label" x={cx - r} y={H - 2} text-anchor="middle">0</text>
<text class="cf-label" x={cx + r} y={H - 2} text-anchor="middle">{fmt(max)}</text>
</svg>
<div class="gc__center">
<span class="gc__value">{fmt(value)}</span>
<span class="gc__label">{(pct * 100).toFixed(0)}% {label}</span>
</div>
</div>
</ChartFrame>
<style>
.gc {
position: relative;
max-width: 340px;
margin: 0 auto;
}
.gc__arc {
stroke-dasharray: 400;
stroke-dashoffset: 400;
animation: gc-draw 1.1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes gc-draw { to { stroke-dashoffset: 0; } }
.gc__center {
position: absolute;
left: 0;
right: 0;
bottom: 6%;
display: flex;
flex-direction: column;
align-items: center;
}
.gc__value {
font-size: clamp(1.5rem, 5vw, 2rem);
font-weight: 750;
color: var(--c-text-1, #fff);
font-variant-numeric: tabular-nums;
line-height: 1.1;
}
.gc__label { font-size: 0.75rem; color: var(--c-text-2, #a3a3a3); }
@media (prefers-reduced-motion: reduce) {
.gc__arc { animation: none; stroke-dashoffset: 0; }
}
</style>
Información Rápida
- Categoría
- Gráficos y Estadísticas
- Nombre de archivo
GaugeChart.astro- Dependencias
- apexcharts (peer)
- Etiquetas
- chartsvgzero-dependencygaugekpigoalprogress