canvas

一.什么是canvas:canvas其实就是html5里面的一个新的标签
    <canavs></canvas>
1.canvas是一个矩形区域的画布,可以用js在上面绘画,控制其每一个像素
2.canvas标签使用js在网页上绘制图像,本身并不具备绘画功能
3.canvas有多种绘制路径、矩形、圆形、字符以及添加图像的方法


二.canvas语法
1.设置canvas的宽高是通过canvas的属性去设置的,而不是css
<canvas width="600" height="600"></canvas>
并且属性值的单位必须是px,否则会忽略
2.width和height默认是300*150px
3.注意:
(1)不要用css控制canvas的宽高,会造成图片拉伸
(2)重新设置canvas标签的宽高属性会让画布擦除所有内容
(3)可以给canvas画布设置背景颜色


三.浏览器不兼容处理
1.ie9以上才支持canvas,其他什么谷歌、火狐、苹果浏览器等都支持
2.只要浏览器兼容canvas,就会支持大部分api
3.移动端的兼容情况非常理想,基本上可以随便使用
4.2d的支持都非常好,3die11才支持,其他浏览器都支持
5.如果浏览器不兼容,最好进行友好提示
6.如果浏览器不兼容,可以使用flash等手段进行优雅降级


四.canvas绘图上下文context
1.context:canvas的上下文、绘制环境
(1)上下文:是所有挥之操作api的入口/集合(其实就是一系列功能的封装体)
(2)canvas自身无法绘制任何内容,它的绘图是使用js操作的
(3)context对象就是js操作canvas的接口。使[CanvasElement].getContext(‘2d’)来获取2D绘图上下文
---->var canvas = document.getElementById( 'cavsElem' ); //获得画布
    var ctx = canvas.getContext( '2d' );//注意:2d小写, 3dwebgl
(4)获取上下文通过js:要在canvas上绘制内容就必须要等到canvas加载完成,所以<script></script>要卸载</cnavas>之后


五.基本绘制路径
1.canvas坐标系:从最左上角(0,0)开始,x向右增大,y向下增大
2.设置绘制起点(moveTo)
(1)语法:ctx.moveTo(x,y)
(2)解释:设置上下文绘制路径的起点,相当于移动画笔到某个位置
(3)参数:x,y都是相对于canvas盒子的最左上角
(4)注意:绘制线段前必须先设置起点,不然绘制无效

3.绘制直线(lineTo)
(1)语法:ctx.lineTo(x,y)
(2)解释:从x,y的位置绘制一条直线到起点/上一个线头点
(3)参数:(x,y)线头点坐标
canvas

2.设置绘制起点(moveTo)
(1)语法:ctx.moveTo(x,y)
(2)解释:设置上下文绘制路径的起点,相当于移动画笔到某个位置
(3)参数:x,y都是相对于canvas盒子的最左上角
(4)注意:绘制线段前必须先设置起点,不然绘制无效

3.绘制直线(lineTo)
(1)语法:ctx.lineTo(x,y)
(2)解释:从x,y的位置绘制一条直线到起点/上一个线头点
(3)参数:(x,y)线头点坐标


4.路径开始和闭合
(1)开始路径:ctx.beginPath();
        核心的作用是将不同绘制的形状进行隔离。每次执行此方法都表示重新绘制一个路径,和之前绘制的墨迹可以进行分开样式设置和管理(其实就是开一个新路径,开启新状态的绘图,新状态可以继承之前状态的样式,但是当前状态设置的所有样式只能作用于当前的状态)
(2)闭合路径:ctx.closePath();
(3)解释:复杂的路径绘制必须使用路径开始和结束。闭合路径会自动把最后的线头和开始的线头连在一起

5.描边(stroke)
(1)语法:ctx.stroke();
(2)解释:根据路径绘制线。路径只是草稿,真正绘制线必须使用stroke
(3)ctx.strokeStyle = “颜色”;   控制描边的颜色
(4)设置线宽:ctx.lineWidth = 数字;

6.填充(fill)
(1)语法:ctx.fill();
(2)解释:将闭合路径的内容填充具体的颜色,默认是黑色。如果需要设置别的颜色就要用ctx.fillStyle = '颜色';
(3)注意:交叉路径的填充问题——“非零环绕原则”,顺逆时针穿插次数决定是否填充
以下是非0环绕原则的原理:(了解即可,非常少会用到复杂的路径)
非零环绕规则是这么来判断有自我交叉情况的路径的:对于路径中的任意给定区域,从该区域内部画一条足够长的线段,
使此线段的终点完全落在路径范围之外。
2-14中的那三个箭头所描述的就是上面这个步骤。
接下来,将计数器初始化为0
然后,每当这条线段与路径上的直线或曲线相交时,
就改变计数器的值。如果是与路径的顺时针部分相交,则加1
如果是与路径的逆时针部分相交,则减1。若计数器的最终值不是0,那么此区域就在路径里面,在调用fill()方法时,
浏览器就会对其进行填充。
如果最终值是0,那么此区域就不在路径内部,浏览器也就不会对其进行填充了

