canvas

canvas

Canvas API 提供了一个通过JavaScript 和 HTML的元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

Canvas API 主要聚焦于 2D 图形。而同样使用元素的 WebGL API 则用于绘制硬件加速的 2D 和 3D 图形。

初识canvas

 <body>
    <!-- 
        id:标识元素的唯一性
        width:画布的宽度
        height:画布的高度
     -->
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
      // 1. 找到画布
      var c1 = document.getElementById("c1");
      // 2. 获取画笔,上下文对象
      var ctx = c1.getContext("2d");
      // 3. 绘制图形
      // 3.1 绘制矩形fillRect(位置x,位置y,宽度,高度)
      ctx.fillRect(100, 200, 300, 300);
    </script>
  </body>

在这里插入图片描述

标签只有两个属性**——** width和height。
id属性并不是元素所特有的,而是每一个 HTML 元素都默认具有的属性(比如 class 属性)。

我们只是在标签中提供了替换内容。不支持的浏览器将会忽略容器并在其中渲染后备内容。而支持的浏览器将会忽略在容器中包含的内容,并且只是正常渲染 canvas。

元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。我们将会将注意力放在 2D 渲染上下文中。

canvas 起初是空白的。为了展示,首先脚本需要找到渲染上下文,然后在它的上面绘制。 元素有一个叫做 getContext() 的方法,这个方法是用来获得渲染上下文它的绘画功能。getContext()接受一个参数,即上下文的类型。

var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');

代码的第一行通过使用 document.getElementById() 方法来为 元素得到 DOM 对象。一旦有了元素对象,你可以通过使用它的 getContext() 方法来访问绘画上下文。

上下文对象

var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d');
console.log(ctx);

在这里插入图片描述

canvas绘制基本图形

矩形绘制-填充模式

<body>
    <!-- 
        id:标识元素的唯一性
        width:画布的宽度
        height:画布的高度
     -->
    <canvas id="c1" width="600" height="400">
        当前浏览器不支持canvas,请下载最新的浏览器
        <a href="https://www.google.cn/intl/zh-CN/chrome/">立即下载</a>
    </canvas>

    <script>
        // 1. 找到画布
        var c1 = document.getElementById("c1");

        // 判断是否有getContext
        if (!c1.getContext) {
            console.log("当前浏览器不支持canvas,请下载最新的浏览器");
        }
        // 2. 获取画笔,上下文对象
        var ctx = c1.getContext("2d");

        console.log(ctx);

        // console.log(document.body);
        // console.log(document.body.getContext);
        // console.log(c1.getContext);
        // 3. 绘制图形
        // 3.1 绘制矩形fillRect(位置x,位置y,宽度,高度)
        // ctx.fillRect(100, 200, 300, 300);

        // 拆开写法
        ctx.rect(100, 200, 300, 300);
        ctx.fill();
    </script>
</body>

fillRect(位置x,位置y,宽度,高度);
rect:矩形。

矩形绘制-路径模式

<body>
    <!-- 
        id:标识元素的唯一性
        width:画布的宽度
        height:画布的高度
     -->
    <canvas id="c1" width="600" height="400">
        当前浏览器不支持canvas,请下载最新的浏览器
        <a href="https://www.google.cn/intl/zh-CN/chrome/">立即下载</a>
    </canvas>

    <script>
        // 1. 找到画布
        var c1 = document.getElementById("c1");

        // 判断是否有getContext
        if (!c1.getContext) {
            console.log("当前浏览器不支持canvas,请下载最新的浏览器");
        }
        // 2. 获取画笔,上下文对象
        var ctx = c1.getContext("2d");

        console.log(ctx);

        // console.log(document.body);
        // console.log(document.body.getContext);
        // console.log(c1.getContext);
        // 3. 绘制图形
        // 3.1 绘制矩形fillRect(位置x,位置y,宽度,高度)
        // ctx.strokeRect(100, 100, 20 0, 100);

        // 拆开写法
        ctx.rect(100, 100, 200, 100);
        ctx.stroke();
    </script>
</body>

strokeRect(100, 100, 20 0, 100);和fillRect()相似,但不填充内部颜色。
也可拆开写
rect(100, 100, 200, 100); 光写这个是没有图象的,必须加下面的stroke();填充模式同理。
stroke();

矩形绘制-清除模式

<body>
    <canvas id="c1" width="600" height="400">
        当前浏览器不支持canvas,请下载最新的浏览器
        <a href="https://www.google.cn/intl/zh-CN/chrome/">立即下载</a>
    </canvas>

    <script>
        // 1. 找到画布
        var c1 = document.getElementById("c1");

        // 判断是否有getContext
        if (!c1.getContext) {
            console.log("当前浏览器不支持canvas,请下载最新的浏览器");
        }
        // 2. 获取画笔,上下文对象
        var ctx = c1.getContext("2d");

        console.log(ctx);

        // console.log(document.body);
        // console.log(document.body.getContext);
        // console.log(c1.getContext);
        // 3. 绘制图形
        // 3.2 路径绘制矩形strokeRect(x1, y1, 矩形宽度, 矩形高度)
        // ctx.strokeRect(100, 100, 200, 100);
        // ctx.fillRect(200, 150, 200, 100);
        //beiginPath和closePath可以完成路径的分段
        ctx.beginPath();
        ctx.rect(100, 100, 200, 100);
        // 显示路径
        ctx.stroke();
        ctx.closePath();

        ctx.beginPath();

        ctx.rect(200, 150, 200, 100);
        ctx.fill();
        ctx.closePath();
        let height = 0;
        let t1 = setInterval(() => {
            height++;
            ctx.clearRect(0, 0, c1.clientWidth, height);
            if (height > c1.clientHeight) {
                clearInterval(t1);
            }
        }, 10);
    </script>
