HTML5 Canvas 2D繪圖


為了防止無良網站的爬蟲抓取文章,特此標識,轉載請注明文章出處。LaplaceDemon/ShiJiaqi。

http://www.cnblogs.com/shijiaqi1066/p/4851774.html

 

 

 

Canvas

Canvas標簽,用於在web中繪制各種圖形。Canvas為基於像素的繪圖,繪制的圖像是位圖。也即Canvas繪圖的基本單位是像素。Canvas是一個相當於畫板的html節點,用js操作繪圖。

 

Canvas特點

  • 依賴分辨率。
  • 不支持事件處理器。
  • 弱的文本渲染能力。
  • 能夠以 .png 或 .jpg 格式保存結果圖像。
  • 最適合圖像密集型的游戲,其中的許多對象會被頻繁重繪。

 

一、Canvas基礎

若瀏覽器不支持HTML5的 <canvas>標簽。則把不支持信息寫在<canvas></canvas>之間。

例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <canvas id="myCanvas" width="600" height="300">
        你的瀏覽器還不支持哦
    </canvas>
</body>
</html>

不建議使用CSS來制定canvas的width,height。因為canvas不光需要指定其dom的寬高,還需要指定canvas內部畫布分辨率的大小。

<canvas>標簽,有兩個基本屬性:height 與width。當兩個屬性的值改變時,該畫布上的任何繪圖都會擦除掉。

  • height的默認值是 150。
  • width默認值是 300。

 

 

1. Canvas繪圖初步

cancas的2d繪圖對象的全稱為CanvasRenderingContext2D對象。CanvasRenderingContext2D理解為canvas的畫筆。

使用canvas dom對象的 getContext() 方法並把"2d"作為方法參數,從而獲取CanvasRenderingContext2D對象。無論調用多少次getContext()方法,獲取的對象都都是相同的。

var canvas=document.getElementById("myCanvas");
var context = canvas.getContext("2d");

 

canvas的基本用法是:設置繪畫動作,執行繪畫動作。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black">
        你的瀏覽器還不支持哦
    </canvas>
    <script type="text/javascript">
        var canvas=document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

        // 狀態設置
        context.moveTo(100,100);
        context.lineTo(700,700);

        // 繪制
        context.stroke();
    </script>
</body>
</html>

繪圖結果:

 

 

2. Canvas Context 的屬性

fillStyle 屬性:用來填充路徑的當前的顏色、模式或漸變。這個屬性可以設置為一個字符串或者一個 CanvasGradient 對象 或 CanvasPattern 對象。當設置為一個字符串時,它被解析為一個 CSS 顏色值並且用來進行實心填充。當設置為一個 CanvasGradient 或 CanvasPattern 對象,通過使用指定的漸變或模式來完成填充。

globalAlpha 屬性:指定在畫布上繪制的內容的不透明度。這個值的范圍在 0.0(完全透明)和 1.0(完全不透明)之間。默認值為 1.0。

globalCompositeOperation 屬性:指定顏色如何與畫布上已有的顏色組合(合成)。

lineCap 屬性:指定線條的末端如何繪制。合法的值是 "butt"、"round" 和 "square"。默認值是 "butt"。

lineJoin 屬性:指定兩條線條如何連接。合法的值是 "round"、"bevel" 和 "miter"。默認值是 "miter"。

lineWidth 屬性:指定了畫筆(繪制線條)操作的線條寬度。默認值是 1.0,並且這個屬性必須大於 0.0。較寬的線條在路徑上居中,每邊有線條寬的一半。

miterLimit 屬性:當 lineJoin 屬性為 "miter" 的時候,這個屬性指定了斜連接長度和線條寬度的最大比率。如需更多細節,請參閱 miterLimit 屬性參考頁。

shadowBlur 屬性:指定羽化陰影的程度。默認值是 0。陰影效果得到 safari 的支持,但是並沒有得到 FireFox 1.5 或 Opera 9 的支持。

shadowColor 屬性:把陰影的顏色指定為一個 CSS 字符串或 Web 樣式字符串,並且可以包含一個 alpha 部分來表示透明度。默認值是 black。陰影效果得到 Safari 的支持,但是並沒有得到 FireFox 1.5 或 Opera 9 的支持。

