Skip to content

Repository files navigation

aspect-grid-collageify

npm version npm downloads minzip size TypeScript ready Canvas powered sideEffects false license

English | 简体中文

Aspect-grid-collageify 是一个轻量级、纯前端、基于 Canvas 的图片拼图工具库。它提供两层能力:

  • CollageCore:无 UI 的拼图核心,负责状态、网格布局、碰撞检测、图片变更、最终渲染和导出。
  • CanvasCollageEditor:基于 CollageCore 的可视化编辑器,负责 canvas 交互、选区、拖拽移动、拖拽插入、快捷键和编辑覆盖层。

Core 输出永远是干净的最终拼图;网格线、占位符、选中框、拖拽预览等编辑 UI 只属于 Editor,不会进入导出结果。

📖 目录

✨ 特性

  • 🎨 纯前端 Canvas 渲染,无服务端依赖。
  • 🖼️ 支持离屏导出 PNG / Blob。
  • 📐 支持自定义容器比例、图片比例、网格列数、间距和内边距。
  • ✨ 支持透明背景、图片圆角、阴影样式。
  • 🧩 支持按网格插入、移动、缩放、交换、删除和替换图片。
  • 🕹️ 支持可视化编辑:点击插槽上传、拖拽文件插入、拖拽移动、拖拽换位、多选、键盘操作。
  • 🧰 鼠标悬浮在已上传图片上时弹出画布内置工具栏:四角方向键移动、右上删除、右下替换、底部 −/+ 缩放;点击图片进入锁定态,工具栏持续显示。
  • 🧠 TypeScript 类型完整导出。
  • 📦 多入口导出,便于只使用 Core 或只引入 Editor。

🌐 在线预览

想先体验可视化编辑器的交互效果,可以直接👉点击预览

Demo 展示了图片上传、拖拽移动、拖拽插入、换位、缩放、删除、替换以及最终导出等核心能力,适合在安装前快速确认组件是否符合你的使用场景。

在线预览

📦 安装

npm install aspect-grid-collageify
pnpm add aspect-grid-collageify
yarn add aspect-grid-collageify

🚀 导入方式

推荐按能力入口导入:

import { CollageCore } from "aspect-grid-collageify/core";
import { CanvasCollageEditor } from "aspect-grid-collageify/editor";

也可以从主入口导入:

import { CollageCore, CanvasCollageEditor } from "aspect-grid-collageify";
入口 导出 说明
aspect-grid-collageify CollageCore, CanvasCollageEditor, 全部公共类型 主入口。
aspect-grid-collageify/core CollageCore 只使用离屏渲染和拼图核心能力时使用。
aspect-grid-collageify/editor CanvasCollageEditor 需要 canvas 可视化编辑能力时使用。

🖼️ 快速开始:离屏生成拼图

import { CollageCore } from "aspect-grid-collageify/core";

const core = new CollageCore({
  containerRatio: "3:4",
  imageRatio: "16:9",
  gridColumns: 8,
  padding2K: 60,
  gap2K: 24,
  background: {
    color: "#ffffff",
    transparent: false,
  },
  imageStyle: {
    borderRadius2K: 24,
    shadowBlur2K: 12,
    shadowOffset2K: 8,
    shadowOpacity: 0.2,
  },
  images: [
    {
      id: "image-1",
      src: "/images/a.jpg",
      name: "A",
      gridX: 0,
      gridY: 0,
      span: 4,
    },
    {
      id: "image-2",
      src: "/images/b.jpg",
      name: "B",
      gridX: 4,
      gridY: 0,
      span: 4,
    },
  ],
});

const dataUrl = await core.exportPNG(2048);

🎛️ 快速开始:可视化编辑器

import { CollageCore } from "aspect-grid-collageify/core";
import { CanvasCollageEditor } from "aspect-grid-collageify/editor";

const canvas = document.querySelector("canvas")!;

const core = new CollageCore({
  containerRatio: "3:4",
  imageRatio: "16:9",
  gridColumns: 8,
  padding2K: 60,
  gap2K: 24,
  images: [],
});

const editor = new CanvasCollageEditor(canvas, core, {
  multiSelect: true,
  keyboard: true,
  dragMove: true,
  dragSwap: true,
  dragInsert: true,
  quickReplace: true,
});

editor.on("change", (images) => {
  console.log("images changed", images);
});

editor.on("cellclick", (placement) => {
  // 调用方可以打开文件选择器,然后调用 editor.insertFiles(files)。
  editor.setPendingInsertPlacement(placement);
});

也可以使用便捷构造:

const editor = CanvasCollageEditor.create(canvas, options, editorOptions);
const core = editor.core;

