canvas

HTML 画布_w3cschoolHTML5标签用于绘制图像(通过脚本,通常是JavaScript)。不过,元素本身并没有绘制能力(它仅仅是图形的容器)-您必须使用脚本来完成实际的绘图任务。getContext()方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性。本手册提供完整的getContext("2d")对象的属性和方法,可用于在画布上绘制文本、线条、矩形、圆形等等。_来自HTML 参考手册,w3cschool编程狮。icon-default.png?t=N7T8https://www.w3cschool.cn/htmltags/ref-canvas.html

<canvas> 元素本身并没有绘制能力(它仅仅是图形的容器) - 必须使用脚本来完成实际的绘图任务。

getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性

颜色、样式和阴影

属性描述
fillStyle设置或返回用于填充绘画的颜色、渐变或模式。
strokeStyle设置或返回用于笔触的颜色、渐变或模式。
shadowColor设置或返回用于阴影的颜色。
shadowBlur设置或返回用于阴影的模糊级别。
shadowOffsetX设置或返回阴影与形状的水平距离。
shadowOffsetY设置或返回阴影与形状的垂直距离。

渐变

方法描述
createLinearGradient()创建线性渐变(用在画布内容上)。
createPattern()在指定的方向上重复指定的元素。
createRadialGradient()创建放射状/环形的渐变(用在画布内容上)。
addColorStop()规定渐变对象中的颜色和停止位置。

线条样式

属性描述
lineCap设置或返回线条的结束端点样式。
lineJoin设置或返回两条线相交时,所创建的拐角类型。
lineWidth设置或返回当前的线条宽度。
miterLimit设置或返回最大斜接长度。

矩形

方法描述
rect()创建矩形。
fillRect()绘制"被填充"的矩形。
strokeRect()绘制矩形(无填充)。
clearRect()清空 / 在给定的矩形内清除指定的像素。

路径

方法描述
fill()填充当前绘图(路径)。
stroke()绘制已定义的路径。
beginPath()起始一条路径,或重置当前路径。
moveTo()把路径移动到画布中的指定点,不创建线条。绘制不连续的路径
closePath()创建从当前点回到起始点的路径。
lineTo()添加一个新点,然后在画布中创建从该点到最后指定点的线条。
clip()从原始画布剪切任意形状和尺寸的区域。
quadraticCurveTo()创建二次贝塞尔曲线。
bezierCurveTo()创建三次贝塞尔曲线。
arc()创建弧/曲线(用于创建圆形或部分圆)。
arcTo()创建两切线之间的弧/曲线。
isPointInPath()如果指定的点位于当前路径中,则返回 true,否则返回 false。

转换

方法描述
scale()缩放当前绘图至更大或更小。
rotate()旋转当前绘图。
translate()重新映射画布上的 (0,0) 位置。
transform()替换绘图的当前转换矩阵。
setTransform()将当前转换重置为单位矩阵。然后运行 transform()。

文本

属性描述
font设置或返回文本内容的当前字体属性。
textAlign设置或返回文本内容的当前对齐方式。
textBaseline设置或返回在绘制文本时使用的当前文本基线。

direction

设置文本方向

measureText

预测量文本宽度,例:let text = ctx.measureText('Canvas!');  console.log(text);

方法描述
fillText()在画布上绘制"被填充的"文本。
strokeText()在画布上绘制文本(无填充)。
measureText()返回包含指定文本宽度的对象。

图像绘制

方法描述
drawImage()向画布上绘制图像、画布或视频。

像素操作

属性描述
width返回 ImageData 对象的宽度。
height返回 ImageData 对象的高度。
data返回一个对象,其包含指定的 ImageData 对象的图像数据。

方法描述
createImageData()创建新的、空白的 ImageData 对象。
getImageData()返回 ImageData 对象,该对象为画布上指定的矩形复制像素数据。
putImageData()把图像数据(从指定的 ImageData 对象)放回画布上。

合成

属性描述
globalAlpha设置或返回绘图的当前 alpha 或透明值。
globalCompositeOperation设置或返回新图像如何绘制到已有的图像上。

其他

