web-dev-qa-db-ja.com

SVGパスの透視変換(四隅が歪む)

ブラウザでSVGのパスを変形して、JavaScriptまたはCSSを使用して特定の視点にパスを変形させるにはどうすればよいですか?遠近法による歪みは、Photoshop、Illustratorなどで簡単に作成できますが、ブラウザはどうですか?

これはソースパスです:

enter image description here

そして、これは変換後のパスです:

enter image description here

30
Timo Kähkönen

これは私のドラッグの歪んだ提案です( 知識を共有してください、Q&Aスタイル )。

ライブの例は http://jsfiddle.net/xjHUk/278/ にあり、メインコードは次のとおりです。
(出力ウィンドウのみ: http://jsfiddle.net/xjHUk/279/embedded/result/

 function transferPoint(xI、yI、source、destination)
 {
 var ADDING = 0.001; //ゼロで除算しないようにする
 
 var xA = source [0] .x; 
 var yA = source [0] .y; 
 
 var xC = source [2] .x; 
 var yC = source [2] .y; 
 
 var xAu = destination [0] .x; 
 var yAu = destination [0] .y; 
 
 var xBu = destination [1] .x; 
 var yBu = destination [1] .y; 
 
 var xCu = destination [2] .x; 
 var yCu = destination [2] .y; 
 
 var xDu = destination [3]。 x; 
 var yDu = destination [3] .y; 
 
 // Calcultations 
 //ポイントが同じ場合、ADDINGを追加して回避する必要がありますゼロで除算
 if(xBu == xCu)xCu + = ADDING; 
 if(xAu == xDu)xDu + = ADDING; 
 if(xAu == xBu)xBu + = ADDING ; 
 if(xDu == xCu)xCu + = ADDING; 
 var kBC =(yBu-yCu)/(xBu-xCu); 
 var kAD =(yAu-yDu) /(xAu-xDu);
 var kAB =(yAu-yBu)/(xAu-xBu); 
 var kDC =(yDu-yCu)/(xDu-xCu); 
 
 if(kBC == kAD)kAD + = ADDING; 
 var xE =(kBC * xBu-kAD * xAu + yAu-yBu)/(kBC-kAD); 
 var yE = kBC *(xE-xBu)+ yBu; 
 
 if(kAB == kDC)kDC + = ADDING; 
 var xF =(kAB * xBu-kDC * xCu + yCu-yBu)/(kAB-kDC); 
 var yF = kAB *(xF-xBu)+ yBu; 
 
 if(xE == xF)xF + = ADDING; 
 var kEF =(yE-yF)/ (xE-xF); 
 
 if(kEF == kAB)kAB + = ADDING; 
 var xG =(kEF * xDu-kAB * xAu + yAu-yDu)/( kEF-kAB); 
 var yG = kEF *(xG-xDu)+ yDu; 
 
 if(kEF == kBC)kBC + = ADDING; 
 var xH =(kEF * xDu-kBC * xBu + yBu-yDu)/(kEF-kBC); 
 var yH = kEF *(xH-xDu)+ yDu; 
 
 var rG =(yC-yI)/(yC-yA); 
 var rH =(xI-xA)/(xC-xA); 
 
 var xJ =(xG -xDu)* rG + xDu; 
 var yJ =(yG-yDu)* rG + yDu; 
 
 var xK =(xH-xDu)* rH + xDu; 
 var yK =(yH-yDu)* rH + yDu; 
 
 if(xF == xJ)xJ + = ADDING; 
 if(xE == xK) xK + = ADDING; 
 var kJF =(yF-yJ)/(xF-xJ); //23
 var kKE =(yE-yK)/(xE-xK); //12

 var xKE; 
 if(kJF == kKE)kKE + = ADDING; 
 var xIu =(kJF * xF-kKE * xE + yE -yF)/(kJF-kKE); 
 var yIu = kJF *(xIu-xJ)+ yJ; 
 
 var b = {x:xIu、y:yIu} ; 
 bx = Math.round(bx); 
 by = Math.round(by); 
 return b; 
} 
 

結果は正しく遠近法に歪んでいます(2つの消失点1)。 2点透視計算の原理は here です。スクリプトは、次の要件を満たしている場合、SVGパスデータを処理できます。

  • すべての座標は絶対値です(つまり、大文字を意味します)。 this を参照してください。
  • 弧( "A")は使用されません
  • VとHはLに正規化されます

アークは正規化できますが、クロスブラウザの方法はまだ見つけていません。 VとHからLへの変換は簡単です。最後に使用したxまたはy座標を取得し、不足している座標をLの後に追加する必要があります。

同じスクリプトでパス内の曲線も処理できます(曲線はTimesのものです)。次のコードはまったく同じですが、パス属性( "d")が異なります。

http://jsfiddle.net/xjHUk/277/function dummy(a) {return a;}(このコードでは、上記のような無効な位置のチェックは行われません)。

上記の例のパスは、ArialとTimesのSVGバージョンから取得されます。フォントは デカルト座標系 を使用することに注意してください。この場合、上に行くとy座標が増加します。それ以外の場合、SVGはビットマップイメージとCSSで使用される極座標系を使用します。つまり、上記のコードでSVGフォントからのパスを使用する場合、パスを垂直方向に反転し、目的のフォントサイズにスケーリングする必要があります。 TTFフォント(および対応するSVGフォント)のサイズは通常2048であるため、グリフのバウンディングボックスには2048 pxのスケーリングがないため、通常、SVGグリフパスをSVGパスに変換すると大きすぎます。

ただし、他のSVGパスを歪めたい場合は、フリッピングとスケーリングを不要にします。

これはかなり長いコードです(多くはドラッグ機能のため)。同じ効果は一部のcss-3D-transform-wayでも達成できると思いますが、そのような実装ではまだうまくいきません...

比較のために、非透視歪みの例(SVGの主要な競合SWF):
http://www.rubenswieringa.com/code/as3/flex/DistortImage/

さらに追加の比較のために、有効なパースペクティブ計算の例:
http://zehfernando.com/f/TriangleTest.swf

28
Timo Kähkönen

選択した回答は古くなっています。

SVGは要素のパースペクティブの変更をサポートしていませんが、CSS3変換を使用することでこれを実現できます。

CSS3は、オブジェクトをアニメーション化する非常に強力な方法です。 CSS3 Transformは、JavaScriptを使用してリアルタイムで作成および適用できます。

CSS3 Transformには優れたサポートがあり、主要なブラウザーの最近のすべてのバージョンでサポートされています。 (IE 8以降、Chrome 31以降、Safari 7.1以降、Opera 26以降、Firefox 34以降、Androidブラウザ4.1+)。詳細: http://caniuse.com/#feat=transforms2d

一部のブラウザバージョンでは、ブラウザ固有のプレフィックスを使用して変換を作成する必要があります。しかし、それを処理する良い方法を説明する非常にきちんとしたサイトがあります: http://bl.ocks.org/mbostock/10571478

CSS3 Transformプロパティには、rotate(angle)scale(dimension)があります。私は知っています、SVG変換rotate(angle)scale(x y)に似ていますが、2つの間に基本的な違いがあるため、CSS3の方がはるかに多いため、これらを同じものにしないことが最善ですSVG変換よりも強力です。さらに、CSS3 Transformsにはperspectiveというプロパティがあり、このプロパティを確認する必要があります。

CSS3変換についてW3より多くの情報を見つけるのに最適な場所はありません: http://www.w3.org/TR/css3-transforms/

ここにコードスニペットがあります: an example of CSS3 Transforms

div {
  height: 150px;
  width: 150px;
}
.container {
  perspective: 500px;
  border: 1px solid black;
  background: gray;
}
.transformed {
  transform: rotateY(50deg);
  background: blue;
}
<!doctype html>
<html>
<body>
<div class="container">
  <div class="transformed"> Hola! He sido transformado!</div>
</div>
</body>
</html>

幸せな変身!

12
oabarca