Thứ tư, ngày 20 tháng 9 năm 2017

HTML5 – Chọn và di chuyển đối tượng trên Canvas

Ngày đăng: 11/4/2012, 8:33:29PM | Lượt xem: 1,762
Hot!

Thay vì lưu trữ nội dung của Canvas dưới dạng ImageData, ta có thể lưu trữ các đối tượng đồ họa dưới dạng cấu trúc dữ liệu và thực hiện vẽ từng phần tử lên Canvas. Với phương pháp này, tôi sẽ minh họa bằng một ví dụ  sử dụng chuột để chọn và di chuyển các hình vẽ trên Canvas.

vector_shape_mouseThay vì lưu trữ nội dung của Canvas dưới dạng ImageData, ta có thể lưu trữ các đối tượng đồ họa dưới dạng cấu trúc dữ liệu và thực hiện vẽ từng phần tử lên Canvas. Với phương pháp này, tôi sẽ minh họa bằng một ví dụ  sử dụng chuột để chọn và di chuyển các hình vẽ trên Canvas.

Xem Demo.

Tạo cấu trúc dữ liệu

Đầu tiên tôi sẽ tạo một lớp Rect dùng để chứa dữ liệu của một hình chữ nhật. Lớp này ngoài các biến lưu trữ tọa độ, kích thước và trạng thái (selected) thì cần một phương thức dùng để kiểm tra xem một tọa độ [x,y] có nằm bên trong nó không. Tôi gọi phương thức này là isContain() và có kiểu trả về là boolean. Mã nguồn của lớp này có dạng:

function Rect() {
  this.isSelected = false;
  this.x = 0;
  this.y = 0;
  this.width = 1;
  this.height = 1;
}
Rect.prototype.isContain = function(x,y){
	var right = this.x + this.width;
	var bottom = this.y + this.height;
	return x > this.x && x < right &&
		 y > this.y && y < bottom;
}

Tiếp theo, tôi tạo một lớp ShapeList dùng để chứa các đối tượng Rect trong một kiểu dữ liệu mảng. Ngoài ra, ShapeList sẽ có thêm một biến dùng để chỉ ra đối tượng Rect đang được chọn (selectedItem), và hai biến dùng để lưu vị trí của chuột khi click lên một đối tượng Rect (offsetX, offsetY). Hai biến offset này dùng để tính tọa độ chính xác khi người dùng sử dụng chuột để di chuyển đối tượng Rect.

ShapeList còn có hai phương thức:

-          addItem: thêm một đối tượng Rect vào danh sách.

-          selectAt:  tìm và chọn đối tượng Rect chứa tọa độ [x,y]. Tôi sẽ duyệt ngược từ cuối mảng để đảm bảo các đối tượng nằm sau sẽ được chọn trước trong trường hợp nhiều Rect cùng chứa điểm [x,y]

function ShapeList(){
	this.items = [];
	this.selectedItem = null;
	this.offsetX = -1;
	this.offsetY = -1;
}

ShapeList.prototype.addItem = function(x,y,width,height){
	var rect = new Rect;
	rect.x = x;
	rect.y = y;
	rect.width = width;
	rect.height = height;

	this.items.push(rect);
}

ShapeList.prototype.selectAt = function(x,y){
	if(this.selectedItem)
		this.selectedItem.isSelected = false;
	this.selectedItem = null;
	for (var i = 0; i < this.items.length; i++) {
		var rect = this.items[i];
		if(rect.contains(x,y))
		{
			this.selectedItem = this.items[i];
			this.offsetX = x - this.items[i].x;
			this.offsetY = y - this.items[i].y;
			this.items[i].isSelected = true;
			break;
		}
    }
}

Các phương thức vẽ bằng context

function draw(){
	clear();
    for (var i = _list.items.length-1;i>=0; i--) {
		drawRect(_list.items[i]);
    }
}

function drawRect(rect){
	_context.fillRect(rect.x,rect.y,rect.width,rect.height);
	if(rect.isSelected)
	{
		_context.save();
		_context.strokeStyle = "red";
		_context.strokeRect(rect.x,rect.y,rect.width,rect.height);
		_context.restore();
	}
}

Các sự kiện chuột của Canvas

Trong các sự kiện này, ta sẽ dùng cờ _ismoving để xác định xem một đối tượng có đang được chọn hay không và thực hiện di chuyển đối tượng ShapeList.selectedItem trong mousemove. Giá trị _ismoving này sẽ được xác định trong sự kiện mousedown và bị hủy khi mouseup.

