Các quy tắc cơ bản của HTML5, Phần 4: Chi tiết cuối cùng
Cập nhật: 10.11.2012 02:13
HTML5 phản ánh những thay đổi to lớn theo cách bây giờ bạn đang kinh doanh trên web và trong đám mây. Bài viết này, là bài thứ tư trong một loạt bài bốn phần được thiết kế để tập trung vào những thay đổi trong HTML5, giới thiệu phần tử Canvas (Khung nền ảnh) của HTML5, bằng cách sử dụng một số ví dụ để giải thích các hàm.

Vai trò của tác giả HTML5, một sự kết hợp dũng cảm của nhà thiết kế và nhà phát triển, là để xây dựng các ứng dụng Internet phong phú có hiệu quả (RIA) và đặc biệt là các UI phong phú. Về hiệu quả tôi muốn nói về việc tạo các cải tiến nói chung và các cải tiến có tính hệ thống mà về mặt kỹ thuật số làm cho đàm thoại dễ dàng giữa chủ sở hữu trang web, các đại lý của chủ sở hữu và người sử dụng của trang web.

Các RIA là nguồn gốc và phương tiện truyền bá kinh nghiệm làm thỏa mãn người dùng và, do đó, là một phần thiết yếu của bất kỳ công việc kinh doanh lấy mạng làm trung tâm thành công nào. Theo tự nhiên, các hoạt động lấy mạng làm trung tâm có tính chất cộng tác ở mức độ này hay khác. Một cách tiếp cận thành công với sự cộng tác kỹ thuật số là cần thiết cho sự thành công của đại lý ở tất cả các cấp, bao gồm tiếp thị và quản lý. Cần vượt qua khả năng để trang web đáp ứng được những mong đợi về chất lượng của khách truy cập của nó.

HTML5, như bạn đã thấy, là hoàn toàn thích hợp cho "một thế giới web" có tính cộng tác về các khả năng xuyên qua các nền tảng, hội tụ viễn thông, ngôn ngữ thống nhất, điện toán ở khắp nơi, và các hệ thống mở. Ba bài đăng đầu tiên của loạt bài này tập trung vào ngữ nghĩa, các phương thức mã hóa thích hợp, đầu vào đóng vai trò trong quá trình trao đổi quan trọng, và các cách thực hành tốt nhất về quản lý trang web, tất cả đều được thiết kế để đặt nền móng tạo ra các RIA theo cách có tổ chức và hợp lý. Các chủ đề phổ biến trong mỗi bài viết đã đăng là việc sản xuất và quản lý một trải nghiệm người dùng phong phú là rất quan trọng để đạt được các mục tiêu đại lý của chủ sở hữu trang web đó. Canvas của HTML5 đóng một vai trò quan trọng trong sự phát triển các RIA hiệu quả. 

Canvas là?

Canvas HTML5 là một phần tử vẽ và tạo hình ảnh động vô cùng có ích. Canvas sử dụng JavaScript để vẽ đồ họa trực tiếp trên trang web. Đây là vùng chữ nhật mà bạn định nghĩa và điều khiển và nó cho phép dựng hình 2D và hình ảnh bitmap động, theo bảng kịch bản lệnh.

Canvas HTML5 là lý tưởng để sản xuất tài liệu hình ảnh thú vị nhằm nâng cao các UI, các bản vẽ, các album ảnh, các biểu đồ, các đồ thị, các hình ảnh động, và các ứng dụng bản vẽ nhúng. Phần tử Canvas có một số phương thức để vẽ các đường, hình chữ nhật, hình tròn, và các nhân vật. 

Các tọa độ canvas

Một điều kiện tiên quyết để vẽ trên canvas (khung nền ảnh) là phải biết rõ về vùng lưới hoặc vùng tọa độ. Các phép đo vùng khung nền này theo chiều rộng và chiều cao được tính bằng pixel (điểm ảnh). Canvas được dựng lên xung quanh việc sử dụng các tọa độ xy. Các tọa độ của canvas tại x=0, y=0 nằm ở góc trên bên trái.

Các thuộc tính mặc định cho vùng hình chữ nhật của canvas có chiều rộng là 300 pixels và chiều cao là 150 pixels, nhưng bạn có thể xác định kích thước chính xác của phần tử canvas này bằng cách quy định chiều rộng và chiều cao. Bản vẽ trong Hình 1 cho thấy cách triển khai thực hiện tọa độ xy.


Hình 1. Các tọa độ canvas
Hình vuông với các đường chéo và ngang qua đó cho thấy các tọa độ của mỗi chỗ giao nhau.

Hình 1 cho thấy một vùng canvas 100 pixel x 100 pixel:

  • Các góc trên bên trái có x=0, y=0.
  • Giá trị x tăng theo chiều ngang, và giá trị y tăng theo chiều dọc.
  • Góc dưới cùng bên phải có x=100, y=100.
  • Tâm điểm có x=50, y=50.