</body>

clearRect(0, 0, c1.clientWidth, height); 清除矩形。
这里有个补充,当在一个画布中画多个图形,并且不需要连笔时,需要对画笔进行分段。
所用api是 ctx.beginPath();和ctx.closePath(); 这样就不会产生连笔的效果

绘制圆形

圆弧

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");
        // arc是绘制圆弧的方法
        // ctx.arc(圆心x,圆心y,半径,开始的角度,结束的角度,逆时针还是顺时针,默认是顺时针false,设置逆时针的时候为true
        ctx.arc(300, 200, 50, 0, Math.PI * 2);
        ctx.fill();
    </script>
</body>

笑脸

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //绘制一张脸
        ctx.beginPath();
        ctx.arc(75, 75, 50, 0, Math.PI * 2);
        ctx.stroke();
        ctx.closePath();

        //绘制嘴巴
        ctx.beginPath();
        ctx.arc(75, 75, 35, 0, Math.PI);
        ctx.stroke();
        ctx.closePath();

        //绘制左眼
        ctx.beginPath();
        ctx.arc(60, 65, 5, 0, Math.PI * 2);
        ctx.stroke();
        ctx.closePath();

        //绘制右眼
        ctx.beginPath();
        ctx.arc(90, 65, 5, 0, Math.PI * 2);
        ctx.stroke();
        ctx.closePath();

    </script>
</body>

这里问题在笔的分段。
要用beginPath()和closePath();

用moveTo()进行分段

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //绘制一张脸
        ctx.beginPath();
        ctx.arc(75, 75, 50, 0, Math.PI * 2);
        ctx.stroke();
        ctx.moveTo(110, 75);

        //绘制嘴巴
        ctx.arc(75, 75, 35, 0, Math.PI);
        ctx.stroke();
        ctx.moveTo(65, 65)

        //绘制左眼
        ctx.beginPath();
        ctx.arc(60, 65, 5, 0, Math.PI * 2);
        ctx.stroke();
        ctx.moveTo(95, 65);

        //绘制右眼
        ctx.arc(90, 65, 5, 0, Math.PI * 2);
        ctx.stroke();
        ctx.closePath();

    </script>
</body>

用beginPaht()和closePath(),进行分段太繁琐,所以有了moveTo(位置x,位置y);

线段

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.beginPath();
        ctx.moveTo(300, 200)
        ctx.lineTo(350, 250)
        ctx.lineTo(350, 200)
        ctx.lineTo(300, 200)
        ctx.stroke();
        // ctx.fill();
        ctx.closePath();

        ctx.beginPath();
        ctx.moveTo(200, 100);
        ctx.lineTo(250, 150)
        ctx.lineTo(250, 100);
        ctx.moveTo(200, 100);

        ctx.fill();
        ctx.closePath();
    </script>
</body>

lineTo(X,Y) 画线用。

弧线

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.beginPath();

        ctx.moveTo(300, 200);
        //第二个点和第三个点,以及圆弧的半径。
        ctx.arcTo(300, 250, 250, 250, 50);
        ctx.stroke();
        ctx.closePath();

    </script>
</body>

arcTo(参考点1X,参考点1Y,参考点2X,参考点2Y,半径)

画圆弧要三个点,第一个点可以来处前面的操作。三个点形成两条直线,圆弧就切这两条线,
在小由半径决定。

贝塞尔二次曲线

在这里插入图片描述
画聊天气泡

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.beginPath();
        ctx.moveTo(200, 300);

        ctx.quadraticCurveTo(150, 300, 150, 200);
        ctx.quadraticCurveTo(150, 100, 300, 100);
        ctx.quadraticCurveTo(450, 100, 450, 200);
        ctx.quadraticCurveTo(450, 300, 250, 300);

        ctx.quadraticCurveTo(250, 350, 150, 350);
        ctx.quadraticCurveTo(200, 350, 200, 300);

        ctx.stroke();
        ctx.closePath();
    </script>
</body>

贝塞尔二次曲线。需要两个参考点,以及一个终点。和弧线同理,第一个可以来处前面的操作。

quardraticCruveTo(第二个参考点X,第二个参考点Y,终点X,终点Y);

贝塞尔三次曲线

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.beginPath();
        ctx.moveTo(300, 200);

        //两个控制点,一个终点
        ctx.bezierCurveTo(350, 150, 400, 200, 300, 250);
        ctx.bezierCurveTo(200, 200, 250, 150, 300, 200);

        ctx.stroke();
        ctx.closePath();
    </script>
