畫影圖形: SVG & Canvas 圖形對比

畫影圖形指描畫犯人面影,懸賞通緝。這裏用法明顯有問題,不過取其表義而已。javascript

在一個前端看來,畫圖有三種方法,Cavas,SVG 以及 CSS。至於三者優劣,將在此針對各類圖形作逐一比較,有方,圓,橢圓,扇形,多邊形,漸變,文本處理以及動畫css

如下是在 codepen 的代碼以及實際效果地址,可打開實際效果地址進行調試html

Stroke and Fill

描邊與填充是圖形的基本屬性。前端

CSS

在 CSS 中是 border-color 以及 background-color 屬性。html5

.rect {
  border: 1px solid #fff;
  background-color: #000;
  width: 100px;
  height: 100px;
}
複製代碼

SVG

在 SVG 中是 fillstroke。能夠直接做爲 element 的屬性,另外也能夠寫到 css 樣式中java

<rect width="100" height="100" fill="#fff" stroke="#000"></rect>
複製代碼

也能夠做爲 css 樣式css3

.rect {
  fill: #fff;
  stoke: #000;
}
複製代碼

除了基本的描邊,SVG 也有如下屬性,此是 canvas 以及 css 所不及的編程

  • stroke-dasharray
  • stroke-dashoffset
  • stroke-linecap
  • stroke-linejoin

Canvas

在 Canvas 中,是 fillStylestrokeStyle 屬性。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)
複製代碼

矩形

CSS

不做介紹svg

.rect {
  width: 100px;
  height: 100px;
  border-radius: 15px;
}
複製代碼

SVG

<svg>
  <rect width="100" height="100" rx="15" ry="15"></rect>
</svg>
複製代碼

rxry 設置圓角矩形大小

Canvas

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]]

CSS

SVG

svg 使用元素 polyline 以及 polygonpolygon 會把終點和起點鏈接起來,造成閉合圖形。

points 屬性指連成多邊形的點。

fill-rule 決定哪裏是圖形的內部。nonzero 表明若是被路徑所包圍,便是內部,fill-rule 表明從某一點出發,到無限遠處,若是隻途經奇數條邊,則在圖形內部。由於效果地址中的五角星是空心的。

<polyline points="81, 95 0, 36 100, 36 19, 95 50, 0" fill-rule="evenodd"></polyline>
複製代碼

Canvas

canvas 須要使用 path 來繪製路徑。

使用 moveTolineTo 來繪製直線,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 爲半徑。只要肯定了圓心和半徑便能肯定一個圓。

扇形爲圓周的一部分以及對應的圓周角組成,是圓的一部分。

CSS

SVG

svg 使用元素 circle 表明圓,(cx, cy) 爲圓心,r 爲半徑。使用元素 ellipse 表明橢圓,rxry 表明長軸和短軸。

<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 有諸多屬性

  • M,Move,與 canvas 的 move 方法一致
  • L,Line,與 canvas 的 line 方法一致
  • A,Arc,七個參數 (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

canvas 使用方法 arc 進行圓的繪製,有六個參數 void ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);。使用 startAngleendAngle 能夠很方便地繪製扇形。 可是無法繪製橢圓是硬傷

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)
複製代碼

漸變

漸變分爲線性漸變和徑向漸變

CSS

SVG

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>
複製代碼

Canvas

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()
複製代碼

文本

效果頁面上的示例是垂直居中

CSS

SVG

svg 使用元素 text 表明文本,屬性 text-anchoralignment-baseline 控制垂直居中。

<text x="50" y="50" text-anchor="middle" alignment-baseline="middle">垂直居中</text>
複製代碼

Canvas

canvas 使用屬性 textAligntextBaseline 控制垂直居中。

const canvas = document.getElementById('text')
const ctx = canvas.getContext('2d')

ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText('垂直居中', 50, 50)
複製代碼

動畫

效果頁面的示例是一個簡單的 loading 動畫

CSS

說到動畫和 css, animation 以及 @keyframes 最常被用來製做動畫。

可是最新出了 css 的屬性 offset-path 能夠像 svg 的 animateMotion 同樣沿着特定軌跡運動。具體可參考如下

SVG

關於動畫的元素有三種

  • animate
  • animateTransform
  • 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

canvas 的動畫就比較簡單粗暴了。大體步驟即是 繪製幀,清畫板,繪製幀,循環往復。優勢是可定製話程度高。

參考

相關文章
相關標籤/搜索