首页龙虾技能列表 › Canvas大规模渲染优化 — 技能工具

Canvas大规模渲染优化 — 技能工具

v1.1.0

优化Canvas大量元素渲染,采用三层管线、空间哈希裁剪、LOD分层与帧调度提升FPS与交互流畅度。

0· 61·0 当前·0 累计
下载技能包
License
MIT-0
最后更新
2026/4/6
安全扫描
VirusTotal
Pending
查看报告
OpenClaw
安全
high confidence
The skill is an instruction-only front-end optimization guide for Canvas rendering; its required resources and instructions align with its stated purpose and it does not request credentials, install code, or contact external endpoints.
评估建议
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.
详细分析 ▾
用途与能力
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.
指令范围
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.
安装机制
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.
凭证需求
The skill requests no environment variables, credentials, or config paths. There are no hidden secret accesses or unrelated credential requests.
持久化与权限
Skill flags are default (not always:true). It does not request persistent presence, nor does it indicate modifying other skills or system-wide settings.
安全有层次,运行前请审查代码。

License

MIT-0

可自由使用、修改和再分发,无需署名。

运行时依赖

无特殊依赖

版本

latestv1.1.02026/4/6

新增定价,内容不变

● Pending

安装命令 点击复制

官方npx clawhub@latest install canvas-render-optimize
镜像加速npx clawhub@latest install canvas-render-optimize --registry https://cn.clawhub-mirror.com

技能文档

核心原则

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 = 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();
  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 <= endX; x++) { for (let y = startY; y <= 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 < 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,0002860
10,0001260
50,000358
100,000155

适用场景

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

一句话总结

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

数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制

免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制

了解定制服务