canvas基础

常用方法

<dl>
  <dt>常用方法</dt>
  <dd>
    <dl>
      <dt>直线(路径)</dt>
      <dd>
        <p>context.lineTo(x, y)</p>
        <canvas id="line" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#line");
            const context = canvas.getContext("2d");

            context.fillStyle = "#000";

            context.beginPath();
            context.moveTo(20, 50);
            context.lineTo(80, 50);
            context.stroke();

            context.beginPath(); //开始画新的路径
            context.moveTo(120, 20);
            context.lineTo(120, 80);
            context.stroke();

            context.beginPath();
            context.moveTo(220, 20);
            context.lineTo(220, 80);
            context.lineTo(250, 80);
            context.stroke();

            context.beginPath();
            context.moveTo(320, 20);
            context.lineTo(320, 80);
            context.lineTo(350, 80);
            context.closePath(); //闭合路径
            context.stroke();
          }
        </script>
      </dd>

      <dt>矩形</dt>
      <dd>
        <p>矩形(路径):context.rect(x, y, width, height)</p>
        <p>填充矩形:context.fillRect(x, y, width, height)</p>
        <p>描边矩形:context.strokeRect(x, y, width, height)</p>
        <canvas id="rect" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#rect");
            const context = canvas.getContext("2d");

            context.fillStyle = "#000";
            context.lineWidth = 1;

            // 矩形
            context.rect(0, 0, 80, 80);
            context.stroke();

            // 矩形填充
            context.fillRect(100, 0, 80, 80);

            // 5像素宽矩形描边
            context.lineWidth = 5;
            context.strokeRect(200, 0, 80, 80);
          }
        </script>
      </dd>

      <dt>圆弧 | 椭圆</dt>
      <dd>
        <p>正圆弧(路径):context.arc(x, y, radius, startAngle, endAngle [, anticlockwise])</p>
        <p>椭圆(路径):context.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)</p>
        <p>给路径添加圆弧(路径):context.arcTo(cpx1, cpy1, cpx2, cpy2, radius)</p>
        <p>贝塞尔曲线(路径):context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)</p>
        <canvas id="arc" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#arc");
            const context = canvas.getContext("2d");

            context.fillStyle = "#000";

            // 顺时针绘制0到1/4弧度圆弧
            context.beginPath();
            context.arc(50, 50, 40, 0, Math.PI / 2);
            context.stroke();

            // 逆时针绘制0到1/4弧度圆弧
            context.beginPath();
            context.arc(150, 50, 40, 0, Math.PI / 2, true);
            context.stroke();

            // 绘制完整圆
            context.beginPath();
            context.arc(250, 50, 40, 0, 2 * Math.PI);
            context.stroke();

            // 绘制椭圆 旋转45°
            context.beginPath();
            context.ellipse(350, 50, 50, 40, Math.PI / 4, 0, 2 * Math.PI);
            context.stroke();

            // 绘制椭圆 旋转45°
            context.beginPath();
            context.ellipse(450, 50, 50, 50, Math.PI / 2, 0, Math.PI);
            context.stroke();

            // 给路径添加圆弧,需要指定控制点和半径,常用于绘制标准圆角
            context.beginPath();
            context.moveTo(500, 50);
            context.arcTo(550, 100, 600, 50, 40);
            context.stroke();
          }
        </script>
      </dd>

      <dt>贝塞尔曲线</dt>
      <dd>
        <p>贝塞尔曲线(路径):context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)</p>
        <p>二次贝塞尔曲线(路径):context.quadraticCurveTo(cpx, cpy, x, y);</p>
        <canvas id="bezier" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#bezier");
            const context = canvas.getContext("2d");

            context.fillStyle = "#000";

            // 贝塞尔曲线
            context.beginPath();
            context.moveTo(0, 50);
            context.bezierCurveTo(30, 75, 60, 40, 90, 60);
            context.stroke();

            context.beginPath();
            context.moveTo(100, 50);
            context.bezierCurveTo(130, 65, 160, 55, 190, 60);
            context.stroke();

            //二次贝塞尔曲线
            context.beginPath();
            context.moveTo(200, 50);
            context.quadraticCurveTo(250, 75, 290, 30);
            context.stroke();
          }
        </script>
      </dd>

      <dt>Image</dt>
      <dd>
        <p>context.drawImage(image, dx, dy);</p>
        <p>context.drawImage(image, dx, dy, dWidth, dHeight);</p>
        <p>context.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);</p>
        <p>context.getImageData(sx, sy, sWidth, sHeight);</p>
        <p>context.putImageData(imagedata, dx, dy);</p>
        <p>context.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);</p>
        <p>context.createImageData(width, height);</p>
        <canvas id="image" width="100" height="100"></canvas>
        <canvas id="image1" width="100" height="100"></canvas>
        <canvas id="image2" width="100" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#image");
            const context = canvas.getContext("2d");

            const canvas1 = document.querySelector("#image1");
            const context1 = canvas1.getContext("2d");

            const canvas2 = document.querySelector("#image2");
            const context2 = canvas2.getContext("2d");

            const image = new Image();
            image.onload = function () {
              context.drawImage(image, 0, 0);

              context1.drawImage(image, 0, 0, 100, 100);

              const val = Math.min(this.width, this.height);
              context2.drawImage(image, 0, 0, val, val, 0, 0, 100, 100);

              // 然后获取区域数据
              const imageData = context2.getImageData(25, 25, 75, 75);
              const length = imageData.data.length;
              for (let index = 0; index < length; index += 4) {
                const r = imageData.data[index];
                const g = imageData.data[index + 1];
                const b = imageData.data[index + 2];
                // 计算灰度
                const gray = r * 0.299 + g * 0.587 + b * 0.114;
                imageData.data[index] = gray;
                imageData.data[index + 1] = gray;
                imageData.data[index + 2] = gray;
              }

              context2.putImageData(imageData, 25, 25);

              const imageData1 = context1.createImageData(80, 50);
              for (let x = 1; x <= 80; x += 5) {
                for (let y = 1; y <= 50; y += 5) {
                  const index = 4 * ((y - 1) * 80 + (x - 1));
                  // 变为绿色,色值依次是0, 128, 0, 256
                  imageData1.data[index] = 0;
                  imageData1.data[index + 1] = 128;
                  imageData1.data[index + 2] = 0;
                  imageData1.data[index + 3] = 256;
                }
              }
              context1.putImageData(imageData1, 25, 25, 0, 0, 50, 50);
            };
            image.src = "../images/1.jpg";
          }
        </script>
      </dd>

      <dt>文本</dt>
      <dd>
        <p>文本绘制:context.fillText(text, x, y [, maxWidth])</p>
        <p>文本描边:context.strokeText(text, x, y [, maxWidth])</p>
        <p>测量文本宽高等信息:context.measureText(text)</p>
        <canvas id="text" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#text");
            const context = canvas.getContext("2d");

            // 设置水平对齐方式,可选值:left、right、center、start、end
            context.textAlign = "left";
            //设置字体垂直对齐方式
            context.textBaseline = "alphabetic";

            const str = "Canvas学习";

            //font默认值:10px sans-serif
            context.fillText(str, 0, 10);
            context.fillText(`宽${context.measureText(str).width}`, 0, 20);

            // 设置字体和字号
            context.font = "20px SimSun, SimHei";
            context.fillText(str, 100, 20);
            context.fillText(`宽${context.measureText(str).width}`, 100, 50);

            //超过maxWidth限制后,文本水平方向压缩
            context.fillText(str, 100, 80, 50);

            // 文字描边
            context.strokeText(str, 250, 20);

            // 文字先描边
            context.lineWidth = 3;
            context.strokeStyle = "red";
            context.strokeText(str, 250, 40);
            // 再填充
            context.fillText(str, 250, 40);
          }
        </script>
      </dd>

      <dt>其它</dt>
      <dd>
        <p>清除区域:context.clearRect(x, y, width, height);</p>
        <p>裁剪区域:context.clip();</p>
        <p>canvas.toDataURL(mimeType, quality);</p>
        <p>canvas.toBlob(callback, mimeType, quality);</p>
        <p>mimeType默认值image/png;quality表示转换的图片质量。范围是0到1。默认压缩值是0.92。</p>
        <canvas id="clearRect" width="100" height="100"></canvas>
        <canvas id="clip" width="100" height="100"></canvas>
        <img src="" id="clip1" width="100" height="100" />
        <img src="" id="clip2" width="100" height="100" />
        <script>
          {
            const canvas = document.querySelector("#clearRect");
            const context = canvas.getContext("2d");

            const canvas1 = document.querySelector("#clip");
            const context1 = canvas1.getContext("2d");

            const image = new Image();
            image.onload = function () {
              context.drawImage(image, 0, 0, canvas.width, canvas.height);
              context.clearRect(25, 25, 50, 50);

              context1.arc(50, 50, 50, 0, 2 * Math.PI);
              context1.clip();
              context1.drawImage(image, 0, 0, canvas.width, canvas.height);

              canvas1.toBlob(function (blob) {
                const url = URL.createObjectURL(blob);
                document.querySelector("#clip1").src = url;
              });

              const dataUrl = canvas1.toDataURL();
              document.querySelector("#clip2").src = dataUrl;
            };
            image.src = "../images/1.jpg";
          }
        </script>
      </dd>
    </dl>
  </dd>
