颜色和样式

通过刚才的例子,我们学会了绘制图形。

但是我们看到,不管是填充还是描边,画出来的都是简单的黑白图形。如果想要指定描绘的内容,画出更丰富的效果应该如何操作呢?

有两个重要的属性可以做到,fillStylestrokeStyle。顾名思义,分别是为填充和描边指定样式。

颜色

在本章节最初的例子里,其实已经看到上色的基本方法,就是直接用颜色作为指定样式。

  1. ctx.fillStyle = 'rgb(200,0,0)'
  2. ctx.fillRect(20, 20, 200, 200)

一旦设置了 fillStyle 或者 strokeStyle 的值,新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,需要画完一种样式的图形后,重新设置 fillStylestrokeStyle 的值。

  1. //填充绘制一个矩形,颜色为暗红色
  2. ctx.fillStyle = 'rgb(200,0,0)'
  3. ctx.fillRect(20, 20, 200, 200)
  4. //描边绘制另一个矩形,边框颜色为半透明蓝色
  5. ctx.strokeStyle = 'rgba(0, 0, 200, 0.5)'
  6. ctx.strokeRect(80, 80, 200, 200)

canvas 的颜色支持各种 CSS 色彩值。

  1. // 以下值均为 '红色'
  2. ctx.fillStyle = 'red' //色彩名称
  3. ctx.fillStyle = '#ff0000' //十六进制色值
  4. ctx.fillStyle = 'rgb(255,0,0)' //rgb色值
  5. ctx.fillStyle = 'rgba(255,0,0,1)' //rgba色值

渐变色

除了使用纯色,还支持使用渐变色。先创建渐变色对象,并将渐变色对象作为样式进行绘图,就能绘制出渐变色的图形。

渐变色对象可以使用 createLinearGradient 创建线性渐变,然后使用 addColorStop 上色。

这里要注意的是,渐变色对象的坐标尺寸都是相对画布的。应用了渐变色的图形实际起到的是类似“蒙版”的效果。

  1. //填充绘制一个矩形,填充颜色为深红到深蓝的线性渐变色
  2. const linGrad1 = ctx.createLinearGradient(0, 0, 300, 300)
  3. linGrad1.addColorStop(0, 'rgb(200, 0, 0)')
  4. linGrad1.addColorStop(1, 'rgb(0, 0, 200)')
  5. ctx.fillStyle = linGrad1
  6. ctx.fillRect(20, 20, 200, 200)
  7. //描边绘制另一个矩形,边框颜色为深蓝到深红的线性渐变色
  8. const linGrad2 = ctx.createLinearGradient(0, 0, 300, 300)
  9. linGrad2.addColorStop(0, 'rgb(0, 0, 200)')
  10. linGrad2.addColorStop(1, 'rgb(200, 0, 0)')
  11. ctx.strokeStyle = linGrad2
  12. ctx.strokeRect(80, 80, 200, 200)

线型

除了颜色,还可以在描边绘制图形的时候,为描边的线条增加线型。

线型可设置的项目包括:

线宽(lineWidth)

线宽

顾名思义,线宽就是描边线条的宽度,单位是像素。

这里要注意两点:

线条的宽度会向图形的内部及外部同时延伸,会侵占图形的内部空间。在使用较宽线条时特别需要注意图形内部填充部分是否被过度挤压。常用解决方法可以尝试先描边后填充。

可能会出现的半渲染像素点。例如,绘制一条 (1, 1) 到 (1, 3),线宽为 1px 的线段,是在 x = 1 的位置,向左右各延伸 0.5px 进行绘制。但是由于实际最小绘制单位是一个像素点,那么最终绘制出来的效果将是线宽 2px,但是颜色减半的线段,视觉上看就会模糊。常用解决方法,一种是改用偶数的线宽绘制;另一种可以将线段绘制的起始点做适当偏移,例如偏移至 (1.5, 1) 到 (1.5, 3),左右各延伸 0.5px 后,正好布满一个像素点,不会出现半像素渲染了。

端点样式(lineCap)

端点样式

端点样式决定了线段端点显示的样子。从上至下依次为 buttroundsquare,其中 butt 为默认值。

这里要注意的是,roundsquare 会使得线段描绘出来的视觉长度,两端各多出半个线宽,可参考蓝色辅助线。

交点样式(lineJoin)

交点样式

交点样式决定了图形中两线段连接处所显示的样子。从上至下依次为 miter, bevelroundmiter 为默认值。

