> SYSTEM / CORE / COMPONENTS / DATA-VIZ _ « 返回索引
📊

数据可视化组件库

用于展示复杂数据的图表、进度条和统计面板。

组件配额 3
状态 ACTIVE

01. 贡献热力图 (Heatmap)

类似 GitHub 的提交记录热力图,展示数据频率。

Activity Heatmap
Less
More
---
interface Props {
  data?: number[];
  cellSize?: number;
  gap?: number;
  colors?: string[];
  title?: string;
}

const { 
  data = Array.from({ length: 35 }).map(() => Math.floor(Math.random() * 5)),
  cellSize = 14,
  gap = 4,
  colors = ['#161b22', '#0e4429', '#006d32', '#26a641', '#39d353'],
  title = "Activity Heatmap"
} = Astro.props;
---

<div class="heatmap-container">
  {title && <div class="heatmap-title">{title}</div>}
  <div class="heatmap-preview">
    <div class="grid" style={{ 
      gridTemplateColumns: `repeat(7, ${cellSize}px)`,
      gap: `${gap}px`
    }}>
      {data.map((level, i) => (
        <div 
          class={`cell level-${level}`} 
          style={{ 
            width: `${cellSize}px`, 
            height: `${cellSize}px`,
            backgroundColor: colors[level]
          }}
          title={`Level ${level}`}
        ></div>
      ))}
    </div>
  </div>
  <div class="heatmap-legend">
    <span>Less</span>
    <div class="legend-cells">
      {colors.map((color, i) => (
        <div class="legend-cell" style={{ backgroundColor: color }}></div>
      ))}
    </div>
    <span>More</span>
  </div>
</div>

<style>
  .heatmap-container {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.25rem;
    background: var(--glass-bg);
    border: var(--glass-border);
    border-radius: 12px;
    box-shadow: var(--glass-shadow);
  }

  .heatmap-title {
    font-size: 0.8rem;
    font-family: var(--font-mono);
    color: var(--color-neutral);
    text-transform: uppercase;
    letter-spacing: 1px;
  }

  .heatmap-preview {
    display: flex;
    justify-content: center;
  }

  .grid {
    display: grid;
  }

  .cell {
    border-radius: 2px;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    cursor: pointer;
  }

  .cell:hover {
    transform: scale(1.2);
    z-index: 2;
    box-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
  }

  .heatmap-legend {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    font-size: 0.7rem;
    color: var(--color-neutral);
  }

  .legend-cells {
    display: flex;
    gap: 3px;
  }

  .legend-cell {
    width: 10px;
    height: 10px;
    border-radius: 2px;
  }
</style>

组件特性

  • 数据映射:将数值自动映射到五个等级的颜色。
  • 动态网格:基于 CSS Grid,支持自定义行列比例。
  • 交互缩放:鼠标悬停时方格平滑放大,并显示详细信息。
  • 图例展示:内置 Legend 区域,清晰展示颜色等级含义。

使用建议

常用于展示 GitHub 贡献、用户活跃度或任何时间序列的频率数据。可以根据项目主题修改 colors 数组来适配不同的色彩倾向(如蓝色系或紫色系)。

示例配置

const data = [
  { date: '2023-01-01', count: 5 },
  { date: '2023-01-02', count: 12 },
  // ...
];

Attributes

参数 说明 类型 默认值
data 活跃度数据数组,0-4 表示不同强度 `number[]` []
cellSize 每个方格的大小 (px) `number` 14
gap 方格之间的间距 (px) `number` 4
colors 五个等级对应的颜色数组 `string[]` ['#161b22', '#0e4429', '#006d32', '#26a641', '#39d353']
title 热力图顶部的标题内容 `string` 'Activity Heatmap'

02. 圆形进度条 (Circular Progress)

动态展示百分比进度的圆形容器,支持自定义颜色和发光特效。

75%
---
interface Props {
  percent?: number;
  size?: number;
  strokeWidth?: number;
  showText?: boolean;
  color?: string;
}

const { 
  percent = 75, 
  size = 120, 
  strokeWidth = 10,
  showText = true,
  color = 'var(--color-primary-start)'
} = Astro.props;

const radius = (size / 2) - strokeWidth;
const center = size / 2;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (percent / 100) * circumference;
---

<div class="circular-progress-preview">
  <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
    <circle
      class="bg"
      cx={center}
      cy={center}
      r={radius}
      stroke-width={strokeWidth}
    />
    <circle
      class="progress"
      cx={center}
      cy={center}
      r={radius}
      stroke-width={strokeWidth}
      stroke-dasharray={circumference}
      stroke-dashoffset={offset}
      style={{ stroke: color }}
    />
    {showText && (
      <text x={center} y={center} text-anchor="middle" dominant-baseline="middle" class="text">
        {percent}%
      </text>
    )}
  </svg>
