2015-01-02 9 views
5

getBoundingClientRect()は、が変換された後に、の要素の座標を返します。が変換される前に、それらの座標をどのように計算するのですか??すなわち変換を伴わない。変換を考慮せずにgetBoundingClientRect()を計算する方法は?

element.style.transform = 'none'; //temporarily reset the transform 
var untransformedOffset = element.getBoundingClientRect().top; //get the value 
element.style.transform = ''; //set it back 

が、それは多くの要素に行われた場合に特に顕著、遅いレイアウトスラッシングが発生します。私が見つけ

最も簡単な方法でした。ライブデモ:http://jsbin.com/nibiqogosa/1/edit?js,console,output

良い方法はありますか?

element.getBoundingClientRect().topの結果は、20(ページの余白を除くとなります(ページの余白を除く)

<div id="element"></div> 
<style> #element { transform: translateY(20px); }</style> 

、結果は0になります:javascriptのコードを適用することができることを


編集:回答総件数

http://jsbin.com/kimaxojufe/1/edit?css,js,console,output

+0

変換行列を読んで、行列値と現在の境界矩形でいくつかの計算を行います。 – Teemu

+2

スーパーハッキーhttp://jsbin.com/sivojuluvo/1/edit?js,console,output –

+0

興味深いことに、あなたが答えとしてそれを置くと、私はそれをアップヴォートするでしょう。それは_hacky_ですが、結果が常にすべてのブラウザの 'matrix'または' matrix3d'である場合はそれほど多すぎません。 –

答えて

7

は、要素上とDOMツリーまでの任意の変換を考慮せずに要素の位置を取得します:

var el = element, 
offsetLeft = 0, 
offsetTop = 0; 

do{ 
    offsetLeft += el.offsetLeft; 
    offsetTop += el.offsetTop; 

    el = el.offsetParent; 
} while(el); 

変換を考慮せずに要素の位置を取得し、それに適用されるが、DOMを任意の変換を追いつい木。

変換を元に戻すことができます。
最初にtransform-origin0,0,0に設定し、変換(スケール、回転)幅をtranslate(50%,50%) ... translate(-50%, -50%)に囲む必要があります。 は、ここでの例で、
変更することを:私たちはgetComputedStyleで返される行列は()が含まれていないためのもの変換起源で行うことを行う必要があり

transform: scale(2) rotate(45deg) translate(20px); 
transform-origin: 50% 50%; //default value 

transform: translate(50%, 50%) scale(2) rotate(45deg) translate(-50%,-50%) translate(20px); 
transform-origin: 0 0 0; 

に。本当に理由は分かりません。私はそれがこの記事の範囲を超えてだと思うので、私は数学の一部を説明しています

function parseTransform(transform){ 
    //add sanity check 
    return transform.split(/\(|,|\)/).slice(1,-1).map(function(v){ 
     return parseFloat(v); 
    }); 
} 

function convertCoord(transformArr, x, y, z){ 
    //add sanity checks and default values  

    if(transformArr.length == 6){ 
     //2D matrix 
     //need some math to apply inverse of matrix 
     var t = transformArr, 
      det = t[0]*t[3] - t[1]*t[2]; 
     return { 
      x: ( x*t[3] - y*t[2] + t[2]*t[5] - t[4]*t[3])/det, 
      y: (-x*t[1] + y*t[0] + t[4]*t[1] - t[0]*t[5])/det 
     } 
    } 
    else /*if (transformArr.length > 6)*/{ 
     //3D matrix 
     //haven't done the calculation to apply inverse of 4x4 matrix 
    } 
} 

var elRect = element.getBoundingClientRect(), 
    st = window.getComputedStyle(element), 

    topLeft_pos = convertCoord(
       parseTransform(st.transform), 
       elRect.left, 
       elRect.top, 
       st.perspective 
    );  

その後、あなたはこのコードを使用することができます。それでも他の場所でそれを説明できますか(別の質問かもしれませんか?)。

+0

トランスフォームを元に戻すのはあまりにも面倒ですが、最初のソリューションは完全かつ効率的に機能します。 –

+0

私はあなたの質問を正しく理解していない、私はあなたが要素の変換を元に戻したいと思ったが、もしあれば親の変換を元に戻したくないと思った。私は2つのソリューションの違いを少し説明するために私の答えを更新しました。 – Ghetolay

+0

それは大きな曖昧さかもしれない。タイトルには "gBCR without any(any)transforms"と書かれていましたが、本文は1つのトランスフォームを元に戻しただけの例でした。 •このため、私は["roundup"](http://jsbin.com/kimaxojufe/1/edit?css,js,console,output)を作成して、すべての可能な状況を含めます。 •あなたの最初の解決策は、私の_title質問_(すべての場合)を解決します。ベンジャミンはワンレベル変換のみを解決します(すべてのケースで) –

1

私はゲトレイの答えが気に入っていました。私はそれを使用しましたが、ループを回避することでもう少しパフォーマンスが向上しました。

私はドラッグ可能なタグクラウドを持っています。トランスフォームを使用してドラッグ位置を更新する必要がありますが、元の位置(変形なし)を記録しておく必要があります。

前の回答は、offsetParentsをループすることを提案しました。私の場合、多くの場合、タグは変換されますが、コンテナは変換されません。したがって、最初のoffsetParentを取得してgetBoundingClientRect()を使用するだけです。ループを維持する必要はありません。私はこれを行うそれを解決しました:

var el = element; 
var parentRect = element.offsetParent.getBoundingClientRect(); 
var offsetLeft = parentRect.left + element.offsetLeft; 
var offsetTop = parentRect.top + element.offsetTop; 
+0

右に見えません。出力は8でなければなりませんが、36です。http://jsbin.com/nufusupeji/edit?js,console,output –

+0

'transformed.getBounding ...'を使用しています。 'transformed.offsetParent.getBounfing 'を使う必要があります。 .. '。そして、この場合、親オフセットはボディの間に相対位置のラッパーがないので、このメソッドはボディマージンもカウントします。したがって、offsetParent.topは8で、element.offsetTopも8です。中間にラッパーがない場合は、element.offsetTopを使用できます。 – ezakto

+0

いくつかの変数と可能な望ましい動作(つまり、配置された親、ネストされたトランスフォーム)があり、あなたのものがまだ多くの場合オフになっているように見えるため、これをテストするために適切なテストスイートを作成しました。 http://jsbin.com/kimaxojufe/1/edit?css,js,console,outputあなたは一見を見て、必要な変更を加えることができますか? –

関連する問題