Canvas 运用

2017-11-23  本文已影响0人  Primers

HTML5 中新增的一个相当于画布的标签,自带各种 API ,通过 JS 调用和搭配,实现图案绘制和想要的效果。

下面这张截图就是由 canvas 在浏览器中生成的。

First Step

想要使用 canvas 标签,首先当然是要添加标签了。
<canvas></canvas>
在 JS 中获取该节点,
var canvas = document.getELementById('canvas')
然后获取 canvas 的上下文环境来获取绘制 API
var context = canvas.getContext('2d')

其中,一定要记住在 getContext 中传入参数 ' 2d '

不然是没法获取到上下文环境的。

Seconds Step

现在画布有了,但是画布的大小还不知道呢, canvas 的默认大小是 300 x 150 个像素。
但如果想要自定义大小的话,用常规的 CSS 样式设置的话并不适用于 canvas,
因为在 canvas 内部,并不是使用一般的像素来作为绘制单位,若想设置其大小,

- 使用内嵌属性 <canvas id= 'canvas' width= '300' height= '500></canvas>
- 使用 JS 设置节点属性 canvas.width = 300; canvas.height = 500;

当设置好这些后,就可以开始 “画画” 了,下面是各种常用的 API

说明一下:

canvas 绘制方法是一些基于状态的绘制,即多数方法只是为了设置 canvas 的状态,并非即时产生绘制效果,当设置好状态后,需要执行一些特定的绘制方法才能在浏览器中呈现,具体后面会讲到。
另外,在 context 上下文中设置属性值时,应该设置成字符串形式,比如设置颜色是要设成 "#ccc" ,而上面的宽高的数字本应也要字符串,但会自动转化类型。

注意:以下方法前面都省略了 context

可以想象一下画布上有一支虚拟的画笔,使用这个方法把画笔的笔尖定位到 xy 坐标上。

将笔尖移动到 xy 坐标,并与笔尖原坐标之间产生连线。可以理解成笔从原坐标到 xy 画一条线段。如果原坐标未定义,则效果相当于 .moveTo 。
结合上述两个方法,这里有个栗子:

// 想要画一条从(50,50)起笔,画到(100,150)的线段。

context.moveTo (50, 50)
context.lineTo (100, 150)

// 若第一行使用 lineTo (50, 50) 有同样效果。因为在那之前笔尖未定义

需要注意的是,浏览器窗口中并未真正出现了线段,请继续往后看。

设置线段的宽度(粗细),
注意,这里并不能加单位 px,canvas 里并不是用像素来做单位的。

按字面理解,就是线段的帽子。
线段两端呈现的形状是什么,默认为平头,另外还有圆头和方头。
方头看着好像没差别,但是其实和圆头一样是有突出来了,如下图左。
有个小技巧,当两条粗线段相接时,使用方头可以完美接合,如下图右两个圈圈标记。

两条或多条连续线段,在它们的接口(转折)处呈现的形状。
默认为两条线段斜切出一个尖角,还可以呈现出斜切面和圆滑。如下图左黄圈处。

在转折处为尖角时,会有一种情况:当两线段夹角越小,延伸出的尖角就越长,为了使画面处于可控范围,默认对尖角长度做限制,长度为10;超过后自动把转折效果设成 "bevel" 。如果想实现原效果,可手动增加 limit 值。长度判定方法如下图粉色标记。

通过调用这个方法,将前面设置的路线结合样式绘制出来,即成像。

用在 stroke 前,这个方法常用于设置线段的颜色,必须设置为字符串,能接受与 JS 相同的颜色表述模式。另外,该方法还能设置渐变和模式。

前面已经说过,canvas 是基于状态绘制的。当设置了一种样式状态比如颜色之后,状态会一直保留,会影响后面甚至之前的绘制的图形,比如:

context.moveTo(50,50)
context.lineTo(100,100)
context.strokeStyle = "blue"
context.stroke()
《》
context.moveTo(200,200)
context.lineTo(300,300)
context.strokeStyle = "red"
context.stroke()
!! 这里看似两次绘制了两条线段,而实际上是第二个stroke时连上面的线段也重新绘制一次,所以:
!! 第二次设置的状态 “红色” 也会影响到第一条线段。

