您现在的位置是:首页 > 前端学习 > Web前端Web前端

利用canvas绘制图形(第十章)(图文)

第十三双眼睛2020-02-18【Web前端】人已围观

简介绘制图形有很多方法,可以借助flash实现,也可以使用svg和vml来实现。本章学习一种新的方法,使用canvas元素,它是基于HTML5原生的绘图功能。使用canvas元素,可以绘制图形,也可以实现动画,它方便了使用javascript脚本的前端开发人员,寥寥数行代码,就可以在canvas元素中实现各种图像及动画。
本章知识点如下:
1认识canvas元素
2使用canvas绘图
3canvas与javascript之间的绘图

HTML5有一套绘图API,自成体系,javascript就是通过调用这些绘图API来实现绘制图形和动画功能的.
canvas的历史
在HTML5以前的标准中,有一个缺陷,就是不能直接动态的在HTML页面中绘制图形。若要在页面中实现绘图,或者是非常复杂的页面实现,或者是借助第三方工具实现,如Flash,SVG,VML,这种做法无疑是把问题复杂化了。在互联网应用不断的发展中,页面绘图使用的越来越多,在未来的发展趋势上,也需要HTML自己完成绘图功能,canvas元素应运而生。
canvas是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图的API展现给客户端javascript以使脚本能够把想绘制的东西都一次性绘制到一块画布上。canvas的概念最初由苹果公司提出。随后火狐1.5和opera9两款浏览器都开始支持canvas绘图,目前IE9以上的版本也已经支持这项功能。canvas的标准化正由以个web浏览器厂商的非正式协会在推进目前canvas已经成为HTML5草案中一个非正式的标准。

canvas与SVG,VML之间的差异
canvas有一个基于javascript的绘图API,而SVG和VML使用一个xml文档来描述绘图。canvas与svg,vml的实现方式不同,但在实现上可以相互模拟。
canvas有自己的优势,由于不存储文档对象,性能较好,但若要移除画布里的图形元素,往往需要擦掉绘图重新绘制。

就在网页上使用canvas元素,像使用其他标签一样简单,然后利用javascript脚本调用绘图API,绘制各种图形,canvas拥有多种绘制路径,举行,圆形,字符,以及添加图像的方法,还能实现动画。

canvas元素是以标签的形式应用到HTML里面的。在HTML中放入一下代码即可。
<canvas></canvas>
不过,canvas毕竟是个新东西,很多旧的浏览器不支持,为了增加用户体验,可以提供代替文字,放在canvas标签中。如:<canvas>您的浏览器不支持</canvas>
当浏览器不支持时,里面的文字就会显示出来。跟其他标签一样,canvas有一些共同属性,如下:
<canvas id="canvas" width="200" height="70">您的浏览器不支持</canvas>实际效果如下图所示:

使用javascript实现绘图的流程
canvas元素本身没有绘图能力的,所有的绘制工作必须在javascript内部完成,前面讲过,canvas元素提供了一套绘图API,在开始绘图之前,先要获取canvas元素的对象,再获取一个绘图上下文,接下来就可以使用绘图API中丰富的功能了。
1获取canvas对象
再绘图之前,首先要从页面上获取canvas对象,通常使用document.getElementById方法来获取,如下:document.getElementById("canvas")
2创建二维的绘图上下文对象
canvas对象包含了不同类型的绘图API,还需要使用getContext方法来获取,如:
var context = canvas.getContext("2d");
getContext对象是内建的HTML5对象,拥有各种绘制路径,矩形,圆形,字符以及添加图像的方法,参数为2d,说明接下来绘制的是一个二维图形。
3再canvas上绘制
设置文字的字体,颜色,和对齐方式。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>canvas</title>
    </head>
    <body>
        <canvas id="canvas" width="200" height="200" style="border: 1px solid red;">您的浏览器不支持</canvas>
    </body>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var context = canvas.getContext("2d");
        context.font = "98px 黑体";
        context.fillStyle = "#036";
        context.textAlign = "center";
        context.fillText("国",100,130);
    </script>
</html>
效果如下:

绘制矩形
矩形属于一种特殊而又普遍使用的一种图形,矩形的宽和高,确定了矩形的样子,在给予一个绘制起始坐标,就可以确定其位置,这样整个矩形就确定下来了。绘图API为绘制矩形提供了两个专用的方法,strokeRect()和fillRect(),可以分别用于绘制矩形边框和填充矩形区域,通常在绘制之前,需要先设置样式,再进行绘制。
1设置样式
关于矩形可以设置的样式有,边框颜色,边框宽度,填充颜色等具体如下:
strokeStyle:设置线条的颜色
lineWitdth:设置线条的宽度,默认宽度为1,单位是像素。
fillStyle:设置区域或文字的填充颜色
其中strokeStyle可以设置矩形边框的颜色,lineWidth可以设置边框的宽度,fillStyle可设置填充颜色。
2绘制矩形边框
绘制矩形边框需要使用strokeRect方法,其语法如下:content.strokeRect(x,y,width,height);
这里仅仅绘制了矩形的边框,且边框的颜色和宽度由属性strokeStyle和lineWidth来指定
3绘制矩形区域
绘制填充矩形区域需要用fillRect()方法,其语法如下:context.fillRect(x,y,width,heith)
该方法的参数和strokeRect是一样的.
例子:绘制一个黄色的矩形,边框为黑色。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形</title>
    </head>
    <style>
        canvas{
            border: 1px solid black;
            width: 200px;
            height: 150px;
        }
    </style>
    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var context = canvas.getContext("2d");
        context.strokeStyle="#ccc";
        context.fillStyle="#f90"
        context.lineWidth=1;
        context.fillRect(50,50,70,50);
    </script>
