SVGで変換元を設定する方法


104

JavaScriptを使用してSVGドキュメントの特定の要素のサイズを変更し、回転する必要があります。問題は、デフォルトで、常に(0, 0)左上の原点の周りに変換を適用することです。

この変換アンカーポイントを再定義するにはどうすればよいですか?

transform-origin属性を使用してみましたが、何の影響もありません。

これは私がそれをした方法です:

svg.getDocumentById('someId').setAttribute('transform-origin', '75 240');

属性が正しく設定されていることをFirefoxで確認できますが、ピボットポイントを指定したポイントに設定していないようです。私はのようなものを試してみましたcenter bottomし、50% 100%とし、括弧なし。これまで何も機能しませんでした。

誰か助けてもらえますか?


:私はまだリストFirefoxの22 MozillaのBugzillaに問題を抱えているものの、おそらく、Firefoxの19ベータ3のように固定FWIW、bugzilla.mozilla.org/show_bug.cgi?id=828286を
Toph

回答:


147

回転するtransform="rotate(deg, cx, cy)"にはを使用します。ここで、degは回転させたい角度で、(cx、cy)は回転の中心を定義します。

スケーリング/サイズ変更の場合は、(-cx、-cy)で変換してから、スケーリングしてから(cx、cy)に変換する必要があります。これは、行列変換を使用して行うことができます。

transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"

ここで、sxはx軸のスケーリング係数、y軸はsyです。


どうもありがとうございます。回転は完璧に機能すると思いますが、スケーリング/サイズ変更は常にランダムな量で終わります。「translate(cx sx、cy sy)scale(sx、sy)」のように、マトリックスを使用して個別に試してみました。同じ結果。
CTheDark

6
それは、transform = "matrix(sx、0、0、sy、cx-sx cx、cy-sy cy)"ではないでしょうか?違いだけで翻訳したいからです。このロジックは正しいと思いますが、それでもポジションを譲ります...
CTheDark

今ではうまくいきます!私はちょうど間違ったcxとcy値を使用していました!どうもありがとう!
CTheDark

1
@JayStevensはい、マトリックス変換はあらゆるシステムで機能します。それは単なる計算です。唯一の違いは記法かもしれません。私の知る限り、CSSマトリックス変換はSVGと同じ表記法を使用しているため、この順序で同じ6つの数値が機能するはずです。
Peter Collingridge 2014

1
明確にするために、cxとcyは、スケーリングのボックスの中心のオフセットである必要があります。これは、CSSボックスモデルで考えていたように、少しつまずきました。@forrestoは以下の彼の回答でこれをほのめかしています。
Jason Farnsworth、2015

22

固定値(「center」や「50%」ではない)を使用できる場合は、代わりにCSSを使用できます。

-moz-transform-origin: 25px 25px;
-ms-transform-origin:  25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin:  25px 25px;
transform-origin: 25px 25px;

一部のブラウザー(Firefoxなど)は、相対値を正しく処理しません。


1
ワオ。できれば+10。これは私の日を救った!ありがとう。
Cullub

これをJavaScriptでどのように行うのですか?
Andrew S

好きelement.setAttribute('transform-origin', '25px 25px')
nikk wong

13

私のように、パンしてからトランスフォーム原点でズームしたい場合は、もう少し必要になります。

// <g id="view"></g>
var view = document.getElementById("view");

var state = {
  x: 0,
  y: 0,
  scale: 1
};

// Origin of transform, set to mouse position or pinch center
var oX = window.innerWidth/2;
var oY = window.innerHeight/2;

var changeScale = function (scale) {
  // Limit the scale here if you want
  // Zoom and pan transform-origin equivalent
  var scaleD = scale / state.scale;
  var currentX = state.x;
  var currentY = state.y;
  // The magic
  var x = scaleD * (currentX - oX) + oX;
  var y = scaleD * (currentY - oY) + oY;

  state.scale = scale;
  state.x = x;
  state.y = y;

  var transform = "matrix("+scale+",0,0,"+scale+","+x+","+y+")";
  //var transform = "translate("+x+","+y+") scale("+scale+")"; //same
  view.setAttributeNS(null, "transform", transform);
};