</body>

一共四个点,起点,两个参考点,一个终点,起点同前面一样。
bezierCurveTo(参考点1X,参考点1Y,参考点2X,参考点2Y,终点X,终点Y)

封装路径

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //heart
        // #region
        var newHeart = new Path2D();

        newHeart.moveTo(300, 200);
        //两个控制点,一个终点
        newHeart.bezierCurveTo(350, 150, 400, 200, 300, 250);
        newHeart.bezierCurveTo(200, 200, 250, 150, 300, 200);

        ctx.stroke(newHeart);
        ctx.fill(newHeart);
        // #endregion


        //chat
        // #region
        var chatPath = new Path2D();

        chatPath.moveTo(200, 300);

        chatPath.quadraticCurveTo(150, 300, 150, 200);
        chatPath.quadraticCurveTo(150, 100, 300, 100);
        chatPath.quadraticCurveTo(450, 100, 450, 200);
        chatPath.quadraticCurveTo(450, 300, 250, 300);

        chatPath.quadraticCurveTo(250, 350, 150, 350);
        chatPath.quadraticCurveTo(200, 350, 200, 300);

        ctx.stroke(chatPath);

        // #endregion


        //创建一条拆线
        var polyLine = new Path2D("M10 10 h 80 v 80 h -80 z")
        ctx.stroke(polyLine);
    </script>
</body>

new path2D();
注意这里封装的是路径,不是画笔,最后要将路径参数放入画笔线段中。
stroke(path)

颜色设置

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //heart
        // #region
        var newHeart = new Path2D();

        newHeart.moveTo(300, 200);
        //两个控制点,一个终点
        newHeart.bezierCurveTo(350, 150, 400, 200, 300, 250);
        newHeart.bezierCurveTo(200, 200, 250, 150, 300, 200);

        ctx.strokeStyle = "red";

        ctx.stroke(newHeart);
        // ctx.fill(newHeart);
        // #endregion


        //chat
        // #region
        var chatPath = new Path2D();

        chatPath.moveTo(200, 300);

        chatPath.quadraticCurveTo(150, 300, 150, 200);
        chatPath.quadraticCurveTo(150, 100, 300, 100);
        chatPath.quadraticCurveTo(450, 100, 450, 200);
        chatPath.quadraticCurveTo(450, 300, 250, 300);

        chatPath.quadraticCurveTo(250, 350, 150, 350);
        chatPath.quadraticCurveTo(200, 350, 200, 300);
        //紫色
        ctx.strokeStyle = "#ff00ff";

        ctx.stroke(chatPath);
        ctx.fillStyle = "rgba(255,200,200,.3)"
        ctx.fill(newHeart);
        // #endregion


        //创建一条拆线
        var polyLine = new Path2D("M10 10 h 80 v 80 h -80 z")
        ctx.strokeStyle = "rgba(0,0,255)";
        ctx.stroke(polyLine);

        ctx.fillStyle = "rgba(200,200,255,1)";

        ctx.fillRect(280, 180, 40, 40);
    </script>
</body>

ctx.strokeStyle = “red”;
ctx.strokeStyle = “#ff00ff”;
ctx.fillStyle = “rgba(255,200,200,.3)”;
颜色设置要放在画之前。注意线段和填充的区别。

线性渐变和径向渐变

线性渐变

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        let linearGradient = ctx.createLinearGradient(100, 200, 400, 500);
        linearGradient.addColorStop(0, "red");
        linearGradient.addColorStop(0.3, "#ffcccc");
        linearGradient.addColorStop(1, "blue");
        ctx.fillStyle = linearGradient;
        ctx.fillRect(100, 200, 300, 300);


        let index = 0;

        function render() {
            ctx.clearRect(0, 0, 600, 400);
            index += 0.01;

            if (index > 1) {
                index = 0;
            }

            let linearGradient = ctx.createLinearGradient(100, 200, 400, 500);
            linearGradient.addColorStop(0, "red");
            linearGradient.addColorStop(index, "#ffcccc");
            linearGradient.addColorStop(1, "blue");
            ctx.fillStyle = linearGradient;
            ctx.fillRect(100, 200, 300, 300);
            requestAnimationFrame(render);
        }


        requestAnimationFrame(render);

    </script>
</body>

createLinearGradient
①创建线性渐变对象ctx.createLinearGradient(渐变起点X, 渐变起点Y, 渐变终点X, 渐变终点Y);

②设置渐变过程addColorStop(0-1渐变比例, “颜色”); 可以多设

③把渐变对象赋值给fillStyle.

径向渐变

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        let radiaGradient = ctx.createRadialGradient(300, 200, 0, 300, 200, 100);

        radiaGradient.addColorStop(0, 'red');
        radiaGradient.addColorStop(0.3, '#ffcccc');
        radiaGradient.addColorStop(1, 'blue');

        ctx.fillStyle = radiaGradient;
        ctx.fillRect(0, 0, 600, 400);


    </script>
</body>

createRadialGradient
它有两个点,从第一个点向第二个点辐射的过程叫径向渐变。就是两个圆之间的径向渐变。