</html>


效果如下:

再绘制的过程中,stroke是用来绘制边框的,fillRect是用来绘制填充的。
特殊的绘制矩形的方式
除了本节介绍的两个与绘制矩形的方法外,还有一个方法clearRect,执行该方法,将会擦除指定区域,使其变得透明,使用方法如下:
context.clearRect(x,y,width,height);
使用路径
路径就是预先构建得图像轮廓,它由一个或多个直线段或曲线段构成,可以是开放得,也可以是闭合得。在很多绘图工具或方法中都会使用。
在canvas中,所有基本图形都是以路径为基础得,我们通常会调用lineTo(),rect(),arc(),等方法来设置一些路径,在最后使用fill()或者stroke()方法进行绘制边框或填充区域时,都是参照这个路径来进行得。使用路径基本上分为3个步骤;
1创建绘图路径
2设置绘图样式
3绘制图形
创建绘图路径经常会用到两个方法,beginPath()和closePath,分别表示开始一个路径和关闭当前路径,首先,使用beginPath()方法创建一个新的路径,该路径是以一个子路径的形式存储的,他们共同构成一个图形,每次调用beginPath方法,都会产生一个新的路径。使用方法如下:context.beginPath();
最会使用closePath()关闭当前路径:context.closePath();
设置绘图样式包括边框样式和填充样式,其形式如下:
1)使用strokeStyle属性设置矩形边框的颜色,设置边框颜色为黑色
context.strokeStyle="";
2)使用lineWidth属性设置边框宽度,设置边框宽度为3像素
context.lineWidth="3"
3)使用fillStyle属性设置填充颜色,设置填充颜色为橘黄色
context.fillStyle="";
绘制图形
路径和样式都设置好了,最后就是调用stroke方法绘制边框,或调用fill填充区域。
context.stroke();//绘制边框
context.fill();填充区域
实例:绘制一个圆形和矩形叠加的图形
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形和圆形叠加的图形</title>
        <style type="text/css">
            canvas{
                width: 300px;
                height: 300px;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var context = canvas.getContext("2d");
        context.beginPath();
        context.arc(150,100,50,0,Math.PI*2,true);
        context.rect(50,50,100,100);
        context.closePath();
        
        context.strokeStyle="#000";
        context.lineWidth="3";
        context.fillStyle="#f90";
        
        context.stroke();
        context.fill();
    </script>
</html>

效果如下:

深入理解路径特性
在创建子路径的三个步骤中,展示的是一个标准的子路径创建过程,如果绘制复杂的图形,标准化的方法有利于代码的规范和管理。
(1)理解一下beginPath的作用
使用beginPath方法,可以新建立一个路径,接下来的绘制都是针对该子路径进行的。如果不使用该方法,那么设置的路径和前面的路径设置默认为同一个路径设置,在接下来的绘制中,前面设置的路径会被重复赋值。
(2)再来理解一下closePath()方法的作用
closePath方法是用来闭合路径的,如果前面设置的路径是开放的,closePath方法会自动用直线连接终点和起点,同样,使用路径的方法绘制两条直线,使用moveTo(x,y)方法设置当前坐标,使用lineTo(x,y)方法为当前子路径添加一条直线。

图形组合
通常,把一个图形绘制在另外一个图形之上,称之为图形组合,默认的情况是上面的图形覆盖了下面的图形,这也是图形组合默认的设置了source-over
在canvas中,可以通过context.globalCompositeOperation来设置如何在画布上组合颜色,总共有12种类型。语法如下:
context.globalCompositeOperation = [value];
参数说明:
参数value的合法值由12个,决定了12种图形组合类型,默认值是source-over;
copy:只绘制新图形,删除其他内容
darker:在图形重叠的地方,颜色由两个颜色值相减后决定
destination-atop:已有的内容只有在它和新的图形重叠的地方保留,新图形绘制与内容之后
destination-in:在新图形及已有画布重叠的地方,已有内容都保留,其他内容成为透明。
destination-out:在已有内容和新图形不重叠的地方,已有内容保留,所有其他内容成为透明。
destination-over:新图形绘制于已有内容的后面
lighter:在图形重叠的地方,由两种颜色值的加值来决定
source-atop:只有在新图形和已有内容重叠的地方,才绘制新图形
source-in:在新图形和已有内容重叠的地方,才绘制新图形,所有其他内容成为透明。
source-out:只有在和已有图形不重叠的地方,才绘制新图形
source-over:新图形绘制与已有图形的顶部,是默认值
xor:在重叠和正常绘制的其他地方,图形都是透明的
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制矩形和圆形叠加的图形</title>
        <style type="text/css">
            canvas{
                width: 400px;
                height: 300px;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //source-over
            context.globalCompositeOperation="source-over";
            RectArc(context);
            
            //lighter
            context.globalCompositeOperation="lighter";
            context.translate(90,0);
            RectArc(context);
            
            //xor
            context.globalCompositeOperation="xor";
            context.translate(-90,90);
            RectArc(context);
            
            //destination-over
            context.globalCompositeOperation="destination-over";
            context.translate(90,0);
            RectArc(context);
        }
        
        function RectArc(context){
            context.beginPath();
            context.rect(10,10,50,50);
            context.fillStyle="#f90";
            context.fill();
            context.beginPath();
            context.arc(60,60,30,0,Math.PI*2,true);
            context.fillStyle="#0f0";
            context.fill();
        }
        
        window.onload = draw();
    </script>
</html>


运行结果如下:

绘制曲线
在实际的绘图种,绘制曲线是很常用的一种绘制方式,我们在设置路径的时候,需要使用一些曲线方法来勾勒除线圈的路径,以完成曲线的绘制,在canvas种中绘图API提供了多种曲线绘制方法,主要的绘制方法有acr(),arcTo(),quadraticCurveTo(),bezierCurveTo()等,
1使用中心点和半径绘制弧线arc()方法
在上节中,我们已经在应用arc方法绘制圆形,该方法是使用中心和半径,为一个画布的当前添加一条弧线,语法如下:
context.arc(x,y,radius,startAngle,endAngle,counterclockwise);
参数说明,x和y表示圆心的坐标,radius描述圆的半径,startAngle表示开始的角度,endAngle表示结束角度,counterclockwise表示方向,true表示逆时针方向,false表示顺时针方向。
实例:绘制一段弧线
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制曲线</title>
    </head>
    <body>
        <canvas id="canvas" width="300" height="300" ></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            context.beginPath();
            context.arc(150,100,50,0,(-Math.PI*2/3),true)
            context.fillStyle="rgba(0,0,0,0.1)";
            context.fill();
            context.beginPath();
            context.arc(150,100,50,0,(-Math.PI*2/3),true)
            context.strokeStyle="rgba(255,135,0,1)";
            context.lineWidth=5;
            context.stroke();
        
        }
        window.onload = huizhi();
    </script>
