当前位置:   article > 正文

JavaScript的Canvas绘图_绘制从起点(-200,-50)到终点(200,-50)的1像素宽的水平黑色直线,并在其上方输出文

绘制从起点(-200,-50)到终点(200,-50)的1像素宽的水平黑色直线,并在其上方输出文

目录

一、Canvas简介

二、Canvas基本用法

三、填充和描边

四、绘制矩形

五、绘制路径

5.1、绘制线段

5.2、绘制三角形

5.3、绘制圆弧

5.4、绘制贝塞尔曲线

5.5、线条样式

六、绘制文本

七、绘制图像

八、模式

九、使用图像数据

十、阴影


一、Canvas简介

    <canvas>元素是HTML5新增的,一个可以使用脚本(通常为JavaScript)在其中绘制图像的HTML元素。它可以用来制作照片集或者制作简单的动画,甚至可以进行实时视频处理和渲染。

    <canvas>由几组API构成,除了具备基本绘图能力的2D上下文<canvas>还具备一个名为WebGL3D上下文

二、Canvas基本用法

    使用<canvas>元素之前,必须先设置其widthheight属性,指定可以绘图的区域大小。

    出现在开始和结束标签中的内容是后备信息,如果浏览器不支持<canvas>元素,就会显示这些信息。

<canvas id="drawing" width="200" height="200">A drawing of something.</canvas>

    要在这块画布上绘图,需要使用getContext()方法传入参数"2d"取得2D上下文对象

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //更多代码
  6. }

    使用2D绘图上下文提供的方法,可以绘制简单的2D图形,比如矩形、弧线和路径。

    2D上下文的坐标开始于<canvas>元素的左上角,原点坐标是(0,0)。

    所有坐标值都基于这个原点计算,x值越大表示越靠右,y值越大表示越靠下。

三、填充和描边

    2D上下文的两种基本绘图操作是填充和描边。

    填充就是用指定的样式(颜色、渐变或图像)填充图形,fillStyle属性设置填充样式。

    描边就是只在图形的边缘画线,strokeStyle属性设置描边样式。

    这两个属性的值可以是字符串、渐变对象或模式对象,例如:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.strokeStyle = "red";
  6. context.fillStyle = "#0000FF";
  7. }

四、绘制矩形

    与绘制矩形有关的方法包括:

  • fillRect()
  • strokeRect()
  • clearRect()

    这三个方法都能接收4个参数:矩形的x坐标、矩形的y坐标、矩形的宽度和矩形高度。参数单位都是像素。

    示例1

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. //绘制半透明的蓝色矩形
  9. context.fillStyle = "rgba(0, 0, 255, 0.5)";
  10. context.fillRect(30, 30, 50, 50);
  11. }

    示例2

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色描边矩形
  6. context.strokeStyle = "#F00";
  7. context.strokeRect(10, 10, 50, 50);
  8. //绘制半透明的蓝色描边矩形
  9. context.strokeStyle = "rgba(0, 0, 255, 0.5)";
  10. context.strokeRect(30, 30, 50, 50);
  11. }

    示例3

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. //绘制半透明的蓝色描边矩形
  9. context.fillStyle = "rgba(0, 0, 255, 0.5)";
  10. context.fillRect(30, 30, 50, 50);
  11. //在两个矩形重叠的地方清除一个小矩形
  12. context.clearRect(40, 40, 10, 10);
  13. }

五、绘制路径

    绘制路径的方法:

  • beginPath()    ——    表示要开始绘制新路径。
  • moveTo(x, y)    ——    将绘图游标移动到(x, y),不画线。
  • lineTo(x, y)    ——    从上一点开始绘制一条直线,到(x, y)为止。
  • rect(x, y, width, height)    ——    从点(x,y)开始绘制一个矩形,宽度和高度分别由width和height指定。这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的独立的形状。
  • arc(x, y, radius, startAngle, endAngle, counterclockwise)    ——   以(x,y)为圆心绘制一条弧线,弧线半径为radius,起始和结束角度(用弧度表示)分别为startAngle和endAngle。最后一个参数表示startAngle和endAngle是否按逆时针方向计算,值为true表示按逆时针方向计算。
  • quadraticCurveTo(cx, cy, x, y)    ——    绘制二次贝塞尔曲线
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y)    ——    绘制三次贝塞尔曲线
  • closePath()    ——    绘制一条连接到路径起点的线条。 
  • fill()    ——    使用fillStyle填充已经完成的路径
  • stroke()    ——    使用strokeStyle为已经完成的路径描边

