Positionオブジェクト(4)

offsetParentメソッド

【抜粋】
  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

引数の要素のoffsetParentを返却するメソッド、なのですが。正直、何故存在するのか分かりません^^; 要素にoffsetParentが存在しないケースを想定しているようなのですが、どういう時に該当するのかが分からず。。。そもそも、他のメソッドの多くが要素のoffsetParentプロパティを使用しているのに対し、このoffsetParentメソッドを使用しているのは後述cloneメソッド一箇所だけです。更に、「スタイルpositionがstaticでない」というのを返却要素の条件にしているのも変です(無指定の場合も該当してしまう)。

・・・謎です><;

例は省かせてください・・・。

withinメソッド

【抜粋】
  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

引数xをページ上X座標、引数yをページ上Y座標とし、引数elementがこれを含んでいるかを判定するメソッド。includeScrollOffsetsプロパティがtrueの場合(スクロール要素がドラッガブル要素を含んでいる場合等)は、次のwithinIncludingScrolloffsetsメソッドに処理を任せます。

コメントの意味は

「overlapメソッドを使用する場合、(このメソッドを使用して)X/Y座標の組を取得すること」

X/Y座標はoffsetプロパティに格納されます。これを後述overlapメソッドで使用しています。

例は「Positionオブジェクト(1) - Backstage of theater.js」のincludeScrollOffsetsプロパティを参照してください。

withinIncludingScrolloffsetsメソッド

【抜粋】
  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

includeScrollOffsetsプロパティがtrueの場合(スクロール要素がドラッガブル要素を含んでいる場合等)、withinメソッドから処理を任されるメソッド。withinメソッドと機能はほぼ一緒ですが、こちらは要素のスクロール量を考慮して判定します(要素のスクロール分は加算し、ページのスクロール分は除いています)。

前述したように、使用前にdeltaXおよびdeltaYプロパティを設定する必要があるため、prepareメソッドを呼び出さなければなりません。

こちらも例は「Positionオブジェクト(1) - Backstage of theater.js」のincludeScrollOffsetsプロパティを参照してください。

overlapメソッド

【抜粋】
  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

引数elementの要素に対する、ある座標の「相対位置」(具体的な意味は後述)を返却するメソッド。「ある座標」はY座標がycompプロパティ、X座標がxcompプロパティ。この値のセットは前述withinメソッドで行われます。コメントに「【訳】直前にwithinメソッドが呼び出される必要がある」と書かれているのはこのためです。また、offsetプロパティにも引数elementの要素の座標が設定されている必要があり、これもwithinメソッドで設定されます。

よって、以下のように使用します。

【参考】使用例 要素elemに対する座標(x,y)の「相対位置」取得
  Position.within($('elem'), x, y);
  var ox = Position.overlap('horizontal', $('elem')); //横の相対位置
  var oy = Position.overlap('vertical', $('elem'));   //縦の相対位置

「相対位置」というのは私が付けた表現です^^; 以下のような値を意味します。

横位置(horizontal)
要素に対する座標の位置 左外側 左端 内側 右端 右外側
返却値 1より上 1 0より上〜1未満 0 0未満
縦位置(vertical)
要素に対する座標の位置 上外側 上端 内側 下端 下外側
返却値 1より上 1 0より上〜1未満 0 0未満

http://www.imgsrc.co.jp/~kuriyama/prototype/prototype.js.html#Position」から表現を借りると、「最初の矩形と重なり、左上の座標が指定された座標であるような矩形を考える。返される値は、二番目の矩形が十分大きいとして幅や高さが重なっている(最初の矩形からみた)割合となる。 」つまり、座標(x,y)をposition:left、topとする無限に大きい要素を考えると、引数の要素elementと重なっている割合になる、ということです(座標が要素から外れるとそうともいえないのですが^^;)。だからoverlapという名前になっているようです。

