Рисование круга с траекторией дуги SVG - PullRequest
134 голосов
/ 21 апреля 2011

Короткий вопрос: используя путь SVG, мы можем нарисовать 99,99% круга, и он появится, но если он равен 99,999999999% круга, то круг не будет отображаться. Как это можно исправить?

Следующий путь SVG может нарисовать 99,99% круга: (попробуйте его на http://jsfiddle.net/DFhUF/1381/ и посмотрите, видите ли вы 4 дуги или только 2 дуги, но обратите внимание, что если это IE, он отображается в VML , не SVG, но есть похожая проблема)

M 100 100 a 50 50 0 1 0 0.00001 0

Но когда это 99,999999999% от круга, тогда вообще ничего не будет отображаться?

M 100 100 a 50 50 0 1 0 0.00000001 0    

То же самое и со 100% круга (это все еще дуга, не так ли, просто очень полная дуга)

M 100 100 a 50 50 0 1 0 0 0 

Как это можно исправить? Причина в том, что я использую функцию, чтобы нарисовать процент дуги, и если мне нужно «особый случай», дуга 99,9999% или 100%, чтобы использовать функцию круга, это было бы глупо.

Опять же, тестовый пример на jsfiddle с использованием RaphaelJS находится на http://jsfiddle.net/DFhUF/1381/
(и если это VML в IE 8, даже второй круг не будет отображаться ... вы должны изменить его на 0,01)


Обновление:

Это потому, что я отрисовываю дугу для оценки в нашей системе, поэтому 3,3 балла получают 1/3 круга. 0,5 получает половину круга, а 9,9 балла - 99% круга. Но что, если в нашей системе есть 9,99 баллов? Нужно ли проверять, находится ли он близко к 99,999% круга, и использовать функцию arc или функцию circle соответственно? Тогда как насчет 9.987? Какой использовать? Смешно знать, какие оценки будут отображаться в «слишком полный круг» и переключаться на функцию круга, а когда это «определенный 99,9%» от круга или 9,9997, тогда использовать функцию дуги .

Ответы [ 12 ]

383 голосов
/ 07 мая 2012

Я знаю, что в игре немного поздно, но я вспомнил этот вопрос с того времени, когда он был новым, и у меня была похожая дилемма, и я случайно нашел «правильное» решение, если кто-то все еще ищет его:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,0 (r * 2),0
    a r,r 0 1,0 -(r * 2),0
    "
/>

Другими словами, это:

<circle cx="100" cy="100" r="75" />

может быть достигнуто как путь с помощью этого:

  <path 
        d="
        M 100, 100
        m -75, 0
        a 75,75 0 1,0 150,0
        a 75,75 0 1,0 -150,0
        "
  />

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

Причина, по которой это невозможно сделать в виде полного круга в одной дуге (и я просторазмышления), потому что вы сказали бы ему нарисовать дугу от себя (скажем, 150 150) к себе (150 150), которую он отображает как «о, я уже там, дуга не нужна!».

Преимущества предлагаемого мною решения:

  1. легко перевести из круга непосредственно в траекторию, и
  2. нет перекрытия в двух линиях дуги (которые могут вызвать проблемы, если вы используете маркеры или шаблоны и т. д.),Это чистая непрерывная линия, хотя и нарисованная из двух частей.

Ничего из этого не имеет значения, если они просто позволят текстовым путям принимать формы.Но я думаю, что они избегают этого решения, так как элементы формы, такие как круг, технически не имеют начальной точки.

jsfiddle demo: http://jsfiddle.net/crazytonyi/mNt2g/

Обновление:

Если вы используете путь для ссылки textPath и хотите, чтобы текст отображался по внешнему краю дуги, вы должны использовать точно такой же метод, но измените флаг развертки с 0 на 1, чтобы он обрабатывалвне пути как поверхности, а не изнутри (представьте себе 1,0 как кого-то, сидящего в центре и рисующего вокруг себя круг, а 1,1 как человека, идущего вокруг центра на расстоянии радиуса и тянущего за собой мел,если это поможет).Вот код, как указано выше, но с изменением:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,1 (r * 2),0
    a r,r 0 1,1 -(r * 2),0
    "
/>
33 голосов
/ 21 апреля 2011

То же самое для дуги XAML. Просто закройте дугу 99,99% с помощью Z, и вы получите круг!

15 голосов
/ 12 января 2015

В отношении решения Энтони, вот функция для получения пути:

function circlePath(cx, cy, r){
    return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0';
}
10 голосов
/ 08 января 2015

Совершенно другой подход:

Вместо того, чтобы возиться с путями для указания дуги в svg, вы также можете взять элемент круга и указать штрих-черту в псевдокоде:

with $score between 0..1, and pi = 3.141592653589793238

$length = $score * 2 * pi * $r
$max = 7 * $r  (i.e. well above 2*pi*r)

<circle r="$r" stroke-dasharray="$length $max" />

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

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

Примечание: Firefox имеет странную ошибку, при которой повороты на 90 градусов и более игнорируются.Таким образом, чтобы начать дугу сверху, используйте:

<circle r="$r" transform="rotate(-89.9)" stroke-dasharray="$length $max" />
5 голосов
/ 21 апреля 2011

Adobe Illustrator использует кривые Безье, такие как SVG, и для кругов создает четыре точки.Вы можете создать круг с помощью двух команд эллиптической дуги ... но тогда для круга в SVG я бы использовал <circle />:)

3 голосов
/ 08 сентября 2012

Хорошей идеей является использование команды двух дуг для рисования полного круга.

Обычно я использую элемент эллипса или круга для рисования полного круга.

2 голосов
/ 30 декабря 2016

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

function(cx, cy, r, deg){
    var theta = deg*Math.PI/180,
        dx = r*Math.cos(theta),
        dy = -r*Math.sin(theta);
    return "M "+cx+" "+cy+"m "+dx+","+dy+"a "+r+","+r+" 0 1,0 "+-2*dx+","+-2*dy+"a "+r+","+r+" 0 1,0 "+2*dx+","+2*dy;
}
2 голосов
/ 01 ноября 2016

Написано как функция, это выглядит так:

function getPath(cx,cy,r){
  return "M" + cx + "," + cy + "m" + (-r) + ",0a" + r + "," + r + " 0 1,0 " + (r * 2) + ",0a" + r + "," + r + " 0 1,0 " + (-r * 2) + ",0";
}
1 голос
/ 27 мая 2018

Эти ответы слишком сложны.

Более простой способ сделать это без создания двух дуг или преобразования в разные системы координат.

Это предполагает, что ваша область холста имеет ширину wи высота h.

`M${w*0.5 + radius},${h*0.5}
 A${radius} ${radius} 0 1 0 ${w*0.5 + radius} ${h*0.5001}`

Просто используйте флаг "длинная дуга", чтобы заполнить полный флаг.Затем сделайте дуги на 99,9999% полным кругом.Визуально это то же самое.Избегайте флага развертки, просто начав окружность с крайней правой точки окружности (один радиус прямо горизонтально от центра).

1 голос
/ 16 мая 2017

Для таких как я, которые искали атрибуты эллипса для преобразования пути:

const ellipseAttrsToPath = (rx,cx,ry,cy) =>
`M${cx-rx},${cy}a${rx},${ry} 0 1,0 ${rx*2},0a${rx},${ry} 0 1,0 -${rx*2},0`
...