Vue 3 + Canvas 实现图形拖拽、缩放、旋转

在很多图形编辑器、UI 设计器、应用绘图系统中,我们常常需要支持图形的 拖拽、缩放、旋转 三种基础操作。本文将分享如何利用 Vue 3 + Canvas 组合实现一个完整的图形操作示例,包括:

  • 项目结构介绍
  • Canvas 操作动作解析
  • 实现 Sprite 类和 Stage 管理器
  • Vue 3 与 Canvas 的组合实践

一、项目结构

我们使用 Vite 创建 Vue 3 项目,类目录结构如下:

css 复制代码
your-canvas-editor/
├─ index.html
├─ package.json
├─ vite.config.js
├─ src/
│  ├─ main.js
│  ├─ App.vue
│  └─ components/
│     └─ CanvasEditor.vue

index.html

指定页面根 DOM 节点

xml 复制代码
<div id="app"></div>
<script type="module" src="/src/main.js"></script>

package.json

指定 Vue 3 和 Vite 配置

perl 复制代码
"dependencies": {
  "vue": "^3.4.0"
},
"devDependencies": {
  "vite": "^5.0.0",
  "@vitejs/plugin-vue": "^5.0.0"
}

二、CanvasEditor.vue 主组件

这是一个基于 Canvas 实现拖拽、缩放、旋转图形的组件,使用 <script setup> 构建。

xml 复制代码
<template>
  <div class="canvas-container">
    <canvas ref="canvasRef" width="300" height="300"></canvas>
  </div>
  <div class="box-container">
    <div class="red-box" @click="addSprite"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const canvasRef = ref(null)
let stage = null

onMounted(() => {
  stage = new Stage({ canvas: canvasRef.value })
})

function addSprite() {
  const randomX = Math.floor(Math.random() * 200)
  const randomY = Math.floor(Math.random() * 200)
  const sprite = new Sprite({
    pos: [randomX, randomY],
    size: [120, 60],
    minSize: [40, 20],
    maxSize: [240, 120]
  })
  stage.append(sprite)
}
</script>

三、核心类: Stage 和 Sprite

Stage 类

用于 Canvas 场景管理,包括:

  • 图形列表
  • 触摸事件分发
  • 拖拽 / 缩放 / 旋转解析与重绘

基本用法:

go 复制代码
stage.append(sprite)

重点方法:

  • handleTouchStart
  • handleTouchMove
  • handleTouchEnd
  • drawSprite()

Sprite 类

代表单个图形,包含:

  • 位置 pos
  • 大小 size
  • 四个顶点坐标 coordinate
  • 操作按钮:旋转/删除/缩放

操作方法:

scss 复制代码
sprite.resetPos(dx, dy) // 拖拽
sprite.resetSize(scale) // 缩放
sprite.setRotateAngle(angle) // 旋转

四、设计策略

1. 使用矩阵转换旋转坐标

Canvas 中旋转操作需要以中心点为基准:

scss 复制代码
ctx.translate(centerX, centerY)
ctx.rotate(angle)
ctx.translate(-centerX, -centerY)

2. 触摸区分别分类处理

  • 旋转区 -> rotateIcon
  • 缩放区 -> scaleIcon
  • 拖动区 -> sprite body
  • 删除区 -> delIcon

3. 各按钮位置用 sprite center + 向量 转换计算

arduino 复制代码
const vector = [x - centerX, y - centerY]
const scaled = [vector[0] * scale, vector[1] * scale]

五、效果展示

点击红色按钮创建新图形,可在 Canvas 中:

  • 按位置拖拽
  • 缩放经度
  • 四分之一圈旋转
  • 删除

支持多个 Sprite 同时存在


六、总结

通过本项目,我们用 Vue 3 的 <script setup> 构造组件,实现了 Canvas 图形的拖拽/缩放/旋转,其核心是:

  • Sprite 对应操作逻辑
  • Stage 分发 touch 操作
  • Canvas 2D 演练 transform 和 icon 操作

同时保持 Vue 3 简洁的编程风格


七、后续可扩展

  • 支持折线或多边形
  • 层级排序
  • 图形经纬系统定位
  • JSON 化导入导出
  • Vuex/Pinia 独立管理 state

帮助设计器类项目快速构建应用编辑器或场景应用。

相关推荐
世界哪有真情5 小时前
拿人类意识卡 AI?等于用 bug 验收正式产品
前端·人工智能·后端
Listen·Rain6 小时前
Vue3:setup详解
前端·javascript·vue.js
Patrick_Wilson6 小时前
修好 bug 只是开始:一次由监控需求反向重构日志结构的复盘
前端·监控·数据可视化
kyriewen7 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
小粉粉hhh7 小时前
React(二)——dom、组件间通信、useEffect
前端·javascript·react.js
Csvn8 小时前
🤖 AI 生成前端代码的 5 个典型翻车现场及修复指南
前端
IT_陈寒9 小时前
SpringBoot自动装配坑了我一天,原来问题出在这
前端·人工智能·后端
索西引擎9 小时前
【React】key 属性:协调算法中的元素标识机制与最佳实践
前端·javascript·react.js
只会cv的前端攻城狮10 小时前
动态组件架构设计:从配置到事件驱动全链路解析
前端·vue.js
飞天狗10 小时前
Next.js 16 App Router 实战:服务端组件与流式渲染
前端·next.js