5.1、绘制线段

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath(); //开始绘制新路径
  6. context.moveTo(50, 50); //把画笔移动到指定的坐标
  7. context.lineTo(200, 50); //绘制一条从当前位置到指定坐标(200, 50)的直线
  8. context.stroke(); //绘制
  9. }

5.2、绘制三角形

    绘制三角形边框:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath(); //开始绘制新路径
  6. context.moveTo(50, 50); //把画笔移动到指定的坐标
  7. context.lineTo(200, 50); //绘制一条从坐标(50, 50)到坐标(200, 50)的直线
  8. context.lineTo(200, 200); //绘制一条从坐标(200, 50)到坐标(200, 200)的直线
  9. context.closePath(); //闭合路径,绘制一条从路径起点到路径终点的直线
  10. context.stroke() //为路径描边
  11. }

    填充三角形:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath(); //开始绘制新路径
  6. context.moveTo(50, 50); //把画笔移动到指定的坐标
  7. context.lineTo(200, 50); //绘制一条从坐标(50, 50)到坐标(200, 50)的直线
  8. context.lineTo(200, 200); //绘制一条从坐标(200, 50)到坐标(200, 200)的直线
  9. context.closePath(); //闭合路径,绘制一条从路径起点到路径终点的直线
  10. context.fill() //填充三角形
  11. }

5.3、绘制圆弧

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath(); //开始绘制新路径
  6. context.arc(100, 100, 99, 0, Math.PI, false);
  7. context.stroke();
  8. }

5.4、绘制贝塞尔曲线

    二次贝塞尔曲线:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath();
  6. context.moveTo(10, 200); //起始点
  7. var x1 = 40, y1 = 100; //控制点
  8. var x2 = 200, y2 = 200; //结束点
  9. //绘制贝塞尔曲线
  10. context.quadraticCurveTo(x1, y1, x2, y2);
  11. context.stroke();
  12. context.beginPath();
  13. context.rect(10, 200, 10, 10);
  14. context.rect(x1, y1, 10, 10);
  15. context.rect(x2, y2, 10, 10);
  16. context.fill();
  17. }

    三次贝塞尔曲线:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath();
  6. context.moveTo(40, 200); //起始点
  7. var x1 = 20, y1 = 100; //控制点1
  8. var x2 = 100, y2 = 120; //控制点2
  9. var x3 = 200, y3 = 200; //结束点
  10. //绘制三次贝塞尔曲线
  11. context.bezierCurveTo(x1, y1, x2, y2, x3, y3);
  12. context.stroke();
  13. context.beginPath();
  14. context.rect(40, 200, 10, 10);
  15. context.rect(x1, y1, 10, 10);
  16. context.rect(x2, y2, 10, 10);
  17. context.rect(x3, y3, 10, 10);
  18. context.fill();
  19. }

