HTML5 繪製圖形 Canvas 與 SVG 的基本用法

HTML5 繪製圖形 Canvas 與 SVG 的基本用法(筆記)

Canvas和SVG是HTML5中主要的2D圖形技術,前者提供畫布標籤和繪製API,後者是一整套獨立的矢量圖形語言,二者有各自的優勢和特點,可適用於不同的場景。


Canvas 與 SVG簡單比較

Canvas SVG
提供API通過JavaScript 繪製 SVG使用 XML 格式定義基於矢量的圖形
逐像素進行渲染 每個被繪製的圖形均被視爲對象
依賴分辨率 不依賴分辨率(圖像在放大或改變尺寸的情況下其圖形質量不會有損失)
渲染速度快 適合圖像密集型的遊戲 複雜度高會減慢渲染速度 不適合遊戲應用

Canvas基本用法

首先,在HTML中添加 canvas 標籤,即在html中創建了一個畫布容器:

<canvas id="myCanvas" width="200" height="100"></canvas>

然後在JS腳本中獲取canvas DOM對象,創建context對象即可開始使用其API方法在canvas創建的畫布上進行繪製了:

<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
context.fillStyle="#FF0000";
context.fillRect(0,0,150,75);
</script>

canvas API簡單介紹

  • 座標
    canvas座標系統與大多數繪圖API一樣,畫布左上角座標爲(0,0),x軸方向水平向右,y軸方向垂直向下,單位爲像素:
    這裏寫圖片描述
  • 繪製矩形
    首先介紹兩種繪製方法:context.fill() 和 context.stroke(),其中fill()爲填充方法,stroke()爲繪製輪廓的方法,以繪製矩形爲例:
context.fillStyle="#FF0000";    //設置填充樣式
context.strokeStyle="rgb(0,165,255)";    //設置輪廓樣式
context.lineWidth=4;     //設置繪製線寬
context.rect(0,0,150,75);     //創建矩形形狀(x,y,width,height)
context.fill();    //填充矩形
context.stroke();    //繪製矩形輪廓

繪製結果如圖:
這裏寫圖片描述
需要在繪製圖形前設置樣式和顏色,顏色設置一般有以下幾種方式:

  1. ctx.fillStyle = “orange”;
  2. ctx.fillStyle = “#FFA500”;
  3. ctx.fillStyle = “rgb(255,165,0)”;
  4. ctx.fillStyle = “rgba(255,165,0,1)”;
    其中,rgba第四個參數爲透明度。

rect()方法只是創建了矩形形狀,並沒有將其繪製出來,API也提供了直接繪製出矩形的方法fillRect(x,y,width,height), strokeRect(…),還有清除矩形的方法clearRect(…)。

  • 繪製路徑和形狀
    先看示例代碼:
    /*填充三角形*/
    context.beginPath();     //新建一條路徑
    context.moveTo(25,25);   //將筆觸移動到指定的座標
    context.lineTo(105,25);     //創建到指定座標的直線
    context.lineTo(25,105);
    context.fill();

    /*描邊三角形*/
    context.beginPath();
    context.moveTo(125,125);
    context.lineTo(125,45);
    context.lineTo(45,125);
    context.closePath();     //閉合路徑
    context.stroke();

繪製結果:
這裏寫圖片描述
其中,moveTo(x,y)方法指將路徑起始點放在哪,即畫路徑筆放在哪個地方,這時還並沒有創建出線條,繼續moveTo到下一個座標並不會產生路徑,只是改變了筆的位置;而lineTo(x,y)方法則創建出了路徑(並沒有繪製出來),且筆觸的位置也跟着改變了;另外closePath()方法指讓路徑閉合,如圖創建出了閉合的三角形。

:beginPath()指開始創建路徑,如果畫下一條路徑時沒有重新調用beginPath(),繪製下一條路徑時,上一條路徑也會重新繪製一遍;fill()會自動閉合路徑,與closePath()一樣,而stroke()不會。

