Javascript sprite rotation animation on click - javascript

I'm trying to figure out how to create a rotating image effect using a sprite sheet in javascript. What I'm trying to do:
Two buttons:
Left button: Rotate 15 frames to the left.
Right button: Rotate 15 frames to the right.
I realize that there are jquery plugins that would allow me to easily do this, but I want to try it from scratch. Beyond the general idea, I don't know where to proceed. Any tips would be greatly appreciated.

Check out this jsFiddle to see a working example
Based on your question, it sounds like you're trying to learn how to animate a sprite and not actually rotate a single image. If so, here is how you would animate a sprite. Note: this uses an image of a man running. In your question, you asked about a rotating image effect. In either case, you are simply looking at different slice of a sprite and then animation is solely dependent on the sprite. As long as your sprite displays a rotating image then the image will appear to rotate.
If you need a plugin to actually rotate an image, see here.
JavaScript
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.js" type="text/javascript"></script>
<script type="text/javascript">
var imgWidth = 240;
var imgHeight = 296;
var ximages = 6;
var yimages = 5;
var currentRow = 0;
var currentColumn = 0;
function MoveSprite(dir) {
if (dir == "left") {
currentColumn--;
if (currentColumn < 0)
{
currentColumn = ximages -1;
if (currentRow == 0) {
currentRow = yimages - 1;
}
else {
currentRow--;
}
}
}
else {
currentColumn++;
if (currentColumn == ximages) {
currentColumn = 0;
if (currentRow == yimages - 1) {
currentRow = 0;
}
else {
currentRow++;
}
}
}
$("#txtRow").val(currentRow);
$("#txtColumn").val(currentColumn);
$("#spritesheet").css("backgroundPosition", -imgWidth * currentColumn + "px " + -imgHeight * currentRow + "px");
}
</script>
HTML
<button onclick="MoveSprite('left');return false;">Move Left</button><button onclick="MoveSprite('right');return false;">Move Right</button>
<div id="spritesheet"></div>
CSS
<style type="text/css">
#spritesheet {
height: 296px;
width:240px;
background-image:url('walking_spritesheet.png');
}
</style>
Sample Sprite (1440x1480):

If you are familiar with MovieClip in flash, I made a library that gives you a similar interface in javascript. https://github.com/wolthers/SpriteClip.js

you could try
css3 (rotation) ex : http://antimatter15.com/misc/rotatedgooglecss3.html
canvas (javascript) ex : https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas
svg (dom or other libs) ex : http://www.svgbasics.com/rotate.html , http://raphaeljs.com/reference.html

Related

Using requestAnimationFrame instead of setInterval

I ran across an issue where my code worked just fine in Chrome but in Safari it began to stutter. I read somewhere that "Safari caps intervals at 1000ms and then adds its own exponential delay, doubling every iteration." That being said I am trying to change my code to work both on Safari and Chrome using requestAnimationFrame but am having issues wrapping my head around the subject.
Essentially what I am trying to do is ease a div across a page with each click using requestAnimationFrame instead of setInterval.
Any guidance would be appreciated.
Here is the Javascript:
let progressAvatar = document.querySelector('.box');
progressAvatar.addEventListener('click', checkClick);
var clicks = 0;
function checkClick() {
clicks += 1;
if (clicks == 1) {
startingLocationOfAvatar();
} else if (clicks == 2) {
locationOfAvatar();
}
}
function startingLocationOfAvatar() {
let speed = 10;
// Initial location of Avatar
let pos = 0;
// Ending location of Avatar
let progressBarWidthDivided = 53;
let id = setInterval(frame, speed);
function frame() {
if (pos == progressBarWidthDivided) {
clearInterval(id);
} else {
pos++;
progressAvatar.style.marginLeft = pos + "px";
}
}
}
// Move the avatar based on its previous location
function locationOfAvatar() {
let speed = 10;
// Pos becomes last location of movePixels
let pos = 53;
let id = setInterval(frame, speed);
// movePixels adds last location by its new location
let movePixels = pos * 2;
function frame() {
if (pos == movePixels) {
clearInterval(id);
} else {
pos++;
progressAvatar.style.marginLeft = pos + "px";
}
}
}
Here is the Html:
<div class="box">
</div>
Here is the Css:
.box {
height: 100px;
width: 100px;
background-color:red;
}
Lastly here is a jsfiddle:
Move Div Across Screen
I will let experts answer, but as a 2 weeks coding noob this is what i know, you can compile all individual animation functions into a grand Animation function. And call that function with request animation frame. Trying to make a sensible game myself, i have totally given up on manipulating css values and coding in pure Javascript.
Note, dependent where you will put your mini-functions - the photos/graphical items will display either on top or under eachother visually.
It should look something like this:
function drawEverything(){
context.clearRect(0,0,width,height);
context.save();
draw();
draw1();
draw2();
context.restore();
requestAnimationFrame(drawEverything);
}
requestAnimationFrame(drawEverything);