</html>


实际效果如下图所示:

使用辅助线绘制弧线acrTo方法()
arcTo()方法是使用切线的方法绘制弧线,使用两个目标点和一个半径,为当前的子路径添加一条弧线,于arc方法相比较,同样是绘制弧线,但绘制思路和侧重带你不一样语法如下:context.arcTo(x1,y1,x2,y2,radius);
参数说明:x1,y1描述了一个坐标点,用P1表示,x2,y2描述了另一个点,用P2表示,radius描述圆弧的半径,然后指定起点和圆形,就能绘制一段与两条线段相切的圆弧。
例子:用辅助前绘制一段圆弧
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>用辅助线绘制圆弧</title>
    </head>
    <body>
        <canvas id="canvas" width="300" height="300"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //绘制辅助线
            context.beginPath();
            context.moveTo(80,120);
            
            context.lineTo(150,60);
            context.lineTo(180,130);
            context.strokeStyle="rgba(0,0,0,0.4)"
            
            context.lineWidth=2
            context.stroke();
            
            //绘制一段圆弧
            context.beginPath();
            context.moveTo(80,120);
            context.arcTo(150,60,180,130,50);
            context.strokeStyle="rgba(255,135,0,1)";
            context.stroke();
            
            
        }
        window.onload = huizhi();
    </script>
</html>


效果如下:

绘制二次样条曲线
二次样条曲线是曲线的一种,canvas绘图API专门提供了此种曲线的绘制方法,context.quadraticCurveTo()方法为当前的子路径添加一条二次样条曲线。语法如下:
context.quadraticCurveTo(cpX,cpy,x,y)
参数说明:cpX,cpY描述了控制点的坐标,x,y描述了曲线的终点坐标。起点即当前的位置,控制点又参数cpX,cpY确定,终点由参数x,y确定。
例子:绘制二次样条曲线
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制二次样条曲线</title>
    </head>
    <body>
        <canvas id="canvas" width="300" height="300"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //绘制辅助线段
            context.beginPath();
            context.moveTo(100,180);
            context.lineTo(200,50);
            context.lineTo(300,200);
            context.strokeStyle="rgba(0,0,0,0.4)";
            context.lineWidth=3;
            context.stroke();
            
            //绘制曲线\n
            context.beginPath();
            context.moveTo(100,180);
            context.quadraticCurveTo(200,50,300,200);
            context.lineWidth=3;
            context.strokeStyle="rgba(255,135,0,1)";
            context.stroke();
            
        }
        window.onload=huizhi();
    </script>
</html>


实际效果如下所示:

绘制贝济埃曲线
贝济埃曲线,是应用于二维图形应用程序的数学曲线,canvas绘图API也提供了贝济埃曲线的绘制方法,context.bezierCurveTo(),与二次样条曲线相比,贝济埃曲线使用了两个控制点,使读者可以创建更复杂的曲线,语法如下:context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
参数说明:
cp1x,cp1y为第一个控制点的坐标,cp2x,cp2y为第二个控制点的坐标,x,y为曲线终点的坐标。
例子:绘制贝济埃曲线
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制贝济埃曲线</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400">
            
            
        </canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //绘制辅助线
            context.beginPath();
            context.moveTo(100,180);
            context.lineTo(110,80);
            context.moveTo(260,100);
            context.lineTo(300,200);
            context.strokeStyle="rgba(0,0,0,0.4)";
            context.lineWidth=3
            context.stroke();
            
            //绘制曲线
            context.beginPath();
            context.moveTo(100,180);
            context.bezierCurveTo(110,80,260,100,300,200);
            context.lineWidth=3;
            context.strokeStyle="rgba(255,135,0,1)";
            context.stroke();
            
        }
        
        window.onload=huizhi();
    </script>
</html>



实际效果如下所示:

使用图像
有的时候,需要借助一些现有的图片,以便绘图更加灵活和方便,在canvas中,绘图API已经提供了插入图像的方法,只需几行代码就能将图像绘制到画布上。使用drawImage()方法可将图像添加到canvas中,即绘制一幅图像,该方法有三个重载的方法。
1把整个图像绘制到画布上将其放在指定点的左上角,并且将整个图像像素映射到画布坐标系统的一个单元。语法如下:
drawImage(image,x,y);
参数说明,image表示要绘制的图像,x,y表示要绘制的左上角的位置。
2把整个图像复制到画布上,但是允许用画布单位来指定图像的宽度和高度,语法如下:
drawImage(Image,x,y,width,height);
参数说明,image是要绘制的图像,x,y表示要绘制的图像的左上角的位置,width和height表示图像应绘制的尺寸,指定这些参数可以使得图像得以缩放。
3此方法完全是通用的,它允许指定图像的任何矩形区域并复制它,对画布中的任何位置都可以进行缩放,语法如下:
context.drawImage(image,sourcex,sourcey,sourcewidth,sourceheight,destx,desty,destwidth,destheight)
参数说明:image表示所要绘制的图像,sourceX,sourceY表示图像要被绘制的位置的左上角,这些参数都用像素来衡量,sourcewidth,sourceheight表示图像所要绘制的区域的大小,用图像像素表示,destX,destY表示要绘制的图像区域的左上角的画布坐标,destwidth,destheight表示图像区域所要绘制的画布大小。
以上三个方法中的参数image都表示所要绘制的图像对象,必须是image对象或canvas元素,一个image对象能够表示文档中的一个img标签或者使用Image()函数构造的一个屏幕外图像。
三个方法中,第一个使用的参数最少,所以最简单,功能也最少,第二种方法复杂一些,功能仍然受限,第三种方法使用的参数最多最复杂,能对图像进行裁剪。
例子:使用三种方法进行图形绘制
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>使用三个方法绘图</title>
    </head>
    <body>
        <canvas id="canvas" width="800" height="800"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var newImg = new Image();
            newImg.src="./img/1.jpg";
            newImg.onload = function(){
                context.drawImage(newImg,0,0);
                
                context.drawImage(newImg,250,100,150,200);
                
                context.drawImage(newImg,90,80,100,100,0,0,120,120);
            }
        }
        
        window.onload = huizhi();
    </script>
</html>


效果如下图所示:

裁剪区域
在路径绘图种,我们使用了两大绘图方法,即用于绘制线条的stroke方法和用于绘制填充区域的fill方法,关于类路径的处理,还有一种叫做裁剪方法clip();
说起裁剪,大多会想到裁剪图片,即保留图片的一部分,但是裁剪的实现方法也是另一种思维。
裁剪区域,是通过路径来实现的,和绘制线条的方法和填充区域的方法一样,也需要预先确定绘图路径,再执行裁剪路径方法clip();这样就确定了裁剪区域,裁剪区域的语法如下:
clip();
例子:使用裁剪区域绘图
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>裁剪区域</title>
    </head>
    <body>
        <canvas id="canvas" height="400" width="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
        var context = canvas.getContext("2d");
        var newImg = new Image();
        newImg.src = "./img/1.jpg";
            newImg.onload = function(){
                ArcClip(context);
                context.drawImage(newImg,0,0);
                context.globalAlpha=0.6;
                fillRect(context);
            }
        }
        
        //设置一个圆形的裁剪区
        function ArcClip(context){
            context.beginPath();
            context.arc(150,150,100,0,Math.PI*2,true);
            context.clip();
        }
        
        //使用路径绘制矩形
        function fillRect(context){
            context.beginPath();
            context.rect(150,150,90,90);
            context.fillStyle="#f90";
            context.fill();
        }
        
        window.onload = huizhi();
    </script>
</html>


效果如下图所示:

从上图来看,裁剪之后的任何绘制,都局限再裁剪区域内部,如果想取消裁剪区域,可以再裁剪预取前先调用save方法保存当前上下文状态,再绘制玩剪裁图像后,再调用restore方法恢复之前保存的上下文状态,这样就去除了剪裁区域,再接下来的绘制中,就不会受到裁剪区域的限制了。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>恢复剪裁区域</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var newImg = new Image();
            newImg.src="./img/1.jpg";
            newImg.onload = function(){
                context.save();
                ArcClip(context);
                context.drawImage(newImg,0,0);
                context.restore();
                context.globalAlpha=0.6
                fillRect(context);
            }
            
        }
        //设置一个圆形的裁剪区
        function ArcClip(context){
            context.beginPath();
            context.arc(150,150,100,0,Math.PI*2,true);
            context.clip();
        }
        
        //使用路径绘制矩形
        function fillRect(context){
            context.beginPath();
            context.rect(150,150,90,90);
            context.fillStyle="#f90";
            context.fill();
        }
        
        window.onload = huizhi();
    </script>
