1 звезда на GitHub = 1 новый компонент.

Поставить звезду
Графики и статистика chartsvgzero-dependencypolarseasonalityradialcyclical

Polar Area Chart

Секторы равного угла с радиусом по площади для цикличных категорий, например месяцев.

Живое превью

Orders by month

Seasonality at a glance

Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
View data
ItemValue
Jan320
Feb280
Mar360
Apr410
May470
Jun520
Jul490
Aug450
Sep430
Oct510
Nov690
Dec820

Использование

Скопируйте и вставьте этот код на вашу страницу Astro:

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

<PolarAreaChart
  items={[
    { label: 'Q1', value: 320 },
    { label: 'Q2', value: 410 },
    { label: 'Q3', value: 380 },
    { label: 'Q4', value: 690 },
  ]}
/>
--- import { PolarAreaChart } from 'astro-component-kit/charts'; --- <PolarAreaChart items={[ { label: 'Q1', value: 320 }, { label: 'Q2', value: 410 }, { label: 'Q3', value: 380 }, { label: 'Q4', value: 690 }, ]} />

Ручная установка

Если вы не используете пакет npm, создайте файл и вставьте следующий код: src/components/lib/PolarAreaChart.astro:

astro
---
/**
 * PolarAreaChart — Equal-angle wedges whose radius encodes value (area-correct
 * via square-root scaling). Good for cyclical categories like months or hours.
 *
 * @param {Array<{label: string, value: number}>} items - Wedges (max 12).
 * @param {string} color - Wedge hue (single series).
 * @param {string} suffix - Value suffix.
 * @param {string} variant - Card style (glass|solid|ghost).
 * @param {string} size - Density (sm|md|lg).
 */
import ChartFrame from './ChartFrame.astro';
import { arcPath, polar, formatValue } from './chart-utils';