Bắt đầu

Để đặt bất cứ thứ gì trên canvas (khung nền ảnh), trước tiên bạn phải định nghĩa canvas trong tệp HTML. Bạn phải tạo mã JavaScript để truy cập thẻ <canvas> và giao tiếp với Canvas API của HTML5 để vẽ hình ảnh của bạn.

Cấu tạo chính của thẻ <canvas> là:

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

Một phần tử canvas có hai thuộc tính riêng của nó: width (chiều rộng) và height (chiều cao). Ngoài ra, phần tử canvas còn sở hữu tất cả các thuộc tính HTML5 quan trọng, chẳng hạn như class (lớp), id (mã định danh), và name (tên). Thuộc tính id thường dùng trong các mã được hiển thị ở trên. JavaScript sử dụng id của phần tử canvas được tạo ở đây để xác định phần tử canvas để vẽ lên. JavaScript xác định phần tử canvas thích hợp bằng cách sử dụng phương thức document.getElementById(), như được hiển thị dưới đây:

var canvas = document.getElementById("myCanvas");

Mỗi phần tử canvas phải có một định nghĩa ngữ cảnh, như hình dưới đây. Hiện nay, đặc tả chính thức chỉ công nhận môi trường 2D:

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

Sau khi bạn xác định phần tử canvas và xác định rõ ngữ cảnh của nó, bạn đã sẵn sàng bắt đầu vẽ.

Các công cụ vẽ, các hiệu ứng, và các phép biến đổi

Cuộc thảo luận này về Canvas của HTML5 đi qua các công cụ vẽ, các hiệu ứng, và các phép chuyển đổi khác nhau. Các công cụ vẽ bao gồm:

  • Các đường kẻ
  • Các hình chữ nhật
  • Các cung tròn
  • Các đường cong Bezier và đường cong bậc hai
  • Các hình tròn và hình bán nguyệt

Các hiệu ứng Canvas mà bạn sẽ sử dụng là:

  • Tô đầy và các nét
  • Các gradien tuyến tính và xuyên tâm

Các phép biến đổi được thảo luận bao gồm:

  • Tỉ lệ
  • Quay tròn
  • Tịnh tiến

Các đường vẽ

Để vẽ một đường trên canvas, sử dụng các phương thức moveTo(), lineTo(), và stroke(). Ngoài ra, bạn sử dụng phương thức beginPath() để thiết lập lại đường dẫn hiện tại:

  • context.beginPath();
  • Context.moveTo(x,y);
  • Context.lineTo(x,y);
  • Context.stroke(x,y);

Phương thức beginPath() bắt đầu một đường dẫn mới. Trước khi bạn vẽ một đường kẻ mới với các đường dẫn nhỏ khác nhau, bạn phải sử dụng phương thức beginPath() để cho biết rằng một điểm khởi đầu mới cho hướng đi của bản vẽ. Không cần phải gọi phương thức beginPath() khi bạn vẽ đường thẳng đầu tiên.

Phương thức moveTo() cho biết nơi bắt đầu đường dẫn nhỏ mới. Phương thức lineTo() tạo các đường dẫn nhỏ. Bạn có thể thay đổi sự xuất hiện của đường kẻ bằng các phần tử lineWidthstrokeStyle. Phần tử lineWidth thay đổi độ dày của đường này, và strokeStyle thay đổi màu sắc.

Trong Hình 2, ba đường kẻ được vẽ tương ứng bằng màu xanh dương, xanh lá cây, và màu đỏ tía.


Hình 2. Canvas có các đường kẻ theo ba màu khác nhau
Một canvas cho thấy ba đường kẻ có màu khác nhau

Các đường kẻ trong Hình 2 do đoạn mã trong Liệt kê 1 tạo ra. Đường kẻ màu xanh dương có hai đầu làm tròn được tạo ra bằng cách đầu tiên thiết lập một đường dẫn mới để bắt đầu: context.beginPath(). Tiếp theo là:

  • context.moveTo(50, 50), đặt điểm đầu cho đường dẫn này (x=50, y-50)
  • context.lineTo(300,50), xác định điểm cuối cho đường kẻ này
  • context.lineWidth = 10, là độ rộng của đường kẻ này
  • context.strokeStyle = "#0000FF", là màu sắc của đường kẻ này
  • context.lineCap = "round", làm tròn các đầu đường kẻ
  • context.stroke(), thực sự vẽ đường kẻ này trên canvas

Tất cả các đường kẻ đều có chiều dài là 50 pixel, mặc dù chúng xuất hiện có các chiều dài khác nhau — một ảo giác gây ra bởi các mũ đường kẻ khác nhau. Có ba kiểu mũ đường kẻ có thể:

  • Context.round (xanh dương)
  • Context.square (xanh lá cây)
  • Context.butt (màu đỏ tía — mặc định)

