前端圖形:SVG與Canvas

2022-10-20 21:00:27

00、前端圖形

前端程式碼實現圖形的幾種方式:CSS、SVG、Canvas(主要是JavaScript編碼)

CSS也是可以畫圖的,需要藉助於高寬、邊框borderclip-path裁剪、漸變色背景等屬性來模擬實現各種圖形,當然只能實現一些簡單的圖形。

border:用四條邊框樣式屬性的各種組合變換,實現一些簡單的圖形。網上也有畫一些稍微複雜的圖形,如哆啦A夢,但程式碼量稍多,可讀性不好,並不推薦。

<div class="gcss">
  <p class="border">border</p>
  <p class="rborder">圓角按鈕</p>
  <p class="radio"></p>radio
  <p class="triangle1"></p>三角形
  <p class="triangle2"></p>三角形
</div>
<style>
  .gcss p {
    display: inline-block;
    text-align: center; vertical-align: middle;
  }
  .border {
    border: 30px solid;
    border-color: aqua tan violet peru;
    border-radius: 20px;
  }        
  .rborder {
    background-color: #b1ccf3;
    width: 100px; height: 40px; line-height: 40px;
    border-radius: 20px;
  }
  .radio {
    width: 40px; height: 40px;
    border-radius: 50%;
    border: 10px solid;
  }
  .triangle1 {
    border: 50px solid #0001;
    border-left-color: red;
  }
  .triangle2 {
    border-left: 50px solid #0001;
    border-right: 50px solid #0001;
    border-bottom: 50px solid red;
  }
</style>


01、< svg>向量圖形

< svg>可縮放向量圖形(Scalable Vector Graphics,SVG),是一種基於 XML(數學)描述的二維的向量圖形,內容可以直接插入網頁,成為DOM的一部分,然後用 JavaScript 和 CSS 進行操作。SVG 內容也可以寫在一個獨立檔案中,然後用CSS(background-url)、<img><object><embed><iframe>來參照。

大多數現代瀏覽器都支援SVG 圖形,越來越多的專案在使用SVG圖形,簡單的像圖示,複雜的一些圖表Chart也有不少是基於SVG實現的。相比於點陣圖,體積更小,可無線縮放而不失真。

比較 向量圖形 點陣圖
儲存的資料 儲存元素、演演算法資料 儲存畫素資料
儲存大小
縮放效果 無線縮放,不失真 固定大小,放大會失真
可維護性 很容易修改 修改麻煩
擴充套件性 支援CSS、JS 不支援
檔案格式 .svg,直接嵌入資料到頁面 .bmp/.png/.jpg/.gif,< img>可嵌入svg檔案
支援的元素 <svg><img><iframe><object> <img><iframe>
相容性 IE9開始支援 較好
渲染效能 複雜的SVG會佔用很多時間 穩定
網路傳輸效能 和頁面資料一起,體積小,速度快 需單獨請求圖片資源
快取 隨網頁內容一起,不可單獨快取 圖片可單獨快取

1.1、< svg>元素

<svg>內部支援多種圖形演演算法,基礎的如線line、圓形<circle>、矩形rect、文字text,複雜的有折線polyline、多邊形polygon、路徑資料path等。這些圖形都以子元素的形式組合,因此也就都支援CSS、JS的操作了。iconfont-阿里巴巴向量圖示庫上有非常豐富的< svg>向量圖形。