繪製一般的形狀,基本都可以使用創建路徑的方式,還有一些其他方法可以創建弧線、曲線等路徑,從而可以繪製出更復雜的圖形:

  1. 弧形

arc(x, y, radius, startAngle, endAngle, anticlockwise);

圓心:(x,y), 半徑:radius,起始弧度:startAngle ,結束弧度:endAngle,逆時針與否:anticlockwise(默認false爲順時針,true爲逆時針)

示例:

context.fillStyle = "rgb(255,165,0)";
context.beginPath();
context.arc(50,50,40,Math.PI/2,Math.PI,true);
context.fill();

繪製結果:
這裏寫圖片描述
2. 曲線
quadraticCurveTo(cp1x, cp1y, x, y)
繪製貝塞爾曲線,cp1x, cp1y爲控制點,x,y爲結束點

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
繪製二次貝塞爾曲線,cp1x, cp1y爲控制點一,cp2x,cp2y爲控制點二,x,y爲結束點
這裏寫圖片描述
如圖,紅色爲控制點,藍色爲起始和結束點
示例:

//二次曲線
    context.fillStyle="#FF0000";
    context.beginPath();
    context.moveTo(75,40);
    context.bezierCurveTo(75,37,70,25,50,25);
    context.bezierCurveTo(20,25,20,62.5,20,62.5);
    context.bezierCurveTo(20,80,40,102,75,120);
    context.bezierCurveTo(110,102,130,80,130,62.5);
    context.bezierCurveTo(130,62.5,130,25,100,25);
    context.bezierCurveTo(85,25,75,37,75,40);
    context.fill();

繪製結果:
這裏寫圖片描述

  • 繪製文本
    繪製文本方法:

    fillText(text, x, y [, maxWidth]); //填充文本,maxWidth 繪製的最大寬度(可選)
    strokeText(text, x, y [, maxWidth]); //繪製文本邊框
    直接看示例:

<canvas id="myCanvas" width="500" height="200" style="border:1px solid #c3c3c3;"></canvas>

<script>
var c=document.getElementById("myCanvas");
var context=c.getContext("2d");
    context.save();
    context.strokeStyle="#0000ff";
    context.moveTo(0,50);
    context.lineTo(500,50);
    context.moveTo(0,80);
    context.lineTo(500,80);
    context.moveTo(90,0);
    context.lineTo(90,200);
    context.moveTo(0,80);
    context.lineTo(500,80);
    context.stroke();
    context.restore();
context.font="30px Arial";    //設置字體
context.textBaseline = "middle";    //基線對齊方式
context.textAlign="left";   //文本對齊方式(相對於指定座標)
context.fillText("Hello World",90,50);
context.textBaseline = "hanging";
context.textAlign="center"; 
context.strokeText("Hello World",90,80);
</script>

繪製結果:
這裏寫圖片描述
其中灰色邊框表示畫布輪廓,繪製的藍色線條顯示了文本對齊的方式。

  • 繪製圖像
    繪製圖像方法共有三種:
    context.drawImage(image, x, y);
    //x 和 y 是其在目標 canvas 裏的起始座標

    context.drawImage(image, x, y, width, height);
    //width 和 height,這兩個參數用來控制 當像canvas畫入時應該縮放的大小

    drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
    這個方法可以實現圖片切片,對應參數如圖:
    這裏寫圖片描述
    實例如下:

context.drawImage(img,60,100,100,100,50,0,100,100);

結果如圖:
這裏寫圖片描述這裏寫圖片描述

另外還可以通過clip()方法對圖片進行裁剪:

context.beginPath();
    context.arc(100,150,50,0,2*Math.PI);
    context.clip();
    context.drawImage(img,0,0);

結果如圖:
這裏寫圖片描述
繪製圖片還可以選擇平鋪模式:”repeat” (x,y雙向平鋪),”repeat-x” (水平平鋪),”repeat-y” (垂直平鋪), “no-repeat” (不平鋪).
實例如下:

  var pattern = context.createPattern(img, 'repeat');
  context.fillStyle = pattern;
  context.fillRect(0,0,400,400);