function canvas_mousedown(e){

	var x = e.pageX - _canvas.offsetLeft;
	var y = e.pageY - _canvas.offsetTop;

	_list.selectAt(x,y)

	if(!_list.selectedItem)
		_list.addItem(x-RECT_SIZE,y-RECT_SIZE,RECT_SIZE*2,RECT_SIZE*2);

	_ismoving = true;
	draw();
}
function canvas_mousemove(e){
	if(_ismoving && _list.selectedItem){
		var x = e.pageX - _canvas.offsetLeft;
		var y = e.pageY - _canvas.offsetTop;

		_list.selectedItem.x = x - _list.offsetX;
		_list.selectedItem.y = y - _list.offsetY;

		draw();
	}
}
function canvas_mouseup(e){
	_ismoving = false;
}

Mã nguồn hoàn chỉnh

<html>
<head>

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

var _canvas;
var _context;
var _list = new ShapeList;
var _ismoving = false;

function Rect() {
  this.isSelected = false;
  this.x = 0;
  this.y = 0;
  this.width = 1;
  this.height = 1;
}
Rect.prototype.contains = function(x,y){
	var right = this.x + this.width;
	var bottom = this.y + this.height;
	return x > this.x && x < right &&
		 y > this.y && y < bottom;
}
function ShapeList(){
	this.items = [];
	this.selectedItem = null;
	this.offsetX = -1;
	this.offsetY = -1;
}

ShapeList.prototype.addItem = function(x,y,width,height){
	var rect = new Rect;
	rect.x = x;
	rect.y = y;
	rect.width = width;
	rect.height = height;

	this.items.push(rect);

}

ShapeList.prototype.selectAt = function(x,y){
	if(this.selectedItem)
		this.selectedItem.isSelected = false;
	this.selectedItem = null;
	for (var i = 0; i < this.items.length; i++) {
		var rect = this.items[i];
		if(rect.contains(x,y))
		{
			this.selectedItem = this.items[i];
			this.offsetX = x - this.items[i].x;
			this.offsetY = y - this.items[i].y;
			this.items[i].isSelected = true;
			break;
		}
    }
}

function canvas_mousedown(e){

	var x = e.pageX - _canvas.offsetLeft;
	var y = e.pageY - _canvas.offsetTop;

	_list.selectAt(x,y)

	if(!_list.selectedItem)
		_list.addItem(x-RECT_SIZE,y-RECT_SIZE,RECT_SIZE*2,RECT_SIZE*2);

	_ismoving = true;
	draw();
}
function canvas_mousemove(e){
	if(_ismoving && _list.selectedItem){
		var x = e.pageX - _canvas.offsetLeft;
		var y = e.pageY - _canvas.offsetTop;

		_list.selectedItem.x = x - _list.offsetX;
		_list.selectedItem.y = y - _list.offsetY;

		draw();
	}
}
function canvas_mouseup(e){
	_ismoving = false;
}

function clear(deleteData){

	_context.clearRect(0,0,_canvas.width,_canvas.height);
	if(deleteData)
		_list.items = [];
}

function draw(){
	clear();
    for (var i = _list.items.length-1;i>=0; i--) {
		drawRect(_list.items[i]);
    }
}

function drawRect(rect){
	_context.fillRect(rect.x,rect.y,rect.width,rect.height);
	if(rect.isSelected)
	{
		_context.save();
		_context.strokeStyle = "red";
		_context.strokeRect(rect.x,rect.y,rect.width,rect.height);
		_context.restore();
	}
}

$(function(){

	_canvas = document.getElementById("canvas");
	_context = _canvas.getContext("2d");
	_context.fillStyle = "wheat";

	_canvas.onmousedown = canvas_mousedown;
	_canvas.onmousemove = canvas_mousemove;
	_canvas.onmouseup = canvas_mouseup;

	$("#button1").click(function(){
		clear(true);
	});
});
</script>
</head>
<body>
	<div>
	<button id="button1">Clear</button>
	</div>
   <canvas id="canvas" width="400px" height="400px" style="border: 1px solid gray;"></canvas>
</body>
</html>

Kết quả:

HTML5 - Canvas - Moving Shape

YinYang’s Programming Blog

 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
ca do bong da online
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.