How to avoid flickering images with keypress? - javascript

I have a piece of code where a user has to press 0 to mute the sound or 1 to play the sound of a music piece. If the sound is muted, the image changes and otherwise when the music plays.
var audio = new Audio();
window.onload = function geluidMaken() {
audio.src = "../Geluiden/Achtergrond_Geluid.mp3";
audio.play();
audio.loop = true;
window.addEventListener("keypress", function geluidsKnoppen() {
var codeGeluid = event.which || event.keyCode;
if(codeGeluid == 48) {
var geluidAanKnop = new Image();
geluidAanKnop.src = "../Afbeeldingen/Sound_Button.png";
mijnObject.drawImage(geluidAanKnop, (canvas.width/2)-25, 850, geluidAanKnop.width, geluidAanKnop.height);
audio.muted = true;
}
else if(codeGeluid = 49) {
var geluidAfKnop = new Image();
geluidAfKnop.src = "../Afbeeldingen/Mute_Button.png";
mijnObject.drawImage(geluidAfKnop, (canvas.width/2)-25, 850, geluidAfKnop.width, geluidAfKnop.height);
audio.muted = false;
}
});
}
I have also a other piece of code where I render all my other functions
function tekenenObjecten() {
mijnObject.clearRect(0, 0, canvas.width, canvas.height);
makenBalkKort();
makenBal();
makenMuur();
makenBord();
The images aren't visible on the canvas but when I click on the keys 0 or 1 the images appears and dissapears directly. How to make sure the images stay on the canvas and change when the 0 or 1 is pressed?

When working with a canvas in html5, remember that when you redraw a frame, you remove everything that is on the canvas, then draw everything you want to see in the new frame.
In your keypress handler, you draw the image once. When a new frame is drawn in the other part of your code, the canvas is cleared, and you never redraw it.
What you want to do is probably have a placeholder that is always drawn, then only change it source and let the main loop take care of it.
var audioKnop = new Image();
var audioAanSource = "../Afbeeldingen/Sound_Button.png";
var audioMuteSource = "../Afbeeldingen/Mute_Button.png";
function init() {
audioKnop.src = audioMuteSource;
}
function tekenenObjecten() {
mijnObject.clearRect(0, 0, canvas.width, canvas.height);
makenBalkKort();
makenBal();
makenMuur();
makenBord();
maakAudioButton();
}
function maakAudioButton() {
mijnObject.drawImage(audioKnop, (canvas.width/2)-25, 850, audioKnop.width, audioKnop.height);
}
window.addEventListener("keypress", function () {
var codeGeluid = event.which || event.keyCode;
if(codeGeluid == 48) {
audioKnop.src = audioAanSource;
audio.muted = true;
} else if(codeGeluid == 49) {
audioKnop.src = audioMuteSource;
audio.muted = false;
}
});

Related

Extract exif data/rotate image added to fabric.js canvas

In my web app users can take photos on their phones from input type file.
Before I used js load image library to automatically detect EXIF data and rotate it if neccessary.
Now I've switched to fabric.js library because I want to allow users to draw on the canvas image before uploading it.
The problem is that I don't know how to get image exif data, or rotate the image when using fabric.js.
My code:
Getting the image from indexed db
var image;
localforage.getItem('photo').then(function(value) {
image = value;
// THIS IS OLD CODE, BEFORE I USER js-load-image to automatically detect exif data
// and rotate if neccessary, then I just appended the result to wrapper
// $("#preview-wrapper").empty();
// if (image) {
// loadImage(
// image,
// function(img) {
// $("#preview-wrapper").append(img);
// },
// {orientation: true} // Options
// );
// }
})
loadFabricOnImageLoad(); // append image to fabric canvas
Fabric.js function
function loadFabricOnImageLoad(){
if(typeof image !== "undefined" && image){
let loaded = false;
if (loaded) {return;}
var c = document.getElementById('myCanvas');
canvas = new fabric.Canvas(c);
canvas.setWidth(width);
canvas.setHeight(500);
canvas.selection = false;
var url = URL.createObjectURL(image);
fabric.Image.fromURL(url, function(img) {
img.set({
left: 0,
right: 0,
top: 0,
});
img.scaleToWidth(width);
canvas.add(img);
canvas.setHeight(img.getScaledHeight());
$("#canvas-loader").hide();
});
fabric.Object.prototype.set({
evented: false
});
canvas.freeDrawingBrush = new fabric['PencilBrush'](canvas);
canvas.freeDrawingBrush.color = 'Red';
canvas.freeDrawingBrush.width = 6;
loaded = true;
} else {
setTimeout(loadFabricOnImageLoad, 250);
}
}
I've managed to do it myself after all by getting the exif data from image file:
localforage.getItem('photo').then(function(value) {
image = value;
// extract the exif data from image file using exif.js
EXIF.getData(image, function() {
let obj = EXIF.getAllTags(this);
imageOrientation = obj.Orientation;
console.log( imageOrientation );
});
})
I had to do a lot of scaling and resizing to get the size of rotated image and canvas correctly:
function loadFabricOnImageLoad(){
if(typeof image !== "undefined" && image){
let loaded = false;
if (loaded) {return;}
var c = document.getElementById('myCanvas');
canvas = new fabric.Canvas(c);
canvas.setWidth(width);
canvas.setHeight(500);
canvas.selection = false;
var url = URL.createObjectURL(image);
fabric.Image.fromURL(url, function(img) {
img.scaleToWidth(canvas.width);
if(imageOrientation == 3 || imageOrientation == 6 || imageOrientation == 8) {
img.scaleToHeight(canvas.height);
canvas.setHeight(img.getScaledHeight());
canvas.add(img);
img.scaleToWidth(canvas.height);
img.scaleToHeight(canvas.width);
img.rotate(getDegreesForOrientation(imageOrientation));
img.center();
} else {
canvas.setHeight(img.getScaledHeight());
canvas.add(img);
}
$("#canvas-loader").hide();
});
// console.log('slika '+JSON.stringify(fabric.Image));
fabric.Object.prototype.set({
evented: false
});
canvas.freeDrawingBrush = new fabric['PencilBrush'](canvas);
canvas.freeDrawingBrush.color = 'Red';
canvas.freeDrawingBrush.width = 6;
loaded = true;
} else {
setTimeout(loadFabricOnImageLoad, 250);
}
}
I know this is already answered but I'd like to suggest different library. exif-js is dead - buggy and no longer maintained, with hundred of unsolved issues.
I would like you to try exifr which i started developing out of frustrations with exif-js.

ActivePointer location not updating

I'm making a sidescroller using Phaser (latest version) and I want the player's projectiles to go towards the pointer when the player clicks, like they do in this example http://phaser.io/examples/v2/games/tanks. I've used some of the code from the example but in my game, the activePointer x and y co-ordinates seem to only initialise when the game starts and never change. So when the player shoots, it's always going towards the same co-ordinates.
I have the following code (note I have removed bits about item collection, enemies etc. for posting on here):
var SideScroller = SideScroller || {};
var startPosX = 100;
var startPosY = 300;
var shooter;
var playerBullets;
var nextFire = 0;
var fireRate = 100;
var cursors;
var currentLoc;
SideScroller.Game = function () {};
SideScroller.Game.prototype = {
create: function () {
//create player
//params = (game, startPositionX,startPositionY, key, frame)
this.player = this.game.add.sprite(startPosX, startPosY, 'player');
//get canvas width and height for later use
canvasWidth = this.game.canvas.width;
canvasHeight = this.game.canvas.height;
//create enemy
var x = this.game.rnd.between(80, this.game.world.width);
var y = this.game.rnd.between(0, 113);
// Point to shoot projectiles from
// allows rotation, if this had been done on the player object, the graphic would have rotated, which we don't want
this.shooter = this.game.add.sprite(startPosX, startPosY, 'blank');
this.shooter.anchor.setTo(0.5, 0.5);
//make a group of player projectiles
playerBullets = this.game.add.group();
playerBullets.enableBody = true;
playerBullets.physicsBodyType = Phaser.Physics.ARCADE;
playerBullets.createMultiple(1000, 'peePower');
playerBullets.setAll('anchor.x', 0.5);
playerBullets.setAll('anchor.y', 0.5);
playerBullets.setAll('outOfBoundsKill', true);
playerBullets.setAll('checkWorldBounds', true);
//enable physics on the player
this.game.physics.arcade.enable(this.player);
//bring player shooting point to the top (not totally necessary)
this.shooter.bringToTop();
//player gravity
this.player.body.gravity.y = gravity;
//player collides with all four edges of the game world
this.player.body.collideWorldBounds = true;
this.player.anchor.setTo(0.5, 0.5);
//the camera will follow the player in the world
this.game.camera.follow(this.player);
//move player with cursor keys
cursors = this.game.input.keyboard.createCursorKeys();
},
update: function () {
currentLoc = this.game.input.activePointer;
//collision between player and platforms
this.game.physics.arcade.collide(this.player, this.blockedLayer, null, null, this);
//make co-ordinates match
this.shooter.x = this.player.x;
this.shooter.y = this.player.y;
//this.shooter's angle towards
this.shooter.rotation = this.game.physics.arcade.angleToPointer(this.shooter, this.game.input.activePointer);
//only respond to keys if the player is alive
if (this.player.alive) {
this.player.body.velocity.x = 0;
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
else if (cursors.right.isDown) {
this.playerForward();
}
else if (cursors.left.isDown) {
this.playerBack();
}
else if (cursors.up.isDown) {
this.playerJump();
}
else if (cursors.down.isDown) {
this.fire();
this.playerDuck();
}
}
},
fire: function () {
//for debugging
console.log("fire was called");
console.log(this.game.input.activePointer.x);
console.log(this.game.input.activePointer.y);
if (this.game.time.now > nextFire && playerBullets.countDead() > 0)
{
nextFire = this.game.time.now + fireRate;
var bullet = playerBullets.getFirstExists(false);
bullet.reset(this.shooter.x, this.shooter.y);
currentLoc = this.game.input.activePointer;
bullet.rotation = this.game.physics.arcade.moveToPointer(bullet, 1000, currentLoc, 1000);
console.log(this.game.input.activePointer);
}
},
playerForward: function () {
this.player.loadTexture('player');
this.player.body.setSize(this.player.standDimensions.width, this.player.standDimensions.height);
this.player.body.velocity.x = 700;
this.player.isMoving = true;
//console.log("Forward height:" + this.player.standDimensions.height);
//console.log("Forward width:" + this.player.standDimensions.width);
},
playerBack: function () {
this.player.loadTexture('playerBack');
this.player.body.velocity.x -= 700;
this.player.isMoving = true;
},
playerJump: function () {
if (this.player.body.blocked.down) {
this.player.body.velocity.y -= 700;
this.player.loadTexture('playerJump');
//console.log("Jump height:" + this.player.jumpDimensions.height);
//console.log("Jump width:" + this.player.jumpDimensions.width);
}
},
playerDuck: function () {
//change image and update the body size for the physics engine
this.player.loadTexture('playerDuck');
this.player.body.setSize(this.player.duckedDimensions.width, this.player.duckedDimensions.height);
//keep track of whether player is ducked or not
this.player.isDucked = true;
},
playerDead: function () {
//set to dead (this doesn't affect rendering)
this.player.alive = false;
//stop moving to the right
this.player.body.velocity.x = 0;
//change sprite image
this.player.loadTexture('playerDead');
},
};
Shooter is a blank sprite on top of the player (much like the turret in the tank example) to allow for rotation without the player rotating (please let me know also if there's a better way to do that!).
I tried updating the currentLoc variable in the update method to the activePointer location but that didn't work.
In addition, this condition has never been hit:
if (this.game.input.activePointer.isDown) {
console.log("pointer is down");
this.fire();
}
So something must be going awry with detecting mouse clicks and I don't know if that's part of the problem?
I think you should look it up in the API. There are few points in your code that are questionable.
http://phaser.io/docs/2.3.0/Phaser.Pointer.html
http://phaser.io/docs/2.3.0/Phaser.Physics.Arcade.html#moveToPointer
The point is that you are actually giving the reference to the pointer (to currentLoc) but not the position. So it should always fire to 0;0.
And for the isDown detection, have you done it in the update function or somewhere else?
Hope i could help!

Drawing application undo button

i have problem with undo button for my drawing application
<input id="undo" type="image" src="images/undo.ico" onclick="cUndo()" width="25" height="25">
var cPushArray = new Array();
var cStep = -1;
var ctx;
// ctx = document.getElementById('myCanvas').getContext("2d");
function cPush() {
cStep++;
if (cStep < cPushArray.length) { cPushArray.length = cStep; }
cPushArray.push(document.getElementById('myCanvas').toDataURL());
}
function cUndo() {
if (cStep > 0) {
cStep--;
var canvasPic = new Image();
canvasPic.src = cPushArray[cStep];
canvasPic.onload = function () { ctx.drawImage(canvasPic, 0, 0); }
}
}
But this doesn't work.Please help
First remark : As #markE underlines, saving with DataURL has a high memory cost. You might consider saving the draw commands + their arguments within an array instead.
Seek for tuts/Stack Overflow post on the topic, out of a few posts you should get some nice ideas.
Anyway, you can go with the dataURL solution in a first time to get your application working (with a limit of 20 undos or like to avoid memory explosion), then you can later improve the undo to reach a higher limit.
I updated my code to handle such a stack limit.
For your issue : onload should be hooked prior to setting the src, but anyway with a DataURL you are not async : the image is built at once, so no need to hook unload.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var historic = [];
var maxHistoricLength = 20; // might be more or less, depending on canvas size...
function saveForUndo() {
historic.push(canvas.toDataURL());
if (historic.length === maxHistoricLength +1) historic.shift();
}
function canUndo() {
return (historic.length !== 0 );
}
function undo() {
if (!canUndo()) return;
var lastDataURL = historic.pop();
var tmpImage = new Image();
tmpImage.src = lastDataURL;
ctx.drawImage(tmpImage, 0, 0);
}

html5 canvas code blanking out

I am in desperate need to fix a problem I have in html5 canvas. I am making an educational game, but after adding another photo and making the necessary code changes, but the canvas blanked out. I reverted the changes, but the problem persisted. I spent the past week or so trying to fix it, but I've run out of ideas :( Here is the relevent code (if anyone needs another part, just say so):
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1041;
canvas.height = 550;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/introbackground.png";
//.... rest of the photos load like this so I won't put it...
// Level 1 background 1 image
var bbg1Ready = false;
var bbg1Image = new Image();
bbg1Image.onload = function () {
bbg1Ready = false; //Exception since it shouldn't load at the beginning
};
bbg1Image.src = "images/pollutedbeach1.png";
// Game objects
var hero = {
speed: 200 // movement in pixels per second
};
var level1;
var level2;
var biolevel = false;
//...Code to make the hero picture move with arrow keys and to reset the game are skipped...
if (hero.x <= (level1.x + 345)
&& level1.x <= (hero.x + 32)
&& hero.y <= (level1.y +50)
&& level1.y <= (hero.y + 32)){
biolevel = true;
return biolevel;
}
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
//...The same for all photos previously loaded...
if (biolevel == true){
level1Ready = false;
level2Ready = false;
bbg1Ready = true;
hero.speed = 125;
}
};
//...Then the main game loop to animate it...
Sorry It's kind of long, but I really need a solution. Thanks!

How to add undo-functionality to HTML5 Canvas?

I have a Sketching app done in all HTML5 and Javascript, and I was wondering how I would create an Undo Button, so you could undo the last thing you drew. Any idea?
You have to store all modifications in a datastructure. Then you can delete the latest modification if the user wants to undo it. Then you repaint all drawing operations from your datastructure again.
On http://arthurclemens.github.io/Javascript-Undo-Manager/ I have a working example of undo with a canvas element. When you make a modification, you feed the undo manager the undo and redo methods. Tracking of the position in the undo stack is done automatically. Source code is at Github.
The other option, if you need to manipulate objects is to convert your canvas to SVG using a library that preserves the Canvas API preventing a rewrite.
At least one such library exists at this time (November 2011):
SVGKit
Once you have SVG, it is much easier to remove objects and much more without the need to redraw the entire canvas.
Here is a solution that works for me. I have tried it in the latest versions of Firefox and Chrome and it works really well in those two browsers.
var isFirefox = typeof InstallTrigger !== 'undefined';
var ctx = document.getElementById('myCanvas').getContext("2d");
var CanvasLogBook = function() {
this.index = 0;
this.logs = [];
this.logDrawing();
};
CanvasLogBook.prototype.sliceAndPush = function(imageObject) {
var array;
if (this.index == this.logs.length-1) {
this.logs.push(imageObject);
array = this.logs;
} else {
var tempArray = this.logs.slice(0, this.index+1);
tempArray.push(imageObject);
array = tempArray;
}
if (array.length > 1) {
this.index++;
}
return array;
};
CanvasLogBook.prototype.logDrawing = function() {
if (isFirefox) {
var image = new Image();
image.src = document.getElementById('myCanvas').toDataURL();
this.logs = this.sliceAndPush(image);
} else {
var imageData = document.getElementById('myCanvas').toDataURL();
this.logs = this.sliceAndPush(imageData);
}
};
CanvasLogBook.prototype.undo = function() {
ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
if (this.index > 0) {
this.index--;
this.showLogAtIndex(this.index);
}
};
CanvasLogBook.prototype.redo = function() {
if (this.index < this.logs.length-1) {
ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
this.index++;
this.showLogAtIndex(this.index);
}
};
CanvasLogBook.prototype.showLogAtIndex = function(index) {
ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height());
if (isFirefox) {
var image = this.logs[index];
ctx.drawImage(image, 0, 0);
} else {
var image = new Image();
image.src = this.logs[index];
ctx.drawImage(image, 0, 0);
}
};
var canvasLogBook = new CanvasLogBook();
So every time you draw any thing you will there after run function canvasLogBook.logDrawing() to store a snapshot of the canvas and then you can call canvasLogBook.undo() to undo and canvasLogBook.redo() to redo.

Categories

Resources