Moving multiple object together in canvas with respect to the current position - javascript

I have a canvas element with multiple images being displayed. I am trying to achieve is that when I click on a button it should move 200 position in X coordinates. I managed to move the second image, but the first image is not moving. And the images must move with respective to their current position. I am here by attaching my javascript for the same.
$(window).on('load', function () {
imageContent(200);
});
function imageContent(x) {
var posX = x;
var imgArray = ['http://via.placeholder.com/200x200?text=first', 'http://via.placeholder.com/200x200?text=second'];
$.each(imgArray, function (i, l) {
var img = new Image();
img.onload = function () {
var x = 0;
myCanvas(img, i * posX);
};
img.src = l;
});
}
function myCanvas(img, x) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var last_ts = -1
var speed = 0.1
function renderScene() {
ctx.beginPath();
ctx.drawImage(img, x, 0);
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
imageContent(x);
requestAnimationFrame(fly);
}
}
renderScene();
$('#movebutton').click(function () {
x = 0;
requestAnimationFrame(fly);
});
}
Here is the codepen. It would be greatful if anyone could help me.

Edit: Modified to achieve side by side movement
I modified your code a little, and removed jQuery. See if it is the effect you are trying to achieve:
var imgArr = [],
c = document.getElementById("myCanvas"),
ctx = c.getContext("2d"),
last_ts = -1,
speed = 0.1,
x = 0
window.onload = function() {
[
'http://via.placeholder.com/200x200?text=first',
'http://via.placeholder.com/200x200?text=second'
].forEach(function(obj, idx) {
var img = new Image()
img.onload = function() {
drawImage(img, idx * 200, 0)
}
img.src = obj
imgArr.push(img)
})
}
function drawImages(x) {
ctx.clearRect(0, 0, c.width, c.height)
imgArr.forEach(function(obj, idx) {
drawImage(obj, x + idx*200, 0)
})
}
function drawImage(img, x, y) {
ctx.beginPath()
ctx.drawImage(img, x, y)
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
drawImages(x)
requestAnimationFrame(fly)
}
}
document
.getElementById('movebutton')
.addEventListener('click', function() {
x = 0
fly()
}, false)
canvas {
border: 1px solid red;
}
<canvas id="myCanvas" width="960" height="600"></canvas>
<button id="movebutton">Move</button>

Related

Return true when user click a bug

I am making a bug smasher game, and want Boolean value(isOnCircle) to return 'true' when a user clicks the bug. However, it always returns 'false'. Although when I tested it as a circle instead of a bug image (with 'context.arc'), it returned 'true'.
*I also inserted an image into the canvas background.
bug.r=32 is the bug image's correct radius size.
var Bug = (function () {
function Bug() {
}
return Bug;
}());
var jumpInterval;
var interval = 4000;
var bug = new Bug();
var canvas = document.getElementById('canvas');
canvas.width =727
canvas.height = 483;
var context = canvas.getContext('2d');
var background = new Image();
background.src = "images/lawn.jpg";
background.onload = function () {
context.drawImage(background, 0, 0);
}
function handleClick(evt) {
console.log(evt.x + ',' + evt.y);
var x = evt.x - 50;
var y = evt.y - 100;
// (x - center_x)^2 + (y - center_y)^2 < radius^2
var isOnCircle = Math.pow(x - bug.x, 2) + Math.pow(y - bug.y, 2) < Math.pow(bug.r, 2);
console.log(isOnCircle);
if (interval > 500) {
interval -= 300;
} else {
interval = 500;
}
console.log(interval);
}
function jump() {
bug.x = ((Math.random() * 10324897) % 500) + 1;
bug.y = ((Math.random() * 10324897) % 500) + 1;
bug.r = 32;
context.clearRect(0, 0, canvas.width, canvas.height);
var background = new Image();
background.src = "images/lawn.jpg";
background.onload = function () {
context.drawImage(background, 0, 0);
}
console.log(bug.x);
console.log(bug.y);
context.beginPath();
//context.arc(bug.x, bug.y, bug.r, 0, 2 * Math.PI);
var bugImage = new Image();
bugImage.src = "images/bug.PNG";
bugImage.onload = function () {
context.drawImage(bugImage, bug.x, bug.y);
}
context.stroke();
clearInterval(jumpInterval);
jumpInterval = setInterval(jump, interval);
}
jumpInterval = setInterval(jump, interval);
canvas.addEventListener("click", handleClick);

cache a canvas in an object (in memory)

