I have a task to make animation with JavaScript.
Basically I have two squares (red and yellow) and a two buttons (button 1 and button 2).
When I click on button1 the red square goes from the (top-left corner) to the (bottom-right corner).
I need to make another button (button2) such that when I click on it I need the red square to go back to the beginning.
I need it to do the opposite move (moving from the bottom-right corner to the top-left corner).
What changes should I do in the second function?
here is the code
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
I'm going to assume the teacher is trying to teach basic javascript, and tell you how I'd solve this with the parts you've provided.
That said, your commenters are correct, requestAnimationFrame is the right tool here. Also, the 5 ms delay on your interval is really short (125fps). If you made this number, I'd suggest changing it to 16, which is roughly 60fps.
// We want each function to be able to see these vars.
var pos = 0;
// Either -1, 0, or 1, depending on if were moving forward, backwards or
// stopped.
var direction = 0;
// This var now serves dual purpose, either its a number which is the
// interval id or its falsy, which we can use to understand the animation
// has stopped.
var id = null;
// Doing this here, will save the browser from having to redo this step on
// each frame.
var elem = document.getElementById("animate");
// Render the elem to the correct starting location.
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
// A single animation function.
function frame() {
// Assume we are heading for 350.
var goal = 350
if (direction < 0) {
// unless the goal is -1, when the goal is zero.
goal = 0
}
if (pos != goal) {
pos += direction;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
} else {
// Reset all the shared vars.
direction = 0;
clearInterval(id);
id = null;
}
}
function myMove1() {
if (id) {
clearInterval(id)
}
direction = 1;
id = setInterval(frame, 5);
}
function myMove2() {
if (id) {
clearInterval(id)
}
direction = -1;
id = setInterval(frame, 5);
}
#animate {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
</body>
</html>
What you're asking is straightforward: take the function you already wrote and change the increment direction on pos. The only difference is you'll need to keep track of x and y coordinates separately since they move in opposite directions. I used this object initialized to the start position of the box:
pos = {x: 350, y: 0};
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
var elem = document.getElementById("animate");
var pos = {x: 350, y: 0};
var id = setInterval(frame, 5);
function frame() {
if (pos.y >= 350 || pos.x <= 0) {
clearInterval(id);
} else {
pos.x--;
pos.y++;
elem.style.top = pos.y + 'px';
elem.style.left = pos.x + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
However, these functions aren't reusable without parameters; this code is WET (wrote everything twice). The animation is brittle because each click creates a new timeout (you can spam the buttons and watch it crumble). Entities in the animation have no state. If you want to change the position or add another box, you have to we-write and duplicate all of your code again.
With that in mind, here's a sketch to illustrate a somewhat improved version as food for thought. The functions and objects are more general and don't need to be re-written for new movements you decide to add. The Box class keeps track of entity state over time. requestAnimationFrame() is used to update and draw all entities on the screen at once, avoiding the many problems with setTimeout.
const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;
const dist = (a, b) => ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5;
class Box {
constructor(elem, pos, size, color, speed) {
this.elem = elem;
this.speed = speed;
this.from = this.to = this.pos = pos;
this.t = 0;
this.elem.style.position = "absolute";
this.elem.style.background = color;
this.elem.style.height = `${size}px`;
this.elem.style.width = `${size}px`;
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
}
move(to) {
this.from = {x: this.pos.x, y: this.pos.y};
this.to = {x: to.x, y: to.y};
this.t = 0;
}
update() {
if (dist(this.pos, this.to) > 1) {
this.pos.x = lerp(this.from.x, this.to.x, this.t);
this.pos.y = lerp(this.from.y, this.to.y, this.t);
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
this.t += this.speed;
}
}
}
const data = [
{color: "red", pos: {x: 0, y: 0}, size: 10},
{color: "yellow", pos: {x: 350, y: 0}, size: 10},
];
const elems = document.getElementsByClassName("box");
const boxes = [];
for (let i = 0; i < elems.length; i++) {
boxes.push(new Box(elems[i], data[i].pos, data[i].size, data[i].color, 0.01));
}
function myMove1() {
boxes[0].move({x: 350, y: 350});
boxes[1].move({x: 0, y: 350});
}
function myMove2() {
boxes[0].move({x: 0, y: 0});
boxes[1].move({x: 350, y: 0});
}
(function render() {
boxes.forEach(e => e.update());
requestAnimationFrame(render);
})();
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div class="box"></div>
<div class="box"></div>
</div>
Lastly, consider using CSS animations, JS canvas or an animation framework to do this sort of task; these tools will abstract away a lot of the math and state representation that animations involve.
Related
so ive been testing out HTML canvas. im trying to get a sprite to change on keyboard input.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id='Game' width='200' height='200' style='border: 2px solid #000000;'></canvas>
<script>
window.onload = function(){
var Game = document.getElementById('Game');
var context = Game.getContext('2d')
var room = new Image();
var lx = 0;
var ly = 0;
var li = 0;
var lo = 0;
var lwidth = 100;
var lheight = 100;
room.onload = function(){
context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);
}
room.src = 'https://i.ibb.co/D7fL7yN/Room.png';
var sprite = new Image();
var cx = 0;
var cy = 125;
var sy = 0;
var sx = 0;
var swidth = 35;
var sheight = 34;
sprite.onload = function(){
context.drawImage(sprite,sx,sy,swidth,sheight,cx,cy,50,50);
}
sprite.src = 'https://i.ibb.co/7VhjqPr/John-Sheet.png';
}
</script>
</body>
</html>
ive been searching on how to change the SX with Keyboard input so my character changes sprites. can you help me? a code example would be best!
Tracking keyboard state.
You can create an object that hold the state of the keyboard, specifically the keys you are interested in reacting to. Use the "keydown" and "keyup" KeyboardEvent to update the keyboard state as the events fire. Use the KeyboardEvent property code to workout which key is changing. DO NOT use keyCode as that has depreciated and is Non Standard
You also want to prevent the default behaviour of keys. Eg prevent arrow keys scrolling the page. This is done by calling the event preventDefault function
const keys = {
ArrowRight: false,
ArrowLeft: false,
ArrowUp: false,
ArrowDown: false,
}
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
function keyEvent(event) {
if (keys[event.code] !== undefined) {
keys[event.code] = event.type === "keydown";
event.preventDefault();
}
}
Then in the game you need only check the keyboard state
if (keys.ArrowRight) { moveRight() }
if (keys.ArrowLeft) { moveLeft() }
// and so on
In the demo below the keys are binded to game actions, meaning that what and how many keys are used are independent of the action. The are also set via configuration, so that key binding can be changed without changing game code. You can also bind other inputs as in example
Animation
To animate you should use the timer function requestAnimationFrame as it is specifically designed to give the best animation results. It will call your rendering function, you can consider the rendering function like a loop, that is call every time you step forward in animation time.
Putting it together
The demo below use the above (modified) methods to get keyboard input and render the scene via animation frame requests.
It also uses some techniques (simple versions of) that help make your game a better product.
Encapsulates the player as an object
Maintains game state by holding the current rendering function in currentRenderState
Has configuration config so all important values are in one place, and could be loaded (from JSON file) to easily change the game without changing code.
Has configurable keyboard binding, Note more than one key can be bound to a game action. In example movement is via WASD or arrow keys.
All text is configurable (making it language independent)
Passes the 2D context to all rendering code.
Separates the game from the rendering. This makes it easier to port the game to low end or high end devices or even move it to a server where ctx is replaced with coms and the game can be broadcast . The game does not change only how it is rendered
var currentRenderState = getFocus; // current game state
const config = {
player: {
start: {x: 100, y:100},
speed: 2,
imageURL: "https://i.stack.imgur.com/C7qq2.png?s=64&g=1",
},
keys: { // link key code to game action
up: ["ArrowUp", "KeyW"],
down: ["ArrowDown", "KeyS"],
left: ["ArrowLeft", "KeyA"],
right: ["ArrowRight", "KeyD"],
},
touchableTime: 140, // in ms. Set to 0 or remove to deactivate
text: {
focus: "Click canvas to get focus",
loading: "Just a moment still loading media!",
instruct: "Use arrow keys or WASD to move",
}
};
requestAnimationFrame(mainLoop); // request first frame
const ctx = gameCanvas.getContext("2d");
const w = gameCanvas.width, h = gameCanvas.height;
const player = {
image: (()=> {
const img = new Image;
img.src = config.player.imageURL;
img.addEventListener("load", () => player.size = img.width, {once: true});
return img;
})(),
x: config.player.start.x,
y: config.player.start.y,
size: 0,
speed: config.player.speed,
direction: 0,
update() {
var oldX = this.x, oldY = this.y;
if (actions.left) { this.x -= this.speed }
if (actions.right) { this.x += this.speed }
if (actions.up) { this.y -= this.speed }
if (actions.down) { this.y += this.speed }
if (this.x < 0) { this.x = 0 }
else if (this.x > w - this.size) { this.x = w - this.size }
if (this.y < 0) { this.y = 0 }
else if (this.y > h - this.size) { this.y = h - this.size }
const mx = this.x - oldX, my = this.y - oldY;
if (mx !== 0 || my !== 0) { this.direction = Math.atan2(my, mx) }
},
draw(ctx) {
if (ctx) {
ctx.setTransform(1, 0, 0, 1, this.x + this.size / 2, this.y + this.size / 2);
ctx.rotate(this.direction + Math.PI / 2); // rotate 90 deg as image points up
ctx.drawImage(this.image,-this.size / 2, -this.size / 2, this.size, this.size);
}
}
}
function drawText(ctx, text, size, color) {
if (ctx) {
ctx.fillStyle = color;
ctx.font = size + "px Arial";
ctx.textAlign = "center";
ctx.fillText(text, w / 2, h * (1/4));
}
}
function getFocus(ctx) {
drawText(ctx, config.text.focus, 24, "black");
}
function drawScene(ctx) {
if (!player.size === 0) {
drawText(ctx, config.text.loading, 16, "blue")
actions.hasInput = false; // ensure instruction are up when ready
} else {
if (!actions.hasInput) { drawText(ctx, config.text.instruct, 16, "blue") }
player.update();
player.draw(ctx);
}
}
function mainLoop() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, w, h);
currentRenderState(ctx);
requestAnimationFrame(mainLoop); // request next frame
}
// keys holds action name for each named key. eg for up action ArrowUp: "up", KeyW: "up",
const keys = Object.entries(config.keys)
.reduce((keys, [action,codes]) =>
codes.reduce((keys, code) => (keys[code] = action, keys), keys), {});
// actions are set true when key down. NOTE first up key for action cancels action
const actions = Object.keys(config.keys)
.reduce((actions,action) => (actions[action] = false, actions),{});
addEventListener("keydown", keyEvent);
addEventListener("keyup", keyEvent);
function keyEvent(event) {
if (keys[event.code] !== undefined) {
actions[keys[event.code]] = event.type === "keydown";
event.preventDefault();
actions.hasInput = true;
}
}
if (config.touchableTime) {
const actionTimers = {};
touchable.addEventListener("click", (e) => {
if (e.target.dataset.action) {
actions[e.target.dataset.action] = true;
clearTimeout(actionTimers[e.target.dataset.action]);
actionTimers[e.target.dataset.action] = setTimeout(() => actions[e.target.dataset.action] = false, config.touchableTime);
actions.hasInput=true;
if (currentRenderState !== drawScene) {
window.focus();
currentRenderState = drawScene;
}
}
});
} else {
touchable.classList.add("hide");
}
gameCanvas.addEventListener("click", () => currentRenderState = drawScene, {once: true});
canvas {border: 1px solid black}
#game {
width:402px;
height:182px;
font-size: 24px;
user-select: none;
}
.left {
position: absolute;
top: 160px;
left: 10px;
cursor: pointer;
}
.right {
position: absolute;
top: 160px;
left: 355px;
cursor: pointer;
}
#touchable span:hover {color: red}
.hide { display: none }
<div id="game">
<canvas id="gameCanvas" width="400" height="180"></canvas>
<div id="touchable">
<div class="left">
<span data-action="up">▲</span>
<span data-action="down">▼</span>
</div>
<div class="right">
<span data-action="left">◄</span>
<span data-action="right">►</span>
</div>
</div>
</div>
Click to snippet frame area for focusing keyboard events
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id='Game' width='200' height='200' style='border: 2px solid #000000;'></canvas>
<script>
window.onload = function(){
// Keyboard collect
const keys = [];
document.onkeydown = e => {
var code = e.which;
if(keys.indexOf(code) < 0){
keys.push(code);
}
};
document.onkeyup = e => keys.splice(keys.indexOf(e.which),1);
// constants
const Game = document.getElementById('Game');
const context = Game.getContext('2d')
const room = new Image();
const lx = 0;
const ly = 0;
const li = 0;
const lo = 0;
const lwidth = 100;
const lheight = 100;
room.onload = function(){
context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);
}
room.src = 'https://i.ibb.co/D7fL7yN/Room.png';
const sprite = new Image();
const swidth = 35;
const sheight = 34;
const sy = 0;
sprite.onload = function(){
context.drawImage(sprite,0,sy,swidth,sheight,0,cy,50,50);
}
sprite.src = 'https://i.ibb.co/7VhjqPr/John-Sheet.png';
// variables
let cx = 0;
let cy = 125;
let sx = 0;
// new variables
const frames_per_step = 20;
let moving = false; // moving flag
let step = 0; // frame counter (for steps)
// main loop function
function tick() {
// keyboard process
if (keys.length) {
keys.forEach(item => {
switch(item){
case 68:case 39://D and right arrow
cx += 1; // move right
// change sprite
if (step++ < frames_per_step / 2) {
sx = 35; // leg up
} else {
sx = 70; // leg down
if(step > frames_per_step) step = 0;
}
moving = true;
break;
case 65:case 37://A and left arrow
cx -= 1; // move left
// change sprite
if (step++ < frames_per_step / 2) {
sx = 105;
} else {
sx = 140;
if(step > frames_per_step) step = 0;
}
moving = true;
break;
// no sprite mechanics here, just move
case 87:case 38://W adn arrow up
cy -= 1;
break;
case 83:case 40://S adn arrow down
cy += 1;
break;
}
});
// render
context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);
context.drawImage(sprite,sx,sy,swidth,sheight,cx,cy,50,50);
} else if(moving) { // return sprite to stay position
sx = 0;
context.drawImage(room,lx,ly,lwidth,lheight,li,lo,200,200);
context.drawImage(sprite,sx,sy,swidth,sheight,cx,cy,50,50);
moving = false;
} // else do nothing
requestAnimationFrame(tick);
}
tick();
}
</script>
</body>
</html>
I am building a game where a spaceship moves into the screen with PC controllers. Now, my remaining part is to make a fireball images drop of the screen randomly with a precise speed and quantity (because the image is only one, we have to multiplicate it). Can someone achieve this?
Here is the code:
Fireball image:
<img src="Photo/fireball.png" id="fireball">
Spaceship image:
<img src="Photo/Spaceship1.png" id="icon-p">
Spaceship moving with controllers + prevent it from going out of screen:
let display = document.getElementById("body");
let rect = icon;
let pos = { top: 1000, left: 570 };
const keys = {};
window.addEventListener("keydown", function(e) {
keys[e.keyCode] = true
});
window.addEventListener("keyup", function(e) {
keys[e.keyCode] = false
});
const loop = function() {
if (keys[37] || keys[81]) { pos.left -= 10; }
if (keys[39] || keys[68]) { pos.left += 10; }
if (keys[38] || keys[90]) { pos.top -= 10; }
if (keys[40] || keys[83]) { pos.top += 10; }
var owidth = display.offsetWidth;
var oheight = display.offsetHeight;
var iwidth = rect.offsetWidth;
var iheight = rect.offsetHeight;
if (pos.left < 0) { pos.left = -10; }
if (pos.top < 0) { pos.top = -10; }
if (pos.left + iwidth >= owidth) { pos.left = owidth - iwidth; }
if (pos.top + iheight >= oheight) { pos.top = oheight - iheight; }
rect.setAttribute("data", owidth + ":" + oheight);
rect.style.left = pos.left + "px";
rect.style.top = pos.top + "px";
};
let sens = setInterval(loop, 1000 / 60);
// Random X coordiante
function rndScreenX(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset));
}
// Set fireball coordinates (X is random)
let fireballElement = document.querySelector('#fireball');
let fireball = {
x: rndScreenX(fireballElement.offsetWidth),
y: 0
}
const loop = function() {
// Change fireball Y
fireball.y += 10;
fireballElement.style.top = fireball.y + 'px';
if (fireball.y > window.innerHeight) {
// Fireball is out of window
// Reset Y and get new random X
fireball.x = rndScreenX(fireballElement.offsetWidth);
fireballElement.style.left = fireball.x + 'px';
fireball.y = 0;
}
};
fireballElement.style.left = fireball.x + 'px';
let sens = setInterval(loop, 1000 / 60);
#fireball {
position: absolute;
/* Ignore this rule if you're using an image */
width: 50px;
height: 50px;
background: red;
border-radius: 40% 40% 50% 50%;
}
<img src="Photo/fireball.png" id="fireball">
This solution includes three configurable variables: spawnRate, advanceRate, and fallDistance. It uses them to determine how often new fireballs spawn, how often they move down the screen, and how far they move on each 'tick'.
The "main" part of the script consists of two setInterval calls, one to handle spawning new fireballs, and the other to handle advancing them down the screen.
(See the in-code comments for further explanation.)
const
display = document.getElementById("display"), // Container element
fireballs = [], // Array to hold all fireball objects
fallDistance = 6; // Measured in `vh` units (but could be whatever)
spawnRate = 2000,
advanceRate = 500;
// Adds the first fireball immediately
spawnFireball(fireballs);
// Moves all fireballs down every 500 milliseconds
const advancerTimer = setInterval(
function(){ advanceAll(fireballs, fallDistance, display); },
advanceRate
);
// Spawns a new fireball every 2000 milliseconds
const spawnerTimer = setInterval(
function(){ spawnFireball(fireballs); },
spawnRate
);
// Defines a function to add a fireball to the array
function spawnFireball(fireballs){
const
img = document.createElement("img"), // Element to add to screen
x = Math.floor(Math.random() * 96) + 2, // Random `x` position
y = 3; // `y` position starts near top of screen
img.src = "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.UyMqod0eO6Qcmco1Zrmj0QAAAA%26pid%3DApi&f=1",
img.classList.add("fireball"); // To style fireballs
img.style.left = x + "vw"; // `x` position will never change
newFb = { x, y, img }; // `fb` object includes coords + img element
fireballs.push(newFb); // Adds the new fireball to the array
}
// Defines a function to advance a fireball's position
function advance(fb, distance){
fb.y += distance;
}
// Defines a function to draw a fireball in the container
function draw(fb, container){
if(fb.y > 100){ return; } // Ignores below-screen fireballs
fb.img.style.top = fb.y + "vh"; // Updates the location on screen
container.appendChild(fb.img); // The `img` property holds our DOM element
}
// Defines a function to advance and draw all fireballs
function advanceAll(fireballs, distance, container){
for(let fb of fireballs){
advance(fb, distance);
draw(fb, container)
}
}
#display{ height: 99vh; width: 99vw; position: relative; }
.fireball{ height: 2em; width: 2em; position: absolute; }
<div id="display"></div>
I have an array of keys that stores which keys are being pressed. Whenever I press the left arrow, spacebar, and the up arrow together, the array will only keep two of the keycodes, leaving one not to be pushed into the array. When these three keys are pressed, the character is supposed to move left, jump up, and shoot a bullet. One of those three actions won't occur. I am using Google Chrome, and I don't know what will happen on other browsers.
var $c = $('canvas');
var ctx = $c[0].getContext('2d');
var x = 20;
var y = 150;
var keys = [];
var bulletX = x + 2;
var bulletY = 0;
var bullets = [];
var face = 1;
function plr() {
ctx.fillStyle = 'black';
ctx.fillRect(x, y, 20, 20);
}
$c.keydown(function(e) {
if (_.includes(keys, e.which) === false) {
keys.push(e.which);
}
});
$c.keyup(function(e) {
_.pull(keys, e.which);
});
function shoot() {
bullets.forEach(function(bullet) {
ctx.fillStyle = 'red';
ctx.fillRect(bullet.bX, bullet.bY, 8, 4);
if (bullet.direction === 0) {
bullet.bX -= 7;
}
if (bullet.direction === 1) {
bullet.bX += 7;
}
if (bullet.bX > 700 || bullet.bX < 0) {
_.pull(bullets, bullet);
}
});
}
setInterval(function() {
ctx.clearRect(0, 0, 700, 500);
if (keys.includes(32)) {
bullets.push({
direction: face,
bX: x + face * 12,
bY: y + 8
});
}
if (keys.includes(37)) {
face = 0;
x -= 3;
}
if (keys.includes(38)) {
y-=3;
}
if (keys.includes(39)) {
face = 1;
x += 3;
}
plr();
shoot();
}, 30);
.canvas {
background-color: #a3c2ba;
outline: none;
border: #fff;
margin: auto;
display: block;
position: relative;
top: 50px;
border-radius: 0px;
}
body {
margin: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Game</title>
<script src='https://code.jquery.com/jquery-3.4.1.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js'></script>
</head>
<body>
<canvas class='canvas' width='300' height='200' tabindex='1' />
</body>
</html>
I have concluded that this is a problem with my keyboard. I tried this on my brother's computer and it worked fine. Thanks to everyone who attempted to help though!
is there a way to get the touch position in a touchmove event every x milliseconds and then execute a function, when the x-coordinate at the moment and the one at the start are differing e.g. 50px?
Thanks
Try the below ;
$('document').ready(function() {
var touch,
action,
diffX,
diffY,
endX,
endY,
startX,
startY,
timer,
timerXseconds = 500, // Change to the Time(milliseconds) to check for touch position
xDifferenceX = 50, // Change to difference (px) for x-coordinates from starting point to run your function
xDifferenceY = 50; // Change to difference (px) for y-coordinates from starting point
function getCoord(e, c) {
return /touch/.test(e.type) ? (e.originalEvent || e).changedTouches[0]['page' + c] : e['page' + c];
}
function testTouch(e) {
if (e.type == 'touchstart') {
touch = true;
} else if (touch) {
touch = false;
return false;
}
return true;
}
function onStart(ev) {
if (testTouch(ev) && !action) {
action = true;
startX = getCoord(ev, 'X');
startY = getCoord(ev, 'Y');
diffX = 0;
diffY = 0;
timer = window.setInterval(checkPosition(ev), timerXseconds); // get coordinaties ever X time
if (ev.type == 'mousedown') {
$(document).on('mousemove', onMove).on('mouseup', onEnd);
}
}
}
function onMove(ev) {
if (action) {
checkPosition(ev)
}
}
function checkPosition(ev) {
endX = getCoord(ev, 'X');
endY = getCoord(ev, 'Y');
diffX = endX - startX;
diffY = endY - startY;
// Check if coordinates on Move are Different than Starting point by X pixels
if (Math.abs(diffX) > xDifferenceX || Math.abs(diffY) > xDifferenceY) {
// console.log('Start is :' + startX + ' End is : ' + endX + 'Difference is : ' + diffX);
$(this).trigger('touchend');
// here Add your function to run...
}
}
function onEnd(ev) {
window.clearInterval(timer);
if (action) {
action = false;
if (ev.type == 'mouseup') {
$(document).off('mousemove', onMove).off('mouseup', onEnd);
}
}
}
$('#monitor')
.bind('touchstart mousedown', onStart)
.bind('touchmove', onMove)
.bind('touchend touchcancel', onEnd);
});
body {
margin: 0;
padding: 0;
}
#monitor {
height: 500px;
width: 500px;
position: relative;
display: block;
left: 50px;
top: 50px;
background: green;
}
.box {
position: absolute;
top: 0;
left: 0;
right: 0;
text-align: center;
font-weight: bold;
bottom: 0;
background: white;
width: 50px;
height: 50px;
margin: auto;
font-size: 16px;
line-height: 23px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='monitor'>
<div class='box'>start here</div>
</div>
Read this post for a more detailed answer
This can be done in a few functions.
The first function is called when there is a movement of the touch event, this event stores the x and y of the touch in a separate variable.
Then we have a function that runs every X miliseconds, this function gets the x and y from the move event and dispatches then to your code.
Functions 3, 4 and 5 are used to handle the start, stop and cancel dragevents, and start/stop the second function:
var timerid;
var x;
var y;
var tick = 0;
function handleStart(evt) {
console.log("handleStart");
evt.preventDefault();
timerid = window.setInterval(timer, 50); // Replace 50 here with X
}
function handleEnd(evt) {
console.log("handleEnd");
evt.preventDefault();
window.clearInterval(timerid);
}
function handleCancel(evt) {
console.log("handleCancel");
evt.preventDefault();
window.clearInterval(timerid);
}
function handleMove(evt) {
console.log("handleMove");
evt.preventDefault();
// Select last point:
var point = evt.changedTouches[evt.changedTouches.length - 1];
x = point.pageX;
y = point.pageY;
}
function timer() {
console.log("timer");
tick++;
document.getElementById("output").innerHTML = "tick: " + tick + " x: " + x + " y:" + y;
}
var el = document.getElementById("canvas");
el.addEventListener("touchstart", handleStart, false);
el.addEventListener("touchend", handleEnd, false);
el.addEventListener("touchcancel", handleCancel, false);
el.addEventListener("touchmove", handleMove, false);
<canvas id="canvas" width="300" height="300" style="border:solid black 1px;"></canvas>
<p id=output></p>
As long as the user is pressing the screen, the code will print out the x and the y coordinate to the screen. You can also integrate the reading of the x and y into your existing game loop instead of having a separate function if that is needed for your project.
Take a look at hammer.js, it has exactly what you need. It supports "touchmove" called pan, that is being called every few milliseconds when you pan. Also there is a threshold property which determine a length in pixels you have to pan before recognizing it as a pan.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div onmouseover="animatedStickers($(this), 17, 5, 4, 2, 3)" style="float: left; background-image: url('http://googledrive.com/host/0B-UH4_eX_YisdlJ4cU9qZ1lwM3c/Tuzki1.png'); background-size: 380px 304px; cursor: pointer; height: 64px; width: 64px; background-position: -6px -6px; color: transparent">Tuzki</div>
<div onmouseover="animatedStickers($(this), 16, 4, 4, 4, 3)" style="float: left; background-image: url('http://googledrive.com/host/0B-UH4_eX_YisdlJ4cU9qZ1lwM3c/Tuzki2.png'); background-size: 304px 304px; cursor: pointer; height: 64px; width: 64px; background-position: -6px -6px; color: transparent">Tuzki</div>
<div onmouseover="animatedStickers($(this), 22, 5, 5, 2, 3)" style="float: left; background-image: url('http://googledrive.com/host/0B-UH4_eX_YisdlJ4cU9qZ1lwM3c/Tuzki3.png'); background-size: 380px 380px; cursor: pointer; height: 64px; width: 64px; background-position: -6px -6px; color: transparent">Tuzki</div>
<script>
var loop = 1;
var stickerInterval = function (element, x, y, last) {
var pos = $(element).css('backgroundPosition').split(' ');
var xPos = parseInt(pos[0].split('px')[0]) - 6 - 6 - 64;
var yPos = parseInt(pos[1].split('px')[0]);
var maxX = ((-6 - 6 - 64) * (x - 1)) - 6;
var maxY = ((-6 - 6 - 64) * last) - 6;
if (loop == y && xPos == maxY) {
// end 1 turn
loop = 1;
xPos = -6;
yPos = -6;
} else if (loop < y && xPos < maxX) {
xPos = -6;
yPos = yPos -6 -6 -64;
loop++;
}
$(element).css('background-position', xPos + 'px ' + yPos + 'px');
};
var animatedStickers = function (element, total, x, y, last, times) {
$(element).removeAttr('onmouseover');
var interval = setInterval(function () { stickerInterval(element, x, y, last) }, 175);
setTimeout(function () {
clearInterval(interval);
loop = 1;
$(element).css('background-position', '-6px -6px');
$(element).attr('onmouseover', 'animatedStickers($(this), ' + total + ', ' + x + ', ' + y + ', ' + last + ', ' + times + ')')
}, 175 * total * times);
};
</script>
I wanna use multiple setInterval() and clear all of them NOT in a time.
<div id="div1" onmouseover="divOver($(this))"></div>
<div id="div2" onmouseover="divOver($(this))"></div>
<script>
var divOver = function (element) {
var id = $(element).attr('id'); // get id
//call setInterval() without the id
var interval = setInterval(function(){ /* do something... */ }, 500);
//clear interval after 1s
setTimeout(function(){ clearInterval(interval) }, 1000);
};
</script>
That code doesn't work fine if I mouseover 2 divs at the same time.
I think: The first I mouseover on div1, function divOver creates a variable name interval. After that (haven't cleared interval yet), I mouseover on div2, function divOver comtinues creating a new variable with the same name interval. So, the first interval can be overridden. Is it right?
To avoid that problem, I think about using setInterval() with id. Something's like this:
var id = $(element).attr('id');
//var interval_ + id = setInterval(function(){ /* do something... */ }, 500);
But that's not javascript syntax. Can you give me any idea to fix this problem?
To answer your question how to maintain a record of different intervals at the same time and being able to start and stop them outside the function scope.
You need to keep an associative arrays with the intervals, such that there can be many intervals at the same time.
<div id="div1" onmouseover="divOver($(this))"></div>
<div id="div2" onmouseover="divOver($(this))"></div>
<script>
var intervals = []
var divOver = function (element) {
var id = element.attr('id'); // get id
//call setInterval() with the id
intervals['i'+id] = setInterval(function(){ /* do something... */ }, 500);
//clear interval after 1s
setTimeout(function(){ clearInterval(intervals['i'+id]) }, 1000);
};
</script>
Though as already mentioned this does most likely not solve your real problem.