方法描述
save()保存当前环境的状态。
restore()返回之前保存过的路径状态和属性。
createEvent()创建新的 Event 对象
getContext()获得用于在画布上绘图的对象
toDataURL()导出在 canvas 元素上绘制的图像

clearRect(x, y, 宽, 高)

清空画布

globalCompositeOperation = 'destination-out'

删除 / 橡皮擦

例:

 1.创建 Canvas 元素:

<canvas id="myCanvas" width="500" height="300"></canvas>

2.获取 Canvas 上下文对象:

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

3.绘制填充矩形

方法一:

ctx.fillRect(50, 50, 100, 100); // (位置X 位置y 宽度 高度)

 方法二:拆分写法

ctx.rect(50, 50, 100, 100)
ctx.fill()

 4.1.填充颜色

ctx.fillStyle = 'red'; 

 4.2路径颜色

ctx.strokeStyle = "red"

5.绘制路径矩形

方法一:

 ctx.strokeRect(50, 50, 100, 100);// (位置X 位置y 宽度 高度)

方法二:拆分写法

ctx.rect(50, 50, 100, 100)
ctx.stroke()

6.清空画布:

ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空整个画布

7.绘制文本:参数(文本,x,y,最大宽度)

        ctx.font = '100px Microsoft YaHei'; // 设置字体样式
        ctx.fillText('Hello, Canvas!', 100, 200, 100);//填充文本
        ctx.strokeText('Hello, Canvas!', 100, 200, 100);//路径文本
        // 文本对齐,textAlign--start(默认),end,left,right,center
        ctx.textAlign = 'left';
        //基线对齐,textBaseline--top,bottom,elphabetic,middle
        ctx.textBaseline = 'middle'

 例:设置文本和圆向左对齐

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.font = '100px Microsoft YaHei';
        // 文本对齐选项textAlign,start(默认),end,left,right,center
        ctx.textAlign = 'left';
        ctx.strokeText('Canvas!', 200, 200);
        ctx.arc(200, 200, 5, 0, Math.PI * 2);
        ctx.fill();

8.绘制图像:

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        //获取图片
        let img = new Image();
        img.src = './img/1.webp';
        //加载完毕的时候执行绘制
        img.onload = function() {
            //第一种绘制方式,参数一为图片,参数二为坐标x,参数三为坐标y
            ctx.drawImage(img, 0, 0);
            //第二种绘制方式,参数一为图片,参数二为坐标x,参数三为坐标y,参数四为绘制宽度,
            //参数五为绘制高度
            ctx.drawImage(img, 0, 0, 100, 100);
            //第三种绘制方式,参数一为图片,参数二为裁剪的起始点x,参数三为裁剪的起始点y,
            //参数四为裁剪的宽度,参数五为裁剪的高度,参数六为绘制宽度,参数七为绘制高度
            ctx.drawImage(img, 100, 100, 100, 100, 10, 10, 100, 100);
        }

8-1.绘制视频

    <canvas id="c1" width="600" height="400"></canvas>
    <video src="./img/mov.mp4" controls></video>
    <button id="btn">播放/暂停</button>
    <script>
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        var video = document.querySelector('video');
        //获取视频播放/暂停按钮
        var btn = document.getElementById('btn');
        btn.onclick = function() {
            video.play()//播放
            render() //调用请求动画帧
        }

        function render() {
            ctx.drawImage(video, 0, 0, 600, 400);//绘制视频
            requestAnimationFrame(render);
        }
    </script>

 8-1-1.给视频打码/添加水印

    <canvas id="c1" width="600" height="400"></canvas>
    <video src="./img/mov.mp4" controls></video>
    <button id="btn">播放/暂停</button>
    <script>
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        var video = document.querySelector('video');
        var btn = document.getElementById('btn');
        btn.onclick = function() {
            video.play()
            render()
        }

        var img = new Image();
        img.src = './img/1.webp';

        function render() {
            ctx.drawImage(video, 0, 0, 600, 400);
            ctx.drawImage(img, 500, 350, 100, 50);//绘制水印图像
            requestAnimationFrame(render);
        }
    </script>

