哆啦 A 梦

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" href="/icon-min.png" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="博客-柒书" />
        <title>Canvas 2D-博客-柒书</title>
      </head>
      <body>
        <canvas id="canvasRef" width="280px" height="340px">
          该浏览器暂不支持canvas标签
        </canvas>
      </body>
      <script>
        // 计算角度
        const Deg = (Number) => {
          if (typeof Number === "number") {
            return (Math.PI / 180) * Number;
          }
          return Number;
        };
    
        const draw = (ctx, x = 0, y = 0) => {
          // 脸轮廓
          ctx.beginPath();
          ctx.fillStyle = "rgb(88,160,232)";
          ctx.arc(140 + x, 100 + y, 90, Deg(0), Deg(360), false);
          ctx.fill();
          ctx.stroke();
          // 项圈
          ctx.beginPath();
          ctx.fillStyle = "rgb(215,42,47)";
          ctx.moveTo(82 + x, 170 + y);
          ctx.quadraticCurveTo(140 + x, 175 + y, 199 + x, 170 + y);
          ctx.quadraticCurveTo(204 + x, 174 + y, 199 + x, 178 + y);
          ctx.quadraticCurveTo(140 + x, 183 + y, 82 + x, 178 + y);
          ctx.quadraticCurveTo(78 + x, 174 + y, 82 + x, 170 + y);
          ctx.fill();
          ctx.stroke();
          // 身体轮廓
          ctx.beginPath();
          ctx.fillStyle = "rgb(88,160,232)";
          ctx.moveTo(90 + x, 178 + y);
          ctx.quadraticCurveTo(65 + x, 155 + y, 40 + x, 140 + y);
          ctx.lineTo(20 + x, 160 + y);
          ctx.quadraticCurveTo(50 + x, 200 + y, 80 + x, 220 + y);
          ctx.quadraticCurveTo(76 + x, 250 + y, 80 + x, 300 + y);
          ctx.quadraticCurveTo(105 + x, 304 + y, 130 + x, 300 + y);
          ctx.lineTo(133 + x, 285 + y);
          ctx.lineTo(150 + x, 275 + y);
          ctx.moveTo(133 + x, 285 + y);
          ctx.lineTo(135 + x, 300 + y);
          ctx.quadraticCurveTo(162 + x, 305 + y, 190 + x, 295 + y);
          ctx.quadraticCurveTo(200 + x, 240 + y, 199 + x, 178 + y);
          ctx.quadraticCurveTo(140 + x, 183 + y, 90 + x, 178 + y);
          ctx.moveTo(199 + x, 178 + y);
          ctx.quadraticCurveTo(215 + x, 190 + y, 230 + x, 220 + y);
          ctx.lineTo(210 + x, 235 + y);
          ctx.quadraticCurveTo(202 + x, 232 + y, 199 + x, 224 + y);
          ctx.fill();
          ctx.stroke();
          // 手
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.arc(24 + x, 144 + y, 17, Deg(0), Deg(360), true);
          ctx.fill();
          ctx.stroke();
          ctx.beginPath();
          ctx.arc(227 + x, 235 + y, 17, Deg(0), Deg(360), true);
          ctx.fill();
          ctx.stroke();
          // 右脚
          ctx.beginPath();
          ctx.moveTo(135 + x, 300 + y);
          ctx.quadraticCurveTo(162 + x, 305 + y, 190 + x, 295 + y);
          ctx.bezierCurveTo(205 + x, 295 + y, 205 + x, 308 + y, 200 + x, 313 + y);
          ctx.quadraticCurveTo(162 + x, 322 + y, 136 + x, 316 + y);
          ctx.fill();
          ctx.stroke();
          // 左脚
          ctx.beginPath();
          ctx.moveTo(80 + x, 300 + y);
          ctx.quadraticCurveTo(105 + x, 304 + y, 130 + x, 300 + y);
          ctx.bezierCurveTo(143 + x, 300 + y, 143 + x, 314 + y, 130 + x, 320 + y);
          ctx.quadraticCurveTo(105 + x, 326 + y, 72 + x, 320 + y);
          ctx.bezierCurveTo(65 + x, 316 + y, 70 + x, 300 + y, 80 + x, 300 + y);
          ctx.fill();
          ctx.stroke();
          // 尾巴
          ctx.beginPath();
          ctx.fillStyle = "rgb(215,42,47)";
          ctx.arc(62 + x, 268 + y, 10, Deg(0), Deg(360), true);
          ctx.moveTo(78 + x, 260 + y);
          ctx.lineTo(70 + x, 265 + y);
          ctx.fill();
          ctx.stroke();
          // 腹部
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.moveTo(115 + x, 180 + y);
          ctx.bezierCurveTo(90 + x, 200 + y, 85 + x, 268 + y, 160 + x, 260 + y);
          ctx.bezierCurveTo(205 + x, 255 + y, 204 + x, 200 + y, 182 + x, 180 + y);
          ctx.quadraticCurveTo(146 + x, 181 + y, 115 + x, 180 + y);
          ctx.fill();
          ctx.stroke();
          // 口袋
          ctx.beginPath();
          ctx.arc(150 + x, 215 + y, 36, Deg(0), Deg(180), false);
          ctx.closePath();
          ctx.stroke();
          // 铃铛
          ctx.beginPath();
          ctx.fillStyle = "rgb(245,215,103)";
          ctx.arc(160 + x, 188 + y, 11, Deg(0), Deg(360), false);
          ctx.fill();
          ctx.stroke();
          ctx.beginPath();
          ctx.moveTo(147 + x, 188 + y);
          ctx.quadraticCurveTo(161 + x, 180 + y, 172 + x, 183 + y);
          ctx.quadraticCurveTo(174 + x, 185 + y, 172 + x, 187 + y);
          ctx.quadraticCurveTo(161 + x, 185 + y, 147 + x, 192 + y);
          ctx.quadraticCurveTo(145 + x, 190 + y, 147 + x, 188 + y);
          ctx.fill();
          ctx.stroke();
          ctx.beginPath();
          ctx.fillStyle = "#000";
          ctx.arc(162 + x, 192 + y, 2.5, Deg(0), Deg(360), false);
          ctx.moveTo(162 + x, 192 + y);
          ctx.lineTo(162 + x, 200 + y);
          ctx.fill();
          ctx.stroke();
          // 脸部轮廓
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.moveTo(90 + x, 170 + y);
          ctx.bezierCurveTo(x - 30, y, 334 + x, y - 4, 200 + x, 170 + y);
          ctx.quadraticCurveTo(140 + x, 175 + y, 90 + x, 170 + y);
          ctx.fill();
          ctx.stroke();
          // 嘴角
          ctx.beginPath();
          ctx.moveTo(205 + x, 110 + y);
          ctx.quadraticCurveTo(220 + x, 110 + y, 230 + x, 90 + y);
          ctx.arc(214 + x, 85 + y, 16, Deg(30), Deg(-160), true);
          ctx.fill();
          ctx.stroke();
          // 嘴
          ctx.beginPath();
          ctx.fillStyle = "rgb(222,43,42)";
          ctx.moveTo(90 + x, 100 + y);
          ctx.quadraticCurveTo(140 + x, 110 + y, 205 + x, 110 + y);
          ctx.bezierCurveTo(190 + x, 180 + y, 100 + x, 180 + y, 85 + x, 105 + y);
          ctx.quadraticCurveTo(82 + x, 98 + y, 90 + x, 100 + y);
          ctx.fill();
          ctx.stroke();
          // 舌头
          ctx.beginPath();
          ctx.fillStyle = "rgb(229,122,30)";
          ctx.moveTo(98 + x, 135 + y);
          ctx.bezierCurveTo(118 + x, 105 + y, 170 + x, 120 + y, 173 + x, 155 + y);
          ctx.bezierCurveTo(155 + x, 168 + y, 108 + x, 160 + y, 98 + x, 135 + y);
          ctx.fill();
          ctx.stroke();
          // 左眼框
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.moveTo(116 + x, 46 + y);
          ctx.bezierCurveTo(116 + x, 76 + y, 158 + x, 76 + y, 152 + x, 42 + y);
          ctx.bezierCurveTo(146 + x, 10 + y, 118 + x, 10 + y, 116 + x, 46 + y);
          ctx.fill();
          ctx.stroke();
          // 右眼框
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.moveTo(152 + x, 42 + y);
          ctx.bezierCurveTo(158 + x, 72 + y, 182 + x, 74 + y, 182 + x, 46 + y);
          ctx.bezierCurveTo(172 + x, 10 + y, 147 + x, 10 + y, 152 + x, 42 + y);
          ctx.fill();
          ctx.stroke();
          // 眼睛
          ctx.beginPath();
          ctx.lineWidth = 3;
          ctx.arc(140 + x, 46 + y, 8, Deg(0), Deg(180), true);
          ctx.moveTo(174 + x, 46 + y);
          ctx.arc(166 + x, 46 + y, 8, Deg(0), Deg(180), true);
          ctx.stroke();
          // 鼻子
          ctx.beginPath();
          ctx.lineWidth = 1;
          ctx.fillStyle = "rgba(218,42,46)";
          ctx.arc(158 + x, 68 + y, 10, Deg(0), Deg(360), true);
          ctx.fill();
          ctx.stroke();
          ctx.beginPath();
          ctx.fillStyle = "#fff";
          ctx.arc(156 + x, 66 + y, 3, Deg(0), Deg(360), true);
          ctx.fill();
          // 胡子
          ctx.beginPath();
          ctx.moveTo(158 + x, 78 + y);
          ctx.quadraticCurveTo(160 + x, 93 + y, 160 + x, 108 + y);
          ctx.moveTo(182 + x, 76 + y);
          ctx.lineTo(220 + x, 50 + y);
          ctx.moveTo(184 + x, 86 + y);
          ctx.lineTo(232 + x, 82 + y);
          ctx.moveTo(182 + x, 96 + y);
          ctx.lineTo(226 + x, 105 + y);
          ctx.moveTo(129 + x, 78 + y);
          ctx.lineTo(75 + x, 58 + y);
          ctx.moveTo(127 + x, 88 + y);
          ctx.lineTo(65 + x, 85 + y);
          ctx.moveTo(129 + x, 98 + y);
          ctx.lineTo(75 + x, 115 + y);
          ctx.stroke();
        };
    
        const canvas = document.querySelector("canvas");
        const ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        draw(ctx, 0, 0);
      </script>
    </html>