⌨️ 快捷键

可视化编辑器内置了一组常用快捷键。启用 keyboard: true 后,canvas 会自动获得可聚焦能力,用户选中图片后即可通过键盘完成移动、缩放和删除操作。

快捷键 操作 说明
Ctrl / Cmd + 单击图片 多选 / 取消多选 需要同时启用 multiSelect: true
/ / / 移动选中图片 按网格方向移动当前选区。
Ctrl / Cmd + ↑ 缩小选中图片 将选中图片的网格跨度减小 1。
Ctrl / Cmd + ↓ 放大选中图片 将选中图片的网格跨度增加 1。
Delete / Backspace 删除选中图片 删除当前选区,并清空选中状态。

⚙️ 配置示例

const options = {
  containerRatio: "3:4",
  imageRatio: "16:9",
  gridColumns: 12,
  padding2K: 60,
  gap2K: 24,
  background: {
    color: "#ffffff",
    transparent: false,
  },
  imageStyle: {
    borderRadius2K: 24,
    shadowBlur2K: 12,
    shadowOffset2K: 8,
    shadowOpacity: 0.2,
  },
  placementPreset: "medium",
  images: [],
};

📚 API

CollageCore

CollageCore 是拼图状态和最终渲染的核心。它不绑定 DOM 事件,不维护选区,不绘制编辑覆盖层。

构造函数

API 位置 参数 返回值 描述
new CollageCore(options) aspect-grid-collageify/core options: CollageOptions CollageCore 创建一个拼图核心实例,并初始化配置和图片列表。

状态 API

API 位置 参数 返回值 描述
getOptions() CollageCore CollageOptions 获取当前拼图配置。
setOptions(options) CollageCore options: CollageOptions void 替换完整配置,并触发变更事件。
updateOptions(options) CollageCore options: Partial<CollageOptions> void 合并更新部分配置,并触发变更事件。
getImages() CollageCore CollageImage[] 获取当前图片列表。
setImages(images) CollageCore images: CollageImage[] void 替换图片列表;会根据当前网格列数约束图片位置。
onChange(callback) CollageCore callback: (images: CollageImage[], options: CollageOptions) => void Unsubscribe 监听配置或图片变化。返回取消监听函数。
destroy() CollageCore void 清理监听器和图片缓存。

几何 API

API 位置 参数 返回值 描述
getLayout(width, height) CollageCore width: number, height: number CollageLayout 根据视口尺寸和当前配置计算布局。
toGridPoint(point, viewport) CollageCore point: GridPoint, viewport: DrawViewport GridPoint 将 canvas 坐标转换为网格坐标。
getImageRect(imageOrId, layout) CollageCore imageOrId: CollageImage | string, layout: CollageLayout ImageRect | null 获取指定图片在 canvas 中的矩形区域。
hitTest(point, viewport) CollageCore point: GridPoint, viewport: DrawViewport CollageImage | null 根据 canvas 坐标命中图片。
getPlacementSpan(preset?) CollageCore preset?: PlacementPreset number 根据当前网格列数和预设计算插入图片的 span。
findSlots(options) CollageCore options: FindSlotsOptions GridPlacement[] 查找当前布局中可放置图片的空插槽。
findFirstSlot(options) CollageCore options: FindSlotsOptions GridPlacement | null 查找第一个可用空插槽。
canPlace(placement, gridRows, ignoreIds?) CollageCore placement: GridPlacement, gridRows: number, ignoreIds?: string[] boolean 判断指定位置是否可放置图片,可忽略指定图片 id。

图片与布局 API

API 位置 参数 返回值 描述
insertImage(image) CollageCore image: CollageImage CollageImage 插入完整图片对象。调用方负责提供 id、src、gridX、gridY 和 span。
insertImageAt(input, placement) CollageCore input: ImageInput, placement: GridPlacement CollageImage 根据图片输入和明确位置创建并插入图片。
insertImages(inputs, options) CollageCore inputs: ImageInput[], options: InsertImagesOptions CollageImage[] 批量插入图片,按空插槽自动排布。
updateImage(id, patch) CollageCore id: string, patch: Partial<CollageImage> boolean 更新指定图片。成功返回 true
removeImage(id) CollageCore id: string boolean 删除单张图片。成功返回 true
removeImages(ids) CollageCore ids: string[] boolean 批量删除图片。成功返回 true
replaceImage(id, input) CollageCore id: string, input: ImageInput boolean 替换指定图片的 src、name 和样式。
moveImage(id, target, gridRows) CollageCore id: string, target: GridPoint, gridRows: number boolean 将单张图片移动到指定网格坐标。
moveImages(ids, delta, gridRows) CollageCore ids: string[], delta: GridPoint, gridRows: number boolean 按网格偏移量批量移动图片。
moveImagesByDirection(ids, direction, gridRows) CollageCore ids: string[], direction: MoveDirection, gridRows: number boolean 按方向批量移动图片。
resizeImage(id, delta, gridRows) CollageCore id: string, delta: number, gridRows: number boolean 调整单张图片 span。
resizeImages(ids, delta, gridRows) CollageCore ids: string[], delta: number, gridRows: number boolean 批量调整图片 span。
swapImages(sourceId, targetId) CollageCore sourceId: string, targetId: string boolean 交换两张图片的位置和 span。
pushBelow(id, rows, gridRows) CollageCore id: string, rows: number, gridRows: number boolean 将指定图片下方的图片整体向下推。
pullBelow(id, rows?) CollageCore id: string, rows?: number boolean 将指定图片下方的图片整体向上拉。

