2016-03-19 4 views
2

があります!私は#drag要素が滑らかに動くことに問題があります。mousemoveイベントのJavascript移動要素60 FPS requestAnimationFrame

私はこの記事を見て:http://www.html5rocks.com/en/tutorials/speed/animations/#debouncing-mouse-events

それがいることを言った:移動要素がのMouseMoveイベントがそう

あまりを解雇されたときmousemoveイベントでの問題は、私は彼らの方法を使用してみてください」:使用します​​boolean checkingライブアクションのために、このフィドルで

外観:。https://jsfiddle.net/5f181w9t/

HTML:

<div id="drag">this is draggable</div> 

CSS:

#drag {width:100px; height:50px; background-color:red; transform:translate3d(0, 0, 0); } 

JS:

var el    = document.getElementById("drag"), 
    startPosition = 0, // start position mousedown event 
    currentPosition = 0, // count current translateX value 
    distancePosition = 0, // count distance between "down" & "move" event 
    isMouseDown  = false; // check if mouse is down or not 

function mouseDown(e) { 
    e.preventDefault(); // reset default behavior 
    isMouseDown  = true; 
    startPosition = e.pageX; // get position X 
    currentPosition = getTranslateX(); // get current translateX value 
    requestAnimationFrame(update); // request 60fps animation 
}  

function mouseMove(e) { 
    e.preventDefault(); 
    distancePosition = (e.pageX - startPosition) + currentPosition; // count it! 
} 

function mouseUp(e) { 
    e.preventDefault(); 
    isMouseDown = false; // reset mouse is down boolean 
} 

function getTranslateX() { 
    var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]); 

    return translateX; // get translateX value 

} 

function update() { 
    if (isMouseDown) { // check if mouse is down 
     requestAnimationFrame(update); // request 60 fps animation 
    } 
    el.style.transform = "translate3d(" + distancePosition + "px, 0, 0)"; 
    // move it! 
} 

el.addEventListener("mousedown", mouseDown); 
document.addEventListener("mousemove", mouseMove); 
document.addEventListener("mouseup", mouseUp); 

が、これはそれをaccompolishedするための正しい方法は何ですか?

私のコードに何が問題なのですか?

おかげ

+0

あなたのコードに何が問題なのですか?コメントするためにKaiidoに感謝します。 – Kaiido

+0

本当に?私は、本当に滑らかではないように感じる? –

+0

私のFFでは完全に滑らかですが、クロムで少し点滅していますが、これは本当ですが、確かにこの赤色のためです。 – Kaiido

答えて

4

問題はmouseDownイベントリスナーでrequestAnimationFrame()を使用していることです。マウスがクリックされたときではなく、マウスが動いたときにディスプレイを更新したいので、mouseMoveイベントリスナーですべての更新を行う必要があります。したがって、update関数のisMouseDown条件のすべての変数を更新する必要があります。私は次のようにコードを修正することをお勧めします。

HTML

<div id="drag">this is draggable</div> 

CSS

#drag { 
width:100px; 
height:50px; 
background-color:red; 
transform:translateX(0); 
} 

JS

var el    = drag, 
    startPosition = 0, // start position mousedown event 
    currentPosition = 0, // count current translateX value 
    distancePosition = 0, // count distance between "down" & "move" event 
    isMouseDown  = false, // check if mouse is down or not 
    needForRAF  = true; // to prevent redundant rAF calls 

function mouseDown(e) { 
    e.preventDefault(); // reset default behavior 
    isMouseDown  = true; 
    currentPosition = getTranslateX(); // get current translateX value 
    startPosition = e.clientX; // get position X 
}  

function mouseMove(e) { 
    e.preventDefault(); 
    distancePosition = (e.clientX - startPosition) + currentPosition; // count it! 
    if (needForRAF && isMouseDown) { 
    needForRAF = false;   // no need to call rAF up until next frame 
    requestAnimationFrame(update); // request 60fps animation 
    }; 
} 