7.canvas绘制的基本步骤
(1)获得上下文  =>  canvasElem.getContext('2d');
(2)开始路径规划  =>  ctx.beginPath()
(3)移动起始点  =>  ctx.moveTo(x, y)
(4)绘制线  =>  ctx.lineTo(x, y)
(5)闭合路径  =>  ctx.closePath()
(6)绘制描边  =>  ctx.stroke();


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>

</style>
</head>
<body>
    <!--设置canvas标签的宽高是通过canvas标签的属性设置的,而不是用css-->
    <canvas id="demo" width="600" height="600"></canvas>

    <script>
        window.onload = function(){
            //第一步:拿到canvas标签
            var canvas = document.getElementById('demo');
            canvas.style.border = "1px solid red";

            //第二部:拿到canvas的上下文
            var ctx = canvas.getContext('2d');

            //第三部:开始绘制
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(100,200);
            // ctx.lineTo(100,100);
            ctx.closePath();
            //上面这些只是将画笔移动到特定的位置,下面的代码才是有线显示
            ctx.stroke();

        }
    </script>
</body>
</html>

8.canvas是基于状态的绘图 

六.绘制矩阵(rect)
1.快速创建矩形rect()方法
(1)语法:ctx.rect(x,y,width,height);
(2)解释:x,y是矩形左上角坐标,width和height都是以像素计
(3)注意
    ·rect方法只是规划了矩形的路径,并没有填充和描边

2.快速创建描边矩形和填充矩形
(1)语法:ctx.strokeRect(x,y,width,height);此方法绘制万路径之后立即进行stroke绘制
                  ctx.fillRect(x,y,width,height);  此方法绘制完路径之后立即对当前矩阵进行fill填充
(2)解释:x,y是矩形左上角坐标,width和height都是以像素计

3.清除矩阵
(1)语法:ctx.clearRect(x,y,width,height);
(2)解释:清除某个矩阵内绘制的内容,相当于橡皮擦


七.绘制圆形(arc):arc()方法创建弧/曲线(用于创建圆/部分圆)
1.语法:ctx.arc(x,y,r,sAngle,eAngle,counterclockwise);
2.解释:
    ·x,y:圆心坐标
    ·r:半径大小
    ·sAngle:绘制开始的角度(起始点和0度坐标线的夹角),圆心到最右边点是0度,顺时针方向弧度增大(注意和我们通常的坐标系有区别)

 canvas

  ·eAngle:结束的角度(结束点和0度坐标线的夹角),注意是弧度。π
    ·counterclockwise:是否是逆时针。ttrue是逆时针false是顺时针
    ·弧度和角度的转化公式:rad = deg*Math.PI/180;
    ·Math提供的方法中sincos等都使用的弧度
canvas

八.绘制文字(会使用就可以了)
1.绘制空心的文字:ctx.strokeText(“要绘制的文字”,文字的x坐标,文字的y坐标)
2.绘制实心的文字:ctx.fillText(“要绘制的文字”,文字的x坐标,文字的y坐标)

九.绘制上下文的文字属性(有印象就可以了)
1.font:设置/返回文本内容的当前字体属性
(1)font属性使用的语法与CSS font属性相同
    例如:ctx.font = "18px '微软雅黑'";
(2)textAlign:设置/返回文本内容的当前对齐方式
    ·start:默认。文本在指定的位置开始
    ·end:文本在指定的位置结束
    ·center:文本的中心被放置在指定的位置
    ·left:文本左对齐
    ·right:文本右对齐
* 例如:ctx.textAlign = 'left';
canvas
行高:两行文本基线的距离


canvas
canvas
(3)textBaseline:设置/返回在绘制文本时使用的当前文本基线
    ·alphabetic:默认。文本基线是普通的字母基线
    ·top:文本基线是em方框的顶端
    ·hanging:文本基线是悬挂基线
    ·middle:文本基线是em方框的正中
    ·ideographic:文本基线是em基线
    ·bottom:文本基线是em方框的底端


canvas