渲染与导出 API

API 位置 参数 返回值 描述
draw(ctx, viewport) CollageCore ctx: CanvasRenderingContext2D, viewport: DrawViewport void 在指定 canvas 上绘制最终拼图。
renderToCanvas(width?) CollageCore width?: number Promise<HTMLCanvasElement> 离屏渲染并返回 canvas。高度由容器比例自动计算。
exportPNG(width?) CollageCore width?: number Promise<string> 导出 PNG Data URL。
exportBlob(width?, type?, quality?) CollageCore width?: number, type?: string, quality?: number Promise<Blob> 导出 Blob。支持 PNG、JPEG、WebP 等 canvas 支持的类型。
getImageLoader() CollageCore ImageLoader 获取内部图片加载器。通常仅高级场景使用。

CanvasCollageEditor

CanvasCollageEditor 是 canvas 可视化编辑引擎。它通过 core 读写拼图状态,并额外维护选区、活动图片、拖拽状态和编辑覆盖层。

构造函数

API 位置 参数 返回值 描述
new CanvasCollageEditor(canvas, core, options?) aspect-grid-collageify/editor canvas: HTMLCanvasElement, core: CollageCore, options?: CanvasCollageEditorOptions CanvasCollageEditor 基于已有 Core 创建可视化编辑器。
CanvasCollageEditor.create(canvas, options, editorOptions?) CanvasCollageEditor canvas: HTMLCanvasElement, options: CollageOptions, editorOptions?: CanvasCollageEditorOptions CanvasCollageEditor 便捷构造:内部创建 CollageCore 并返回 editor。

基础 API

API 位置 参数 返回值 描述
core CanvasCollageEditor CollageCore 底层 Core 实例。
getCore() CanvasCollageEditor CollageCore 获取底层 Core 实例。
render() CanvasCollageEditor void 重绘最终拼图和编辑覆盖层。
resize() CanvasCollageEditor void 根据 canvas 当前尺寸重新渲染。
destroy() CanvasCollageEditor void 移除事件监听并释放由 editor 创建的 Object URL。

选区 API

API 位置 参数 返回值 描述
getSelection() CanvasCollageEditor string[] 获取当前选中的图片 id 列表。
setSelection(ids) CanvasCollageEditor ids: string[] void 设置选区。无效 id 会被忽略。
getActiveId() CanvasCollageEditor string | null 获取当前活动图片 id。
setActiveId(id) CanvasCollageEditor id: string | null void 设置当前活动图片,并同步选区。
clearSelection() CanvasCollageEditor void 清空选区和活动图片。

输入与文件 API

API 位置 参数 返回值 描述
handleKeyDown(event) CanvasCollageEditor event: KeyboardEvent boolean 处理删除、方向移动、快捷缩放等键盘操作。
insertFiles(files, options?) CanvasCollageEditor files: FileList | File[], options?: Partial<InsertImagesOptions> Promise<CollageImage[]> 解析并插入文件。若存在 pending placement,则优先插入该位置。
insertFilesAt(files, point) CanvasCollageEditor files: FileList | File[], point: GridPoint Promise<CollageImage[]> 按 canvas 坐标插入文件;优先命中空插槽,否则回退到网格落点。
replaceActiveFile(file) CanvasCollageEditor file: File Promise<boolean> 用文件替换当前活动图片。
replaceFile(id, file) CanvasCollageEditor id: string, file: File Promise<boolean> 用文件替换指定图片。
setPendingInsertPlacement(placement) CanvasCollageEditor placement: GridPlacement | null void 设置下一次 insertFiles() 优先使用的插入位置。

事件 API