interface Props {
  title?: string;
  subtitle?: string;
  items?: Array<{ label: string; value: number }>;
  color?: string;
  prefix?: string;
  suffix?: string;
  variant?: 'glass' | 'solid' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

const {
  title = 'Orders by month',
  subtitle = 'Seasonality at a glance',
  items = [
    { label: 'Jan', value: 320 }, { label: 'Feb', value: 280 }, { label: 'Mar', value: 360 },
    { label: 'Apr', value: 410 }, { label: 'May', value: 470 }, { label: 'Jun', value: 520 },
    { label: 'Jul', value: 490 }, { label: 'Aug', value: 450 }, { label: 'Sep', value: 430 },
    { label: 'Oct', value: 510 }, { label: 'Nov', value: 690 }, { label: 'Dec', value: 820 },
  ],
  color = 'var(--chart-7, #9085e9)',
  prefix = '',
  suffix = '',
  variant = 'glass',
  size = 'md',
  className = '',
} = Astro.props;

const S = 320;
const c = S / 2;
const R = S / 2 - 26;
const max = Math.max(...items.map((i) => i.value)) || 1;
const n = Math.min(items.length, 12);
const sweep = (Math.PI * 2) / n;
const rings = [0.25, 0.5, 0.75, 1];
const fmt = (v: number) => formatValue(v, prefix, suffix);
---

<ChartFrame
  title={title}
  subtitle={subtitle}
  variant={variant}
  size={size}
  className={className}
  table={{ headers: ['Item', 'Value'], rows: items.map((i) => [i.label, fmt(i.value)]) }}
>
  <div class="pa">
    <svg viewBox={`0 0 ${S} ${S}`} role="img" aria-label={`${title}: polar area chart of ${n} categories`}>
      {rings.map((f) => <circle class="cf-grid" cx={c} cy={c} r={R * Math.sqrt(f)} fill="none" />)}
      {items.slice(0, n).map((it, i) => {
        const r = R * Math.sqrt(it.value / max);
        const a0 = i * sweep + 0.012;
        const a1 = (i + 1) * sweep - 0.012;
        const [lx, ly] = polar(c, c, R + 14, i * sweep + sweep / 2);
        const isMax = it.value === max;
        return (
          <g>
            <path class="cf-mark cf-dim" d={arcPath(c, c, r, 0, a0, a1)} fill={color} fill-opacity={0.35 + 0.6 * (it.value / max)}
              tabindex="0" role="img" aria-label={`${it.label}: ${fmt(it.value)}`} data-tip-title={it.label} data-tip={`${color}::${fmt(it.value)}`} />
            <text class={isMax ? 'cf-label cf-label--strong' : 'cf-label'} x={lx} y={ly + 4} text-anchor="middle">{it.label}</text>
          </g>
        );
      })}
    </svg>
  </div>
</ChartFrame>

<style>
  .pa { max-width: 360px; margin: 0 auto; }
</style>
--- /** * PolarAreaChart — Equal-angle wedges whose radius encodes value (area-correct * via square-root scaling). Good for cyclical categories like months or hours. * * @param {Array<{label: string, value: number}>} items - Wedges (max 12). * @param {string} color - Wedge hue (single series). * @param {string} suffix - Value suffix. * @param {string} variant - Card style (glass|solid|ghost). * @param {string} size - Density (sm|md|lg). */ import ChartFrame from './ChartFrame.astro'; import { arcPath, polar, formatValue } from './chart-utils'; interface Props { title?: string; subtitle?: string; items?: Array<{ label: string; value: number }>; color?: string; prefix?: string; suffix?: string; variant?: 'glass' | 'solid' | 'ghost'; size?: 'sm' | 'md' | 'lg'; className?: string; } const { title = 'Orders by month', subtitle = 'Seasonality at a glance', items = [ { label: 'Jan', value: 320 }, { label: 'Feb', value: 280 }, { label: 'Mar', value: 360 }, { label: 'Apr', value: 410 }, { label: 'May', value: 470 }, { label: 'Jun', value: 520 }, { label: 'Jul', value: 490 }, { label: 'Aug', value: 450 }, { label: 'Sep', value: 430 }, { label: 'Oct', value: 510 }, { label: 'Nov', value: 690 }, { label: 'Dec', value: 820 }, ], color = 'var(--chart-7, #9085e9)', prefix = '', suffix = '', variant = 'glass', size = 'md', className = '', } = Astro.props; const S = 320; const c = S / 2; const R = S / 2 - 26; const max = Math.max(...items.map((i) => i.value)) || 1; const n = Math.min(items.length, 12); const sweep = (Math.PI * 2) / n; const rings = [0.25, 0.5, 0.75, 1]; const fmt = (v: number) => formatValue(v, prefix, suffix); --- <ChartFrame title={title} subtitle={subtitle} variant={variant} size={size} className={className} table={{ headers: ['Item', 'Value'], rows: items.map((i) => [i.label, fmt(i.value)]) }} > <div class="pa"> <svg viewBox={`0 0 ${S} ${S}`} role="img" aria-label={`${title}: polar area chart of ${n} categories`}> {rings.map((f) => <circle class="cf-grid" cx={c} cy={c} r={R * Math.sqrt(f)} fill="none" />)} {items.slice(0, n).map((it, i) => { const r = R * Math.sqrt(it.value / max); const a0 = i * sweep + 0.012; const a1 = (i + 1) * sweep - 0.012; const [lx, ly] = polar(c, c, R + 14, i * sweep + sweep / 2); const isMax = it.value === max; return ( <g> <path class="cf-mark cf-dim" d={arcPath(c, c, r, 0, a0, a1)} fill={color} fill-opacity={0.35 + 0.6 * (it.value / max)} tabindex="0" role="img" aria-label={`${it.label}: ${fmt(it.value)}`} data-tip-title={it.label} data-tip={`${color}::${fmt(it.value)}`} /> <text class={isMax ? 'cf-label cf-label--strong' : 'cf-label'} x={lx} y={ly + 4} text-anchor="middle">{it.label}</text> </g> ); })} </svg> </div> </ChartFrame> <style> .pa { max-width: 360px; margin: 0 auto; } </style>

Краткая информация

Категория
Графики и статистика
Имя файла
PolarAreaChart.astro
Зависимости
apexcharts (peer)
Теги
chartsvgzero-dependencypolarseasonalityradialcyclical