①创建线性渐变对象ctx.createRadialGradient(中心点X, 中心点Y, 半径,中心点X, 中心点Y,半径);

②设置渐变过程addColorStop(0-1渐变比例, “颜色”); 可以多设

③把渐变对象赋值给fillStyle.

径向渐变模式3D小球

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        let radialGradient = ctx.createRadialGradient(250, 150, 10, 300, 200, 100);

        radialGradient.addColorStop(0, "#ffcccc");
        radialGradient.addColorStop(1, "red");
        ctx.fillStyle = radialGradient;

        ctx.arc(300, 200, 100, 0, Math.PI * 2);
        ctx.fill();

    </script>
</body>

圆锥渐变

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");
        var ctx = c1.getContext('2d');

        //圆锥渐变createConicGradient(角度,位置X,位置Y)
        let conicGradient = ctx.createConicGradient(Math.PI / 4, 300, 200);

        conicGradient.addColorStop(0, "red");
        conicGradient.addColorStop(0.5, "yellow");
        conicGradient.addColorStop(1, "blue");
        ctx.fillStyle = conicGradient;

        ctx.fillRect(0, 0, 600, 400);
    </script>
</body>

createConicGradient
它有两个点,从第一个点向第二个点辐射的过程叫径向渐变。就是两个圆之间的径向渐变。

①创建线性渐变对象ctx.createConicGradient(角度,位置X,位置Y);

②设置渐变过程addColorStop(0-1渐变比例, “颜色”); 可以多设

③把渐变对象赋值给fillStyle.

pattern模式

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");
        var ctx = c1.getContext('2d');

        //创建图案样式pattern
        var img = new Image();
        img.src = "./imgs/money.png";


        img.onload = function () {
            //创建图案对象createPattern(图片对象(可以是image对象,也可以是canvas对象)重复方式repeat,no-repeat,repeat-x,repeat-y)
            var pattern = ctx.createPattern(img, "repeat-y");
            ctx.fillStyle = pattern;
            ctx.fillRect(0, 0, 600, 400);
        }

    </script>
</body>

①创建图案样式pattern,new Image();
②创建图案对象createPattern,createPattern(图片对象,重复方式)
③把图案对象赋值给fillStyle.

线条样式

线条样式

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");


        ctx.moveTo(290, 150);
        ctx.lineTo(300, 200);
        ctx.lineTo(310, 150);

        //设置线条样式,默认1px
        ctx.lineWidth = 40;
        //设置线条端点样式,butt平齐,round半圆,正方形:square
        ctx.lineCap = "round";

        //设置2个线段连接处的样式,mitter处侧相连的角,,round角被磨圆了,bevel
        ctx.lineJoin = "mitter";
        //对斜接面进行限制
        ctx.miterLimit = 5;

        ctx.stroke();
    </script>
</body>

lineWidth 设置线条样式,默认1px
lineCap 设置线条端点样式,butt平齐,round半圆,正方形:square
lineJoin 设置2个线段连接处的样式,mitter处侧相连的角,,round角被磨圆了,bevel
miterLimit 对斜接面进行限制

虚线设置

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");
        let index = 0;

        function render() {
            ctx.clearRect(0, 0, 600, 400);
            index++;

            if (index > 400) {
                index = 0;
            }

            ctx.moveTo(150, 150);
            ctx.lineTo(300, 200);
            ctx.lineTo(450, 150);

            //设置线条样式,默认1px
            ctx.lineWidth = 1;
            //设置线条端点样式,butt平齐,round半圆,正方形:square
            ctx.lineCap = "square";

            //设置2个线段连接处的样式,mitter处侧相连的角,,round角被磨圆了,bevel
            ctx.lineJoin = "mitter";
            //对斜接面进行限制
            ctx.miterLimit = 5;

            //设置虚线
            ctx.setLineDash([40, 20]);
            ctx.lineDashOffset = index;

            ctx.stroke();
            requestAnimationFrame(render);
        }

        render();

    </script>
</body>

setLineDash([40, 20]);设置虚线 数组两个参数是虚线的实线和虚线的空白长度。

阴影设置

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //heart
        // #region
        var newHeart = new Path2D();

        newHeart.moveTo(300, 200);
        //两个控制点,一个终点
        newHeart.bezierCurveTo(350, 150, 400, 200, 300, 250);
        newHeart.bezierCurveTo(200, 200, 250, 150, 300, 200);


        // #endregion

        //chat
        // #region
        var chatPath = new Path2D();

        chatPath.moveTo(200, 300);

        chatPath.quadraticCurveTo(150, 300, 150, 200);
        chatPath.quadraticCurveTo(150, 100, 300, 100);
        chatPath.quadraticCurveTo(450, 100, 450, 200);
        chatPath.quadraticCurveTo(450, 300, 250, 300);

        chatPath.quadraticCurveTo(250, 350, 150, 350);
        chatPath.quadraticCurveTo(200, 350, 200, 300);

        //设置阴影
        ctx.shadowOffsetX = 10;
        ctx.shadowOffsetY = 10;
        ctx.shadowBlur = 5;
        ctx.shadowColor = "rgba(255,100,100,1)";

        ctx.stroke(newHeart);
        ctx.fill(newHeart);
        ctx.stroke(chatPath);

        // #endregion


        //创建一条拆线
        var polyLine = new Path2D("M10 10 h 80 v 80 h -80 z")
        ctx.stroke(polyLine);
    </script>