Mũ ghép là giá trị mặc định. Khi bạn sử dụng một kiểu mũ tròn hoặc hình vuông, chiều dài của đường kẻ này tăng lên một lượng đúng bằng chiều rộng của đường kẻ này. Ví dụ, một đường kẻ dài 200 pixel và rộng 10 pixel có kiểu mũ tròn hoặc vuông sẽ có chiều dài đường kẻ là 210 pixel, bởi vì mỗi nắp sẽ bổ sung thêm 5 pixel cho mỗi đầu của đường kẻ này. Một đường kẻ dài 200 pixel và rộng 20 pixel có kiểu mũ tròn hoặc vuông sẽ có chiều dài đường kẻ kết quả là 220 pixel, vì mỗi mũ sẽ thêm 10 pixel cho mỗi đầu của đường kẻ này.

Thực hiện và làm thay đổi mã trong Liệt kê 1 để có được hiểu biết nhiều hơn về cách vẽ các đường kẻ.


Liệt kê 1. Tạo ba đường kẻ có màu khác nhau trên canvas
	
<!DOCTYPE HTML>
<html>
    <head>
	    <title>Line Example</title>
        <style>
            body {
                margin: 0px;
                padding: 0px;
            }
            
            #myCanvas {
                border: 1px solid #9C9898;
            }
        </style>
        <script>
            
          window.onload = function() {
                var canvas = document.getElementById("myCanvas");
                var context = canvas.getContext("2d");
                
                // blue line with round ends
                context.beginPath();
                context.moveTo(50, 50);
                context.lineTo(300,50);
                context.lineWidth = 10;
                context.strokeStyle = "#0000FF"; 
                context.lineCap = "round";
                context.stroke();

                // green line with square ends
                context.beginPath();
                context.moveTo(50, 100);
                context.lineTo(300,100);
                context.lineWidth = 20;
                context.strokeStyle = "#00FF00"; 
                context.lineCap = "square";
                context.stroke();

                // purple line with butt ends
                context.beginPath();
                context.moveTo(50, 150);
                context.lineTo(300, 150);
                context.lineWidth = 30;
                context.strokeStyle = "#FF00FF"; 
                context.lineCap = "butt";
                context.stroke();
            };
        </script>
    </head>
    <body>
        <canvas id="myCanvas" width="400" height="200">
        </canvas>

    </body>
</html>

Vẽ các hình chữ nhật

Có ba phương thức để xử lý một vùng hình chữ nhật trên canvas:

  • fillRect(x,y,width,height), vẽ một hình chữ nhật thêm vào
  • strokeRect(x,y,width,height), vẽ nét ngoài của một hình chữ nhật
  • clearRect(x,y,width,height), xóa vùng cụ thể và làm cho nó hoàn toàn trong suốt

Đối với một trong ba phương thức nói trên, xy chỉ ra vị trí trên canvas tương đối so với góc trên bên trái của hình chữ nhật (x=0, y=0), và widthheight tương ứng là chiều rộng và chiều cao của hình chữ nhật.

Hình 3 cho thấy ba vùng hình chữ nhật do đoạn mã trong Liệt kê 2 tạo ra.


Hình 3. Canvas hình chữ nhật
Hộp tô đầy màu vàng có một hình chữ nhật có nét đen dày và một hình chữ nhật nét đen mảnh trên nó

Phương thức fillRect() tạo ra một hình chữ nhật được tô đầy bằng màu đen mặc định. Phương thức clearRect() xóa một vùng hình chữ nhật ở giữa hình chữ nhật đầu tiên. Đó là cùng giữa hình chữ nhật được hình thành bởi phương thức fillRect(). Phương thức strokeRect tạo ra một hình chữ nhật chỉ có đường viền màu đen nhìn thấy được.


Liệt kê 2. Mã canvas hình chữ nhật
	
<!DOCTYPE HTML>
<html>
<head>
<title>Rectangle Example</title>
        <style>
            body {
                margin: 0px;
                padding: 0px;
            }
            
            #myCanvas {
                border: 1px solid #000000;
                background-color: #ffff00;
            }
        </style>
<script type="text/javascript">
function drawShape(){
   var canvas = document.getElementById('myCanvas');

    var context = canvas.getContext('2d');


    context.fillRect(25,25,50,50);
    context.clearRect(35,35,30,30);
    context.strokeRect(100,100,50,50);

}
</script>
</head>
<body onload="drawShape();">
   <canvas id="myCanvas" width="200" height="200"></canvas>
</body>
</html>

Vẽ các cung, các đường cong, các hình tròn, và các hình bán nguyệt

Cả hai hình tròn và hình bán nguyệt đều sử dụng phương thức arc(). Phương thức arc() có sáu đối số:

context.arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);