9.设置样式和属性:

  • ctx.strokeStyle:设置描边 / 路径颜色
  • ctx.fillStyle:设置填充颜色
  • ctx.lineWidth:设置线条宽度
  • ctx.globalAlpha:设置全局透明度 
  • ctx.fillStyle:"rgba(255,200,200,0.3)";透明度

10.渐变

10-1线性渐变
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        let linearGradient = ctx.createLinearGradient(100, 200, 400, 500);
        linearGradient.addColorStop(0, 'red');
        linearGradient.addColorStop(1, 'blue');
        ctx.fillStyle = linearGradient;
        ctx.fillRect(100, 200, 300, 300)
10-2径向 / 圆形 渐变
        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(1, 'blue');
        ctx.fillStyle = radiaGradient
        ctx.fillRect(0, 0, 600, 400)
案例:模拟3D球
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        let radiaGradient = ctx.createRadialGradient(250, 150, 10, 300, 200, 100);
        radiaGradient.addColorStop(0, '#fff');
        radiaGradient.addColorStop(1, 'red');
        ctx.fillStyle = radiaGradient
        ctx.arc(300, 200, 100, 0, Math.PI * 2);
        ctx.fill()
 10-3圆锥 渐变

createRadialGradient(角度,x,y)创建一个锥形渐变对象

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        let coneGradient = ctx.createConicGradient(0, 300, 200);
        coneGradient.addColorStop(0, '#fff');
        coneGradient.addColorStop(1, 'red');
        ctx.fillStyle = coneGradient
        ctx.fillRect(0, 0, 600, 400)

11.阴影

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        //设置阴影
        ctx.shadowOffsetX = 8;
        ctx.shadowOffsetY = 8;
        ctx.shadowBlur = 5;
        ctx.shadowColor = 'red'
        ctx.strokeRect(50, 50, 200, 100);

案例:绘制一个矩形

一:填充矩形fillRect(x1, y1, 宽, 高)
        <canvas id="myCanvas"></canvas>
        var c1 = document.getElementById('myCanvas');
        var ctx = c1.getContext('2d');
        ctx.fillRect(10, 20, 200, 100);// (位置X 位置y 宽度 高度)

拆开写法:ctx.fillRect();=ctx.rect();ctx.fill()

ctx.rect(10, 20, 200, 100)
ctx.fill()

二:路径矩形strokeRect(x1, y1, 宽, 高)
        <canvas id="c1"></canvas>
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.strokeRect(100, 100, 200, 100);

拆开写法:ctx.strokeRect();=ctx.rect();ctx.stroke()

ctx.rect(100, 100, 200, 100)
ctx.stroke()

三:动画 / 清除模式clearRect(x1, y1, 宽, 高)
    <canvas id="c1"></canvas>
    <script type="text/javascript">
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.strokeRect(100, 100, 200, 100);
        let h = 0;
        let t1 = setInterval(() => {
            h++;
            ctx.clearRect(0, 0, c1.clientWidth, h);
            if (h > c1.clientHeight) {
                clearInterval(t1);
            }
        }, 10)
    </script>

拆开写法: 开始绘制beginPath(),结束绘制closePath(),可以完成路径的分段

beginPath()起始一条路径,或重置当前路径。
closePath()创建从当前点回到起始点的路径。
<script type="text/javascript">
        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        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 h = 0;
        let t1 = setInterval(() => {
            h++;
            ctx.clearRect(0, 0, c1.clientWidth, h);
            if (h > c1.clientHeight) {
                clearInterval(t1);
            }
        }, 10)
</script>

案例:绘制一个圆

方法一:arc是绘制圆弧的方法,arc(圆心x,圆心y,半径,起始角度,结束角度,逆时针还是顺时针,默认是顺时针false,设置顺时针为true ) ,

Math.PI / 1就是半圆

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.arc(300, 200, 50, 0, Math.PI * 2,true)
        ctx.fill()

 方法二:arcTo()

        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()

案例:绘制一个笑脸