//设置阴影
ctx.shadowOffsetX = 10; 偏移
ctx.shadowOffsetY = 10;偏移
ctx.shadowBlur = 5; 模糊度
ctx.shadowColor = “rgba(255,100,100,1)”; 阴影颜色

绘制图片

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>
        var c1 = document.getElementById('c1');

        var ctx = c1.getContext('2d');

        let img = new Image();
        img.src = "./imgs/girl.webp";
        img.onload = function () {
            //第一种绘制图片的方式,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置;
            // ctx.drawImage(img, 0, 0);
            //第二种绘制图片,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置,4将图片缩放到对应的宽度,5将图片缩放到对应的高度
            // ctx.drawImage(img, 0, 0, 600, 400);
            //第三种绘制图片的方式,Img参数后面的四个参数分别为源图片上要裁剪的起点位置和矩形宽高,后面四个参数分别为画布的位置和要渲染的矩形宽高。
            ctx.drawImage(img, 640, 0, 1280, 720, 0, 0, 600, 400);
        }
    </script>
</body>

//第一种绘制图片的方式,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置;
// ctx.drawImage(img, 0, 0);
//第二种绘制图片,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置,4将图片缩放到对应的宽度,5将图片缩放到对应的高度
// ctx.drawImage(img, 0, 0, 600, 400);
//第三种绘制图片的方式,Img参数后面的四个参数分别为源图片上要裁剪的起点位置和矩形宽高,后面四个参数分别为画布的位置和要渲染的矩形宽高。
ctx.drawImage(img, 640, 0, 1280, 720, 0, 0, 600, 400);

绘制视频和叠加水印

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <video src="./imgs/mov_bbb.mp4" controls></video>

    <button id="btn">播放/暂停</button>

    <script>
        var c1 = document.getElementById("c1");

        if (!c1.getContext) {
            console.log("plase relogin");
        }

        var ctx = c1.getContext("2d");

        var video = document.querySelector("video");

        let btn = document.querySelector("#btn");
        btn.onclick = function () {
            if (video.paused) {
                video.play();
                render();
            } else {
                video.pause();
            }
        };

        let img = new Image();
        img.src = "./imgs/logo.png";

        function render() {
            ctx.drawImage(video, 0, 0, 600, 400);
            ctx.drawImage(img, 400, 350, 200, 50);
            requestAnimationFrame(render);
        }

    </script>
</body>

文字绘制

在这里插入图片描述

<body>

    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //文字大小/字体
        ctx.font = "100px Microsoft YaHei";

        ctx.strokeStyle = "#ff0000";

        //填充渲染文字
        // fillText(文本,文本的起点X,文本的起点Y,绘制文字最大的宽度)
        // ctx.fillText("hello", 300, 200, 100);


        //文本对齐选项textAlign,start(默认),end,left,right,center
        ctx.textAlign = "center";
        //文本基线对齐,textBaseline,top,bottom,alphabetic,middle
        ctx.textBaseline = "middle";

        //文本的方向
        ctx.direction = "rtl";

        //预测量文本宽度
        let text = ctx.measureText("Hello!");
        console.log(text);

        ctx.strokeText("Hello!", 300, 200);


        ctx.arc(300, 200, 5, 0, 2 * Math.PI);
        ctx.fill();
    </script>
</body>

//填充渲染文字
// fillText(文本,文本的起点X,文本的起点Y,绘制文字最大的宽度)

//文本对齐选项textAlign,start(默认),end,left,right,center

//文本基线对齐,textBaseline,top,bottom,alphabetic,middle

//文本的方向
ctx.direction = “rtl”;

//预测量文本宽度
let text = ctx.measureText(“Hello!”);

变换

translate

在这里插入图片描述

<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>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //绘制图形
        //位移,translate,位移坐标系,每次位移都是相对当前位置。
        ctx.translate(100, 100);
        ctx.fillRect(0, 0, 50, 50);
        ctx.translate(100, 100);
        ctx.fillRect(0, 0, 50, 50);


    </script>
</body>

//位移,translate,位移坐标系,每次位移都是相对当前位置。
ctx.translate(100, 100);

scale

在这里插入图片描述

<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>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //scale拉伸坐标系,横向,纵向。
        ctx.scale(5, 2);

        ctx.fillRect(0, 0, 50, 50);



    </script>
</body>

//scale拉伸坐标系,横向,纵向。
ctx.scale(5, 2);

rotate

在这里插入图片描述

<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>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //旋转rotate
        ctx.rotate(Math.PI / 6);
        ctx.fillRect(0, 0, 500, 50);


    </script>
</body>

//旋转rotate
ctx.rotate(Math.PI / 6);

混合使用

在这里插入图片描述

<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>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.translate(300, 200);
        ctx.rotate(Math.PI / 4);
        ctx.scale(2, 1);
        ctx.fillRect(-250, -25, 500, 50);


    </script>
