SVG 원을 경로로 분해
게시 됨: 2022-03-10이 기사는 고백으로 시작합니다. 나는 SVG를 손으로 코딩하는 것을 좋아합니다. 항상 그런 것은 아니지만 종종 나와 같은 취향을 공유하지 않는 사람들에게는 독특하게 보일 수 있습니다. 도구가 할 수 없는 방식으로 SVG를 최적화(경로를 더 단순한 경로 또는 모양으로 전환)하거나 D3 또는 Greensock과 같은 라이브러리가 작동하는 방식을 단순히 이해하는 것과 같이 SVG를 손으로 작성할 수 있으면 많은 이점이 있습니다. .
즉, SVG의 원형 모양과 기본 원을 지나 이동할 때 원형 모양으로 할 수 있는 작업에 대해 더 자세히 살펴보고 싶습니다. 왜 서클인가? 글쎄요, 저는 서클을 좋아합니다. 그들은 내가 가장 좋아하는 모양입니다.
먼저(이전에 SVG에서 기본 원을 본 적이 있기를 바랍니다.) 다음은 하나를 보여주는 펜입니다.
원으로 많은 작업을 수행할 수 있습니다. 애니메이션을 적용할 수 있고 다른 색상을 적용할 수 있습니다. 여전히 SVG 1.1에서 원이 할 수 없는 두 가지 아주 좋은 일이 있습니다. 다른 그래픽 요소가 원의 경로를 따라 움직이게 할 수 없고( animateMotion
요소를 사용하여) 원의 경로를 따라 텍스트 모양을 만들 수 없습니다(이렇게 하면 SVG 2.0이 출시된 후에만 허용됨).
우리의 원을 경로로 바꾸기
원에서 경로를 만드는 데 도움이 되는 약간의 온라인 도구가 있지만(여기에서 시도해 볼 수 있음), 우리는 모든 것을 처음부터 새로 만들 것이므로 실제로 이면에서 무슨 일이 일어나고 있는지 알아낼 것입니다.
원형 경로를 만들기 위해 실제로 두 개의 호, 즉 한 경로에서 원을 완성하는 반원을 만들 것입니다. 위의 SVG에서 눈치채셨겠지만 CX
, CY
및 R
속성은 각각 X 및 Y 축을 따라 원이 그려지는 위치를 정의하고 R
은 원의 반경을 정의합니다. CX
와 CY
는 원의 중심을 생성하므로 그 점을 중심으로 원이 그려집니다.
해당 원을 복제하면 다음과 같을 수 있습니다.
<path d=" M (CX - R), CY a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 " />
CX
는 원의 cx
속성과 동일합니다. CY
와 원의 cy
속성, 원의 R
과 r
속성도 마찬가지입니다. a
문자는 타원형 호의 세그먼트를 정의하는 데 사용됩니다. 선택적 Z
(또는 z
)를 사용하여 경로를 닫을 수 있습니다.
소문자 a
는 현재 위치에 상대적으로 그려진 타원 호의 시작을 나타냅니다. 특정 경우에는 다음과 같습니다.
<path d=" M 25, 50 a 25,25 0 1,1 50,0 a 25,25 0 1,1 -50,0 " />
이 펜에서 일어나는 마술을 볼 수 있습니다.
경로 아래에 빨간색 채우기가 있는 원이 숨겨져 있습니다. 경로 값을 가지고 놀면 경로가 원을 완전히 덮는 한 해당 원이 표시되며(경로 자체는 동일한 크기의 원임) 작업을 올바르게 수행하고 있음을 알 수 있습니다. .
또한 알아야 할 한 가지는 상대 호를 그리는 한 그리는 각 호에 a
명령을 반복할 필요가 없다는 것입니다. 호에 대해 처음 7개 입력이 완료되면 다음 호에 대해 두 번째 7개 입력이 사용됩니다.
경로에서 두 번째 a
를 제거하여 위의 펜으로 이것을 시도할 수 있습니다.
a 25,25 0 1,1 50,0 25,25 0 1,1 -50,0
이것은 같아 보일 수 있지만 그림을 마칠 준비가 될 때까지 그대로 두는 것을 선호하며 이는 또한 내가 어디에 있는지 추적하는 데 도움이 됩니다.
이 경로의 작동 방식
먼저 이미지에서 절대 위치에 있는 X,Y
좌표로 이동합니다. 거기에는 아무 것도 그리지 않고 그냥 거기로 이동합니다. 원 요소 CX
의 경우 CY
는 원의 중심을 나타냅니다. 그러나 타원형 호에서 발생하는 것처럼 호의 실제 CX
및 CY
는 해당 호의 다른 속성에서 계산됩니다.
다시 말해, CX
가 50
이고 반경이 25
인 경우 50 - 25
로 이동해야 합니다(물론 왼쪽에서 오른쪽으로 그리는 경우). 이것은 첫 번째 호가 25 X, 50 Y
에서 그려지고 첫 번째 호가 25,25 0 1,0 50,0
이 된다는 것을 의미합니다.
호의 값 25,25 0 1,0 50,0
이 실제로 의미하는 바를 분석해 보겠습니다.
-
25
: 호의 상대 X 반경; -
25
: 호의 상대 Y 반경; -
0 1,0
: 세 가지 중간 값(rotation, large-arc-flag 및 sweep-flag 속성)에 대해 이야기하지 않겠습니다. 두 호에 대해 동일합니다. -
50
: 호의 끝 X 좌표(상대); -
0
: 호의 끝 Y 좌표(상대).
두 번째 호는 25,25 0 1,0 -50,0
입니다. 이 호는 마지막 호가 그리기를 멈춘 곳에서 그리기 시작한다는 점을 염두에 두십시오. 물론 X, Y 반경은 같지만( 25
) 끝 X 좌표는 현재 좌표가 있는 곳의 -50
입니다.
분명히 이 원은 다양한 방법으로 그려질 수 있습니다. 원을 경로로 바꾸는 이 과정을 분해라고 합니다. SVG 2 사양에서 원의 분해는 4개의 호로 수행되지만 권장하는 방법은 아직 지정되지 않은 세그먼트 완성 닫기 경로라는 기능에 현재 종속되어 있으므로 아직 사용할 수 없습니다.
다양한 방법으로 원을 그릴 수 있음을 보여드리기 위해 다양한 예를 들어 작은 펜을 준비했습니다.
자세히 살펴보면 원 위에 경로를 그리는 방법에 대한 다섯 가지 다른 예와 함께 원래 원을 볼 수 있습니다. 각 경로에는 CX
, CY
및 R
값을 사용하여 원을 작성하는 방법을 설명하는 자식 desc
요소가 있습니다. 첫 번째 예는 여기에서 논의한 것이고 나머지 세 개는 코드를 읽을 때 이해할 수 있는 변형을 사용합니다. 마지막 예제에서는 위에 링크된 SVG 2 사양에 설명된 프로세스를 어느 정도 복제하여 2개가 아닌 4개의 반원 호를 사용합니다.
마크업에서 나중에 오는 요소를 이전에 오는 요소 위에 배치하는 SVG의 자연스러운 z-인덱싱을 사용하여 원을 서로의 위에 겹칩니다.
펜에서 원형 경로를 클릭하면 첫 번째 클릭은 경로가 콘솔에 어떻게 구성되어 있는지 인쇄하고 요소에 클래스를 추가하여 원이 그려지는 방식의 획 색상을 볼 수 있습니다(아래에서 볼 수 있음) 첫 번째 원이 스트로크의 시작 쐐기로 그려집니다). 두 번째 클릭은 원이 제거되므로 아래의 원과 상호 작용할 수 있습니다.
각 원에는 다른 채우기 색상이 있습니다. 실제 circle 요소는 노란색이며 클릭할 때마다 콘솔에 "You clicked on the circle"이라고 표시됩니다. 물론 desc
요소가 매우 간단하기 때문에 단순히 코드를 읽을 수도 있습니다.
경로에서 원으로 이동
원을 그리는 방법에는 여러 가지가 있지만 사용된 경로는 여전히 매우 유사해 보입니다. 특히 그리기 프로그램의 SVG 출력에서 원은 경로로 표시되는 경우가 많습니다. 이것은 아마도 그래픽 프로그램 코드의 최적화 때문일 것입니다. 경로를 그리는 코드가 있으면 무엇이든 그릴 수 있으므로 그냥 사용하십시오. 이것은 추론하기 어려운 다소 팽창된 SVG로 이어질 수 있습니다.
추천 자료 : Sara Soueidan의 "더 나은 웹용 SVG 생성 및 내보내기를 위한 팁"
Wikipedia의 다음 SVG를 예로 들어 보겠습니다. 해당 파일의 코드를 보면 Jake Archibald의 SVGOMG! (여기에서 자세히 읽을 수 있음) 다음 파일과 같이 상당히 최적화되었지만 문서의 원이 여전히 경로로 렌더링됩니다.
따라서 경로가 어떻게 작동하는지 알고 있는 경우 해당 원이 실제 원 요소인 경우 해당 원이 무엇인지 알아낼 수 있는지 봅시다. 문서의 첫 번째 경로는 분명히 원이 아닌 반면 다음 두 경로는 ( d
속성만 표시):
M39 20a19 19 0 1 1-38 0 19 19 0 1 1 38 0z
M25 20a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
따라서 두 번째 a
를 생략할 수 있음을 기억하고 이를 좀 더 이해하기 쉽게 다시 작성해 보겠습니다. (첫 번째 경로는 큰 원입니다.)
M39 20 a19 19 0 1 1-38 0 a19 19 0 1 1 38 0z
그 호는 분명히 다음과 같습니다.
aR R 0 1 1 - (R * 2) 0 aR R 0 1 1 (R * 2) 0
이것은 우리의 원 반경이 19
라는 것을 의미하지만 CX
및 CY
값은 무엇입니까? 우리 M39
가 실제로 CX + R
이라고 생각합니다. 즉, CX
는 20
이고 CY
도 20
입니다.
다음과 같이 모든 경로 뒤에 원을 추가한다고 가정해 보겠습니다.
<circle fill="none" stroke-width="1.99975" stroke="red" r="19" cx="20" cy="20" />
그것이 정확하고 빨간색 선이 그어진 원이 큰 원을 정확히 덮고 있음을 알 수 있습니다. 재구성된 두 번째 원 경로는 다음과 같습니다.
M25 20 a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
분명히 반지름은 5
이고 CX
및 CY
값은 이전과 동일합니다. - 20
.
참고 : CX = 20
이면 CX + R = 25
입니다. 원은 중앙의 더 큰 원 안에 있으므로 분명히 동일한 CX
및 CY
값을 가져야 합니다.
경로 끝에 다음 원을 추가합니다.
<circle fill="yellow" r="5" cx="20" cy="20" />
이제 다음 펜을 보면 이것이 정확하다는 것을 알 수 있습니다.
이제 원이 무엇인지 알았으므로 불필요한 경로를 제거하고 실제로 원을 만들 수 있습니다. 여기에서 볼 수 있습니다.
텍스트 줄 바꿈을 위한 원형 경로 사용
이제 경로에 원이 있으므로 해당 경로에서 텍스트를 줄 바꿈할 수 있습니다. 아래는 이전 "All Circles" 펜과 경로가 같지만 경로에 텍스트가 래핑된 펜입니다. 경로를 클릭할 때마다 해당 경로가 삭제되고 텍스트는 다음과 같이 사용 가능한 다음 경로로 줄바꿈됩니다.
다른 경로를 보면 각각의 경로 사이에 작은 차이가 있음을 알 수 있지만(좀 더 자세히 설명), 먼저 약간의 브라우저 간 비호환성을 확인할 수 있습니다. 특히 첫 번째 경로에서 두드러집니다.
파이어폭스 개발자 | |
크롬 | |
마이크로소프트 엣지 |
"Smashing"의 시작 "S"가 Firefox 솔루션에서 재미있는 각도에 있는 이유는 (사용한 vR 명령으로 인해) 실제로 경로를 그리기 시작한 곳이기 때문입니다. 이것은 우리가 그린 원의 첫 번째 파이 모양의 쐐기를 명확하게 볼 수 있는 Chrome 버전에서 더 분명합니다.
크롬은 모든 쐐기를 따르지 않으므로 텍스트를 "Smashing Magazine"으로 변경한 결과입니다. |
그 이유는 Chrome에 부모 text
요소에 선언된 textLength
속성의 상속과 관련된 버그가 있기 때문입니다. 둘 다 동일하게 보이도록 하려면 텍스트뿐만 아니라 textPath
요소에 textLength
속성을 추가하십시오. 왜요? textLength
속성이 text
요소에 지정되지 않은 경우 Firefox 개발자가 동일한 버그를 갖고 있는 것으로 나타났기 때문입니다(이것은 현재 몇 년 동안 그랬습니다).
Microsoft Edge에는 완전히 다른 버그가 있습니다. Text
와 자식 TextPath
요소 사이의 공백을 처리할 수 없습니다. 공백을 제거하고 text
및 textPath
요소 모두에 textLength
속성을 넣으면 모두 상대적으로 동일하게 보일 것입니다(기본 글꼴 등의 차이로 인한 약간의 변형만 있음). 따라서 세 가지 다른 브라우저에서 세 가지 다른 버그가 있습니다. 이것이 사람들이 종종 라이브러리 작업을 선호하는 이유입니다!
다음 펜은 문제를 해결할 수 있는 방법을 보여줍니다.
또한 텍스트 줄 바꿈을 더 쉽게 볼 수 있도록 다양한 채우기 색상을 제거했습니다. 채우기 색상을 제거한다는 것은 내가 pointer-events="all"
속성을 추가하지 않는 한 경로를 순환하고 모양을 볼 수 있도록 하는 작은 기능이 작동하지 않는다는 것을 의미하므로 저도 추가했습니다.
참고 : Tiffany B. Brown이 설명한 "포인터 이벤트 속성과 SVG 상호 작용 관리"에서 그 이유에 대해 자세히 읽을 수 있습니다.
우리는 이미 multiarc 경로의 래핑에 대해 논의했으므로 이제 다른 경로를 살펴보겠습니다. 우리가 감싸는 경로가 하나 있기 때문에 텍스트는 항상 같은 방향으로 이동합니다.
영상 | 길 | 설명 |
---|---|---|
M CX, CY a R, R 0 1,0 -(R * 2), 0 a R, R 0 1,0 R * 2, 0 translate 기능을 사용하여 X축에서 +R 을 이동합니다. | textPath 의 시작 위치(어떤 식으로든 지정하지 않았기 때문에)는 호 자체의 반경이 주어지면 첫 번째 끝 호 -(R * 2) 에 의해 결정됩니다. | |
M (CX + R), CY a R,R 0 1,0 -(R * 2),0 a R,R 0 1,0 (R * 2),0 | 이전 경로와 동일하게 적용됩니다. | |
M CX CY m -R, 0 a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 | 첫 번째 호에서 (R * 2 ) 에서 끝나기 때문에 분명히 반대 위치에서 시작할 것입니다. 즉, 이것은 이전 두 경로가 끝난 곳에서 시작됩니다. | |
M (CX - R), CY a R,R 0 1, 1 (R * 2),0 a R,R 0 1, 1 -(R * 2),0 | 이것은 (R * 2) 로 인해 마지막 위치와 같은 위치에서 시작하지만, 스윕 플래그 속성(노란색으로 표시)을 1 로 설정했기 때문에 시계 방향으로 실행됩니다. |
원의 단일 경로에서 텍스트를 래핑하는 방법을 살펴보았습니다. 이제 그 경로를 두 가지 경로로 나눌 수 있는 방법과 이를 통해 얻을 수 있는 이점을 살펴보겠습니다.
우리의 길을 부분으로 나누기
경로에 있는 텍스트로 할 수 있는 일이 많이 있습니다. 예를 tspan
요소를 사용하여 스타일 효과를 내고, 텍스트의 오프셋을 설정하거나, 텍스트에 애니메이션을 적용합니다. 기본적으로 무엇을 하든 경로 자체에 의해 제한됩니다. 그러나 다중 호 경로를 단일 호 경로로 나누면 텍스트 방향, 텍스트의 다른 부분에 대한 z-인덱싱 및 더 복잡한 애니메이션을 얻을 수 있습니다.
먼저 다른 SVG 이미지를 사용하여 일부 효과를 표시하려고 합니다. 앞에서 언급한 포인터 이벤트에 대한 기사의 다이아몬드를 사용할 것입니다. 먼저 단일 경로 원형 텍스트가 그 위에 놓여 있는 모습을 보여 드리겠습니다.
원이 CX 295, CY 200, R 175
라고 가정해 보겠습니다. 이제 원형 경로 방법을 따르면 다음이 표시됩니다.
M (CX - R), CY a R,R 0 1,1 (R * 2),0 a R,R 0 1,1 -(R * 2),0
경로나 텍스트 크기, 채우기 또는 획 색상에 대해서는 이야기하지 않겠습니다. 지금쯤이면 우리 모두가 그것을 이해하고 우리가 원하는 대로 만들 수 있어야 합니다. 그러나 텍스트를 보면 몇 가지 단점이나 한계를 바로 알 수 있습니다.
- 텍스트는 모두 한 방향으로 실행됩니다.
- 특히 MAGAZINE이라고 쓰여 있는 곳에서 일부 텍스트를 자수정 뒤에 배치하는 것이 좋을 수 있습니다. 'M'과 'E'가 원 위에 일직선이 되도록 하기 위해서는 'A'가 자수정의 측면 하단에 있어야 하는데, 이는 다른 의미로 언밸런스한 느낌을 줍니다. ('A'가 정확히 그 지점을 가리키고 있어야 한다고 생각합니다.)
이러한 문제를 해결하려면 단일 경로를 두 개로 분할해야 합니다. 다음 펜에서 경로를 두 개의 경로로 분리했습니다(그리고 우리의 defs
가 참조할 SVG의 textPath
영역에 배치했습니다).
다시 말하지만, CX
가 295, CY 200, R 175
라고 가정하면 두 경로는 다음 형식(상단 반원 경로의 경우)입니다.
M (CX - R), CY a R,R 0 1,1 (R * 2),0
그리고 하단에 대한 다음 사항:
M (CX + R), CY a R,R 0 1,1 -(R * 2),0
그러나 우리는 여전히 모두 같은 방향으로 움직이는 원형 텍스트를 가지고 있습니다. Edge를 제외한 모든 항목에 대해 이 문제를 해결하려면 'MAGAZINE' textPath
를 포함하는 text
요소에 side="right"
속성을 추가하기만 하면 됩니다.
텍스트를 다른 방향으로 이동하기
가능한 한 많은 브라우저를 지원하려면 경로를 변경해야 하며 완전히 지원되지 않는 side
속성에 의존하지 않아야 합니다. 우리가 할 수 있는 것은 상단 반원 경로를 복사하되 스윕을 1
에서 0
으로 변경하는 것입니다.
전에:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
1
350,0
350,0
후에:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
0
350,0
350,0
그러나 이제 우리의 텍스트는 스윕에 의해 정의된 내부 원에 그려지고 다른 브라우저에서는 그렇게 멋지게 보이지 않을 것입니다. 즉, 'Smashing'의 'S'에 맞춰 경로의 위치를 이동하고 경로의 끝 X를 더 크게 만들고 텍스트에 약간의 오프셋을 설정해야 합니다. 보시다시피, Firefox와 다른 것들 사이에는 약간의 텍스트 차이가 있습니다. text
요소의 textLength
속성을 textPath
에서 공백을 제거하여 개선할 수 있습니다(Firefox는 공백이 의미가 있다고 분명히 생각하기 때문에).
해결책:
원형 텍스트 일부의 Z-색인 변경
마지막으로 텍스트가 자수정 앞과 뒤 모두에 오도록 하고 싶습니다. 그건 쉽습니다. SVG의 요소 z-인덱싱은 태그의 위치를 기반으로 한다는 것을 기억하십니까? 따라서 두 개의 요소가 있는 경우 요소 1
은 요소 2
뒤에 그려집니다. 다음으로 우리가 해야 할 일은 SVG 마크업에서 text
요소를 위로 이동하여 자수정 앞에 그려지도록 하는 것입니다.
자수정 하단 부분에 'MAGAZINE'이라는 단어가 가려진 부분을 아래에서 확인할 수 있습니다.
마크업을 보면 글의 하단 반원이 자수정을 그리는 경로 앞으로 이동되었음을 알 수 있습니다.
서클의 일부에 애니메이션 적용하기
이제 텍스트를 두 개의 반원에 넣어 텍스트 부분의 방향성을 완전히 제어하여 원형 텍스트를 만드는 기능이 있습니다. 물론 이것은 텍스트의 애니메이션을 만드는 데에도 악용될 수 있습니다. 브라우저 간 SVG 애니메이션을 만드는 것은 실제로 다른 기사(또는 더 많은 기사)의 주제입니다. 이 예제는 CSS 키프레임이나 Greensock과 같은 도구 대신 SMIL 애니메이션 구문을 사용하기 때문에 Chrome 및 Firefox에서만 작동합니다. 그러나 분해된 원에 애니메이션을 적용하여 얻을 수 있는 효과에 대한 좋은 지표를 제공합니다.
다음 펜을 가져오세요.
코드펜에서 '다시 실행' 버튼을 눌러 애니메이션이 실행되는 모습을 확인하세요. 원형 텍스트의 두 부분은 동시에 애니메이션을 시작하지만 지속 시간이 다르기 때문에 서로 다른 시간에 종료됩니다. textLength
속성에 애니메이션을 적용하기 때문에 각 text
아래에 두 개의 animate
지시문을 textpath
습니다.
결론
이 기사에서 우리는 경로를 최적화해야 할 때와 그렇지 않을 때를 더 잘 이해하기 위해 원을 경로로 바꾸고 다시 되돌리는 방법을 보았습니다. 원을 경로로 바꾸면 원형 경로에 텍스트를 배치할 수 있는 방법과 원형 경로를 반원으로 더 분할하고 원형 텍스트의 구성 요소 부분의 방향성과 애니메이션을 보다 완벽하게 제어하는 방법을 살펴보았습니다. .
SmashingMag에 대한 추가 정보:
- 반응형 SVG 재고
- SVGator로 SVG 파일 애니메이션
- CSS로 SVG 스타일 지정 및 애니메이션 적용
- 포인터 이벤트 속성으로 SVG 상호 작용 관리하기