Các đối số centerXcenterY là các tọa độ của tâm hình tròn. Đối số radius (bán kính) giống như với toán học là: một đường thẳng từ tâm đến chu vi. Cung được tạo ra sẽ là một phần của hình tròn đã định. Các đối số startAngleendAngle tương ứng là điểm đầu và điểm cuối của cung tính bằng radian. Đối số anticlockwise (ngược chiều kim đồng hồ) là một giá trị Boolean. Khi giá trị này true (đúng) thì cung được vẽ ngược chiều kim đồng, khi là false (sai) thì cung được vẽ theo chiều kim đồng hồ.

Để vẽ một hình tròn bằng phương thức arc(), hãy định nghĩa góc đầu là 0 và góc cuối là 2*PI, như được hiển thị dưới đây:

context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);

Để vẽ một hình bán nguyệt bằng phương thức arc(), hãy xác định góc cuối là startingAngle + PI, như được hiển thị dưới đây:

context.arc(centerX, centerY, radius, startingAngle, startingAngle + Math.PI, false);

Đường cong bậc hai

Bạn tạo một đường cong bậc hai bằng cách sử dụng phương thức quadraticCurveTo() được hiển thị dưới đây. Các đường cong bậc hai được xác định bởi điểm ngữ cảnh, một điểm điều khiển, và một điểm cuối. Điểm điều khiển xác định độ cong của đường thẳng này.

context.moveTo(x, y);
context.quadraticCurveTo(controlX, controlY, endX, endY);

Đường cong Bezier

Cũng như với đường cong bậc hai, đường cong Bezier có một điểm đầu và cuối; nhưng không giống đường cong bậc hai, nó có hai điểm điều khiển:

context.moveTo(x, y);
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);

Bạn tạo một đường cong Bezier bằng phương thức bezierCurveTo(). Vì đường cong Bezier được định nghĩa có hai điểm điều khiển chứ không phải chỉ có một, nên bạn có thể tạo các độ cong phức tạp hơn.

Hình 4 hiển thị — từ trái sang phải — một cung, một đường cong bậc hai, một đường cong Bezier, một hình bán nguyệt, và một hình tròn.


Hình 4. Cung, các đường cong, và các hình tròn
Ảnh cho thấy có các cung, các đường cong, các hình tròn và các hình bán nguyệt trên canvas

Hình 4 được tạo bằng cách sử dụng mã trong Liệt kê 3.


Liệt kê 3. Mã của cung, đường cong, và hình tròn
	
<!DOCTYPE HTML>
<html>
    <head>
	<title>Arcs, Curves, Circles, & Semicircles</title>
        <style>
            body {
                margin: 0px;
                padding: 0px;
            }
            
            #myCanvas {
                border: 1px solid #9C9898;
            }
        </style>
<script>
function drawArc(){
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
 
    var centerX = 100;
    var centerY = 160;
    var radius = 75;
    var startingAngle = 1.1 * Math.PI;
    var endingAngle = 1.9 * Math.PI;
    var counterclockwise = false;
 
    context.arc(centerX, centerY, radius, startingAngle, 
        endingAngle, counterclockwise);
 
    context.lineWidth = 10;
    context.strokeStyle = "black"; 
    context.stroke();
};

function drawQuadratic(){
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
 
    context.moveTo(200, 150);
 
    var controlX = 288;
    var controlY = 0;
    var endX = 388;
    var endY = 150;
 
    context.quadraticCurveTo(controlX, controlY, endX, endY);
    context.lineWidth = 10;
    context.strokeStyle = "black"; 
    context.stroke();
};

function drawBezier(){
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
 
    context.moveTo(350, 350);
 
    var controlX1 = 440;
    var controlY1 = 10;
    var controlX2 = 550;
    var controlY2 = 10;
    var endX = 500;
    var endY = 150;
 
    context.bezierCurveTo(controlX1, controlY1, controlX2, 
        controlY2, endX, endY);
 
    context.lineWidth = 10;
    context.strokeStyle = "black"; 
    context.stroke();
};

function drawCircle(){
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
 
    var centerX = 450;
    var centerY = 375;
    var radius = 70;
 
    context.beginPath();
    context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
 
    context.fillStyle = "#800000";
    context.fill();
    context.lineWidth = 5;
    context.strokeStyle = "black";
    context.stroke();
};


function drawSemicircle(){
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
 
    var centerX = 100;
    var centerY = 375;
    var radius = 70;
    var lineWidth = 5;
 
    context.beginPath();
    context.arc(centerX, centerY, radius, 0, Math.PI, false);
    context.closePath();
 
    context.lineWidth = lineWidth;
    context.fillStyle = "#900000";
    context.fill();
    context.strokeStyle = "black";
    context.stroke();
};

window.onload = function (){
drawArc();
drawQuadratic(); 
drawBezier(); 
drawCircle(); 
drawSemicircle()
}
</script>
    </head>
    <body>
        <canvas id="myCanvas" width="600" height="500">
        </canvas>
    </body>