</body>

矩阵transform

位移

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        ctx.transform(1, 0, 0, 1, 100, 100);
        ctx.fillRect(0, 0, 50, 50);


    </script>
</body>

ctx.transform(1, 0, 0, 1, 100, 100);

旋转

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>

        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //旋转rotate
        ctx.transform(1, 1, -1, 1, 50, 0);
        ctx.fillRect(0, 0, 500, 50);


    </script>
</body>

ctx.transform(1, 1, -1, 1, 50, 0);

合成图像

在这里插入图片描述

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");


        ctx.fillStyle = "rgba(0,0,255,1)";
        ctx.fillRect(300, 200, 100, 100);
        ctx.globalCompositeOperation = "source-in";
        ctx.fillStyle = "rgba(255,0,0,1)";
        ctx.fillRect(250, 150, 100, 100);
    </script>
</body>

// ctx.globalCompositeOperation = “source-in”;

合成图像实现刮刮卡

在这里插入图片描述

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #ggk {
            width: 600px;
            height: 400px;
            font-size: 30px;
            font-weight: 900;
            text-align: center;
            line-height: 400px;
            overflow: hidden;
            position: absolute;
            left: 0;
            right: 0;
        }

        canvas {
            position: absolute;
            left: 0;
            right: 0;
            z-index: 10;
        }
    </style>
</head>

<body>
    <div id="ggk">谢谢惠顾</div>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");


        let img = new Image();
        img.src = "./imgs/m2.png";
        img.onload = function () {
            ctx.drawImage(img, 0, 0, 600, 400);
        }

        var isDarw = false;

        c1.onmousedown = function () {
            isDarw = true;
        }

        c1.onmouseup = function () {
            isDarw = false;
        }

        c1.onmousemove = function (e) {
            if (isDarw) {
                let x = e.pageX;
                let y = e.pageY;

                ctx.globalCompositeOperation = "destination-out";

                ctx.arc(x, y, 20, 0, Math.PI * 2);
                ctx.fill();
            }
        }

        let random = Math.random();
        if (random < 0.1) {
            var ggkDiv = document.querySelector("#ggk");
            ggkDiv.innerHTML = "恭喜您获得IPHONE14PRO大奖!";
        }
    </script>
</body>


裁剪路径

在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //heart
        // #region
        var newHeart = new Path2D();

        newHeart.moveTo(300, 200);
        //两个控制点,一个终点
        newHeart.bezierCurveTo(350, 150, 400, 200, 300, 250);
        newHeart.bezierCurveTo(200, 200, 250, 150, 300, 200);

        ctx.stroke(newHeart);
        ctx.fill(newHeart);
        // #endregion


        //chat
        // #region
        var chatPath = new Path2D();

        chatPath.moveTo(200, 300);

        chatPath.quadraticCurveTo(150, 300, 150, 200);
        chatPath.quadraticCurveTo(150, 100, 300, 100);
        chatPath.quadraticCurveTo(450, 100, 450, 200);
        chatPath.quadraticCurveTo(450, 300, 250, 300);

        chatPath.quadraticCurveTo(250, 350, 150, 350);
        chatPath.quadraticCurveTo(200, 350, 200, 300);

        ctx.clip(chatPath);

        ctx.stroke(chatPath);

        // #endregion
        let img = new Image();
        img.src = "./imgs/girl.webp";
        img.onload = function () {
            //第二种绘制图片,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置,4将图片缩放到对应的宽度,5将图片缩放到对应的高度
            // ctx.drawImage(img, 0, 0, 600, 400);

            ctx.drawImage(img, 0, 0, 600, 400);
            ctx.lineWidth = 20;
            ctx.stroke(chatPath);
        }

    </script>
</body>

ctx.clip(chatPath);

状态的保存与恢复

在这里插入图片描述

<body>
    <canvas id="c1" width="800" height="800"></canvas>
    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");


        ctx.fillStyle = "red";
        ctx.fillRect(0, 0, 100, 100);
        ctx.save();

        ctx.fillStyle = "blue";
        ctx.fillRect(100, 100, 100, 100);
        ctx.save();

        ctx.fillStyle = "yellow";
        ctx.fillRect(200, 200, 100, 100);
        ctx.save();

        ctx.fillStyle = "green";
        ctx.fillRect(300, 300, 100, 100);
        ctx.save();

        ctx.restore();
        ctx.fillRect(400, 400, 100, 100);

        ctx.restore();
        ctx.fillRect(500, 500, 100, 100);

        ctx.restore();
        ctx.fillRect(600, 600, 100, 100);

        ctx.restore();
        ctx.fillRect(700, 700, 100, 100);

        ctx.restore();
        ctx.fillRect(800, 800, 100, 100);
    </script>
</body>

ctx.save();保存
ctx.restore();恢复

像素操作

