跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端 Canvas 基础绘制与动画交互实现

介绍前端 Canvas 的核心用法。涵盖基础图形绘制(矩形、圆形、路径)、使用 requestAnimationFrame 实现流畅动画、处理鼠标触摸交互事件、绘制数据图表以及像素级图像灰度处理。通过对比错误写法与优化方案,帮助开发者掌握 Canvas 性能优化技巧及实际应用场景。

怪力乱神发布于 2026/4/5更新于 2026/6/637 浏览

前端 Canvas 基础绘制与动画交互实现

常见误区

在 Canvas 开发中,常见的误区包括性能未优化、使用 setInterval 而非 requestAnimationFrame 导致动画卡顿等。

// 反面教材:简单的 Canvas 绘制
function drawCircle() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    // 绘制一个简单的圆形
    ctx.beginPath();
    ctx.arc(100, 100, 50, 0, Math.PI * 2);
    ctx.fillStyle = 'red';
    ctx.fill();
    ctx.stroke();
}

// 反面教材:没有优化的动画
function animate() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    let x = 0;
    setInterval(() => {
        // 每次都清除整个画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 绘制移动的矩形
        ctx.fillStyle = 'blue';
        ctx.fillRect(x, 50, 50, 50);
        x += 1;
        if (x > canvas.width) {
            x = 0;
        }
    }, 16);
}

基础绘制

Canvas 支持绘制矩形、圆形、路径和文本等基本图形。

// 正确的做法:Canvas 基础绘制
function basicDrawing() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    // 设置画布尺寸
    canvas.width = 800;
    canvas.height = 600;
    // 绘制矩形
    ctx.fillStyle = 'blue';
    ctx.fillRect(50, 50, 100, 100);
    // 绘制圆形
    ctx.beginPath();
    ctx.arc(250, 100, 50, 0, Math.PI * 2);
    ctx.fillStyle = 'red';
    ctx.fill();
    // 绘制路径
    ctx.beginPath();
    ctx.moveTo(350, 50);
    ctx.lineTo(450, 150);
    ctx.lineTo(350, 150);
    ctx.closePath();
    ctx.strokeStyle = 'green';
    ctx.lineWidth = 2;
    ctx.stroke();
    // 绘制文本
    ctx.font = '24px Arial';
    ctx.fillStyle = 'black';
    ctx.textAlign = 'center';
    ctx.fillText('Canvas 绘制示例', canvas.width / 2, 30);
}

动画效果

推荐使用 requestAnimationFrame 实现流畅的动画效果。

// 正确的做法:Canvas 动画
function canvasAnimation() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = 800;
    canvas.height = 600;
    let x = 0;
    let y = canvas.height / 2;
    let dx = 2;
    let dy = 2;
    const radius = 20;

    function animate() {
        // 清除画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 绘制移动的圆形
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.fillStyle = 'purple';
        ctx.fill();
        // 边界检测
        if (x + radius > canvas.width || x - radius < 0) {
            dx = -dx;
        }
        if (y + radius > canvas.height || y - radius < 0) {
            dy = -dy;
        }
        // 更新位置
        x += dx;
        y += dy;
        // 使用 requestAnimationFrame
        requestAnimationFrame(animate);
    }
    animate();
}

交互操作

通过监听鼠标事件实现绘图交互。

// 正确的做法:Canvas 交互
function canvasInteraction() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = 800;
    canvas.height = 600;
    let isDrawing = false;
    let lastX = 0;
    let lastY = 0;

    // 鼠标按下事件
    canvas.addEventListener('mousedown', (e) => {
        isDrawing = true;
        [lastX, lastY] = [e.offsetX, e.offsetY];
    });

    // 鼠标移动事件
    canvas.addEventListener('mousemove', (e) => {
        if (!isDrawing) return;
        ctx.beginPath();
        ctx.moveTo(lastX, lastY);
        ctx.lineTo(e.offsetX, e.offsetY);
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 2;
        ctx.stroke();
        [lastX, lastY] = [e.offsetX, e.offsetY];
    });

    // 鼠标释放事件
    canvas.addEventListener('mouseup', () => {
        isDrawing = false;
    });

    // 鼠标离开事件
    canvas.addEventListener('mouseout', () => {
        isDrawing = false;
    });
}

数据可视化

利用 Canvas 绘制图表展示数据。