Tooltip with full screen image

First of all, sorry, because probably this is kind of a long shot. My coding knowledge is very limited and everything I always do is based on tutorials, and codes I see around.
Basically, I created this site, with a list of galleries and institutions. When one hovers on the name of the venue there's a tooltip with image that comes out and follows the mouse. I really liked this effect but realized it is not working that well on small screens such like the laptop ones.
Is there any easy way to modify this js so I can have an image coming out as full screen (covering the whole screen) fixed and responsive?
<script language="javascript" type="text/javascript">
var tooltipSpans = document.getElementsByClassName('tooltip-span');
window.onmousemove = function (e) {
var x = e.clientX,
y = e.clientY,
i, l = tooltipSpans.length;
for(i = 0; i < l; i++) {
tooltipSpans[i].style.top = (y + 20) + 'px';
tooltipSpans[i].style.left = (x + 20) + 'px';
}
};
</script>
Thank you so much in advance!!!
You could set the image as background image of your body-tag. And set following styling to it:
#container {
background-repeat: no-repeat;
background-size: contain;
background-attachment: fixed;
}
Here the javascript changes:
window.onmousemove = function (e) {
var i, l = tooltipSpans.length;
for(i = 0; i < l; i++){
var backgroundimageSRC = tooltipSpans[i].children.getAttribute("src");
document.getElementById("conatiner").style.backgroundImage = "url("+ backgroundimageSRC +")";
}
}
Maybe you have to change a little bit. But I think it will do the magic.

Sliding puzzle (web game) - transitions