十.上下文绘制文字方法
1.ctx.fillText():在画布上绘制“被填充的文本”
2.ctx.strokeText():在画布上绘制空心文本(无填充)
3.ctx.measureText():返回包含指定文本宽度的对象(测量文本的宽度,在()里面放置文本的话就会自动返回文本的宽度)
ctx.moveTo( 300, 300 );
ctx.fillStyle = "purple"; //设置填充颜色为紫色
ctx.font = '20px "微软雅黑"'; //设置字体
ctx.textBaseline = "bottom"; //设置字体底线对齐绘制基线
ctx.textAlign = "left"; //设置字体对齐的方式
//ctx.strokeText( "left", 450, 400 );
ctx.fillText( "Top-g", 100, 300 ); //填充文字


十一.绘制图片
1.基本绘制图片的方式:context.drawImage(img,x,y);
(1)解释:x,y绘制图片左上角的坐标,img绘制图片的dom对象

2.在画布上绘制图像并规定图像的宽高:context.drawImage(img,x,y,width,height)
(1)解释:width绘制图片的宽度,height绘制图片的高度
(2)注意:如果指定宽高,最好成比例,否则图片会被拉伸
    ·等比公式:toH = Height * toW / width
                    设置高 = 原高度 * 设置宽 / 原宽度

canvas

 