5.5、线条样式

    lineWidth属性用于设置线宽

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.beginPath();
  6. context.moveTo(10, 10);
  7. context.lineTo(100, 10);
  8. context.lineWidth = 10;
  9. context.stroke();
  10. context.beginPath();
  11. context.moveTo(110, 10);
  12. context.lineTo(160, 10);
  13. context.lineWidth = 20;
  14. context.stroke();
  15. }

    lineCap属性用于设置线条末端样式,可以设置为三个值:

  • butt    ——    线段末端为方形
  • round    ——    线段末端以圆形结束
  • square    ——    线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var lineCaps = ["butt", "round", "square"]
  6. for(var i = 0; i < 3; i++){
  7. context.beginPath();
  8. context.moveTo(20 + 30 * i, 30);
  9. context.lineTo(20 + 30 * i, 100);
  10. context.lineWidth = 20;
  11. context.lineCap = lineCaps[i];
  12. context.stroke();
  13. }
  14. context.beginPath();
  15. context.moveTo(0, 30);
  16. context.lineTo(300, 30);
  17. context.moveTo(0, 100);
  18. context.lineTo(300, 100);
  19. context.strokeStyle = "red";
  20. context.lineWidth = 1;
  21. context.stroke();
  22. }

    lineJoin属性用于设置线条与线条间接合处的样式,可以设置为三个值:

  • round    ——    通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。圆角的半径是线段的宽度。
  • bevel    ——    在相连部分的末端填充一个额外的以三角形为底的区域,每个部分都有各自独立的矩形拐角。
  • miter(默认)    ——    通过延沈相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var lineJoin = ['round', 'bevel', 'miter'];
  6. context.lineWidth = 20;
  7. for (var i = 0; i < lineJoin.length; i++){
  8. context.lineJoin = lineJoin[i];
  9. context.beginPath();
  10. context.moveTo(50, 50 + i * 50);
  11. context.lineTo(100, 100 + i * 50);
  12. context.lineTo(150, 50 + i * 50);
  13. context.lineTo(200, 100 + i * 50);
  14. context.lineTo(250, 50 + i * 50);
  15. context.stroke();
  16. }
  17. }

六、透明度

    globalAlpha属性用于指定所有绘制的透明度,默认值为0。

    示例:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. //修改全局透明度
  9. context.globalAlpha = 0.5;
  10. //绘制蓝色矩形
  11. context.fillStyle = "rgba(0, 0, 255, 1)";
  12. context.fillRect(30, 30, 50, 50);
  13. //重置全局透明度
  14. context.globalAlpha = 0;
  15. }

 

七、变换

7.1、translate()

    translate(x, y)用于将坐标原点移动到(x, y),执行这个变换后,坐标(0, 0)会变成之前由(x, y)表示的点。

    示例

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //开始路径
  6. context.beginPath();
  7. //绘制外圆
  8. context.arc(100, 100, 99, 0, 2 * Math.PI, false);
  9. //绘制内圆
  10. context.moveTo(194, 100);
  11. context.arc(100, 100, 94, 0, 2 * Math.PI, false);
  12. //变换原点
  13. context.translate(100, 100);
  14. //绘制分针
  15. context.moveTo(0, 0);
  16. context.lineTo(0, -85);
  17. //绘制时针
  18. context.moveTo(0, 0);
  19. context.lineTo(-65, 0);
  20. //描边路径
  21. context.stroke();
  22. }

7.2、rotate(angle)

    rotate(angle)方法能够旋转坐标轴。

    示例

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //开始路径
  6. context.beginPath();
  7. //绘制外圆
  8. context.arc(100, 100, 99, 0, 2 * Math.PI, false);
  9. //绘制内圆
  10. context.moveTo(194, 100);
  11. context.arc(100, 100, 94, 0, 2 * Math.PI, false);
  12. //变换原点
  13. context.translate(100, 100);
  14. //旋转表针
  15. context.rotate(Math.PI / 6);
  16. //绘制分针
  17. context.moveTo(0, 0);
  18. context.lineTo(0, -85);
  19. //绘制时针
  20. context.moveTo(0, 0);
  21. context.lineTo(-65, 0);
  22. //描边路径
  23. context.stroke();
  24. }

7.3、scale(scaleX, scaleY)  

    scale(scaleX, scaleY)方法用于缩放图像,在x方向乘以scaleX,在y方向乘以scaleY

    scaleXscaleY的默认值都是1.0

    示例

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //开始路径
  6. context.beginPath();
  7. //绘制外圆
  8. context.arc(100, 100, 99, 0, 2 * Math.PI, false);
  9. //绘制内圆
  10. context.moveTo(194, 100);
  11. context.arc(100, 100, 94, 0, 2 * Math.PI, false);
  12. //变换原点
  13. context.translate(100, 100);
  14. //旋转表针
  15. context.rotate(Math.PI / 6);
  16. //绘制分针
  17. context.moveTo(0, 0);
  18. context.lineTo(0, -85);
  19. //绘制时针
  20. context.moveTo(0, 0);
  21. context.lineTo(-65, 0);
  22. //放大路径
  23. context.scale(5, 5);
  24. //描边路径
  25. context.stroke();
  26. }

