2017-02-28 91 views
0

我有一个SVG,绘制原点和鼠标指针之间的一条线,我想要做的是当移动被压下(event.shiftKey ===真)使行“捕捉”到最接近的45度坐标,基本上与在Photoshop中获得的行为相同。计算坐标45度捕捉

我已经设法找出两点之间的角度(所以我可以决定哪个角度也可以捕捉,如果需要可能使用IF/ELSE树)但是我不知道我是如何 - 根据新的度数计算“结束”坐标。

我已经在这里设置一个简单的例子:https://jsbin.com/sohafekije/2/edit?html,js,output

我也采取了Photoshop的行为我试图重现的照片(质量不好我那么我不能使用相机“T截图 - 对不起)只是要100%清楚:http://i.imgur.com/Yo04uxY.jpg

enter image description here

基本上我想,当你按住Shift键,以重新在Photoshop中获得的行为,但我的猜测是,你需要用数学来解决问题是非常好的,我不是!

任何帮助是极大的赞赏:)

var app = document.getElementById('app'), 
 
    svg = SVG(app), 
 
    line = svg.polyline([]).fill('none').stroke({ width: 1 }), 
 
    start = [250,250], 
 
    end = null, 
 
    angleTxt = document.getElementById('angle'), 
 
    lineLengthTxt = document.getElementById('linelength'); 
 

 
line.marker('start', 10, 10, function(add) { 
 
    add.circle(10).fill('#f06') 
 
}) 
 

 
// On mouse move, redraw the line 
 
svg.on('mousemove', function(e){ 
 
    end = [e.layerX, e.layerY]; 
 
    line.plot([start, end]); 
 
    calcAngle(); 
 
}); 
 

 
function calcAngle() { 
 
    var deltaX = end[0] - start[0], 
 
     deltaY = end[1] - start[1], 
 
     rad = Math.atan2(deltaY, deltaX), 
 
     deg = rad * (180/Math.PI), 
 
     linelen = Math.sqrt(deltaX * deltaX + deltaY * deltaY); 
 
    
 

 
    
 
    angleTxt.textContent = deg; 
 
    lineLengthTxt.textContent = linelen; 
 
    
 
}
#app { border: 1px solid blue; width:100%; height:600px}
<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <meta charset="utf-8"> 
 
    <meta name="viewport" content="width=device-width"> 
 
    <title>JS Bin</title> 
 
    <script type="text/javascript" src="https://rawgit.com/svgdotjs/svg.js/master/dist/svg.js"></script> 
 
</head> 
 
<body> 
 
    <div id="app"></div> 
 
    Angle: <span id="angle">-</span><br> 
 
    Line Length: <span id="linelength">-</span> 
 
</body> 
 
</html>

+0

您是否尝试将长度=第一个点和鼠标之间的距离的线上的角度应用? (距离= sqrt((x2 - x1)2 +(y2 - y1)2)) – Kornflexx

+0

@Kornflexx我试过这个:https://jsbin.com/kebikekaxo/1/edit?html,js,output。但是,当您将其与Photoshop行为(我用作用于UX用途的“标准”)进行比较时,绘制的线条长度太长。我猜他们在计算线长时必须做些更复杂的事情。 – TRG

+0

我注意到线长上的“过冲”随着距离增大而增大(当线较小时,过冲很小)。也许他们对线长应用某种指数修饰符? (但是我真的对数学不好,所以我只是在这里抓着吸管) – TRG

回答

1

我做到了!

如何使用它

您计算出新的角度和使用x值和窦Y值余弦应用它。这里角度以PI/4的步进到-PI到PI;如果你想改变'var newAngle = ...'这一行替换4的其他数字。

它如何运作

首先,我在想这个事实,你需要8角位置,由4 PI拉德(一cirlce是2PI弧度)。所以你需要简化你的角度。

newAngle/Math.PI // value is between -1 and 1 (it's a double) 
newAngle/Math.PI * 4 // value is between -4 and 4 (it's a double) 
Math.round(newAngle/Math.PI * 4) // value is between -4 and 4 (but it's a integer now) 
Math.round(newAngle/Math.PI * 4)/4 // value is between -1 and 1 (with step of 0.25) 
Math.round(newAngle/Math.PI * 4)/4 * Math.PI // value is between -PI and PI with step of 0.25 * PI (PI/4) 

现在你的新角度是正确的。 Cosinus返回角度的x值(请看维基百科的图形解释)和Sinus角度的y值。 通过将COSINUS/SINUS乘以长度,您可以找到下一个点。

function applyNewAngle() { 
    var deltaX = end[0] - start[0], 
     deltaY = end[1] - start[1], 
     dist = Math.sqrt(Math.pow(deltaX,2) + Math.pow(deltaY,2)); 
    var newAngle = Math.atan2(deltaY, deltaX); 
    var shiftedAngle = Math.round(newAngle/Math.PI * 4)/4 * Math.PI; 
    end = [start[0]+dist*Math.cos(shiftedAngle), start[1]+dist*Math.sin(shiftedAngle)]; 
} 
+0

你先生,是一个传奇!我不知道你是如何解决这个问题的(我想在数学方面很有帮助),但它完美地工作。非常感谢:D – TRG

+0

Ahaha,欢迎您:)。我要更新我的解释,你需要明白,这并不难。 – Kornflexx

+0

@TRG,Kornflexx,我可以提出一点改变/改进建议吗?在计算新的结束之前添加'dist * = Math.cos(shiftedAngle-newAngle);'。这会稍微改变距离,以便在该角度/矢量上,end是最靠近光标的点。 – Thomas