PerfectVector
작성: Irene Kim6분 읽기

SVG 변환 순서: 그림 크기와 위치 조정하기

측정한 로고 예제로 SVG translate와 scale 순서를 비교하세요. 중첩 그룹을 사용하고 지점 하나를 추적하며 원본 경로 변경 없이 그림을 배치합니다.

목차

SVG 속성 transform="translate(60 25) scale(2)"에서는 원본 지점을 두 배로 확대한 뒤 부모 좌표계로 매핑하면서 가로 60단위, 세로 25단위 이동합니다. 목록을 scale(2) translate(60 25)로 뒤집으면 이동도 두 배가 됩니다. 그림 크기는 같지만 위치는 다릅니다.

크기를 바꾼 뒤 로고가 갑자기 움직이면 경로를 편집하기 전에 변환 목록을 확인하세요. 바깥 그룹은 배치, 안쪽 그룹은 크기 조절에 쓰는 구성이 유용합니다. 두 작업이 분명하게 드러나고 원래 그림 좌표도 이후 편집에 사용할 수 있습니다.

순서를 추측하지 말고 지점 하나 추적하기

원본 지점 (10, 10)을 보겠습니다. 배율 2와 이동 (60, 25)에서 두 목록은 다음 결과를 냅니다.

SVG transform 속성지점 계산부모 좌표계의 최종 지점
translate(60 25) scale(2)(10 × 2 + 60, 10 × 2 + 25)(80, 45)
scale(2) translate(60 25)((10 + 60) × 2, (10 + 25) × 2)(140, 70)

두 지점은 같은 원본 좌표에서 나옵니다. 두 번째 목록은 그림과 이동을 모두 확대합니다. 최종 위치는 첫 번째와 (60, 25)만큼 다릅니다.

순서 설명이 서로 모순처럼 보일 수 있습니다. SVG 명세는 목록을 작성 순서의 중첩 좌표계로 설명합니다. 맨 왼쪽 변환이 바깥 그룹입니다. 원본 지점을 그룹 바깥으로 따라가면 가장 안쪽 연산이 먼저 작용합니다. W3C transform 속성 정의는 같은 중첩 구조를 명시적으로 보여 줍니다.

지점 계산은 가장 오른쪽 함수에서 왼쪽으로 진행하세요. 그룹 구조는 바깥에서 안쪽으로 읽으세요. 계산 전반에 같은 해석을 유지하세요.

같은 두 조각 표식 비교하기

이 완전한 예제를 transform-order.svg로 저장하고 브라우저에서 여세요. 직접 만든 정사각형 고리와 별도의 삼각형 강조 부분입니다. 구멍은 even-odd 채우기 규칙이 정의한 실제 빈 공간입니다.

<svg xmlns="http://www.w3.org/2000/svg" width="700" height="400"
     viewBox="0 0 350 200">
  <g id="art" transform="translate(60 25) scale(2)">
    <path fill="#147d78" fill-rule="evenodd"
      d="M10 10H50V50H10Z M20 20H40V40H20Z"/>
    <path fill="#e5a340" d="M65 40L85 10L105 40Z"/>
  </g>
</svg>

그룹 속성만 transform="scale(2) translate(60 25)"로 바꾸세요. 표식은 더 오른쪽 아래로 이동하지만 크기와 조각 사이 간격은 같습니다.

브라우저에서 두 목록과 동일한 중첩 그룹 구성을 렌더링했습니다. 비교 패널은 같은 좌표 영역을 사용하며 희미한 표식은 원본 도형입니다. 빨간 점은 원본 지점 (10, 10)이 도달하는 위치입니다.

translate와 scale 목록을 뒤집은 정사각형 고리·삼각형과 같은 중첩 그룹 구성을 비교한 브라우저 화면
같은 원본 경로에 세 변환 구성을 적용했습니다. 첫 목록과 중첩 그룹은 표시 지점을 (80, 45)에, 반대 목록은 (140, 70)에 놓습니다.

원본 그림의 로컬 상자는 x=10, y=10, width=95, height=40입니다. 첫 구성의 루트 좌표 경계는 x=80, y=45, width=190, height=80입니다. 반대 목록은 x=140, y=70이며 크기는 같은 190 × 80입니다.

이 측정은 스트로크 없는 단순 예제를 설명합니다. 애니메이션이나 CSS 변환은 없습니다. 좌표 합성을 보여 주며 PerfectVector 변환 품질이나 모든 SVG 편집기 호환성을 보여 주지는 않습니다.

중첩 그룹으로 배치와 크기 분리하기

경로는 유지하고 원래 그룹을 다음 구조로 교체하세요.

<g transform="translate(60 25)">
  <g id="art" transform="scale(2)">
    <path fill="#147d78" fill-rule="evenodd"
      d="M10 10H50V50H10Z M20 20H40V40H20Z"/>
    <path fill="#e5a340" d="M65 40L85 10L105 40Z"/>
  </g>
</g>

그룹 하나의 translate(60 25) scale(2)와 같습니다. 바깥 이동은 조절된 좌표계를 배치합니다. 안쪽 배율을 바꿔도 바깥 이동 값은 (60, 25)로 유지됩니다.

크기를 바꿀 때 모든 보이는 지점이 고정된다는 뜻은 아닙니다. 로컬 원점에서 떨어진 지점은 좌표에 배율을 곱하면 여전히 움직입니다. 이동을 선택하기 전에 어느 원본 지점을 그림의 기준으로 할지 정하세요.

예를 들어 고리의 원본 모서리 (10, 10)이 두 배 확대 후 (120, 80)에 도달해야 한다면 다음처럼 계산하세요.

tx = targetX - scale × anchorX = 120 - 2 × 10 = 100
ty = targetY - scale × anchorY =  80 - 2 × 10 =  60

translate(100 60) scale(2)를 사용하세요. 모서리는 이제 (120, 80)으로 매핑됩니다. (120, 80)만큼 직접 이동하면 그곳에 로컬 원점을 놓아 모서리는 더 오른쪽 아래로 갑니다.

이 계산은 회전이나 기울임 없는 균일 확대를 가정합니다. 회전 중심을 의도적으로 선택하려면 SVG transform-origin 가이드를 사용하세요. 무관한 보정을 시행착오로 합치지 말고 각 작업을 맡는 그룹에 변환을 두세요.

중첩 파일의 렌더링 매핑 읽기

가져온 SVG는 여러 상위 요소에 이미 변환이 있을 수 있습니다. 가장 가까운 그룹 속성만 보면 합친 효과를 놓칩니다. MDN transform 참고 문서는 CSS 속성과 표현 속성이 같은 요소를 대상으로 하면 CSS 변환이 우선한다고도 설명합니다. 속성을 바꿔도 변화가 없어 보이면 계산된 스타일을 확인하세요.

렌더링된 인라인 SVG에서 다음 코드는 선택 그룹의 지점을 루트 SVG 사용자 좌표로 매핑합니다.

const root = document.querySelector('svg');
const art = document.querySelector('#art');
const rootMatrix = root.getScreenCTM();
const artMatrix = art.getScreenCTM();
if (!rootMatrix || !artMatrix) throw new Error('SVG is not measurable');
 
const toRoot = rootMatrix.inverse().multiply(artMatrix);
const point = new DOMPoint(10, 10).matrixTransform(toRoot);
const result = { x: point.x, y: point.y };

루트 역행렬은 루트의 공통 화면 매핑을 제거합니다. 예제의 700 × 400 표시는 350 × 200 viewBox의 두 배이므로 중요합니다. 여기서는 화면 픽셀과 SVG 좌표의 단위가 다릅니다. MDN은 getScreenCTM()의 반환 매핑을 설명합니다.

브라우저 비교에서 첫 목록과 중첩 버전은 matrix(2 0 0 2 60 25)를 냈습니다. 반대 목록은 matrix(2 0 0 2 120 50)였습니다. 이 크기·이동 예제에서는 마지막 두 숫자가 이동 차이를 명확히 합니다.

코드는 역행렬이 존재하는 2차원 변환을 가정합니다. 배율 0은 이 역행렬 검사에 적합하지 않습니다. 오버레이, 맞춤 내보내기, 스트로크나 회전 상자는 더 상세한 SVG 경계 작업 흐름을 사용하세요.

그림 그룹의 getBBox()가 변환된 루트 위치를 보고한다고 기대하지 마세요. getBBox 참고 문서가 설명하듯 로컬 결과에는 해당 요소와 상위 요소의 변환이 제외됩니다. 표식이 눈에 띄게 움직여도 로컬 상자는 그대로일 수 있습니다.

그림을 다시 만들기 전에 변환 수정하기

SVG 사본에서 작업하세요. 함께 움직여야 할 경로를 파악하고 그룹과 상위 요소를 확인하세요. 알아보기 쉬운 기준 지점과 그 지점의 목표 위치를 기록하세요.

변환을 한 번에 하나씩 바꾸세요. 크기는 맞지만 위치가 틀리면 두 순서의 이동 결과를 비교하세요. 조각이 따로 움직이면 공통 배치를 포함 그룹에 넣으세요. 회전 중심은 크기 조절 순서 문제와 분리하세요.

대상에서 저장 파일을 다시 열고 표식 전체 범위를 확인하세요. 변환이 올바라도 그림이 viewBox 밖이나 클리핑 영역으로 이동할 수 있습니다. SVG 편집 가이드는 더 넓은 정리·내보내기 과정을 다룹니다.

표식이 PNG나 JPG로만 있고 편집 가능한 윤곽선이 필요하다면 PerfectVector의 로고 벡터화 도구가 SVG 후보를 준비할 수 있습니다. 실루엣, 구멍과 분리 도형을 확인하고 복원 그림을 그룹화한 뒤 편집기나 코드에서 배치 변환을 적용하세요.

비트맵은 벡터화 없이도 이동·크기 조절할 수 있습니다. 편집 가능한 도형이 필요할 때 추적을 사용하고 기존 벡터 원본이 있으면 보존하세요. 정확한 로고 도형이나 글자에는 수동 재구성이 필요할 수 있습니다. 로고 벡터화 가이드는 시작 방식의 선택을 설명합니다.

FAQ

SVG는 변환을 왼쪽에서 오른쪽으로 적용하나요, 반대로 적용하나요? 목록은 작성 순서대로 바깥에서 안쪽의 중첩 좌표계에 대응합니다. 원본 지점의 최종 위치를 계산할 때는 가장 오른쪽 함수를 먼저 적용하고 왼쪽 바깥으로 진행하세요.

translate와 scale을 뒤집으면 로고가 움직이는 이유는 무엇인가요? 속성 목록에서 scale 다음 translate이면 배율이 이동에도 곱해집니다. translate 다음 scale이면 이동은 배율 밖에 있습니다. 같은 값으로 같은 크기를 다른 위치에 만들 수 있습니다.

바깥 이동이 안쪽 그룹 크기 조절 시 모든 지점을 고정하나요? 아닙니다. 바깥 이동 값을 안쪽 배율과 분리합니다. 로컬 원점에서 떨어진 지점은 확대 시 여전히 움직입니다. 기준 지점을 선택하고 배치에 필요한 이동을 계산하세요.

Sources

  1. W3C — SVG transform 속성 — 변환 목록과 중첩 좌표계의 관계를 정의합니다.
  2. MDN — SVG transform — 변환 문법, 행렬 매핑과 CSS 우선순위를 설명합니다.
  3. MDN — getScreenCTM — SVG 좌표를 문서 뷰포트로 매핑하는 행렬을 설명합니다.
  4. MDN — getBBox — 로컬 경계와 측정 요소의 변환 제외를 설명합니다.

원본 로고에 편집 가능한 도형이 필요하면 PerfectVector로 SVG 후보를 준비하고 윤곽선과 별도 부분을 확인하세요. 기준 지점을 선택하고 확대 후 최종 위치를 검증하세요.

블로그의 다른 글

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