7.4、transform(a, b, c, d, e, f)

    直接修改变换矩阵,方式是乘以如下矩阵:

7.5、setTransform(a, b, c, d, e, f)

    将变换矩阵重置为默认状态,然后再调用transform()

八、save()和restore()

    调用save()方法,当时所有的设置都会进入一个栈结构,得以妥善保管。

    然后可以对上下文进行其他修改,等想要回到之前保存的设置时,可以调用restore()方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。

    连续调用save()可以把更多设置保存到栈结构中,之后再连续调用restore()则可以一级一级返回。

    示例:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.fillStyle = "#F00";
  6. context.save();
  7. context.fillStyle = "#0F0";
  8. context.translate(100, 100);
  9. context.save();
  10. context.fillStyle = "#00F";
  11. //从点(100, 100)开始绘制蓝色矩形
  12. context.fillRect(0, 0, 100, 200);
  13. context.restore();
  14. //从点(110, 110)开始绘制绿色矩形
  15. context.fillRect(10, 10, 100, 200);
  16. context.restore();
  17. //从点(0, 0)开始绘制红色矩形
  18. context.fillRect(0, 0, 100, 200);
  19. }

九、绘制文本

    绘制文本主要有两个方法:

  • fillText()
  • strokeText()

    这两个方法都可以接收4个参数:要绘制的文本字符串、x坐标、y坐标和可选的最大像素宽度。

    这两个方法都以下列3个属性为基础:

  • font    ——    表示文本样式、大小及字体,用CSS中指定字体的格式来指定,例如"10px Arial"
  • textAlign    ——    表示文本对齐方式。可能的值有"start"、"end"、"left"、"right"和"center"
  • textBaseline    ——    表示文本的基线,可能的值有"top"、"hanging"、"middle"、"alphabetic"、"ideographic"、"bottom"

    示例

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //开始路径
  6. context.beginPath();
  7. //绘制分针
  8. context.moveTo(100, 100);
  9. context.lineTo(100, 15);
  10. //描边路径
  11. context.stroke();
  12. context.font = "bold 14px Arial";
  13. context.textAlign = "center";
  14. context.textBaseline = "middle";
  15. context.fillText("12", 100, 20);
  16. //起点对齐
  17. context.textAlign = "start";
  18. context.fillText("12", 100, 40);
  19. //终点对齐
  20. context.textAlign = "end";
  21. context.strokeText("12", 100, 60);

    fillText()strokeText()方法都可以接收第四个参数,也就是文本的最大像素宽度。提供这个参数后,调用fillText()strokeText()时如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。

十、绘制图像

    2D绘图上下文内置了对图像的支持,可以使用drawImage()方法。

    drawImage()有9个参数:要素绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度。

    ①绘制图像简单示例

  1. var drawing = document.getElementById("drawing");
  2. var img = new Image(); //创建Image对象
  3. img.src = 'https://avatar.csdn.net/6/4/D/1_qq_35732147.jpg?1539065138'; //设置图片源
  4. //确定浏览器支持<canvas>元素
  5. if(drawing.getContext){
  6. var context = drawing.getContext("2d"); //取得2D上下文对象
  7. img.addEventListener("load", function(){
  8. context.drawImage(img, 0, 0); //图像加载完之后才会执行这条语句
  9. },false);
  10. }

    使用DOM0级的Image对象可以在客户端预先加载图像,可以像使用<img>元素一样使用Image对象,但无法将其添加到DOM树中。

    考虑到图片是从网络加载,所以应该保证图像加载完之后再调用drawImage()方法绘制图像。

    ②缩放图片简单示例:

  1. var drawing = document.getElementById("drawing");
  2. var img = new Image(); //创建Image对象
  3. img.src = 'https://avatar.csdn.net/6/4/D/1_qq_35732147.jpg?1539065138'; //设置图片源
  4. //确定浏览器支持<canvas>元素
  5. if(drawing.getContext){
  6. var context = drawing.getContext("2d"); //取得2D上下文对象
  7. img.addEventListener("load", function(){
  8. context.drawImage(img, 0, 0, 400, 400); //图像加载完之后才会执行这条语句
  9. },false);
  10. }

    ③切片

    切片示例:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var img = new Image();
  6. img.src = "https://avatar.csdn.net/6/4/D/1_qq_35732147.jpg?1539071828";
  7. img.addEventListener("load", function(){
  8. context.drawImage(img, 50, 50, 200, 200, 0, 0, 200, 200);
  9. }, false);
  10. }