</html>

Các phép biến đổi: tịnh tiến, tỷ lệ, và quay tròn

Các phương thức translate(), scale(), và rotate() tất cả đều sửa đổi ma trận hiện tại. Phương thức translate(x, y) di chuyển các mục trên canvas đến một điểm khác trên lưới. Trong phương thức translate(x,y), các tọa độ (x,y) cho biết số điểm ảnh mà ảnh nên được di chuyển theo hướng-x và số điểm ảnh mà ảnh phải được di chuyển theo hướng-y.

Nếu bạn vẽ một ảnh tại (15,25) bằng phương thức drawImage(), bạn có thể sử dụng phương thức translate() có các đối số (20,30), để đặt ảnh này ở vị trí (15+20, 25+30) = (35, 55).

Phương thức scale(x,y) thay đổi kích thước của một ảnh. Đối số x xác định rõ hệ số tỷ lệ theo chiều ngang, và đối số y xác định rõ hệ số tỷ lệ theo chiều dọc. Ví dụ, scale(1.5, .75) sẽ tạo một ảnh lớn hơn 50% theo hướng x và chỉ bằng 75% kích thước hiện tại theo hướng y. Phương thức rotate(angle) chuyển đổi một đối tượng dựa trên góc đã định.

Hình 5 là một ví dụ về những gì có thể được đưa ra khi sử dụng các phương thức translate(), scale(), và rotate().


Hình 5. Sử dụng các phép biến đổi
Ảnh cho thấy một hộp mày xanh dưông có các từ mirror image đọc từ bên phải sang.

Liệt kê 4 cung cấp đoạn mã đã tạo ảnh trong Hình 5.


Liệt kê 4. Mã để tạo các phép biến đổi
	
<!DOCTYPE HTML>
<html>
<head>
<Title>Transformations Example</title>
<script>
 
window.onload = function() {
	var canvas=document.getElementById("myCanvas");
	var context=canvas.getContext("2d");
 
	var rectWidth = 250;
	var rectHeight = 75;
 
	// translate context to center of canvas
	context.translate(canvas.width/2,canvas.height/2); 		
 
	// half the y component 
	context.scale(1,0.5);

	// rotate 45 degrees clockwise
	context.rotate(-Math.PI/4); 
 
	context.fillStyle="blue";
	context.fillRect(-rectWidth/2,-rectHeight/2,
		rectWidth,rectHeight);


	// flip context horizontally
	context.scale(-1,1);
 
	context.font="30pt Calibri";
	context.textAlign="center";
	context.fillStyle="#ffffff";
	context.fillText("Mirror Image",3,10);

}
 
</script>
</head>
<body>
	<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
</html>

Các gradien

Một gradien là một vùng tô đầy di chuyển từ một màu này sang màu khác, pha trộn các màu ở nơi chúng giao nhau. Có hai kiểu gradien mà bạn có thể tạo trong Canvas là: tuyến tính và xuyên tâm.

Bạn tạo ra một gradien tuyến tính bằng phương thức createLinearGradient(). Phương thức createLinearGradient(x0,y0,x1,y1) tạo ra một gradien dọc theo một đường thẳng được xác định bởi hai điểm: (x0,y0)(x1,y1)— tương ứng, là điểm đầu và điểm cuối của gradien. Phương thức này trả về một đối tượng.

Một gradien màu có thể có nhiều màu sắc. Phương thức addcolorStop(offset, color) xác định rõ sự lưu lại màu với màu sắc được chỉ ra cho gradien ở giá trị bù cụ thể. Phương thức addColorStop() cho phép bạn chỉ rõ một giá trị bù giữa 0 và 1, ở đây quá trình chuyển tiếp sang màu bên cạnh bắt đầu. Giá trị 0 là giá trị bù ở một đầu của gradien; 1 là giá trị bù ở đầu kia. Sau khi đã định nghĩa gradien màu, đối tượng gradien có thể được gán cho phương thức fillStyle(). Bạn cũng có thể vẽ văn bản bằng một gradien bằng cách sử dụng phương thức fillText().

Gradien xuyên tâm — createradialGradient(x0,y0,r0,x1,y1,r1) — kết hợp hai hoặc nhiều màu trong một mẫu hình tròn hoặc hình nón bằng cách sử dụng sáu đối số:

  • (x0,y0). Tâm của hình tròn đầu tiên của một hình nón
  • r0. Bán kính của hình tròn đầu tiên
  • (x1,y1). Tâm của hình tròn thứ hai của hình nón
  • r1. Bán kính của hình tròn thứ hai

Hình 6 có bốn gradien: một gradien tuyến tính, một gradien văn bản, một gradien tuyến tính theo đường chéo, và một gradien xuyên tâm.


Hình 6. Ví dụ về gradien
Vẽ các gradien trên canvas

Hình 6 đã được tạo bằng cách sử dụng mã trong Liệt kê 5.