function mouseUp(e) { 
    e.preventDefault(); 
    isMouseDown = false; // reset mouse is down boolean 
} 

function getTranslateX() { 
    var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]); 
    return translateX; // get translateX value 
} 

function update() { 
    needForRAF = true; // rAF now consumes the movement instruction so a new one can come 
    el.style.transform = "translateX(" + distancePosition + "px)";// move it! 
} 

el.addEventListener("mousedown", mouseDown); 
document.addEventListener("mousemove", mouseMove); 
document.addEventListener("mouseup", mouseUp); 

をそれをチェック10

+0

なぜ、mouseMove()もそれを呼び出すと、アニメーションフレームをupadte()内で再帰的に要求しますか?また、フレームごとに複数のmouseMoveイベントがある場合は、前のリクエストをキャンセルする必要はありませんか? –

+0

@Ilpo Oksanenはい、あなたは正しいと思われます。この特定のケースでは、requestAnimationFrameの擬似再帰的な供給は冗長です。ディスプレイを更新する私の標準的なアプローチから見た残った鉱山の見落としです。指摘していただきありがとうございます。私はそれに応じて修正します。 – Redu

+2

あなたは依然として多くの呼び出しをrequestAnimationFrameに積み重ねています。これらの呼び出しはすべて同時に実行されます。ブール値を使用して、このフレームでイベントを処理したかどうかを確認し、rAFを呼び出す前にそれを発生させ、rAFコールバックでfalseに設定します。すでにtrueに設定されている場合は、rAFを呼び出しないでください。 – Kaiido

1

コードはすでに正常に動作しているはずです。しかし、ここでそれを行うための別の方法です:

あなたが確認する必要がありますが、一つだけ​​呼び出しは、フレームごとに見ていきましょう、ラグと減少が発生する可能性があり、そうでない場合update()次のrepaintで複数回呼び出されます、あなたのfps。これを行うには、要求されたフレームを保存し、各フレームに既にフレームが整列しているかどうかを確認するために、それぞれのmousemoveイベントチェックを行います。存在する場合は、cancelAnimationFrameを使用してキャンセルし、新しいリクエストを行うことをお勧めします。このようにupdate()は、ブラウザが変更をレンダリングできるだけの頻度で呼び出されます(ほとんどのブラウザではI.E.60fps)。lastUpdateCallnullでない場合にも、もう一度​​を呼び出すことができませんでしたが、それはあなたがアニメーションのフレームコール外event火災、またはアニメーションが遅れるだろうたびに距離を計算する必要があると思います意味します

function mouseDown(e) { 
    e.preventDefault(); // cancel default behavior 
    isMouseDown  = true; 
    startPosition = e.pageX; // get position X 
    currentPosition = getTranslateX(); // get current translateX value 
} 

var lastUpdateCall=null; 
function mouseMove(e){ 
    if(isMouseDown){ //check if mousedown here, so there aren't any unnecessary animation frame requests when the user isn't dragging 
     e.preventDefault(); // You probably only want to preventDefault when the user is actually dragging 

     if(lastUpdateCall) cancelAnimationFrame(lastUpdateCall); //if an animation frame was already requested after last repaint, cancel it in favour of the newer event 

     lastUpdateCall=requestAnimationFrame(function(){ //save the requested frame so we can check next time if one was already requested 
      distancePosition = (e.clientX - startPosition) + currentPosition; // Do the distance calculation inside the animation frame request also, so the browser doesn't have to do it more often than necessary 
      update(); //all the function that handles the request 
      lastUpdateCall=null; // Since this frame didn't get cancelled, the lastUpdateCall should be reset so new frames can be called. 
     }); 
    } 
} 

function update(){ 
    el.style.transform = "translateX(" + distancePosition + "px)";// move it! 
} 

あなたのマウスの背後で最大20ms。どちらの方法も問題ありません。

関連する問題