方法一:

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        //绘制大圆圈
        ctx.arc(75, 75, 50, 0, Math.PI * 2)
        ctx.stroke()
        //绘制嘴巴
        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()

 方法二:使用moveTo()绘制一条不连续的路径

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.beginPath();
        ctx.arc(75, 75, 50, 0, Math.PI * 2); //大圆圈
        ctx.moveTo(110, 75);
        ctx.arc(75, 75, 35, 0, Math.PI) //嘴巴
        ctx.moveTo(65, 65);
        ctx.arc(60, 65, 5, 0, Math.PI * 2) //右边的眼睛
        ctx.moveTo(95, 65);
        ctx.arc(90, 65, 5, 0, Math.PI * 2) //右边的眼睛
        ctx.stroke()
        ctx.closePath()

 案例:绘制直线和线段 lineTo(x,y)

绘制一个三角形

        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.closePath()

案例:位移-缩放-旋转

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.translate(100, 100) //位移
        ctx.scale(0.5, 0.5) //缩放
        ctx.rotate(Math.PI / 6) //旋转30度
        ctx.fillRect(0, 0, 100, 100);

案例:变形Transforms

transforms(水平缩放,竖直缩放,水平倾斜偏移,竖直倾斜偏移,水平移动,竖直移动)

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.transform(1, 0, 0, 1, 100, 100)
        ctx.fillRect(0, 0, 300, 50);

案例:合成globalCompositeOperation

  1. source-over: 默认属性,新绘制的图像位于原有内容之上。
  2. source-atop: 新绘制的图像仅覆盖原有内容重叠的部分,并位于原有内容之上。
  3. source-in: 新绘制的图像仅显示与原有内容重叠的部分,其他部分透明。
  4. source-out: 新绘制的图像仅显示不与原有内容重叠的部分,与原有内容重叠的部分透明。
  5. destination-over: 原有内容位于新绘制的图像之上。
  6. destination-atop: 原有内容仅覆盖新绘制的图像重叠的部分,并位于新绘制的图像之上。
  7. destination-in: 原有内容仅显示与新绘制的图像重叠的部分,其他部分透明。
  8. destination-out: 原有内容仅显示不与新绘制的图像重叠的部分,与新绘制的图像重叠的部分透明。
  9. lighter: 新绘制的图像与原有内容叠加,颜色变亮。
  10. copy: 仅显示新绘制的图像,忽略原有内容。
  11. xor: 使用异或操作组合新绘制的图像与原有内容。

 例:显示两个矩形重叠的部分,其他部分透明

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.fillStyle = 'red';
        ctx.fillRect(300, 200, 100, 100);
        ctx.globalCompositeOperation = 'source-in';
        ctx.fillStyle = 'blue';
        ctx.fillRect(250, 150, 100, 100);

 案例:刮刮卡

source-out: 新绘制的图像仅显示不与原有内容重叠的部分,与原有内容重叠的部分透明

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        var img = new Image();
        img.src = './img/1.webp'
        img.onload = function() {
            ctx.drawImage(img, 0, 0, 600, 400);
        }
        var isDrawing = false;
        c1.onmousedown = function(e) {
            isDrawing = true
        }
        c1.onmouseup = function() {
            isDrawing = false
        }
        c1.onmousemove = function(e) {
            if (isDrawing) {
                var x = e.pageX;
                var y = e.pageY;
                ctx.globalCompositeOperation = 'destination-out';
                ctx.arc(x, y, 20, 0, 2 * Math.PI)
                ctx.fill()
            }
        }

 案例:裁剪路径clip( )

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        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)
        ctx.clip(chatPath)
        let img = new Image();
        img.src = './img/12.webp'
        img.onload = function() {
            ctx.drawImage(img, 0, 0, 600, 400)
        }

贝塞尔曲线:

一般用来绘制复杂有规律的图形,

canvas调试二次贝塞尔曲线

Canvas Quadratic Curve Exampleicon-default.png?t=N7T8https://blogs.sitepointstatic.com/examples/tech/canvas-curves/quadratic-curve.html

canvas调试三次贝塞尔曲线

Canvas Bézier Curve Exampleicon-default.png?t=N7T8https://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html

案例:绘制聊天气泡框,

