我试图让绿色三角形围绕其中心旋转,并朝向鼠标位置定位。我能够做到这一点,你可以在这里查看完整的代码和结果:
https://codepen.io/Carpetfizz/project/editor/DQbEVe
考虑以下代码行:
r = Math.atan2(mouseY - centerY, mouseX - centerX)
ctx.rotate(r + Math.PI/2)
我随意地将Math.PI/2
添加到我的角度计算中,因为没有它,旋转似乎是90度(通过检查)。我想要更好地理解atan2正在计算的坐标系,这样我可以证明将角度偏移90度的原因(并希望简化代码)。
编辑:
据我了解,Math.atan2
正在测量蓝色所示的角度。不应该旋转两个三角形,蓝色角度朝向鼠标指针(橙色点)?嗯 - 显然不是因为它是相同的角度而且它们是两个不同的方向,但我似乎无法向自己证明这一点。
答案 0 :(得分:2)
画布上的坐标系使用0°指向右。这意味着你想要点“向上”的任何东西必须最初正确绘制。
在这种情况下您需要做的就是更改此图:
到
指向“向上”0°
你可以将数学回到你期望的那样。
var ctx = c.getContext("2d"), img = new Image;
img.onload = go; img.src = "https://i.stack.imgur.com/Yj9DU.jpg";
function draw(pos) {
var cx = c.width>>1,
cy = c.height>>1,
angle = Math.atan2(pos.y - cy, pos.x - cx);
ctx.setTransform(1,0,0,1,cx, cy);
ctx.rotate(angle);
ctx.drawImage(img, -img.width>>1, -img.height>>1);
}
function go() {
ctx.globalCompositeOperation = "copy";
window.onmousemove = function(e) {draw({x: e.clientX, y: e.clientY})}
}
html, body {margin:0;background:#ccc}
#c {background:#fff}
<canvas id=c width=600 height=600></canvas>
答案 1 :(得分:1)
当你在数学课上做反复数词时,你通常会处理一个向上增加的y轴。然而,在大多数计算机图形系统中,包括画布图形,y增加向下。 [删除了错误的陈述]
编辑:我必须承认我之前写的错误有两个原因:
rotate
函数顺时针旋转以获得正角度,仅此一项就可以补偿y轴的翻转。我在Plunker中使用了您的代码副本,现在我意识到90°旋转只是补偿您正在绘制的图形图像的起始方向。如果箭头指向右边开始,而不是直接向上,则不需要添加π/ 2.
答案 2 :(得分:1)
这是因为Math.atan2
的工作原理。
在上图中,正X轴是从交汇点到最右边位置的水平段。
为了更清楚,这里是这个图的交互式版本,其中x,y值被转换为[-1~1]值。
const ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
radius = 0.3;
ctx.textAlign = 'center';
canvas.onmousemove = canvas.onclick = e => {
// offset mouse values so they are relative to the center of our canvas
draw(as(e.offsetX), as(e.offsetY));
}
draw(0, 0);
function draw(x, y) {
clear();
drawCross();
drawLineToPoint(x, y);
drawPoint(x, y);
const angle = Math.atan2(y, x);
drawAngle(angle);
writeAngle(angle);
}
function clear() {
ctx.clearRect(0, 0, w, h);
}
function drawCross() {
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(s(0), s(-1));
ctx.lineTo(s(0), s(1));
ctx.moveTo(s(-1), s(0));
ctx.lineTo(s(0), s(0));
ctx.strokeStyle = ctx.fillStyle = '#2e404f';
ctx.stroke();
// positive X axis
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(s(0), s(0));
ctx.lineTo(s(1), s(0));
ctx.stroke();
ctx.lineWidth = 1;
ctx.font = '20px/1 sans-serif';
ctx.fillText('+X', s(1) - 20, s(0) - 10);
}
function drawPoint(x, y) {
ctx.beginPath();
ctx.arc(s(x), s(y), 10, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill();
ctx.font = '12px/1 sans-serif';
ctx.fillText(`x: ${x.toFixed(2)} y: ${y.toFixed(2)}`, s(x), s(y) - 15);
}
function drawLineToPoint(x, y) {
ctx.beginPath();
ctx.moveTo(s(0), s(0));
ctx.lineTo(s(x), s(y));
ctx.strokeStyle = 'red';
ctx.setLineDash([5, 5]);
ctx.stroke();
ctx.setLineDash([0]);
}
function drawAngle(angle) {
ctx.beginPath();
ctx.moveTo(s(radius), s(0));
ctx.arc(s(0), s(0), radius * w / 2,
0, // 'arc' method also starts from positive X axis (3 o'clock)
angle,
true // Math.atan2 returns the anti-clockwise angle
);
ctx.strokeStyle = ctx.fillStyle = 'blue';
ctx.stroke();
ctx.font = '20px/1 sans-serif';
ctx.fillText('∂: ' + angle.toFixed(2), s(0), s(0));
}
// below methods will add the w / 2 offset
// because canvas coords set 0, 0 at top-left corner
// converts from [-1 ~ 1] to px
function s(value) {
return value * w / 2 + (w / 2);
}
// converts from px to [-1 ~ 1]
function as(value) {
return (value - w / 2) / (w / 2);
}
&#13;
<canvas id="canvas" width="500" height="500"></canvas>
&#13;
所以现在,如果我们回到你的图像,它当前指向顶部(正Y轴),而你刚测量的角度对x轴是实际的,所以它没有&# 39; t指向你想要的地方。
现在我们知道了问题,解决方案非常简单:
+ Math.PI / 2
偏移量应用于您的角度,答案 3 :(得分:0)
我遇到了同样的问题,并且能够通过跟随轴“技巧”达到预期的结果:
// Default usage (works fine if your image / shape points to the RIGHT)
let angle = Math.atan2(delta_y, delta_x);
// 'Tricky' usage (works fine if your image / shape points to the LEFT)
let angle = Math.atan2(delta_y, -delta_x);
// 'Tricky' usage (works fine if your image / shape points to the BOTTOM)
let angle = Math.atan2(delta_x, delta_y);
// 'Tricky' usage (works fine if your image / shape points to the TOP)
let angle = Math.atan2(delta_x, -delta_y);