shadowOffsetX, shadowOffsetY 屬性:指定陰影的水平偏移和垂直偏移。較大的值使得陰影化的對象似乎漂浮在背景的較高位置上。默認值是 0。陰影效果得到 Safari 的支持,但是並沒有得到 FireFox 1.5 或 Opera 9 的支持。

strokeStyle 屬性:指定了用於畫筆(繪制)路徑的顏色、模式和漸變。這個屬性可能是一個字符串,或者一個 CanvasGradient 對象 或 CanvasPattern 對象。如果是一個字符串,它被解析為一個 CSS 顏色值,並且畫筆用所得的實色來繪制。如果這個屬性的值是一個 CanvasGradient 對象或 CanvasPattern 對象,畫筆使用這個漸變或模式來實現。

 

 

3. Canvas Context 實例的繪圖方法

繪制路徑

beginPath() :beginPath() 丟棄當前定義的路徑,開始一條新的路徑。

closePath() :繪制路徑結束,它會繪制一個閉合的區間,添加一條起始位置到當前坐標的閉合曲線。

moveTo(x,y) :設置繪圖起始坐標。

lineTo(x,y) :從最后一點到點(x,y)繪制一條直線。

arc(x,y,radius,startAngle,endAngle,anticlockwise) :繪制中心點在(x,y)的弧,半徑為radius,角度在[startAngle,endAngle]之間(角度單位為弧度)。anticlockwise為布爾類型,若為true表示逆時針;若為false表示順時針。

arcTo(x1, y1, x2, y2, radius) :創建兩切線之間的弧/曲線。圓弧是半徑為radius的圓的部分。該圓弧有一個點與當前位置到P1(x1,y1)的線段相切,還有一個點和從P1(x1,y1)到P2(x2,y2)的線段相切。這兩個切點就是圓弧的起點和終點,圓弧繪制的方向就是連接這兩個點的最短圓弧的方向。

bezierCurveTo(c1x,c1y,c2x,c2y,x,y) :使用控制點(c1x,c2y)和(c2x,c2y)從最后一點到點(x,y)繪制一條三次貝塞爾曲線。

quadraticCurveTo(cx,cy,x,y) :控制點(cx,cy)從最后一點到點(x,y),繪制一條貝塞爾曲線。

rect(x,y,width,height) :為當前路徑添加一條矩形路徑。矩形是路徑的一個子路徑,沒有和路徑中的任何其他子路徑相連。當 rect() 方法返回時,當前位置是 (0,0)。

stroke() :渲染路徑。

 

說明:

調用beginPath()方法表示新路徑的開始。

調用closePath(),表示路徑閉合。

beginPath()方法與closePath()方法不一定要成對出現。當不需要使繪圖路徑封閉,可以不使用closePath,僅僅可以使用beginPath開始下一段路徑的繪制。

如果路徑已經閉合,可以調用 fill()方法用fillStyle填充它。調用 fill()方法時,canvas會自動將未封閉的路徑封閉。

調用clip(),根據路徑創建一個剪裁區域。

isPointInPath(x,y) 判斷路徑是否存在於路徑之上。該方法在路徑關閉之前調用。

 

 

繪制矩形

clearRect(left,top,width,height) :清除指定的矩形區域。

strokeRect(left,top,width,height) :繪制矩形框。無填充色。框的顏色由strokeStyle屬性指定。strokeStyle屬性默認為黑色('#000000')。

fillRect(left,top,width,height) :繪制內部填充顏色的矩形。填充顏色由fillStyle屬性指定。fillStyle屬性默認為黑色('#000000')。

 

 

繪制文本

文本繪制API不一定在瀏覽器中有實現。

fillText(text,x,y) :繪制實心文字。

stokeText(text,x,y) :繪制空心文字。

繪制文本的context屬性:

  • font
  • textAlign
  • textBaseline

fill(),stroke(),clip() 在完成繪制的最后的填充和邊界輪廓,剪輯區域。

 

 

使用圖片

使用drawImage() 方法可以把圖片繪制到畫布上。該方法有有3個變形。

drawImage(image, x, y) :把整個圖像復制到畫布,將其放置到指定點的左上角,並且將每個圖像像素映射到畫布上。

drawImage(image, x, y, width, height) :把整個圖像復制到畫布,允許指定圖像的寬度和高度。

drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight) :指定圖像的任何矩形區域,對畫布中的任何位置都可進行任何的縮放。

