PerfectVector
작성: Irene Kim8분 읽기

SVG 상대 경로 명령: 현재 지점 추적하기

현재 지점을 추적하며 SVG 절대 경로와 상대 경로를 읽어 보세요. 동일한 결과를 내는 자체 예제로 moveto 좌표 쌍, closepath의 지점 초기화, 3차 곡선 좌표를 확인합니다.

목차

M, L, C 같은 SVG 절대 경로 명령은 현재 사용자 좌표계의 위치를 사용합니다. 상대 형식인 m, l, c는 현재 지점으로부터의 오프셋을 사용합니다. 경로를 읽거나 다시 작성하려면 각 세그먼트가 끝날 때마다 그 지점을 추적하세요. 숫자는 그대로 두고 명령 문자만 바꾸면 모양이 달라질 수 있습니다.

혼동을 일으키는 규칙은 주로 두 가지입니다. 처음 나오는 m의 첫 좌표 쌍은 절대 이동으로 동작하지만 이후 좌표 쌍은 상대 직선이 됩니다. 또 Z 또는 z는 하위 경로를 닫고 현재 지점을 그 시작점으로 되돌립니다. 닫은 뒤 새로 나오는 상대 이동은 초기화된 지점을 사용합니다.

위치와 오프셋을 구분해서 읽기

W3C 경로 명세는 현재 지점, 하위 경로, 그리기 명령으로 경로를 정의합니다. 좌표는 SVG 사용자 단위이며 반드시 화면 픽셀을 뜻하지는 않습니다. viewBox나 변환을 통해 표시 위치가 달라질 수 있습니다.

(40, 40)에서 시작하면 다음 두 명령은 같은 직선을 나타냅니다.

L180 40
l140 0

첫 번째는 끝점 (180, 40)을 지정합니다. 두 번째는 (40, 40)에 (140, 0)을 더합니다. 둘 다 (180, 40)에서 끝나며, 이 지점이 다음 세그먼트의 현재 지점이 됩니다.

반면 l180 40은 (180, 40)을 더해 (220, 80)에서 끝납니다. 문법은 유효하지만 다른 직선을 그립니다.

명령위치 값의 의미
M x y지정한 위치에서 하위 경로 시작
m dx dy현재 지점을 기준으로 하위 경로 시작. 최초 m의 동작은 아래 설명 참고
L x y지정한 위치까지 직선 그리기
l dx dy현재 지점에 오프셋을 더한 위치까지 직선 그리기
C / c두 제어점과 끝점을 절대 위치 또는 동일한 시작점 기준 오프셋으로 지정
Z / z하위 경로의 시작점으로 닫고 현재 지점 초기화

대문자와 소문자 Z의 효과는 같습니다. 둘 다 좌표 인수를 받지 않습니다. MDN d 참고 문서에 각 명령과 개별 매개변수가 정리되어 있습니다.

같은 원본 그림을 표현하는 두 방식 비교하기

다음 완전한 SVG를 absolute.svg로 저장하고 브라우저에서 열어 보세요. 정사각형 구멍이 있는 청록색 복합 배지와 별도의 산호색 3차 곡선이 들어 있습니다.

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="240" viewBox="0 0 300 240">
  <path class="badge" fill="#173b40" fill-rule="evenodd" d="M40 40L180 40L210 80L180 140L40 140Z M80 70L80 110L120 110L120 70Z"/>
  <path class="curve" fill="none" stroke="#f28567" stroke-width="6" d="M40 190C80 145 155 225 220 180"/>
</svg>

relative.svg에서는 SVG 크기, viewBox, 스타일을 유지하고 두 경로 요소를 다음으로 교체하세요.

<path class="badge" fill="#173b40" fill-rule="evenodd"
  d="m40 40 140 0 30 40 -30 60 -140 0z m40 30 0 40 40 0 0 -40z"/>
<path class="curve" fill="none" stroke="#f28567" stroke-width="6"
  d="m40 190c40 -45 115 35 180 -10"/>

두 원본 파일과 함께, 절대 좌표 배지를 의도적으로 잘못 수정한 복사본을 브라우저에서 렌더링했습니다. 잘못된 복사본에서는 첫 번째 L180 40만 l180 40으로 바꿨으며 숫자는 그대로 두었습니다.

실제 SVG 렌더링에서 절대 좌표와 상대 좌표의 복합 배지 및 3차 곡선이 일치하며, 좌표를 변환하지 않고 직선 명령 하나의 대소문자만 바꾼 배지는 왜곡된 모습
처음 두 표현은 일치합니다. 세 번째는 첫 직선의 끝점이 (180, 40)에서 (220, 80)으로 바뀝니다. 아래 패널은 경로 닫기, 3차 곡선 오프셋, 해당 비교 쌍의 브라우저 측정값을 보여 줍니다.