在这里插入图片描述
这里会遇到跨域问题,解决方法为用vscod的一个插件
在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400"></canvas>
    <script>
        var c1 = document.getElementById('c1');

        var ctx = c1.getContext('2d');

        let img = new Image();
        img.src = "./imgs/girl.webp";
        img.onload = function () {
            //第一种绘制图片的方式,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置;
            // ctx.drawImage(img, 0, 0);
            //第二种绘制图片,参数1为图片对象,参数2为将图片渲染到画布的水平位置,参数3将图片渲染到画布的垂直位置,4将图片缩放到对应的宽度,5将图片缩放到对应的高度
            // ctx.drawImage(img, 0, 0, 600, 400);
            //第三种绘制图片的方式,Img参数后面的四个参数分别为源图片上要裁剪的起点位置和矩形宽高,后面四个参数分别为画布的位置和要渲染的矩形宽高。
            ctx.drawImage(img, 0, 0, 600, 400);


            //获取象素数据
            let imageData = ctx.getImageData(0, 0, 600, 400);
            console.log(imageData);

            // 循环修改数据
            for (let i = 0; i < imageData.data.length; i += 4) {
                //计算出当前像素的平均值
                let avg = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3;

                imageData.data[i] = avg;
                imageData.data[i + 1] = avg;
                imageData.data[i + 2] = avg;
                imageData.data[i + 3] = 255;
            }

            // for (let i = 0; i < imageData.data.length; i += 4) {
            //     imageData.data[i] = 255 - imageData.data[i];
            //     imageData.data[i + 1] = 255 - imageData.data[i + 1];
            //     imageData.data[i + 2] = 255 - imageData.data[i + 2];
            //     imageData.data[i + 3] = 255;
            // }

            //将修改后的数据重新渲染到画布上
            ctx.putImageData(imageData, 0, 0);
            // ctx.putImageData(imageData, 0, 0, 300, 200, 200, 200);
        }
    </script>
</body>

核心代码

 //获取象素数据
            let imageData = ctx.getImageData(0, 0, 600, 400);

 //将修改后的数据重新渲染到画布上
            ctx.putImageData(imageData, 0, 0);

封装绘制和物体

在这里插入图片描述
在这里插入图片描述

<body>
    <canvas id="c1" width="600" height="400">
        当前浏览器不支持canvas,请下载最新的浏览器
        <a href="https://www.google.cn/intl/zh-CN/chrome/">立即下载</a>
    </canvas>

    <script>
        // 1. 找到画布
        var c1 = document.getElementById("c1");

        // 判断是否有getContext
        if (!c1.getContext) {
            console.log("当前浏览器不支持canvas,请下载最新的浏览器");
        }
        // 2. 获取画笔,上下文对象
        var ctx = c1.getContext("2d");

        class Heart {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.color = "red";
                this.isIn = false;
                this.eventMapList = {
                    hover: [],
                    leave: [],
                };

                c1.onmousemove = (e) => {
                    let x = e.offsetX;
                    let y = e.offsetY;
                    this.isIn = ctx.isPointInPath(this.heartPath, x, y);
                    if (this.isIn) {
                        this.eventMapList.hover.forEach((item) => {
                            item();
                        });
                    } else {
                        this.eventMapList.leave.forEach((item) => {
                            item();
                        });
                    }
                };
            }

            onHover(fn) {
                this.eventMapList.hover.push(fn);
            }

            onLeave(fn) {
                this.eventMapList.leave.push(fn);
            }



            draw() {
                this.heartPath = new Path2D();
                // 起点
                this.heartPath.moveTo(this.x, this.y);
                // 2个控制点、1个终点
                this.heartPath.bezierCurveTo(
                    this.x + 50,
                    this.y - 50,
                    this.x + 100,
                    this.y,
                    this.x,
                    this.y + 50
                );
                this.heartPath.bezierCurveTo(
                    this.x - 100,
                    this.y,
                    this.x - 50,
                    this.y - 50,
                    this.x,
                    this.y
                );
                ctx.save();
                ctx.fillStyle = this.color;
                ctx.fill(this.heartPath);

                ctx.restore();
            }
        }


        let heart = new Heart(100, 100);

        heart.onHover(() => {
            heart.color = "blue";
            // heart.draw();
        });
        heart.onLeave(() => {
            heart.color = "red";
            // heart.draw();
        });

        function render() {
            ctx.clearRect(0, 0, c1.width, c1.height);
            heart.draw();
            requestAnimationFrame(render);
        }
        render();
    </script>
</body>

签名画板

在这里插入图片描述

