Canvas绘图环境中有些属于立即绘制图形方法,有些绘图方法是基于路径的。
立即绘制图形方法仅有两个strokeRect(),fillRect(),虽然strokezText(),fillText()方法也是立即绘制的,但是文本不算是图形。
基于路径的绘制系统
大多数绘制系统,如:SVG(Scalable Verctor Graphics, 可缩放的矢量图形),Adobe Illustrator等,都是基于路径的,
使用这些绘制系统时,你需要先定义一个路径,然后再对其进行描边或填充,也可以描边加填充这样图形才能显示出来。
Canvas中的三种绘制方式:
绘制一条线段
Canvas绘图环境中,线段也是基于路径绘制的,称为线性路径,创建线性路径的方法:moveTO()与lineTo(),在创建路径之后调用stroke()方法,才能在Canvas中画出线段出来。
这就是前面我们所说的基于路径的绘制方法,必须对其进行描边或者填充;
通常两点连一线因此绘制线段非常简单,通过moveTO()指定线的起点,通过lineTo()移动到另一个点。
function drawLine(){ cxt.moveTo(50, 50); cxt.lineTo(100, 100); }
然而这样我们在画布中是看不见线段的,前面我们说到基于路径的绘制方法,必须要描边或者填充。所以要想看到结果,我们必须还要使用stroke()方法。
因此我们把方法修改成下面这样就会绘制出一条线段
function drawLine(){ cxt.moveTo(50, 50); cxt.lineTo(200, 200); cxt.stroke(); }
我们只使用lineTo()也是能在画布中绘制出线段的,我们把上面的代码改成如下面所示,效果也是一样的
function drawLine(){ cxt.lineTo(50, 50); cxt.lineTo(200, 200); cxt.stroke(); }
总结下moveTo()与lineTo()的用法
- moveTo(x,y): 将笔触移动到指定的坐标x以及y上,向当前路径中增加一条子路径,该方法不会清除当前路径中的任何子路径。
- lineTo(x,y): 绘制一条从当前位置到指定x以及y位置的直线,如果当前路径中没有子路径,那么这个方法的行为与moveTo()一样。如果当前路径中存在子路径,此方法会将你所指定的这个点加入子路径中。
改变线段的样式
改变线段的宽度
function= 14; cxt.lineTo(50, 50); cxt.lineTo(200, 200); cxt.stroke(); }
改变线段的颜色
function drawLine(){ cxt.lineWidth = 14; cxt.strokeStyle = 'green'; cxt.lineTo(50, 50); cxt.lineTo(200, 200); cxt.stroke(); }
我们还可以利用CanvasGradient对象或者CanvasPattern对象给线段添加渐变色或图案
function drawLine(){ cxt.lineWidth = 14; var gradient = cxt.createLinearGradient(0, 0, canvas.width/2, canvas.height/2); gradient.addColorStop(0, 'blue'); gradient.addColorStop(0.5, 'purple'); gradient.addColorStop(1, 'yellow'); cxt.strokeStyle = gradient; cxt.lineTo(50, 50); cxt.lineTo(200, 200); cxt.stroke(); }
beginPath()与closePath()
从上面canvas中的三种绘制方式中我们可以看出,第二行的弧形路径是开放路径,最后一行的弧形是封闭路径。那么封闭的路径是怎么实现的呢?
下面我们来看看canvas中路径绘制中两个比较重要的方法
- beginPath(): 清除当前所有子路径,以此来重置当前路径,重新规划一条路径。
- closePath(): 用于封闭某段开放路径。不是必需的,如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
先绘制出一条折线
function drawLine(){ cxt.strokeStyle = 'green'; cxt.lineWidth = 2; cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.lineTo(150, 150); cxt.stroke(); }
修改上面例子中的代码在代码中添加beginPath()与closePath()方法
function drawLine(){ //描边三角形 cxt.strokeStyle = 'green'; cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.stroke(); cxt.beginPath(); cxt.lineTo(150, 150); cxt.lineTo(150, 250); cxt.stroke(); cxt.closePath(); }
可以看出我们在画布中绘制了两条路径
注意:调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo()。所以我们在绘制图形的时候一定要先使用beginPath()。
我们继续修改我们的代码
function drawLine(){ //描边三角形 cxt.strokeStyle = 'green'; cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.lineTo(150, 150); cxt.closePath(); cxt.stroke(); //折线 cxt.translate(150, 0); cxt.strokeStyle = 'red'; cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.lineTo(150, 150); cxt.stroke(); cxt.closePath(); //绿色填充三角形 cxt.translate(150, 0); cxt.fillStyle = 'green'; cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.lineTo(150, 150); cxt.fill(); cxt.closePath(); //红色填充三角形 cxt.translate(150, 0); cxt.fillStyle = 'red'; cxt.lineWidth = 2; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(50, 150); cxt.lineTo(150, 150); cxt.closePath(); cxt.fill(); }
从上面的例子我们可以看出closePath()的位置不同,也会影响我们的图形
注意:当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以此时closePath()函数不是必须的。
但是调用stroke():如果你在stroke()方法之前只用closePath()会形成闭合路径,如果在stroke()方法之后调用closePath()方法,此时图形已经绘制完成,当前的绘制路径已经关闭,所以closePath()方法不起作用。
线段与像素边界
先来看一个例子
function drawLine(){ //描边三角形 cxt.lineWidth = 1; cxt.beginPath(); cxt.moveTo(50, 50); cxt.lineTo(450, 50); cxt.stroke(); cxt.beginPath(); cxt.moveTo(50.5, 150.5); cxt.lineTo(450.5, 150.5); cxt.stroke(); }
从图中我们可以看出,我们将两条线段的lineWidth都是设置为1像素,但是上面的线段画出的却是两像素。
如果你在某2个像素的边界处绘制一条1像素宽的线段,那么该线段实际会占据2个像素的宽度;
因为当你在像素边界处绘制一条1像素宽度的垂直线段时,canvas的绘图环境对象会试着将半个像素画在边界中线的右边,将另外半个像素画在边界中线的左边。
然而,在一个整像素的范围内绘制半个像素宽的线段是不可能的,所以在左右两个方向上的半个像素都被扩展为1个像素。
另外一方面,绘制在两个像素之间,这样的话,中线左右两端的那半个像素就不会延伸,它们结合起来恰好占据1个像素的宽度。所以说,如果要绘制一条真正1像素宽度的线段,你必须将该线段绘制在某两个像素之间
网格的绘制
既然我们已经明白了如何绘制真正的1像素的线段,那我们就开始绘制网格
function drawLine(stepx, stepy){ cxt.lineWidth = 0.5; cxt.strokeStyle = 'green'; //绘制竖线 for(var i= stepx + 0.5; i< cxt.canvas.width; i+= stepx){ cxt.beginPath(); cxt.moveTo(i, 0); cxt.lineTo(i, cxt.canvas.height); cxt.stroke(); } //绘制横线 for(var i= stepy + 0.5; i< cxt.canvas.height; i+= stepy){ cxt.beginPath(); cxt.moveTo(0, i); cxt.lineTo(cxt.canvas.width, i); cxt.stroke(); } } drawLine(10, 10);
上面例子中我们将线段绘制在两个像素之间的像素上,而且绘制出来的线段仅有0.5像素宽,
虽说canvas规范没有明文规定,不过所有浏览器的Canvas实现都使用了“抗锯齿”技术,以便创建出“亚像素”线段的绘制效果来
总结
本节内容主要讲解canvas中路径中线性路径的绘制方法,主要是利用 moveTo()定义起点,lineTo()定义终点,stroke()描绘当前路径。这三个方法绘制线段
canvas中绘制路径有两个重要的方法,beginPath()与closePath()。绘制图形之前先调用beginPath()是绘制多个图形必要的步骤。
closePath()在使用fill()时是可以省略的,而且还要注意closePath()方法的调用位置。
绘制线段时我们可以使用 lineWidth改变线段的宽度,strokeStyle改变线段的颜色。
弄清楚线段的像素边界,这样我们才能绘制出真正的1像素线宽的线段。
对canvas绘制图形感兴趣的同学,请持续关注后续更新,如有不对的地方也请指出并多多交流。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]