How JavaScript animation works (conclusion)

Source: Internet
Author: User

Original Author: Steven Riche

Released on: July 15, February 18, 2014

Link: http://code.tutsplus.com/tutorials/javascript-animation-that-works-part-4-of-4--net-35263

Translation: Zi Yi --------- perform JavaScript to the end

Split two sentences

After more than a month of hard work, it was terrible to add things together. The blog has been suspended for about a month. From today on, everything is new. You can just do it yourself.

Bytes ----------------------------------------------------------------------------------------------

In the first article of this series, we introduced how to create simple and cross-browser interactive animations on the web with genie. In the second article, we made animation work. In the third article, we sorted out our code and prepared for its use on the web.


Introduction
Now, in our last part, we will build an event handler, instead of making a response when the robot clicks the button, and our robot will move along with the mouse on the screen. In this process, we will discuss cross-browser code and the touch screen is also available.
If you look at our last code, you can see that although our code runs well (and there are multiple robots at the same time ), however, there is no simple way to run the code.
Event Handler
The event handler is a command that tells certain code to run when a specific event is triggered. For example, you can run 'my _ function () 'whenever a user clicks 'div' with "my_div 'id. Or, when you move the mouse over 'my _ osther_div ', 'My _ osther_function ()' executes
Theoretically, this is a simple and intuitive idea. Unfortunately, it will be a bit confusing when you get involved in different browsers. Ideally, Each browser will interpret the code in the same way, and developers will only write the code once to let every user see the same result. In the real world, different browsers may have different names for the same thing (* cough ** cough * IE ), so sometimes, if you want to run a piece of code in all browsers, it may feel like a group of cats are grazing. Recently, the situation has become very good. Chrome, Firefox, Safgari, and Opera have very similar responses to the Code, and IE9 and IE10 have become more standard-compliant than earlier versions. And almost no one is using IE7 or IE6. Therefore, our code will make the event handler work in modern browsers and IE8
This is one reason to use a powerful JavaScript library, such as jQuery. JQuery has completed all the cross-browser tests for you. Therefore, you only need to enter a command that jQuery will translate behind the scenes to make it available in every browser. In addition, many jQuery commands are more intuitive and simple than the core JavaScript commands.
However, because of my stubbornness, and this is a learning opportunity, we will continue to work hard on this difficult road, using only JavaScript to do it all without relying on any libraries.
Page Interaction
The first step is to determine how to interact with the page. When I move the mouse in the stage area, I want all the robots to move in the direction of the mouse. I want them to stop moving when they arrive at the mouse or place the mouse on them. If you place the mouse on them, I want them to jump up. Finally, when the mouse leaves the stage, I want them to stop running. We will start from binding events to the RobotMaker function.
stage.addEventListener('mousemove', stage_mousemove_listener, false);robot.addEventListener('mouseover', robot_mouseover_listener, false);stage.addEventListener('mouseout', stage_mouseout_listener, false);