名前だけみると、要素と要素の重なり割合を返却するメソッドのように思えますが、そうではないです・・・。その算出には利用できますが。

【例】
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 //EN">
<html>
<head>
<title></title>
<style>
<!--
.mark{
  background-color:red;
  width:50px;
  height:50px;
}
#mark0{
  background-color:blue;
  position:absolute;
  top:100px;
  left:100px;
  width:200px;
  height:200px;
}
#mark1{
  position:absolute;
  top:50px;
  left:50px;
}
#mark2{
  position:absolute;
  top:100px;
  left:100px;
}
#mark3{
  position:absolute;
  top:200px;
  left:200px;
}
#mark4{
  position:absolute;
  top:300px;
  left:300px;
}
#mark5{
  position:absolute;
  top:350px;
  left:350px;
}
#test{
  position:absolute;
  top:320px;
  left:50px;
}

-->
</style>
<script language="javascript" src="prototype.js" charset="utf-8"></script>
<script>
<!--
function test(){
  var str = "";
  var offset;
  
  offset = Position.cumulativeOffset($('mark1'));
  Position.within($('mark0'), offset[0], offset[1]);
  str += "mark0 & mark1 (horizontal) : "
      + Position.overlap('horizontal', $('mark0')) + "</br>";
  str += "mark0 & mark1 (vertical) : "
      + Position.overlap('vertical', $('mark0')) + "</br>";
  
  offset = Position.cumulativeOffset($('mark2'));
  Position.within($('mark0'), offset[0], offset[1]);
  str += "mark0 & mark2 (horizontal) : "
      + Position.overlap('horizontal', $('mark0')) + "</br>";
  str += "mark0 & mark2 (vertical) : "
      + Position.overlap('vertical', $('mark0')) + "</br>";

  offset = Position.cumulativeOffset($('mark3'));
  Position.within($('mark0'), offset[0], offset[1]);
  str += "mark0 & mark3 (horizontal) : "
      + Position.overlap('horizontal', $('mark0')) + "</br>";
  str += "mark0 & mark3 (vertical) : "
      + Position.overlap('vertical', $('mark0')) + "</br>";

  offset = Position.cumulativeOffset($('mark4'));
  Position.within($('mark0'), offset[0], offset[1]);
  str += "mark0 & mark4 (horizontal) : "
      + Position.overlap('horizontal', $('mark0')) + "</br>";
  str += "mark0 & mark4 (vertical) : "
      + Position.overlap('vertical', $('mark0')) + "</br>";

  offset = Position.cumulativeOffset($('mark5'));
  Position.within($('mark0'), offset[0], offset[1]);
  str += "mark0 & mark5 (horizontal) : "
      + Position.overlap('horizontal', $('mark0')) + "</br>";
  str += "mark0 & mark5 (vertical) : "
      + Position.overlap('vertical', $('mark0')) + "</br>";

  Element.update('view', str);
}
//-->
</script>
</head>
<body>
<div id="mark0"></div>
<div id="mark1" class="mark">MARK1</div>
<div id="mark2" class="mark">MARK2</div>
<div id="mark3" class="mark">MARK3</div>
<div id="mark4" class="mark">MARK4</div>
<div id="mark5" class="mark">MARK5</div>
<div id="test">
<button onclick="test();">TEST</button>
<div id="view"></div>
</div>
</body>
</html>

要素の左上座標取得にcumulativeOffsetメソッドを使用しました。

【上記例の実行結果】
mark0 & mark1 (horizontal) : 1.25
mark0 & mark1 (vertical) : 1.25
mark0 & mark2 (horizontal) : 1
mark0 & mark2 (vertical) : 1
mark0 & mark3 (horizontal) : 0.5
mark0 & mark3 (vertical) : 0.5
mark0 & mark4 (horizontal) : 0
mark0 & mark4 (vertical) : 0
mark0 & mark5 (horizontal) : -0.25
mark0 & mark5 (vertical) : -0.25