创建 canvas

首先创建一个canvas元素,我们只需要在html文件中加入这么一句代码:

  1. <canvas id="canvas">当前浏览器不支持canvas,请更换浏览器使用!</canvas>

同时我们也可以通过canvas的标签属性width和height设置canvas画布的大小:

  1. <canvas id="canvas" width="800" height="800">当前浏览器不支持canvas,请更换浏览器使用!</canvas>

当然,我们也可以通过js来设置canvas的宽高,下文会提到如何设置。

接下来我们就在js中获取到该canvas元素,然后设置它的宽高,并获取到上下文的环境:

  1. var canvas = document.getElementById("canvas");//获取到canvas元素
  2. //设置宽高
  3. canvas.width = 800;
  4. canvas.height = 800;
  5. var context = canvas.getContext("2d");//获取上下文的环境

接下来我们的所有操作都是基于这个context的上下文环境。

现在画一条简单的直线:

  1. context.moveTo(100,100);
  2. context.lineTo(500,500);

moveTo()方法表示一次绘制的起点坐标,lineTo()表示基于上一个坐标点到这个坐标点之间的直线连接。

注意的是,canvas是基于状态的绘制,而不是基于对象的绘制。所以,上面代码都是状态的设置,我们还需要使用stroke()方法进行绘制:

  1. context.stroke();//绘制

除此之外,我们还可以设置线条的一些基本属性:

  1. context.lineWidth = 8;//线条的宽度
  2. context.strokeStyle = "#333";//线条的颜色

一个简单的绘制一条直线的完整例子:

  1. var canvas = document.getElementById("canvas");//获取到canvas元素
  2. //设置宽高
  3. canvas.width = 800;
  4. canvas.height = 800;
  5. var context = canvas.getContext("2d");//获取上下文的环境
  6. //canvas 是基于状态的绘制,而不是对象
  7. context.moveTo(100,100);
  8. context.lineTo(500,500);
  9. context.lineWidth = 8;//线条的宽度
  10. context.strokeStyle = "#333";//线条的颜色
  11. context.stroke();//绘制

运行结果如下图:

接下来我们绘制一个连续折线:

  1. context.moveTo(100,100);
  2. context.lineTo(500,100);
  3. context.lineTo(500,500);
  4. context.lineTo(100,500);

运行结果如下:

如果我们想要让这个折线闭合形成一个矩形的话,可以再设置context.lineTo(100,100);然而如果线条的宽度比较大的时候,就会出现一些瑕疵,这个的话大家自己试试看。所以标准的话应该使用context.closePath();这个知识点后面会讲到,这里大家可以先试试,看看运行结果是怎么样的。

上面这个简单的例子我们是连续绘制的折线,也就是说可以一笔连续画完的折线。如果是多条间断的折线,那么我们就需要使用context.moveTo()来重新绘制一条折线的起点坐标:

  1. context.moveTo(100,200);
  2. context.lineTo(300,400);
  3. context.lineTo(100,600);
  4.  
  5. context.moveTo(300,200);
  6. context.lineTo(500,400);
  7. context.lineTo(300,600);
  8.  
  9. context.moveTo(500,200);
  10. context.lineTo(700,400);
  11. context.lineTo(500,600);

运行结果如下:

此时,如果我们想要绘制的这三条折线是不同颜色的,那该怎么办?一种常见的错误用法就是:

  1. context.moveTo(100,200);
  2. context.lineTo(300,400);
  3. context.lineTo(100,600);
  4. context.lineWidth = 8;
  5. context.strokeStyle = "red";
  6. context.stroke();//绘制
  7.  
  8. context.moveTo(300,200);
  9. context.lineTo(500,400);
  10. context.lineTo(300,600);
  11. context.lineWidth = 8;
  12. context.strokeStyle = "green";
  13. context.stroke();//绘制
  14.  
  15. context.moveTo(500,200);
  16. context.lineTo(700,400);
  17. context.lineTo(500,600);
  18. context.lineWidth = 8;
  19. context.strokeStyle = "blue";
  20. context.stroke();//绘制

运行结果会是三条折线都是蓝色的。因为这里的第二条折线的strokeStyle属性会覆盖第一条折线的strokeStyle属性,而stroke()方法的执行会绘制当前所有的状态,所以第一条折线就变成绿色。同理,最终三条折线就都是蓝色。因此呢,这里就需要使用beginPath()方法来重新进行一次全新的绘制。

  1. context.lineWidth = 8;//线条的宽度
  2. context.beginPath();
  3. context.moveTo(100,200);
  4. context.lineTo(300,400);
  5. context.lineTo(100,600);
  6. context.strokeStyle = "red";
  7. context.stroke();//绘制
  8.  
  9. context.beginPath();
  10. context.moveTo(300,200);
  11. context.lineTo(500,400);
  12. context.lineTo(300,600);
  13. context.strokeStyle = "green";
  14. context.stroke();//绘制
  15.  
  16. context.beginPath();
  17. context.moveTo(500,200);
  18. context.lineTo(700,400);
  19. context.lineTo(500,600);
  20. context.strokeStyle = "blue";
  21. context.stroke();//绘制

这里在每绘制一条折线的时候,都使用beginPath()方法来进行一次全新的路径绘制。此时再使用stroke()方法进行绘制的时候,就只会绘制beginPath()方法下面的状态。运行结果如下:

从上面的代码我们可以看到:context.lineWidth = 8;放在了最前面,这是因为beginPath()方法不会将没有修改的属性变成默认值。比如这里的lineWidth,三条折线都是8,那么我们放在前面的话,在进行stroke()方法进行绘制的时候,都是会使用lineWidth = 8;来进行绘制。而需要修改的属性则在具体的路径绘制里进行修改,比如这里的线条颜色属性,每条折线的颜色都不一样,所以就需要各自设置。

还有一点就是:此段代码中的moveTo()方法可以改成lineTo()方法:

  1. context.lineWidth = 8;//线条的宽度
  2. context.beginPath();
  3. context.lineTo(100,200);
  4. context.lineTo(300,400);
  5. context.lineTo(100,600);
  6. context.strokeStyle = "red";
  7. context.stroke();//绘制

因为使用了beginPath()方法,就会对之前绘制的路径进行清空,但不会回到(0,0)原点。所以这里我们直接使用lineTo()方法同样能起到绘制起点的作用,但必须和beginPath()方法一起使用才能替换moveTo()方法。

上面曾简单讲过context.closePath()方法,这里将具体展开介绍:context.closePath()方法和context.beginPath()方法一起使用,以绘制闭合的路径图形,这是绘制封闭多边形的标准做法。而且使用context.closePath()方法,最后一条线的绘制可以省略,它会自动帮我们连接到绘制起点以形成封闭的多边形。

  1. context.beginPath();
  2. context.moveTo(100,100);
  3. context.lineTo(500,100);
  4. context.lineTo(500,500);
  5. context.lineTo(100,500);
  6. context.closePath();
  7. context.lineWidth = 8;
  8. context.strokeStyle = "#333";
  9. context.stroke();

运行结果如下:

接下来我们介绍一下填充属性fillStyle和填充绘制方法fill():

  1. context.beginPath();
  2. context.moveTo(100,100);
  3. context.lineTo(500,100);
  4. context.lineTo(500,500);
  5. context.lineTo(100,500);
  6. context.closePath();
  7. context.lineWidth = 8;
  8. context.strokeStyle = "#333";
  9. context.stroke();
  10. context.fillStyle = "red"; //填充颜色
  11. context.fill(); //填充

最后两行代码就是设置了填充的颜色(红色)和进行闭合图形的颜色填充,运行结果如下:

可以看到图形的边框宽度比没有填充颜色的图形的边框宽度小,这是因为我们先绘制边框,再填充颜色。而实际上应该是先填充颜色,再绘制边框。而且fill()方法和stroke()方法的原理是一样的,都是基于当前状态进行绘制。所以,为了可读性,我们可以将属性设置放在一起,最后在使用fill()和stroke()方法:

  1. context.beginPath();
  2. context.moveTo(100,100);
  3. context.lineTo(500,100);
  4. context.lineTo(500,500);
  5. context.lineTo(100,500);
  6. context.closePath();
  7. context.lineWidth = 8;
  8. context.strokeStyle = "#333";
  9. context.fillStyle = "red";
  10.  
  11. context.fill(); //先填充
  12. context.stroke(); //再绘制边框

这次的运行结果:

可以看到,这次的结果就是正确的了。

对于绘制矩形这个很常用,那么我们就可以封装成函数,方便以后调用:

  1. drawRect(context,100,100,400,400,8,"#333","blue");
  2.  
  3. function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
  4. cxt.beginPath();
  5. cxt.moveTo(x,y);
  6. cxt.lineTo(x+width,y);
  7. cxt.lineTo(x+width,y+height);
  8. cxt.lineTo(x,y+height);
  9. cxt.closePath();
  10. cxt.lineWidth = borderWidth;
  11. cxt.strokeStyle = borderColor;
  12. cxt.fillStyle = fillColor;
  13. cxt.fill();
  14. cxt.stroke();
  15. }

同样的,运行结果也是正常的:

但是呢,canvas API 提供了绘制矩形更加方便的方法:rect()方法用于规划矩形的路径,fillRect()方法在规划了矩形的路径之后还填充了矩形的颜色,而strokeRect()方法则绘制了矩形的边框。

所以上面的函数若使用context.rect()方法可以简化为:

  1. function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
  2. cxt.beginPath();
  3. cxt.rect(x,y,width,height);
  4. cxt.closePath();
  5. cxt.lineWidth = borderWidth;
  6. cxt.strokeStyle = borderColor;
  7. cxt.fillStyle = fillColor;
  8. cxt.fill(); //先填充
  9. cxt.stroke(); //再绘制边框
  10. }

而使用fillRect()和strokeRect()这两个方法则可以更加简单就实现:

  1. function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
  2. cxt.lineWidth = borderWidth;
  3. cxt.strokeStyle = borderColor;
  4. cxt.fillStyle = fillColor;
  5. cxt.fillRect(x,y,width,height);
  6. cxt.strokeRect(x,y,width,height);
  7. }

此时如果我们绘制了两个矩形:

  1. drawRect(context,100,100,400,400,8,"#333","blue");
  2. drawRect(context,300,300,400,400,8,"#333","red");

运行结果是这样的:

可以看到,后绘制的矩形会盖在前绘制的矩形之上,当然得颜色不同才体现出来。

此时我们将第二个矩形的填充颜色改一下:

  1. drawRect(context,300,300,400,400,8,"#333","rgba(255,0,0,0.5)");

结果如下:

可以看到第二个矩形的填充颜色是半透明的红色。那么就需要说明一下:fillStyle 和 strokeStyle 属性的颜色值可以是CSS3支持的任何一种形式:

  1. #ffffff
  2. #333
  3. red
  4. rgb(0,0,0)
  5. rgba(255,0,0,0.5)
  6. hsl(20,50%,50%)
  7. hsla(20,50%,60%,0.6)

线段还有其他一些属性,接下来分别讲解:

lineCap属性就是定义线段开头和结尾处的形状,此属性有三个属性值:butt(默认值),round,square 。

通过代码来演示这三种效果:

  1. context.lineWidth = 50;
  2. context.strokeStyle = "#005588";
  3.  
  4. context.beginPath();
  5. context.moveTo(100,200);
  6. context.lineTo(700,200);
  7. context.lineCap = "butt";
  8. context.stroke();
  9.  
  10. context.beginPath();
  11. context.moveTo(100,400);
  12. context.lineTo(700,400);
  13. context.lineCap = "round";
  14. context.stroke();
  15.  
  16. context.beginPath();
  17. context.moveTo(100,600);
  18. context.lineTo(700,600);
  19. context.lineCap = "square";
  20. context.stroke();

这里画了三条线段,分别设置了不同的lineCap属性值,看看有什么不同:

从结果可以看出来,使用round属性值会比默认值butt多出一个半圆的形状包在线段的开始和结尾处,而是用square属性值会在开始和结尾处多处半个方形,这就是它们的不同之处。其中,round对于我们绘制一些圆角效果的图形比较有用,但是它只对线条的开头和结尾处有效果,对于线段之间的连接处没有作用,这点需要注意。

接下来我们来绘制一个五角星:

先看一下效果图:

我们要绘制一个这样的五角星,其实就是要绘制出十个顶点,而且这十个顶点是有规律可循的:

从这个图可以看到,五角星的十个顶点可以分成两组,分别在外圆和内圆上的五个顶点,通过数学公式可以得知:a是18度,b是36度,故a+b=54度,有了一个角的度数,还有大小圆的半径,就可以根据三角函数公式求出顶点的坐标了,而且大小圆上的每个顶点之间的度数都是相差72度,那么我们就可以使用函数来绘制这个五角星:

  1. context.lineWidth = 10;
  2. context.strokeStyle = "#005588";
  3. drawStar(context,150,300,400,400,0);
  4. context.stroke();
  5.  
  6. function drawStar(cxt,r,R,x,y,rotate){
  7. cxt.beginPath();
  8. for(var i = 0; i < 5; i++){
  9. cxt.lineTo(Math.cos((18 + i*72 - rotate)/180*Math.PI)*R + x,
  10. -Math.sin((18 + i*72 - rotate)/180 * Math.PI)*R + y);
  11. cxt.lineTo(Math.cos((54 + i*72 - rotate)/180*Math.PI)*r + x,
  12. -Math.sin((54 + i*72 - rotate)/180 * Math.PI)*r + y);
  13. }
  14. cxt.closePath();
  15. }

至于这里面的公式,大家就自己想一下吧,其实就是正弦和余弦函数。drawStar()方法的参数分别是上下文环境,小圆半径,大圆半径,偏移量x,偏移量y,旋转角度。

最后还有两个线条的属性:lineJoin 和 miterLimit

lineJoin顾名思义就是线条与线条之间的连接方式,该属性有三个属性值:miter(默认值,尖角),bevel(衔接),round(圆角)。

我们基于上面的五角星的例子,分别设置不同的lineJoin属性值,看看有什么不同:

  1. context.lineJoin = "bevel";

  1. context.lineJoin = "round";

这些细微的差别还是大家自己试一下才有比较直观的感受,更能理解其中的用法。

还有一个miterLimit属性,这个属性只有当lineJoin属性值是miter时才有用,默认值是10 。那么它到底是什么呢?

我们通过代码来演示:

  1. context.lineWidth = 10;
  2. context.strokeStyle = "#005588";
  3. context.lineJoin = "miter";
  4. drawStar(context,30,300,400,400,0);
  5. context.stroke();

我们将小圆的半径设置得比较小,此时我们的lineJoin是miter,即尖角。那么结果会是怎么样的呢?

可以看到它毕竟变成bevel连接方法了,这就是miterLimit属性的影响,那么它究竟怎么计算的呢?看下图:

可以看到,它的计算还是比较复杂的,所以canvas给我们一个经验值,也就是10,当然自己也可以修改miterLimit的值,得到自己想要的结果。

好的,以上就是线条的全部内容!未完待续….

canvas绘图详解笔记之线条及线条属性的更多相关文章

  1. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  2. 【HTML5】Canvas绘图详解-1

    ----->Canvas绘制基础 1,线条绘制 1-1,线条组成的图形和beginPath 案例:绘制由不同颜色的线条组成的图案 1-2,多边形的填充和closePath 案例:绘制封闭具有填充 ...

  3. HTML5 Canvas绘图详解 drawImage() 方法 有图有真相!

    步骤 1 2 3 4 5   简介 是一个新的HTML元素,这个元素可以被Script语言(通常是JavaScript)用来绘制图形.例如可以用它来画图.合成图象.或做简单的(和不那么简单的)动画. ...

  4. Android Canvas绘图详解(图文)

    编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! Andr ...

  5. 【转】Android Canvas绘图详解

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android中使用图形处理引擎,2D部分是an ...

  6. canvas绘图详解-06-绘制一个五角星-常用绘图原理

    先将如何画一个正规的五角星 在五角星的内外画两个圆,五角星有五个角,360/5=72度 所以得出这两个角的度数 然后算出这两个点坐标 角度转弧度 角度/180*Math.PI 所以外顶点坐标 x:   ...

  7. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  8. TCP-IP详解笔记8

    TCP-IP详解笔记8 TCP超时与重传 下层网络层(IP)可能出现丢失, 重复或丢失包的情况, TCP协议提供了可靠的数据传输服务. TCP启动重传操作, 重传尚未确定的数据. 基于时间重传. 基于 ...

  9. TCP-IP详解笔记7

    TCP-IP详解笔记7 TCP: 传输控制协议(初步) 使用差错校正码来纠正通信问题, 自动重复请求(Automatic Repeat Request, ARQ). 分组重新排序, 分组复制, 分组丢 ...

随机推荐

  1. ECharts修改坐标轴,坐标轴字体,坐标轴网格样式以及控制坐标轴是否显示

    转自:http://blog.csdn.net/kirinlau/article/details/72876689 首先要将一个图表显示在前端页面上: var myChart = echarts.in ...

  2. php Only variables can be passed by reference

    最近做项目,发现了一个报错  Only variables can be passed by reference,  意思是"只有变量能通过'引用'" 就是在代码中 使用了一个方法 ...

  3. OKEX API(Websocket)

    本文介绍OKEX API Websocket WebSocket API for SPOT 开始使用 WebSocket是HTML5一种新的协议(Protocol).它实现了客户端与服务器全双工通信, ...

  4. sql 对某列取值进行if判断

    select  if(area_id =350000, 1, 2)  as area_id from my_table 取地区编号为350000的设置成 1, 其他的设置成2

  5. 如何下载Bilibili视频

    方法1: https://www.bilibili.com/video/av25940642 (源网址) https://www.ibilibili.com/video/av25940642 (新网址 ...

  6. 10个实用的Django建议(转)

    前言:随着Django1.4第二个候选版的发布,虽然还不支持Python3,但Django团队已经在着手计划中,据官方博客所说, Django1.5将会试验性的支持python3.Django 作为一 ...

  7. java实现树状图

    1.定义测试数据类 VirtualDataGenerator: import java.util.ArrayList;import java.util.HashMap;import java.util ...

  8. Windows下pycharm使用theano的方法

    安装theano前需要自行安装Anaconda和PyCharm.在网上查了在PyCharm上安装theano的方法,但是均遇到了一些问题,现将问题与解决方案介绍如下. (一)第一种安装方式 打开cmd ...

  9. java读取resource目录下的配置文件

    java读取resource目录下的配置文件 1:配置resource目录 下的文件 host: 127.0.0.1 port: 9300 2:读取    / 代表resource目录 InputSt ...

  10. CentOS 6.5通过yum的方式安装MySql

    一.mysql简介 说到数据库,我们大多想到的是关系型数据库,比如mysql.oracle.sqlserver等等,这些数据库软件在windows上安装都非常的方便,在Linux上如果要安装数据库,咱 ...