第16章 Canvas绘图画布

用代码作画:竞赛任务9 | 课型:实习课 | 建议课时:2节

🏠 返回总目录 / 第16章

🎯 学习目标

知识目标

  • 掌握canvas元素与2D上下文
  • 掌握路径绘制:beginPath/moveTo/lineTo/stroke
  • 掌握鼠标事件坐标换算
  • 了解requestAnimationFrame动画循环

能力目标

  • 能独立完成竞赛任务9"绘图画布"
  • 能用Canvas绘制柱状图等数据图形
  • 能实现平滑的连续画线

德育目标

  • 培养把抽象需求拆解为绘图步骤的建模能力
  • 体会"像素级精确"的工程标准

教学重点

  • 2D上下文获取与画笔设置
  • 按下-移动-抬起三事件模型
  • 坐标换算getBoundingClientRect

教学难点

  • 连续画线需记录上一个点
  • canvas宽高属性与CSS尺寸的区别

💻 实例演示1个实例 · 可在线运行

▶ 竞赛任务9:绘图画布

800×600画布,红绿蓝三色切换,鼠标拖动画线——2026纯JS版。

新窗口运行 下载源码

操作步骤

  1. 打开demo1.html,按住鼠标拖动画线
  2. 点击绿/蓝色块换色再画
  3. 快速画圈,观察线条是否平滑(lineJoin的作用)
  4. 注释掉[lastX,lastY]=[x,y]更新,观察放射状线条
  5. 对照评分点:尺寸/边框/三色/平滑画线

效果观察点

  • mousemove中不断从上一点画到当前点
  • getBoundingClientRect换算画布内坐标
  • data-color读取自定义属性
查看核心代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Task 9 - 画板</title>
<style>
  * { margin: 0; padding: 0; }
  body { background: #f2f6f8; padding: 24px; font-family: Arial, sans-serif; }
  #canvas { border: 2px solid black; background: #fff; cursor: crosshair; }
  .color > div { width: 40px; height: 40px; cursor: pointer; float: left; margin: 20px 20px 20px 0; border-radius: 6px; }
  .red { background: red; } .green { background: green; } .blue { background: blue; }
  .color > div.active { outline: 3px solid #123a52; }
</style>
</head>
<body>
  <canvas id="canvas" width="800" height="600"></canvas>
  <div class="color">
    <div class="red active" data-color="red"></div>
    <div class="green" data-color="green"></div>
    <div class="blue" data-color="blue"></div>
  </div>
<script>
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  let drawing = false, lastX = 0, lastY = 0;
  ctx.lineWidth = 4; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = 'red';
  function getPos(e) {
    const rect = canvas.getBoundingClientRect();
    return [e.clientX - rect.left, e.clientY - rect.top];
  }
  canvas.addEventListener('mousedown', e => { drawing = true; [lastX, lastY] = getPos(e); });
  canvas.addEventListener('mousemove', e => {
    if (!drawing) return;
    const [x, y] = getPos(e);
    ctx.beginPath(); ctx.moveTo(lastX, lastY); ctx.lineTo(x, y); ctx.stroke();
    [lastX, lastY] = [x, y];
  });
  ['mouseup', 'mouseleave'].forEach(ev => canvas.addEventListener(ev, () => drawing = false));
  document.querySelectorAll('.color > div').forEach(sw => {
    sw.addEventListener('click', () => {
      document.querySelector('.color .active').classList.remove('active');
      sw.classList.add('active');
      ctx.strokeStyle = sw.dataset.color;
    });
  });
</script>
</body>
</html>

📋 实习任务书

任务目标:独立完成竞赛任务9画板并理解绘图模型

任务内容与评分
任务1:创建800×600带边框画布(15分)
任务2:实现按下-移动-抬起画线模型(35分)
任务3:三色色块切换画笔颜色(20分)
任务4:线条圆角平滑无锯齿(15分)
任务5:画出canvas属性宽高与CSS宽高的区别(15分)

自我评价

📚 课后作业与预习