画影图形指描画犯人面影,悬赏通缉。这里用法明显有问题,不过取其表义而已。javascript
在一个前端看来,画图有三种方法,Cavas,SVG 以及 CSS。至于三者优劣,将在此针对各类图形作逐一比较,有方,圆,椭圆,扇形,多边形,渐变,文本处理以及动画css
如下是在 codepen 的代码以及实际效果地址,可打开实际效果地址进行调试html
描边与填充是图形的基本属性。前端
在 CSS 中是 border-color
以及 background-color
属性。html5
.rect {
border: 1px solid #fff;
background-color: #000;
width: 100px;
height: 100px;
}
复制代码
在 SVG 中是 fill
和 stroke
。能够直接做为 element
的属性,另外也能够写到 css 样式中java
<rect width="100" height="100" fill="#fff" stroke="#000"></rect>
复制代码
也能够做为 css 样式css3
.rect {
fill: #fff;
stoke: #000;
}
复制代码
除了基本的描边,SVG 也有如下属性,此是 canvas 以及 css 所不及的编程
在 Canvas 中,是 fillStyle
及 strokeStyle
属性。canvas
const canvas = document.getElementById('rect')
const ctx = canvas.getContext('2d')
ctx.fillStyle = '#000'
ctx.strokeStyle = '#fff'
ctx.fillRect(0, 0, 100, 100)
ctx.fillRect(115, 0, 100, 100)
复制代码
不做介绍svg
.rect {
width: 100px;
height: 100px;
border-radius: 15px;
}
复制代码
<svg>
<rect width="100" height="100" rx="15" ry="15"></rect>
</svg>
复制代码
由 rx
及 ry
设置圆角矩形大小
const canvas = document.getElementById('rect')
const ctx = canvas.getContext('2d')
ctx.fillRect(0, 0, 100, 100)
ctx.fillRect(115, 0, 100, 100)
复制代码
在效果地址中能够看到没有使用 Canvas 绘出的圆角矩形, Canvas 无法直接经过矩形的 API 直接绘制出圆角矩形,这是它的硬伤
如下是经过其它方法绘制出来的圆角矩形,略(很是)麻烦
CSS3 border radius to HTML5 Canvas
多边形由多个点链接而成,只须要肯定多个点的位置,便能肯定多边形。在效果页面中,使用五角星做为示例
构成五角星的五个点分别是 [[81, 95], [0, 36], [100, 36], [19, 95], [50, 0]]
svg 使用元素 polyline
以及 polygon
。polygon
会把终点和起点链接起来,造成闭合图形。
points
属性指连成多边形的点。
fill-rule
决定哪里是图形的内部。nonzero
表明若是被路径所包围,便是内部,fill-rule
表明从某一点出发,到无限远处,若是只途经奇数条边,则在图形内部。由于效果地址中的五角星是空心的。
<polyline points="81, 95 0, 36 100, 36 19, 95 50, 0" fill-rule="evenodd"></polyline>
复制代码
canvas 须要使用 path
来绘制路径。
使用 moveTo
及 lineTo
来绘制直线,closePath
表明把终点和起点链接起来,至关于 svg 的 polygon
。
canvas 的 fill
方法也有 fillRule
属性。
const canvas = document.getElementById('star')
const ctx = canvas.getContext('2d')
const drawStar = ({ stroke = false, fillRule = 'nonzero' } = {}) => {
ctx.beginPath()
ctx.moveTo(81, 95)
ctx.lineTo(0, 36)
ctx.lineTo(100, 36)
ctx.lineTo(19, 95)
ctx.lineTo(50, 0)
ctx.closePath()
// fill 的时候自动 closePath
stroke ? ctx.stroke() : ctx.fill(fillRule)
}
drawStar({ stroke: true })
ctx.translate(115, 0)
drawStar()
ctx.translate(115, 0)
drawStar()
ctx.translate(115, 0)
drawStar({ fillRule: 'evenodd' })
复制代码
圆的标准方程为 (x-a)²+(y-b)²=r²
,其中 (a, b) 为圆心,r 为半径。只要肯定了圆心和半径便能肯定一个圆。
扇形为圆周的一部分以及对应的圆周角组成,是圆的一部分。
svg 使用元素 circle
表明圆,(cx, cy)
为圆心,r
为半径。使用元素 ellipse
表明椭圆,rx
和 ry
表明长轴和短轴。
<circle cx="50" cy="50" r="49"></circle>
<ellipse cx="50" cy="50" rx="30" ry="40"></ellipse>
复制代码
svg 对于扇形没有现成的元素,须要使用 path
来做扇形。固然 canvas 除了矩形剩余图形都是使用 path
来绘制出来。
path
中的 d
表明路径,d
有诸多属性
(x, y, r, d1, d2, direction)
,A 用来画椭圆,详细参考 MDN SVG Paths。若是使用 svg 画扇形的话,须要确认圆弧的两个端点以及圆心的位置,远没有 canvas 直接使用圆心角肯定一个圆方便地多
<path d="M 50 50 L 99 50 A 49 49 0 1 0 50 99"></path>
复制代码
canvas 使用方法 arc
进行圆的绘制,有六个参数 void ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
。使用 startAngle
和 endAngle
能够很方便地绘制扇形。 可是无法绘制椭圆是硬伤
const canvas = document.getElementById('circle')
const ctx = canvas.getContext('2d')
function drawArc (radius, { anticlockwise = false, stroke = false } = {}) {
ctx.beginPath()
ctx.arc(50, 50, 49, 0, radius / 180 * Math.PI * 2, anticlockwise)
ctx.lineTo(50, 50)
ctx.closePath()
stroke ? ctx.stroke() : ctx.fill()
}
drawArc(360)
ctx.translate(115, 0)
drawArc(60, { anticlockwise: true })
ctx.translate(115, 0)
drawArc(60)
ctx.translate(115, 0)
ctx.scale(0.6, 0.8)
ctx.translate(20, 10)
drawArc(360)
复制代码
渐变分为线性渐变和径向渐变
略
linearGradient
表明线性渐变,radialGradient
表明径向渐变。
<svg>
<defs>
<linearGradient id="linear" x1="0" y1="0" x2="0.3" y2="0.3" spreadMethod="reflect">
<stop offset="0" stop-color="red"></stop>
<stop offset="100%" stop-color="#fff"></stop>
</linearGradient>
<radialGradient id="radial" cx="0.5" cy="0.5" r="0.5" fx="0.8" fy="0.8">
<stop offset="0" stop-color="red"></stop>
<stop offset="100%" stop-color="#fff"></stop>
</radialGradient>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#linear)"></rect>
<circle cx="50" cy="50" r="50" fill="url(#radial)" transform="translate(115, 0)"></circle>
</svg>
复制代码
createLinearGradient
表明线性渐变,createRadialGradient
表明径向渐变。
const canvas = document.getElementById('grad')
const ctx = canvas.getContext('2d')
// canvas 实现 reflect 和 repeat 须要本身编程实现
const grad1 = ctx.createLinearGradient(0, 0, 100, 100)
grad1.addColorStop(0, 'red')
grad1.addColorStop(0.3, '#fff')
grad1.addColorStop(0.6, 'red')
grad1.addColorStop(0.9, '#fff')
ctx.fillStyle = grad1
ctx.fillRect(0, 0, 100, 100)
const grad2 = ctx.createRadialGradient(50, 50, 50, 80, 80, 0)
// 注意与 svg 中 stop 的颜色值相反
grad2.addColorStop(0, '#fff')
grad2.addColorStop(1, 'red')
ctx.fillStyle = grad2
ctx.translate(115, 0)
ctx.beginPath()
ctx.arc(50, 50, 50, 0, Math.PI * 2)
ctx.fill()
复制代码
效果页面上的示例是垂直居中
略
svg 使用元素 text
表明文本,属性 text-anchor
和 alignment-baseline
控制垂直居中。
<text x="50" y="50" text-anchor="middle" alignment-baseline="middle">垂直居中</text>
复制代码
canvas 使用属性 textAlign
和 textBaseline
控制垂直居中。
const canvas = document.getElementById('text')
const ctx = canvas.getContext('2d')
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText('垂直居中', 50, 50)
复制代码
效果页面的示例是一个简单的 loading 动画
说到动画和 css, animation
以及 @keyframes
最常被用来制做动画。
可是最新出了 css 的属性 offset-path
能够像 svg 的 animateMotion
同样沿着特定轨迹运动。具体可参考如下
关于动画的元素有三种
关于如下 loading 动画绘制的原理是,圆的半径从大变小,颜色由有至透明
<svg>
<circle cx="50" cy="50" r="49">
<animate attributeName="r" values="50; 5; 50" keyTimes="0; 0.5; 1" dur="3s" repeatCount="indefinite">
</animate>
<animate attributeName="fill" values="red; white; red" dur="3s" repeatCount="indefinite">
</animate>
<circle/>
</svg>
复制代码
canvas 的动画就比较简单粗暴了。大体步骤即是 绘制帧,清画板,绘制帧,循环往复。优势是可定制话程度高。