How to move around an image with javascript? - javascript

I'm developing a simple web quiz and using javascript, I would like to create an effect that displays a small image (1UP) that wanders around the "game deck" when users reach a specific level or score; user could gain an extra life simply clicking on it in time.
Do you know any Jquery plugin or javascript snippet to achieve an effect like this?

It's actually surprisingly easy to do this:
Create the element:
img = document.createElement('img');
Set its source:
img.src = "myimage.png";
Position it absolutely and such:
img.style.position = "absolute";
img.style.left = "50px";
img.style.top = "50px";
img.style.width = "50px"; // Make these match the image...
img.style.height = "50px"; // ...or leave them off
(Obviously, use whatever coordinates and size you want.)
You may want to make sure it appears above other things:
img.style.zIndex = 100; // Or whatever
Add it to the document:
document.body.appendChild(img);
Move it around
Use window.setInterval (or setTimeout depending on how you want to do it) to move it around by changing its style.left and style.top settings. You can use Math.random to get a random floating point number between 0 and 1, and multiply that and run it through Math.floor to get a whole number for changing your coordinates.
Example
This creates an image at 50,50 and animates it (in a very jittery random way; I didn't spend any time making it look nifty) every fifth of a second for 10 seconds, then removes it:
function createWanderingDiv() {
var img, left, top, counter, interval;
img = document.createElement('img');
img.src = "myimage.png";
left = 200;
top = 200;
img.style.position = "absolute";
img.style.left = left + "px";
img.style.top = top + "px";
img.style.width = "200px"; // Make these match the image...
img.style.height = "200px"; // ...or leave them out.
img.style.zIndex = 100; // Or whatever
document.body.appendChild(img);
counter = 50;
interval = 200; // ms
window.setTimeout(wanderAround, interval);
function wanderAround() {
--counter;
if (counter < 0)
{
// Done; remove it
document.body.removeChild(img);
}
else
{
// Animate a bit more
left += Math.floor(Math.random() * 20) - 10;
if (left < 0)
{
left = 0;
}
top += Math.floor(Math.random() * 10) - 5;
if (top < 0)
{
top = 0;
}
img.style.left = left + "px";
img.style.top = top + "px";
// Re-trigger ourselves
window.setTimeout(wanderAround, interval);
}
}
}
(I prefer re-scheduling on each iteration via setTimeout [as above] to using setInterval, but it's totally your call. If using setInterval, remember the interval handle [return value from setInterval and use window.clearTimeout to cancel it when you're done.)
The above is raw DOM/JavaScript; jQuery offers some helpers to make it a bit simpler, but as you can see, it's pretty straightforward even without.

There's also a jQuery function that can be used to move thing's around.
See this for examples:
http://api.jquery.com/animate/

Related

Repeatedly setting translate3d(10px,0,0) is not moving div to the right repeatedly. How to make it work?

I know how to move a div element using top/left position increments. But I heard that translate3d gives performance improvements, and so I wanted to check it out.
Lets say I have this,
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.position = 'absolute';
document.body.appendChild(div);
The following,
div.getBoundingClientRect().left
gives the value 8.
Now, calling
div.style.transform = 'translate3d(10px,0,0)'
moves the element to the right by 10px as expected as seen by
div.getBoundingClientRect().left
giving the value 18.
But repeatedly executing,
div.style.transform = 'translate3d(10px, 0, 0)';
does not move the div to the right repeatedly. Instead I have to increment the first argument of translate3d to higher values (eg. 20, 30 etc) to move it repeatedly.
This makes me think the translation is calculated from some initial point. But googling around, I could not find how to update this initial point, so that translate3d(10px, 0, 0) works in a loop.
I tried updating the div.style.left property, but it still does not work.
So can someone tell me how translate3d calculates the translation? And if there is a way to use translate3d(10px,0,0) and some origin resetting, to make a div move repeatedly?
(The end goal is to make a div move to the right every time it is clicked, using translate3d)
When you are doing div.style.transform = 'translate3d(10px, 0, 0)'; you are just removing the transform value to replace it by another, so your element will keep the same position. If you want to move your element using translate3d, you can use a variable and increment it every click :
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.position = 'absolute';
document.body.appendChild(div);
var leftValue = 0;
var increment = 10;
var button = document.querySelector('button');
button.addEventListener('click', function(event) {
leftValue += increment;
div.style.transform = 'translate3d('+leftValue+'px,0,0)';
})
<button>Move</button>
For multiple elements, using getBoundingClientRect().left
When calculating a new offset, we have to take into account the initial position of the element or the new value will be wrong. The problem can be see here.
To avoid this, we can store the initial position of the element and then substract this value when calculating the new offset:
var increment = 10;
var moveBoxes = document.getElementsByClassName('moveBox');
Array.from(moveBoxes).forEach(function(box) {
var initialOffset = getComputedStyle(box).getPropertyValue('left').replace('px', '');
box.addEventListener('click', function(event) {
var offset = this.getBoundingClientRect().left - initialOffset + increment;
this.style.transform = 'translate3d('+offset+'px,0,0)';
});
});
.moveBox {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
<div class="moveBox" style="left: 32px;"></div>
<div class="moveBox" style="top: 120px; left: 100px;"></div>
Using a forEach loop instead of a classical for loop let us store the right initialOffset value in each listeners (there are some others ways to achieve this). Since the array of div is a HTML collection, using Array.from is required to use forEach.
translate3d(10px,0,0)
Is defined here: https://www.w3.org/TR/css-transforms-1/#funcdef-translate3d
I wrote a CodePen to see your issue: https://codepen.io/cyruscuenca/pen/mamjgw?&editable=true
I also scanned the doc, and it seems like the position is based on a coordinate system, and there seems to be separate origin properties. I would read those sections.
The sections that I found that look to be related are 6 and 3.
Hope this helps!
It's very simple.
For the point of the count this function is used your current coordinates by X, Y and Z axes.
So, if you want to move your block, you should always increment this valuse(these values) of the axes.
You can apply multiple transformations on the same element.
div.style.transform = 'translate3d(10px,0,0) translate3d(10px,0,0) translate3d(10px,0,0)';
Which would mean you need to append the string on every loop iteration:
div.style.transform += ' translate3d(10px,0,0)';
However, if you have too many transformations, the string would become very long and might impact the performance, let alone the readability.
If it's always the same transformation you're applying, why not increase the 10px along the way while iterating through the loop:
var offset = 10;
// then on every iteration
div.style.transform = 'translate3d(' + offset + 'px,0,0)';
offset += 10;
Taking ideas from #Arkellys answer (the accepted one), I came up with a solution which seems to be working fine for me. I am a JS newbie so I do not know how well it will hold up. Anyways here it is in case it helps anyone,
// Create container
var container = document.createElement('div');
container.style.width = '1000px';
container.style.height = '500px';
container.style.border = '2px solid black';
container.style.background = 'lightblue';
container.style.margin = '0';
container.style.padding = '10px';
document.body.appendChild(container);
var containerPosition = container.getBoundingClientRect();
// 'click' Callback function generator.
// I pass the initial position to the generator, who then generates a callback
// function which holds this value for use when the event occurs.
function clickCallbackGenerator(initialPos, increment){
var left = initialPos.left;
var clickCallback = function(event) {
var newLeftPosition = this.getBoundingClientRect().left - left + increment;
this.style.transform = `translate3d(${newLeftPosition}px, 0, 0)`;
console.log('clicked : ', this.innerHTML,' now at : ', this.getBoundingClientRect().left);
};
return clickCallback;
}
// function to create 'move-on-click' div nodes
function createNodeDiv(position, text) {
var div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = `${position.top}px`;
div.style.left = `${position.left}px`;
div.style.border = '2px solid blue';
div.style.background = 'black';
div.style.color = 'white';
div.style.margin = '0';
div.style.padding = '0';
div.style.cursor = 'pointer';
div.innerHTML = text;
div.setAttribute('class', 'node');
div.setAttribute('contenteditable', 'true');
container.appendChild(div);
div.addEventListener('click', clickCallbackGenerator(div.getBoundingClientRect(), 10));
console.log('Created : ', div.innerHTML, ' at : ', div.getBoundingClientRect().left);
return div;
}
var defaultPosition = {x: containerPosition.left, y: containerPosition.top};
var increment = 10;
var nodes = [];
nodes.push(createNodeDiv({left: containerPosition.left, top: containerPosition.top}, 'hello'));
nodes.push(createNodeDiv({left: containerPosition.left+50, top: containerPosition.top+50}, 'world'));
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="Free Web tutorials">
<meta name="keywords" content="HTML,CSS,XML,JavaScript">
<meta name="author" content="John Doe">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="script.js"></script>
</body>
</html>
I used a function clickCallbackGenerator to generate the callbacks for each moveable div. That is the only thing I changed.

Changing Z-index Problems

I am making an old-RPG game on HTML, and I want to make a Function on Javascript
that makes the div of the player get lower than the obstacle, and when the top get higher than the obstacle, the z-index of the player go higher than the obstacle:
var top = parseInt($("#player").css("top"));
var hei = $("#player").height();
var total = top + hei;
var obTop = parseInt($("#obstacle").css("top"));
var obHei = $("#obstacle").height();
var obTotal = obHei + obTop;
if (total < obTotal) {
player.style.zIndex = 1;
$("#obstacle").css('z-index', 2);
} else {
player.style.zIndex = 2;
$("#obstacle").css('z-index', 1);
}
When top's player is higher than the obstacle (Fire)
When top is Lower
You need to compare the Y positions of the objects in question. In this case, When the fire y is lower then the player y, You want to have the player have a higher Z-index than the fire. And Vice Versa, Where when the fire y is higher than the player y, you want the fire to have a higher Z-index than the fire. You could do something like this like this:
//Define player y and fire y
player.style.zIndex = 1;
$("obstacle").css("z-index", 1);
if (playery > firey){
player.style.zIndex = 2;
} else {
$("obstacle").css("z-index", 2);
}
This hasnt been tested as there Is not a runnable example given.

JavaScript - how to draw on the canvas and get an image to follow the mouse

I've gotten a lot of help from this site, but I seem to be having a problem putting all of it together. Specifically, in JS, I know how to
a) draw an image onto canvas
b) make a rectangle follow the cursor (Drawing on a canvas) and (http://billmill.org/static/canvastutorial/ball.html)
c) draw a rectangle to use as a background
What I can't figure out is how to use a rectangle as the background, and then draw an image (png) on the canvas and get it to follow the cursor.
What I have so far looks like this:
var canvas = document.getElementByID('canvas');
var ctx = canvas.getContext('2d');
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var bgColor = '#FFFFFF';
var cirColor = '#000000';
clear = function() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
drawIMG = function(x,y,r) {
ctx.fillStyle = cirColor;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
draw = function() {
ctx.fillStyle = bgColor;
clear();
ctx.fillRect(0, 0, WIDTH, HEIGHT);
drawIMG(150, 150, 30);
drawIMG(300, 500, 12);
};
draw();
This will draw in the HTML5 canvas element, the height and width of which are specified in the HTML and so are variable, with a white rectangle the size of the canvas beneath two black circles at (150,150) and (300,500). It does that perfectly well.
However, I don't know how to also make JS draw a .png on top of that that follows the cursor. Like I said, I've been able to do most of the steps individually, but I have no idea how to combine them. I know, for instance, that I have to do
img = new Image();
and then
img.src = 'myPic.png';
at some point. They need to be combined with position modifiers like
var xPos = pos.clientX;
var yPos = pos.clientY;
ctx.drawImage(img, xPos, yPos);
But I have no idea how to do that while maintaining any of the other things I've written above (specifically the background).
Thanks for your patience if you read through all of that. I have been up for a while and I'm afraid my brain is so fried I wouldn't recognize the answer if it stripped naked and did the Macarena. I would appreciate any help you could possibly send my way, but I think a working example would be best. I am an initiate in the religion of programming and still learn best by shamelessly copying and then modifying.
Either way, you have my optimistic thanks in advance.
First off, I've made an animated purple fire follow the mouse. Click (edit doesn't exist anymore)here to check it out.
Before you continue, I recommend you check out these websites:
http://www.williammalone.com/articles/create-html5-canvas-javascript-sprite-animation/
William talks about the basic techniques of canvas animations
http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Paul Irish talks about a recursive animation function that turns at 60 fps.
Using both of their tutorials is pretty a good start for animation.
Now from my understanding you want one 'background' and one animation that follows the cursor. The first thing you should keep in mind is once you draw on your canvas, whatever you draw on, gets replaced. So the first thing I notice that will cause performance issues is the fact you clear your whole canvas, and not what needs to be cleared.
What you need to do is memorize the position and size of your moving element. It doesn't matter what form it takes because your clearRect() should completely remove it.
Now you're probably asking, what if I draw on the rectangle in the background. Well that will cause a problem. You have two solutions. Either, (a) Clear the background and clear your moving animation and draw them back again in the same order or (b) since you know your background will never move, create a second canvas with position = absolute , z-index = -1 , and it's location the same as the first canvas.
This way you never have to worry about the background and can focus on the animation currently going on.
Now getting back to coding part, the first thing you'll want to do is copy Paul Irish's recursive function:
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
Question then is, how to use it? If you go here you can check out how it was done:
function fireLoop()
{
window.requestAnimationFrame(fireLoop);
fire.update();
fire.render();
console.log('you spin me right round baby right round');
follow();
}
This is the loop I use. Every second Paul Irish's function will call the main loop. In this loop. I update the information choose the right animation that needs to be drawn and then I draw on the canvas (after having removed the previous element).
The follow function is the one that chooses the next coordinates for the animation. You'll have to change this part since, you don't want to move the canvas but move the animation. You can use the same code, but you need to apply location to where you want to draw on the canvas.
function follow()
{
$(fireCanvas).offset({
top: getTop(),
left: getLeft()
});
}
function getTop()
{
var off = $(fireCanvas).offset();
if(off.top != currentMousePos.y - $(fireCanvas).height() + 10)
{
if(off.top > currentMousePos.y - $(fireCanvas).height() + 10)
{
return off.top - 1;
}
else
{
return off.top + 1;
}
}
}
function getLeft()
{
var off = $(fireCanvas).offset();
if(off.left != currentMousePos.x - $(fireCanvas).width()/2)
{
if(off.left > currentMousePos.x - $(fireCanvas).width()/2)
{
return off.left - 1;
}
else
{
return off.left + 1;
}
}
}
var currentMousePos = { x: -1, y: -1 };
$(document).mousemove(function(event) {
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
});
If you want me to go into depth about anything specific let me know.

