← 返回 Skills 市场
chenxiaoyu0124-web

Canvas大规模渲染优化

作者 chenxiaoyu0124-web · GitHub ↗ · v1.1.0 · MIT-0
cross-platform ✓ 安全检测通过
121
总下载
0
收藏
1
当前安装
2
版本数
在 OpenClaw 中安装
/install canvas-render-optimize
功能描述
优化Canvas大量元素渲染,采用三层管线、空间哈希裁剪、LOD分层与帧调度提升FPS与交互流畅度。
使用说明 (SKILL.md)

Canvas 大规模渲染优化

核心原则

Canvas 的瓶颈不是「画多少」,而是「每帧画多少」。

分离静态和动态元素,只重绘变化的部分。

三层渲染管线

Layer 1: 静态层 (OffscreenCanvas)

class StaticLayer {
  private canvas: OffscreenCanvas;
  private ctx: OffscreenCanvasRenderingContext2D;
  private dirty = true;

  constructor(width: number, height: number) {
    this.canvas = new OffscreenCanvas(width, height);
    this.ctx = this.canvas.getContext('2d')!;
  }

  render(items: StaticItem[]) {
    if (!this.dirty) return;
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    items.forEach(item => this.drawItem(item));
    this.dirty = false;
  }

  // 数据变化时调用
  invalidate() { this.dirty = true; }

  // 合成到主画布
  composite(target: CanvasRenderingContext2D) {
    target.drawImage(this.canvas, 0, 0);
  }
}

⚠️ 兼容性:Safari 16.4+ 才支持 OffscreenCanvas,需要 fallback:

const useOffscreen = typeof OffscreenCanvas !== 'undefined';
const canvas = useOffscreen ? new OffscreenCanvas(w, h) : document.createElement('canvas');

Layer 2: 动态层 (脏矩形追踪)

class DynamicLayer {
  private dirtyRects: Set\x3Cstring> = new Set();
  private minRectSize = 64; // 最小合并阈值

  markDirty(x: number, y: number, w: number, h: number) {
    // 合并小矩形,避免碎片段过多
    const rx = Math.floor(x / this.minRectSize);
    const ry = Math.floor(y / this.minRectSize);
    this.dirtyRects.add(`${rx},${ry}`);
  }

  render(ctx: CanvasRenderingContext2D, marks: DynamicItem[]) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    marks.forEach(mark => {
      this.drawMark(ctx, mark);
    });
    this.dirtyRects.clear();
  }
}

Layer 3: UI 叠加层

// tooltip、坐标轴、图例等,独立 Canvas 或在主 Canvas 上最后绘制
function renderOverlay(ctx: CanvasRenderingContext2D, ui: UIState) {
  if (ui.tooltip) drawTooltip(ctx, ui.tooltip);
  if (ui.selection) drawSelection(ctx, ui.selection);
  drawAxes(ctx);
  drawLegend(ctx);
}

空间哈希视口裁剪

draw calls 从 O(n) 降到 O(visible)

class SpatialGrid {
  private grid = new Map\x3Cstring, T[]>();
  private cellSize: number;

  constructor(items: T[], cellSize: number) {
    this.cellSize = cellSize;
    items.forEach(item => {
      const key = `${Math.floor(item.x / cellSize)},${Math.floor(item.y / cellSize)}`;
      if (!this.grid.has(key)) this.grid.set(key, []);
      this.grid.get(key)!.push(item);
    });
  }

  // 只返回视口内的元素
  query(viewport: Rect): T[] {
    const result: T[] = [];
    const startX = Math.floor(viewport.x / this.cellSize);
    const endX = Math.ceil((viewport.x + viewport.w) / this.cellSize);
    const startY = Math.floor(viewport.y / this.cellSize);
    const endY = Math.ceil((viewport.y + viewport.h) / this.cellSize);

    for (let x = startX; x \x3C= endX; x++) {
      for (let y = startY; y \x3C= endY; y++) {
        const items = this.grid.get(`${x},${y}`);
        if (items) result.push(...items);
      }
    }
    return result;
  }
}

LOD (细节层次)

function getLOD(zoom: number): 'full' | 'simple' | 'block' {
  if (zoom >= 2) return 'full';      // 完整绘制含边框
  if (zoom >= 0.5) return 'simple';  // 纯色块无边框
  return 'block';                     // 合并为区域色块
}

帧调度

class FrameScheduler {
  private rafId: number | null = null;
  private lastTime = 0;
  private targetFPS = 60;
  private frameInterval = 1000 / 60;