使用二次曲线:quadraticCurveTo(cp1x, cp1y, x, x); cp1x,cp1y为控制点,xy为结束点

        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()

案例:绘制一个心形

使用三次曲线:bezierCurveTo(cp1x, cp1y, cp2x,cp2y,x, x); cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,xy为结束点 

        var c1 = document.getElementById('c1');
        var ctx = c1.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.fillStyle = "#E992B9";
        ctx.fill();
        ctx.closePath();

图案样式pattern

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        //创建图案样式pattern
        var img = new Image();
        img.src = './img/1.webp';
        img.onload = function() {
            //创建图案对象createPattern(图片对象,重复方式repeat,no-repeat ,repeat x,repeat-y)
            var pattern = ctx.createPattern(img, 'no-repeat');
            ctx.fillStyle = pattern;
            ctx.fillRect(0, 0, 600, 350);
        }

path2D封装路径

创建一条折线:字符串写法

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        var polyline = new Path2D('M10 10 h 80 v 80 h -80 z')
        ctx.stroke(polyline)

 封装绘制聊天气泡框路线

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        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)

requestAnimationFrame 函数

requestAnimationFrame 是一个由浏览器提供的用于优化动画效果的方法。它告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。

相比于使用 setTimeoutsetInterval 来实现动画,requestAnimationFrame 具有以下优势:

  1. 浏览器会在适当的时间内执行动画,以确保最佳的性能和流畅度。
  2. 当页面处于非激活状态(例如在后台标签页)时,动画会自动暂停,节省资源。
  3. 能够自动适应设备的刷新率,避免不必要的绘制。
  4. 在支持硬件加速的浏览器中,动画效果会更加流畅。

 语法:

function animate() {
    // 动画更新逻辑
    requestAnimationFrame(animate);
}

// 启动动画
requestAnimationFrame(animate);

案例:渐变矩形动画效果

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        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, 'blue');
            ctx.fillStyle = linearGradient;
            ctx.fillRect(100, 200, 300, 300)
            //请求浏览器在下一帧绘制动画,实现动画效果。不断调用 render 函数,实现动画的连续播放
            requestAnimationFrame(render);
        }
        requestAnimationFrame(render);


状态保存和恢复save() ,restore()

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        ctx.fillStyle = 'yellow'
        ctx.fillRect(10, 10, 100, 100);
        ctx.save() //保存黄色的状态
        ctx.fillStyle = 'red'
        ctx.fillRect(50, 50, 100, 100);
        ctx.fillStyle = 'green'
        ctx.fillRect(100, 100, 100, 100);
        ctx.restore() //恢复/取出黄色的状态,恢复的为上一次保存的状态
        ctx.fillRect(150, 150, 100, 100); //为黄色

像素操作:lmageData (), putImageData()

putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) 

  • imageData: 表示要绘制到画布上的 ImageData 对象。
  • dx 和 dy: 表示将图像数据放置在画布上的位置坐标,即横坐标和纵坐标。
  • dirtyX 和 dirtyY: 表示从 ImageData 对象中提取图像数据的起始位置坐标。
  • dirtyWidth 和 dirtyHeight: 表示从 ImageData 对象中提取图像数据的宽度和高度

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        var img = new Image();
        img.src = './img/12.webp';
        img.onload = function() {
            ctx.drawImage(img, 0, 0, 600, 400);
            let imageData = ctx.getImageData(0, 0, 600, 400);
            //循环修改数据
            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
            }
            //将修改后的数据重新渲染到画布上
            ctx.putImageData(imageData, 0, 0);
        }

