You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Fabric.js将Sprite Sheet转为Canvas横向连续视频缩略图

在Fabric.js中实现连续视频缩略预览组件

核心思路

  1. 批量加载所有Sprite Sheet图片,确保全部加载完成后再进行布局
  2. 遍历每张Sprite Sheet,拆分出60个缩略图,按顺序横向排列到Fabric Canvas上
  3. 借助容器的滚动属性,实现预览条的横向滚动效果

实现代码

// 配置参数
const SPRITE_CONFIG = {
  thumbnailWidth: 142,
  thumbnailHeight: 80,
  cols: 10,
  rows: 6,
  totalSprites: 3, // 示例:3分钟视频对应3张Sprite Sheet
  spritePathPrefix: "path/to/sprite." // 图片路径前缀,最终拼接为sprite.0.jpg格式
};

// 初始化Fabric Canvas
const canvasContainer = document.getElementById("timeline-container");
const canvas = new fabric.Canvas("timeline", {
  height: SPRITE_CONFIG.thumbnailHeight,
  width: canvasContainer.clientWidth // 初始宽度适配容器
});

// 批量加载所有Sprite Sheet图片
function loadAllSprites() {
  const promises = [];
  for (let i = 0; i < SPRITE_CONFIG.totalSprites; i++) {
    const promise = new Promise((resolve, reject) => {
      const img = new Image();
      img.src = `${SPRITE_CONFIG.spritePathPrefix}${i}.jpg`;
      img.onload = () => resolve(img);
      img.onerror = reject;
    });
    promises.push(promise);
  }
  return Promise.all(promises);
}

// 布局所有缩略图到Canvas
function layoutThumbnails(spriteImages) {
  let currentX = 0; // 记录当前缩略图的横向位置

  spriteImages.forEach(spriteImg => {
    // 创建Fabric图片对象,复用原始Sprite图
    const fabricSprite = new fabric.Image(spriteImg, {
      selectable: false,
      evented: false
    });

    // 遍历当前Sprite Sheet的所有缩略图(10列×6行)
    for (let row = 0; row < SPRITE_CONFIG.rows; row++) {
      for (let col = 0; col < SPRITE_CONFIG.cols; col++) {
        // 计算当前缩略图在Sprite Sheet中的裁剪区域
        const cropX = col * SPRITE_CONFIG.thumbnailWidth;
        const cropY = row * SPRITE_CONFIG.thumbnailHeight;

        // 克隆图片对象并设置裁剪和位置属性
        const thumbnail = fabricSprite.clone();
        thumbnail.set({
          left: currentX,
          top: 0,
          cropX: cropX,
          cropY: cropY,
          width: SPRITE_CONFIG.thumbnailWidth,
          height: SPRITE_CONFIG.thumbnailHeight
        });

        canvas.add(thumbnail);
        currentX += SPRITE_CONFIG.thumbnailWidth;
      }
    }
  });

  // 更新Canvas总宽度为所有缩略图的总宽度
  canvas.setWidth(currentX);
  canvas.setHeight(SPRITE_CONFIG.thumbnailHeight);
}

// 执行加载与布局流程
loadAllSprites()
  .then(layoutThumbnails)
  .catch(err => console.error("Sprite图片加载失败:", err));

容器样式设置(CSS)

要实现横向滚动,需给Canvas的容器添加以下样式:

#timeline-container {
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  border: 1px solid #eee;
}

#timeline {
  display: block;
}

关键说明

  • 批量加载:用Promise.all确保所有Sprite图片加载完成后再布局,避免因加载顺序导致的布局错乱
  • 裁剪复用:通过克隆Fabric图片对象并设置cropX/cropY属性,高效拆分Sprite Sheet中的缩略图,减少重复创建图片对象的开销
  • 滚动实现:依靠容器的overflow-x: auto属性实现横向滚动,Canvas总宽度设为所有缩略图的总宽度,高度固定为单张缩略图的高度

内容的提问来源于stack exchange,提问作者Yogesh Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:40:25