0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実務で使えるSVG】transformと座標変換 チートシート|translate・scale・rotateを整理

0
Posted at

🎯 やりたかったことは?

SVGを扱っていると、

「図形を少し右にずらしたい」
「中心を基準に回転させたい」
「左右反転したい」
「scaleした後の座標ってどう考えればいいんだっけ?」

みたいな場面が結構あります。

単純な移動なら分かりやすいですが、
scale や rotate が入ってくると、
見た目の位置と元の座標の関係が少し分かりにくくなります。

自分も実務でSVGの座標を扱うことがあるので、
translate、scale、rotate を中心に、
よく使う transform と座標変換をまとめておきます。


🚀 急いでいる人向け

SVGの transform でよく使うものはこのあたりです。

やりたいこと 指定
移動 translate(x y)
拡大・縮小 scale(sx sy)
回転 rotate(angle)
指定座標を中心に回転 rotate(angle cx cy)
X方向へ傾ける skewX(angle)
Y方向へ傾ける skewY(angle)
行列でまとめて変換 matrix(a b c d e f)

例えば、

<rect
    x="20"
    y="20"
    width="80"
    height="50"
    transform="translate(100 40)"
    fill="#4CAF50" />

なら、

X方向に +100
Y方向に +40

移動します。

拡大なら、

transform="scale(2)"

回転なら、

transform="rotate(45)"

です。

複数の変換を組み合わせる場合は、
順番によって結果が変わるので注意します。


💡 この記事で分かること

  • transform 属性の基本
  • translate で図形を移動する方法
  • scale で拡大・縮小・反転する方法
  • rotate で回転する方法
  • 指定した点を中心に回転する方法
  • transform を複数組み合わせるときの考え方
  • 変換前と変換後の座標の考え方
  • CSSの transform を使う場合の注意点

SVGの transform とは?

SVGでは、要素そのものの座標を書き換えなくても、
transform を使って表示位置や大きさを変更できます。

例えば、

<rect
    x="20"
    y="20"
    width="80"
    height="50"
    fill="#4CAF50"
    transform="translate(100 40)" />

元の座標は、

x = 20
y = 20

のままです。

ただし表示上は、

x = 120
y = 60

の位置へ移動します。

つまり、

元の座標
+
transformによる変換
=
表示上の位置

という考え方になります。


translate:移動する

translate は要素を移動するときに使います。

基本形は、

translate(x y)

です。

<rect
    x="20"
    y="20"
    width="80"
    height="50"
    transform="translate(100 40)"
    fill="#4CAF50" />

この場合、

x方向:+100
y方向:+40

移動します。

元の左上座標が、

(20, 20)

なので、表示上は、

(120, 60)

になります。


X方向だけ移動する

Yを省略すると 0 として扱われます。

transform="translate(100)"

これは、

transform="translate(100 0)"

と同じです。


scale:拡大・縮小する

scale は要素を拡大・縮小するときに使います。

<rect
    x="20"
    y="20"
    width="80"
    height="50"
    transform="scale(2)"
    fill="#2196F3" />

基本形は、

scale(sx sy)

です。

値が1なら元のサイズです。

scale(1)
→ そのまま

scale(2)
→ 2倍

scale(0.5)
→ 半分

X方向とY方向を別々に指定する

transform="scale(2 0.5)"

なら、

X方向:2倍
Y方向:0.5倍

になります。


scaleすると座標も変わる

ここは少し注意が必要です。

例えば、

<rect
    x="20"
    y="20"
    width="80"
    height="50"
    transform="scale(2)" />

とすると、
サイズだけでなく座標も2倍になります。

x = 20
y = 20

は表示上、

x = 40
y = 40

になります。

つまり scale(2) は、

座標 × 2
サイズ × 2

です。

単純にその場で大きくなるわけではありません。


任意の位置を基準にscaleしたい場合

例えば図形の位置を変えず、
ある点を基準に拡大したい場合は、
translate と組み合わせます。

考え方は、

1. 基準点を原点へ移動
2. scaleする
3. 元の位置へ戻す

です。

例えば (100, 100) を基準に2倍するなら、

transform="
    translate(100 100)
    scale(2)
    translate(-100 -100)
"

のような考え方になります。

複数の変換は順番によって結果が変わるため、
複雑になってきた場合は <g> で分けると追いやすくなります。


負のscaleで反転する

scale にマイナスを指定すると反転できます。

左右反転

transform="scale(-1 1)"

X方向が反転します。

上下反転

transform="scale(1 -1)"

Y方向が反転します。

例えば、

<path
    d="M20 20 L100 20 L60 100 Z"
    transform="scale(1 -1)"
    fill="#FF9800" />

とすると、
Y方向が反転します。

ただし、

y = 20
↓
y = -20

となるため、
単純に scale(1 -1) を付けるだけだと画面外へ移動することがあります。

そのため、実際には translate と組み合わせることがあります。

transform="translate(0 200) scale(1 -1)"

このあたりは、
見た目だけでなく座標を使った操作をするときにも注意が必要です。


rotate:回転する

rotate は要素を回転させます。

<rect
    x="50"
    y="50"
    width="100"
    height="50"
    transform="rotate(45)"
    fill="#9C27B0" />

基本形は、

rotate(angle)

です。

角度は度数で指定します。

rotate(45)
rotate(90)
rotate(180)

rotateの基準点に注意する

次の指定では、

transform="rotate(45)"

SVG座標系の原点、

(0, 0)

を基準に回転します。

そのため、

図形の中心で回転すると思ったら、位置まで大きく動いた

ということがあります。


指定座標を中心に回転する

rotate では、
回転角度と一緒に中心座標を指定できます。

rotate(angle cx cy)

例えば、

<rect
    x="50"
    y="50"
    width="100"
    height="50"
    transform="rotate(45 100 75)"
    fill="#9C27B0" />

なら、

回転角度:45度
中心X:100
中心Y:75

です。

この rect の中心も、

x = 50
width = 100
→ 中心X = 100

y = 50
height = 50
→ 中心Y = 75

なので、
図形の中心を基準に回転します。


図形の中心座標を計算する

rect なら比較的簡単です。

centerX = x + width / 2
centerY = y + height / 2

例えば、

x = 50
y = 50
width = 100
height = 50

なら、

centerX = 50 + 100 / 2
        = 100

centerY = 50 + 50 / 2
        = 75

です。

JavaScriptなら、

const centerX =
    x + width / 2;

const centerY =
    y + height / 2;

と計算できます。


getBBox() から中心を求める

path のように、
単純に x / width を持っていない要素では getBBox() が使えます。

const shape =
    document.getElementById("sampleShape");

const box =
    shape.getBBox();

const centerX =
    box.x + box.width / 2;

const centerY =
    box.y + box.height / 2;

あとは、

shape.setAttribute(
    "transform",
    `rotate(45 ${centerX} ${centerY})`
);

のように指定できます。


skewX / skewY:傾ける

使用頻度は高くありませんが、
要素を斜めに変形することもできます。

X方向

transform="skewX(20)"

Y方向

transform="skewY(20)"

例えば、

<rect
    x="50"
    y="50"
    width="100"
    height="60"
    transform="skewX(20)"
    fill="#009688" />

のように使います。


transformを複数指定する

例えば、

transform="translate(100 50) rotate(30)"

のように、
複数の変換を並べられます。

ただし、ここで重要なのが、

transformの順番を変えると結果も変わる

という点です。

例えば、

transform="translate(100 50) rotate(30)"

と、

transform="rotate(30) translate(100 50)"

は同じ結果とは限りません。

移動や回転によって、
次の変換で使われる座標系も変わるためです。


複雑なtransformは <g> に分ける

複数の変換が増えてきた場合は、
1つの transform に詰め込みすぎるより <g> を使う方が追いやすいことがあります。

<g transform="translate(100 50)">

    <g transform="rotate(30)">

        <rect
            x="20"
            y="20"
            width="80"
            height="50"
            fill="#4CAF50" />

    </g>

</g>

これなら、

外側
→ translate

内側
→ rotate

と役割が分かれます。

実務ではこの方が、
あとから見たときに分かりやすいことがあります。


座標変換の基本

単純な変換なら、
変換後の座標も計算できます。

translate

元の座標を、

(x, y)

移動量を、

(tx, ty)

とすると、

x' = x + tx
y' = y + ty

です。

例えば、

元: (20, 30)
移動:(+100, +50)

なら、

変換後:(120, 80)

になります。


scaleの座標変換

x' = x × sx
y' = y × sy

です。

例えば、

元:(20, 30)

scale(2)

なら、

x' = 20 × 2 = 40
y' = 30 × 2 = 60

になります。


負のscale

例えば、

scale(1 -1)

なら、

x' = x
y' = -y

です。

(20, 30)

は、

(20, -30)

になります。

これが、
上下反転したSVGで座標処理をするときに少し厄介になるポイントです。


rotateの座標変換

原点 (0, 0) を基準に角度 θ 回転する場合は、

x' = x cosθ - y sinθ
y' = x sinθ + y cosθ

となります。

ただ、実装時に毎回この式を直接書くより、
SVGやブラウザが持っている変換行列を利用する方が扱いやすい場合もあります。


matrix() でまとめて変換する

SVGの transform には matrix() もあります。

matrix(a b c d e f)

例えば、

transform="matrix(1 0 0 1 100 50)"

なら、
結果としては100px右、50px下へ移動する変換です。

matrix は、

  • 移動
  • 拡大縮小
  • 回転
  • 傾き

などを1つの変換行列として表せます。

ただ、人が直接読むには分かりにくいので、
自分でSVGを書く場合は、

translate
scale
rotate

を使った方が読みやすいことが多いです。

SVG編集ツールから出力されたデータでは、
matrix() が入っていることがあります。


JavaScriptからtransformを変更する

transform はJavaScriptからも変更できます。

const shape =
    document.getElementById("sampleShape");

shape.setAttribute(
    "transform",
    "translate(100 50)"
);

複数指定する場合は、

shape.setAttribute(
    "transform",
    "translate(100 50) rotate(30)"
);

です。


CSSのtransformを使う

SVG要素にはCSSの transform も指定できます。

.sample-shape {
    transform: rotate(45deg);
}

ただし、
SVG属性の transform とCSSの transform は書き方や基準点の扱いが少し違います。

例えばSVG属性では、

transform="rotate(45 100 75)"

のように回転中心を指定できます。

CSSでは、

.sample-shape {
    transform-box: fill-box;
    transform-origin: center;
    transform: rotate(45deg);
}

のように書くことがあります。


SVG属性とCSS、どちらを使う?

自分の場合はざっくり、

座標や図形そのものの変換
→ SVGのtransform属性

アニメーションや見た目の動き
→ CSS transform

くらいで分けることが多いです。

もちろん絶対ではありません。

ただ、座標計算を追う必要がある処理では、
どこで変換しているかを統一しておいた方が分かりやすいです。


⚠️ ハマりやすいポイント

scaleすると位置も変わる

transform="scale(2)"

は、

サイズだけ2倍

ではありません。

座標も2倍になります。

位置を維持したまま拡大したい場合は、
基準点を考える必要があります。


rotateの中心は図形の中心とは限らない

transform="rotate(45)"

だけでは、
原点を基準に回転します。

図形の中心を使うなら、

rotate(45 cx cy)

のように中心を指定します。


負のscaleで座標方向も反転する

scale(1 -1)

で見た目を上下反転すると、
Y座標の方向も反転します。

表示だけなら問題なくても、
ドラッグやマウス座標を扱うようになると、

上へ動かしたのに図形が下へ動く

といったことがあります。

これは別の記事で、
実際にハマったケースとして詳しくまとめる予定です。


transformの順番で結果が変わる

translate
↓
rotate

と、

rotate
↓
translate

では結果が変わります。

複雑になったら <g> を分けると追いやすくなります。


元の属性値は変わらない

例えば、

<rect
    x="20"
    transform="translate(100 0)" />

としても、

rect.getAttribute("x");

で取得できる値は、

20

のままです。

画面上では120付近に見えていても、
元の x 属性を書き換えたわけではありません。

元座標

と、

transform適用後の表示座標

は分けて考える必要があります。


📝 まとめ

SVGでよく使う transform は次のとおりです。

transform 用途
translate 移動
scale 拡大・縮小・反転
rotate 回転
skewX X方向へ傾ける
skewY Y方向へ傾ける
matrix 行列でまとめて変換

単純な表示だけなら、

translate
scale
rotate

を覚えておけばかなり対応できます。

ただ、マウス操作やドラッグ処理まで入ってくると、

元の座標
transform後の座標
ブラウザ上の座標

を分けて考える必要が出てきます。

特に、

scale(1 -1)

のような反転は、
見た目だけでは気づきにくい座標のズレにつながるので注意が必要です。

自分もSVGの座標処理で迷ったときに見返せるよう、
基本的な変換をまとめておきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?