I am trying to cache the different states a user sets for a canvas,
The thing is that using .push and canvas.clone() when I append it later it's same size, but white; without the image that it was showing,
Any posible way to store a canvas in memory?
-EDIT-
This is how I'm trying
effectosFotos: function ($foto) {
var t;
var selector = '#'+$foto.attr('id');
var $foto = $(selector);
var $backup = $foto.clone();
var times = 0;
var cached = [];
$('.filters').show();
var img1 = document.createElement('img');
img1.onload = function () {
var width1 = $('.filters li').eq(0).width()/3;
var height1 = this.height*(width1/this.width);
console.log(width1, height1);
var canvas1 = document.createElement('canvas'),
ctx1 = canvas1.getContext('2d');
canvas1.width = width1;
canvas1.height = height1;
ctx1.drawImage(this, 0, 0, width1, height1);
var newUrl = canvas1.toDataURL('image/jpeg', 0.8);
$('.filters li a').each(function() {
$(this).append( '<img id="preview_'+$(this).data('id')+'" src="'+newUrl+'">' );
});
$('.filters li a').each(function(i) {
var $this = $(this);
t = setTimeout(function () {
var effect = $this.data('id');
var $img = $('#preview_'+effect);
//console.log('Item='+i +' About to render '+ effect +' and exists? ' + $img.length );
Caman('#preview_'+effect, function () {
this[effect]();
this.render(function(){
//console.log('rendered '+effect);
$this.parent().addClass('rendered');
});
});
}, 1*i)
});
}
img1.src = $foto.attr('src');
$('.filters').on('click', 'li:not(.active) a', function(e){
var start = new Date().getTime();
var $this = $(this).addClass('loading');
$this.parent().addClass('loading');
e.preventDefault();
var effect = $(this).data('id');
var parent = $(selector).parent();
//console.log('f'+$(selector).length, effect,times,$(selector).prop("tagName"),$backup.prop("tagName"));
/*if(times == 0){
$backup = $foto.clone();
}
times++;*/
$(selector).remove();
parent.append($backup);
console.log(cached);
var found = -1;
for ( var c = 0; c < cached.length; c++ ) {
var item = cached[c];
if ( item.effect == effect ) {
found = c;
}
}
if (effect == 'normal'){
$(selector).css('opacity',1);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
} else if ( found > -1 ) {
console.log('Cargamos caché ' + effect + ' a '+width +'x'+height);
var canvas = document.getElementById($foto.attr('id'))
canvas.width = width;
canvas.height = height;
var ctx3 = canvas.getContext('2d');
ctx3.clearRect( 0, 0, width, height );
ctx3.drawImage( cached[found].canvas, 0, 0);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
} else {
$(selector).remove();
parent.append($backup);
$(selector).css('opacity',0.3);
$('.takePictureHolder').addClass('caming');
Caman(selector, function () {
this[effect]();
this.render(function(){
$(selector).css('opacity',1);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
$('.takePictureHolder').removeClass('caming');
if (found == -1) {
var canvas = document.getElementById($foto.attr('id'));
var clone = canvas.cloneNode(true);
clone.getContext('2d').drawImage(canvas, 0,0);
cached.push({ 'effect' :effect, "canvas":clone });
/*var ctx4 = document.getElementById($foto.attr('id')).getContext('2d');
console.log('Cacheamos ' + effect + ' a '+width +'x'+height);
cached.push({ 'effect' :effect, "canvas":ctx4.getImageData(0,0,width, height) });*/
}
var end = new Date().getTime();
var time = end - start;
console.log('Execution time: ' + time);
});
});
}
});
}
The easiest and way more efficient than export methods is to draw your to-be-saved canvas on a clone, using clonedCtx.drawImage(canvas, 0,0). You will then be able to store the cloned canvas in an array :
Andreas' snippet with modified code :
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [];
console.log('setup states...');
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
var clone = canvas.cloneNode(true);
clone.getContext('2d').drawImage(canvas, 0,0);
states.push(clone)
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, state.width, state.height);
context.drawImage(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>
But, as pointed out by #markE, if you need to store a lot of these states (e.g if you want to implement an undo/redo feature), it can quickly fill all your memory.
Then the recommended way is to save all drawing operations and reapply them. Still using Andreas' snippet, a minimal implementation could be :
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [];
console.log('setup states...');
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
// create an object with all our states settings and operations
var state = {fillStyle: rndColor(), width: Math.floor(Math.random() * 100), height:Math.floor(Math.random() * 100)};
// save the operations in an array
state.operations = [{name:'fillRect',arguments: [0,0,state.width, state.height]}];
// save the state
states.push(state);
// parse it a first time;
parse(state);
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function parse(state){
// restore our canvas and context's properties
// this could be improved by creating canvas and context objects in our state and then restore the corresponding with a for(x in y) loop
canvas.width = state.width;
canvas.height = state.height;
context.fillStyle = state.fillStyle;
// retrieve the operations we applied
var op = state.operations;
// loop through them
for(var i=0; i<op.length; i++){
// check it actually exists as a function
if(typeof context[op[i].name]==='function')
// apply the saved arguments
context[op[i].name].apply(context, op[i].arguments);
}
}
function restoreStates() {
var state = states.shift();
parse(state);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 1px blue }
<canvas></canvas>
You could save the content of the canvas with .getImageData().
And .putImageData() for restoring the old content.
var data = [];
// store canvas/image
data.push(context.getImageData(0, 0, canvas.width, canvas.height));
// restore canvas/image
var oldData = data.pop();
canvas.width = oldData.width;
canvas.height = oldData.height;
context.clearRect(oldData, 0, 0, canvas.width, canvas.height);
context.putImageData(oldData, 0, 0);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [],
img;
console.log("setup states...");
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
states.push(context.getImageData(0, 0, canvas.width, canvas.height));
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, state.width, state.height);
context.putImageData(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>
The same would be possible with .toDataUrl()
and .drawImage()
But this would be the slower approach: jsperf (at least in chrome)
var images = [];
// store canvas/image
var img = new Image();
img.src = canvas.toDataURL();
images.push(img);
// restore canvas/image
var oldImage = images.pop();
canvas.width = oldImage.width;
canvas.height = oldImage.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(oldImage, 0, 0);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [],
img;
console.log("setup states...");
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
img = new Image();
img.src = canvas.toDataURL();
states.push(img);
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>

HTML5 drawImage - Not working in Chrome while dragging

Im trying to drag and drop an image in canvas. But when dragging in chrome the image disapears but in Mozilla it works fine. Any help on this would be really appreciated.
HTML File
<head>
<script>
var canvasImages = [];
function imageProp() {
this.imgName = ' ';
this.imgX = 0;
this.imgY = 0;
this.ImgWidth = 1;
this.ImgHeight = 1;
}
function GetFilename(url) {
if (url) {
var m = url.toString().match(/.*\/(.+?)\./);
if (m && m.length > 1) {
return m[1];
}
}
return "";
}
function load(source) {
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext('2d');
var imageObj = new Image();
//Loading image to Canvas
imageObj.onload = function () {
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = source;
//Inserting properties of image loaded in canvas to an array
var Property = new imageProp;
//Property.imgName = GetFilename(source);
Property.imgName = source;
Property.imgX = 0;
Property.imgY = 0;
Property.ImgWidth = imageObj.width;
Property.ImgHeight = imageObj.height;
canvasImages.push(Property);
}
</script>
</head>
<body>
<img id = "imgID" onclick=" load(this.src)" src = 'download.png'/>
<canvas id="mycanvas" width="1000" height="1000">HTML5 Not Supported</canvas>
<script src="Canvas_js.js"></script>
</body>
Javascript file
(function () {
"use strict";
/*global document*/
/*global clear*/
/*global canvasImages*/
/*jslint devel: true */
/*jslint browser: true */
var canvas, ctx, ghostcanvas, gctx, RedrawInterval = 20, canvasValid = false, clickLoc = {}, isDragging = false, index = 0, selectedIndex = 0;
clickLoc.x = 0;
clickLoc.y = 0;
function drawCanv() {
var i = 0, imageObj;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (i = 0; i < canvasImages.length; i += 1) {
imageObj = new Image();
imageObj = document.createElement('img');
imageObj.src = canvasImages[i].imgName;
imageObj.onload = function () {
ctx.drawImage(imageObj, canvasImages[i].imgX, canvasImages[i].imgY);
};
}
}
function resizeHandler(index) {
ctx.beginPath();
ctx.strokeRect(canvasImages[index].imgX, canvasImages[index].imgY, canvasImages[index].ImgWidth + 5, canvasImages[index].ImgHeight + 5);
}
function canvasOnClick(e) {
var rect, i = 0;
isDragging = true;
//Get X and Y coordinates of the click
rect = canvas.getBoundingClientRect();
clickLoc.x = e.clientX - rect.left;
clickLoc.y = e.clientY - rect.top;
//Check whether any image is clicked
for (i = 0; i < canvasImages.length; i += 1) {
if (clickLoc.x >= canvasImages[i].imgX && clickLoc.x <= canvasImages[i].imgX + canvasImages[i].ImgWidth && clickLoc.y >= canvasImages[i].imgY && clickLoc.y <= canvasImages[i].imgY + canvasImages[i].ImgHeight) {
selectedIndex = i;
resizeHandler(i);
}
}
}
function canvasMouseUp(e) {
isDragging = false;
}
function canvasMouseMove(e) {
if (isDragging === true) {
canvasImages[selectedIndex].imgX += 5;
drawCanv();
}
}
function init() {
// Defining Canvas and fake canvas
canvas = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
ghostcanvas = document.createElement('canvas');
ghostcanvas.height = canvas.height;
ghostcanvas.width = canvas.width;
gctx = ghostcanvas.getContext('2d');
// Redrawing canvas for the interval
//setInterval(draw, RedrawInterval);
// Adding Eventlisteners
canvas.addEventListener("mousedown", canvasOnClick, false);
canvas.addEventListener("mouseup", canvasMouseUp, false);
canvas.addEventListener("mousemove", canvasMouseMove, false);
}
init();
}());
Start messing around with
user-select: none;
-webkit-user-select: none;
in your css.

HTML5/CANVAS :Mouse event issue

I'm facing a problem right now, the mouse event doesn't seem to work. I have a button sprite and a player sprite , and I want that when I click on the button , the player should move butit doesn't, well here's mycode:
var canvas = document.getElementById("canvas_1");
ctx = canvas.getContext("2d");
canvas.addEventListener('mousedown', doMouseDown, true);
var X = 100;
var Y = 0;
var x = 0;
var y = 0;
var player = new Image();
var butt = new Image();
player.src = 'images/player.png';
butt.src = 'images/right.png';
player.onload = function () {
ctx.drawImage(player, x, 0);
}
butt.onload = function () {
ctx.drawImage(butt, X, Y);
}
update = function () {
ctx.clearRect(0, 0);
ctx.drawImage(player, x, y);
}
setInterval(update, 1000 / fps.getFPS());
var fps = {
startTime: 0,
frameNumber: 0,
getFPS: function () {
this.frameNumber++;
var d = new Date().getTime(),
currentTime = (d - this.startTime) / 1000,
result = Math.floor((this.frameNumber / currentTime));
if (currentTime > 1) {
this.startTime = new Date().getTime();
this.frameNumber = 0;
}
return result;
}
};
function doMouseDown(event) {
var mousePos = getMousePos(canvas, event);
if ((mousePos.x >= X && mousePos.x <= X + butt.width) && (mousePos.y >= Y && mousePos.y <= Y + butt.height)) {
x += 4;
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
what you are doing is like you clicked, doMouseDown function called and end.
and you needed to call this function many times to get animation.so,
you can try like
if clicked var clicked=true
and put this below code in loop
if (clicked){
x+=4
}

HTML5 Canvas blinking on drawing

I'm beginning with an isometric game, and my canvas is blinking(Not in IE) when draws all the parts of the ground. When I set fps to 20 or less, the blinking stops. How can I solve that? Any ideas?
var camerax = 300, cameray = 100;
var fps = 60;
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var img = new Image();
img.onload = function() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
img.src = "ground.png";
}
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);
Right now you're reloading the image every frame and unless the onload callback fires within the 16ms of the frame you're going to see a blank canvas.
You should only need to call the new Image, img.onload sequence once, to preload your images. The onload callback would then kick off your first frame, and the draw calls are free to use the image in memory.
Something like:
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function init() {
img = new Image();
img.onload = function() {
loop = setInterval(function() {
update();
draw();
}, 1000/fps);
};
img.src = "ground.png";
}
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
}
Of course, it gets more complex once you're waiting for multiple images to preload since you need to start the loop only once all of them are done.
Nice tip, freejosh! Thanks! My screen now is not blinking and the code result was that:
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function update() {
}
function draw() {
clearCanvas();
drawGround();
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
function init() {
img = new Image();
img.onload = function() {
drawGround();
};
img.src = "ground.png";
}
function keyListener(e){
e = e || window.event
if(e.keyCode==37){
camerax--;
}
else if(e.keyCode==39){
camerax++;
}
else if(e.keyCode==38){
cameray--;
}
else if(e.keyCode==40){
cameray++;
}
}
window.onkeypress = function(e) {
keyListener(e);
}
init();
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);

Categories

Resources