绘制反向圆弧以更改圆心坐标

时间:2018-08-28 11:13:07

标签: javascript svg trigonometry

我正在使用this piece of code绘制弧线,到目前为止效果很好,但是textPath遇到了一个我无法弄清的问题。

请运行以下代码段。

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 largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
    ].join(" ");

    return d;       
}

var correctPath = document.getElementById('correctPath'),
    incorrectPath = document.getElementById('incorrectPath'),
    expectedPath = document.getElementById('expectedPath');
    
correctPath.setAttribute('d', describeArc(24,24,20,0,90));
incorrectPath.setAttribute('d', describeArc(24,24,20,90,0));
expectedPath.setAttribute('d', 'M24 2.75 a 1 1 1 1 1 0 42.8');
.col {width: 32%; float: left; padding: 0.5%}
<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="correctPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="green" font-size="3.2">
      <textPath xlink:href="#correctPath">correct</textPath>
    </text>    
  </svg>
</div>

<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="incorrectPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="red" font-size="3.2">
      <textPath xlink:href="#incorrectPath">incorrect</textPath>
    </text>    
  </svg>
</div>

<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="expectedPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="blue" font-size="3.2">
      <textPath xlink:href="#expectedPath">expected</textPath>
    </text>    
  </svg>
</div>

因此使用

correctPath.setAttribute('d', describeArc(24,24,20,0,90));

它似乎可以完成应做的事情,但是在这种情况下,我需要将文本上下颠倒,因此我尝试将startAngleendAngle颠倒

incorrectPath.setAttribute('d', describeArc(24,24,20,90,0));

您看到的结果是不正确的,它基本上将弧中心坐标重新定位到另一个位置,而不是提供我期望的坐标。

我如何调整这两个函数以能够处理startAngleendAngle的反面以产生预期的结果?

1 个答案:

答案 0 :(得分:1)

arc命令的结构如下:

rx ry x-axis-rotation large-arc-flag sweep-flag x y

最后一个标志sweep-flag描述了圆弧绕圆的方向。如果在极坐标中交换起始角度和终止角度,则也交换方向:endAngle> startAngle表示顺时针,startAngle> endAngle逆时针。您的函数从endAngle到startAngle绘制弧线,因此反之。

一个简单的解决方案是实施此规则:

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 largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
    var sweepFlag = endAngle > startAngle ? 0 : 1; //sic

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y
    ].join(" ");

    return d;       
}

var correctPath = document.getElementById('correctPath'),
    incorrectPath = document.getElementById('incorrectPath'),
    expectedPath = document.getElementById('expectedPath');
    
correctPath.setAttribute('d', describeArc(24,24,20,0,90));
incorrectPath.setAttribute('d', describeArc(24,24,20,90,0));
expectedPath.setAttribute('d', 'M24 2.75 a 1 1 1 1 1 0 42.8');
.col {width: 32%; float: left; padding: 0.5%}
<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="correctPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="green" font-size="3.2">
      <textPath xlink:href="#correctPath">counterclockwise</textPath>
    </text>    
  </svg>
</div>

<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="incorrectPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="red" font-size="3.2">
      <textPath xlink:href="#incorrectPath">clockwise</textPath>
    </text>    
  </svg>
</div>

<div class="col">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <defs>
      <path d="" id="expectedPath"></path>
    </defs>
    <circle r="24" cx="24" cy="24" fill="#eee"></circle>
    <text id="nameText" fill="blue" font-size="3.2">
      <textPath xlink:href="#expectedPath">expected</textPath>
    </text>    
  </svg>
</div>

但是请注意,只要您想真正越过圆弧的终点,该规则就会失效。可以说是顺时针从300度到90度。如果您打算这样做,则必须明确声明它,并将旋转方向作为参数传递给函数。

(无法绘制您的参考路径M24 2.75 a 1 1 1 1 1 0 42.8,并自动将其重写为M 24,2.75 a 21.4,21.4 1 1 1 0 42.8。有关管理此替换的规则,请参见these notes。)