Коловий малюнок з дуговим шляхом SVG


146

Коротке запитання: використовуючи шлях SVG, ми можемо намалювати 99,99% кола, і воно з’явиться, але коли це 99,99999999% кола, то коло не з’явиться. Як це можна виправити?

Наступний шлях 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,99999999% кола, то взагалі нічого не покаже?

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,9987? Який використовувати? Смішно потрібно знати, які показники будуть відображати на "занадто повне коло" і переходити на функцію кола, а коли це "певні 99,9%" кола або 9,9987 бал, а потім використовувати функцію дуги .


@minitech звичайно, це працює ... це тоді 99% кола (просто грубо кажучи). Справа в тому, що вона може намалювати 98%, 99%, 99,99% кола, але не 99,9999999% або 100%
неополярність

1
Обидва ці посилання йдуть на одне і те ж, і це прекрасно працює в Safari.
Марк Бессі

правильно, те саме посилання, я просто хочу, щоб люди бачили тестовий випадок раніше, тому я додаю посилання на початку запитання. Правильно, сафарі це зробить, як приємно ... Chrome і Firefox не будуть ... Якийсь дивний cof Safari і Chrome є обома Webkit ... але чи движок SVG залежить від Webkit?
неополярність

@Marcin виглядає чудово, як? ви бачите 4 дуги або 2 дуги? ти навіть дивився на код?
неополярність

2
оновлений jsfiddle з Рафаелем, включеним як бібліотека, щоб подолати помилку перехресного походження завантаження raphael.js: jsfiddle.net/DFhUF/1381
ericsoco

Відповіді:


35

Те саме для дуги XAML. Просто закрийте дугу 99,99% а Zі у вас є коло!


тож чи можете ви закрити третій випадок у зразку jsfiddle і змусити його працювати?
неополярність

зі зниженням значення до 0,0001, так. проблема звучить, пов’язану з різною реалізацією веб-браузера в браузері, а не самому SVG. Але саме так ви складаєте коло в компоненті Arg SVG / XAMLs.
Todd Main

Ах-а, обман, завжди найкраще рішення. Ще потрібно обробити 100-відсотковий випадок, але просто шляхом "округлення" до 99,999%, а не з цілою окремою гілкою коду.
SimonR

Будь-яка демонстрація? Ця відповідь не відповідає
Медет Тлеукабілулі

@MedetTleukabiluly у вас є дуга вище у питанні, додайте а zв кінці і зробіть . Можливо, вам доведеться видалити нулі, наприклад, в останньому Chrome я повинен був написати, 0.0001щоб він працював. Якщо ви шукаєте, куди слід поставити рядок шляху, подивіться на Шляхи на MDN .
TWiStErRob

415

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

<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: 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
    "
/>

1
+1, спасибі за формули. Звичайно, перші дві команди можна було б об'єднати.
Джон Гітцен

+1 для чіткості та практичності рішення в цілому, але особливо для "елементів форми, таких як коло, технічно не мають" початкової "точки" - такий чіткий спосіб висловити проблему.
Девід Джон Уельс

11
Я думаю, що проблема тут не в тому, що "о, я вже там, дуга не потрібна!", А надаючи 1 як великий-дуга-прапор, ви чітко говорите двигуну, що ви хочете, щоб він пішов далі. Справжня проблема полягає в тому, що існує нескінченно багато кіл, які повною мірою обмежують проходження вашої точки. Це пояснює, чому коли ви хочете дугу 360 *, тоді двигун не знає, що робити. Причина, за якої це не працює для 359.999, полягає в тому, що це чисельно нестабільне обчислення, і хоча технічно існує саме одне коло, яке відповідає запиту, воно, мабуть, не буде таким, якого ви хотіли в будь-якому випадку
qbolec

@qbolec - Ти маєш рацію, я думав з точки зору великої дуги і розгортки, а дуга не мала призначення. Або принаймні, що навіть при великій дузі та розгортці було передбачено, що існує якась фундаментальна конструкція, яка визначає дугу як криву між двома точками (щоб одна точка, яка використовується двічі, бачила її як єдину крапку). бачення дуги, яка потенційно малює 360 кіл навколо однієї точки, має сенс, хоч вона обвалиться на одне коло, якщо визначено центр, що постає питання, чи могла б одна дуга зробити повне коло, якби центр існував?
Антоній

1
"елементи форми, такі як коло, технічно не мають" початкової "точки". Це насправді не так. Специфікація SVG абсолютно вказує, де починається точка всіх форм. Це потрібно зробити для того, щоб масиви тире працювали на фігурах.
Пол ЛеБо

17

Посилаючись на рішення Ентоні, ось функція отримати шлях:

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

Зовсім інший підхід:

Замість того, щоб сповзати з шляхами, щоб вказати дугу у 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" />