十一、模式

    模式其实就是重复的图像,可以用来填充或描边图形。

    要创建一个新模式,可以调用createPattern()方法并传入两个参数:

  • HTML<img>元素
  • 表示如何重复图像的字符串,这个参数的值与CSS的background-repeat属性值相同,包括"repeat"、"repeat-x"、"repeat-y"、"no-repeat"
  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var img = new Image();
  6. img.src = "https://avatar.csdn.net/E/9/8/3_weixin_42058532.jpg";
  7. img.addEventListener("load", function(){
  8. var pattern = context.createPattern(img, "repeat");
  9. //绘制矩形
  10. context.fillStyle = pattern;
  11. context.fillRect(10, 10, 200, 200);
  12. }, false);
  13. }

十二、使用图像数据

    canvas操作图像数据使用的几个方法:

    ①getImageData()    ——    用于取得画布上指定矩形的像素数据。

    具体是这个方法会返回ImageData对象,ImageData对象中包含图像数据。

     getImageData()方法接收4个参数:

  • 要取得画面区域左上角的x坐标
  • 要取得画面区域左上角的y坐标
  • 要取得画面区域的像素宽度
  • 要取得画面区域的像素高度

    例如要取得左上角坐标为(10,5)、大小为50*50像素的区域的图像数据:

        var imageData = context.getImageData(10, 5, 50, 50);

    返回的对象是ImageData的实例,每个ImageData对象都有三个属性:

  • width    ——    图像的宽度
  • height    ——    图像的高度
  • data    ——    保存图像中每一个像素的数据的数组,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度值。

    ②putImageData()    ——    把图像数据(从指定的ImageData对象)放回画布上。

    这个方法接收以下参数:

    

    下面的代码通过getImageData()取得画布上指定矩形的像素数据,然后通过putImageData()将图像数据放回画布:

  1. var c=document.getElementById("myCanvas");
  2. var ctx=c.getContext("2d");
  3. ctx.fillStyle="green";
  4. ctx.fillRect(10,10,50,50);
  5. var imgData=ctx.getImageData(10,10,50,50);
  6. ctx.putImageData(imgData,10,70);

    ③createImageData()    ——    创建新的、空白的ImageData对象

    这个方法接收的参数:

    以下代码创建100*100像素的ImageData对象,其中每个像素都是红色的,然后把它放到画布上:

  1. var c=document.getElementById("myCanvas");
  2. var ctx=c.getContext("2d");
  3. var imgData=ctx.createImageData(100,100);
  4. for (var i=0;i<imgData.data.length;i+=4)
  5. {
  6. imgData.data[i+0]=255;
  7. imgData.data[i+1]=0;
  8. imgData.data[i+2]=0;
  9. imgData.data[i+3]=255;
  10. }
  11. ctx.putImageData(imgData,10,10);

    效果:

    示例

    创建一个简单的灰阶过滤器:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var image = new Image();
  6. image.src = "liyangqiao.jpg";
  7. image.addEventListener("load", function(event){
  8. var red, green, blue, alpha, average;
  9. //绘制原始图像
  10. context.drawImage(image, 0, 0);
  11. //取得图像数据
  12. imageData = context.getImageData(0, 0, image.width, image.height);
  13. data = imageData.data;
  14. for(var i = 0, len = data.length; i < len; i += 4){
  15. red = data[i];
  16. green = data[i + 1];
  17. blue = data[i + 2];
  18. alpha = data[i + 3];
  19. //求得rgb平均值
  20. average = Math.floor((red + green + blue) / 3);
  21. //设置颜色值,透明度不变
  22. data[i] = average;
  23. data[i + 1] = average;
  24. data[i + 2] = average;
  25. }
  26. //回写图像数据并显示结果
  27. imageData.data = data;
  28. context.putImageData(imageData, 0, 0);
  29. }, false);
  30. }

    注意只有在画布“干净”的情况下(即图像并非来自其他域),才可以取得图像数据。如果画布”不干净“,那么访问图像数据时会导致JavaScript错误。

