2012-01-25 10 views
2

私はページを持っており、その上にウィジェットがいくつかあります。 2つの列があります。左(または右)にウィジェットがない場合、ウィジェットは自動的にリサイズされます。ページ全体のポイントで要素を取得します(表示されていなくても)

私はdocument.elementFromPoint(ウィジェットのオフセットを取得した後)を使用して、その横にウィジェットがあるかどうかを検出しています。

ただし、document.elementFromPointに問題があります。

指定されたポイントがドキュメントの表示範囲外の場合...結果はnullです。

要素がビューポート内にある場合にのみ機能します。どの要素が表示されていなくても特定の位置にあるかどうかをどのように検出できますか?

EDIT:ここでは例です:

Crappy Mockup

赤線でビューポート、および(赤書き込みと)グレーのボックスウィジェットD'S 元の位置(他のウィジェットDでありますページが読み込まれたときの位置です)。ページが読み込まれると、ウィジェットB、C、Dがチェックされ、オフセットが取得され、document.elementFromPointを使用して、ウィジェットAが正しいかどうかを確認します。ウィジェットAがその右にある場合、ウィジェットは半幅であり、全幅ではありません。

document.elementFromPointがビューポートの外にあるため、ウィジェットDは全角です。ビューセットの外にあってもウィジェットAがウィジェットDの右にあることをどのように検出できますか?

+0

あなたのコードが頻繁に実行されていない場合、あなたは 'html'または' body'要素を移動することができます要素がビューポート内で一時的になるように、左/右/上/下に移動します。別のオプション:比較する要素が分かっている場合は、 '$( 'selector').offset()'( '.top'と' .left')と '.height()' /'.outerHeight ) 'と' .width() '/'.outerWidth()'を使って要素の相対位置を計算します。 –

+1

@RobW:厄介なモックアップで私の問題を説明しようとしました。 –

+0

したがって、どの要素を互いに対してサイズ変更する必要があるのか​​知っていますか? –

答えて

4

次のコードは、要素の境界をxとyの2つのリストに保存します。次に、for-loopを使用して、指定されたオフセットから開始し、リスト内を移動することができます。答えの一番下に、実装が示されています。

// These arrays are going to contain many empty elements ;) 
var xAxis = []; 
var yAxis = []; 

// Our storage. Each element looks like: [$element, top, right, bottom, left] 
// Beware of cross-references! Deleted elements cannot be GCed if they're here! 
var allElements = []; 

/* 
* @param $elem jQuery object 
* @returns Object containing the jQuery object and the floored border offsets 
*/ 
function getBorders($elem) { 
    $elem = $elem instanceof jQuery ? $elem.first() : $($elem); 
    var offset = $elem.offset();   // Properties: top, left 

    var width = $elem.outerWidth();  // Includes padding, border. 
    var leftBorder = offset.left;   // Position of the left border ->| 
    var rightBorder = leftBorder + width; // Position of the right border |<- 

    var height = $elem.outerHeight();  // Includes padding, border 
    var topBorder = offset.top;   // Position of the top border _v_ 
    var bottomBorder = offset.top + height;// Position of the bottom border^

    // Turn all numbers in integers, so that they can be used as indexes 
    // for arrays 
    // See also: http://stackoverflow.com/a/8112802/938089 
    return { 
     $elem: $elem, 
     top: ~~topBorder, 
     right: ~~rightBorder, 
     bottom: ~~bottomBorder, 
     left: ~~leftBorder 
    }; 
} 

$('.widget').each(function() { 
    var $this = $(this); 

    var info = getBorders($this); 
    allElements.push(info); 
    // The positions are floored, so that they can be used as a quick reference 
    xAxis[info.left] = xAxis[info.right] = info; 
    yAxis[info.top] = yAxis[info.bottom] = info; 
}); 

作成されたリストを使用して、衝突する要素がないかどうかを確認できるようになりました。たとえば、次の関数を考えてみます。

function doesItCollide($elem) { 
    // WeakMaps are useful. For compatibility, I don't use them. 
    var info$elem = getBorders($elem); 
    // info$elem properties: $elem, top, right, bottom, left 
    // Y-oriented 
    for (var y=info$elem.top; y<yAxis.length; y++) { 
     var candidate = yAxis[y]; 
     // Not undefined, and not iself 
     if (candidate && candidate.$elem[0] !== info$elem.$elem[0]) { 
      // Check whether the element is inside the range 
      if (candidate.top >= info$elem.bottom && 
       candidate.bottom >= info$elem.bottom) continue; 
      // It's here, so the top/bottom are possibly in the same range 
      // Check whether the x-positions are also colliding 
      if (candidate.left >= info$elem.left && /* Left within range? */ 
       candidate.left <= info$elem.right || /* OR */ 
       candidate.right <= info$elem.right && /* Right within range? */ 
       candidate.right >= info$elem.left) { 
       return candidate; 
      } 
     } 
    } 
    return null; 
} 

例(デモ:http://jsfiddle.net/LtJsM/):

$('.widget').each(function() { 
    var $this = $(this); 
    var overlapping = doesItCollide($this); 
    if (overlapping) { 
     alert('Current element: '+this.className + 
      '\nColliding element: ' + overlapping.$elem[0].className); 
    } 
}); 
+0

ありがとう、少し調整する必要がありますが、要素の位置の配列は素晴らしいアイデアです:-) –

関連する問題