返回 导航

HTML5 / CSS3

hangge.com

HTML5 - Canvas的使用样例14(图形增加鼠标点击、拖动交互)

作者:hangge | 2016-02-21 10:10
Canvas是一种非保留性的绘图界面,即不会记录过去执行的绘图操作,而是保持最终结果(构成图像的彩色像素)。
如果想让Canvas变得具有交互性,比如用户可以选择、拖动画布上的图形。那么我们必须记录绘制的每一个对象,才能在将来灵活的修改并重绘它们,实现交互。

1,鼠标点击选择图形对象
(1)下面样例中点击“添加圆圈”按钮可以在画布上增加位置、大小、颜色都是随机的圆圈。
(2)点击“清空画布”按钮可以清除画布上所有圆圈。
(3)鼠标点击任意圆圈,该圆圈会出现黑色边框,表示选中。


代码说明:
(1)为了能够将圆圈对象保存起来,我们定义了一个叫 Circle() 的函数类创建自定义对象。同时要让这个对象能够保持数据,要使用关键字 this 来创建属性。
(2)drawCircles() 函数用来根据当前圆圈的集合来填充画布。每次程序刷新画布时,会先使用 clearRect() 方法清除画布上的所有内容。但不用当心这样会造成画布闪烁,即画布上的圆圈一下子全部消失,然后一下子又重新出现。
因为Canvas针对这个问题进行了优化,会在所有绘图逻辑执行完毕后才清除或绘制所有内容,保证最终结果的流畅。
(3)要实现鼠标选中某个图像,就要用到碰撞检测。即计算鼠标点击的那个点是否落在某个形状里。对于圆圈而言,只要计算单击点与圆心的直线距离即可。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>hangge.com</title>

 <style>
	 canvas {
	   cursor: pointer;
	   border: 1px solid black;
	 }
 </style>
 <script>
	// 这个方法用来储存每个圆圈对象
	function Circle(x, y, radius, color) {
	  this.x = x;
	  this.y = y;
	  this.radius = radius;
	  this.color = color;
	  this.isSelected = false;
	}

	// 保存画布上所有的圆圈
	var circles = [];

	var canvas;
	var context;

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

	  canvas.onmousedown = canvasClick;
	};

	function addRandomCircle() {
	  // 为圆圈计算一个随机大小和位置
	  var radius = randomFromTo(10, 60);
	  var x = randomFromTo(0, canvas.width);
	  var y = randomFromTo(0, canvas.height);

	  // 为圆圈计算一个随机颜色
	  var colors = ["green", "blue", "red", "yellow", "magenta", "orange", "brown", "purple", "pink"];
	  var color = colors[randomFromTo(0, 8)];

	  // 创建一个新圆圈
	  var circle = new Circle(x, y, radius, color);

	  // 把它保存在数组中
	  circles.push(circle);

	  // 重新绘制画布
	  drawCircles();
	}

	function clearCanvas() {
	  // 去除所有圆圈
	  circles = [];

	  // 重新绘制画布.
	  drawCircles();
	}

	function drawCircles() {
	  // 清除画布,准备绘制
	  context.clearRect(0, 0, canvas.width, canvas.height);

	  // 遍历所有圆圈
	  for(var i=0; i<circles.length; i++) {
		var circle = circles[i];

		// 绘制圆圈
		context.globalAlpha = 0.85;
		context.beginPath();
		context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
		context.fillStyle = circle.color;
		context.strokeStyle = "black";

		if (circle.isSelected) {
		  context.lineWidth = 5;
		}
		else {
		  context.lineWidth = 1;
		}
		context.fill();
		context.stroke(); 
	  }
	}

	var previousSelectedCircle;

	function canvasClick(e) {
	  // 取得画布上被单击的点
	  var clickX = e.pageX - canvas.offsetLeft;
	  var clickY = e.pageY - canvas.offsetTop;

	  // 查找被单击的圆圈
	  for(var i=circles.length-1; i>=0; i--) {
		var circle = circles[i];
		//使用勾股定理计算这个点与圆心之间的距离
		var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) 
			+ Math.pow(circle.y - clickY, 2))
		// 判断这个点是否在圆圈中
		if (distanceFromCenter <= circle.radius) {
		  // 清除之前选择的圆圈
		  if (previousSelectedCircle != null) previousSelectedCircle.isSelected = false;
		  previousSelectedCircle = circle;
		  
		  //选择新圆圈
		  circle.isSelected = true;

		  //更新显示
		  drawCircles();

		  //停止搜索
		  return;
		}
	  }
	}

	//在某个范围内生成随机数
	function randomFromTo(from, to) {
	  return Math.floor(Math.random() * (to - from + 1) + from);
	}
 </script>