ここでそれは働いています:http : //forresto.github.io/dataflow-prototyping/react/


github link 404s
NuclearPeon

こんにちは@NuclearPeon、これは素晴らしいですが、コードに実装できないようです。適用したいSVG要素はすでに「mainGrid」と呼ばれる変数です。「view」のインスタンスを「mainGrid」に置き換えても効果はありません。何が欠けていますか?ありがとう!
sakeferret

@sakeferretで確認する最も明白なことidは、getElementByIdおよびドキュメントのid="..."属性の一致です。コードを見なければ、確実に知ることは困難です。あなたはSOの質問として投稿したくない場合、あなたはそれが動作するまで、あなたの属性名を使用して、最も簡単な例を作成してみてください/あなたが問題を見つけることができ、その後に残りのバックを追加します。
NuclearPeon

12

matrix変換を使用せずにスケーリングするには:

transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"

そして、それはCSSにあります:

transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)

0

ここで私たちはすべてトリックを逃したようです: transform-box: fill-box

を使用transform-box: fill-boxすると、SVG内の要素が通常のHTML要素として動作します。次にtransform-origin: center、通常どおりに適用できます(または他の何か)。

そうtransform-box: fill-boxです、複雑なマトリックスの必要はありません


-1

同様の問題がありました。しかし、私は要素を配置するためにD3を使用していて、変換遷移をCSSで処理したいと考えていました。これは私の元のコードで、Chrome 65で動作しました。

//...
this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('circle')
  .attr('transform-origin', (d,i)=> `${valueScale(d.value) * Math.sin( sliceSize * i)} 
                                     ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)}`)
//... etc (set the cx, cy and r below) ...

これは私が設定することができcxcyおよびtransform-origin同じデータを使用してJavaScriptで値を。

しかし、これはFirefoxでは機能しませんでした!私がしなければならなかったことはcirclegタグとtranslateその上にあるのと同じ配置式を使用してタグをラップすることでした。次にcirclegタグにを追加し、cxとのcy値をに設定しました0。そこtransform: scale(2)から、期待どおりに中心からスケーリングします。最終的なコードは次のようになります。

this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('g')
  .attrs({
    class: d => `dot ${d.metric}`,
    transform: (d,i) => `translate(${valueScale(d.value) * Math.sin( sliceSize * i)} ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)})`
  })
  .append('circle')
  .attrs({
    r: this.opts.dotRadius,
    cx: 0,
    cy: 0,
  })

この変更を行った後、を追加するためにのcircle代わりにをターゲットにするようにCSSを変更しまし.dottransform: scale(2)。私も使用する必要はありませんでしたtransform-origin

ノート:

  1. d3-selection-multi2番目の例で使用しています。これにより、属性ごと.attrsに繰り返す代わりに、オブジェクトをに渡すことができ.attrます。

  2. 文字列テンプレートリテラルを使用する場合は、最初の例に示すように改行に注意してください。これにより、出力に改行が含まれ、コードが壊れる可能性があります。


2
おそらく、transform-b​​ox:fill-box;を設定した場合。Firefoxは思い通りに機能するでしょう。
ロバートロングソン2018年

試してみました。うまくいかなかったようです。私はFirefoxのページで設定を変更した後、それはうまくsvg:transform-origin.enabledいきましたabout:config。しかし...それは適切な解決策のようには思えませんでした。私はまたの間で矛盾を発見したtransform-origin: 50% 50%transform-origin: center center
ジェイミーS

svg.transform-origin.enabled設定は多くのバージョンで削除されました。非常に古いバージョンを使用しているのでない限り、50%と中央の間に違いはありません。Firefox 59以降で違いがある場合は、遠慮なくバグジラバグを報告してください。
ロバートロングソン2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.