3.图片剪裁并在画布上定位被剪切的部分:context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
(1)解释:sx、sy —— 剪裁图片的左上角坐标
                 swidth —— 剪裁图片的宽度(将要截取的图片的宽)
                 sheight —— 剪裁图片的高度
                      x,y —— 将要绘制到画布的哪里(绘制图片左上角的坐标

4.用js创建img对象
(1)var img = document.getElementById(“imgId”);
(2)var img = new Image() ;   //这个就是img标签的dom对象
        img.src = “”;      //只要设置了src,当前的img对象就会立即去加载图片
        img.alt = “”;
        img.onload = function(){
                //图片加载完成后执行该方法(图片加载完成之后再绘制到canvas上)
        }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
    <div id="container">
        <canvas id="cavsElem">
            你的浏览器不支持canvas,请升级浏览器
        </canvas>
    </div>
    <script>
        (function(){
            var canvas = document.querySelector( '#cavsElem' );
            var ctx = canvas.getContext( '2d' );

            canvas.width = 900;
            canvas.height = 900;
            canvas.style.border = "1px solid #000";

            //第一步:创建图片的dom对象
            var img = new Image();
            img.src = 'images/a.jpg'; //只要设置了src属性,当前img对象立即去加载图片

            img.onload = function(){
                //图片加载完成之后再绘制到canvas上
                ctx.drawImage(img,100,100);

                //绘制10条狗
                for(var i = 0 ; i < 10 ; i++){
                    ctx.drawImage(img,100 + 20 * i,100 + 20 * i);
                }
            }

        }());
    </script>
</body>
</html>
结果:
canvas

实现虚拟列帧:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
    <div id="container">
        <canvas id="cavsElem">
            你的浏览器不支持canvas,请升级浏览器
        </canvas>
    </div>

    <script>
        (function(){
            var canvas = document.querySelector( '#cavsElem' );
            var ctx = canvas.getContext( '2d' );

            canvas.width = 900;
            canvas.height = 900;
            canvas.style.border = "1px solid #000";

            //第一步:创建图片的dom对象
            var img = new Image();
            img.src = 'images/gameImgs/DMMban.png'; //只要设置了src属性,当前img对象立即去加载图片

            img.onload = function(){
                var frameIndex = 0;
                setInterval(function(){
                    ctx.clearRect(0,0,canvas.width,canvas.height); //清除之前绘制的图片
                    // canvas.width = canvas.width; 如果通过代码重新设置canvas画布的宽高,canvas画布里面所有的内容都会被清空,不建议使用这种方法
                    ctx.drawImage(img,frameIndex * 40,0,40,65,200,200,80,130); //绘制图片
                    frameIndex ++; //绘制完图片后让帧++,添加到下一帧
                    frameIndex %= 4; //取余数
                },1000/10); //10帧:100ms绘制一次图片
            }
        }());
    </script>
</body>
</html>


十二.设置阴影(了解,较少用,性能很差)
  • 类比于CSS3的阴影。
  • shadowColor 设置或返回用于阴影的颜色
  • shadowBlur 设置或返回用于阴影的模糊级别,大于1的正整数,数值越高,模糊程度越大
  • shadowOffsetX 设置或返回阴影距形状的水平距离
  • shadowOffsetY 设置或返回阴影距形状的垂直距离
ctx.fillStyle = "rgba(255,0,0, .9)"
ctx.shadowColor = "teal";
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 10;
ctx.shadowOffsetY = 10;
ctx.fillRect(100, 100, 100, 100);


十三.复杂样式
1.创建线性渐变样式(了解)
  • 一般不用,都是用图片代替,canvas绘制图片效率更高。
  • 线性渐变可以用于 矩形、圆形、文字等颜色样式
  • 线性渐变是一个对象
  • 语法:ctx.createLinearGradient(x0,y0,x1,y1); //参数:x0,y0起始坐标,x1,y1结束坐标
例如:
//创建线性渐变的对象,
var grd=ctx.createLinearGradient(0,0,170,0);
grd.addColorStop(0,"black"); //添加一个渐变颜色,第一个参数介于 0.0 1.0 之间的值,表示渐变中开始与结束之间的位置。
grd.addColorStop(1,"white"); //添加一个渐变颜色
ctx.fillStyle =grd; //关键点,把渐变设置到 填充的样式

2.设置圆形渐变(径向渐变,了解)
  • 创建放射状/圆形渐变对象。可以填充文本、形状等
  • context.createRadialGradient(x0,y0,r0,x1,y1,r1);
  • radial 半径的;放射状的;光线的;光线状的 ['reɪdɪəl] ['redɪəl]
  • 参数详解:
    • x0: 渐变的开始圆的 x 坐标
    • y0: 渐变的开始圆的 y 坐标
    • r0: 开始圆的半径
    • x1: 渐变的结束圆的 x 坐标
    • y1: 渐变的结束圆的 y 坐标
    • r1: 结束圆的半径
var rlg = ctx.createRadialGradient(300,300,10,300,300,200);
rlg.addColorStop(0, 'teal'); //添加一个渐变颜色
rlg.addColorStop(.4, 'navy');
rlg.addColorStop(1, 'purple');
ctx.fillStyle = rlg;//设置 填充样式为延续渐变的样式
ctx.fillRect(100, 100, 500, 500);

3.绘制背景图(了解)
  • ctx.createPattern(img,repeat) 方法在指定的方向内重复指定的元素了解
  • patternn. 模式;图案;样品 ['pæt(ə)n] ['pætɚn]
  • 第一参数:设置平铺背景的图片,第二个背景平铺的方式。
    • image 规定要使用的图片、画布或视频元素。
    • repeat 默认。该模式在水平和垂直方向重复。
    • repeat-x 该模式只在水平方向重复。
    • repeat-y 该模式只在垂直方向重复。
    • no-repeat 该模式只显示一次(不重复)。
var ctx=c.getContext("2d");
var img=document.getElementById("lamp");
var pat=ctx.createPattern(img,"repeat");
ctx.rect(0,0,150,100);
ctx.fillStyle=pat;// 把背景图设置给填充的样式
ctx.fill();


十四.变换(重点)
1.缩放(重点):scale() —— 缩放当前绘图,更大/更小
(1)语法:context.scale(scaleWidth,scaleHeight)
(2)参数解释
    ·scaleWidth:缩放当前绘图的宽度(1=100%,0.5=50%,2=200%)
    ·scaleHeight:缩放当前绘图的高度
(3)注意:缩放的是整个画布,缩放后继续绘制的图形会被放大/缩小

2.位移画布(重点):ctx.translate(x,y) —— 重新映射画布上(0,0)的位置
(1)参数解释:
    ·x:添加到水平坐标(x)上的值
    ·y:添加到垂直坐标(y)上的值
(2)发生位移后相当于把画布的(0,0)坐标更换到(x,y)的位置,所有绘制的新元素都会被影响
(3)位移画布一般配合缩放和旋转等

3.旋转(重点):context.rotate(angle):方法旋转当前的绘图
(1)注意参数的单位是弧度
(2)如果需要将角度转化为弧度就使用degrees*Math.PI/180 公式进行计算

4.绘制环境保存和还原(重要)
(1)ctx.save():保存当前环境的状态(把当前上下文的状态保存起来,可以把当前绘制环境进行保存到缓存中)
(2)ctx.restore():返回之前保存过的路径状态和属性(把之前保存的上下文再挪出来,获取最近缓存的ctx)
(3)一般配合位移画布使用

5.设置绘制环境的透明度(了解)
  • context.globalAlpha=number;
  • number:透明值。必须介于 0.0(完全透明) 1.0(不透明) 之间。
  • 设置透明度是全局的透明度的样式。注意是全局的。

6.画布限定区域绘制(了解)
  • ctx.clip(); 方法从原始画布中剪切任意形状和尺寸
  • 一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)
  • 一般配合绘制环境的保存和还原。