參數說明:

  • image 所要繪制的圖像。這必須是表示 <img> 標記或者屏幕外圖像的 Image 對象,或者是 Canvas 元素。
  • x, y 要繪制的圖像的左上角的位置。
  • width, height 圖像所應該繪制的尺寸。指定這些參數使得圖像可以縮放。
  • sourceX, sourceY 圖像將要被繪制的區域的左上角。這些整數參數用圖像像素來度量。
  • sourceWidth, sourceHeight 圖像所要繪制區域的大小,用圖像像素表示。
  • destX, destY 所要繪制的圖像區域的左上角的畫布坐標。
  • destWidth, destHeight 圖像區域所要繪制的畫布大小。

 

 

坐標變換

2D繪圖環境支持所有基本繪圖變換。當創建繪圖環境,變換矩陣便已經初始化了默認值。

translate(dx,dy) :平移變換。將畫布按向量(dx,dy)平移。也即將原點移動到坐標(dx,dy)。

rotate(a) :旋轉變換,畫布繞原點旋轉a弧度角。

scale(scaleX,scaleY) :縮放圖像,x軸放大scaleX,y軸放大scaleY。scaleX,scaleY默認都為1.0。

transform(m1_1,m1_2,m2_1,m2_2,dx,dy) :將變換矩陣乘以以下矩陣。

m1_1 m1_2 dx

m2_1 m2_2 dy

0       0        1

setTransform(m1_1,m1_2,m2_1,m2_2,dx,dy) :重置變換矩陣到默認狀態,然后調用transform()。

 

說明:

平移 :context.translate(dx,dy) 可以使用context.transform(1,0,0,1,dx,dy) 或者 context.transform(0,1,1,0.dx,dy) 代替。

旋轉 :context.rotate(a)可以使用context.transform(Math.cos(a*Math.PI/180),Math.sin(a*Math.PI/180),-Math.sin(a*Math.PI/180),Math.cos(a*Math.PI/180),0,0)

或者用

context.transform(-Math.sin(a*Math.PI/180),Math.cos(a*Math.PI/180),Math.cos(a*Math.PI/180),Math.sin(a*Math.PI/180), 0,0)代替。

縮放 :context.scale(sx, sy)可以使用context.transform(sx,0,0,sy,0,0)或者context.transform(0,sy,sx,0, 0,0)代替。

 

 

保存圖形狀態

save() 和 restore() 方法允許你保存和恢復一個 CanvasRenderingContext2D 對象的狀態。

save() 把當前狀態推入到棧中。

restore() 從棧的頂端彈出最近保存的狀態,並且根據這些存儲的值來設置當前繪圖狀態。

CanvasRenderingContext2D 對象的所有屬性(除了畫布的屬性是一個常量)都是保存的狀態的一部分。變換矩陣和剪切區域也是這個狀態的一部分,但是當前路徑和當前點並不是。

 

 

操作像素

createImageData

getImageData

putImageData

ImageData對象保存了圖像像素值。每個對象有三個屬性: width, height 和data。data 屬性類型為CanvasPixelArray,用於儲存width*height*4個像素值。每一個像素有RGB值和透明度alpha值(其值為 0 至255,包括alpha在內!)。像素的順序從左至右,從上到下,按行存儲。

 

 

漸變

Context對象可以通過createLinearGradient()和createRadialGradient()兩個方法創建漸變對象,這兩個方法的原型如下:

Object createLinearGradient(x1, y1, x2, y2) :創建一個從(x1, y1)點到(x2, y2)點的線性漸變對象。

Object createRadialGradient(x1, y1, r1, x2, y2, r2) :創建一個從以(x1, y1)點為圓心、r1為半徑的圓到以(x2, y2)點為圓心、r2為半徑的圓的徑向漸變對象。

 

漸變對象創建完成之后必須使用它的addColorStop()方法來添加顏色,該方法的原型如下:

void addColorStop(position, color) :其中position表示添加顏色的位置,取值范圍為[0, 1],0表示起點,1表示終點;color表示添加的顏色,取值可以是任何CSS顏色值。

漸變對象創建並配置完成之后就可以將其賦予Context對象的strokeStyle屬性或者fillStyle屬性,然后繪制的圖形就具有了所需的漸變效果。

 

 

4. 一些簡單的例子

4.1 繪制路徑