API 位置 参数 返回值 描述
on("change", callback) CanvasCollageEditor callback: (images: CollageImage[]) => void Unsubscribe Core 变化并完成 editor 重绘后触发。
on("selectionchange", callback) CanvasCollageEditor callback: (ids: string[]) => void Unsubscribe 选区变化时触发。
on("activechange", callback) CanvasCollageEditor callback: (id: string | null) => void Unsubscribe 活动图片变化时触发。
on("cellclick", callback) CanvasCollageEditor callback: (placement: GridPlacement) => void Unsubscribe 点击空插槽时触发。
on("replacerequest", callback) CanvasCollageEditor callback: (id: string) => void Unsubscribe 双击图片请求替换时触发。
on("error", callback) CanvasCollageEditor callback: (error: unknown) => void Unsubscribe 文件解析、拖拽插入等异步错误发生时触发。

类型 API

基础类型

类型 位置 字段 / 参数 描述
RatioOption aspect-grid-collageify "1:1" | "3:4" | "4:3" | "16:9" | "9:16" | "custom" | string 比例配置。普通字符串应为 w:h 格式。
PlacementPreset aspect-grid-collageify "small" | "medium" | "large" 自动插入图片时使用的尺寸预设。
MoveDirection aspect-grid-collageify "up" | "down" | "left" | "right" 方向移动枚举。
GridPoint aspect-grid-collageify { x: number; y: number } 网格点或 canvas 点。语义由 API 参数决定。
GridPlacement aspect-grid-collageify { gridX: number; gridY: number; span: number } 图片在网格中的位置和尺寸。
ViewportSize aspect-grid-collageify { width: number; height: number } 视口尺寸。
DrawViewport aspect-grid-collageify { width: number; height: number } 绘制视口尺寸。
Unsubscribe aspect-grid-collageify () => void 取消监听函数。

配置与图片类型

类型 位置 字段 / 参数 描述
ImageStyleOptions aspect-grid-collageify borderRadius2K?: number, shadowBlur2K?: number, shadowOffset2K?: number, shadowOpacity?: number 图片样式配置。数值以 2K 画布为基准缩放。
CollageImage aspect-grid-collageify id: string, src: string, name: string, gridX: number, gridY: number, span: number, ImageStyleOptions 拼图中的图片模型。
ImageInput aspect-grid-collageify id?: string, src: string, name?: string, style?: ImageStyleOptions 插入或替换图片时的输入模型。
CollageOptions aspect-grid-collageify containerRatio, imageRatio, gridColumns, padding2K, gap2K, background?, imageStyle?, images?, placementPreset? 拼图核心配置。

布局与操作类型

类型 位置 字段 / 参数 描述
CollageLayout aspect-grid-collageify scale, padding, gap, cellW, cellH, gridRows, offsetX, offsetY, gridW, gridH, containerRatioVal, imageRatioVal 根据配置和视口计算出的布局数据。
ImageRect aspect-grid-collageify { x: number; y: number; w: number; h: number } 图片在 canvas 中的矩形区域。
FindSlotsOptions aspect-grid-collageify { span: number; gridRows: number } 查找空插槽的参数。
InsertImagesOptions aspect-grid-collageify { span?: number; placementPreset?: PlacementPreset; gridRows: number } 批量插入图片的参数。
CanvasCollageEditorOptions aspect-grid-collageify/editor multiSelect?, keyboard?, dragMove?, dragSwap?, dragInsert?, quickReplace?, preventDefaultFileDrop?, fileResolver?, overlay? Editor 交互配置。
EditorOverlayOptions aspect-grid-collageify showBoundary?, showGridlines?, showSlots?, slotText? Editor 覆盖层显示配置。

🛠️ 本地开发

pnpm install
pnpm dev

打开 demo 页面后可以测试 canvas 可视化编辑能力。

构建发布产物:

pnpm build

当前构建会输出 ESM、CommonJS 和类型声明,并支持以下包入口:

aspect-grid-collageify
aspect-grid-collageify/core
aspect-grid-collageify/editor

🗂️ 目录结构

src/
  core.ts           # CollageCore:状态、几何、布局变更、最终渲染和导出
  editor.ts         # CanvasCollageEditor:canvas 可视化编辑能力
  editor-render.ts  # 编辑覆盖层渲染
  image-loader.ts   # 图片加载和缓存
  layout.ts         # 纯几何、网格、碰撞、空位查找
  render.ts         # 最终拼图渲染
  types.ts          # 公共类型
  index.ts          # 主导出入口

📄 协议

本项目使用 MIT License

Copyright (c) 2026 liuxin2533