Therefore, in the above Code, we have said that whenever a user moves the mouse over the stage element, a function called stage_mousemove_listener () will be triggered (note, in the command, we do not include parameters ). Similarly, when you move the mouse over the robot element, robot_mouseover_listener () is triggered. When you move the mouse from the stage, stage_mouseout_listenr () is triggered ()
Unfortunately, we mentioned earlier that IE8 and earlier versions use different (but similar) commands to do the same thing. Therefore, we need to perform a test, so that you can know which command your browser will understand and execute the corresponding method.
if (stage.addEventListener){ // We will test to see if this command is available  stage.addEventListener('mousemove', stage_mousemove_listener, false);  robot.addEventListener('mouseover', robot_mouseover_listener, false);  stage.addEventListener('mouseout', stage_mouseout_listener, false);} else { // If not, we have to use IE commands  stage.attachEvent('onmousemove', stage_mousemove_listener);  robot.attachEvent('onmouseover', robot_mouseover_listener);  stage.attachEvent('onmouseout', stage_mouseout_listener); }

You may notice that the command formats are very similar, but there are still some major differences: one is 'addeventlistener ', the other is 'attachevent', and the other is 'mousemove ', however, the other is called 'onmousemove '. One requires the third parameter, while the other uses only two. Obfuscation of any one of them will cause the command to not be executed. This series of things will make you use your head to hit the wall. Unfortunately, in order to have cross-browser capabilities, this is not the final code we need to write.
Listener Function
Next, we will compile the listener function. It starts by writing functions triggered by users' moving on the stage. Because it is a mousemove listener, It is triggered every time the mouse moves in the stage area (which means it will be triggered multiple times in one second) this function compares the location of the robot with the location of the mouse and allows the robot to act on the camera. Each time a function is triggered, it detects whether the robot needs to continue to run in the same direction or change to another action. Therefore, it needs to be written as follows.

// Inside of RobotMaker // We will need to introduce a few extra variables to trackvar mouseX; // For tracking horizontal mouse positionvar running_dir = ''; // For tracking if (and where) robot is currently runningvar stageOffset; // For tracking the position of the stage function stage_mousemove_listener(e){     // Find the horizontal position of the mouse inside of the stage ...    // That position will be saved in 'mouseX'     // Then we compare 'mouseX' to the robot, and decide if we need to run differently  if (((robot.offsetLeft + (15 * run_speed)) < (mouseX - robot.offsetWidth)) && running_dir !== 'r' && (!jump_timer || jump_timer === undefined)){     // If the mouse is in the stage and to the right of the robot, make run right, if not already    running_dir = 'r';    clearTimeout(run_timer);    run_r(1, robot.offsetLeft);  } else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== 'l' && (!jump_timer || jump_timer === undefined)) {    // If the mouse is in the stage and to the left of the robot, make run left, if not already    running_dir = 'l';    clearTimeout(run_timer);    run_l(1, robot.offsetLeft);  } else if ((robot.offsetLeft < mouseX) && ((robot.offsetLeft + robot.offsetWidth) > mouseX) && running_dir !== '' && (!jump_timer || jump_timer === undefined)) {    // If the mouse is in the stage and over a robot, stop and clear running_dir    running_dir = '';    clearTimeout(run_timer);    if (face_right){      robot.style.backgroundPosition = "0px 0px";    } else {      robot.style.backgroundPosition = "0px -50px";    }  }  // If none of the above is true, then we let our current behavior continue}


In the above function, once we find mouseX, we can compare it with the location of the robot. If needed, we can trigger or stop different running functions. Unfortunately, identifying mouseX is tricky because the mouse position is a different thing for different browsers. Complex and lengthy explanations to avoid identifying mouseX, just as inspired by the excellent Quirksmode blog (a great place to learn more advanced JavaScript technologies ):
Function stage_mousemove_listener (e) {var posX = 0; if (! E) {var e = window. event;} if (e. pageX) {posX = e. pageX;} else if (e. clientX) {posX = e. clientX + document. body. scrollLeft + document.doc umentElement. scrollLeft;} mouseX = posX-stageOffset. xpos; // we found mouseX !}

We have a parameter called e in the function. Although we didn't pass anything to it, it is an event listener and we will automatically have a variable named e, this variable stores event-related information, such as mouse data. However, different browsers have different storage methods, so we have to add an additional step.
We finally find the posX (the horizontal coordinate of the mouse on the page) and subtract the value from the page on the left of the stage (stored in stageOffset. xpos), and then find the mouseX, which gives the distance between the mouse and the left border of the stage, and we can use it to directly communicate with the robot. offsetLeft for comparison. According to the layout, the stage may be located in different locations. We also need to find the precise pixel offset of the stage and store it in stageOffset. Fortunately, we can use a clever trick to find the absolute offset of the element. This function comes from the Vishal Astik blog.
// In RobotMaker, var x = 0; var y = 0; function find_stage_offset (el) {x = el. offsetLeft; y = el. offsetTop; el = el. offsetParent; while (el! = Null) {x = parseInt (x) + parseInt (el. offsetLeft); y = parseInt (y) + parseInt (el. offsetTop); el = el. offsetParent;} return {xpos: x, ypos: y };} var stageOffset = find_stage_offset (stage );

Now we have written the mousemove listener, and the rest will be much easier. For the robot mouseover listener, we only need to check whether the robot is jumping. If not, stop running to make it skip.
function robot_mouseover_listener(){  if (!jump_timer || jump_timer === undefined){    clearTimeout(run_timer);    jmp(true, robot.offsetTop);  }}

The mouseout listener is also very simple. We only need to reset some variables we use to track the robot. If the robot does not jump, it will set the robot as a standing genie.
function stage_mouseout_listener(){  mouseX = undefined;  running_dir = '';  if (!jump_timer || jump_timer === undefined){    clearTimeout(run_timer);    if (face_right){      robot.style.backgroundPosition = "0px 0px";    } else {      robot.style.backgroundPosition = "0px -50px";    }  }}

Animation Functions
This time, the running and jumping functions have not changed much. We just added some tracking variables running_dir, and removed the declaration that the robot was about to hit a strong one (because this is the redundancy of the mouseout function, and added some code to the Skip function, which is used for re-detection, if the mouse is still in the stage, does the robot need to start running when it falls after the jump. The following is the final code (quite large ):
function run_r(phase, left){  face_right = true;  running_dir = 'r';  if ((left + (15 * run_speed)) < (mouseX - robot.offsetWidth)){ // if mouse is to the right, run             left = left + (15 * run_speed);    robot.style.left = left+"px";    switch (phase){      case 1:        robot.style.backgroundPosition = "-40px 0px";        run_timer = setTimeout(function(){run_r(2, left);}, 200);        break;      case 2:        robot.style.backgroundPosition = "-80px 0px";        run_timer = setTimeout(function(){run_r(3, left);}, 200);        break;      case 3:        robot.style.backgroundPosition = "-120px 0px";        run_timer = setTimeout(function(){run_r(4, left);}, 200);        break;      case 4:        robot.style.backgroundPosition = "-80px 0px";        run_timer = setTimeout(function(){run_r(1, left);}, 200);        break;    }} else if ((left + (15 * run_speed)) < mouseX) { // if mouse if above, stop    robot.style.backgroundPosition = "0px 0px";    running_dir = '';} else { // if mouse is to the left, run left    running_dir = 'l';    run_l(1, robot.offsetLeft);  }} function run_l(phase, left){  face_right = false;  running_dir = 'l';  if (mouseX < robot.offsetLeft - (15 * run_speed)){ // if mouse is to the left, run         left = left - (15 * run_speed);    robot.style.left = left+"px";    switch (phase){      case 1:        robot.style.backgroundPosition = "-40px -50px";        run_timer = setTimeout(function(){run_l(2, left);}, 200);        break;      case 2:        robot.style.backgroundPosition = "-80px -50px";        run_timer = setTimeout(function(){run_l(3, left);}, 200);        break;      case 3:        robot.style.backgroundPosition = "-120px -50px";        run_timer = setTimeout(function(){run_l(4, left);}, 200);        break;      case 4:        robot.style.backgroundPosition = "-80px -50px";        run_timer = setTimeout(function(){run_l(1, left);}, 200);        break;    }} else if (mouseX < (robot.offsetLeft + robot.offsetWidth - (15 * run_speed))){ // if mouse overhead, stop    robot.style.backgroundPosition = "0px -50px";    running_dir = '';} else { // if mouse is to the right, run right    running_dir = 'r';    run_r(1, robot.offsetLeft);  }}                 function jmp(up, top){  running_dir = '';  if (face_right){    robot.style.backgroundPosition = "-160px 0px";  } else {    robot.style.backgroundPosition = "-160px -50px";  }   if (up && (robot.offsetTop > (20 * (1 / jump_height)))){    top = top - (top * 0.1);    robot.style.top = top+"px";    jump_timer = setTimeout(function(){jmp(up, top);}, 60);  } else if (up) {    up = false;    jump_timer = setTimeout(function(){jmp(up, top);}, 60);  } else if (!up && (robot.offsetTop < 115)){    top = top + (top * 0.1);    robot.style.top = top+"px";    jump_timer = setTimeout(function(){jmp(up, top);}, 60);  } else {    robot.style.top = "120px";    if (face_right){      robot.style.backgroundPosition = "0px 0px";    } else {      robot.style.backgroundPosition = "0px -50px";    }         jump_timer = false;    if (mouseX !== undefined){      if (((robot.offsetLeft + (15 * run_speed)) < (mouseX - robot.offsetWidth)) && running_dir !== 'r'){         // make run right, if not already        running_dir = 'r';        clearTimeout(run_timer);        run_r(1, robot.offsetLeft);      } else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== 'l') {        // make run left, if not already        running_dir = 'l';        clearTimeout(run_timer);        run_l(1, robot.offsetLeft);      }    }  }}

Now we completely rewrite the function and work well across browsers ...... Unless the browser has a touch screen input. We still need to move forward so that our robots can run on any device. Because the touch screen is somewhat different, we need to perform some additional encoding on the event listener.
Support Touch Screen
We need to develop some new rules for the touch screen: on stage, when the screen is touched anywhere, the robot will go to that point until the fingertip leaves. If you touch a robot, the robot jumps up. In short, we need to add some additional event processors for the previous functions, and we will write the code in this way: No matter when the RobotMaster function is called, it will automatically run.
(function (){  if (stage.addEventListener){    stage.addEventListener('touchstart', stage_mousemove_listener, false);    stage.addEventListener('touchmove', stage_mousemove_listener, false);    stage.addEventListener('touchend', stage_mouseout_listener, false);             stage.addEventListener('mousemove', stage_mousemove_listener, false);    robot.addEventListener('mouseover', robot_mouseover_listener, false);    stage.addEventListener('mouseout', stage_mouseout_listener, false);  } else {    stage.attachEvent('onmousemove', stage_mousemove_listener);    robot.attachEvent('onmouseover', robot_mouseover_listener);    stage.attachEvent('onmouseout', stage_mouseout_listener);  }})();

We do not need to worry about the format of the touch event in IE8. If any device does not support touch, it will ignore these listeners. Now, if the browser has the touch function, We need to update the stage_mousemove_listener () function to have different performances ,.
function stage_mousemove_listener(e){   /* * First we check if this is a touch screen device (if it has e.touches) */  if (e.touches){    e.preventDefault(); // we want to cancel what the browser would usually do if touched there    // If the touch was within the boundaries of the stage...    if ((e.touches[0].pageX > stageOffset.xpos)     && (e.touches[0].pageX < (stageOffset.xpos + stage.offsetWidth))    && (e.touches[0].pageY > stageOffset.ypos)    && (e.touches[0].pageY < (stageOffset.ypos + stage.offsetHeight))){      // we set the mouseX to equal the px location inside the stage      mouseX = e.touches[0].pageX - stageOffset.xpos;     } else { // if the touch was outside the stage, we call the mouseout listener      stage_mouseout_listener();    }         /*     * If the touch is directly on the robot, then we stop the run timer and make the robot jump     */    if ((e.touches[0].pageX > robot.offsetLeft) && (e.touches[0].pageX < (robot.offsetLeft + robot.offsetWidth))    && (e.touches[0].pageY > (stageOffset.ypos + stage.offsetHeight - robot.offsetHeight))    && (e.touches[0].pageY < (stageOffset.ypos + stage.offsetHeight))    && (!jump_timer || jump_timer === undefined)){      clearTimeout(run_timer);      jmp(true, robot.offsetTop);    }       } else { // Finding the mouseX for non-touch devices...    // All of our non-touch device code here  }}

You may notice that in the RobotMaker function, there is no "door" here, but because all the code we call with Event Handlers is in RobotMaker, so we no longer need them. For our stages and characters, you need to add a little special CSS for the touch device so that they will not try to cut or paste any image when the user's fingers hold them down.
#stage, .character {  -webkit-user-select: none;}

Finally, we declare that all robots use the same format at the bottom of the page. When the page is loaded, the event processor makes the code run automatically-This method also prevents robot objects from becoming global variables. Therefore, throughout the script, the only global variable we have is the RobotMaker () function.
(function(){  var j = RobotMaker(document.getElementById('j'), 1, 1);  var j2 = RobotMaker(document.getElementById('j2'), .8, 5);  var j3 = RobotMaker(document.getElementById('j3'), 1.1, .5);  var j4 = RobotMaker(document.getElementById('j4'), .5, .75);})();

View the final result in glory
Summary
I strongly recommend that you learn all the code (and all comments), and you can download four robot genie here.
Happy animation!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.