交点最大斜接长度(miterLimit)

交点最大斜接长度

在上图交点样式为 miter 的展示中,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。

miterLimit 属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,交点样式会自动变成了 bevel

示例

  1. ctx.lineWidth = 20
  2. ctx.lineCap = 'round'
  3. ctx.lineJoin = 'bevel'
  4. ctx.strokeRect(80, 80, 200, 200)

使用虚线

setLineDash 方法和 lineDashOffset 属性来制定虚线样式。 setLineDash 方法接受一个数组,来指定线段与间隙的交替;lineDashOffset 属性设置起始偏移量。

示例

  1. drawLineDashCanvas () {
  2. const canvas = this.$element('linedash-canvas')
  3. const ctx = canvas.getContext('2d')
  4. let offset = 0
  5. // 绘制蚂蚁线
  6. setInterval(() => {
  7. offset++
  8. if (offset > 16) {
  9. offset = 0
  10. }
  11. ctx.clearRect(0, 0, 300, 300)
  12. // 设置虚线线段和间隙长度 分别为 4px 2px
  13. ctx.setLineDash([4, 2])
  14. // 设置虚线的起始偏移量
  15. ctx.lineDashOffset = -offset
  16. ctx.strokeRect(10, 10, 200, 200)
  17. }, 20)
  18. }

运行效果如下

绘制虚线

组合使用

通过学习,我们为刚才绘制的快应用 logo 添加颜色和样式。

  1. drawCanvas () {
  2. const r = 20
  3. const h = 380
  4. const p = Math.PI
  5. const linGrad1 = ctx.createLinearGradient(h, h, 0, 0)
  6. linGrad1.addColorStop(0, '#FFFAFA')
  7. linGrad1.addColorStop(0.8, '#E4C700')
  8. linGrad1.addColorStop(1, 'rgba(228,199,0,0)')
  9. ctx.fillStyle = linGrad1
  10. ctx.fillRect(0, 0, h, h)
  11. const linGrad2 = ctx.createLinearGradient(0, 0, h, h)
  12. linGrad2.addColorStop(0, '#C1FFC1')
  13. linGrad2.addColorStop(0.5, '#ffffff')
  14. linGrad2.addColorStop(1, '#00BFFF')
  15. ctx.beginPath()
  16. ctx.moveTo(r * 2, r)
  17. ctx.arc(r * 2, r * 2, r, -p / 2, -p, true)
  18. ctx.lineTo(r, h - r * 2)
  19. ctx.arc(r * 2, h - r * 2, r, p, p / 2, true)
  20. ctx.lineTo(h - r * 2, h - r)
  21. ctx.arc(h - r * 2, h - r * 2, r, p / 2, 0, true)
  22. ctx.lineTo(h - r, r * 2)
  23. ctx.arc(h - r * 2, r * 2, r, 0, -p / 2, true)
  24. ctx.closePath()
  25. ctx.lineWidth = 10
  26. ctx.strokeStyle = linGrad2
  27. ctx.stroke()
  28. const s = 60
  29. ctx.beginPath()
  30. ctx.moveTo(h / 2 + s, h / 2)
  31. ctx.arc(h / 2, h / 2, s, 0, -p / 2 * 3, true)
  32. ctx.arc(h / 2, h / 2 + s + s / 2, s / 2, -p / 2, p / 2, false)
  33. ctx.arc(h / 2, h / 2, s * 2, -p / 2 * 3, 0, false)
  34. ctx.arc(h / 2 + s + s / 2, h / 2, s / 2, 0, p, false)
  35. ctx.fillStyle = '#4286f5'
  36. ctx.fill()
  37. ctx.beginPath()
  38. ctx.moveTo(h / 2 + s * 2, h / 2 + s + s / 2)
  39. ctx.arc(h / 2 + s + s / 2, h / 2 + s + s / 2, s / 2, 0, p * 2, false)
  40. ctx.fillStyle = 'rgb(234, 67, 53)'
  41. ctx.fill()
  42. ctx.beginPath()
  43. ctx.moveTo(h / 2 + s / 4 * 3, h / 2 + s / 2)
  44. ctx.arc(h / 2 + s / 2, h / 2 + s / 2, s / 4, 0, p * 2, false)
  45. ctx.fillStyle = 'rgba(250, 188, 5, 1)'
  46. ctx.fill()
  47. }

实现效果如下

颜色和样式