十三、阴影

    2D上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影。

  • shadowColor    ——    用CSS颜色格式表示的阴影颜色,默认为黑色。
  • shadowOffsetX    ——    形状或路径x轴方向的阴影偏移量,默认为0。
  • shadowOffsetY    ——    形状或路径y轴方向的阴影偏移量,默认为0。
  • shadowBlur    ——    模糊的像素数,默认0,即不模糊。
  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //设置阴影
  6. context.shadowOffsetX = 5;
  7. context.shadowOffsetY = 5;
  8. context.shadowBlur = 5;
  9. context.shadowColor = "rgba(0, 0, 0, 0.5)";
  10. //绘制红色矩形
  11. context.fillStyle = "#F00";
  12. context.fillRect(10, 10, 50, 50);
  13. //绘制蓝色矩形
  14. context.fillStyle = "rgba(0, 0, 255, 1)";
  15. context.fillRect(30, 30, 50, 50);
  16. }

十四、渐变

    渐变由CanvasGradient实例表示,很容易通过2D上下文来创建和修改。

    要创建一个新的线性渐变对象,可以调用createLinearGradient()方法。

    这个方法接受4个参数:起点的x坐标、起点的y坐标、终点的x坐标、终点的y坐标。

    创建了渐变对象后,下一步就是使用addColorStop()方法来指定色标。

    这个方法接收两个参数:色标位置和CSS颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字。

    示例:

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var gradient = context.createLinearGradient(30, 30, 70, 70);
  6. gradient.addColorStop(0, "white");
  7. gradient.addColorStop(1, "black");
  8. //绘制红色矩形
  9. context.fillStyle = "#ff0000";
  10. context.fillRect(10, 10, 50, 50);
  11. //绘制渐变矩形
  12. context.fillStyle = gradient;
  13. context.fillRect(30, 30, 50, 50);
  14. }

    要创建径向渐变(或放射性渐变),可以使用createRadialGradient()方法。

    这个方法接收6个参数,对应着两个圆的圆心和半径。前三个参数指定的是起点圆的圆心和半径,后三个参数指定的是终点圆的圆心和半径。

    示例

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
  6. gradient.addColorStop(0, "white");
  7. gradient.addColorStop(1, "black");
  8. //绘制红色矩形
  9. context.fillStyle = "#ff0000";
  10. context.fillRect(10, 10, 50, 50);
  11. //绘制渐变矩形
  12. context.fillStyle = gradient;
  13. context.fillRect(30, 30, 50, 50);
  14. }

十五、合成

    globalCompositionOperation属性表示后绘制的图形怎样与先绘制的图形结合。

    这个属性的值是字符串,可能的值如下:

  • source-over(默认值)    ——    后绘制的图形位于先绘制的图形上方
  • source-in    ——    后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明
  • source-out    ——    后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明
  • source-atop    ——    后绘制的图形与先绘制的图形重叠部分可见,先绘制图形不受影响
  • destination-over    ——    后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见
  • destination-in    ——    后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明
  • destination-out    ——    后绘制的图形擦除与先绘制的图形重叠的部分
  • destination-atop    ——    后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明
  • lighter    ——    后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮
  • copy    ——    后绘制的图形完全替代与之重叠的先绘制图形
  • xor    ——    后绘制的图形与先绘制的图形重叠的部分执行“异或”操作

    ①source-over(默认值)

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. context.globalCompositeOperation = "source-over";
  6. //绘制红色矩形
  7. context.fillStyle = "#F00";
  8. context.fillRect(10, 10, 50, 50);
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ②source-in

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "source-in";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ③source-out

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "source-out";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ④source-atop

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "source-atop";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑤destination-over

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "destination-over";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑥destination-in

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "destination-in";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑦destination-out

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "destination-out";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑧destination-atop

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "destination-atop";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑨lighter

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "lighter";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑩copy

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "copy";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

    ⑾xor

  1. var drawing = document.getElementById("drawing");
  2. //确定浏览器支持<canvas>元素
  3. if(drawing.getContext){
  4. var context = drawing.getContext("2d"); //取得2D上下文对象
  5. //绘制红色矩形
  6. context.fillStyle = "#F00";
  7. context.fillRect(10, 10, 50, 50);
  8. context.globalCompositeOperation = "xor";
  9. //绘制蓝色矩形
  10. context.fillStyle = "rgba(0, 0, 255, 1)";
  11. context.fillRect(30, 30, 50, 50);
  12. }