例: canvas的繪制是基於狀態的。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <canvas id="myCanvas" width="800" height="800" style="border: 1px solid black">
        你的瀏覽器還不支持哦
    </canvas>
    <script type="text/javascript">
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

        // 狀態設置
        context.moveTo(100,100);
        context.lineTo(700,700);
        context.lineTo(100,700);
        context.lineTo(100,100);
        context.lineWidth = 5;
        context.strokeStyle = "red";
        // 繪制
        context.stroke();

        // 狀態設置
        context.moveTo(200,100);
        context.lineTo(700,600);
        context.strokeStyle = "black";
        // 繪制
        context.stroke();
    </script>
</body>
</html>

繪圖結果:

wps9B3C.tmp

由於stroke()方法會把當前路徑中的所有線條都描一遍。所以第二段線條的黑色線的屬性把第一段線條的屬性覆蓋掉了,從而導致了兩條線段都是黑色的。

所以繪制新圖像之前必須使用beginPath、closePath。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    // 開始一段路徑
    context.beginPath();
    // 狀態設置
    context.moveTo(100,100);
    context.lineTo(700,700);
    context.lineTo(100,700);
    context.lineTo(100,100);
    context.lineWidth = 5;
    context.strokeStyle = "red";
    // 繪制
    context.stroke();

    // 開始一段路徑
    context.beginPath();
    // 狀態設置
    context.moveTo(200,100);
    context.lineTo(700,600);
    context.strokeStyle = "black";
    // 繪制
    context.stroke();
</script>
</body>
</html>

繪圖結果:

wps9B5D.tmp

 

 

 

4.2 繪制七巧板

例:繪制七巧板,該例需要繪制線條而只是繪制圖形,所以不需要使用stroke()方法,只需要使用fill()方法。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    var tangram = [
        {p:[{x:0,y:0},{x:800,y:0},{x:400,y:400}],color:"#caff67"},
        {p:[{x:0,y:0},{x:400,y:400},{x:0,y:800}],color:"#67becf"},
        {p:[{x:800,y:0},{x:800,y:400},{x:600,y:600},{x:600,y:200}],color:"#ef3d61"},
        {p:[{x:600,y:200},{x:600,y:600},{x:400,y:400}],color:"#f9f51a"},
        {p:[{x:400,y:400},{x:600,y:600},{x:400,y:800},{x:200,y:600}],color:"#a594c0"},
        {p:[{x:200,y:600},{x:400,y:800},{x:0,y:800}],color:"#fa8ecc"},
        {p:[{x:800,y:400},{x:800,y:800},{x:400,y:800}],color:"#f6ca29"},
    ];

    function draw(piece,ctx){
        ctx.beginPath();
        var p0 = piece.p[0];
        ctx.moveTo(p0.x,p0.y);
        for(var i = 1;i<piece.p.length;i++){
            var pi = piece.p[i];
            ctx.lineTo(pi.x, pi.y);
        }
        ctx.lineWidth = 1;
        ctx.strokeStyle = "black";
        ctx.fillStyle = piece.color;
        ctx.fill();    // 繪圖,填充顏色。
        ctx.closePath();
    }

    // 繪制七巧板
    for(var i=0;i<tangram.length;i++){
        draw(tangram[i],context);
    }

</script>
</body>
</html>

繪圖結果:

 

 

 

4.3 繪制畫圓

對於arc()方法。其圓弧的極坐標表示方法如下:

 

例:繪制一段圓弧。

var context = document.getElementById("myCanvas").getContext("2d");

context.lineWidth = 5;
context.strokeStyle = "blue";
context.arc(300,300,200,0,1.5*Math.PI);
context.stroke();

繪圖結果:

 

 

arc()方法最后一個參數用於設置繪制圓弧的順逆時針。若為true,表示逆時針,若為false,表示順時針。但這里的順逆時針的概念與一般的不同。具體參看示例。

var context = document.getElementById("myCanvas").getContext("2d");

context.beginPath();
context.lineWidth = 5;
context.strokeStyle = "blue";
context.arc(200,400,100,0,1.5*Math.PI,true);
context.stroke();

context.beginPath();
context.arc(500,400,100,0,0.5*Math.PI,true);
context.stroke();

繪圖結果:

 

 

 

二、保存canvas圖形為文件