</dl>

绘制属性

<dl>
  <dt>属性</dt>
  <dd>
    <dl>
      <dt>线</dt>
      <dd>
        <p>线宽:context.lineWidth = value</p>
        <p>线条转角:context.lineJoin = 'miter'; context.lineJoin = 'round'; context.lineJoin = 'bevel';</p>
        <p>线条端点:context.lineCap = 'butt'; context.lineCap = 'round'; context.lineCap = 'square';</p>
        <p>虚线绘制的偏移距离:context.lineDashOffset = value</p>
        <canvas id="lineWidth" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#lineWidth");
            const context = canvas.getContext("2d");

            context.lineWidth = 2;
            context.strokeRect(0, 0, 80, 80);

            context.lineWidth = 10;
            context.lineJoin = "miter";
            context.strokeRect(100, 0, 80, 80);

            context.lineJoin = "round";
            context.strokeRect(200, 0, 80, 80);

            context.lineJoin = "bevel";
            context.strokeRect(300, 0, 80, 80);

            context.lineJoin = "miter";
            context.lineCap = "butt";
            context.beginPath();
            context.moveTo(400, 20);
            context.lineTo(480, 20);
            context.stroke();

            context.lineCap = "round";
            context.beginPath();
            context.moveTo(400, 50);
            context.lineTo(480, 50);
            context.stroke();

            context.lineCap = "square"; //线的端点多出一个方框,框框的宽度和线一样宽,高度是线厚度的一半
            context.beginPath();
            context.moveTo(400, 80);
            context.lineTo(480, 80);
            context.stroke();

            context.lineCap = "butt";
            //重置虚线设置 ctx.setLineDash(segments)
            context.setLineDash([2, 2]);
            context.lineDashOffset = 0;
            context.beginPath();
            context.moveTo(500, 20);
            context.lineTo(580, 20);
            context.stroke();

            context.setLineDash([1, 2, 3, 6]);
            context.lineDashOffset = 5;
            context.beginPath();
            context.moveTo(500, 50);
            context.lineTo(580, 50);
            context.stroke();

            context.lineDashOffset = -5;
            context.beginPath();
            context.moveTo(500, 80);
            context.lineTo(580, 80);
            context.stroke();
          }
        </script>
      </dd>

      <dt>描边样式</dt>
      <dd>
        <p>context.strokeStyle = color</p>
        <p>context.strokeStyle = gradient</p>
        <p>context.strokeStyle = pattern</p>
        <canvas id="stroke" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#stroke");
            const context = canvas.getContext("2d");

            context.lineWidth = 10;

            context.strokeStyle = "RGB(255, 0, 0)";
            context.strokeRect(0, 0, 80, 80);

            context.strokeStyle = "RGBA(255, 0, 0, .5)";
            context.strokeRect(100, 0, 80, 80);

            context.strokeStyle = "#FF0000";
            context.strokeRect(200, 0, 80, 80);

            // 创建线性渐变对象 context.createLinearGradient(x0, y0, x1, y1)
            const gradientLinear = context.createLinearGradient(0, 0, 0, 100);
            gradientLinear.addColorStop(0, "red");
            gradientLinear.addColorStop(0.5, "yellow");
            gradientLinear.addColorStop(1, "green");
            context.strokeStyle = gradientLinear;
            context.strokeRect(300, 0, 80, 80);

            // 创建径向渐变对象  context.createRadialGradient(x0, y0, r0, x1, y1, r1);
            const gradientRadial = context.createRadialGradient(440, 40, 0, 440, 40, 50);
            gradientRadial.addColorStop(0, "red");
            gradientRadial.addColorStop(1, "green");
            context.strokeStyle = gradientRadial;
            context.strokeRect(400, 0, 80, 80);

            // 创建图案对象
            const imagePattern = document.createElement("img");
            imagePattern.onload = function () {
              // 缩放原始图片到50*50大小
              const canvas_img = document.createElement("canvas");
              canvas_img.width = canvas_img.height = 50;
              const context_img = canvas_img.getContext("2d");
              // 通过drawImage()方法缩放
              context_img.drawImage(this, 0, 0, 50, 50);
              // 把这个创建的canvas图形作为图案使用  context.createPattern(image, repetition)
              const pattern = context.createPattern(canvas_img, "repeat");
              // 填充图案
              context.strokeStyle = pattern;
              context.strokeRect(500, 0, 80, 80);
            };
            imagePattern.src = "../images/1.jpg";
          }
        </script>
      </dd>

      <dt>填充样式</dt>
      <dd>
        <p>context.fillStyle = color</p>
        <p>context.fillStyle = gradient</p>
        <p>context.fillStyle = pattern</p>
        <canvas id="fill" width="800" height="100"></canvas>
        <script>
          {
            const canvas = document.querySelector("#fill");
            const context = canvas.getContext("2d");

            context.fillStyle = "RGB(255, 0, 0)";
            context.fillRect(0, 0, 80, 80);

            context.fillStyle = "RGBA(255, 0, 0, .5)";
            context.fillRect(100, 0, 80, 80);

            context.fillStyle = "#FF0000";
            context.fillRect(200, 0, 80, 80);

            // 创建线性渐变对象 context.createLinearGradient(x0, y0, x1, y1)
            const gradientLinear = context.createLinearGradient(0, 0, 0, 100);
            gradientLinear.addColorStop(0, "red");
            gradientLinear.addColorStop(0.5, "yellow");
            gradientLinear.addColorStop(1, "green");
            context.fillStyle = gradientLinear;
            context.fillRect(300, 0, 80, 80);

            // 创建径向渐变对象  context.createRadialGradient(x0, y0, r0, x1, y1, r1);
            const gradientRadial = context.createRadialGradient(440, 40, 0, 440, 40, 50);
            gradientRadial.addColorStop(0, "red");
            gradientRadial.addColorStop(1, "green");
            context.fillStyle = gradientRadial;
            context.fillRect(400, 0, 80, 80);

            // 创建图案对象
            const imagePattern = document.createElement("img");
            imagePattern.onload = function () {
              // 缩放原始图片到50*50大小
              const canvas_img = document.createElement("canvas");
              canvas_img.width = canvas_img.height = 50;
              const context_img = canvas_img.getContext("2d");
              // 通过drawImage()方法缩放
              context_img.drawImage(this, 0, 0, 50, 50);
              // 把这个创建的canvas图形作为图案使用
              const pattern = context.createPattern(canvas_img, "repeat");
              // 填充图案
              context.fillStyle = pattern;
              context.fillRect(500, 0, 80, 80);
            };
            imagePattern.src = "../images/1.jpg";
          }
        </script>
      </dd>
    </dl>
  </dd>
