【问题标题】:Draw Arc initial point, radius and final point in JavaScript Canvas在 JavaScript Canvas 中绘制 Arc 起点、半径和终点
【发布时间】:2014-11-19 17:18:45
【问题描述】:

我需要画一条弧线,有起点、半径和终点。

我在 JavaScript 中使用 HTML5 画布圆弧函数(x、y、半径、startAngle、endAngle、逆时针)。

context.arc(x, y, 半径, startAngle, endAngle, 逆时针)

有:

var initialPoint = { x: 20, y: 40 };
var radius = 40;
var finalPoint = { x: 180, y: 40 };

预期结果:

请帮忙

【问题讨论】:

  • 如果所需半径为 40,context.arc 将永远不会绘制连接 initialPoint 和 finalPoint 的弧。通过这两个点的弧是 80。请记住 context.arc 将始终绘制部分-circle 使曲线不能“弯曲”以在这两点之间伸展。正如您之前关于此主题的问题所建议的那样......使用context.quadraticCurveTo 在两点之间“弯曲”一条曲线。 ;-)

标签: javascript html canvas html5-canvas


【解决方案1】:

您必须做一些数学运算才能找到与您的 3 个约束条件相匹配的圆心:
• 与初始点相交
• 与 finalPoint 相交
• 已提供半径

请注意,可能没有结果:如果点距离彼此半径的两倍远,则没有圆可以匹配。
如果点距离 两个 结果,我不知道您希望您的用户如何选择。

数学使用了一些属性:
• 圆心位于垂直于 p1、p2 的线上。
• pm,(p1, p2) 的中点也是(c1, c2) 的中点。
• 三角形 (p1, pm, c1) 和 (p1, pm, c2) 在 pm 中具有 90° 角(在法语中称为“三角形矩形”,在英语中称为 donno)。

以下是绿色/红色两种可能弧线的屏幕截图:

http://jsbin.com/jutidigepeta/1/edit?js,output

var initialPoint = { x: 100, y: 160 };
var radius = 90;
var finalPoint = { x: 240, y: 190 };

var centers = findCenters(radius,initialPoint, finalPoint );

核心功能:

//
function findCenters(r, p1, p2) {
  // pm is middle point of (p1, p2)
  var pm = { x : 0.5 * (p1.x + p2.x) , y: 0.5*(p1.y+p2.y) } ;
  drawPoint(pm, 'PM (middle)');
  // compute leading vector of the perpendicular to p1 p2 == C1C2 line
  var perpABdx= - ( p2.y - p1.y );
  var perpABdy = p2.x - p1.x;
  // normalize vector
  var norm = Math.sqrt(sq(perpABdx) + sq(perpABdy));
  perpABdx/=norm;
  perpABdy/=norm;
  // compute distance from pm to p1
  var dpmp1 = Math.sqrt(sq(pm.x-p1.x) + sq(pm.y-p1.y));
  // sin of the angle between { circle center,  middle , p1 } 
  var sin = dpmp1 / r ;
  // is such a circle possible ?
  if (sin<-1 || sin >1) return null; // no, return null
  // yes, compute the two centers
  var cos = Math.sqrt(1-sq(sin));   // build cos out of sin
  var d = r*cos;
  var res1 = { x : pm.x + perpABdx*d, y: pm.y + perpABdy*d };
  var res2 = { x : pm.x - perpABdx*d, y: pm.y - perpABdy*d };
  return { c1 : res1, c2 : res2} ;  
}

实用程序:

function sq(x) { return x*x ; }

function drawPoint(p, name) {
  ctx.fillRect(p.x - 1,p.y - 1,2, 2);
  ctx.textAlign = 'center';
  ctx.fillText(name, p.x, p.y+10);
}

function drawCircle(c, r) {
  ctx.beginPath();
  ctx.arc(c.x, c.y, r, 0, 6.28);
  ctx.strokeStyle='#000';
  ctx.stroke();
}

function drawCircleArc(c, r, p1, p2, col) {
  var ang1 = Math.atan2(p1.y-c.y, p1.x-c.x);
  var ang2 = Math.atan2(p2.y-c.y, p2.x-c.x);
  ctx.beginPath();
  var clockwise = ( ang1 > ang2);
  ctx.arc(c.x, c.y, r, ang1, ang2, clockwise);
  ctx.strokeStyle=col;
  ctx.stroke();
}

编辑:

这里是一个使用'side'的小提琴,一个布尔值,表示我们应该选择弧的哪一侧。

http://jsbin.com/jutidigepeta/3/edit

【讨论】:

  • 不客气。我的伪类是 GameAlchemist,我相信你可以花时间把它全部输入。关于您的问题,如果我猜对了,那就是知道要绘制弧的哪一侧,在这种情况下,您可以 1) 让用户给出第三个点,指示弧应该所在的空间部分。 2) 按照惯例考虑弧应该总是在 p1p2 的左边。 Rq,在这种情况下,(p1, p2) 的顺序很重要。
  • 嗯第二个想法我猜布尔参数左/右是一个更好的选择。输入为 P1,P2,R,侧。只需更改我的代码,在 drawCircleArc 中,var 顺时针 = side;并且只使用 c1,第一个计算的圆心。查看我的编辑。
【解决方案2】:

如果有人正在寻找 SVG 中的等价物(使用 D3.js),请使用 answer from opsb

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

function describeArc(x, y, radius, startAngle, endAngle){
    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);
    var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, arcSweep, 0, end.x, end.y
    ].join(" ");
    return d;       
}

function sq(x) { return x*x ; }

function drawCircleArcSVG(c, r, p1, p2, col) {
  var ang1 = Math.atan2(p1.y-c.y, p1.x-c.x)*180/Math.PI+90;
  var ang2 = Math.atan2(p2.y-c.y, p2.x-c.x)*180/Math.PI+90;
  var clockwise = side;
  var path = describeArc(c.x, c.y, r, ang1, ang2)
  console.log(path)
  svg.append("path").attr("d", path).attr("fill", "none").attr("stroke-width", 3).attr("stroke", col)
}

function drawPointSVG(p, name) {
    svg.append("circle").attr("cx", p.x).attr("cy", p.y).attr("r", 2)
    svg.append("text").attr("x", p.x).attr("y", p.y+10).style("font-size", 10).text(name).style("font-family", "Arial")
}

function drawCircleSVG(c, r) {
    svg.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", r).style("fill", "none").attr("stroke", "#000")
}

工作示例:https://jsbin.com/qawenekesi/edit

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2012-07-08
    • 2018-11-02
    • 1970-01-01
    • 2016-03-07
    • 2017-12-27
    • 2014-11-22
    相关资源
    最近更新 更多