1.什么是SVG?
描述:
- 一種使用XML描述的2D圖形的語言
- SVG基於XML意味着,SVG DOM中的每個元素都是可用的,可以為某個元素附加Javascript事件處理器。
- 在 SVG 中,每個被繪制的圖形均被視為對象。如果 SVG 對象的屬性發生變化,那么瀏覽器能夠自動重現圖形。
2.什么是canvas?
描述:
- 通過Javascript來繪制2D圖形。
- 是逐像素進行渲染的。
- 其位置發生改變,會重新進行繪制。
3.什么是WebGL 3D?
- 說白了就是基於Canvas的3D框架
- 主要用來做 3D 展示、動畫、游戲。
因為前兩項都是描述2D圖形的,而WebGL是描述3d的,所以以下針對SVG和Canvas做比較。
3.有了Canvas為什么還要使用SVG
最重要的一點是SVG不依賴於終端設備的像素,可以隨意放大縮小但是不會失真
繼續:為什么SVG放大不會失真而Canvas卻會變模糊呢?
因為SVG的渲染的原理是通過對圖形的數學描述來繪圖的,例如:以下哆啦A夢的頭型的思路是,我先畫一個貝塞爾函數,然后填充顏色。
而Canvas的渲染原理是通過對每個像素顏色的填充,最后組成圖形,例如:以下馬里奧的帽子我們可以看出,其實帽子的形狀是由一個個像素填充出來的。
另外Canvas渲染出來的圖叫位圖,SVG渲染出來的圖叫矢量圖

看到這里你肯定會覺得那直接所有圖形都用SVG畫不就行了,位圖就可以直接淘汰了呀,但是SVG畫的圖也有缺點,以下針對兩者的不同做一個對比。
4.兩者的對比

理解適用場景:
從以下這張微軟開發社區公布的性能圖中也可以看出,SVG在繪圖面積較大,數據量較小的時候性能較好,渲染時間較短,而Canvas剛好相反。