</dl>

变换

<dl>
  <dt>平移</dt>
  <dd>
    <p>context.translate(x, y)</p>
    <p>顺时针方向旋转画布,单位是弧度。角度转弧度计算公式是:radian = degree * Math.PI / 180。</p>
    <p>默认旋转中心点是Canvas的左上角(0, 0)坐标点</p>
    <canvas id="translate" width="100" height="100"></canvas>
    <script>
      {
        const canvas = document.querySelector("#translate");
        const context = canvas.getContext("2d");

        const width = canvas.width;
        const height = canvas.height;
        const img = new Image();
        img.onload = function () {
          context.translate(width / 2, height / 2); // 先位移坐标到中心
          context.drawImage(this, 0, 0, width / 2, height / 2);
          context.setTransform(1, 0, 0, 1, 0, 0); // 坐标系还原到初始
        };
        img.src = "../images/1.jpg";
      }
    </script>
  </dd>

  <dt>缩放</dt>
  <dd>
    <p>context.scale(x, y)</p>
    <p>缩放Canvas画布的坐标系,只是影响坐标系,之后的绘制会受此方法影响,但之前已经绘制好的效果不会有任何变化。</p>
    <p>默认缩放中心点是Canvas的左上角(0, 0)坐标点</p>
    <canvas id="scale" width="800" height="100"></canvas>
    <script>
      {
        const canvas = document.querySelector("#scale");
        const context = canvas.getContext("2d");

        // 对比
        context.fillRect(10, 10, 10, 10);

        // 缩放
        context.scale(10, 3);
        context.fillRect(10, 10, 10, 10);
        context.setTransform(1, 0, 0, 1, 0, 0); // 恢复坐标系

        // 对比
        context.fillRect(30, 10, 10, 10);

        context.save(); // 记住Canvas状态
        // 垂直翻转
        context.scale(1, -1);
        context.font = "20px SimSun, SimHei";
        context.fillText("Canvas学习", 300, -50);
        context.restore(); // 恢复状态,不要影响接下来的绘制

        context.fillText("Canvas学习", 300, 80);
      }
    </script>
  </dd>

  <dt>旋转</dt>
  <dd>
    <p>context.rotate(angle)</p>
    <p>顺时针方向旋转画布,单位是弧度。角度转弧度计算公式是:radian = degree * Math.PI / 180。</p>
    <p>默认旋转中心点是Canvas的左上角(0, 0)坐标点</p>
    <canvas id="rotate" width="100" height="100"></canvas>
    <script>
      {
        const canvas = document.querySelector("#rotate");
        const context = canvas.getContext("2d");

        const width = canvas.width;
        const height = canvas.height;
        const img = new Image();
        img.onload = function () {
          context.translate(width / 2, height / 2); // 先位移坐标到中心
          context.rotate((180 * Math.PI) / 180); // 旋转
          context.translate((-1 * width) / 2, (-1 * height) / 2); // 把定位中心移动到左上角
          context.drawImage(this, 0, 0, width, height);
          context.setTransform(1, 0, 0, 1, 0, 0); // 坐标系还原到初始

          // 旋转45度
          context.rotate((45 * Math.PI) / 180);
          context.font = "20px SimSun, SimHei";
          context.fillText("Canvas学习", 50, 40);
          // 重置当前的变换矩阵为初始态
          context.setTransform(1, 0, 0, 1, 0, 0);
        };
        img.src = "../images/1.jpg";
      }
    </script>
  </dd>

  <dt>变换</dt>
  <dd>
    <p>context.transform(a, b, c, d, e, f)</p>
    <p>a 水平缩放 b 水平斜切</p>
    <p>c 垂直斜切 d 垂直缩放</p>
    <p>e 水平位移 f 垂直位移</p>
    <canvas id="transform" width="100" height="100"></canvas>
    <canvas id="transform1" width="100" height="100"></canvas>
    <canvas id="transform2" width="100" height="100"></canvas>
    <script>
      {
        const canvas = document.querySelector("#transform");
        const context = canvas.getContext("2d");

        const canvas1 = document.querySelector("#transform1");
        const context1 = canvas1.getContext("2d");

        const canvas2 = document.querySelector("#transform2");
        const context2 = canvas2.getContext("2d");

        const width = canvas.width;
        const height = canvas.height;
        const img = new Image();
        img.onload = function () {
          context.transform(0.5, 0, 0, 0.5, 0, 0);
          context.drawImage(this, 0, 0, width, height);
          context.setTransform(1, 0, 0, 1, 0, 0); // 坐标系还原到初始

          context1.transform(1, 0, 0, 1, -20, -20);
          context1.drawImage(this, 0, 0, width, height);
          context1.setTransform(1, 0, 0, 1, 0, 0); // 坐标系还原到初始

          context2.transform(1, 0.1, 0, 1, 0, 0);
          context2.drawImage(this, 0, 0, width, height);
          context2.setTransform(1, 0, 0, 1, 0, 0); // 坐标系还原到初始
        };
        img.src = "../images/1.jpg";
      }
    </script>
  </dd>
</dl>

posted @ 2024-03-01 16:40  carol2014  阅读(3)  评论(0编辑  收藏  举报