Рисование перевернутой дуги окружности изменяет координаты центра круга - PullRequest
0 голосов
/ 28 августа 2018

Я использую этот кусок кода для рисования дуг, и пока это было здорово, однако я столкнулся с проблемой с 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));

кажется, что он делает то, что должен, но в этом случае мне нужно перевернуть текст вверх дном, поэтому я пытаюсь повернуть startAngle с помощью endAngle

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

и вы видите результат, который неверен, он в основном перемещает координаты центра дуги в другое положение, вместо того, чтобы давать мне координаты, которые я ожидал.

Как я могу настроить эти две функции, чтобы иметь возможность обрабатывать обратную сторону startAngle и endAngle для получения ожидаемого результата?

1 Ответ

0 голосов
/ 28 августа 2018

Команда дуги структурирована так:

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. См. в этих примечаниях для правил, регулирующих эту замену.)

...