十六、基本动画

16.1、动画的基本步骤

    ①清空canvas

    除非要画的内容会完全充满canvas(例如背景图),否则需要清空所有。

    最简单的做法就是用clearRect()方法。

    ②保存canvas状态

    如果要改变一些会改变canvas状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,需要先保存一下。

    ③绘制动画图形

    这一步才是重绘动画帧

    ④恢复canvas状态

    如果已经保存了canvas的状态,可以先恢复它,然后重绘下一帧。

16.2、操纵动画

    在canvas上绘制内容是用canvas提供的或者自定义的方法,而通常,我们仅仅在脚本执行结束后才能看见结果,比如说,在for循环里面做完成动画是不太可能的,因为for循环一直高速执行,动画都来不及绘制。

    因此,为了实现动画,我们需要一些可以定时执行重绘的方法。

    首先,可以用window.setInterval()window.setTimeout(),和window.requestAnimationFrame()来设定定期执行一个指定函数:

  • setInterval(function, delay)    ——    当设定好间隔时间后,function会定期执行
  • setTimeout(function, delay)    ——    在设定好的时间之后执行函数
  • requestAnimationFrame(callback)    ——    告诉浏览器希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画

    如果并不需要与用户互动,可以使用setInterval()方法,它就可以定期执行指定代码。

    如果需要做一个游戏,我们可以使用键盘或者鼠标事件配合上setTimeout()方法来实现。

    通过设置事件监听,可以捕捉用户的交互,并执行相应的动作。

16.3、太阳系的动画

    下面的例子,采用window.requestAnimationFrame()实现动画效果。

    这个方法提供了更加平缓并更加有效率的方式来执行动画,当系统准备好了重绘条件的时候,才调用绘制动画帧。

    一般每秒钟回调函数执行60次,也有可能会被降低。

    一个小型的太阳系模拟动画:

  1. var sun = new Image();
  2. var moon = new Image();
  3. var earth = new Image();
  4. function init(){
  5. sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
  6. moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
  7. earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
  8. window.requestAnimationFrame(draw);
  9. }
  10. function draw(){
  11. var ctx = document.getElementById("drawing").getContext('2d');
  12. //后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见
  13. ctx.globalCompositeOperation = 'destination-over';
  14. ctx.clearRect(0, 0, 300, 300); //clear canvas
  15. ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
  16. ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)';
  17. ctx.save();
  18. //移动坐标原点
  19. ctx.translate(150, 150);
  20. // Earth
  21. var time = new Date();
  22. ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds() );
  23. ctx.translate(105, 0);
  24. ctx.fillRect(0, -12, 50, 24); //Shadow
  25. ctx.drawImage(earth, -12, -12);
  26. // Moon
  27. ctx.save();
  28. ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds() );
  29. ctx.translate(0, 28.5);
  30. ctx.drawImage(moon, -3.5, -3.5);
  31. ctx.restore();
  32. ctx.restore();
  33. ctx.beginPath();
  34. ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // Earth orbit
  35. ctx.stroke();
  36. ctx.drawImage(sun, 0, 0, 300, 300);
  37. window.requestAnimationFrame(draw);
  38. }
  39. init();

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/332603
推荐阅读
相关标签
  

闽ICP备14008679号