元素/屬性 描述 值/範例
< svg> 向量圖形元素
viewBox SVG 畫布顯示區域,這裡 1 單位等同於 1 螢幕單位,SVG裡的座標、尺寸都是基於此畫布區域 viewBox="0 0 300 200"
width、height 寬度、高度 width="300" height="200"
xmlns xml標籤的名稱空間,為了區分html、svg,可以省略
< line> 線段
x1、y1 起點x、y座標 <line x1="0" y1="100" />
x2、y2 終點x、y座標 x2="300" y2="100"
< rect> 矩形:<rect x="5" y="50" height="100" width="290"/>
x、y 起點座標
width、height 矩形的寬、高
rx、ry x、y方向的圓角半徑。r=radius 半徑 rx="50" ry="50"
<circle/ellipse> 圓和橢圓:<circle cx="150" cy="100" r="80"/>
cx、cy 圓心的x、y座標
r 圓的半徑長度
rx、ry 橢圓的x、y半徑
<polyline/polygon> 折線、多邊形,兩者資料結構相似,多邊形是自動首尾連線封閉成一個區域(Polygon /ˈpɒlɪɡən/ 多邊形)
points x、y座標的集合,多個座標逗號,分割 points="0 0, 20 40, 70 80/>
< path> 路徑,很常用、很強大的圖形繪製,資料在屬性d
< d> 路徑資料&lt; path&gt;最重要的屬性,由多組命令+ 座標點組成 d="M 50 5 H250 V195 H50 Z"
M x y 移動畫筆到座標點x、y M50 5
L x y 劃線到座標x、y L 250 0
H x 繪製水平線,到座標x;小寫h的座標為相對位置 H 250
V y 繪製垂直線,到座標y;小寫v的座標為相對位置 V195
Z 閉合路徑(closepath),放到最後用於閉合路徑
C* 繪製曲線,包括貝塞爾曲線、圓弧。
<text> 文字標籤,支援CSS樣式中的文字樣式
x、y 文字開始位置
font-size 字型大小
< textPath> 文字繪製的路徑,這個就比較有趣了 <textPath xlink:href="#path1">
公共屬性 部分屬性可以用CSS設定,支援hover偽類
stroke 筆畫顏色(stroke /stroʊk/ 筆畫) ,包括線段、形狀線條。 stroke="red"
stroke-width 畫筆線寬 stroke-width="10"
fill 填充顏色,填充一個區域(矩形、圓形等) fill="#0001"

❗小提示:注意伺服器新增對svg的支援,及gzip壓縮。

<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
	<circle cx="150" cy="100" r="80" fill="green" />
	<circle cx="150" cy="100" r="70" fill="#fff" />                
	<text x="150" y="125" font-size="60" text-anchor="middle" fill="orange">SVG</text>
	<line x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8"/>
</svg>
<svg class="icon" height="200" viewBox="0 0 300 200" version="1.1">
	<rect x="5" y="50" rx="50" ry="50" height="100" width="290" fill="white" stroke="blue" stroke-width="10"/>
	<path d="M 50 5 H250 V195 H50 Z" stroke="red" stroke-width="10" fill="#00000001" />
	<text x="145" y="125" font-size="60" text-anchor="middle" fill="#fab">Path</text>
</svg>
<style>
	svg:hover{
		background-color: aliceblue;
		stroke: red;
		stroke-width: 1px;
		fill: red;
	}
</style>

1.2、動畫

SVG 本身就是一個HTML元素,因此動畫可以用CSS的動畫來實現(參考 CSS動畫),SVG中也有專門用於實現動畫的<animate>子元素。這裡範例採用JavaScript+transform變換實現旋轉效果。

<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
	<circle cx="150" cy="100" r="80" fill="green" />
	<circle cx="150" cy="100" r="70" fill="#fff" />
	<text class="svgc" x="150" y="125" font-size="60" text-anchor="middle" fill="orange" >SVG</text>
	<line class="svgc" x1="0" y1="100" x2="300" y2="100" stroke="white" stroke-width="8" />
</svg>
<script>
	let svgcs = document.querySelectorAll(".svgc");
	//設定中心點
	svgcs.forEach(element => {
		element.setAttribute("transform-origin", '150 100');
	});
	let deg = 0;
	setInterval(() => {
		deg = deg > 360 ? 0 : deg+4;
		svgcs.forEach(element => {
			element.setAttribute("transform", `rotate(${deg})`);
		});
	}, 100);
</script>
<!-- 用CSS動畫實現的版本 -->
<style>
	.svgc {
		transform-origin: 150px 100px;
		animation: svgc-routate 2s linear 1s infinite;
	}
	@keyframes svgc-routate {
		from {
			transform: rotate(0deg);
		}
		to {
			transform: rotate(360deg);
		}
	}
</style>

1.3、svg工具/資源/庫