7.画布保存base64编码内容(重要):把canvas绘制的内容输出成base64内容
(1)语法:canvas.toDataURL(type,encoderOptions
(2)参数说明:
    ·type设置输出的类型(比如image/png image/jpeg等)
    ·encoderOptions:0-1之间的数字,用于标识输出图片的质量,1表示无损压缩,类型为image/jpeg或image/webp才能起作用

8.画布渲染画布(重点):context.drawimage(img,x,y);
(1)参数说明:img参数也可以是画布,也就是把画布整体渲染到另一个画布上

9.线条样式(了解)
  • lineCap 设置或返回线条的结束端点(线头、线冒)样式
    • butt 默认。向线条的每个末端添加平直的边缘。
      • 翻译.:屁股;烟头;笑柄;靶垛;粗大的一端 [bʌt] [bʌt]
    • round 向线条的每个末端添加圆形线帽。
square 向线条的每个末端添加正方形线帽。 
canvas

  • lineJoin 设置或返回两条线相交时,所创建的拐角类型
    • bevel: 创建斜角。
      • 翻译. 斜角;斜面;[] 斜角规 ['bev(ə)l] ['bɛvl]
    • round: 创建圆角。
    • miter: 默认。创建尖角 
canvas

  • lineWidth 设置或返回当前的线条宽度
  • miterLimit 设置或返回最大斜接长度
    • 意思: 斜接 ['maɪtə]
    • 斜接长度指的是在两条线交汇处内角和外角之间的距离。
    • 一般用默认值:10就可以了。除非需要特别长的尖角时,使用此属性。

canvas

十五.了解贝塞尔曲线
1.绘制一条二次方曲线(知道有就行了)
  • 微软的画图板中的曲线的颜色。
  • quadratic:二次方的意思, [kwɒ'drætɪk] [kwɑ'drætɪk]
  • Curve:曲线的意思, [kɜːv] [kɝv]
  • 语法: context.quadraticCurveTo(cpx,cpy,x,y);
  • 参数:
    • cpx 贝塞尔控制点的 x 坐标
    • cpy 贝塞尔控制点的 y 坐标
    • x 结束点的 x 坐标
y 结束点的 y 坐标 
canvas

2.绘制贝塞尔曲线(知道有就行)
  • 绘制一条三次贝塞尔曲线
  • 语法:context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
  • 提示:三次贝塞尔曲线需要三个点。前两个点是用于三次贝塞尔计算中的控制点,第三个点是曲线的结束点。曲线的开始点是当前路径中最后一个点。如果路径不存在,那么请使用 beginPath() moveTo() 方法来定义开始点。
  • 参数说明:
    • cp1x 第一个贝塞尔控制点的 x 坐标
    • cp1y 第一个贝塞尔控制点的 y 坐标
    • cp2x 第二个贝塞尔控制点的 x 坐标
    • cp2y 第二个贝塞尔控制点的 y 坐标
    • x: 结束点的 x 坐标
    • y: 结束点的 y 坐标
//绘制复杂的贝塞尔曲线
ctx.beginPath();
ctx.moveTo(400,400);
//参数说明:context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
// cp1x 第一个贝塞尔控制点的 x 坐标
// cp1y 第一个贝塞尔控制点的 y 坐标
// cp2x 第二个贝塞尔控制点的 x 坐标
// cp2y 第二个贝塞尔控制点的 y 坐标
// x: 结束点的 x 坐标
// y: 结束点的 y 坐标
ctx.bezierCurveTo(500, 200, 600, 600, 700, 300);
ctx.stroke();
canvas


3.创建两条切线的弧(知道有就行)
  • 在画布上创建介于当前起点和两个点形成的夹角的切线之间的弧
  • 语法: context.arcTo(x1,y1,x2,y2,r); //类比:css3中的圆角。
  • 例如: ctx.arcTo(240, 100, 240, 110, 40);
  • 参数:
    • x1: 弧的端点1 x 坐标
    • y1: 弧的端点1 y 坐标
    • x2: 弧的端点2(终点) x 坐标
    • y2: 弧的端点2(终点) y 坐标
    • r : 弧的半径
//代码demo
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(200,100);
//context.arcTo(x1,y1,x2,y2,r); //类比:css3中的圆角。
ctx.arcTo(240, 100, 240, 110, 40);
ctx.lineTo(240, 300);
ctx.stroke();
canvas


4.了解断点是否在路径中(知道有就行)
context.isPointInPath(x,y);
//isPointInPath() 方法返回 true,如果指定的点位于当前路径中;否则返回 false
//判断x,y坐标的点是否在当前的路径中。

5.了解文本宽度的计算(知道有就行)
context.measureText(text).width;