I'm making a sliding puzzle (something like this) using HTML, CSS and JavaScript/jQuery.
Everything works fine, but I want to add a sliding transition each time a slide moves.
The code works based on the following logic:
12, 16 or 48 <div>s are created (depending on the level of difficulty).
A background-image is assigned to all of them, and cropped accordingly to simulate a "piece" of the original image.
They all have a class of image, and also piece<number>, where <number> is the number of the tile. The last tile (piece12, piece16 or piece48) also has a class of voidBlock, that removes the background-image. This is the empty tile that permits the ones directly next to it to move into its place. All the other tiles have an additional class, imgBlock.
When one of the tiles that are next to the voidBlock is clicked, it exchanges classes with the voidBlock. For example, if we were to click piece6, which happens to be next to the voidBlock(let's say the difficulty is set to easy, and thus voidBlock is piece12), this would happen:
The original voidBlock changes its piece12 class to piece6.
The original voidBlock changes its voidBlock class to imgBlock.
The original piece6 changes its piece6 class to piece12.
The original piece6 changes its imgBlock class to voidBlock.
After that, a draw() function is called; it sets the background-position of each tile, depending on its piece number.
As you might have guessed by now, none of the <div>s actually move. They remain still as the background-position of their background-image changes through their classes.
Although I do have some experience in programming (namely in Python and Java), web development in general is very new to me. I have tried various methods of transitioning, but the best thing I could come up with was to have the background image move each time a tile moved (which is just weird and unintuitive).
My question is, thus: is there any way to have an animation/transition of the tiles sliding each time that they move?
Code
(the lines that are commented out have nothing to do with the question)
CSS:
Part of the main.css file:
.image {
background-image: url(/Users/user/puzzle-test/img/image001.jpg);
width: 200px;
height: 200px;
display: inline-block;
vertical-align: top;
margin: 10px 10px 10px 10px;
}
.voidBlock {
background-image: none;
}
.imgBlock {
background-image: url(/Users/user/puzzle-test/img/image001.jpg);
}
JavaScript/jQuery:
The <div> click handler:
var clickHandler = function() {
var voidPosX = $(".voidBlock").css("left");
var voidPosY = $(".voidBlock").css("top");
voidPosX = parseInt(voidPosX.substring(0, voidPosX.length-2));
voidPosY = parseInt(voidPosY.substring(0, voidPosY.length-2));
var posX = $(this).css("left");
var posY = $(this).css("top");
posX = parseInt(posX.substring(0, posX.length-2));
posY = parseInt(posY.substring(0, posY.length-2));
if((voidPosX == posX - finalWidth) && (voidPosY == posY)){
posX -= finalWidth;
voidPosX += finalWidth;
move($(this));
}else if((voidPosX == posX + finalWidth) && (voidPosY == posY)){
posX += finalWidth;
voidPosX -= finalWidth;
move($(this));
}else if((voidPosY == posY - finalHeight) && (voidPosX == posX)){
posY -= finalHeight;
voidPosY += finalHeight;
move($(this));
}else if((voidPosY == posY + finalHeight) && (voidPosX == posX)){
posY += finalHeight;
voidPosY -= finalHeight;
move($(this));
}
}
The move function (used in the click handler) (h and v are the horizontal and vertical dimensions of the puzzle):
function move(element) {
//moveCounter++;
var temp = element.attr("class").split(" ");
for(var i = 0; i < temp.length; i++){
if(temp[i].substring(0, 5) == "piece"){
var pieceNum = temp[i].substring(5);
}
}
element.addClass("tempBlock1");
$(".voidBlock").addClass("tempBlock2");
element.filter(".tempBlock1").addClass("piece"+(h*v));
element.filter(".tempBlock1").removeClass("piece"+pieceNum);
element.filter(".tempBlock1").addClass("voidBlock");
element.filter(".tempBlock1").removeClass("imgBlock");
$(".voidBlock").filter(".tempBlock2").addClass("piece"+pieceNum);
$(".voidBlock").filter(".tempBlock2").removeClass("piece"+(h*v));
$(".voidBlock").filter(".tempBlock2").addClass("imgBlock");
$(".voidBlock").filter(".tempBlock2").removeClass("voidBlock");
$(".tempBlock1").removeClass("tempBlock1");
$(".tempBlock2").removeClass("tempBlock2");
draw();
}
The draw function (the numbers 800 and 600 represent the dimensions of the image):
function draw() {
//var imgSelect = $("input[type='radio'][name='bgImage']:checked").val();
var j = 1;
for(var pY = 0; pY > -600; pY -= finalHeight){
for(var pX = 0; pX > -800; pX -= finalWidth){
$(".piece"+j).css("background-position", pX+"px "+pY+"px");
//$(".piece"+j).css("background-image", "url(/Users/user/puzzle-test/img/"+imgSelect+".jpg)");
//$(".piece"+j).find(".helpNum").text(j);
j++;
}
}
//$(".move").text("Moves: " + moveCounter);
$(".voidBlock").css("background-image", "none");
//$(".grid").find("img").attr("src", "img/"+imgSelect+".jpg");
//$(".image:not(.voidBlock)").css("cursor", "pointer");
//$(".voidBlock").css("cursor", "default");
}
Finally, the <div>s are created by the shuffle function, like this (pieces is a shuffled array of the puzzle pieces, basically used to tell where to position each tile):
// DRAW
for(var i = 0; i < pieces.length; i++){
// HTML
var el = "<div class=\"image piece"+(pieces[i])+"\"><p class=\"helpNum\"></p></div>";
$(".grid").append(el);
$(".piece"+(h*v)).addClass("voidBlock");
}
// CSS div positioning
var j = 0;
for(var pY = 0; pY > -600; pY -= finalHeight){
for(var pX = 0; pX > -800; pX -= finalWidth){
$(".piece"+pieces[j]).css({left: pX, top: pY});
j++;
}
}
I finally solved it thanks to #BillyNate 's answer, which was to set the position property of the <div>s to absolute, then move them by changing the top and left properties.

How to reverse direction of moving div once it reaches side of screen?

I have an absolutely positioned div that uses the jQuery .animate function to move horizontally from the right to left of the screen.
My problem is that once the div reaches the far left side, it continues and eventually disappears from the screen. How do you make it so that once the div reaches the left side, it will reverse and start going to the right? (and then vice versa so that the right side won't continue going right, but goes left again once it reaches the end)
HTML:
<div class="container">
<div class="block"></div>
</div>
CSS:
.block {
float:right;
position:absolute;
right:100px;
width:100px;
height:100px;
background:red;
}
jQuery:
$('.block').click(function() {
$(this).animate(
{"right": "+=100px"},"slow");
});
Here is my JSFiddle: https://jsfiddle.net/ebkc9dzL/
Thank you I really appreciate the help!
may be you should try like this:
$('.block').click(function() {
var leftPosition = $(this).position();
if (leftPosition.left > 100) {
$(this).animate({"right": "+=100px"},"slow");
} else {
$(this).animate({"right": "-=100px"},"slow");
}
});
when the element is close to the border the if..else part of the code will reverse the direction.
Here is a fiddle, try to click on the red box to get an idea on how it works:
https://jsfiddle.net/dimitrioglo/ebkc9dzL/14/
Working fiddle: https://jsfiddle.net/ebkc9dzL/19/
You need to have a variable outside the click function that will tell you the direction of the animation, so that once inside the click function you can calculate the location of the animated object using getBoundingClientRect() (mdn reference).
Then, if object is moving left and its left distance is less than its own width, you need to move it only enough so that it comes to the edge. If it's AT the edge (left is zero), you need to change the direction.
If it's moving right and its right distance is less than its own width, you need to move it only enough (calculated by window.innerWidth - 100, since 100 is width of your object) so that it comes to the edge. If it's AT the right edge, you need to change direction.
Changing direction in object you pass to jQuery's animate function is a simple matter of adding or subtracting from its "right" attribute.
var direction = "+";
$('.block').click(function() {
var obj = {},
distance = 100,
rect = this.getBoundingClientRect();
if(direction=="+"){
if(rect.left>0 && rect.left < 100)
distance = rect.left;
else if(rect.left<=0)
direction = "-";
}
else {
if(rect.right >(window.innerWidth-100) && rect.right+1<window.innerWidth)
distance = (window.innerWidth-rect.right);
else if(rect.right+1 >=window.innerWidth){
direction = "+";
}
}
obj = {"right": direction+"="+distance.toString()+"px"}
$(this).animate(obj,"slow");
});
Here you go: jsFiddle.
The new javascript is as follows:
var goLeft = true;
$('.block').click(function() {
var animateDist = 100;
var distLeft = $(this).position().left;
var distRight = window.innerWidth - distLeft;
if (goLeft) {
if (distLeft < 100) {
animateDist = "+="+distLeft+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = false;
} else {
$(this).animate(
{"right": "+=100px"},"slow"
);
}
} else {
if (distRight < 100) {
animateDist = "-="+distRight+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = true;
} else {
$(this).animate(
{"right": "-=100px"},"slow"
);
}
}
});
This isn't perfect, you need to adjust your internal window width to match the parent container, but this is enough to get you in the right direction.
Good luck!
Try this code:
var sign = [ "+" , "-" ];
var signPosition = 0;
var maxOffset = $(".block").offset().left;
$('.block').click(function() {
if ($(this).offset().left < 100) {
signPosition = 1;
} else if ($(this).offset().left == maxOffset) {
signPosition = 0;
}
$(this).animate(
{"right": sign[signPosition] + "=100px"},"slow");
});
The variable sign is the array that contains the directions in which the element might move, the variable signPosition contains the position of the direction currently in use, the variable maxOffset contains the starting position.
Hope this will help you.

Creating a floating box which stays within a div

I'm trying to create a div 'floater' which acts similar to a fixed div (stuck in a specific position regardless of scrolling), but when it hits the boundaries of the div it is within, it stops being fixed.
When the scrollbar is at the top, it should have the div placed at 0 within the containing div (positioned say 100 pixels from the top) and when the scrollbar reaches the bottom, it should prevent the floater from going outside the container. The height of the floater would be static, but the container height would be dynamic.
I've seen this type of this all over the place, but can't figure out how to find a good example for it.
I'd like to avoid jQuery if possible, as I imagine it should only require some simple JavaScript to determine the current position relative to the div it is within.
Thank you.
Okay folks, here is a complete solution. I've only tested this in Firefox and IE, but it should work across the board (I think). This is straight JavaScript and jQuery is not used. The first JS function makes sure the height returned works in various browsers.
Edit - I improved on this, see below.
<html>
<head>
<style type="text/css">
* {margin:0;padding:0;}
#header {height:300px;width:100%;background:#888;}
#main {height:800px;width:70%;background:#eee;float:left;}
#side {width:30%;height:auto;background:#ddd;float:left;position:relative;}
#floater {height:400px;width:90%;background:#dcd;top:0px;position:absolute;}
#footer {height:300px;width:100%;background:#888;clear:both;}
</style>
<script>
function getPageY() {
var height = 0;
if(typeof(window.pageYOffset) == 'number') {
height = window.pageYOffset;
}
else if(document.body && document.body.scrollTop) {
height = document.body.scrollTop;
}
else if(document.documentElement && document.documentElement.scrollTop) {
height = document.documentElement.scrollTop;
}
return height;
}
onload=function() {
window.onscroll = scroll;
function scroll() {
ybox.value = "this: "+getPageY();
var f = document.getElementById("floater");
var y = getPageY()-300; // minus header height
var divh = document.getElementById("main").offsetHeight;
if (divh > 400) { // greater than floater height
divh -= 400; // minus floater height
if (y < 0) y = 0;
else if (y > divh) y = divh;
f.style.top = y+"px";
}
}
}
</script>
</head>
<body>
<div id="header"></div>
<div id="main"></div>
<div id="side"><div id="floater">Float Content<br />
<input name="ybox" id="ybox"></div></div>
<div id="footer"></div>
</body>
</html>
This works, but with images it is extremely jumpy. I modified it to use a fixed position when it should be stuck in a position. Replace the three matching lines with this for a smoother result:
if (y < 0) {y = 0;f.style.position = "absolute";}
else if (y > divh) {y = divh;f.style.position = "absolute";f.style.top = divh+"px";}
else {f.style.position = "fixed";f.style.top = 0;}
I've implemented this and its pretty good. http://net.tutsplus.com/tutorials/html-css-techniques/creating-a-floating-html-menu-using-jquery-and-css/. But this is done using jquery only. Ill let you know if icome across any links with just plain javascript.

Categories