<body>
    <canvas id="c1" width="800" height="600"></canvas>
    <hr>
    <button id="boldBtn" type="button">粗线条</button>
    <button id="thinBtn" type="button">细线条</button>
    <button id="saveBtn" type="button">保存签名</button>
    <input type="color" name="" id="color" value="" />
    <button class="clearBtn">橡皮擦</button>
    <button id="nullBtn">清空画布</button>

    <script>
        var c1 = document.getElementById("c1");

        var ctx = c1.getContext("2d");

        //连接处圆润
        ctx.lineJoin = "round";
        //开端和结束也是圆的
        ctx.lineCap = "round";
        // 设置画笔的粗细
        var boldBtn = document.querySelector('#boldBtn')

        var thinBtn = document.querySelector('#thinBtn')
        //画笔颜色
        var inputColor = document.querySelector('#color')
        // 保存签名
        var saveBtn = document.querySelector('#saveBtn')
        // 橡皮擦按钮
        var clearBtn = document.querySelector('.clearBtn');
        // 清空画布
        var nullBtn = document.querySelector('#nullBtn');

        //设置是否允许绘制
        var isDraw = false;

        c1.onmousedown = function () {
            isDraw = true;
            ctx.beginPath();

            var x = event.pageX - c1.offsetLeft;
            var y = event.pageY - c1.offsetTop;

            ctx.moveTo(x, y);
        }

        c1.onmouseleave = function () {
            isDraw = false;
            ctx.closePath();
        }

        c1.onmouseup = function () {
            isDraw = false;
            ctx.closePath();
        }

        c1.onmousemove = function () {
            if (isDraw) {
                var x = event.pageX - c1.offsetLeft;
                var y = event.pageY - c1.offsetTop;

                ctx.lineTo(x, y);
                ctx.stroke();
            }
        }

        boldBtn.onclick = function () {
            ctx.globalCompositeOperation = "source-over";
            ctx.lineWidth = 20;
            boldBtn.classList.add('active');
            thinBtn.classList.remove("active");
            clearBtn.classList.remove("active");
        }

        thinBtn.onclick = function () {
            ctx.globalCompositeOperation = "source-over";
            ctx.lineWidth = 2;
            thinBtn.classList.add("active");
            boldBtn.classList.remove("active");
            clearBtn.classList.remove("active");
        }


        clearBtn.onclick = function () {
            ctx.globalCompositeOperation = "destination-out";
            ctx.lineWidth = 30;
            clearBtn.classList.add("active");
            boldBtn.classList.remove("active");
            thinBtn.classList.remove("active");
        }

        nullBtn.onclick = function () {
            ctx.clearRect(0, 0, 800, 600);
        }

        saveBtn.onclick = function () {
            var urlData = c1.toDataURL();

            // var img = new Image();
            // img.src = urlData;
            // document.body.appendChild(img);

            var downloadA = document.createElement("a");
            downloadA.setAttribute("download", "我的签名");
            downloadA.href = urlData;
            downloadA.click();
        }


        inputColor.onclick = function () {
            console.log(inputColor.value);
            ctx.strokeStyle = inputColor.value;
        }

    </script>
</body>

时钟

在这里插入图片描述

<body>
    <canvas id="c1" width="800" height="600"></canvas>
    <script>
        var c1 = document.querySelector("#c1");
        var ctx = c1.getContext("2d");


        function render() {

            ctx.clearRect(0, 0, 800, 600);
            //存档,保存当前坐标位置和上下文对象的状态
            ctx.save();
            ctx.translate(400, 300);
            ctx.rotate(-Math.PI / 2);

            ctx.save();
            for (let i = 0; i < 12; i++) {
                //绘制小时的刻度
                ctx.beginPath();
                ctx.moveTo(170, 0);
                ctx.lineTo(190, 0);
                ctx.lineWidth = 8;
                ctx.strokeStyle = "gray";
                ctx.stroke();
                ctx.closePath();
                ctx.rotate((2 * Math.PI) / 12);
            }

            ctx.restore();
            ctx.save();
            for (let i = 0; i < 60; i++) {
                //绘制分钟的刻度
                ctx.beginPath();
                ctx.moveTo(180, 0);
                ctx.lineTo(190, 0);
                ctx.lineWidth = 2;
                ctx.strokeStyle = "gray";
                ctx.stroke();
                ctx.closePath();
                ctx.rotate((2 * Math.PI) / 60);
            }

            ctx.restore();
            ctx.save();

            //获取当前时间
            var time = new Date();
            var hour = time.getHours();
            var min = time.getMinutes();
            var sec = time.getSeconds();
            hour = hour > 12 ? hour - 12 : hour;

            //绘制秒针
            ctx.rotate(((2 * Math.PI) / 60) * sec);
            ctx.beginPath();
            ctx.moveTo(-30, 0);
            ctx.lineTo(190, 0);
            ctx.lineWidth = 2;
            ctx.strokeStyle = "red";
            ctx.stroke();
            ctx.closePath();
            ctx.restore()
            ctx.save();

            //绘制分针
            ctx.rotate(((2 * Math.PI) / 60) * min + ((2 * Math.PI) / 60 / 60) * sec);
            ctx.beginPath();
            ctx.moveTo(-20, 0);
            ctx.lineTo(130, 0);
            ctx.lineWidth = 4;
            ctx.strokeStyle = "#888";
            ctx.stroke();
            ctx.closePath();
            ctx.restore()
            ctx.save();

            //绘制时针
            ctx.rotate(((2 * Math.PI) / 12) * hour +
                ((2 * Math.PI) / 12 / 60) * min +
                ((2 * Math.PI) / 60 / 60) * sec);
            ctx.beginPath();
            ctx.moveTo(-50, 0);
            ctx.lineTo(110, 0);
            ctx.lineWidth = 8;
            ctx.strokeStyle = "blue";
            ctx.stroke();
            ctx.closePath();
            ctx.restore()
            ctx.restore()

            requestAnimationFrame(render);
        }

        render();

    </script>
</body>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值