我想在canvas元素周围创建一个碰撞区域,使我能够使用鼠标事件宽度普通javascript与该元素进行交互。
在下面详细说明我的问题:
首先,我用x,y,radius,beginAngle,endAngle和颜色自变量制作一个弧段构造器
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
/* arc class constructor */
function ArcSegment(x, y, radius, beginAngle, endAngle, segColor) {
this.x = x;
this.y = y;
this.radius = radius;
this.beginAngle = beginAngle;
this.endAngle = endAngle;
this.segColor = segColor;
this.update = function() {
this.draw();
}
this.draw = function(){
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, this.beginAngle, this.endAngle, false);
ctx.lineWidth = 20;
ctx.strokeStyle = this.segColor;
ctx.stroke();
}
}
第二,我添加一些值来创建这些弧段
/* x, y, radius, startAngle, endAngle and color */
var centerX = canvas.width/2;
var centerY = canvas.height/2;
var radiuses = [
100,
120
];
var pi = Math.PI;
var segmentStart = [
pi/2,
0
];
var segmentRotation = [
1.4*pi,
0.2*pi
];
var segmentColors = [
"#133046",
"#15959F"
];
然后,我将它们绘制在画布上。
var segment1 = new ArcSegment(centerX, centerY, radiuses[0], segmentStart[0], segmentStart[0]+segmentRotation[0], segmentColors[0]);
segment1.update();
var segment2 = new ArcSegment(centerX, centerY, radiuses[1], segmentStart[1], segmentStart[1]+segmentRotation[1], segmentColors[1]);
segment2.update();
这是结果:
我现在想要的是一种在创建的每个弧段的顶部创建碰撞检测的方法,以便在该特定弧段的顶部单击或移动鼠标时
可能会发生一系列事件(例如,例如旋转动画等等)。
我所做的所有研究都建议获取矩形的x和y值并计算鼠标位置的距离(mouse.x,mouse.y)和矩形的长度,但是该方法没有使用具有lineWidth属性的弧段。
在此问题上的任何帮助将不胜感激。
答案 0 :(得分:1)
下面是纯数学方法,这里的关键是代码isPointInside
// Classes
function Arc(x, y, angle, arc, radius, colour, highlightColour) {
this.x = x;
this.y = y;
this.angle = angle;
this.arc = arc;
this.radius = radius;
this.colour = colour;
this.highlightColour = highlightColour;
this.highlighted = false;
this.lineWidth = 20;
}
Arc.prototype = {
isPointInside: function(x, y) {
var _x = x - this.x;
var _y = y - this.y;
var distance = Math.sqrt(_x * _x + _y * _y);
var invDistance = 1.0 / distance;
var angle = Math.acos(
_x * Math.cos(this.angle) * invDistance +
_y * Math.sin(this.angle) * invDistance
);
return distance > (this.radius - this.lineWidth/2) &&
distance < (this.radius + this.lineWidth/2) &&
angle < this.arc/2;
},
render: function(ctx) {
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.highlighted ? this.highlightColour : this.colour;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, this.angle - this.arc/2, this.angle + this.arc/2, false );
ctx.stroke();
}
};
// Variables
var canvas = null;
var ctx = null;
var arcs = [];
// Functions
function draw() {
ctx.fillStyle = "gray";
ctx.fillRect(0, 0, 999, 999);
for (var i = 0; i < arcs.length; ++i) {
arcs[i].render(ctx);
}
}
// Event Listeners
function onMouseMove(e) {
var bounds = canvas.getBoundingClientRect();
var x = e.clientX - bounds.left;
var y = e.clientY - bounds.top;
for (var i = 0; i < arcs.length; ++i) {
arcs[i].highlighted = arcs[i].isPointInside(x, y);
}
draw();
}
// Entry Point
onload = function() {
canvas = document.getElementById("canvas");
canvas.onmousemove = onMouseMove;
ctx = canvas.getContext("2d");
arcs.push(new Arc(190, 75, 0.2, 1.8, 60, "blue", "lime"));
arcs.push(new Arc(90, 75, 3.5, 4.2, 60, "red", "lime"));
draw();
}
<canvas id="canvas"></canvas>