如圖所示:
這裏寫圖片描述這裏寫圖片描述

  • 另外一些常用方法
  • context.save();//保存當前context狀態,包括fillStyle,strokeStyle等
  • context.restore();//還原保存的context狀態
  • context.getImageData(sx,sy,sw,sh);//sx,sy爲相對canvas座標,sw、sh爲相對canvas寬高,獲取像素顏色數組,數組格式爲[r1,g1,b1,a1,r2,g2,b2,a2,…..]從左到右,從上到下排列的像素數組
  • context.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);//根據像素數組繪製圖像,dx,dy爲繪製座標,dirty爲圖像數據限定的矩形範圍
  • context.transform(m11, m12, m21, m22, dx, dy);//圖像變換,m11 水平縮放,m12 水平傾,m21 垂直傾斜,m22垂直縮放,dx 水平移動,dy 垂直移動

    SVG基本用法

    在 HTML5 中,您能夠將 SVG 元素直接嵌入 HTML 頁面中,Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 都支持內聯SVG。

<!DOCTYPE html>
<html>
<body>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190">
  <polygon points="100,10 40,180 190,60 10,60 160,180"
  style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;">
</svg>

</body>
</html>

如上例,xmlns爲命名空間,polygon 爲創建了一個多邊形圖形。

svg主要有以下元素:
矩形 < rect >
圓形 < circle >
橢圓 < ellipse >
線 < line >
折線 < polyline >
多邊形 < polygon >
路徑 < path >
文本 < text >

  • 矩形
<rect x="50" y="20" rx="20" ry="20" width="150" height="100"
  style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/>

這裏寫圖片描述
其中 x,y 爲圖形左上角相對父元素svg的座標,rx,ry分別爲x,y方向的圓角半徑;style定義樣式,也可以拆分成屬性寫法:

<rect x="50" y="20" rx="50" ry="150" width="150" height="100" fill="red" stroke="black" stroke-width=5  opacity=0.5 />
  • 圓形
 <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="pink" />

這裏寫圖片描述cx和cy定義圓點的x和y座標。如果省略cx和cy,圓的中心會被設置爲(0, 0)

  • 橢圓
  <ellipse cx="120" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" />

這裏寫圖片描述 cx,cy定義的橢圓中心的座標,rx,ry定義的水平和垂直半徑

  • 直線
<line x1="0" y1="0" x2="200" y2="200"
  style="stroke:rgb(255,0,0);stroke-width:2"/>

這裏寫圖片描述 x1,y1爲起始點座標,x2,y2爲終點座標

  • 多邊形
<polygon points="100,10 40,180 190,60 10,60 160,180" style="fill:red;stroke:black;stroke-width:5;fill-rule:nonzero;"/>

這裏寫圖片描述points 就是多邊形的各個頂點
注:這裏需要注意的是fill-rule,有幾個屬性值 nonzero | evenodd | inherit
關於fill-rule,我這裏以下是引用另外一位作者的文章:

http://blog.csdn.net/mishiwjp/article/details/53484235

nonzero
字面意思是“非零”。按該規則,要判斷一個點是否在圖形內,從該點作任意方向的一條射線,然後檢測射線與圖形路徑的交點情況。從0開始計數,路徑從左向右穿過射線則計數加1,從右向左穿過射線則計數減1。得出計數結果後,如果結果是0,則認爲點在圖形外部,否則認爲在內部。
這裏寫圖片描述