5.總結
Canvas和SVG兩者的適用場景不同,開發者在使用是應根據具體的項目需求來選擇相應的渲染方式。
最后附上一個SVG編譯器幫大家更好的理解和使用SVG
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SVG 編輯器</title>
<style>
#toolbox {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 250px;
border-right: 1px solid #CCC;
}
#toolbox h2 {
margin: 0;
padding: 0;
background: #EEE;
font-size: 16px;
height: 24px;
line-height: 24px;
padding: 5px 10px;
}
#toolbox form {
padding: 10px;
}
#canvas {
position: absolute;
left: 260px;
top: 10px;
bottom: 10px;
right: 10px;
box-shadow: 2px 2px 10px rgba(0,0,0,.4);
border-radius: 5px;
}
label {
display: inline-block;
width: 80px;
text-align: right;
}
</style>
</head>
<body>
<div id="toolbox">
<h2>創建</h2>
<form id="create-shape">
<button type="button" create="rect">Rect</button>
<button type="button" create="circle">Circle</button>
<button type="button" create="ellipse">Ellipse</button>
<button type="button" create="line">Line</button>
</form>
<h2>形狀</h2>
<form id="shape-attrs">
請先創建圖形
</form>
<h2>外觀和變換</h2>
<form id="look-and-transform" disabled="disabled">
<p>
<label style="display: inline;">填充</label>
<input id="fill" type="color" value="#ffffff" />
</p>
<p>
<label style="display: inline;">描邊</label>
<input id="stroke" type="color" value="#ff0000" />
<input id="strokeWidth" type="range" value="1" />
</p>
<p>
<label>translateX</label>
<input id="translateX" type="range" min="-400" max="400" value="0" />
<label>translateY</label>
<input id="translateY" type="range" min="-400" max="400" value="0" />
<label>rotate</label>
<input id="rotate" type="range" min="-180" max="180" value="0" />
<label>scale</label>
<input id="scale" type="range" min="-1" max="2" step="0.01" value="1" />
</p>
</form>
</div>
<div id="canvas"></div>
</body>
<script>
var SVG_NS = 'http://www.w3.org/2000/svg';
// 圖形及對應默認屬性
var shapeInfo = {
rect: 'x:10,y:10,width:200,height:100,rx:0,ry:0',
circle: 'cx:200,cy:200,r:50',
ellipse: 'cx:200,cy:200,rx:80,ry:30',
line: 'x1:10,y1:10,x2:100,y2:100'
};
// 默認公共屬性
var defaultAttrs = {
fill: '#ffffff',
stroke: '#ff0000'
};
var createForm = document.getElementById('create-shape');
var attrForm = document.getElementById('shape-attrs');
var lookForm = document.getElementById('look-and-transform');
var svg = createSVG();
var selected = null;
createForm.addEventListener('click', function(e) {
if (e.target.tagName.toLowerCase() == 'button') {
create(e.target.getAttribute('create'));
}
});
attrForm.addEventListener('input', function(e) {
if (e.target.tagName.toLowerCase() != 'input') return;
var handle = e.target;
selected.setAttribute(handle.name, handle.value);
});
lookForm.addEventListener('input', function(e) {
if (e.target.tagName.toLowerCase() != 'input') return;
if (!selected) return;
selected.setAttribute('fill', fill.value);
selected.setAttribute('stroke', stroke.value);
selected.setAttribute('stroke-width', strokeWidth.value);
selected.setAttribute('transform', encodeTranform({
tx: translateX.value,
ty: translateY.value,
scale: scale.value,
rotate: rotate.value
}));
});
function createSVG() {
var svg = document.createElementNS(SVG_NS, 'svg');
svg.setAttribute('width', '100%');
svg.setAttribute('height', '100%');
canvas.appendChild(svg);
svg.addEventListener('click', function(e) {
if (e.target.tagName.toLowerCase() in shapeInfo) {
select(e.target);
}
});
return svg;
}
function create(name) {
var shape = document.createElementNS(SVG_NS, name);
svg.appendChild(shape);
select(shape);
}
function select(shape) {
var attrs = shapeInfo[shape.tagName].split(',');
var attr, name, value;
attrForm.innerHTML = "";
while(attrs.length) {
attr = attrs.shift().split(':');
name = attr[0];
value = shape.getAttribute(name) || attr[1];
createHandle(shape, name, value);
shape.setAttribute(name, value);
}
for (name in defaultAttrs) {
value = shape.getAttribute(name) || defaultAttrs[name];
shape.setAttribute(name, value);
}
selected = shape;
updateLookHandle();
}
function createHandle(shape, name, value) {
var label = document.createElement('label');
label.textContent = name;
var handle = document.createElement('input');
handle.setAttribute('name', name);
handle.setAttribute('type', 'range');
handle.setAttribute('value', value);
handle.setAttribute('min', 0);
handle.setAttribute('max', 800);
attrForm.appendChild(label);
attrForm.appendChild(handle);
}
function updateLookHandle() {
fill.value = selected.getAttribute('fill');
stroke.value = selected.getAttribute('stroke');
var t = decodeTransform(selected.getAttribute('transform'));
translateX.value = t ? t.tx : 0;
translateY.value = t ? t.ty : 0;
rotate.value = t ? t.rotate : 0;
scale.value = t ? t.scale : 1;
}
function decodeTransform(transString) {
var match = /translate\((\d+),(\d+)\)\srotate\((\d+)\)\sscale\((\d+)\)/.exec(transString);
return match ? {
tx: +match[1],
ty: +match[2],
rotate: +match[3],
scale: +match[4]
} : null;
}
function encodeTranform(transObject) {
return ['translate(', transObject.tx, ',', transObject.ty, ') ',
'rotate(', transObject.rotate, ') ',
'scale(', transObject.scale, ')'].join('');
}
</script>
</html>
