如何将onclick事件绑定到饼图段?

时间:2015-03-13 14:03:16

标签: html5-canvas

1 个答案:

答案 0 :(得分:2)

饼图片段实际上是一个楔子。你有几种方法来测试楔形。

一种方式是数学方式:

  • 测试鼠标是否在楔形创建的圆的半径范围内。

  • 如果半径测试为真,则计算鼠标与圆的中心点的角度。

  • 将该角度与每个楔形进行比较。如果角度在特定楔形弧的起始角度和结束角度之间,则鼠标位于该楔形内部。

另一种方法是使用canvas的内置路径命中测试方法:isPointInPath

  • 重新定义一个楔子。没有必要实际抚摸或填充那个楔子。只需执行从beginPathclosePath的命令。

  • 如果鼠标位于该楔子内,请使用context.isPointInPath(mouseX,mouseY)进行测试。

  • 如果isPointInPath返回true,则您在鼠标下方发现了楔形。如果没有,那么重新定义&点击测试其他每个楔子。

这是我在一段时间后编码的东西,在徘徊时测试饼图的楔形,并在点击楔形时将楔形移出馅饼。

它使用isPointInPath方法进行命中测试:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineJoin = "round";

var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();

function Wedge(cx, cy, radius, startAngleDeg, endAngleDeg, fill, stroke, linewidth) {
  this.cx = cx;
  this.cy = cy;
  this.radius = radius;
  this.startAngle = startAngleDeg * Math.PI / 180;
  this.endAngle = endAngleDeg * Math.PI / 180;
  this.fill = fill;
  this.stroke = stroke;
  this.lineWidth = linewidth;
  this.offsetX = 0;
  this.offsetY = 0;
  this.rr = radius * radius;


  this.centerX = cx;
  this.centerY = cy;

  this.midAngle = this.startAngle + (this.endAngle - this.startAngle) / 2;
  this.offsetDistance = 15;
  this.explodeX = this.offsetDistance * Math.cos(this.midAngle);
  this.explodeY = this.offsetDistance * Math.sin(this.midAngle);
  this.isExploded = false;



};
Wedge.prototype.draw = function(fill, stroke) {
  this.define();
  this.fillStroke(fill, stroke);
  ctx.beginPath();
  ctx.arc(this.cx, this.cy, this.radius, 0, Math.PI * 2);
  ctx.closePath();
  ctx.lineWidth = 0.50;
  ctx.stroke();
}
Wedge.prototype.fillStroke = function(fill, stroke) {
  ctx.fillStyle = fill || this.fill;
  ctx.fill();
  ctx.strokeStyle = stroke, this.stroke;
  ctx.lineWidth = this.lineWidth;
  ctx.stroke();
}
Wedge.prototype.define = function() {
  var x = this.cx + this.offsetX;
  var y = this.cy + this.offsetY;
  ctx.beginPath();
  ctx.arc(x, y, this.radius, this.startAngle, this.endAngle);
  ctx.lineTo(x, y);
  ctx.closePath();
}
Wedge.prototype.ptAtAngle = function(radianAngle) {
  var xx = (this.cx + this.offsetX) + this.radius * Math.cos(radianAngle);
  var yy = (this.cy + this.offsetY) + this.radius * Math.sin(radianAngle);
  return ({
    x: x,
    y: y
  });
}
Wedge.prototype.explode = function(isExploded) {
  this.isExploded = isExploded;
  this.offsetX = isExploded ? this.explodeX : 0;
  this.offsetY = isExploded ? this.explodeY : 0;
  this.draw();
}
Wedge.prototype.isPointInside = function(x, y) {
  var dx = x - (this.cx + this.offsetX);
  var dy = y - (this.cy + this.offsetY);
  if (dx * dx + dy * dy > this.rr) {
    return (false);
  }
  var angle = (Math.atan2(dy, dx) + Math.PI * 2) % (Math.PI * 2);
  return (angle >= this.startAngle && angle <= this.endAngle);
}
Wedge.prototype.marker = function(pos) {
  ctx.beginPath();
  ctx.arc(pos.x, pos.y, 3, 0, Math.PI * 2);
  ctx.closePath();
  ctx.fillStyle = "red";
  ctx.fill();
}


function handleMouseDown(e) {
  e.preventDefault();
  mouseX = parseInt(e.clientX - offsetX);
  mouseY = parseInt(e.clientY - offsetY);

  clear();
  for (var i = 0; i < wedges.length; i++) {
    var wedge = wedges[i].wedge;
    if (wedge.isPointInside(mouseX, mouseY)) {
      wedge.explode(!wedge.isExploded);
    }
    wedge.draw();
  }
}

function handleMouseUp(e) {
  e.preventDefault();
  mouseX = parseInt(e.clientX - offsetX);
  mouseY = parseInt(e.clientY - offsetY);

  // Put your mouseup stuff here
  isDown = false;
}

function handleMouseOut(e) {
  e.preventDefault();
  mouseX = parseInt(e.clientX - offsetX);
  mouseY = parseInt(e.clientY - offsetY);

  // Put your mouseOut stuff here
  isDown = false;
}

function handleMouseMove(e) {
  e.preventDefault();
  mouseX = parseInt(e.clientX - offsetX);
  mouseY = parseInt(e.clientY - offsetY);

  for (var i = 0; i < wedges.length; i++) {
    var wedge = wedges[i].wedge;
    if (wedge.isPointInside(mouseX, mouseY)) {
      wedge.draw("black");
    } else {
      wedge.draw();
    }
  }


}

$("#canvas").mousedown(function(e) {
  handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
  handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
  handleMouseUp(e);
});
$("#canvas").mouseout(function(e) {
  handleMouseOut(e);
});

function clear() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

var PI2 = Math.PI * 2;
var cx = 150;
var cy = 150;
var r = 100;
var line = 2;
var stroke = "black";
var wedges = [];
wedges.push({
  percent: 18,
  fill: "red"
});
wedges.push({
  percent: 30,
  fill: "blue"
});
wedges.push({
  percent: 25,
  fill: "green"
});
wedges.push({
  percent: 13,
  fill: "purple"
});
wedges.push({
  percent: 14,
  fill: "gold"
});
var rAngle = 0;
for (var i = 0; i < wedges.length; i++) {
  var wedge = wedges[i];
  var angle = 360 * wedge.percent / 100;
  wedge.wedge = new Wedge(cx, cy, r, rAngle, rAngle + angle, wedge.fill, "black", 1);
  wedge.wedge.draw();
  rAngle += angle;
}

window.onscroll = function(e) {
  var BB = canvas.getBoundingClientRect();
  offsetX = BB.left;
  offsetY = BB.top;
}
body {
  background-color: ivory;
}
#canvas {
  border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Hover wedge to highlight it<br>Click wedge to explode that wedge</h4>
<canvas id="canvas" width=300 height=300></canvas>