페이지에서는 SVG 기본 메서드인 getTotalLength()와 getPointAtLength()를 사용해 각 경로에서 전체 길이의 같은 비율에 해당하는 301개 표본을 비교했습니다. 표시된 길이는 각 배지가 657.082 사용자 단위, 각 곡선이 189.066이었습니다. 표본 지점 간 최대 차이는 두 쌍 모두 0.000000으로 표시되었습니다.

이 측정은 해당 문자열의 일치를 뒷받침하며, 직선 꼭짓점과 3차 곡선 지점도 아래 계산으로 일치합니다. 임의의 재작성이나 변환기가 모든 SVG 명령을 처리한다는 증거는 아닙니다. 비교 전반에서 변환하지 않은 동일한 뷰포트와 페인트 설정을 사용했습니다.

첫 m과 암시적 직선 따라가기

배지는 다음으로 시작합니다.

m40 40 140 0 30 40 -30 60 -140 0z

첫 좌표 쌍만 이동을 수행합니다. 나머지 쌍은 암시적 상대 l 세그먼트로 동작합니다. moveto 정의는 초기 m40 40을 절대 시작점으로 처리하더라도 이후 좌표 쌍은 상대 좌표로 유지한다고 명시합니다.

좌표 쌍을 하나씩 추적해 보세요.

좌표 쌍 또는 명령동작동작 후 현재 지점
m40 40초기 이동(40, 40)
140 0암시적 상대 직선(180, 40)
30 40암시적 상대 직선(210, 80)
-30 60암시적 상대 직선(180, 140)
-140 0암시적 상대 직선(40, 140)
z이 하위 경로의 시작점으로 닫기(40, 40)

비교하자면, 좌표 쌍이 여러 개 있는 대문자 M은 이후 쌍을 암시적 절대 L 세그먼트로 바꿉니다. 모든 쌍을 또 다른 이동으로 취급하지 않으며, 이 소문자 예제와 같은 변화량을 사용하지도 않습니다.

경로 요소마다 독립적인 경로 시퀀스가 만들어집니다. 최초 상대 m을 앞에 있는 무관한 경로 요소의 끝점에서 시작하지 마세요.

닫힌 하위 경로의 시작점을 다음 이동의 기준으로 사용하기

구멍은 첫 번째 z 다음에 시작합니다.

m40 30 0 40 40 0 0 -40z

이때 현재 지점은 (40, 40)이므로 새로운 상대 이동은 (40, 30)을 더해 (80, 70)에서 구멍을 시작합니다. 이후 암시적 직선이 (80, 110), (120, 110), (120, 70)에 도달한 뒤 닫힙니다.

바깥 배지의 마지막 직선 끝점 (40, 140)을 기준으로 잘못 사용하면 이동 위치는 (80, 170)이 됩니다. 앞서 경로를 닫았기 때문에 이 계산은 틀립니다. closepath 정의는 현재 지점을 현재 하위 경로의 최초 지점으로 되돌립니다.

두 하위 경로는 하나의 경로 요소에 속합니다. 이 예제의 fill-rule="evenodd"는 안쪽 정사각형을 구멍으로 만듭니다. 좌표 재작성을 비교할 때 채우기 규칙과 페인트 설정을 유지해야 채우기 변경이 확인하려는 도형을 가리지 않습니다.

각 3차 곡선 제어점을 같은 시작점에서 측정하기

별도의 곡선은 (40, 190)에서 시작합니다.

M40 190 C80 145 155 225 220 180
m40 190 c40 -45 115 35 180 -10

이 소문자 c 세그먼트 하나에서는 세 좌표 쌍 모두 (40, 190) 기준 오프셋입니다. 두 번째 제어점은 첫 번째 제어점 기준이 아니며, 끝점도 두 번째 제어점 기준이 아닙니다.

지점상대 좌표 쌍절대 위치
첫 번째 제어점(40, -45)(80, 145)
두 번째 제어점(115, 35)(155, 225)
끝점(180, -10)(220, 180)

세그먼트가 끝나면 현재 지점을 끝점 (220, 180)으로 갱신합니다. 다음 상대 세그먼트는 이 새로운 시작점을 사용합니다. MDN 경로 튜토리얼은 3차 곡선 제어점과 절대·상대 형식을 설명합니다. Bézier 연결 가이드는 접선 핸들과 축약 명령 S를 별도로 다룹니다.

