How to make an Animate up to the mouse position and after starting to follow the mouse?

Asked

Viewed 1,196 times

0

I have the following code

$(document).ready(function(){
    var LeftInicial = $('.MarcadorMenu').css('left');
    var WidthInicial = $('.MarcadorMenu').css('width');
    $('.CorpoMenuHead').hover(function(){
        $('.CorpoMenuHead').bind('mousemove', function(e){
            var Tam1 = $('.MenuHead').innerWidth();
            var Tam2 = $('.CorpoMenuHead').innerWidth();
            $('.MarcadorMenu').css({
                left: e.pageX -(Tam1-Tam2)/2-50,
                width: '100px'
            });
        });
    },function(){
        $('.MarcadorMenu').animate({
            left: LeftInicial,
            width: WidthInicial
        });
    });
});

With that when I put the cursor over the div CorpoMenuHead o a div MarcadorMenu "jumps" to that position to start following the mouse pointer

Would it be possible to get div reached the location of the mouse with a animate so it doesn’t have such a sudden and somewhat ugly effect?

Fiddle

I made a change and got closer than I’d like

Fiddle updated

I think now the question to solve this bug is "is there any way to verify if there is an event running?" ex: will be called the animate and while that animate does not need to be executed he will not start the command .css() in my else

  • Rodrigo, this is what you seek? http://jsfiddle.net/4GDm6/

  • Hi Rodrigo, is it so that the div goes to the mouse position (your cursor)? Or so that it goes to an element through which passed the mouse?

  • Good morning, it’s for him to go to the cursor... @carlosrafaelgn

  • @Sergio is basically this, however I wanted him not to have this delay to follow the cursor, the moment I put the mouse on top the first time is plausible to have a delay, but after he is already in the position of the cursor I would like it to be "in real time"

  • Hi Rodrigo! Serves a suggestion without jQuery?

  • @carlosrafaelgn serves any js that work :D

Show 1 more comment

2 answers

2

Rodrigo, here is my suggestion:

Example: http://jsfiddle.net/853qb/

$(document).ready(function () {
    var marcador = $('.MarcadorMenu');
    var LeftInicial = marcador.css('left');
    var WidthInicial = marcador.css('width');
    var entrou = false;
    $('.CorpoMenuHead').on('mousemove', function (event) {
        console.log(entrou, event.pageX);
        if (!entrou) {
            marcador.stop().animate({
                left: (event.pageX - LeftInicial.replace('px', '')) + 'px'
            },500, function(){
                entrou = true;
            });
        }else{
        marcador.css('left', (event.pageX - LeftInicial.replace('px', '')) + 'px');
        }

    });

    $('.MenuHead').on('mouseleave', function () {
        entrou = false;
        marcador.stop().animate({
            left: LeftInicial,
            width: WidthInicial
        });
    });
});

I switched to mouseenter/mouseleave. In this case I only use mouseleave once Mousemove already confirms that the mouse is on the element. The problem with the Hover is that it triggers too many events.

I also took bind() from inside the move, the risk is that the DOM is adding Event handlers every time the Hover fires, and that is not desirable.

I added the .stop() in the animations so that they don’t wait around for each other but stop and start again if a new Animate is triggered.

I used . on() instead of . bind() as jQuery’s own indication for versions after 1.7

  • Well, that’s the closest answer I’ve seen so far than I wish, the only problem is a delay the moment the mouse enters the div, since it keeps stopping the Animate as the mouse moves, the ideal would be that it continued the Animate however that the final value was the current position of the rest cursor was exactly as it should work

2


This code performs a smooth movement of div until the cursor, every time the cursor enters the menu area, and the cursor is "far" from the div.

Since the div reaches the cursor, it follows it directly (at least while the cursor has not left the menu).

When the cursor goes back inside the menu, the smooth movement occurs if it is "far" from the div, otherwise it just takes the div down to the cursor.

The concept of "far" and how smooth the movement of div, can be configured only by changing the coefficients indicated along the code.