</html>



效果如下图所示:

绘制渐变
渐变是一种很普遍的视觉现象,能带来视觉上的舒适感。再canvas中,绘图API提供了两个原生的渐变方法,包括线性渐变和径向渐变。渐变,再颜色上使用了逐步抽象的算法,可以应用在描边样式和填充样式中。使用渐变需要3个步骤,首先是创建渐变对象,其次是设置渐变颜色和过度方式,最后将渐变对象赋值给填充样式或者描边样式。
绘图API提供了两种渐变的创建方法,创建线性兼并的context.createLinearGradient()方法和创建径向渐变的context.createRadialGradient()方法,
1创建线性渐变对象
线性渐变,是指起点和终点之间线性的内插颜色值,创建线性渐变的语法如下所示:
context.createLinearGradient(xstart,ystart,xend,yend);
参数说明:xstart,ystart表示渐变的起点和终点的坐标,xend和yend是表示渐变的结束点的坐标。返回一个渐变对象
2创建径向渐变对象
径向渐变,是指两个指定圆的圆周之间放射性的插值颜色。创建径向渐变的语法如下所示:
context.createRadialGradient(xstart,ystart,radiusstart,xend,yend,radiusend);
参数说明:xstart,ystart,表示开始圆的圆心坐标,radisstart表示开始圆的半径。xend,yend表示结束圆的圆心坐标,radiusend表示结束圆的半径。返回一个渐变对象gradient
3设置渐变颜色和过度方式
设置渐变颜色,需要在渐变对象上使用addColorStop方法,在渐变中的某一点添加一个颜色变化。语法如下:
addColorStop(offset,color);
参数说明:offset是一个范围在0-1之间的浮点值,表示渐变的开始点和结束点之间的一部分,offset为0对应开始点,offset为1对应结束点,color是一个颜色值,表示在指定offset显示的颜色。
4将渐变对象赋值给填充样式或者描边样式
描边样式strokeStyle和填充样式fillStyle,都可以使用渐变对象,当样式被赋值为渐变对象时,绘制出来的描边和填充都会有渐变效果。
例子:绘制线性渐变的矩形
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制线性渐变的矩形</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400">
            
        </canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //创建渐变对象,线性渐变,
            var grad = context.createLinearGradient(0,0,300,0);
            grad.addColorStop(0,"#f90");
            grad.addColorStop(1,"#0f0");
            context.fillStyle=grad;
            context.fillRect(0,0,300,80);
        }
        window.onload = huizhi();
    </script>
</html>


具体效果如下所示:

绘制径向渐变的矩形
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制径向渐变的矩形</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var grad = context.createRadialGradient(50,50,0,100,100,90);
            grad.addColorStop(0,"#0f0");
            grad.addColorStop(1,"#f90");
            context.fillStyle=grad;
            context.beginPath();
            context.arc(100,100,90,0,Math.PI*2,true);
            context.fill();
        }
        window.onload = huizhi();
    </script>
</html>


具体效果如下图所示:

描边属性
描边的过程也是绘制线条的过程,绘制出来的图像是有一定宽度的带颜色的线条,描边常用的属性,除了属性lineWidth,和strokeStyle之外,还包括线条末端的控制属性,lineCap,线条之间的连接属性,lineJoin和miterLimit
1线条宽度属性lineWidth
描述了画笔的操作的线条宽度,并且这个属性必须大于0.0,较宽的线条在路径上居中,每边有线条宽的一半。语法如下:
lineWidth=4;
参数说明,参数value为数字,单位为像素,默认为1
2线条样式属性strokeStyle
描述了画笔操作的线条样式,该样式可以设置颜色,渐变和模式。语法如下:
strokeStyle = [value];
参数说明:参数value可以设置为字符串表示的颜色,也可以是一个渐变对象,也可以是模式对象。
3线帽属性lineCap
描述了线的末端如何绘制,语法如下:lineCap = [value];
参数说明:参数value的值可以是butt,round,square,默认值是butt,当线条有一定的宽度了,才能表现出各自的差异。
butt:定义了线段没有线帽。
round:定义了线段的末端为一个半圆形的线帽,半圆的直径等于线段的宽度,并且线段在断点之外扩展了线段宽度的一半。
square:定义了线段的末端为一个矩形的线帽,这个值和butt有同样的形状效果,但是先对的长度扩展了宽度的一半。
4线条的连接属性
描述了两条线段的连接方式;语法如下:
lineJoin = [value];
参数说明:参数value的值有以下取值,round,bevel,miter,默认值是miter,当一个路径包含了线段或者曲线相交的情况时,lineJoin属性可以表现为这些交点的连接方式,不过只有当线条较宽的时候,才能表现出不同连接方式的差异。
miter:定义了两条线段的外边缘一直延申到他们相交,当两条线段以锐角相交,连接的地方可能会延长到很长。
round:定义了两条线段的外边缘应该和一个填充的弧形结合,这个弧的直径等于线段的宽度。
bevel:定义了两条线段的外边缘应该和一个填充的三角形相交。
5扩展的线条连接属性miterLimit
进一步描述了如何绘制两条线段的交点。
miterLimit = [value];
参数说明:当线条的lineJoin属性为miter时,并且两条线段以锐角相交时,连接的地方可能会很长,miterLimit可以为该延申的长度作一个限制,这个属性可以表示延申到长度和线条长度的比值,默认是10,表示延申长度不能超过线条宽度的10倍。当属性lineJoin的值为round或者bevel时,属性miterLimit是无效的。