  start(loop: (dt: number) => void) {
    const tick = (time: number) => {
      this.rafId = requestAnimationFrame(tick);
      const dt = time - this.lastTime;
      if (dt \x3C this.frameInterval) return; // 帧率限制
      this.lastTime = time - (dt % this.frameInterval);
      loop(dt);
    };
    this.rafId = requestAnimationFrame(tick);
  }

  stop() {
    if (this.rafId) cancelAnimationFrame(this.rafId);
  }
}

完整组合

class WaferMapRenderer {
  private staticLayer: StaticLayer;
  private dynamicLayer: DynamicLayer;
  private spatialGrid: SpatialGrid;
  private scheduler: FrameScheduler;

  constructor(canvas: HTMLCanvasElement, dies: DieData[]) {
    this.staticLayer = new StaticLayer(canvas.width, canvas.height);
    this.dynamicLayer = new DynamicLayer();
    this.spatialGrid = new SpatialGrid(dies, DIE_SIZE);
    this.scheduler = new FrameScheduler();

    this.staticLayer.render(dies);
    this.scheduler.start(() => this.frame());
  }

  private frame() {
    const ctx = this.mainCanvas.getContext('2d')!;
    ctx.clearRect(0, 0, this.mainCanvas.width, this.mainCanvas.height);

    // Layer 1: 合成静态层
    this.staticLayer.composite(ctx);

    // Layer 2: 只画视口内的动态元素
    const visible = this.spatialGrid.query(this.viewport);
    this.dynamicLayer.render(ctx, visible.filter(isDynamic));

    // Layer 3: UI
    renderOverlay(ctx, this.uiState);
  }
}

实测数据

元素数量 优化前 FPS 优化后 FPS
5,000 28 60
10,000 12 60
50,000 3 58
100,000 1 55

适用场景

  • 晶圆图 (WaferMap) 可视化
  • 热力图 / 散点图
  • 地图标注点
  • 甘特图 / 时间线
  • 大型 Canvas 表格

一句话总结

分层、裁剪、按需重绘 — draw calls O(n) → O(visible)。

安全使用建议
This is a content-only guide with runnable TypeScript/JS snippets for browser Canvas performance—no network calls or credentials are involved. If you paste these snippets into your project, review and adapt them for your codebase (types, canvas element references, OffscreenCanvas availability, and coordinate systems). Test in a staging environment and verify cross-browser behavior (e.g., Safari fallback) before deploying to users.
能力评估
Purpose & Capability
Name/description (Canvas large-scale rendering optimization) match the SKILL.md content: layered rendering, spatial hashing, LOD, and frame scheduling. All requested or used APIs are browser Canvas/JS primitives appropriate for the stated goal.
Instruction Scope
SKILL.md contains code snippets and prose limited to canvas rendering techniques. It does not instruct reading system files, accessing environment variables, network endpoints, or unrelated configuration. Compatibility notes (OffscreenCanvas fallback) are appropriate and scoped to browser behavior.
Install Mechanism
There is no install specification and no code files to install or execute; this is instruction-only, which minimizes risk. The snippets are TypeScript/JavaScript examples intended for manual integration.
Credentials
The skill requests no environment variables, credentials, or config paths. There are no hidden secret accesses or unrelated credential requests.
Persistence & Privilege
Skill flags are default (not always:true). It does not request persistent presence, nor does it indicate modifying other skills or system-wide settings.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install canvas-render-optimize
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /canvas-render-optimize 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.1.0
新增定价,内容不变
v1.0.0
初始发布:三层渲染管线+空间哈希裁剪+LOD
元数据
Slug canvas-render-optimize
版本 1.1.0
许可证 MIT-0
累计安装 1
当前安装数 1
历史版本数 2
常见问题

Canvas大规模渲染优化 是什么?

优化Canvas大量元素渲染,采用三层管线、空间哈希裁剪、LOD分层与帧调度提升FPS与交互流畅度。 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 121 次。

如何安装 Canvas大规模渲染优化?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install canvas-render-optimize」即可一键安装,无需额外配置。

Canvas大规模渲染优化 是免费的吗?

是的,Canvas大规模渲染优化 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

Canvas大规模渲染优化 支持哪些平台?

Canvas大规模渲染优化 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Canvas大规模渲染优化?

由 chenxiaoyu0124-web(@chenxiaoyu0124-web)开发并维护,当前版本 v1.1.0。

💬 留言讨论