</head>	

<body>

  <canvas id="canvas" width="400" height="300">
  </canvas>

  <div>
    <button onclick="addRandomCircle()">添加圆圈</button>
    <button onclick="clearCanvas()">清空画布</button>
  </div>
 
</body>
</html>

2,鼠标拖动图形对象
下面做个功能改进,允许用户在画布上拖动圆圈。只要监听Canvas的 onMouseMove 事件,相应地修改圆圈的坐标,然后再调用 drawCircle() 函数重绘画布即可。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>hangge.com</title>

 <style>
	 canvas {
	   cursor: pointer;
	   border: 1px solid black;
	 }
 </style>
 <script>
	// 这个方法用来储存每个圆圈对象
	function Circle(x, y, radius, color) {
	  this.x = x;
	  this.y = y;
	  this.radius = radius;
	  this.color = color;
	  this.isSelected = false;
	}

	// 保存画布上所有的圆圈
	var circles = [];

	var canvas;
	var context;

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

	  canvas.onmousedown = canvasClick;
	  canvas.onmouseup = stopDragging;
	  canvas.onmouseout = stopDragging;
	  canvas.onmousemove = dragCircle;
	};

	function addRandomCircle() {
	  // 为圆圈计算一个随机大小和位置
	  var radius = randomFromTo(10, 60);
	  var x = randomFromTo(0, canvas.width);
	  var y = randomFromTo(0, canvas.height);

	  // 为圆圈计算一个随机颜色
	  var colors = ["green", "blue", "red", "yellow", "magenta", "orange", "brown", "purple", "pink"];
	  var color = colors[randomFromTo(0, 8)];

	  // 创建一个新圆圈
	  var circle = new Circle(x, y, radius, color);

	  // 把它保存在数组中
	  circles.push(circle);

	  // 重新绘制画布
	  drawCircles();
	}

	function clearCanvas() {
	  // 去除所有圆圈
	  circles = [];

	  // 重新绘制画布.
	  drawCircles();
	}

	function drawCircles() {
	  // 清除画布,准备绘制
	  context.clearRect(0, 0, canvas.width, canvas.height);

	  // 遍历所有圆圈
	  for(var i=0; i<circles.length; i++) {
		var circle = circles[i];

		// 绘制圆圈
		context.globalAlpha = 0.85;
		context.beginPath();
		context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
		context.fillStyle = circle.color;
		context.strokeStyle = "black";

		if (circle.isSelected) {
		  context.lineWidth = 5;
		}
		else {
		  context.lineWidth = 1;
		}
		context.fill();
		context.stroke(); 
	  }
	}

	var previousSelectedCircle;

	function canvasClick(e) {
	  // 取得画布上被单击的点
	  var clickX = e.pageX - canvas.offsetLeft;
	  var clickY = e.pageY - canvas.offsetTop;

	  // 查找被单击的圆圈
	  for(var i=circles.length-1; i>=0; i--) {
		var circle = circles[i];
		//使用勾股定理计算这个点与圆心之间的距离
		var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) 
			+ Math.pow(circle.y - clickY, 2))
		// 判断这个点是否在圆圈中
		if (distanceFromCenter <= circle.radius) {
		  // 清除之前选择的圆圈
		  if (previousSelectedCircle != null) previousSelectedCircle.isSelected = false;
		  previousSelectedCircle = circle;
		  
		  //选择新圆圈
		  circle.isSelected = true;

		  // 使圆圈允许拖拽
		  isDragging = true;

		  //更新显示
		  drawCircles();

		  //停止搜索
		  return;
		}
	  }
	}

	//在某个范围内生成随机数
	function randomFromTo(from, to) {
	  return Math.floor(Math.random() * (to - from + 1) + from);
	}

	var isDragging = false;

	function stopDragging() {
	  isDragging = false;
	}

	function dragCircle(e) {
	  // 判断圆圈是否开始拖拽
	  if (isDragging == true) {
	    // 判断拖拽对象是否存在
	    if (previousSelectedCircle != null) {
	      // 取得鼠标位置
	      var x = e.pageX - canvas.offsetLeft;
	      var y = e.pageY - canvas.offsetTop;

	      // 将圆圈移动到鼠标位置
	      previousSelectedCircle.x = x;
 	      previousSelectedCircle.y = y;

 	     // 更新画布
 	     drawCircles();
	    }
	  }
	}
 </script>
</head>	

<body>

  <canvas id="canvas" width="400" height="300">
  </canvas>

  <div>
    <button onclick="addRandomCircle()">添加圆圈</button>
    <button onclick="clearCanvas()">清空画布</button>
  </div>
 
</body>
</html>
评论

全部评论(2)

回到顶部