HTML5 – Vẽ hình bằng chuột trong Canvas

drawing_penTrong bài viết này, tôi sẽ giới thiệu cách bắt và xử lý các thao tác chuột trên Canvas để thực hiện một ứng dụng vẽ hình đơn giản. Bên cạnh đó, bạn có thể biết được cách để lưu và phục hồi lại dữ liệu của canvas khi cần thiết. Các ví dụ trong bài khá đơn giản nên tôi sẽ không đi vào giải thích chi tiết.

Xem demo.

Xác định tọa độ chuột

Để xác định được tọa chuột trên canvas, tôi sẽ sử dụng tham số của các sự kiện như mousedown, mousemove, … Tham số của các sự kiện này chứa tọa độ chuột lưu trong hai biến pageX và pageY. Tôi sẽ dùng tọa độ này trừ đi tọa độ của canvas (canvas.offsetLeft và canvas.offsetTop) để lấy được vị trí chính xác của chuột trên canvas.

Đầu tiên là việc mô phỏng công cụ Pen cho phép vẽ tự do trong canvas:

<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var preX;
var preY;
var paint;
var canvas;
var context;

$(function(){
	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");

	$('#canvas').mousedown(function(e){
		preX = e.pageX - this.offsetLeft;
		preY = e.pageY - this.offsetTop;

		paint = true;
	});
	$('#canvas').mousemove(function(e){
	  if(paint){
		var x = e.pageX - this.offsetLeft;
		var y = e.pageY - this.offsetTop;
		context.moveTo(preX,preY);
		context.lineTo(x,y);
		context.stroke();
		preX = x;
		preY = y;
	  }
	});
	$('#canvas').mouseenter(function(e){
		if(paint)
		{
		preX = e.pageX - this.offsetLeft;
		preY = e.pageY - this.offsetTop;
		}
	});
	$("#canvas").mouseup(function(){
		paint = false;
	});
	$('#canvas').mouseleave(function(e){
		paint = false;
	});

});

</script>
</head>
<body>
   <canvas id="canvas" width="500px" height="500px" style="border: 1px solid gray;"></canvas>
</body>
</html>  

Lưu nội dung của Canvas

Để lưu lại dữ liệu của Canvas nhằm phục hồi khi cần thiết (chẳng hạn như chức năng Undo, Redo), tôi sẽ sử dụng phương thức context.getImageData() (xem bài HTML5 – Canvas: Vẽ ảnh và thao tác với pixel).Tôi sẽ sử dụng phương pháp này để thực hiện chức năng vẽ đoạn thẳng trên Canvas. Trước khi bắt đầu vẽ một đoạn thằng, canvas cần được lưu lại nội dung và mỗi khi chuột di chuyển, tôi sẽ phục hồi lại nội dung được lưu đó đồng thời vẽ một đoạn thẳng từ điểm bắt đầu đến vị trí chuột.

Tôi cũng sửa ví dụ trên thành một jQuery plugin để tiện sử dụng:

<html>
<head>

<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>

(function( $ ) {

	var preX;
	var preY;
	var tool;	 // pen, line
	var canvas;
	var context;
	var imageData;
	var paint;

  $.fn.makeDrawable = function() {

	canvas = this[0];
	if( !$(canvas).is("canvas") )
		throw "The target element must be a canvas";

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

	$(canvas).mousedown(function(e){
		preX = e.pageX - canvas.offsetLeft;
		preY = e.pageY - canvas.offsetTop;
		paint = true;
		if(tool=="line")
		{
			imageData = context.getImageData(0, 0, canvas.width, canvas.height);
		}
	});
	$(canvas).mousemove(function(e){
		if(paint)
		{
			var x = e.pageX - canvas.offsetLeft;
			var y = e.pageY - canvas.offsetTop;

			if(tool=="pen")
			{
				context.moveTo(preX,preY);
				context.lineTo(x,y);
				context.stroke();

				preX = x;
				preY = y;
			}
			else if(tool=="line")
			{
				canvas.width=canvas.width; // clear canvas content
				context.putImageData(imageData,0,0);

				context.moveTo(preX,preY);
				context.lineTo(x,y);
				context.stroke();
			}

		}
	});

	$(canvas).mouseup(function(e){
		if(tool=="line")
		{
			var x = e.pageX - canvas.offsetLeft;
			var y = e.pageY - canvas.offsetTop;

			context.moveTo(preX,preY);
			context.lineTo(x,y);
			context.stroke();
		}
		paint = false;
	});
	$(canvas).mouseleave(function(e){
		paint = false;
	});

	return $(canvas);
  };

  $.fn.setTool = function(newTool) {
	tool=newTool;
	return $(canvas);
  }
 $.fn.clear = function() {
	canvas.width=canvas.width;
	return $(canvas);
  }
})( jQuery );

$(function(){

	$("#canvas").makeDrawable();
	$("#button1").click(function(){
		$("#canvas").clear();
	});

	$("#pen").change(function(){
		if(this.value)
			$("#canvas").setTool("pen");
	});
	$("#line").change(function(){
		if(this.value)
			$("#canvas").setTool("line");
	});

	$("#canvas").setTool("pen");
});

</script>
</head>
<body>
	<div>
	<button id="button1">Clear</button>
	<input name="tool" type="radio" id="pen" checked="true">Pen</input>
	<input name="tool" type="radio" id="line">Line</input>
	</div>
   <canvas id="canvas" width="500px" height="500px" style="border: 1px solid gray;"></canvas>
</body>
</html>  

Kết quả:

Canvas drawing example

YinYang’s Programming Blog

Advertisements

18 thoughts on “HTML5 – Vẽ hình bằng chuột trong Canvas

  1. tớ là người mới học html5 và cũng rất hay vào blog của bạn.bạn cho mình hỏi là: khi ta nhấn chuột, giữ, kéo lê chuôt và thả ra thì ta được 1 đường (như trong demo của bạn), nhưng tớ muốn khi vẽ đường tiếp theo thì tất cả các đường trước đó sẽ bị xóa đi thì phải làm như thế nào? tớ dùng clearRect mãi mà không được. mong bạn cho mình ý kiến. thank bạn nhiều

    Trả lời
  2. chào bạn, bạn có thể cho mình hỏi, nếu mình muốn vẽ hình chữ nhật, mình dùng context.rect(preX, preY, width, height) (var width = e.pageX – canvas.offsetLeft; var height = e.pageY – canvas.offsetTop;) nó vẫn vẽ được hình chữ nhật nhưng mỗi lần kích thước lại khác nhau, tại sao lại như vậy?

    Trả lời
    • Khi vẽ hình chữ nhật, bạn cần chọn 1 điểm đầu để bắt đầu vẽ, giả sử điểm này là A. Sau đó chọn điểm kết thúc là B. Bạn chỉ cần tính width = B.x-A.x , height = B.y – A.y.

      Có thể lấy trị tuyệt đối vì giá trị này có thể âm.

      Trả lời

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s