1 estrella en GitHub = 1 componente nuevo.

Dar una estrella
Gráficos y Estadísticas chartsvgzero-dependencyheatmapmatrixsequentialgrid

Heatmap Chart

Mapa de calor matricial con rampa secuencial de un solo tono, valores y leyenda de escala.

Vista Previa en Vivo

Error rate by service

Per weekday, % of requests

MonTueWedThuFriSatSun
auth 0.2 0.3 0.2 0.4 0.6 0.1 0.1
billing 0.8 1.2 0.9 1.6 2.4 0.4 0.3
search 0.4 0.5 0.7 0.6 0.9 0.3 0.2
uploads 1.1 1.4 1.9 2.8 3.2 0.9 0.6
webhooks 0.3 0.2 0.4 0.5 0.4 0.2 0.1
View data
MonTueWedThuFriSatSun
auth0.2%0.3%0.2%0.4%0.6%0.1%0.1%
billing0.8%1.2%0.9%1.6%2.4%0.4%0.3%
search0.4%0.5%0.7%0.6%0.9%0.3%0.2%
uploads1.1%1.4%1.9%2.8%3.2%0.9%0.6%
webhooks0.3%0.2%0.4%0.5%0.4%0.2%0.1%

Uso

Copia y pega este código directamente en tu página de Astro:

astro
---
import { HeatmapChart } from 'astro-component-kit/charts';
---

<HeatmapChart
  rows={['auth', 'billing']}
  columns={['Mon', 'Tue', 'Wed']}
  values={[[0.2, 0.3, 0.2], [0.8, 1.2, 0.9]]}
  suffix="%"
/>
--- import { HeatmapChart } from 'astro-component-kit/charts'; --- <HeatmapChart rows={['auth', 'billing']} columns={['Mon', 'Tue', 'Wed']} values={[[0.2, 0.3, 0.2], [0.8, 1.2, 0.9]]} suffix="%" />

Instalación Manual

Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/lib/HeatmapChart.astro:

astro
---
/**
 * HeatmapChart — Matrix of cells colored on a single-hue sequential ramp
 * (light = low, saturated = high), with a scale legend.
 *
 * @param {string[]} rows - Row labels.
 * @param {string[]} columns - Column labels.
 * @param {number[][]} values - values[row][col].
 * @param {boolean} showValues - Print values inside cells.
 * @param {string} suffix - Value suffix.
 * @param {string} color - Ramp hue.
 * @param {string} variant - Card style (glass|solid|ghost).
 * @param {string} size - Density (sm|md|lg).
 */
import ChartFrame from './ChartFrame.astro';