而这里,引入一个我自己的理解——图层(类似于ps中),
使用了 beginPath 方法后,程序将新建一个图层,
这个图层独立于之前,图形、样式等状态将得到初始化,
具体用法就是在上面书名号那行插入此方法,就可以得到两条不同颜色的线段。

看名字,我本以为这是和上面那个方法是一对,但事实上功能却没什么关系,该方法用于把线段封闭起来,形成一个封闭的区域,即你只要绘制两条有夹角的线段,然后调用 closePath 就可以得到一个三角形。

填充,在封闭的区域中填充颜色。

设置填充方法的颜色。同上面的 strokeStyle ,还能填充渐变和模式。

绘制一个左上角位于 xy ,宽高为 wh 的矩形,默认为黑色。

类似于橡皮擦,清除左上角位于 xy ,宽高为 wh 的矩形区域。一般用于清空画布。
context.clearRect (0, 0, canvas.width, canvas.height)

下面会说到三个图形转换,如果熟悉 CSS3 的 transform 应该会挺了解的。
下面说列出几点要点:

  • 图形转换是针对整个画布坐标系的转换,而不是单独某个对象。
  • 设置了图形转换,之后设置的绘图状态将会受到影响,而之前的则不会。
  • 多次设置图形转换,效果是传递的。
  • beginPath 也没法清除影响,使用反向转换或储存状态(后面介绍)解决。

位移,使坐标系在 xy 方向上位移,即改变原点位置(默认在画布左上角)。
当多次设置位移而不清除的话,每次位移都是基于上次位移后的状态继续位移的。
注意,在 JS 坐标系中 y 轴向下为正方向。

旋转,以原点为圆心,坐标系旋转角度。角度必须转化为弧度制
表现特点同上。即,连续设置两个45°等于设置一个90°

伸缩,坐标系在 xy 方向上的伸缩(倍数)。表现特点也如上所述。
下图中我用线段描绘三个起始点在 50,50 长宽都为50的矩形,
但是中间插入了两次 scale (2,2) ,而最终出现了三个位置大小都不一样的矩形。
观察以下可以看到,第一个最小的矩形就是代码描述的样子。
而第二个矩形,因为 xy 轴伸长成了两倍,所以起始位置,和长宽都是原来两倍。
第三个矩形,则是在第二个矩形的基础上,继续两倍。
所以可以看出,图形转换的效果,是会传递的。
最有趣的,三个矩形连线段宽度都是成倍增长的。

既然图形转化这么厉害,设置了之后怎么复原呢?下面介绍

储存。该方法可以储存当前的状态,包括图形转换的状态。它恢复的是状态设置,而不影响已经绘制的内容。
一般用于储存画布最初始的状态,然后在一顿绘制之后使用 restore 恢复初始状态。或者在设置图形转换之前储存一下,转换使用完后再 restore ,避免转换持续影响绘图。

恢复成上次储存的状态,用法见上。

上面再介绍填充的时候有介绍到,除了颜色还可以填充渐变,

填充渐变,首先就要创建一个渐变模式。

线性渐变,创建一个从 x1y1 点到 x2y2 点的线性渐变。默认为没有颜色。

为上面创建的渐变模式添加颜色锚点,至少两个或以上才会产生渐变效果,例如
Object.addColorStop(0.5,"red"); Object.addColorStop(1,"blue");
即表示从两个坐标之间,50%的位置开始,由红色渐变到 100% 的位置蓝色。
而前面未涉及的50%则由临近的颜色填充,即红色。

以上仅仅是创建了渐变状态而已,下面来演示一下整个填充的过程:
var gradient = context.createLinearGradient(0,0,1200,0)

gradient.addColorStop(0,"red")
gradient.addColorStop(.16,"orange")
gradient.addColorStop(.34,"yellow")
gradient.addColorStop(.51,"#0ef51f")
gradient.addColorStop(.68,"#0beffb")
gradient.addColorStop(.84,"blue")
gradient.addColorStop(1,"#8000e8")

context.fillStyle = gradient

context.fillRect(0,0,1200,800)

径向渐变,另一种渐变模式,实现效果的方法和特点同上。
由一个以 x1y1 为圆心半径为 r1 的圆渐变到以 x2y2 为圆心半径为 r2 的圆。
一般我们会把 r1 设置为零,实现由圆心渐变到圆周的效果。

