マウスカーソルの下の要素をオーバーレイで効率的に強調表示するにはどうすればよいですか?

javascript jquery optimization performance
マウスカーソルの下の要素をオーバーレイで効率的に強調表示するにはどうすればよいですか?

まだhttps://stackoverflow.com/questions/4698259/jquery-highlight-element-under-mouse-cursor [この質問]に答えようとしており、最終的に解決策を見つけたと思いますが、実行が遅すぎます。

var $div = $('')
    .css({ 'border': '1px solid red', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

$('body *').live('mousemove', function(e) {
    var topElement = null;
    $('body *').each(function() {
        if(this == $div[0]) return true;
        var $elem = $(this);
        var pos = $elem.offset();
        var width = $elem.width();
        var height = $elem.height();
        if(e.pageX > pos.left && e.pageY > pos.top
            && e.pageX < (pos.left + width) && e.pageY < (pos.top + height)) {
            var zIndex = document.defaultView.getComputedStyle(this, null).getPropertyValue('z-index');
            if(zIndex == 'auto') zIndex = $elem.parents().length;
            if(topElement == null || zIndex > topElement.zIndex) {
                topElement = {
                    'node': $elem,
                    'zIndex': zIndex
                };
            }

        }
    });
    if(topElement != null ) {
        var $elem = topElement.node;
        $div.offset($elem.offset()).width($elem.width()).height($elem.height());
    }
});

基本的に、ページ上のすべての要素をループし、カーソルの下の一番上の要素を見つけます。

クワッドツリーなどを使用してページをセグメント化し、ループをより高速に実行する方法はありますか?

  12  12


ベストアンサー

_
クワッドツリーなどを使用してページをセグメント化し、ループをより高速に実行する方法はありますか?
_

少し戻って、問題がどれほど小さいか、そして挑戦するほど複雑な答えが使用されることを認識してください。

ここで必要なことは、強調表示のために4つの要素を作成することです。 それらは*空の正方形*を形成するため、マウスイベントは自由に起動できます。 これは、http://jsbin.com/xusira/1/ [overlay example]で作成したものに似ています。

違いは、必要なのは4つの要素のみで(サイズ変更マーカーは不要)、4つのボックスのサイズと位置が少し異なる(赤い枠を模倣する)ことです。 次に、デフォルトで実際の最上位要素を取得するため、イベントハンドラで「event.target」を使用できます。

*別のアプローチ*は、exra要素を非表示にし、 `elementFromPoint`を取得し、計算してから戻すことです。

彼らは光よりも速いです、私はあなたに伝えることができます。 アインシュタインでさえ同意します:)

  • 1。)elementFromPointオーバーレイ/境界線-
    [Demo1]* FF needs v3.0+

var box = $("").css({
  display: "none", position: "absolute",
  zIndex: 65000, background:"rgba(255, 0, 0, .3)"
}).appendTo("body");

var mouseX, mouseY, target, lastTarget;

// in case you need to support older browsers use a requestAnimationFrame polyfill
// e.g: https://gist.github.com/paulirish/1579671
window.requestAnimationFrame(function frame() {
  window.requestAnimationFrame(frame);
    if (target && target.className === "outer") {
        box.hide();
        target = document.elementFromPoint(mouseX, mouseY);
    }
    box.show();

    if (target === lastTarget) return;

    lastTarget = target;
    var $target = $(target);
    var offset = $target.offset();
    box.css({
        width:  $target.outerWidth()  - 1,
        height: $target.outerHeight() - 1,
        left:   offset.left,
        top:    offset.top
    });
});

$("body").mousemove(function (e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    target = e.target;
});

” ” ‘

  • 2。)マウスオーバー境界-[Demo2]*

var box = new Overlay();

$("body").mouseover(function(e){
  var el = $(e.target);
  var offset = el.offset();
  box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);
});​

/**
 * This object encapsulates the elements and actions of the overlay.
 */
function Overlay(width, height, left, top) {

    this.width = this.height = this.left = this.top = 0;

    // outer parent
    var outer = $("").appendTo("body");

    // red lines (boxes)
    var topbox    = $("").css("height", 1).appendTo(outer);
    var bottombox = $("").css("height", 1).appendTo(outer);
    var leftbox   = $("").css("width",  1).appendTo(outer);
    var rightbox  = $("").css("width",  1).appendTo(outer);

    // don't count it as a real element
    outer.mouseover(function(){
        outer.hide();
    });

    /**
     * Public interface
     */

    this.resize = function resize(width, height, left, top) {
      if (width != null)
        this.width = width;
      if (height != null)
        this.height = height;
      if (left != null)
        this.left = left;
      if (top != null)
        this.top = top;
    };

    this.show = function show() {
       outer.show();
    };

    this.hide = function hide() {
       outer.hide();
    };

    this.render = function render(width, height, left, top) {

        this.resize(width, height, left, top);

        topbox.css({
          top:   this.top,
          left:  this.left,
          width: this.width
        });
        bottombox.css({
          top:   this.top + this.height - 1,
          left:  this.left,
          width: this.width
        });
        leftbox.css({
          top:    this.top,
          left:   this.left,
          height: this.height
        });
        rightbox.css({
          top:    this.top,
          left:   this.left + this.width - 1,
          height: this.height
        });

        this.show();
    };

    // initial rendering [optional]
    // this.render(width, height, left, top);
}

18


最初に、 `$( ‘body *’)。live`を実行することは非常に良い考えだとは思いません。非常に高価なようです(マウスを動かすたびにブラウザがしなければならない計算の種類を考えてください)

とはいえ、ここではその側面を無視する最適化されたバージョンがあります

var $div = $('')
    .css({ 'border': '1px solid red', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

$('body *').live('mousemove', function(e) {
    var topElement = null;
    var $bodyStar = $('body *');
    for(var i=0,elem;elem=$bodyStar[i];i++) {
        if(elem == $div[0]) continue;
        var $elem = $(elem);
        var pos = $elem.offset();
        var width = $elem.width();
        var height = $elem.height();
        if(e.pageX > pos.left && e.pageY > pos.top && e.pageX < (pos.left + width) && e.pageY < (pos.top + height)) {
            var zIndex = document.defaultView.getComputedStyle(this, null).getPropertyValue('z-index');
            if(zIndex == 'auto') zIndex = $elem.parents().length;
            if(topElement == null || zIndex > topElement.zIndex) {
                topElement = {
                    'node': $elem,
                    'zIndex': zIndex
                };
            }

        }
    }
    if(topElement != null) {
        var $elem = topElement.node;
        $div.offset($elem.offset()).width($elem.width()).height($elem.height());
    }
});

将来の参考のために、パフォーマンスが必要な場合はjQueryのループメカニズムを使用しないでください。 関数呼び出しを行うときに発生する呼び出しスタックの開始は、実行する必要があるほとんどの反復操作にとって大きなオーバーヘッドであるため、これらはすべて、反復ごとの関数呼び出しを中心に構築されています。これは通常のループと比較して非常に遅いです。

エラーを修正し、要素を動的に挿入できるようにコードを更新しました。

1


タイトルとURLをコピーしました