模式
模式是一个抽象的概念,描述的是一种规律,在canvas中,通常会为贴图图像创建一个模式,用于描边样式和填充样式,可以在绘制出带图案的边框和背景图。在canvs中,模式是一个对象,使用createPattern()方法可以为贴图图像创建一个模式,语法如下:context.createPattern();
参数说明:image是一个贴图图像,可以是一个图形图像,也可以是一个canvas对象,repetitonStyle描述了该贴图图像的循环方式,在四个值分别为repeat,repeat-x,repeat-y,no-repeat,repeat表示图像在各个方向上循环平铺,repeat-x,表示图像在x方向上平铺,repeat-y表示图像在纵向上平铺,no-repeat表示不平铺。
例子:用贴图模式填充矩形
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>模式</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var img = new Image();
            img.src="img/1.jpg";
            img.onload=function(){
                var pattern = context.createPattern(img,"repeat");
                context.fillStyle = pattern;
                context.fillRect(0,0,300,200);
            }
        }
        window.onload = huizhi();
        
        
    </script>
</html>


效果如下图所示:

变换
在绘图的过程中,如果一种形状的图形要绘制很多次,显然是增加了复杂性,canvas提供了多种变换方法,为实现复杂的绘图操作提供了便捷的方法,常见的变换方法包括平移,缩放,旋转和变形等。
在默认情况下,canvas的坐标控间是以左上角为原点 ,x值向右增加,y值向下增加,坐标空间中的一个单位同行转换为像素,也就是说,坐标空间默认包含了一些基本属性,所以,可以把变换理解为,改变了坐标空间的一些属性设置。
1移动变换
移动变换,是将整个坐标系统设置一定的偏移数量,绘制出来的图像也会跟着便宜,为坐标系统添加水平和垂直的偏移。实现移动,语法如下:
context.translate(x,y);
参数说明.x为水平方向上的偏移,y为垂直方向上的偏移。添加偏移后,会将偏移量符加在后续的所有坐标点上。
2缩放变换
缩放变换是将整个坐标系统设置一个缩放因子,绘制出来的图像会响应的缩放,作坐标系同添加一个缩放变换,设置独立的水平方垂直方向的缩放因子。语法如下:
context.scale(x,y);
参数说明,x为水平方向上的缩放因子,y为垂直方向上的缩放因子,都为大于0的数字,大于1时,为放大图像,小于1时,为缩小图像。
3旋转变换
旋转变换是将整个坐标系统设置一个旋转的角度,绘制出来的图像会响应的旋转,为坐标系统指定一个旋转的角度,绘制出来的图像也会作相应的旋转,即实现了图像的旋转变换,语法如下:context.rotate(angle);
参数说明:angel是旋转的量,用弧度表示,正值表示顺时针方向旋转,负值表示逆时针方向旋转,旋转的中心为坐标系统的远点。
4矩阵变换
通过使用矩阵,可以让图形变形更加复杂,在默认绘图的坐标系统中,事实上存在一个默认的矩阵,当我们对这个矩阵进行修改时,就会造成图像的变形,矩阵变换的语法如下:context.transform(m11,m12,m21,m22,x,y);
参数说明:该方法中的6个参数,组成一个变形矩阵,于当前矩阵进行乘法计算,形成新的矩阵系统。该变形矩阵的形式如下:
m11        m21      x
m12        m22      y
0             0           1
前面讲过3种变换,其实都可以看作矩阵变换的特例。
移动,也可以使用context.transform()1,0,0,1,x.y;或者context.transform(0,1,1,0,x,y );来实现
缩放,也可以使用context.transform(x,0,0,y,0,0);或者context.transform(0,y,x,0,0,0,);来实现
旋转,也可以使用context.transform(cosA,sinA,-sinA,cosA,0,0);或者context.transform(-sinA,cosA,cosA,sinA,0,0);来实现



