canvas 系列学习笔记二《绘制图形》

2022-09-08 11:18:53 浏览数 (1)

canvas 可以获取上下文,2d 部分是CanvasRenderingContext2D,它用于绘制形状,文本,图像和其他对象。

画矩形


canvas提供了三种方法绘制矩形:

fillRect(x, y, width, height) 绘制一个填充的矩形

strokeRect(x, y, width, height) 绘制一个矩形的边框

clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明。

代码:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绘制矩形</title>
</head>
<body>
   <canvas id="canvas2d" width="200" height="200" style="background:red"></canvas>
</body>
<script>
    let canvas2d = document.getElementById('canvas2d')
    console.log(canvas2d);
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext('2d');
        ctx.fillRect(25, 25, 100, 100);
        ctx.clearRect(45, 45, 60, 60);
        ctx.strokeRect(50, 50, 50, 50);
    }
</script>
</html>

结果:

绘制圆形


画圆形api

代码语言:javascript复制
void ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

参数:

x 圆弧中心(圆心)的 x 轴坐标。

y 圆弧中心(圆心)的 y 轴坐标。

radius 圆弧的半径。

startAngle 圆弧的起始点, x轴方向开始计算,单位以弧度表示。

endAngle 圆弧的终点, 单位以弧度表示。

anticlockwise 可选 可选的Boolean值 ,如果为 true,逆时针绘制圆弧,反之,顺时针绘制。

例子代码:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绘制圆形</title>
</head>
<body>
   <canvas id="canvas2d" width="200" height="200"></canvas>
</body>
<style>
  #canvas2d{
    border: 1px solid;
    display: block;
    margin: 0 auto;
  }
</style>

<script>
    let canvas2d = document.getElementById('canvas2d')
    canvas2d.width = window.innerWidth/2
    canvas2d.height = window.innerHeight
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext('2d');
      ctx.beginPath();
      ctx.arc(75, 75, 50, 0, 2 * Math.PI);
      ctx.stroke();  

      ctx.beginPath();
      ctx.moveTo(260,75)
      ctx.arc(200, 75, 60, 0, 2 * Math.PI);
      ctx.fill()
    }
</script>
</html>

显示:

绘制五角星


首先整理下思路,看了别人一个图比较好,拿来一下。

思路:

  1. 两个圆各自五个点,每个点相差72度
  2. 点可以根据半径和度数求出x,y 坐标
  3. 循环点,canvans 连线
代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>绘制五角星</title>
  </head>
  <body>
    <canvas id="canvas2d" width="200" height="200"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    canvas2d.width = window.innerWidth / 2;
    canvas2d.height = window.innerHeight;
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      ctx.beginPath();
      // 将坐标移动到画布中央
      ctx.translate(canvas2d.width / 2, canvas2d.height / 2);
      // 设置大圆、小圆半径
      let R = 200;
      let r = 100;
      let x;
      let y;
      // 逆时针计算五角星外围10个点的坐标
      for (let i = 0; i < 5; i  ) {
        // 外围凸出的每个点坐标
        x = Math.cos(((18   72 * i) / 180) * Math.PI) * R;
        y = -Math.sin(((18   72 * i) / 180) * Math.PI) * R; // canvas中y轴的正向方向与直角坐标系相反
        ctx.lineTo(x, y);
        // 外围凹下去的每个点坐标
        x = Math.cos(((54   72 * i) / 180) * Math.PI) * r;
        y = -Math.sin(((54   72 * i) / 180) * Math.PI) * r; // canvas中y轴的正向方向与直角坐标系相反
        ctx.lineTo(x, y);
      }
      ctx.closePath();
      ctx.stroke();
    }
  </script>
</html>

绘制笑脸


官方示例,这是相比于五角星,会有一个移动画笔的动作。

代码:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>绘制五角星</title>
  </head>
  <body>
    <canvas id="canvas2d" width="200" height="200"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    // canvas2d.width = window.innerWidth / 2;
    // canvas2d.height = window.innerHeight;
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      ctx.beginPath();
      ctx.arc(75, 75, 50,  0, Math.PI * 2, false); // 绘制
      ctx.moveTo(110, 75);
      ctx.arc(75, 75, 35, 0, Math.PI, false); // 口 (顺时针)
      ctx.moveTo(65, 65);
      ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // 左眼
      ctx.moveTo(95, 65);
      ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // 右眼
      ctx.stroke();
    }
  </script>
</html>

效果:

二次贝塞尔曲线

贝塞尔曲线一般用来画曲线,波浪等图形,依赖于贝塞尔曲线公式。可借助在线工具帮助获取想要的曲线控制点。

贝塞尔画线工具

API 说明

quadraticCurveTo(cp1x, cp1y, x, y)

绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。

下面例子是用二次贝塞尔曲线画一个提示框

示例代码

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>二次贝塞尔曲线</title>
  </head>
  <body>
    <canvas id="canvas2d" width="500" height="500"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      // 二次贝塞尔曲线
      ctx.beginPath();
      ctx.moveTo(75, 25);
      ctx.quadraticCurveTo(25, 25, 25, 62.5);
      ctx.quadraticCurveTo(25, 100, 50, 100);
      ctx.quadraticCurveTo(50, 120, 30, 125);
      ctx.quadraticCurveTo(60, 120, 65, 100);
      ctx.quadraticCurveTo(125, 100, 125, 62.5);
      ctx.quadraticCurveTo(125, 25, 75, 25);
      ctx.stroke();
    }
  </script>
</html>

效果展示

三次贝塞尔曲线


API 说明

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。