IE 6,7,8 don't support onload event in image object or DOM

My application has a large size of images to present and which should be resized for uniformly presentation with fixed width and height, to do so I write a JavaScript method in image's onload image like this:
var autoResizeImage = function(targetWidth, targetHeight, objImg) {
if (0 >= targetWidth || 0 >= targetHeight) {
// Ilegal parameters, just return.
return;
}
var img = new Image();
img.src = objImg.src;
// Calculate the width and height immediately the image is loaded.
img.onload = function() {
var hRatio;
var wRatio;
var width = img.width;
var height = img.height;
var calcWidth = width;
var calcHeight = height;
wRatio = targetWidth / width;
hRatio = targetHeight / height;
if (wRatio < hRatio) {
calcHeight = targetHeight;
calcWidth = (targetHeight / height) * width;
} else {
calcWidth = targetWidth;
calcHeight = (targetWidth / width) * height;
}
objImg.width = calcWidth;
objImg.height = calcHeight;
};
};
HTML image:
<img src='PATH' onload='autoResizeImage(100, 100, this)'>
This way works well on Chrome and Firefox except IE 6,7,8. I'm suffering on this, how can I complete this task on IE 6,7,8.
Thanks so much.
I would start by saying that if you're serving images to be displayed at a particular size, you should send them from the server at the correct size in the first place. Sending excessively large images and having the browser resize them is poor practice because it means that you're using up a lot more bandwidth than you need to. Your users may have restricted bandwidth, and may not appreciate the extra load time on your page caused by this.
However, I don't really know why you need to do this resizing exersise at all? HTML will by default scale an image to the size of the <img> tag that contains it anyway, so all you need to do is specify height and width styles for your <img> tag, and the scaling will be done automatically. There should be absolutely no need for all that messing around with Javascript.
<img src='PATH' style='width:100px; height:100px;'>
That should work in all browsers; no JS required. The image should be scaled for you.
But ideally, as I said, please try to avoid sending excessively large images to the page if you're not going to use them at full size.
Change the order of assignments. First assign onload function and then src attribute. It works for IE 8 at least.
var div = document.getElementById('div');
var img = new Image();
img.onload = function() {
var text = document.createTextNode('loaded ' + img.src);
div.appendChild(text);
};
window.setTimeout(function() {
var random = Math.random();
img.src ="http://stackoverflow.com/users/flair/450989.png?random=" + random;
}, 1000);
div.appendChild(img);
<div id="div"/>

