Positionオブジェクト(6)
absolutizeメソッド および relativizeメソッド
【抜粋】 absolutize: function(element) { element = $(element); if (element.style.position == 'absolute') return; Position.prepare(); var offsets = Position.positionedOffset(element); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px';; element.style.left = left + 'px';; element.style.width = width + 'px';; element.style.height = height + 'px';; }, relativize: function(element) { element = $(element); if (element.style.position == 'relative') return; Position.prepare(); element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; }
結論から言うと、この二つのメソッドは、あまり有用ではないと思います。汎用メソッドとしては不可解な部分が多く、なにかの処理に特化したメソッドのように見えます。
なぜPosition.prepareメソッドを呼び出しているのかが分かりづらいですし*1、要素のスタイルtop、leftの取得にElement.getStyleメソッドを使わずに、要素のstyleプロパティを使用しているのもおかしな気がします。また、relativizeメソッドは単独では使用できません。absolutizeメソッドで処理された要素のみを扱うことができます(それ以外を扱うとエラーが発生する)。
どうも、script.aculo.usのDraggableオブジェクト用じゃないかと思うのですが・・・。
要素の高さ・幅の取得にclientWidth、clientHeightプロパティを使用していますが、Netscape7.1では要素のclientWidth、clientHeightプロパティは無効なため、機能しません。ここはoffsetWidth、offsetHeightを使うべきのような。
私の拙い例を見るよりも、script.aculo.usのサンプルを見てもらったほうが理解が早いと思います。
script.aculo.us - downloads
最新バージョンscriptaculous-js-1.6.4.zipをダウンロードしてください(prototype.js(v1.5.0rc1)が含まれています)。解凍したら、「scriptaculous-js-1.6.4\test\run_functional_tests.html」をブラウザで開いてください。左フレームの「dragdrop4_test」をクリックすると右フレームにテストページが表示されます。下にある「Ghost effect」という要素がドラッグ可能です。このとき、処理中でabsolutizeメソッドとrelativizeメソッドが使用されています*2。処理を簡単に説明すると、
- クリック時、要素の複製を作成して直前に挿入。absolutizeで処理。要素を半透明化。
- ドロップ時、要素の複製を削除。relativizeで処理。
- 元の位置までアニメーションさせて移動。要素の半透明化を解除。
ということをしています。
ポイントは「元の位置までアニメーションさせて移動」させたい、ということのような気がします。このため、relativizeメソッド処理時にドラッグ後の位置で表示させているわけです。
特性を理解すれば使えるかもしれませんが・・・。
cumulativeOffsetメソッド(Konqueror、Safari、KHTML用上書き)
【抜粋】 // Safari returns margins on body which is incorrect if the child is absolutely // positioned. For performance reasons, redefine Position.cumulativeOffset for // KHTML/WebKit only. if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { Position.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return [valueL, valueT]; } }
UAがKonqueror、Safari、KHTMLの場合、cumulativeOffsetを上書きしています。コメントのおおよその意味は以下。
「Safariでは、body要素の子要素がposition:absolute;である場合、body要素のマージンは正確でない。パフォーマンス上の理由から、Position.cumulativeOffsetを再定義を、KHTML/WebKit系UAの場合のみ行う。」
要素のoffsetParentがbodyで、position:absolute;のとき、offsetTop、offsetLeftの累積を停止するという処理が入っています。この場合、body要素がさらにoffsetParent、offsetTop、offsetLeftを持つが、これは余計である、ということでしょうか。
すみません、環境がないので確認できないです・・・。
*1:多分、スタイルposition変更時のウィンドウスクロール量の変化を考慮していると思いますが
*2:scriptaculous-js-1.6.4\src\dragdrop.js 336行目、400行目