evenodd
字面意思是“奇偶”。按該規則,要判斷一個點是否在圖形內,從該點作任意方向的一條射線,然後檢測射線與圖形路徑的交點的數量。如果結果是奇數則認爲點在內部,是偶數則認爲點在外部。下圖演示了evenodd 規則:
這裏寫圖片描述
一看兩幅圖,你可能會有兩個疑問,這些線段的箭頭是什麼?兩組圖形的第三幅圖爲什麼是一樣的?其實這些線段的方向是由我們給出的座標的順序決定的,points=”100,0 160,180 10,60 190,60 40,180”,起始點是最上方的點,然後是右下,最左邊,最右邊,再到左下。把這些點按順序連起來就變成了五角星。
這裏寫圖片描述
先看nozero時,怎麼判斷點是否在內部區域。射線1和圖形線段只有一個交點,爲從左到右,所以結果是1,判定爲內部區域;射線2有兩個交點,都是從左到右,結果是2,內部區域;射線3有三個交點,兩個從左到右,一個從右到左,結果是1,內部區域;射線4有四個交點,兩個從左到右,兩個從右到左,結果是0,所以是外部區域。
evenodd時,只判斷交點個數,所以1,3都是內部區域,2,4都是外部區域。

  • 曲線
<polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" style="fill:white;stroke:red;stroke-width:4" />

這裏寫圖片描述 points指定了曲線的拐點

  • 路徑
<path d="M150 0 L75 200 L225 200 Z" fill="orange" stroke="black" stroke-width="3" />

這裏寫圖片描述
d定義路徑屬性,其中有一些路徑命令:
M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Bézier curve
T = smooth quadratic Bézier curveto
A = elliptical Arc
Z = closepath
命令後接座標值
注:以上所有命令均允許小寫字母。大寫表示絕對定位,小寫表示相對定位

  • 文本
<svg>
 <defs>
    <path id="MyPath"
          d="M 100 200 
             C 200 100 300   0 400 100
             C 500 200 600 300 700 200
             C 800 100 900 100 900 100" />
  </defs>
  <use xlink:href="#MyPath" fill="none" stroke="red"  />
  <text font-family="Verdana" font-size="42.5">
    <textPath xlink:href="#MyPath">Hello world</textPath>
  </text>
</svg>

這裏寫圖片描述
SVG 允許我們定義以後需要重複使用的圖形元素。 建議把所有需要再次使用的引用元素定義在defs元素裏面。這樣做可以增加SVG內容的易讀性和可訪問性。 在defs元素中定義的圖形元素不會直接呈現。 你可以在你的視口的任意地方利用 < use >元素呈現這些元素。
SVG 也可以根據 < path > 元素的形狀來放置文字。 只要在textPath元素內部放置文本,並通過其xlink:href屬性值引用< path >元素,我們就可以讓文字塊呈現在< path >元素給定的路徑上了。

  • g元素
    元素g是用來組合對象的容器。添加到g元素上的變換會應用到其所有的子元素上。添加到g元素的屬性會被其所有的子元素繼承。此外,g元素也可以用來定義複雜的對象,之後可以通過< use >元素來引用它們。
<body>
<svg width="300" height="300" viewBox="0 0 95 50"
     xmlns="http://www.w3.org/2000/svg">
  <g stroke="green" fill="white" stroke-width="5">
    <circle cx="25" cy="25" r="15" />
    <circle cx="40" cy="25" r="15" />
    <circle cx="55" cy="25" r="15" />
    <circle cx="70" cy="25" r="15" />
  </g>
</svg>

這裏寫圖片描述
注: viewBox視圖盒子,viewBox = x y width height,x 和 y 值決定viewBox的左上角,,width和height決定視窗的寬高。如果svg圖形太大或者太小,就可以用ViewBox屬性來調整在頁面中的顯示範圍、大小。
上例svg width=”300” height=”300” viewBox=”0 0 95 50” 表示svg的寬95 高50範圍顯示在寬300 高300的視圖。(FireFox3.6 下座標系相反,座標系建立在 svg 圖形上。)
這裏寫圖片描述
參考另外一位作者的解釋比較接地氣,容易理解:

http://www.zhangxinxu.com/wordpress/2014/08/svg-viewport-viewbox-preserveaspectratio/

嗯,暫時就這些了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章