Javascript: edit an images height in a for loop

I'm trying to edit an images height that is repeating in a for loop in javascript but I can't figure out where I would need to add it in.
Here are the variables if it's important:
var i;
var start = 1;
var seg = document.getElementById("selSegs").value;
var parent = document.getElementById("divInch"), //parent for appendChild
imagePath = 'InchwormSegment.gif', //variable for image
img; //adding img element
Here is my loop:
for(i = start; i<=seg; i++) {
img = new Image(); //creating new image object
img.src = imagePath; // element src = imagePath
img.style.height = "215px"; // sets the height of all in loop
// img.style.height = (img.style.height * .9) + "px"; - does nothing
parent.appendChild(img); //appendChild adds another child (img) object
}
I've tried adding in some math but I just can't figure out where it is supposed to go
Let me know if this fiddle accomplishes what you are trying to do: http://jsfiddle.net/AyNY5/. A few things to remember:
You can edit the image "height" attribute directly, no need to go through style (You don't even need to add px!)
Don't use new Image() - use document.createElement('img'). That's the W3C supported standard.
If I'm off let me know - otherwise, you were on the right track!
JS Code in Fiddle:
var parent = document.getElementById("imgholder")
for (i=0;i<3;i++) {
var img = document.createElement('img');
img.src = "http://bit.ly/1975WKA"
img.height = "200"
parent.appendChild(img)
}
At this point image does not have style.height assigned. It does have height attribute though.
Instead of
img.style.height = (img.style.height * .9) + "px";
try
img.style.height = (img.height * .9) + "px";

Categories

Resources