填充模式,这种更加强大,可以使图片、视频甚至是一个新的画布。
使用方式与上面渐变相似,首先要创建想要填充的模式,传入对象和重复模式。
重复模式可以选择 "no-repeat" / "repeat-x" / "repeat-y" / "repeat" ,下面有个栗子:

// 创建一个新的画布
var pattern = function () {
      var newCanvas = document.createElement('canvas')
      var context2 = newCanvas.getContext('2d')

      newCanvas.width = 100
      newCanvas.height = 100
      
      context2.fillStyle = "#000"
      context2.fillRect(0,0,100,100)

      retern newCanvas
}

// 将新画布作为旧画布的填充模式,传入新画布并设置重复
var fillPattern = context.createPattern(pattern, "repeat") 
context.fillStyle = fillPatern
context.fillRect(0,0,400,400)

画弧。在画布上画一段圆弧,这是画圆圈的主要方法。
以 xy 为圆心,r 为半径的一个圆,圆弧开始点为 star 结束 为 end,
计算起止点时,以右切点为 0 点,顺时针方向增加,并且始终不变。

这里还有顺逆时针的概念,即从起始点绘制结束点是按顺时针还是逆时针。当 acw 为 false 或不填时,为顺时针。当 acw 为 true 时为逆时针。但无论如何,位置标点都不会变。
以下举例:
1、false;2、false, closePath;3、true, closePath;
4、true;5、false, fill;6、true, fill

图片来自慕课网

利用圆弧来画圆角矩形

以参考线画一个弧,相对于上面那个,比较复杂,下面只简要说明要点。
1、原笔尖所在的位置为起始点,到 x1y1 位置画一条线段。
2、x1y1 位置到 x2y2 位置画一条线段。
3、两条线段形成一个夹角,所画的圆弧就在夹角之间,半径为 r。
4、圆弧与刚才的两条线段相切,起始点到第一个切点为直线。
5、第一个切点之后开始圆弧,第二个切点曲线结束。
6、圆弧起止点不一定在线段上,可以是在延长线上。

二次贝塞尔曲线。
x2y2 为终止点,x1y1 为控制点,将起始点和终止点之间的线段拉扯成弧。

三次贝塞尔曲线,x1y1 和 x2y2 为控制点。

除了几何图形,文字肯定是不能少的。

就像 CSS 中的 font 属性一样,可以并排设置多种字体属性。其中有五种:
font-style || font-variant || font-weight || font-size || font-family

描边字,这个方法传入的字符串,呈现出中空只有描边的文字,并将字符串的左上角定位在 xy,若设置了最大长度,当超过后会强制压缩字宽。该方法的样式同样受 strokeStyle 等相关状态影响。

填充字,出现经过填充的实心字,特点同上。并且接受 fillStyle 的各种。

文字对齐,设置上面绘制的文字的对齐方式,以文字设置的起始点为基准。

设置阴影状态。之后绘制的图形会有阴影。(颜色,X位移,Y位移,虚化程度)

全局透明度。

叠合操作模式。画布中先后绘制的内容会根据不同的模式来呈现效果。
默认为后绘制的覆盖先绘制的,也可以设置为先绘制的覆盖后绘制的,甚至可以让两次绘制重叠部分镂空或者提亮颜色。
属性模式有以下是一种,并且我个人制作了个演示页面,展示不同模式的效果。
source-over || source-atop || source-in || source-out || destination-over || destination-atop || destination-in || destination-out || lighter || copy || xor

剪辑区域。先设置路径再调用。把画布裁剪成刚才设置的路径区域。canvas 标签并没有变小,但是之后的绘制只会在该裁剪区域内可见。

判定 xy 坐标是否在当前设置的路径内。传回布尔值。Demo (暂时,可能日后会更新)


写在后面

可以看到 canvas 标签还是很强大的,它的功能当然不止这些,canvas 的 context 支持自定义,可以自己添加一些原创的方法和规则进去;canvas 甚至能进行一些图像处理,例如打马赛克,添加滤镜等等,在此篇章中就暂不深入介绍了。
待把这些基础的玩出花,再去进一步扩展也不迟,
同时,canvas 也还在不断地发展,各个浏览器也慢慢一步步兼容,所以了解 canvas 的最新情况是有必要的。这里可以参考以下W3C 的 canvas 文档。



Wait me back

上一篇 下一篇

猜你喜欢

热点阅读