interface Props {
  title?: string;
  subtitle?: string;
  rows?: string[];
  columns?: string[];
  values?: number[][];
  showValues?: boolean;
  suffix?: string;
  color?: string;
  variant?: 'glass' | 'solid' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

const {
  title = 'Error rate by service',
  subtitle = 'Per weekday, % of requests',
  rows = ['auth', 'billing', 'search', 'uploads', 'webhooks'],
  columns = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
  values = [
    [0.2, 0.3, 0.2, 0.4, 0.6, 0.1, 0.1],
    [0.8, 1.2, 0.9, 1.6, 2.4, 0.4, 0.3],
    [0.4, 0.5, 0.7, 0.6, 0.9, 0.3, 0.2],
    [1.1, 1.4, 1.9, 2.8, 3.2, 0.9, 0.6],
    [0.3, 0.2, 0.4, 0.5, 0.4, 0.2, 0.1],
  ],
  showValues = true,
  suffix = '%',
  color = 'var(--chart-1, #3987e5)',
  variant = 'glass',
  size = 'md',
  className = '',
} = Astro.props;

const flat = values.flat();
const min = Math.min(...flat);
const max = Math.max(...flat);
const t = (v: number) => (max === min ? 1 : (v - min) / (max - min));
const fill = (v: number) => `color-mix(in srgb, ${color} ${Math.round(12 + t(v) * 88)}%, #141416)`;
---

<ChartFrame
  title={title}
  subtitle={subtitle}
  variant={variant}
  size={size}
  className={className}
  table={{ headers: ['', ...columns], rows: rows.map((r, ri) => [r, ...values[ri].map((v) => `${v}${suffix}`)]) }}
>
  <div class="hm" style={`--hm-cols:${columns.length}`}>
    <div class="hm__grid" role="grid" aria-label={title}>
      <div class="hm__row" role="row">
        <span class="hm__corner" role="columnheader"></span>
        {columns.map((c) => <span class="hm__col" role="columnheader">{c}</span>)}
      </div>
      {rows.map((r, ri) => (
        <div class="hm__row" role="row">
          <span class="hm__rowlabel" role="rowheader">{r}</span>
          {columns.map((c, ci) => {
            const v = values[ri]?.[ci] ?? 0;
            return (
              <span class="hm__cell cf-mark" role="gridcell" tabindex="0" style={`background:${fill(v)}`}
                aria-label={`${r}, ${c}: ${v}${suffix}`} data-tip-title={`${r} · ${c}`} data-tip={`${v}${suffix}`}>
                {showValues && <span class={t(v) > 0.55 ? 'hm__v hm__v--strong' : 'hm__v'}>{v}</span>}
              </span>
            );
          })}
        </div>
      ))}
    </div>
    <div class="hm__scale" aria-hidden="true">
      <span>{min}{suffix}</span>
      <span class="hm__ramp" style={`background:linear-gradient(90deg, ${fill(min)}, ${fill(max)})`}></span>
      <span>{max}{suffix}</span>
    </div>
  </div>
</ChartFrame>

<style>
  .hm { overflow-x: auto; }
  .hm__grid { display: grid; gap: 3px; min-width: calc(5rem + var(--hm-cols) * 2.4rem); }
  .hm__row {
    display: grid;
    grid-template-columns: 5rem repeat(var(--hm-cols), minmax(2.2rem, 1fr));
    gap: 3px;
  }
  .hm__col { text-align: center; font-size: 0.6875rem; color: var(--c-text-3, #8a8a8a); padding-bottom: 0.2rem; }
  .hm__rowlabel {
    display: flex;
    align-items: center;
    font-size: 0.75rem;
    color: var(--c-text-2, #a3a3a3);
    font-family: var(--font-mono, monospace);
  }
  .hm__cell {
    display: grid;
    place-items: center;
    min-height: 34px;
    border-radius: 4px;
    transition: transform 0.15s ease;
  }
  .hm__cell:hover { transform: scale(1.06); }
  .hm__cell:focus-visible { outline: 2px solid var(--c-text-1, #fff); outline-offset: 1px; }
  .hm__v { font-size: 0.6875rem; color: rgb(var(--ink-rgb, 255 255 255) / 0.7); font-variant-numeric: tabular-nums; }
  .hm__v--strong { color: #fff; font-weight: 650; }
  .hm__scale {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.9rem;
    font-size: 0.6875rem;
    color: var(--c-text-3, #8a8a8a);
  }
  .hm__ramp { flex: 0 1 160px; height: 8px; border-radius: 4px; }
</style>
--- /** * HeatmapChart — Matrix of cells colored on a single-hue sequential ramp * (light = low, saturated = high), with a scale legend. * * @param {string[]} rows - Row labels. * @param {string[]} columns - Column labels. * @param {number[][]} values - values[row][col]. * @param {boolean} showValues - Print values inside cells. * @param {string} suffix - Value suffix. * @param {string} color - Ramp hue. * @param {string} variant - Card style (glass|solid|ghost). * @param {string} size - Density (sm|md|lg). */ import ChartFrame from './ChartFrame.astro'; interface Props { title?: string; subtitle?: string; rows?: string[]; columns?: string[]; values?: number[][]; showValues?: boolean; suffix?: string; color?: string; variant?: 'glass' | 'solid' | 'ghost'; size?: 'sm' | 'md' | 'lg'; className?: string; } const { title = 'Error rate by service', subtitle = 'Per weekday, % of requests', rows = ['auth', 'billing', 'search', 'uploads', 'webhooks'], columns = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], values = [ [0.2, 0.3, 0.2, 0.4, 0.6, 0.1, 0.1], [0.8, 1.2, 0.9, 1.6, 2.4, 0.4, 0.3], [0.4, 0.5, 0.7, 0.6, 0.9, 0.3, 0.2], [1.1, 1.4, 1.9, 2.8, 3.2, 0.9, 0.6], [0.3, 0.2, 0.4, 0.5, 0.4, 0.2, 0.1], ], showValues = true, suffix = '%', color = 'var(--chart-1, #3987e5)', variant = 'glass', size = 'md', className = '', } = Astro.props; const flat = values.flat(); const min = Math.min(...flat); const max = Math.max(...flat); const t = (v: number) => (max === min ? 1 : (v - min) / (max - min)); const fill = (v: number) => `color-mix(in srgb, ${color} ${Math.round(12 + t(v) * 88)}%, #141416)`; --- <ChartFrame title={title} subtitle={subtitle} variant={variant} size={size} className={className} table={{ headers: ['', ...columns], rows: rows.map((r, ri) => [r, ...values[ri].map((v) => `${v}${suffix}`)]) }} > <div class="hm" style={`--hm-cols:${columns.length}`}> <div class="hm__grid" role="grid" aria-label={title}> <div class="hm__row" role="row"> <span class="hm__corner" role="columnheader"></span> {columns.map((c) => <span class="hm__col" role="columnheader">{c}</span>)} </div> {rows.map((r, ri) => ( <div class="hm__row" role="row"> <span class="hm__rowlabel" role="rowheader">{r}</span> {columns.map((c, ci) => { const v = values[ri]?.[ci] ?? 0; return ( <span class="hm__cell cf-mark" role="gridcell" tabindex="0" style={`background:${fill(v)}`} aria-label={`${r}, ${c}: ${v}${suffix}`} data-tip-title={`${r} · ${c}`} data-tip={`${v}${suffix}`}> {showValues && <span class={t(v) > 0.55 ? 'hm__v hm__v--strong' : 'hm__v'}>{v}</span>} </span> ); })} </div> ))} </div> <div class="hm__scale" aria-hidden="true"> <span>{min}{suffix}</span> <span class="hm__ramp" style={`background:linear-gradient(90deg, ${fill(min)}, ${fill(max)})`}></span> <span>{max}{suffix}</span> </div> </div> </ChartFrame> <style> .hm { overflow-x: auto; } .hm__grid { display: grid; gap: 3px; min-width: calc(5rem + var(--hm-cols) * 2.4rem); } .hm__row { display: grid; grid-template-columns: 5rem repeat(var(--hm-cols), minmax(2.2rem, 1fr)); gap: 3px; } .hm__col { text-align: center; font-size: 0.6875rem; color: var(--c-text-3, #8a8a8a); padding-bottom: 0.2rem; } .hm__rowlabel { display: flex; align-items: center; font-size: 0.75rem; color: var(--c-text-2, #a3a3a3); font-family: var(--font-mono, monospace); } .hm__cell { display: grid; place-items: center; min-height: 34px; border-radius: 4px; transition: transform 0.15s ease; } .hm__cell:hover { transform: scale(1.06); } .hm__cell:focus-visible { outline: 2px solid var(--c-text-1, #fff); outline-offset: 1px; } .hm__v { font-size: 0.6875rem; color: rgb(var(--ink-rgb, 255 255 255) / 0.7); font-variant-numeric: tabular-nums; } .hm__v--strong { color: #fff; font-weight: 650; } .hm__scale { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.9rem; font-size: 0.6875rem; color: var(--c-text-3, #8a8a8a); } .hm__ramp { flex: 0 1 160px; height: 8px; border-radius: 4px; } </style>

Información Rápida

Categoría
Gráficos y Estadísticas
Nombre de archivo
HeatmapChart.astro
Dependencias
apexcharts (peer)
Etiquetas
chartsvgzero-dependencyheatmapmatrixsequentialgrid