Canvas元素有一個toDataURL()方法。該方法可以將canvas中的圖像數據進行base64編碼。

函數:canvas.toDataURL(type, encoderOptions);

  • type:圖像格式,默認為"image/png"。
  • encoderOptions:數值為0~1,表示圖片質量,僅在type為"image/jpeg"或"image/webp"時有效。

該方法返回一串URI字符串。該字符串是canvas中圖像數據的base64編碼。

toDataURL()方法的瀏覽器兼容情況:

Chrome Firefox(Gecko) Internet Explorer Opera Safari Android Chrome for Android Firefox Mobile(Gecko Mobile) IE Mobile Opera Mobile Safari Mobile
4 3.6(1.9.2) 9 9 4.0 3.2  18   1.0(1.9.2) (Yes)  19   3.0

 

 

例:打印URL。

var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
//  打印出URL
console.log(dataURL);

 

例:設置圖像編碼的質量。

var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
var lowQuality = canvas.toDataURL("image/jpeg", 0.1);

 

例:將canvas的繪圖結果顯示到img中。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<canvas id="myCanvas" width="800" height="800" style="border: 1px solid black"></canvas>
<img id="myImg" src="" width="800" height="800" alt="canvas picture" />
<script type="text/javascript">
    var img = document.getElementById("myImg");
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    // 繪圖
    context.beginPath();    context.arc(400,400,200,0,2*Math.PI);
    context.stroke();

    // 設置img的src
    var url = canvas.toDataURL();
    img.src = url;
</script>
</body>
</html>

 

例:將canvas保存成圖片文件。

方法一:將canvas的圖形同步到image。既可以鼠標右擊保存圖片。

 

方法二:將window.location.href 賦值為DataURL 。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas>
<input id="saveBtn" type="button" onclick="saveImg()" value="保存圖片"/>
<script type="text/javascript">var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    // 繪圖
    context.beginPath();
    context.arc(150,150,50,0,2*Math.PI);
    context.stroke();

    function saveImg(){
        var url = canvas.toDataURL();
        var newURL = url.replace("image/png", "image/octet-stream");
        window.location.href = newURL;
    }
</script>
</body>
</html>

這個方法存在問題,首先在IE10下,瀏覽器只是跳轉到了空白頁,沒有下載文件。其次,在Chrome中下載文件沒有文件名。Chrome中總是這樣顯示:

 

 

 

方法三:使用超鏈接<a></a>提供的鏈接進行下載。該方法可以解決下載文件名缺失的問題,但IE10中無法使用。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas>
<input id="saveBtn" type="button" onclick="saveImg()" value="保存圖片"/>
<script type="text/javascript">
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    // 繪圖
    context.beginPath();
    context.arc(150,150,50,0,2*Math.PI);
    context.stroke();

    function saveImg(){
        var url = canvas.toDataURL();
        var saveLink = document.createElement('a');
        saveLink.href = url;
        saveLink.download = "圓弧.png";
        // 觸發點擊事件
        var clickEvent = document.createEvent('MouseEvents');
        clickEvent.initEvent('click', true, true);
        saveLink.dispatchEvent(clickEvent);
    }
</script>
</body>
</html>

繪圖結果:

 

 

 

三、讓低版本IE支持Canvas

Google提供了一個ExplorerCanvas的函數庫,簡稱excanvas。該函數庫使Canvas在低版本的IE下也可使用。

excanvas的原理是在低版本IE中使用VML繪圖。需要注意的是,低版本的IE678使用VML繪圖的效率比HTML5繪圖的效率低很多。

例:在IE 6,7,8中使用canvas畫圓。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <!--[if IE]><script type="text/javascript" src="lib/excanvas.js"></script><![endif]-->
</head>
<body>
<canvas id="myCanvas" width="300" height="300" style="border: 1px solid black"></canvas>
<script type="text/javascript">
    // IE 6,7,8中必須等所有dom加載完畢才能畫出圖形。
    window.onload = function () {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");

        // 繪圖
        context.beginPath();
        context.arc(150,150,50,0,2*Math.PI);
        context.stroke();
    };
</script>
</body>
</html>

 

 

 

 

 

為了防止無良網站的爬蟲抓取文章,特此標識,轉載請注明文章出處。LaplaceDemon/ShiJiaqi。

http://www.cnblogs.com/shijiaqi1066/p/4851774.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM