好吧,我会称自己是一位非常优秀的程序员,从未真正遵循学术方式。因此,我的数学知识相当有限,这对我有时需要完成的事情来说是一个小负担。我知道你们中的一些人都非常聪明,喜欢计算这个(对你来说很容易)的事情:
我需要为客户实现一些图表和图表。我选择了OCanvas作为绘图库。它真的有帮助,我需要做的一切都很好,但有一点需要注意。
我有两个圆圈,并且可以通过对象OCanvas为我创建一个函数,在圆圈1的中心和圆圈2的中心之间画一条线。现在我想在线条上添加三角形它是一个箭头。
我知道我需要计算线的倾斜度,以正确对齐三角形。我还需要计算圆边和线之间的交点位置,以定位三角形。
我会为你提供一些代码,但老实说,我不知道如何计算这个。我的已知值包括:行 startX , startY , endX , endY 以及圈子1 X , Y 和半径 /圈2 X , Y 和 radius (X和Y代表圆圈的中心)
提前致谢!
编辑:
视觉表示,需要红色三角形:
答案 0 :(得分:2)
不完整但可能会给你一个良好的开端。
let c = document.getElementById("myCanvas"),
ctx = c.getContext("2d"),
startX = 50,
startY = 50,
endX = 250,
endY = 150,
rS = 30,
rE = 50,
alpha = Math.atan((startY - endY) / (startX - endX)),
dir = 0, // start 0 end 1
side = 10;
ctx.beginPath();
ctx.arc(startX, startY, rS, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(endX, endY, rE, 0, 2 * Math.PI);
ctx.stroke();
if (startX < endX) {
endcx = endX + (rE + side/2) * Math.cos(alpha + Math.PI);
endcy = endY + (rE + side/2) * Math.sin(alpha + Math.PI);
startcx = startX - (rS + side/2) * Math.cos(alpha - Math.PI);
startcy = startY - (rS + side/2) * Math.sin(alpha - Math.PI);
dir = 0;
} else if (startX >= endX) {
endcx = endX - (rE + side/2) * Math.cos(alpha + Math.PI);
endcy = endY - (rE + side/2) * Math.sin(alpha + Math.PI);
startcx = startX + (rS + side/2) * Math.cos(alpha - Math.PI);
startcy = startY + (rS + side/2) * Math.sin(alpha - Math.PI);
dir = 1;
}
ctx.beginPath();
ctx.moveTo(startcx, startcy);
ctx.lineTo(endcx, endcy);
ctx.lineWidth=3;
ctx.stroke();
drawEqTriangle(ctx, side, startcx, startcy, dir?0:1);
drawEqTriangle(ctx, side, endcx, endcy, dir);
function drawEqTriangle(ctx, side, cx, cy, dir) {
var h = side * (Math.sqrt(3) / 2);
ctx.save();
ctx.strokeStyle = "#000";
ctx.fillStyle = "#000";
ctx.translate(cx, cy);
ctx.rotate(alpha + Math.PI / 2);
ctx.beginPath();
ctx.lineWidth=1;
if (dir === 0) {
ctx.moveTo(0, -h / 2);
ctx.lineTo(-side / 2, h / 2);
ctx.lineTo(side / 2, h / 2);
ctx.lineTo(0, -h / 2);
} else if (dir === 1) {
ctx.moveTo(0, h / 2);
ctx.lineTo(-side / 2, -h / 2);
ctx.lineTo(side / 2, -h / 2);
ctx.lineTo(0, h / 2);
}
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.restore();
}
&#13;
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="400" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
</html>
&#13;
答案 1 :(得分:1)
要获得三角形的倾斜角度,您需要以下内容:
假设(x1,y1)
是该行开头的坐标,而(x2,y2)
是该行结尾的坐标,并且您想在该行的末尾绘制三角形:
alpha = arctan((y2-y2) / (x2-x1))
然后您需要创建以该角度(alpha)倾斜的三角形。
另一个三角形是alpha + 180 degrees
或alpha - 180 degrees
(产生相同的)。
答案 2 :(得分:1)
尝试帮助您解决问题:
编辑:
通过整合@bluehipy答案,也许这会更接近
//Objects
Circle = function(oX, oY, r){
this.oX = oX;
this.oY = oY;
this.r = r;
context.beginPath();
context.arc(oX, oY, r, 0, 2 * Math.PI, false);
context.fillStyle = 'red';
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#003300';
context.stroke();
}
//Functions
drawArrowFromCirclesOrigins = function(side,c1, c2){
context.beginPath();
//line
context.moveTo(c1.oX, c1.oY);
context.lineTo(c2.oX, c2.oY);
context.stroke();
//triangle
var alpha = Math.tan((c2.oY-c1.oY) / (c2.oX-c1.oX));
var h = side * (Math.sqrt(3) / 2);
context.translate(c2.oX/alpha+c2.r-(-(side/2)), c2.oY/alpha+c2.r-(-(side/2)));
context.rotate(alpha + Math.PI / 2);
context.beginPath();
context.moveTo(0, -h / 2);
context.lineTo(-side / 2, h / 2);
context.lineTo(side / 2, h / 2);
context.lineTo(0, -h / 2);
context.fillStyle = 'green';
context.fill();
context.stroke();
}
//Variables
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
//Program
var cir1 = new Circle(20, 20, 10);
var cir2 = new Circle(40, 40, 10);
drawArrowFromCirclesOrigins(-11,cir1, cir2);
canvas {
border: 2px solid black;
}
<canvas id="canvas" width="200" height="100"></canvas>
答案 3 :(得分:1)
如果你使用的是纯帆布,那就不那么繁琐了。
首先是两个圈子
const circle1 = {
x : ?,
y : ?,
r : ?, // Radius
lineWidth : ?,
}
const circle2 = {
x : ?,
y : ?,
r : ?,
lineWidth : ?,
}
然后是箭头描述
const arrow = {
width : ?,
depth : ?, // tip to back of arrow head
}
数学。
从circle1到circle2获取矢量
var vx = circle2.x - circle1.x;
var vy = circle2.y - circle1.y;
他们之间的距离
var dist = Math.sqrt(vx * vx + vy * vy);
现在需要通过将矢量除以长度来标准化矢量。这使得向量长一个单位
vx /= dist;
vy /= dist;
现在你可以渲染箭头了。尖端是圆2的边缘。要找到该点,从距离
减去半径和线宽的一半const aDist = dist - (circle2.r + circle2.lineWidth / 2);
标准化矢量可以乘以距离来找到位置,或者如果使用画布2D API,则使用法线来设置变换,然后它全部与x轴对齐。
ctx.beginPath(); // drawing the arrow head
ctx.lineTo(circle1.x + vx * aDist, circle1.y + vy * aDist); // tip of arrow
我们需要从尖端向后移动并从90度的线向外移动才能执行此操作,您可以通过交换x,y部分并取消新x来旋转90度的矢量。
ctx.lineTo(
circle1.x + vx * (aDist - arrow.depth) - vy * arrow.width,
circle1.y + vy * (aDist - arrow.depth) + vx * arrow.width
// ^------- along line -----^ ^--Out from line--^
);
// and the other side
ctx.lineTo(
circle1.x + vx * (aDist - arrow.depth) + vy * arrow.width,
circle1.y + vy * (aDist - arrow.depth) - vx * arrow.width
// ^------- along line -----^ ^--Out from line--^
);
// ctx.closePath();
ctx.fill();
或者如果您使用转换
ctx.setTransform(vx,vy,-vy,vx,circle1.x,circle1.y); // set the circle1 as origin
// and use the normal to
// align the x axis
ctx.beginPath(); // drawing the arrow head
ctx.lineTo(aDist,0); // tip of arrow
ctx.lineTo(aDist - arrow.depth, arrow.width);
ctx.lineTo(aDist - arrow.depth, -arrow.width);
// ctx.closePath();
ctx.fill();
ctx.setTransform(1,0,0,1,0,0); // restore default transform.
const ctx = canvas.getContext("2d");
const circle1 = {
x : 50,
y : 100,
r : 45, // Radius
lineWidth : 3,
}
const circle2 = {
x : 250,
y : 50,
r : 45,
lineWidth : 3,
}
const arrow = {
width : 10,
depth : 20, // tip to back of arrow head
}
var vx = circle2.x - circle1.x;
var vy = circle2.y - circle1.y;
var dist = Math.sqrt(vx * vx + vy * vy);
vx /= dist;
vy /= dist;
const aDist = dist - (circle2.r + circle2.lineWidth / 2);
ctx.lineWidth = circle1.lineWidth;
ctx.beginPath();
ctx.arc(circle1.x, circle1.y, circle1.r, 0, 2 * Math.PI);
ctx.moveTo(circle2.x + circle2.r, circle2.y);
ctx.arc(circle2.x, circle2.y, circle2.r, 0, 2 * Math.PI);
ctx.moveTo(circle1.x, circle1.y);
ctx.lineTo(circle2.x, circle2.y);
ctx.stroke();
ctx.beginPath(); // drawing the arrow head
ctx.lineTo(circle1.x + vx * aDist, circle1.y + vy * aDist); // tip of arrow
ctx.lineTo(
circle1.x + vx * (aDist - arrow.depth) - vy * arrow.width,
circle1.y + vy * (aDist - arrow.depth) + vx * arrow.width
// ^------- along line -----^ ^--Out from line--^
);
// and the other side
ctx.lineTo(
circle1.x + vx * (aDist - arrow.depth) + vy * arrow.width,
circle1.y + vy * (aDist - arrow.depth) - vx * arrow.width
// ^------- along line -----^ ^--Out from line--^
);
// ctx.closePath();
ctx.fill();
canvas { border : 2px solid black; }
const ctx = canvas.getContext("2d");
<canvas id="canvas"></canvas>
setTransform
这使用setTransform来减少数学量。此示例也使用线宽但箭头指向圆
const ctx = canvas.getContext("2d");
const circle1 = {
x : 50,
y : 100,
r : 45, // Radius
lineWidth : 3,
}
const circle2 = {
x : 250,
y : 50,
r : 45,
lineWidth : 3,
}
const arrow = {
width : 10,
depth : 20, // tip to back of arrow head
}
var vx = circle2.x - circle1.x;
var vy = circle2.y - circle1.y;
var dist = Math.sqrt(vx * vx + vy * vy);
vx /= dist;
vy /= dist;
const aDist = dist - (circle2.r + circle2.lineWidth / 2);
ctx.lineWidth = circle1.lineWidth;
ctx.beginPath();
ctx.arc(circle1.x, circle1.y, circle1.r, 0, 2 * Math.PI);
ctx.moveTo(circle2.x + circle2.r, circle2.y);
ctx.arc(circle2.x, circle2.y, circle2.r, 0, 2 * Math.PI);
ctx.moveTo(circle1.x, circle1.y);
ctx.lineTo(circle2.x, circle2.y);
ctx.stroke();
ctx.beginPath(); // drawing the arrow head
ctx.setTransform(vx, vy, -vy, vx, circle1.x, circle1.y); // set the circle1 as origin
// and use the normal to
// align the x axis
ctx.beginPath(); // drawing the arrow head
ctx.lineTo(aDist,-circle1.lineWidth/2); // tip of arrow circle1.linewidth is same for line between circles
ctx.lineTo(aDist,circle1.lineWidth/2); // tip of arrow circle1.linewidth is same for line between circles
ctx.lineTo(aDist - arrow.depth, arrow.width + circle1.lineWidth/2);
ctx.lineTo(aDist - arrow.depth, -arrow.width - circle1.lineWidth/2);
// ctx.closePath();
ctx.fill();
ctx.setTransform(1,0,0,1,0,0); // restore default transform.
ctx.fill();
canvas { border : 2px solid black; }
const ctx = canvas.getContext("2d");
<canvas id="canvas"></canvas>
答案 4 :(得分:0)
你可以用来简化事情的另一个想法(也许是上面实现的@ Blindman67但我不理解它)就是这样想:
无论在哪里放置圆圈,您都可以旋转上下文,使其中心位于水平或垂直(如果您愿意),这样所有兴趣点都位于单个坐标上,即线性。画出你需要的东西然后再旋转上下文。