Liệt kê 5. Mã mẫu của gradien
	
<!doctype>
<html>
<head>
<title>Gradient Example</title>
<script>
   window.onload = function() {
      var canvas = document.getElementById("myCanvas");

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

      //Let's try the gradient on a rectangle

      // Create a linear gradient 
      var fillColor = context.createLinearGradient(50,50, 150,50);

      // Set  gradient colors
      fillColor.addColorStop(0.15,"red");
      fillColor.addColorStop(0.35,"black");
      fillColor.addColorStop(0.65,"green");
      fillColor.addColorStop(0.87,"yellow");

      // Assign gradient object to fillstyle
      context.fillStyle= fillColor;

      // Draw rectangle
      context.fillRect(50,50,100,100);

      // With text  

      var fillColorText = context.createLinearGradient(300,50,600,50);
 
      fillColorText.addColorStop(0.2,"red");
      fillColorText.addColorStop(0.4,"black");
      fillColorText.addColorStop(0.6,"green");
      fillColorText.addColorStop(0.8,"yellow");


     context.fillStyle= fillColorText;

      context.font="40px verdana";
      context.textBaseline="top";
      context.fillText("With text too!", 300,50)

      // Gradient on a diagonal
      var fillColordiagonal = context.createLinearGradient(50,200, 100,450);

      // Gradient colors
      fillColordiagonal.addColorStop(0.2,"red");
      fillColordiagonal.addColorStop(0.4,"black");
      fillColordiagonal.addColorStop(0.6,"green");
      fillColordiagonal.addColorStop(0.75,"yellow");

      // Assign gradient object to fillstyle
      context.fillStyle= fillColordiagonal;

      // Draw  rectangle
      context.fillRect(50,225, 100,250);

      // Draw radial gradient
     fillColorRadial = context.createRadialGradient(450,300,0, 450,300,200);
     fillColorRadial.addColorStop(0, "red");
     fillColorRadial.addColorStop(0.2, "black");
     fillColorRadial.addColorStop(0.4, "green");
     fillColorRadial.addColorStop(0.7, "yellow");
     context.fillStyle = fillColorRadial;
     context.rect(300,200,500,400);
     context.fill();

}
</script>
</head>
<body>
<div>
    <p><canvas id="myCanvas" width="600" height="400"></canvas></p>
</div>
</body>
</html>

Cắt ảnh

Bạn có thể thay đổi các ảnh bằng cách cắt các vùng đã chọn bên ngoài chúng. Cắt trên canvas là một hàm chất tải lên phương thức drawImage(). Phương thức drawImage() có ba tùy chọn. Bạn có thể sử dụng hoặc ba, năm, hoặc chín đối số.

Cấu hình ba-đối số — drawImage(image, dx, dy)— vẽ ảnh này trên canvas ở tọa độ đích (dx, dy). Các tọa độ này thiết lập góc trên bên trái của hình ảnh.

Cấu hình năm-đối số — drawImage(image, dx, dy, dw, dh)—đưa ra chiều rộng và chiều cao của ảnh đích. Hình ảnh này được điều chỉnh để phù hợp với chiều rộng và chiều cao của đích này.

Cấu hình chín-đối số — drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)— lấy một hình ảnh, cắt rời ra một vùng hình chữ nhật bắt đầu ở các tọa độ nguồn (sx,sy) với chiều rộng và chiều cao (sw,sh), và điều chỉnh nó cho phù hợp với chiều rộng và chiều cao (dw,dh) của đích này, đặt nó trên canvas tại (dx,dy).

Hình 7 cho thấy hình ảnh mà bạn sẽ cắt ra.


Hình 7. Cắt một ảnh
Ảnh mô tả Napoleon đang cưỡi ngựa.

Khi sử dụng ảnh được hiển thị trong Hình 7, một tập các ảnh được đặt trên canvas (khung nền ảnh) này. Một ảnh là một canvas đã định kích thước và được sử dụng làm khung nền. Một ảnh khác được tạo ra nhỏ hơn và chèn vào phía dưới bên phải của khung nền đó. Một ảnh thứ ba là ảnh cắt ra phần đầu của Napoleon mà bạn đặt ở góc trên bên trái của khung nền này. Ảnh đã cắt xong được hiển thị trong Hình 8.


Hình 8. Ảnh đã cắt xong
Cũng ảnh Napoleon đó nhưng có ảnh chân dung ở góc trên bên trái và một ảnh nhỏ hơn ở dưới cùng bên phải

Hình 8 được tạo bằng cách sử dụng đoạn mã trong Liệt kê 6. Trước khi thực hiện mã này, hãy chắc chắn tải tệp ảnh Napolean.png được dùng trong ví dụ này.


Liệt kê 6. Đoạn mã để cắt ảnh ví dụ
	