使用文本
在canvas种,也可以绘制文本,可以使用填充的方法绘制,也可以使用描边的方式绘制,并在绘制文字之前,还可以设置文字的字体样式和对齐方式,绘制文本有两个方法,分别时填充绘制方法和描边绘制方法,语法如下:
context.fillText(text,x,y,maxwidth);
context.strokeText(text,x,y,maxwidth);
参数说明,text为要绘制的文本,参数x表示文字位置的横坐标,参数y为绘制文字的纵坐标,,参数maxWidth为可选参数,表示显示文本的最大宽度,防止文本的溢出。
绘制文本之前,可以先对样式进行设置,绘图API提供了专门用于设置文本样式的属性,可以设置文本的字体,大小,类似于css的字体属性,也可以用于设置对齐方式,包括水平方向上对齐和垂直方向上对齐。相关属性如下:
font                                               css样式字符串                                                                     设置字体样式
textAlign                                       start end left right center                                                  设置水平对齐方式,默认start
textBaseline                                  top hanging  middle  alphabetic  ideographic bottom    设置垂直对齐方式,默认alphabetic
实例:绘制文本
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>绘制文本</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //填充方式绘制文本
            context.fillStyle="#f90";
            context.font="bold 36px impact";
            context.fillText("hello world",10,50);
            
            context.strokeStyle="#f90";
            context.font="bold italic 36px impact";
            context.strokeText("hello world",10,100);
        }
        window.onload = huizhi();
    </script>
</html>



有时候需要知道文本的宽度,以方便布局,绘图API提供了专门的方法,语法如下:
context.measureText(text);
参数说明:text表示要绘制的文本,该方法会返回一个TextMetrics对象,表示文本的空间度量,可以通过该对象的width属性获取文本的宽度。
实例:度量的绘制文本
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>度量的绘制文本</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var txt ="hello world";
            //以填充方式绘制文本
            context.fillStyle="#f90";
            context.font="bold 30px impact";
            var tm = context.measureText(txt);
            context.fillText(txt,10,50);
            context.fillText(tm.width,tm.width+150,50);
            
            context.strokeStyle="#f90";
            context.font="bold italic 36px impact";
            tm = context.measureText(txt);
            context.strokeText(txt,10,100);
            context.strokeText(tm.width,tm.width+15,100);
        }
        window.onload = huizhi();
    </script>
</html>




阴影效果
阴影效果可以增加图像的立体感,为图像添加阴影效果,可以利用绘图API提供的绘制阴影的属性,阴影属性不会单独绘制阴影,只需要在绘制任何图像之前,添加阴影属性,就能绘制出带有阴影效果的图像,设置阴影的属性有四个,如下所示:
shadowColr   符合css规范的值      可以使用半透明颜色
shadowOffsetX  数值     阴影的横向偏移量,向右为正,向左为负
shadowOffsetY 数值     阴影的纵向偏移量,向下为正,向上为负
shadowBlur   数值   高斯模糊,值越大,阴影边缘越模。
例子:文字和图像添加阴影
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>文字和图像添加阴影</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            context.shadowColor="#666";
            context.shadowOffsetX=5;
            context.shadowOffsetY=5;
            context.shadowBlur=5.5;
            //绘制文本
            context.fillStyle="#f90";
            context.font="bold 36px impac";
            context.fillText("hello world",10,50);
            //路径绘制图形
            context.fillStyle="#f90";
            context.arc(100,100,30,0,Math.PI*2,false);
            context.fill();
        }
        window.onload = huizhi();
    </script>
</html>


效果如下图所示:

状态的恢复于保存
在裁剪区域的一节种,介绍了去除裁剪区域的内容,就是通过保存和恢复图像状态来实现的,在绘图过程种,绘图状态会不断改变,如果某个状态需要多次使用,可以保存这个状态,在需要的时候,把需要的状态恢复。
绘图API提供了状态保存方法,和恢复方法,分别用于绘图状态的保存于恢复使用,使用方法比较简单,语法如下:
save();
restore();
状态的保存和恢复是通过数据站栈进行的,当调用save方法时,当前的状态会保存到数据栈里,当调用restore方法时,会取出最后一次保存到数据栈里面的数据,即恢复最后一次保存的状态。
其中绘图的状态由以下几个因素决定
1左边系统的变换,平移,缩放,旋转与矩阵变形。
2绘图API提供的所有属性,
3裁剪的区域。
实例:状态的保存于恢复
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>状态的保存于恢复</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            //设置填充颜色
            context.fillStyle="#0f0";
            context.save();
            context.fillStyle="#f90";
            context.beginPath();
            context.rect(10,10,90,90);
            context.fill();
            
            //恢复状态
            context.restore();
            //填充一个圆形区域
            context.beginPath();
            context.arc(100,100,50,0,Math.PI*2,true);
            context.fill();
        }
        window.onload = huizhi();
    </script>
</html>


效果如下图所示:

像素操作
在canvas种,绘图API还提供了像素级的操作方法,分别是:
context.createImageData();
context.getImageData();
context.putImageData();
使用这些方法,可以直接操作底层的像素数据,这里还使用了一个图像数据对象ImageData
1ImageData对象
在处理像素数据的过程种,该对象为一种处理的媒介,保存了可以操作的图像像素数据,细致的图像操作,就是在对象ImageData中进行的。
该对象由3个属性,width,height,data,其中width表示每行有多少个像素,height表示有多少行像素。data是一个一维数组,保存了所有像素的颜色值,按照从左到右,从上到下依次存储。
关于颜色值,每个像素的颜色值包括四个数字,分别代表红,绿,蓝和透明度,各个数字值得范围均为0-255,包括透明度得值也是这个范围。
2获取图像数据得方法
getImageData()
从canvas中获取图像数据,语法如下:getImageData(x,y,w,h);
参数说明:x,y表示获取区域得起点横坐标和纵坐标,w,h分别表示所获取区域得宽度和高度,返回得结果是一个ImageData对象。
3绘制图像数据方法putImageData()
将处理好的图像数据绘制到canvas中,语法如下:
putImageData(imageData,x,y,dirx,diry,dirw,dirh);
参数说明:该方法有3个必须参数和4个可选参数,imageData为imageData对象,包含了图像数据,x,y表示绘制的起点的横坐标和纵坐标,可选参数表示了一个矩形,如果加上这四个参数,绘制的图像仅仅在该矩形范围内,类似一个裁剪的区域。
4创建图像数据的方法createImageData()方法
直接创建一组空的图像数据:方法如下:
createImageData(w,h);
w表示宽度,h表示高度
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>图像的底片效果</title>
    </head>
    <body>
        <canvas id="canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript">
        function huizhi(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var newImg = new Image();
            newImg.src="img/1.jpg";
            newImg.onload = function(){
                context.drawImage(newImg,0,0,400,300);
                context.save();
                var imageData = context.getImageData(0,0,400,300);
                for(var i=0;i<imageData.length;i++){
                    //红色部分
                    imageData.data[i+0]=255-imageData.data[i+0];
                    //绿色部分
                    imageData.data[i+1]=255-imageData.data[i+1];
                    //蓝色部分
                    imageData.data[i+2]=255-imageData.data[i+2];
                }
                context.putImageData(imageData,200,150);
            }
        }
        window.onload=huizhi();
    </script>
</html>



效果如下图所示:

直接操作像素,通过ImageData可以完成很多功能,除了上面实例的底片效果,还可以实现诸如图像滤镜,数学可视化等特效。
在canvas中实现动画
在canvas中,除了常规的一些绘图,还能开发一些动画,甚至是游戏,而这一切动画的实现,除了充分利用canvas绘图API,还需要javascript功能。
在canvas中,动画是通过一系列的连续画面按顺序呈现的。而这些连续的动画,是通过及时绘制出来的,为了动画更加流畅,可能在很短的时间内绘制很多次,动画的实现流程大致分为以下几步:
1清空画布
2改变绘图的状态
3重新绘制图形
4回到第一步
在上面几个步骤里,需要将绘制动作放在一个定时器里,javascript提供了两个定时器方法,分别是,setInterval(code,millesec)和seteTimeOut(code,millsec)
动画1:绘制一个碰碰球
现在,就利用学过的知识来绘制一个简单的碰碰球,这个动画中,球在画布中不停的移动,当碰到边界时,改变球的颜色,并弹回去。如此循环。同时给出开始和暂停按钮。以便在画布之外控制动画。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>动画</title>
        <style type="text/css">
            canvas{
                border-top: 2px solid #f00;
                border-right: 2px solid #f90;
                border-left: 2px solid blue;
                border-bottom: 2px solid green;
            }
        </style>
    </head>
    <body>
        <div align="center">
            <canvas id="canvas" width="400" height="300">您的浏览器不支持</canvas>
            <input onclick="animation.start()" value="开始" type="button"/>
            <input onclick="animation.pause()" value="暂停" type="button" />
        </div>
    </body>
    <script type="text/javascript">
        //定义一个动画对象
        var animation = {};
        animation.interval = null;
        animation.x=100;
        animation.y=50;
        animation.xstep=2;
        animation.ystep=2;
        animation.radius=15;
        animation.color="red";
        animation.delay=10;
        
        //添加upate方法
        animation.update = function(width,height){
            this.x += this.xstep;
            this.y +=this.ystep;
            
            if(this.x<this.radius){
                this.x = this.radius;
                this.xstep= -this.xstep;
                this.color="blue";
            }
            if(this.x+this.radius>width){
                this.x = width-this.radius;
                this.xstep=-this.xstep;
                this.color="#f90";
            }
            if(this.y<this.radius){
                this.y = this.radius;
                this.ystep=-this.ystep;
                this.color="red";
            }
            if(this.y+this.radius>height){
                this.y=height-this.radius;
                this.ystep=-this.ystep;
                this.color="green";
            }
        }
        
        animation.draw=function(){
            var canvas = document.getElementById("canvas");
            var width = canvas.getAttribute("width");
            var height = canvas.getAttribute("height");
            var context = canvas.getContext("2d");
            context.save();
            context.clearRect(0.,0,width,height);
            this.update(width,height);
            context.fillStyle=this.color;
            context.translate(this.x,this.y);
            context.beginPath();
            context.arc(0,0,this.radius,0,Math.PI*2,true);
            context.fill();
            context.restore();
            
        }
        
        animation.pause=function(){
            clearInterval(this.interval);
        }
        animation.start=function(){
            this.pause();
            this.interval= setInterval("animation.draw()",this.delay);
        }
    </script>
</html>


效果如下图所示:




 

Tags:HTML   canvas   图形绘制

很赞哦! ()

随机图文

文章评论

    共有条评论来说两句吧...

    用户名:

    验证码:

本站推荐

站点信息

  • 网站名称:JavaStudy
  • 建站时间:2019-1-14
  • 网站程序:帝国CMS7.5
  • 文章统计64篇文章
  • 标签管理标签云
  • 统计数据百度统计
  • 微信公众号:扫描二维码,关注我们