Daily Code Challenge
Day 1 - Dragon Fire

jQuery mouse move and click events




This script shows how to use jQuery to fire functions when triggered by mouse events.

The Markup

The only elements you need

What it does

The draggable <img/> element needs an id so we can select it. The draggable="false" parameter is used to disable the standard browser functionality of dragging images.

The fire <img/> element is really only there so we can preload the gif. Set to display: none so we cant see it initially.
What it looks like

<img src="images/dragon.gif" id="dragon" draggable="false"/>
<img src="images/fire.gif" class="fire" style="display:none"/>
                        

The CSS

Making it look good

What it does

Both #dragon and .fire need position: absolute; in order to be placed in the correct spot on the DOM.

#dragon needs a higher z-index than .fire for correct layering.

I tend to use z-index: 9999; to make sure it is the top most element.
What it looks like

#dragon {
    position:absolute;
    z-index:9999
}
.fire {
    position:absolute;
    z-index:9990
}

                        

The jQuery

Where all the magic happens

What it does

First, we need to set some global variables.
gl is for global event tracking.
w is the window element.
fireShooter is our interval variable for repeative firing.
mouseStillDown is boolean (true/false) to know if we should still be firing.

Next, we define a function for our mouse movement on the window element (w).
gl = e; updates the global event variable.
#dragon's CSS positioning is updated with the global client x & y offsets. 'top' : gl.clientY - 90 + w.scrollTop() sets the top value of #dragon to the y position of the mouse minus 90px (due to where the dragon's head is in the gif) then we add the window scroll top offset so we can scroll the page without the dragon moving. code>'left' : gl.clientX - 50 sets the left value of #dragon to the x position of the mouse minus 50px (due to where the dragon's head is in the gif).

Then, we define the function to make the magic happen.
if( !mouseStillDown ) { return; } checks to see if the mouse is not being pressed. return stops the function execution.
If the mouse is still being pressed, define the image element being added (ele).
Define the image source and class with src: "images/fire.gif", class: "fire".
Append the new image element to the body with $('body').append(ele);
The image needs to know where to be placed, apply css in the same manner we did with #dragon. However, mind the offsets based on image size.
Each appended image gets animated with animate({'top': "-=20px"}, 700); which moves the fire image up 20 pixels over 700 ms. The fire needs to go away at a certain point, so we use setTimeout to slowly fadeOut the image then .remove() it.

Finally, we need to bind the mouse events appropriately.
Binding to #dragon, img, body makes sure that we fire out function regardless of what is clicked. mousedown sets mouseStillDown to true and using setInterval to call fireShooterFun every 10 ms. mouseup sets mouseStillDown to false and stops firing function.
What it looks like

var gl,
    w = $(window),
    fireShooter,
    mouseStillDown = false;

w.mousemove(function(e){
    gl = e;
    $('#dragon').css({
        'top': gl.clientY - 90 + w.scrollTop(),
        'left': gl.clientX - 50
    });
});

function fireShooterFun(){

    if( !mouseStillDown ) { return; }

    if(mouseStillDown) {

        var ele = $('<img/>',
        {
            src: "images/fire.gif",
            class: "fire"
        });

        $('body').append(ele);

        ele.css({
            'top': gl.clientY - 40 + w.scrollTop(),
            'left': gl.clientX - 40
        }).animate({
            'top': "-=20px"
        }, 700);

        setTimeout(function(){
            ele.fadeOut('slow',function(){
                $(this).remove();
            });
        },700);
    }
}

$('#dragon, img, body').mousedown(function(e){
    mouseStillDown = true;
    fireShooter = setInterval( function(){fireShooterFun()}, 10);

}).mouseup(function(e){
    mouseStillDown = false;
});