<!doctype>
<html>
<head>
<title>Crop Example</title>
<script type="text/javascript">
  window.onload = function()  {
  var canvas=document.getElementById("cropNapolean");
	var context=canvas.getContext("2d");
 
	var imageObj = new Image();
	imageObj.onload = function() {
	// draw image to cover the entire canvas
		context.drawImage(imageObj,0,0, 600, 400);
 
	// draw small image in bottom right corner
		var sourceX = 0;
		var sourceY = 0;
		var sourceWidth = 1200;
		var sourceHeight = 801;
		var destX = 300;
		var destY = 200;
		var destWidth = sourceWidth - 900;
		var destHeight = sourceHeight - 600;
 
		context.drawImage(imageObj, sourceX, sourceY, sourceWidth,
			sourceHeight, destX, destY, destWidth, destHeight);
	
	 //draw Napolean's head only
		var sourceNapoleanX = 460;
		var sourceNapoleanY = 25;
		var sourceNapoleanWidth = 250;
		var sourceNapoleanHeight = 175;
		var destNapoleanX = 0;
		var destNapoleanY = 0;
		var destNapoleanWidth = sourceNapoleanWidth - 150 ;
		var destNapoleanHeight = sourceNapoleanHeight - 100;
 
        context.drawImage(imageObj, sourceNapoleanX, sourceNapoleanY, 
             sourceNapoleanWidth, sourceNapoleanHeight, 
               destNapoleanX, destNapoleanY, 
                 destNapoleanWidth, destNapoleanHeight);
	}
	imageObj.src = "Napoleon.png";	
}
</script>
  
  </head>
<body>
  <div>
    <p><canvas id="cropNapolean" width="600" height="400"></canvas></p>
  </div>
</body>
</html>

Hình ảnh động và nhiều canvas

Khi làm việc với hình ảnh động, câu hỏi về các lớp luôn phát sinh. Các lớp cho phép các thành phần được tách rời nhau, làm cho việc mã hóa và gỡ lỗi dễ dàng hơn và hiệu quả hơn. Canvas API không có các lớp, nhưng bạn có thể tạo nhiều khung nền ảnh (canvas).

Hình ảnh động phải được kiểm soát theo thời gian. Vì vậy, để tạo một hình ảnh động, bạn phải giải quyết từng khung hình của hình ảnh động. Canvas API có hạn chế chủ yếu khi nó tạo hình ảnh động: Sau khi một hình được gỡ khỏi canvas, nó vẫn như vậy. Để di chuyển hình này, bạn phải vẽ lại nó.

Để tạo một hình ảnh động:

  1. Hãy xóa canvas của các hình bất kỳ đã được vẽ trước đó.
  2. Lưu lại trạng thái canvas để đảm bảo trạng thái ban đầu được sử dụng mỗi khi một khung được vẽ.
  3. Thực hiện các bước để hiển thị các khung hình.
  4. Nếu bạn đã lưu trạng thái đó, hãy khôi phục lại nó trước khi vẽ một khung mới.

Bạn có thể điều khiển hình ảnh động theo hai cách: bằng cách sử dụng các hàm setInterval hay setTimeout, mỗi hàm có thể được dùng để gọi một hàm theo một khoảng thời gian đặt trước. Hàm setInterval thực hiện mã được cung cấp lặp lại nhiều lần. Hàm setTimeout chỉ thực hiện một lần sau khi thời gian đặt trước đã trôi qua.

Hình 9 cho thấy một khung hình của hình ảnh động nhiều canvas của người bơi. Nước ở trên một canvas, và người bơi ở trên một canvas khác.


Hình 9. Hình ảnh động khi sử dụng các hình ảnh trên nhiều canvas
Ảnh đính trên nền gradien màu xanh dương.

Bạn tạo người bơi bằng cách sử dụng đoạn mã trong Liệt kê 7. Người bơi này sử dụng một gradien tuyến tính để tạo nước. Nước có bốn sắc thái của màu xanh, cung cấp một ảo giác hợp lý của nước. Bạn tạo chuyển động cho người bơi bằng cách sử dụng các giá trị positionXpositionY, để làm thay đổi các tư thế của ảnh. Bạn tạo đầu của người bơi bằng cách sử dụng phương thức arc(). Các chân và cánh tay của người bơi được tạo bằng cách vẽ các đường kẻ rồi thay đổi các vị trí lineTo() của chúng. Bạn thay đổi thân bằng cách thay đổi vị trí moveTo(). Vì đây là một hình ảnh động, nên bạn sẽ phải thực hiện đoạn mã này để xem người bơi chuyển động như thế nào.


Liệt kê 7. Ví dụ về hình ảnh động
	
<!DOCTYPE HTML>
<html>
    <head>
	<title>Animation & Multiple Canvas Example</title>
