[SVG|JavaScript] transformされたローカル座標をSVGの座標に変換したい

2018/03/30

こんにちは。きんくまです。

今回は座標変換です。
座標変換は、ローカル座標からグローバル座標に変換したり、その逆のパターンがあります。

それでgなどが入れ子状態になっていて、それぞれがtransformされている中に入っている子供の要素の座標(ローカル座標)から、SVGからみたときの座標(グローバル座標)に変換したかったです。

参考サイトなど
>> SVG localToGlobal – JSFiddle
>> SVG coordinates with transform matrix

getCTM()を使って変換行列を取得する

そのような入れ子状態だとしても、getCTM() を使うと SVGの座標に変換してくれる行列が手に入ります。

>> SVGGraphicsElement

変換するときは matrixTransform() を使います。

サンプルコード

こんな感じに、transformされたgの中にあるcirlceがあるとします。
青が元の座標においたもの、赤がgの中に入ったので移動したものです。
最近知ったのですが、cssのtransformは中に scale translate みたいに連続で変換を書けるんですね。matrixを使わないといけないと思ってました。

html

<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
     id="sample_svg"
     width="300" height="300">

    <circle
      cx="80"
      cy="120"
      r="10"
      fill="blue"
      id="original_circle"></circle>

    <g transform="scale(1.5, 1.5) translate(50, 30)">
        <circle
          cx="80"
          cy="120"
          r="10"
          fill="red"
          id="transformed_circle"></circle>
    </g>
</svg>

座標変換のJS

function addCircleToSamePoint(){
    const xmlns = 'http://www.w3.org/2000/svg';

    const svg = document.getElementById('sample_svg');
    const transformedCircle = document.getElementById('transformed_circle');
    var localCircleX = transformedCircle.getAttribute('cx');
    var localCircleY = transformedCircle.getAttribute('cy');

    console.log(localCircleX, localCircleY); //=> 100 150

    const point = svg.createSVGPoint();
    point.x = localCircleX;
    point.y = localCircleY;

    //この行列をかけるとSVGの座標に変換される
    const matrix = transformedCircle.getCTM();
    //SVGからみたtransformedCircleの座標
    const svgPoint = point.matrixTransform(matrix);
    console.log(svgPoint); //=> SVGPoint {x: 225, y: 270}

    //同じ位置に緑のcircleを入れる
    //作るときはnamespaceが違うのでcreateElementNSを使う
    const newCircle = document.createElementNS(xmlns, 'circle');
    newCircle.setAttribute('cx', svgPoint.x);
    newCircle.setAttribute('cy', svgPoint.y);
    newCircle.setAttribute('r', 30);
    newCircle.setAttribute('opacity', 0.5);
    newCircle.setAttribute('fill', 'green');
    svg.appendChild(newCircle);
}

window.onload = function(){
    addCircleToSamePoint();
};

今回は座標変換したあとに、svgの直下に同じ位置になるように半透明にした緑の円を置いてみました。
位置もぴったり合っていました。

IE11やその他のモダンブラウザでも動きました。
座標変換は面倒なんですが、分かってよかったです。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る