封装绘制的物体:

 封装一个爱心图像,鼠标在里面的时候为红色,鼠标不在里面的时候为蓝色

        var c1 = document.getElementById('c1');
        var ctx = c1.getContext('2d');
        class Heart {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.color = "#333";
                //监听鼠标移动
                c1.onmousemove = (e) => {
                    var x = e.offsetX;
                    var y = e.offsetY;
                    var isIn = ctx.isPointInPath(this.heartPath, x, y); //判断鼠标在不在里面
                    if (isIn) {
                        this.color = "red"; //鼠标在里面
                    } else {
                        this.color = "blue"; //鼠标不在里面
                    }
                }
            }
            setPosition(x, y) {
                this.x = x;
                this.y = y;
            }
            draw() {
                this.heartPath = new Path2D()
                this.heartPath.moveTo(this.x, this.y); //起点
                this.heartPath.bezierCurveTo(this.x + 50, this.y - 50, this.x + 100, this.x, this.y, 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)

        function render() {
            ctx.clearRect(0, 0, c1.width, c1.height)
            heart.draw()
            requestAnimationFrame(render)
        }
        render()

制作画笔 / 在线画板:

 

<canvas id="c1" width="600" height="400"></canvas>
<button id="boldBtn">粗线条</button>
<button id="thinBtn">细线条</button>
<button id="save">保存</button>
<button id="clearBtn">橡皮擦</button>
<button id="nullBtn">清空画布</button>
<input id="color" type="color" value="" name=""></input>
<script>
    var c1 = document.getElementById('c1');
    var ctx = c1.getContext('2d');
    //设置画笔连接处圆润
    ctx.lineJoin = 'round';
    //设置画笔开始和结束圆润
    ctx.lineCap = 'round';

    //设置允许绘制的变量
    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();
        }
    };
    //点击粗线条按钮,画笔变粗
    var boldBtn = document.querySelector('#boldBtn');
    boldBtn.onclick = function() {
        //点击线条进行绘制的时候,从橡皮擦的模式回来
        ctx.globalCompositeOperation = 'source-over';
        ctx.lineWidth = 20
    };
    //点击细线条按钮,画笔变细
    var thinBtn = document.querySelector('#thinBtn');
    thinBtn.onclick = function() {
        //点击线条进行绘制的时候,从橡皮擦的模式回来
        ctx.globalCompositeOperation = 'source-over';
        ctx.lineWidth = 0.1
    };
    //选择颜色
    var inputColor = document.querySelector('#color');
    color.onchange = function() {
        ctx.strokeStyle = color.value
    };
    //点击保存
    var saveBtn = document.querySelector('#save');
    saveBtn.onclick = function() {
        //先转换为一个图片地址
        var urlData = c1.toDataURL();
        var img = new Image();
        img.src = urlData;
        document.body.appendChild(img);
        console.log(urlData, '图片地址');

    };

    //点击橡皮擦
    var clearBtn = document.querySelector('#clearBtn');
    clearBtn.onclick = function() {
        ctx.globalCompositeOperation = 'destination-out';
        ctx.lineWidth = 30;
    };

    //点击清空画布
    var nullBtn = document.querySelector('#nullBtn');
    nullBtn.onclick = function() {
        ctx.clearRect(0, 0, 600, 400)
    }
</script>

制作时钟:

    <canvas id="c1" width="800" height="600"></canvas>
    <script>
        var c1 = document.getElementById('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 + 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 + Math.PI / 12 / 60 * min + 2 * Math.PI / 12 / 60 / 60 * sec);
            ctx.beginPath();
            ctx.moveTo(-15, 0);
            ctx.lineTo(110, 0);
            ctx.lineWidth = 8;
            ctx.strokeStyle = '#333';
            ctx.stroke();
            ctx.closePath();
            ctx.restore();
            ctx.restore();
            requestAnimationFrame(render)
        };
        //请求动画帧
        render()
    </script>

案例:利用canvas设置视频封面,用video播放视频然后指定某一帧作为封面图

 <video :src="currentUrl"
  controls :poster="imageShow"
  :autoplay="false" style="width: 100%; height: 100%;"
  ></video>
  <canvas width="640" height="360" style="display: none;"></canvas>
  captureFrame(url, file) {
      const video = document.createElement('video')
      video.src = url
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      video.onloadedmetadata = () => {
        video.currentTime = 3
      }
      video.oncanplay = () => {
        canvas.width = 1160
        canvas.height = 570
        ctx.drawImage(video, 0, 0, 1160, 570)
        Vue.set(file, 'imageShow', canvas.toDataURL('image/png'))
      }
   },
this.captureFrame(jumpUrl, item)

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值