// 正确的做法:Canvas 数据可视化
function canvasChart() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = 800;
    canvas.height = 600;
    // 数据
    const data = [12, 19, 3, 5, 2, 3, 7, 11, 15, 18, 10, 6];
    const labels = ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月'];
    // 绘制坐标系
    const padding = 50;
    const chartWidth = canvas.width - padding * 2;
    const chartHeight = canvas.height - padding * 2;
    // X 轴
    ctx.beginPath();
    ctx.moveTo(padding, canvas.height - padding);
    ctx.lineTo(canvas.width - padding, canvas.height - padding);
    ctx.stroke();
    // Y 轴
    ctx.beginPath();
    ctx.moveTo(padding, padding);
    ctx.lineTo(padding, canvas.height - padding);
    ctx.stroke();
    // 绘制数据
    const maxValue = Math.max(...data);
    const barWidth = chartWidth / data.length;
    data.forEach((value, index) => {
        const barHeight = (value / maxValue) * chartHeight;
        const x = padding + index * barWidth;
        const y = canvas.height - padding - barHeight;
        // 绘制柱子
        ctx.fillStyle = 'rgba(54, 162, 235, 0.6)';
        ctx.fillRect(x + 5, y, barWidth - 10, barHeight);
        // 绘制标签
        ctx.font = '12px Arial';
        ctx.fillStyle = 'black';
        ctx.textAlign = 'center';
        ctx.fillText(labels[index], x + barWidth / 2, canvas.height - padding + 15);
    });
    // 绘制标题
    ctx.font = '20px Arial';
    ctx.fillStyle = 'black';
    ctx.textAlign = 'center';
    ctx.fillText('月度销售数据', canvas.width / 2, padding / 2);
}

图像处理

支持像素级操作,如灰度滤镜。

// 正确的做法:Canvas 图像处理
function canvasImageProcessing() {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = 800;
    canvas.height = 600;
    // 加载图像
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
        // 绘制原始图像
        ctx.drawImage(img, 0, 0, 400, 300);
        // 获取图像数据
        const imageData = ctx.getImageData(0, 0, 400, 300);
        const data = imageData.data;
        // 处理图像(灰度)
        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];
            const gray = (r + g + b) / 3;
            data[i] = gray;
            data[i + 1] = gray;
            data[i + 2] = gray;
        }
        // 绘制处理后的图像
        ctx.putImageData(imageData, 400, 0);
    };
    img.src = 'https://picsum.photos/800/600';
}

总结

  • 基础绘制:矩形、圆形、路径、文本等
  • 动画效果:使用 requestAnimationFrame 实现流畅动画
  • 交互操作:鼠标、触摸等事件处理
  • 数据可视化:绘制图表、仪表盘等
  • 图像处理:像素级操作,实现滤镜效果
  • 性能优化:合理使用缓存、避免频繁重绘
  • 响应式:根据容器大小调整画布尺寸
  • 工具库:使用 Chart.js、Fabric.js 等库简化开发

目录

  1. 前端 Canvas 基础绘制与动画交互实现
  2. 常见误区
  3. 基础绘制
  4. 动画效果
  5. 交互操作
  6. 数据可视化
  7. 图像处理
  8. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Neo4j 核心概念与在线控制台使用指南
  • 链表相加:LeetCode 两数相加算法详解
  • Seedance 2.0 实测:影视级 AI 视频生成的商业化落地
  • Android 开发核心面试题解析:系统启动、Binder 与内存管理
  • Web 架构深度解析:前后端分离与传统的利弊权衡
  • cann-recipes-train 解析:昇腾平台 DeepSeek-R1 与 Qwen2.5 强化学习优化
  • Python 分支结构与循环结构应用实战
  • 护网行动与红蓝对抗详解
  • MySQL 动态分区管理:自动化与优化实践
  • 智慧生活商城系统设计与实现:SpringBoot+Vue+MySQL
  • Office Copilot 区域限制问题的排查与修复方案
  • WhisperLiveKit 实战指南:从本地部署到生产环境
  • 2025 年全球 AI 大模型格局:技术突破、开源崛起与未来趋势
  • 量化、算子融合、内存映射:C 语言实现 AI 推理优化
  • IDEA 中 Java 及 Java Web 项目常见问题
  • Mac 本地部署 OpenClaw 并接入飞书打造 AI 助手
  • 并查集数据结构详解与实战应用
  • C++ 控制流详解:从基础语法到高级应用实践
  • 初识 Linux 与 gcc 编译器
  • MacOS 下基于 Docker 部署 OpenClaw 并集成飞书机器人

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online