下面利用三次贝塞尔曲线画一个心形

效果演示

代码示例

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>三次贝塞尔曲线</title>
  </head>
  <body>
    <canvas id="canvas2d" width="200" height="200"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      // 三次贝塞尔曲线
      ctx.beginPath();
      ctx.moveTo(75, 40);
      ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
      ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
      ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
      ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
      ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
      ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
      ctx.fill();
    }
  </script>
</html>

综合应用


把以上图形综合应用到项目里,添加

效果演示

代码示例

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>综合示例</title>
  </head>
  <body>
    <canvas id="canvas2d" width="500" height="500"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      // 将坐标移动到画布中央
      ctx.translate(160, 160);

      //大石块障碍物
      roundedRect(ctx, 12, 12, 200, 200, 15);
      roundedRect(ctx, 19, 19, 200, 200, 9);
      roundedRect(ctx, 53, 53, 49, 33, 10);
      roundedRect(ctx, 53, 119, 49, 16, 6);
      roundedRect(ctx, 135, 53, 49, 33, 10);
      roundedRect(ctx, 135, 119, 25, 49, 10);

      ctx.beginPath();
      // 开始角度和结束角度限制形成缺口
      ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false);
      ctx.lineTo(31, 37);
      ctx.fill();

      // 小方块黑点
      for (var i = 0; i < 8; i  ) {
        ctx.fillRect(51   i * 16, 35, 4, 4);
      }

      for (i = 0; i < 6; i  ) {
        ctx.fillRect(115, 51   i * 16, 4, 4);
      }

      for (i = 0; i < 8; i  ) {
        ctx.fillRect(51   i * 16, 99, 4, 4);
      }

      // 怪物,从左下角开始画
      ctx.beginPath();
      ctx.moveTo(83, 116);
      ctx.lineTo(83, 102);
      ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
      ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
      ctx.lineTo(111, 116);
      ctx.lineTo(106.333, 111.333);
      ctx.lineTo(101.666, 116);
      ctx.lineTo(97, 111.333);
      ctx.lineTo(92.333, 116);
      ctx.lineTo(87.666, 111.333);
      ctx.lineTo(83, 116);
      ctx.fill();

      // 怪兽眼睛,是贝塞尔曲线不是圆
      ctx.fillStyle = "white";
      ctx.beginPath();
      ctx.moveTo(91, 96);
      ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
      ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
      ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
      ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
      ctx.moveTo(103, 96);
      ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
      ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
      ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
      ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
      ctx.fill();

      // 怪兽黑眼珠
      ctx.fillStyle = "black";
      ctx.beginPath();
      ctx.arc(101, 102, 2, 0, Math.PI * 2, true);
      ctx.fill();

      ctx.beginPath();
      ctx.arc(89, 102, 2, 0, Math.PI * 2, true);
      ctx.fill();
    }

    // 封装的一个用于绘制圆角矩形的函数。
    // 方块从左上角弧度下开始化
    function roundedRect(ctx, x, y, width, height, radius) {
      ctx.beginPath();
      ctx.moveTo(x, y   radius);
      ctx.lineTo(x, y   height - radius);
      ctx.quadraticCurveTo(x, y   height, x   radius, y   height);
      ctx.lineTo(x   width - radius, y   height);
      ctx.quadraticCurveTo(
        x   width,
        y   height,
        x   width,
        y   height - radius
      );
      ctx.lineTo(x   width, y   radius);
      ctx.quadraticCurveTo(x   width, y, x   width - radius, y);
      ctx.lineTo(x   radius, y);
      ctx.quadraticCurveTo(x, y, x, y   radius);
      ctx.stroke();
    }
  </script>
</html>

Path2D


Path2D 看这个名字已经明白了这个对象的意义,就是路径,我们可以把路径看做对象,路径对象可以添加多条轨迹集合。这样高效在画布上进行复用。

以三维贝塞尔曲线画心型为例,可以缓存心形路径达到复用路径的目的。

代码示例

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>path2d</title>
  </head>
  <body>
    <canvas id="canvas2d" width="500" height="500"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      // 用path 对象画图

      let heart = new Path2D();
      heart.moveTo(75, 40);
      heart.bezierCurveTo(75, 37, 70, 25, 50, 25);
      heart.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
      heart.bezierCurveTo(20, 80, 40, 102, 75, 120);
      heart.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
      heart.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
      heart.bezierCurveTo(85, 25, 75, 37, 75, 40);
      ctx.stroke(heart);
      ctx.translate(30,10)
      ctx.fill(heart)
    }
  </script>
</html>

效果演示

path2d svg 路径支持

新的 Path2D API 有另一个强大的特点,就是使用 SVG path data 来初始化 canvas 上的路径。这将使你获取路径时可以以 SVG 或 canvas 的方式来重用它们。

这条路径将先移动到点 (M10 10) 然后再水平移动 80 个单位(h 80),然后下移 80 个单位 (v 80),接着左移 80 个单位 (h -80),再回到起点处 (z)。你可以在Path2D constructor 查看这个例子。

代码示例

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>path2d</title>
  </head>
  <body>
    <canvas id="canvas2d" width="500" height="500"></canvas>
  </body>
  <style>
    #canvas2d {
      border: 1px solid;
      display: block;
      margin: 0 auto;
    }
  </style>

  <script>
    let canvas2d = document.getElementById("canvas2d");
    if (canvas2d.getContext) {
      var ctx = canvas2d.getContext("2d");
      var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
      ctx.strokeStyle = 'red'
      ctx.stroke(p);
    }
  </script>
</html>

效果演示

0 人点赞