</div>

<style>
  .circular-progress-preview {
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
  }

  svg {
    transform: rotate(-90deg);
  }

  circle {
    fill: none;
    stroke-linecap: round;
  }

  .bg {
    stroke: rgba(var(--color-primary-rgb), 0.05);
  }

  .progress {
    filter: drop-shadow(0 0 8px var(--color-primary-start));
    transition: stroke-dashoffset 1s cubic-bezier(0.4, 0, 0.2, 1);
  }

  .text {
    fill: var(--color-text-title);
    font-size: 1.5rem;
    font-weight: 800;
    font-family: var(--font-mono);
    transform: rotate(90deg);
    transform-origin: center;
  }
</style>

组件特性

  • SVG 渲染:基于原生 SVG,支持任意缩放而不失真。
  • 平滑动画:内置 CSS 过渡动画,进度切换自然流畅。
  • 高度定制:可自由调整粗细、大小、颜色及文字显示。
  • 响应式设计:适配各种容器尺寸。

使用建议

适用于展示任务进度、资源占用、仪表盘等场景。可以通过 color 参数配合主题变量,实现不同状态(如成功、警告、错误)的视觉反馈。

Attributes

参数 说明 类型 默认值
percent 当前的进度百分比 (0-100) `number` 75
size 组件的宽度和高度 (px) `number` 120
strokeWidth 进度条的线条粗细 `number` 10
showText 是否显示中间的百分比文字 `boolean` true
color 进度条的颜色 (支持 CSS 颜色值) `string` var(--color-primary-start)

03. 数字雨背景 (Digital Rain)

经典的黑客帝国风格代码雨特效,基于 Canvas 渲染,高度可配置。

---
interface Props {
  speed?: number;
  fontSize?: number;
  color?: string;
  density?: number;
  class?: string;
}

const { 
  speed = 1, 
  fontSize = 14, 
  color = "var(--color-primary-start)",
  density = 0.5,
  class: className 
} = Astro.props;
---

<div class:list={["digital-rain-container", className]}>
  <canvas id="digitalRainCanvas"></canvas>
  <div class="overlay"></div>
</div>

<script define:vars={{ speed, fontSize, color, density }}>
  const canvas = document.getElementById('digitalRainCanvas');
  const ctx = canvas.getContext('2d');

  let width, height, columns;
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$+-*/=%\"'#&_(),.;:?!\\|{}<>[]^~";
  let drops = [];

  function init() {
    width = canvas.parentElement.offsetWidth;
    height = canvas.parentElement.offsetHeight;
    canvas.width = width;
    canvas.height = height;

    columns = Math.floor(width / fontSize);
    drops = [];
    for (let i = 0; i < columns; i++) {
      drops[i] = Math.random() * -height;
    }
  }

  function draw() {
    ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
    ctx.fillRect(0, 0, width, height);

    ctx.fillStyle = color;
    ctx.font = `${fontSize}px monospace`;

    for (let i = 0; i < drops.length; i++) {
      if (Math.random() > (1 - density)) {
        const text = chars[Math.floor(Math.random() * chars.length)];
        ctx.fillText(text, i * fontSize, drops[i]);
      }

      drops[i] += fontSize * speed;

      if (drops[i] > height && Math.random() > 0.975) {
        drops[i] = 0;
      }
    }
  }

  init();
  let interval = setInterval(draw, 33);

  window.addEventListener('resize', () => {
    init();
  });
</script>

<style>
  .digital-rain-container {
    position: relative;
    width: 100%;
    height: 300px;
    background: #000;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid rgba(var(--color-primary-rgb), 0.2);
  }

  canvas {
    display: block;
  }

  .overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(
      rgba(0, 0, 0, 0.2) 50%,
      transparent 50%
    );
    background-size: 100% 4px;
    pointer-events: none;
  }
</style>

组件特性

  • 高性能渲染:基于原生 Canvas API 绘制,即使在大量字符下落时也能保持流畅。
  • 动态适配:自动监听容器尺寸变化并重新初始化,确保全屏或局部展示都能完美填充。
  • 氛围增强:叠加了一层细微的扫描线效果,模拟老式显示器的质感。
  • 全字符集:内置了包括字母、数字、特殊符号在内的丰富字符集,随机掉落。

使用建议

建议作为页面的局部背景(如卡片内部)或全屏背景使用。为了保证文字可读性,建议在上方覆盖一层半透明的遮罩或使用高对比度的文字颜色。

Attributes

参数 说明 类型 默认值
speed 下落速度倍率 `number` 1
fontSize 字符大小 (px) `number` 14
color 字符颜色 `string` 'var(--color-primary-start)'
density 字符密度 (0-1) `number` 0.5
class 自定义样式类名 `string` ''