майте на увазі, що це рішення застосовується лише у випадках, коли ви не використовуєте будь-який тип заливки і вам потрібен лише сегмент дуги без відхилень. У той момент, коли ви хочете намалювати сектори, вам навіть потрібен новий вузол шляху SVG, який в іншому випадку можна обробляти в одному тезі контуру.
mxfh

@mxfh не дуже, якщо взяти штрих-ширину вдвічі більше значення r, ви отримаєте ідеальні сектори.
mvds

З stroke-dasharray="0 10cm 5cm 1000cm"ним можна уникнути перетворення
stenci

@stenci так, але недоліком є ​​те, що ви не можете мати один параметр у дашаррі для масштабування від 0% до 100% заповнення (що було однією з моїх цілей)
mvds

5

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


"Ви можете створити коло за допомогою двох еліптичних команд дуги"? Що ви маєте на увазі? Ви не можете просто використовувати його? Принаймні, зробивши перехід від (0,0) до (0,01, 0), щоб він щось робив. Для використання circleдив. Оновлення замість цього питання.
неополярність

Ні, я не думаю, що ти можеш використовувати лише один. Ви показали, що не можете, і у вас є аналогічна проблема з дугами полотна HTML5.
Фрогз

ви маєте на увазі, використовуючи arcдля створення повного кола за допомогою лівої дуги та правої дуги? Отже, дуга не може намалювати повне коло ... для цього arcпотрібні два шляхи
неополярність

2
@ 動靜 能量 Правильно, потрібні два шляхи дуги (або некрасивий злом однієї дуги, який проходить більшу частину шляху, а потім команда близького шляху до прямої лінії до кінця).
Фрогз

1
Ілюстратор смокче. Ви не можете зробити коло з кривими Безьє. Тільки щось близьке до кола, але все ж не коло.
adius

4

Добре, що за допомогою двох дугових команд намалювати повне коло.

Зазвичай я використовую елемент еліпса або кола, щоб намалювати повне коло.


5
Основним обмеженням svg є те, що елементи фігури не можна використовувати для текстових шляхів. Це, мабуть, головна мотивація для всіх, хто відвідує це питання.
Антоній

1
@Anthony вони можуть зараз. Firefox підтримує textPath проти будь-якої форми. Я підозрюю, що Chrome теж робить.
Роберт Лонгсон

@RobertLongson - Чи можете ви навести приклад або посилання на приклад? Цікаво, як він визначає, звідки починається шлях тексту та чи знаходиться він зовні або всередині (тощо), коли він намальований без традиційної початкової точки.
Ентоні

@Anthony Дивіться специфікацію SVG 2, наприклад w3.org/TR/SVG2/shapes.html#CircleElement , також новий атрибут
textPath

4

Спираючись на відповіді Ентоні та Антона, я включив можливість обертати створене коло, не впливаючи на загальний вигляд. Це корисно, якщо ви використовуєте шлях для анімації і вам потрібно контролювати, де вона починається.

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;
}

Це саме те, що мені було потрібно. Я використовував плагін morsock morph, щоб перетворити кругову доріжку на прямокутну стежку і мені знадобилося невелике обертання, щоб воно виглядало як раз.
RoboKozo

3

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

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`

2

Написана як функція, це виглядає приблизно так:

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";
}

2
Це чудова відповідь! Лише невелике доповнення: Цей шлях промальований Схід, Північ, Захід, Південь. Якщо ви хочете, щоб коло поводитися так само , як <circle>ви повинні змінити напрямок на схід, південь, захід, північ: "M" + cx + "," + cy + "m" + (r) + ",0" + "a" + r + "," + r + " 0 1,1 " + (-r * 2) + ",0" + "a" + r + "," + r + " 0 1,1 " + (r * 2) + ",0" Перевага полягає в тому, що stroke-dashoffsetі в startOffsetданий час працює таким же чином.
loominade

2

Ці відповіді є занадто складними.

Простіший спосіб зробити це без створення двох дуг або перетворення в різні системи координат ..

Це передбачає, що ваша область полотна має ширину 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

Іншим способом було б використання двох кубічних кривих Безьє. Це для iOS людей, які використовують кишеньковийSVG який не розпізнає параметр svg дуги.

C x1 y1, x2 y2, xy (або c dx1 dy1, dx2 dy2, dx dy)

Кубічна крива Безьє

Останній набір координат тут (x, y) - це місце, де потрібно закінчити рядок. Інші два - контрольні пункти. (x1, y1) - контрольна точка для початку вашої кривої, а (x2, y2) - кінцева точка вашої кривої.

<path d="M25,0 C60,0, 60,50, 25,50 C-10,50, -10,0, 25,0" />

1

я зробив jsfiddle, щоб зробити це тут:

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;       
}
console.log(describeArc(255,255,220,134,136))

посилання

все, що вам потрібно зробити, це змінити вхід console.log і отримати результат у консолі


Це саме те, що я шукав. Найкраща відповідь тут! підняти цей хлопець
Måns Dahlström
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.