<script>            
// Water canvas
function  drawWater() {
    var canvasWater = document.getElementById("myWaterCanvas");
    var contextWater = canvasWater.getContext("2d");
	contextWater.globalAlpha = .50 ;

    // Create a linear gradient fill
    var linearGrad = contextWater.createLinearGradient(0,0,400,400);
    linearGrad.addColorStop(0, '#0000ff'); // sets the first color
    linearGrad.addColorStop(.25, '#0099ff'); // sets the second color
    linearGrad.addColorStop(.50, '#00ccff'); // sets the third color
    linearGrad.addColorStop(.75, '#00ffff'); // sets the fourth color
    contextWater.fillStyle = linearGrad;
    contextWater.fillRect(0,0,400,400);
}

// Swimmer canvas
           setInterval(drawSwimmer, 30);
           var positionX = 0;
           var positionY = 0;
            
          function  drawSwimmer(){
                var canvasSwimmer = document.getElementById("mySwimmerCanvas");
                var contextSwimmer = canvasSwimmer.getContext("2d");
                contextSwimmer.clearRect(0,0,400,400);

                if (positionX < 30)
                  {
                     positionX += 1;
                     positionY += 1;
                  }
                else
                {
                     positionX = 0;
                     positionY = 0;
                }
               

                contextSwimmer.save();

               // draw circle for head
               var centerX = 200;
               var centerY = 50;
               var radius = 20;
 
               contextSwimmer.beginPath();
               contextSwimmer.arc(centerX, centerY+positionY, 
			                         radius, 0, 2 * Math.PI, false);
 
               contextSwimmer.fillStyle = "#000000";
               contextSwimmer.fill();
               contextSwimmer.lineWidth = 5;


                // torso
                contextSwimmer.beginPath();
                contextSwimmer.moveTo(200,70+positionY);
                contextSwimmer.lineTo(200,175);
                contextSwimmer.lineWidth = 10;
                contextSwimmer.strokeStyle = "#000000"; 
                contextSwimmer.lineCap = "round";
                contextSwimmer.stroke();

               // image right arm
                contextSwimmer.beginPath();
                contextSwimmer.moveTo(200, 100);
                contextSwimmer.lineTo(175-positionX,140-positionY);
                contextSwimmer.lineWidth = 10;
                contextSwimmer.strokeStyle = "#000000"; 
                contextSwimmer.lineCap = "round";
                contextSwimmer.stroke();

               // image left arm
                contextSwimmer.beginPath();
                contextSwimmer.moveTo(200, 100);
                contextSwimmer.lineTo(225+positionX,140-positionY);
                contextSwimmer.lineWidth = 10;
                contextSwimmer.strokeStyle = "#000000"; 
                contextSwimmer.lineCap = "round";
                contextSwimmer.stroke();

               // image right leg
                contextSwimmer.beginPath();
                contextSwimmer.moveTo(200, 175);
                contextSwimmer.lineTo(190-positionX,250-positionY);
                contextSwimmer.lineWidth = 10;
                contextSwimmer.strokeStyle = "#000000"; 
                contextSwimmer.lineCap = "round";
                contextSwimmer.stroke();


               // image left leg
                contextSwimmer.beginPath();
                contextSwimmer.moveTo(200, 175);
                contextSwimmer.lineTo(210+positionX,250-positionY);
                contextSwimmer.lineWidth = 10;
                contextSwimmer.strokeStyle = "#000000"; 
                contextSwimmer.lineCap = "round";
                contextSwimmer.stroke();

                contextSwimmer.restore();

           };

</script>

</head>
    <body onload="drawWater();">
        <canvas id="myWaterCanvas" width="400" height="400" style="z-index: 2; 
		              position:absolute;left:0px;top:0px;">
        </canvas>
        <canvas id="mySwimmerCanvas" width="400" height="400" style="z-index: 1; 
		              position:absolute;left:0px;top:0px;">
        </canvas>

    </body>
</html>

Kết luận

Canvas HTML5 là điểm chính để xây dựng các RIA dựa trên trình duyệt. Nó cung cấp một môi trường vẽ thiết thực được JavaScript và trí tưởng tượng của bạn thúc đẩy. Nó không thực sự khó học, và có nhiều công cụ hỗ trợ trên trang web cho nhu cầu rèn luyện và học tập của bạn, bao gồm các cẩm nang, các blog, các bài viết trực tuyến, các hướng dẫn video và không-video, và các ứng dụng mẫu.

Khả năng để thay đổi văn bản và hình ảnh trực quan và để mô phỏng chuyển động làm cho Canvas trở thành một công cụ vô cùng có giá trị. Cho dù bạn tiếp cận nó từ quan điểm của một nhà thiết kế hay nhà phát triển, việc sử dụng Canvas để xây dựng các ứng dụng trò chơi chạy trên các thiết bị di động, hoặc chỉ muốn nâng cao việc sử dụng toàn bộ tài sản thực của màn hình, thì Canvas vẫn là một thành phần quan trọng của trải nghiệm HTML5.