周老虎落网的时候,网易跟腾讯都推出了牛逼轰轰的HTML5页面来展现其关系网(网易http://news.163.com/special/data_zyk/ ,腾讯http://news.qq.com/zt2014/zykgxw/index.htm),查看这俩页面,都是经过H5中canvas强大的绘图功能来实现的。若是你不曾学习过H5,看完这俩屌炸天的页面,兴许会勾起你学习的欲望。css
canvas其实没有那么玄乎,它不外乎是一个H5的标签,跟其它HTML标签一模一样:css3
<canvas></canvas>
canvas自己没有任何的绘图能力,全部的绘图工做都是经过js来实现的。一般咱们在js经过getElementById来获取要操做的canvas(这意味着咱得给canvas设个id):canvas
<canvas id="myCanvas"></canvas> <script> var c = document.getElementById("myCanvas"); //获取要操做的canvas //操做canvas的代码... </script>
注意最好在一开始的时候就给canvas设置好其宽高(若不设定宽高,浏览器会默认设置canvas大小为宽300、高100像素),并且不能使用css来设置(会被拉伸),建议直接写于canvas标签内部:浏览器
<canvas id="myCanvas" width="200" height="200"></canvas>
也能够在js脚本中设置:ide
<canvas id="myCanvas"></canvas> <script> var c = document.getElementById("myCanvas"); c.width=200; c.height=200; </script>
关于canvas大小须要知道的一点是,后续我们对canvas所作的所有绘图操做,超出此大小范围的部分是不可见的。顾名思义,能够把canvas当作一块画布,其大小是咱设定好的宽高,那么不管你怎么画,画布外的地方天然是画不到的。函数
对于有些浏览器是不支持canvas功能的,咱们能够直接在canvas标签中写一些替换内容,在浏览器不支持canvas时显示:学习
<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC;"> 您的浏览器不支持canvas,建议使用最新版的Chrome </canvas>
接着在聊如何在canvas上绘图前,咱得先说说.getContext("2d")这东西。
.getContext() 是canvas的绘图对象/方法,要让canvas执行绘图工做必须先获取canvas的.getContext()对象来执行。spa
.getContext()只接受一个参数,该参数用于获取canvas的绘图环境,例如.getContext("2d")表示该canvas的绘图环境为2D平面(能够绘制文本、直线、弧线、矩形、圆形等)。当前H5只支持2D环境,在不久的未来会开放3D绘图功能。(故咱可将“getContext”翻译为“获取绘图环境”)翻译
理论很少说,咱们先来个小例子,从最简单的绘制直线开始:设计
<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC;"> 您的浏览器不支持canvas,建议使用最新版的Chrome </canvas> <script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象 ctx.moveTo(10,10); //定义绘画开始的位置 ctx.lineTo(150,50); //画一条直线,结束点坐标是x=150,y=50 ctx.stroke(); //描边 </script>
效果以下:
在这里咱们使用了3个getContext("2d")对象的绘图方法:
.moveTo(x坐标 , y坐标) 能够理解为定位画笔在画布上的位置(注意全部绘图方法所定义的坐标是相对canvas而言的而不是浏览器窗口,对canvas来讲,最左上角的点的坐标是(0,0))
.lineTo(x坐标 , y坐标) 顾名思义,就是画一条直线到某个点,很好理解。须要知道的是此方法仅仅作路径运动,而不存在任何视觉上的绘图效果(上色、描边)
.stroke() 描边方法,有玩过AfterEffect的朋友会很清楚,不给运动路径加stroke特效的画是不存在描边效果的,canvas也同样,想要运动路径轨迹能有视觉效果,须要使用相应的上色/描边方法
自此咱们很轻松地绘制了一条黑色的直线,但若是咱们想要绘制一条红色的或者其它颜色的线段,该怎么作呢?
答案很简单,使用ctx.strokeStyle来设定描边的颜色便可。咱们画三条红色的线段吧:
<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC; margin:30px;"> 您的浏览器不支持canvas,建议使用最新版的Chrome </canvas> <script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象 ctx.moveTo(0,0); //咱把“画笔”移到坐标(0,0) ctx.lineTo(150,50); //从上个点(0,0)画一条直线,结束点坐标是(150,50) ctx.lineTo(20,100); //从上个点(150,50)继续画一条直线,结束点坐标是(20,100) ctx.moveTo(90,90); //咱把“画笔”移到坐标(90,90) ctx.lineTo(80,150); //从上个点(60,60)继续画一条直线,结束点坐标是(80,150) ctx.strokeStyle = "red"; //设定描边颜色为红色,只要写在.stroke()方法前面便可 ctx.stroke(); //描边 </script>
注释都说的很清楚了,故再也不赘述实现原理,其效果以下:
注意在开始绘制路径的时候,必定要加上moveTo(x,y),不然第一个lineTo()的运动轨迹将不计入绘图中(浏览器会认为没获取到该运动轨迹的起始点,故忽略此线段)。
另外有一个问题,若是上方咱们会出来的两条线段(嗯,一条折线,一条直线),咱们但愿第一条折线是蓝色的,第二条直线是红色的,应当怎么作?
你会地很天然地作以下处理:
<script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); ctx.moveTo(0,0); ctx.lineTo(150,50); ctx.lineTo(20,100); ctx.strokeStyle = "blue"; //设定描边颜色为蓝色 ctx.stroke(); ctx.moveTo(90,90); ctx.lineTo(80,150); ctx.strokeStyle = "red"; //设定描边颜色为红色 ctx.stroke(); </script>
但运行脚本会发现,折线除了被描了一遍蓝色,也被描了一遍红色:
这是由于canvas在第二次给路径上色时,是把以前的全部路径轨迹合在一块儿来上色的,除非我们让canvas知道那折线和直线应该是独立开来的俩路径。
咱们可使用.beginPath()来解决:
<script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); ctx.moveTo(0,0); ctx.lineTo(150,50); ctx.lineTo(20,100); ctx.strokeStyle = "blue"; //设定描边颜色为蓝色 ctx.stroke(); ctx.beginPath(); //告诉canvas我们要从新绘制一条全新的路径了,以前画的东西今后再无关系 ctx.moveTo(90,90); ctx.lineTo(80,150); ctx.strokeStyle = "red"; //设定描边颜色为红色 ctx.stroke(); </script>
有的朋友一开始会搞不清楚beginPath()的用途,以为有moveTo()就能够了,其实beginPath()能够作到上述的隔离路径绘制效果的做用,防止以前的效果被污染。
接着唠嗑.strokeStyle的赋值方式,我们上方是直接用了 ctx.strokeStyle="red" 来定义描边颜色为红色,不过ctx.strokeStyle可获值的形式有三种:
ctx.strokeStyle=color|gradient|pattern; //即支持 “颜色/渐变/图案笔刷” 的赋值
⑴ 先看看color赋值方式,和咱们常规的css赋值是同样的,支持css3颜色值标准,以下例:
//下面四种形式都是同样的,表示描边颜色为“橙色” ctx.strokeStyle = "orange"; ctx.strokeStyle = "#FFA500"; //#rrggbb形式 ctx.strokeStyle = "rgb(255,165,0)"; //RGB形式 ctx.strokeStyle = "rgba(255,165,0,1)"; //比上面的rgb多了个a(Alpha),即透明度
⑵ 再看下渐变gradient,这个稍有复杂:
var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); ctx.moveTo(0,0); ctx.lineTo(150,50); ctx.lineTo(20,100); var grd = ctx.createLinearGradient(0,0,170,0); //定义线性渐变对象,设定渐变线起始点和结束点坐标,坐标格式为(起始点x,起始点y,结束点x,结束点y) grd.addColorStop(0,"black"); //定义渐变线起点颜色 grd.addColorStop(0.5,"red"); //定义渐变线中间点的颜色 grd.addColorStop(1,"yellow"); //定义渐变线结束点的颜色 ctx.strokeStyle = grd; //将渐变对象赋值给strokeStyle ctx.stroke(); //描边
效果以下:
这里咱们提到了一个概念叫“渐变线”,没有玩过设计的朋友须要了解下渐变的知识点,咱们能够把LinearGradient(线性渐变,另有放射状/圆形渐变RadialGradient)范围当作一个矩形(你能够经过Illustator、Photoshop等专业设计软件来辅助你理解这点):
咱们一开始定义线性渐变对象的代码 var grd = ctx.createLinearGradient(0,0,170,0) 不外乎就是设定了线性渐变线起始点为(0,0),结束点为(170,0)。
紧接着咱们经过 addColorStop( 渐变线位置<0~1>, 颜色 ) 来设定了渐变色值,分别在渐变线0、0.五、1的位置设置了黑色、红色、黄色,其渐变效果以下:
经过 ctx.strokeStyle = grd 将渐变赋值给描边方法,最终描边获得了咱们想要的渐变效果。
⑶ 最后看看pattern描边方式,strokeStyle之因此不叫strokeColor是由于它除了支持颜色描边还支持图案描边(搞设计的朋友或许称做笔触描边会更有feel)。
线性渐变描边须要先createLinerGradient(xstart,ystart,xend,yend),那么设置图案描边天然也要先新建一个canvasPattern对象:
createPattern(image, repetitionStyle)
其中参数 image 表明图案对象,通常经过 document.createElement('img') 或者 new Image() ,再定义其src值来建立该对象。
而repetitionStyle参数很好理解,即图案重复形式,其可选值有"repeat" 、"repeat-x"、"repeat-y" 和"no-repeat" (和css的background-repeat可选值同样,不赘述)。
那咱们能够试着这样写:
<body> <canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC; margin:30px;"> 您的浏览器不支持canvas,建议使用最新版的Chrome </canvas> <script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); pic = new Image(); //建立图片对象,或者 pic = document.createElement('img') pic.src = "http://images.cnblogs.com/cnblogs_com/vajoy/558870/o_5.jpg"; //定义图片的映射地址 var redTexture = ctx.createPattern(pic, "repeat"); //定义Pattern对象,设定填充图案为pic图片,填充形式为平铺 ctx.strokeStyle = redTexture; //定义描边样式为上一行设定的Pattern描边 ctx.moveTo(80,10); ctx.lineTo(10,90); ctx.stroke(); </script>
只是在执行效果的时候会发现,执行十次有九次不是咱们预期的图片填充效果,而是默认的黑色描边效果,这是为什么?
缘由在于浏览器可能还未加载完图片pic,就已经执行了ctx.stroke(),解决方法是让ctx在图片pic加载完毕以后才开始执行绘图:
<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC; margin:30px;"> 您的浏览器不支持canvas,建议使用最新版的Chrome </canvas> <script> var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); pic = new Image(); //建立图片对象,或者 pic = document.createElement('img') pic.src = "http://images.cnblogs.com/cnblogs_com/vajoy/558870/o_5.jpg"; pic.onload = patternFill; //在图片加载完成时执行绘图函数 function patternFill() { //定义绘图函数 var redTexture = ctx.createPattern(pic, "repeat"); ctx.strokeStyle = redTexture; ctx.moveTo(80,10); ctx.lineTo(10,90); ctx.lineWidth = 8; //定义线段粗度为8像素 ctx.stroke(); } </script>
效果以下:
注意这里我还加了个 ctx.lineWidth = 8 来设定线段的粗度。
自此咱们学习了strokeStyle的三个赋值方式,也学习了上述的经过 ctx.lineWidth = lineWeight 的形式来给线段设定粗度。
最后我们再学习两个很简单的线段属性 lineCap 和 lineJoin。
⑴ lineCap是设定线段端点的形状(线帽),其值能够是
butt 默认,即线条端点为平直的边缘 round 线条端点为圆角线帽 square 为线条端点添加正方形线帽 |
<canvas id="myCanvas" width="250" height="120" style="border:1px solid #DDD;"> </canvas> <script> var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); ctx.lineWidth=10; ctx.beginPath(); ctx.lineCap="butt"; ctx.moveTo(20,10); ctx.lineTo(200,60); ctx.strokeStyle="red"; ctx.stroke(); ctx.beginPath(); ctx.lineCap="round"; ctx.moveTo(30,90); ctx.lineTo(200,40); ctx.strokeStyle="blue"; ctx.stroke(); ctx.beginPath(); ctx.lineCap="square"; ctx.moveTo(10,30); ctx.lineTo(200,80); ctx.strokeStyle="green"; ctx.stroke(); </script>
代码效果以下:
光看此图可能看不太出“butt”和"square"的区别,但懂得使用AI绘制矢量的同窗们应该比较了解:
⑵ lineJoin则是设定折线的交接处的外角类型,其值可为:
miter 默认,折线交接处为尖角 round 折线交接处为圆角 bevel 折线交接处为斜角 |
<canvas id="myCanvas" width="200" height="220" style="border:1px solid #DDD;"> </canvas> <script> var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); ctx.lineWidth=13; ctx.lineJoin="bevel"; ctx.moveTo(20,20); ctx.lineTo(100,50); ctx.lineTo(20,80); ctx.strokeStyle="red"; ctx.stroke(); ctx.beginPath(); ctx.lineJoin="round"; ctx.moveTo(20,60); ctx.lineTo(100,90); ctx.lineTo(20,150); ctx.strokeStyle="green"; ctx.stroke(); ctx.beginPath(); ctx.lineJoin="miter"; ctx.moveTo(20,90); ctx.lineTo(100,150); ctx.lineTo(20,200); ctx.strokeStyle="blue"; ctx.stroke(); </script>
效果以下:
须要了解的是,miter还受到了属性miterLimit的影响(点此查看详细),但我的以为它跟bevel实现的效果是一致的,故在此不作介绍。
开篇就先讲到这里,主要是对canvas线段绘制功能的介绍,共勉~