모든 명령의 모든 숫자에 좌표 빼기를 적용하지 마세요. 호에서는 반지름, 회전, 플래그가 서로 다른 역할을 하며, 끝점 좌표 쌍만 절대·상대 위치 사이를 전환합니다. A 또는 a 데이터를 다시 작성하기 전에 호 플래그 설명을 참고하세요. 이 예제는 일반적인 경로 변환 루틴이 아니라 직선, 이동, 닫기와 일반적인 3차 곡선 세그먼트 하나를 보여 줍니다.

배치와 경로 문법을 혼동하지 않고 그림 이동하기

모든 좌표가 상대적인 이 복합 배지에서 최초 m40 40을 m60 60으로 바꾸면 꼭짓점이 (20, 20)만큼 이동합니다. 이후 변화량과 상대 하위 경로 이동이 바뀐 시작점을 따라가기 때문입니다. 별도의 곡선 경로는 그대로 유지됩니다. 절대·상대 좌표가 섞인 데이터에서는 이후 절대 위치도 지정한 좌표에 고정되므로 첫 이동을 편집하면 경로가 변형될 수 있습니다.

두 경로로 구성된 그림 전체를 하나로 이동하려면 두 d 문자열을 유지하고 요소들을 transform="translate(20 20)"가 지정된 그룹 안에 넣으세요. SVG 좌표계 명세는 변환으로 좌표 매핑이 만들어지는 방식을 설명합니다. 그룹 변환은 원래 경로 데이터를 다시 작성하지 않고 배치를 바꿉니다.

이동한 그림이 뷰포트 안에 남아 있는지 확인하세요. 그룹을 이동해도 캔버스가 자동으로 커지지는 않습니다. SVG 변환 순서 가이드는 이동과 크기 조절을 함께 사용할 때의 배치를 다룹니다.

표기법을 바꾸기 전에 원본 도형 확인하기

그림이 PNG나 JPG로만 있다면 PerfectVector가 도움이 될 수 있습니다. SVG 후보를 준비한 뒤, 경로 데이터를 편집하기 전에 복원한 실루엣, 구멍, 곡선 모양을 원본과 비교하세요. 절대·상대 표기법 자체로는 복원한 도형이 적합한지 판단할 수 없습니다.

벡터 원본이 있다면 그대로 사용하고, 단순한 기호를 직접 다시 그리는 편이 제어하기 쉽다면 그렇게 하세요. 명령을 다시 작성해도 누락된 래스터 정보에서 의도한 모양을 복원할 수는 없습니다. 이미지 벡터화 개요는 이 별도의 재구성 단계를 설명합니다.

사용 가능한 SVG를 편집할 때는 원본 사본을 보관하고, 지원되는 세그먼트를 한 번에 하나씩 바꾼 뒤 실제 파일을 같은 배율로 비교하세요. 현재 지점뿐 아니라 하위 경로의 시작점도 추적하세요. 비교 중에는 채우기와 스트로크 설정을 유지하고, 내보낸 파일을 실제로 받을 애플리케이션에서 테스트하세요.

FAQ

첫 소문자 m은 다른 경로를 기준으로 하는 상대 좌표인가요? 아닙니다. m이 경로의 첫 명령이면 첫 좌표 쌍은 절대 시작점으로 처리됩니다. 이후 쌍은 암시적 상대 직선이며, 다른 경로 요소의 끝점은 시작 기준이 아닙니다.

Z 또는 z 다음의 현재 지점은 어디인가요? 방금 닫은 하위 경로의 시작점입니다. 다음 상대 이동은 앞선 직선의 끝점이 아니라 초기화된 이 지점을 사용합니다.

명령을 소문자로 바꾸기만 해도 경로를 변환할 수 있나요? 아닙니다. 각 명령의 의미에 맞게 위치 값을 다시 계산해야 합니다. 이 예제에서 현재 지점이 (40, 40)이면 L180 40은 l140 0이 되며, l180 40은 다른 직선을 그립니다.

Sources

  1. W3C — SVG 2 경로 — 현재 지점, 최초 moveto, 암시적 직선, 닫기, 3차 곡선 매개변수를 정의합니다.
  2. MDN — 경로 튜토리얼 — 절대·상대 직선 및 곡선 명령을 예로 설명합니다.
  3. MDN — d 속성 — 호와 closepath를 포함한 명령 매개변수의 역할을 정리합니다.
  4. W3C — SVG 2 좌표계 — 사용자 좌표 매핑과 변환을 이용한 그림 배치를 설명합니다.

래스터 그림만 가지고 시작하시나요? PerfectVector로 SVG 경로를 준비하고 복원한 실루엣과 구멍을 확인하세요. 이해한 명령만 편집한 뒤 최종 SVG를 원본과 비교해 검증하세요.

블로그의 다른 글

편집하기 쉬운
더 깔끔한 SVG로 다시 시작하세요