• canvas API ,通俗的canvas基础知识(二)


    上文我们讲到了画一条线,画矩形,写文字,总算是有了一个好的开头,如果还没有看的同学出门左转,先看看那篇,这里就不多做叙述了,接下来我们看比较复杂的一些属性和方法!

    讲之前呢,我还是想温习一下,毕竟上文还有几个属性没有讲到,那我们从画三角形开始吧!

    如果看了上文,机智的少年肯定会想到,三角形,多简单啊,无非是比直线多一个点,于是这少年就开始动手了:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.moveTo(50,50);
    ctx.lineTo(100,100);
    ctx.lineTo(50,200);
    ctx.stroke();

    呀呵,怎么是一个折线,三角形不是只有三个点吗?是不是因为没有闭合呢?那我再加一个点:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.moveTo(50,50);
    ctx.lineTo(100,100);
    ctx.lineTo(50,200);
    ctx.lineTo(50,50);
    ctx.stroke();

    哈哈,果然机智如你啊!这个思路其实是正解的,三角形就是这么简单,其实还有一种方式可以画三角形,只需3个点,那就是我们要介绍的:

    closePath() 闭合路径

    有闭合就是开始,一般来说他们是成双成对的

    beginPath() 开始路径

    这对活宝的用法一般是:

    ctx.beginPath();
    
    ctx.closePath();

    先开始路劲,里面写你要绘制的内容,然后结束路劲,相当于是一个盒子已经封箱了,这样做有个好处就是可以避免绘制过程中的样式污染,你不知道怎么污染?好吧,看下面:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    //第一个三角
    ctx.strokeStyle = 'red';
    ctx.moveTo(50,50);
    ctx.lineTo(100,100);
    ctx.lineTo(50,200);
    ctx.lineTo(50,50);
    ctx.stroke();
    //第二个三角
    ctx.strokeStyle = 'green';
    ctx.moveTo(150,50);
    ctx.lineTo(200,100);
    ctx.lineTo(150,200);
    ctx.lineTo(150,50);
    ctx.stroke();

    如图,如果我本来是想让第一个三角的颜色为红色,第二个为绿色,但是现在的结果却都是绿色,而且眼尖的同学还看到,第一个三角感觉有2个颜色,颜色也特别的深,感觉是叠了2个三角,你没看到?好,我们改改,你在看:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    //第一个三角
    ctx.strokeStyle = 'red';
    ctx.moveTo(50,50);
    ctx.lineTo(100,100);
    ctx.lineTo(50,200);
    ctx.lineTo(50,50);
    //ctx.stroke();
    //第二个三角
    ctx.strokeStyle = 'green';
    ctx.moveTo(150,50);
    ctx.lineTo(200,100);
    ctx.lineTo(150,200);
    //ctx.lineTo(150,50);
    ctx.stroke();

    我们先不画第一个三角,也不画第二个三角的左边一边,然后看一下:

    第一个三角没有双重色了,说吧绘制了2次,一次红,一次绿,去掉了重绘,后面的颜色也将前面的颜色污染了,这不是我们想要的,这污染,你应该明白了吧!

    那我们使用那对活宝看看:

    var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            //第一个三角
            ctx.beginPath();
            ctx.strokeStyle = 'red';
            ctx.moveTo(50,50);
            ctx.lineTo(100,100);
            ctx.lineTo(50,200);
            ctx.lineTo(50,50);
            ctx.closePath();
            ctx.stroke();
            //第二个三角
            ctx.beginPath();
            ctx.strokeStyle = 'green';
            ctx.moveTo(150,50);
            ctx.lineTo(200,100);
            ctx.lineTo(150,200);
            ctx.lineTo(150,50);
            ctx.closePath();
            ctx.stroke();

    这才是我们想要的嘛,你玩你的,我玩我的,互不干扰,(你说画三角只需3个点的呢,吹牛B吧,你看你都是用的4个点),哦,对。

    closePath() 方法创建从当前点到开始点的路径,这是对此方法的描述,也就是说,使用这个方法,就能将画笔移到beginPath()的位置,这样才能结束画布,所以照这个理论,当画三角时,画到第三个点时,我们用closePath()方法让画笔回到起点,再画线,是不是就闭合了,看看效果:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.strokeStyle = 'red';
    ctx.moveTo(50,50);
    ctx.lineTo(100,100);
    ctx.lineTo(50,200);
    ctx.closePath();
    ctx.stroke();

    看,只有三个点,不是折线吧,后面要讲的什么扇形图,不规则图形都可以用此技能,妥妥的!

    嗨,也不过如此,你这线条都是一像素的,又不能跟孙悟空的金箍棒一样,要大变大,要小变小,哼,谁说的,哥有神器在手,天下无敌!

    我的法宝就是:

    lineWidth  设置或返回当前的线条宽度

    怎么用?哥给一个跟金箍棒:

    var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            var timer = null;
            var num = 1;
            ctx.moveTo(150,50);
            ctx.strokeStyle = 'gold';
            setInterval(function(){
                if(num == 100){
                    clearInterval(timer);
                    num=1;    
                }else{
                    num++;    
                };
                ctx.lineTo(150,100+num*2);
                ctx.lineWidth = num;
                ctx.stroke();
            },100)

    金箍棒,大,大,大,大,在大点,哈哈哈~~~

    咳咳,严肃点,有此神器,我们就可以修改任何线框,线条的线条宽度了,比如说空心三角形,空心矩形,当然,空心文字你就不要问我了,我不知道~

     关于线条,还有另外2个属性:

    lineJoin  两线交叉的拐角类型

    参数:

    miter : 尖角 默认

    bevel : 斜角

    round : 圆角

    什么意思,那就用空心矩形为例:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.lineWidth = 10;
    ctx.beginPath();
    ctx.lineJoin = 'miter';
    ctx.strokeRect(100,10,80,80);
    ctx.closePath();
    ctx.beginPath();
    ctx.lineJoin = 'round';
    ctx.strokeRect(100,110,80,80);
    ctx.closePath();
    ctx.beginPath();
    ctx.lineJoin = 'bevel';
    ctx.strokeRect(100,210,80,80);
    ctx.closePath();

       

    右侧为折线效果

    配合折线效果,还有一个属性:

    miterLimit 规定最大斜接长度。什么意思?看看右边的这个折线图,最下面那组的尖尖角,这个就是斜接,意思通俗意思就是规定那个尖尖角的长度,如果尖尖角的长度小于miterLimit 的值,则正常显示,如果大于的话,就会被截掉一部分,其形状就跟lineJoin='bevel'一样一样的,且此方法只对lineJoin="miter" 默认值的时候才起作用,给个形象的例子吧:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.lineWidth=10;
    ctx.lineJoin="miter";
    ctx.beginPath();
    ctx.miterLimit=19;
    ctx.moveTo(20,20);
    ctx.lineTo(150,27);
    ctx.lineTo(20,34);
    ctx.stroke();
            
    ctx.beginPath();
    ctx.miterLimit=18;
    ctx.moveTo(20,120);
    ctx.lineTo(150,127);
    ctx.lineTo(20,134);
    ctx.stroke();

      ctx.beginPath();
      ctx.lineJoin="bevel";
      ctx.moveTo(20,220);
      ctx.lineTo(150,227);
      ctx.lineTo(20,234);
      ctx.stroke();

     

    如图,当miterLimit 的值大于等于19时,尖尖角正常显示,小于18时,尖尖角被截断了,效果跟设置lineJoin='bevel'是一样的,暂不知道会有什么作用,待以后来发掘!

    另一个:

    lineCap  设置或返回线条的结束端点样式  注意,这是设置线条的哦!

    参数:

    butt 默认。向线条的每个末端添加平直的边缘。

    round  向线条的每个末端添加圆形线帽。

    square 向线条的每个末端添加正方形线帽。

    什么意思?线条嘛,我们还是以金箍棒为例,算了,还是用线条吧(看到金箍棒我就想笑了);

    var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            ctx.lineWidth = 10;
            ctx.beginPath();
            ctx.lineCap = 'butt';
            ctx.moveTo(50,50);
            ctx.lineTo(200,50);
            ctx.stroke();
            
            ctx.beginPath();
            ctx.lineCap = 'round';
            ctx.moveTo(50,100);
            ctx.lineTo(200,100);
            ctx.stroke();
            
            ctx.beginPath();
            ctx.lineCap = 'square';
            ctx.moveTo(50,150);
            ctx.lineTo(200,150);
            ctx.stroke();

    可以看到,后面2个比第一个要长一点,具体长多少呢?画一个图示意一下:

    圆角和方脚的原理其实是这样的,很明显多出的一部分的宽度就是线条的一半的长度,所以要精确计算其长度,此小细节需谨记!

    现在我们来讲讲画圆及其相关的图形:

    arc(x,y,r,sAngle,eAngle,counterclockwise)

    什么意思? x,y表示坐标点表示圆心坐标,r表示半径,sAngle表示开始弧度,eAngle表示结束弧度,counterclockwise表示顺时针还是逆时针方式,默认为顺时针false,逆时针为true

    注意,这里的角度是用弧度表示的,不是直接写角度,那问题来了,一般我们知道一个圆弧是多少度,怎么知道它是多少弧度呢?总感觉弧度太抽象,嗯嗯,我也有同感,那我们就来科普一下弧度的算法吧,列几个公式(初中,高中的数学,都还给老师了):

    1弧度 = r;

    360° = 2∏;

    周长C = 2∏r;

    那么一周的弧度数 = 2∏r/r = 2∏ = 360° 

    则1°  =  2∏*1°/360° = ∏*1° /180° (弧度)

    90°  =  ∏*90° /180° (弧度)

    圆的初始位置是在最右边,跟我们自己手绘圆的起点有那么一点点的不一样,默认是顺时针方向,那角度就应该是如图所示的角度,要是还不清楚的话,我们画2半圆,分别表示顺时针和逆时针,这样就应该清楚了,哦,需要说明的一点就是,画用的方法跟画直线和矩形框的原理是一样的,只是画出了路径,并没有添墨水,仍需用黑白双煞:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(80,100,50,0,180*Math.PI/180,false);       
    ctx.stroke();
    ctx.beginPath(); ctx.arc(
    200,100,50,0,180*Math.PI/180,true); ctx.stroke();

    js里面是没有∏的,你懂的,但是有函数Math.PI,咦,这里为什么是圆弧而不是半圆啊,如果我要画一个半圆怎么弄呢?哈哈~,还记得上面三角形的那个折线吗?这个是一个原理,只是图形没有闭合而已,用closePath()就可以闭合了。

    画一个扇形看看,这里我就闭合图形哈:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(80,100,50,30*Math.PI/180,150*Math.PI/180,false);
    ctx.closePath();
    ctx.stroke();

    当当当当~~~

    噗,喷了一口老血,怎么是一条小船,说好的扇子呢?再看看三角图形,瞬间就明白了,图形闭合不是以圆心为起始点的,而是初始弧度为起点,然后闭合的时候是回到初始点,就变成小船了,那怎么才能画出一个扇形呢?给个思路,这里暂时不给代码,以后有时间当小实例给到大家,如果我以圆心为起点,画2条直线,连到圆弧的起始点和结束点,是不是就是一个扇形了,哈哈~,不多说了,脑补一下吧,当然,圆弧的起始点的坐标和结束点的坐标计算还是有点费劲的

    前面我们画的是空心的圆或弧,可否画实心的呢?貌似问的有点多余,上面说了用黑白双煞,好吧,直接给个一饼好了:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.arc(150,150,50,0,360*Math.PI/180,false);
    ctx.fill();

    咦,怎么这么像某岛国国旗,还好我用的是默认黑色,嘘嘘,都没看到哈~

    还有一个方法可以画圆弧:

    arcTo(x1,y1,x2,y2,r) 创建两个切线之间的弧/曲线

    参数:x1,y1 表示第一个坐标,x2,y2表示第二个坐标,r表示曲线半径

    两个切线之间的曲线,试试:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(20,20);          
    ctx.lineTo(100,20);          
    ctx.arcTo(150,20,150,70,50); 
    ctx.lineTo(150,120);        
    ctx.stroke();  

    果然是要在两条线段之间写曲线, 要是先写2条曲线,在写arcTo(),貌似就出不来了,这让我们想到了moveTo(),lineTo(),再写一个例子:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.moveTo(150, 20);
    ctx.arcTo(150,200,50,0,20);
    ctx.stroke();

    想试一下,要是只有一条切线,会怎样?

    好大的一个鱼钩啊,看来这样也是可以的,要是没有切线,可否?

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.arcTo(150,200,50,0,20);
    ctx.stroke();

    额,狗带了,没反应,看来必须至少有一个切线才能画弧线,有个点都行,要求不算高,满足你。

    感觉这里始终没有将清楚,arcTo()为什么会画出这样的曲线呢,我觉得有必要画一张图来表示:

        

    它的绘图原理应该是这样的,起始点是圆弧的第一个切点,也是画笔的起始点,然后arcTo的两个坐标点分别是圆弧的起点和终点,这样3个点就形成了2天相交的线,然后以半径为r画一个圆,与这2条线相切,2个切点就是绘制的这条弧,而第二张图就是arcTo()所绘制的图形,为了证实这一点,我们写一个相近的图形来看看:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.fillRect(100,100,5,5);
    ctx.fillRect(180,80,5,5);
    ctx.fillRect(160,180,5,5);
    ctx.moveTo(62,112);
    ctx.lineTo(182,82);
    ctx.lineTo(162,182);
    //这里是绘制切线弧        
    ctx.moveTo(103,103);
    ctx.arcTo(183,83,162,182,40);
    ctx.stroke();

          

    对比这2组图,将生成的弧线用圆对比一下,会发现起点并不是切点,但基本思路是正确的,3点形成一个夹角,然后以r为圆心,画一个圆,从起点到第二个切点,就是arcTo()方法所绘制的图形。

    今天就到这吧!讲的很混乱,东一脚西一脚的,希望你们能懂!最希望的是能对你们有帮助,那就再好不过了!

  • 相关阅读:
    局域网共享磁盘或文件夹访问
    Android实例-退出程序
    delphi 合并两个 Wav 文件流的函数
    Delphi数据库处理
    cxgrid的FINDPANEL编程
    Python之路【目录】
    Delphi TreeView – 自动展开树形结构
    Delphi TreeView – 自动给标题上加图片
    Delphi 发送邮件 通过Office Outlook
    Delphi Create(nil), Create(self), Create(Application)的区别
  • 原文地址:https://www.cnblogs.com/liugang-vip/p/5364292.html
Copyright © 2020-2023  润新知