The code below is summarized in this fiddle.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="pt-br">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Mouse</title>
    <script type="text/javascript">
        //
        //Alerta! Não foi testado com IE8-, só com IE9+. Os outros browsers estão OK!
        //
        var ultX = 0, ultT, percentualConcluido = 0, meuDiv, meuMenu, meuMenuLeft,
            alcancouOCursor = true, primeiraVez = true;
        //prepara algumas funções necessárias para animação, temporização e localização
        if (!window.requestAnimationFrame) {
            window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                window.oRequestAnimationFrame ||
                window.msRequestAnimationFrame ||
                function (callback) { return window.setTimeout(function () { return callback(+new Date()); }, 1000 / 60); });
        }
        if (!Date.now)
            Date.now = function () { return (+new Date()); };
        function elementLeft(element) {
            //https://github.com/carlosrafaelgn/GraphicalFilterEditor/blob/master/Common.js
            var left;
            if (element.getBoundingClientRect) {
                left = element.getBoundingClientRect();
                left = left.left + window.pageXOffset;
            } else {
                left = 0;
                while (element) {
                    left += element.offsetLeft;
                    element = element.offsetParent;
                }
            }
            return left;
        }

        function meuMenu_MouseEnter(e) {
            //armazena a coordenada X (relativa a meuMenu) para animar
            ultX = e.pageX - meuMenuLeft;
            //não deixa meuDiv passar do fim de meuMenu
            if (ultX > (meuMenu.clientWidth - 45))
                ultX = (meuMenu.clientWidth - 45);
            //
            //esse bloco if/else pode ser removido, caso desejado...
            //
            if (primeiraVez) {
                primeiraVez = false;
            } else {
                //determina se realmente é necessário iniciar uma animação,
                //conforme a distância entre o cursor e meuDiv
                var meuDivLeft = elementLeft(meuDiv) - meuMenuLeft;
                if (Math.abs(meuDivLeft - ultX) < 50)
                    return true;
            }
            //reinicia a animação
            alcancouOCursor = false;
            ultT = Date.now();
            requestAnimationFrame(animaDiv);
            return true;
        }

        function meuMenu_MouseMove(e) {
            //armazena a coordenada X (relativa a meuMenu) para animar
            ultX = e.pageX - meuMenuLeft;
            //não deixa meuDiv passar do fim de meuMenu
            if (ultX > (meuMenu.clientWidth - 45))
                ultX = (meuMenu.clientWidth - 45);
            if (alcancouOCursor) {
                //não há necessidade de animar, apenas define a posição
                meuDiv.style.left = ultX + "px";
            }
            return true;
        }

        //essa função vai animar a posição do div de uma forma não muito brusca
        function animaDiv() {
            //ver comentário dentro da função document_MouseMove
            if (alcancouOCursor)
                return;

            //Date.now() retorna um tempo em milissegundos, por isso divide por 1000
            var agora = Date.now(), deltaT = (agora - ultT) / 1000, meuDivLeft, velocidade;
            ultT = agora;
            requestAnimationFrame(animaDiv);

            //obtém a coordenada left de meuDiv, relativo a meuMenu
            meuDivLeft = elementLeft(meuDiv) - meuMenuLeft;

            //é possível ajustar a velocidade alterando os coeficientes aqui!!!
            velocidade = Math.abs(ultX - meuDivLeft) * 5;
            if (velocidade > 2000)
                velocidade = 2000;
            else if (velocidade < 100)
                velocidade = 100;

            //anima o div, conforme a velocidade
            if (meuDivLeft < ultX) {
                meuDivLeft += velocidade * deltaT;
                if (meuDivLeft >= ultX) {
                    alcancouOCursor = true;
                    meuDivLeft = ultX;
                }
            } else {
                meuDivLeft -= velocidade * deltaT;
                if (meuDivLeft <= ultX) {
                    alcancouOCursor = true;
                    meuDivLeft = ultX;
                }
            }
            meuDiv.style.left = meuDivLeft + "px";
        }
    </script>
</head>
<body>
    <!-- apenas um exemplo -->
    <div id="meuMenu" style="position: relative; height: 45px; background: #00f; color: #fff;">
        <span>Item A</span> | <span>Item B</span> | <span>Item C</span> | <span>Item D</span>
        <div id="meuDiv" style="position: absolute; width: 45px; height: 5px; bottom: 0px; background: #fff;"></div>
    </div>
    <script type="text/javascript">
        meuMenu = document.getElementById("meuMenu");
        meuDiv = document.getElementById("meuDiv");
        //armazena left de meuMenu, para evitar ficar utilizando a função elementLeft toda a vez
        meuMenuLeft = elementLeft(meuMenu);
        //trata o evento do movimento do cursor na fase de captura
        meuMenu.addEventListener("mouseenter", meuMenu_MouseEnter, true);
        meuMenu.addEventListener("mousemove", meuMenu_MouseMove, true);
    </script>
</body>
</html>
  • Exactly that :D, but what a code stick the.O

  • hehehehe is just to remove any external dependencies ;)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.