SVG의 호 경로로 원 그리기


146

짧은 질문 : SVG 경로를 사용하면 원의 99.99 %를 그릴 수 있지만 표시되지만 원의 99.99999999 % 인 경우 원이 표시되지 않습니다. 어떻게 고칠 수 있습니까?

다음 SVG 경로는 99.99 %의 원을 그릴 수 있습니다. ( http://jsfiddle.net/DFhUF/1381/에서 시도하고 4 개의 호 또는 2 개의 호만 보이는지 확인하십시오. 그러나 IE 인 경우에는 SVG가 아닌 VML로 렌더링되지만 비슷한 문제가 있음)

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 % 호를 "특별한 경우"해야한다면 어리석은 일입니다.

다시 RaphaelJS를 사용하는 jsfiddle의 테스트 케이스는 http://jsfiddle.net/DFhUF/1381/에 있습니다
(IE 8의 VML 인 경우 두 번째 원조차 표시되지 않습니다 ... 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에서 제대로 작동합니다.
마크 베시

똑같은 링크, 나는 사람들이 테스트 케이스를 더 일찍 보길 원하므로 질문의 시작 부분에 링크를 추가하십시오. 오른쪽 사파리가 얼마나 멋진 일을합니까? 크롬과 파이어 폭스는 ... 이상한 이상한 사파리와 크롬은 모두 웹킷이지만 SVG 엔진은 웹킷에 의존합니까?
nonopolarity

@Marcin은 어떻게 보입니까? 4 호 또는 2 호가 보입니까? 코드를 보았습니까?
nonopolarity

2
Raphael이 라이브러리로 포함 된 업데이트 된 jsfiddle은 raphael.js를로드하는 출처 간 오류를 피할 수 있습니다. jsfiddle.net/DFhUF/1381
ericsoco

답변:


35

XAML의 아크와 동일합니다. a로 99.99 % 호를 닫으면 Z원이 생깁니다!


jsfiddle 샘플에서 세 번째 사례를 닫고 작동시킬 수 있습니까?
nonopolarity

값을 0.0001로 낮추면됩니다. 이 문제는 SVG 자체가 아닌 다양한 브라우저의 WebKit 구현과 관련이 있습니다. 그러나 이것이 SVG / XAMLs Arc 구성 요소에서 원을 만드는 방법입니다.
토드 메인

아, 부정 행위, 항상 최고의 솔루션입니다. 여전히 100 % 사례를 처리해야하지만, 완전히 분리 된 코드 브랜치가 아니라 99.999 %로 "반올림"하면됩니다.
SimonR

어떤 데모? 이 답변은 이행되지 않습니다
Medet Tleukabiluly

@MedetTleukabiluly 당신은 질문에 위의 호를 가지고 z끝에 끝에 추가 하고 완료했습니다. 예를 들어 최신 Chrome에서 0.0001작동하도록 하려면 0을 제거해야 할 수도 있습니다 . 경로 문자열을 넣을 위치를 찾고 있다면 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, 수식 주셔서 감사합니다. 물론 처음 두 명령은 통합 될 수 있습니다.
존 Gietzen

일반적으로 솔루션의 명확성과 실용성을 위해 +1, 특히 '원과 같은 모양 요소에는 기술적으로 "시작"지점이 없습니다 . 문제를 명확하게 표현할 수있는 방법입니다.
David John Welsh

11
여기서 큰 문제는 1 번의 큰 아크 플래그를 제공함으로써 엔진이 더 나아가고 싶다고 명시 적으로 알려주기 때문에 "오, 나는 이미 거기에 있고, 아크가 필요 없다!"라는 문제가 아니라고 생각합니다. 실제 문제는 당신의 요점을 통과하는 제약 조건을 가득 채우는 무한히 많은 원이 있다는 것입니다. 이것은 360 * arc를 원할 때 엔진이 무엇을 해야할지 모르는 이유를 설명합니다. 이 359.999 작동하지 않는 이유는이 수치 불안정 계산이며, 기술적으로 정확하게 요청을 일치 하나 원이 있지만, 그것은 아마 당신이 어쨌든 원하는 일하지 않을 것입니다
qbolec

@qbolec-맞습니다. 큰 아크와 스윕이 꺼져 있고 아크가 목적지가 없다는 측면에서 생각하고있었습니다. 또는 최소한 큰 호와 스윕을 사용하더라도 두 점 사이의 곡선으로 호를 정의하는 기본 설계가있었습니다 (한 점이 두 번 사용되면 축소 된 단일 점으로 보임). 한 점 주위에 360 개의 원을 그릴 수있는 호의 비전은 의미가 있지만, 중심이 정의되면 하나의 원으로 붕괴 될 수 있습니다. 중심이 존재하면 단일 호가 완전한 원을 만들 수 있을까요?
Anthony

1
"원과 같은 모양 요소에는 기술적으로"시작 "지점이 없습니다. 이것은 사실이 아닙니다. SVG 사양은 모든 모양의 시작점이 어디에 있는지 절대적으로 지정합니다. 대시 배열이 모양에서 작동하려면 그렇게해야합니다.
Paul LeBeau

17

Anthony의 솔루션과 관련하여 경로를 얻는 함수는 다음과 같습니다.

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 %까지 채울 수있는 매개 변수를 하나도 가질 수 없다는 것입니다 (내 목표 중
하나임

5

Adobe Illustrator는 SVG와 같은 베 지어 곡선을 사용하며 원의 경우 4 개의 점을 만듭니다. 두 개의 타원형 호 명령 으로 원을 만들 수 있지만 SVG의 원에는 <circle />:)을 사용합니다.


"타원 호 명령 두 개로 원을 만들 수 있습니까?" 무슨 소리 야? 하나만 사용할 수 없습니까? 적어도 (0,0)에서 (0.01, 0)으로 이동하여 무언가를 렌더링합니다. 를 사용 하려면 대신 질문 circle에서 업데이트 를 참조하십시오 .
nonopolarity

아니요, 하나만 사용할 수 있다고 생각하지 않습니다. 할 수 없음을 보여 주었으며 HTML5 Canvas 호에 비슷한 문제가 있습니다.
Phrogz

당신이 사용하는 말은 arc왼쪽 아크 오른쪽 아크를 사용하여 완전한 원을 만드는 방법? 따라서 호는 완전한 원을 그릴 수 없습니다 ... 그렇게하기 위해서는 두 개의 arc경로가 필요합니다
비극성

2
맞습니다. 두 개의 호 경로가 필요합니다 (또는 대부분의 길을가는 원호의 추악한 해킹과 끝까지 직선으로가는 closepath 명령).
Phrogz

1
일러스트 레이터가 짜증 난다. 베 지어 곡선으로 원을 만들 수 없습니다. 원에 가깝지만 여전히 원이 아닙니다.
adius

4

두 개의 호 명령을 사용하여 완전한 원을 그리는 것이 좋습니다.

일반적으로 타원 또는 원 요소를 사용하여 완전한 원을 그립니다.


5
svg의 주요 제한 사항은 모양 요소를 텍스트 경로에 사용할 수 없다는 것입니다. 이것은이 질문을 방문하는 모든 사람들에게 주요 동기가 될 것입니다.
Anthony

1
@ 안토니 그들은 지금 할 수 있습니다. Firefox는 모든 모양에 대해 textPath를 지원합니다. 크롬도 그렇게 생각합니다.
Robert Longson

@RobertLongson-예제를 제공하거나 예제에 대한 링크를 제공 할 수 있습니까? 텍스트 경로가 시작되는 위치와 기존 시작점없이 그려 질 때 텍스트 경로가 외부 또는 내부에 있는지 등을 결정하는 방법이 궁금합니다.
Anthony

@Anthony SVG 2 사양 (예 : w3.org/TR/SVG2/shapes.html#CircleElement )과 새로운 textPath 측면 속성
Robert Longson

4

Anthony와 Anton의 답변을 바탕으로 생성 된 원을 전체 모양에 영향을주지 않고 회전시키는 기능을 통합했습니다. 애니메이션의 경로를 사용하고 있고 애니메이션의 시작 위치를 제어해야하는 경우에 유용합니다.

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

이것이 바로 내가 필요한 것입니다. greensock 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에서 14:17

2

이 답변은 너무 복잡합니다.

두 개의 호를 만들거나 다른 좌표계로 변환하지 않고이 작업을 수행하는 가장 간단한 방법입니다.

이것은 캔버스 영역에 width w와 height 가 있다고 가정합니다 h.

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

"long arc"플래그 만 사용하면 전체 플래그가 채워집니다. 그런 다음 호를 99.9999 %의 완전한 원으로 만듭니다. 시각적으로 동일합니다. 원의 가장 오른쪽에서 원을 시작하여 스윕 플래그를 피하십시오 (중심에서 직접 수평으로 한 반지름).


1

다른 방법은 두 개의 큐빅 베 지어 곡선을 사용하는 것입니다. svg arc 매개 변수를 인식하지 않는 pocketSVG 를 사용하는 iOS 사람들을위한 것 입니다.

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의 입력을 변경하고 콘솔에서 결과를 얻는 것만으로도 충분합니다.


이것은 내가 찾던 것입니다. 가장 좋은 답변은 여기입니다! 이 사람을
찬양하라
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.