Why is the Canvases image squished when used `.toDataURL()`? - javascript

I want to make the canvases PNG file, when exported, to be not squished ( Original size: Width: 480 pixels, height: 360 pixels. ) and plus, have the blue background color ( Color: #85c9ff ) . Source:
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Flippy in JavaScript! - Replit</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body onload="startGame()">
<canvas id="flippyGoesHere"></canvas>
<center>
<button onmousedown="moveup()" onmouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>
<div>
<button onmousedown="moveleft()" onmouseup="clearmove()" ontouchstart="moveleft()">LEFT</button>
<button onmousedown="moveright()" onmouseup="clearmove()" ontouchstart="moveright()">RIGHT</button>
<br>
<br>
</div>
<button onmousedown="movedown()" onmouseup="clearmove()" ontouchstart="movedown()">DOWN</button>
<br>
<br>
<button onclick="exportAsPng()">EXPORT AS IMAGE</button>
<br>
<br>
</center>
<script src="script.js"></script>
</body>
</html>
JS:
var myGamePiece;
var imgLink = document.getElementById("imgLink")
function startGame() {
myGamePiece = new component(20, 10, "/flippy.svg", 140, 70, "image");
myGameArea.start();
myGameArea.context.fillStyle = "#85c9ff"
myGameArea.context.fillRect(0, 0, myGameArea.canvas.width, myGameArea.canvas.height)
}
var myGameArea = {
canvas: document.getElementById("flippyGoesHere"),
start: function () {
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
},
clear: function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function () {
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
if (type == "image") {
this.image = new Image();
this.image.src = color;
}
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function () {
ctx = myGameArea.context;
if (type == "image") {
ctx.drawImage(this.image,
this.x,
this.y,
this.width, this.height);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function () {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
}
function moveup() {
myGamePiece.speedY = -1;
}
function movedown() {
myGamePiece.speedY = 1;
}
function moveleft() {
myGamePiece.speedX = -1;
}
function moveright() {
myGamePiece.speedX = 1;
}
function clearmove() {
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
}
function exportAsPng() {
imgLink.setAttribute("href", myGameArea.canvas.toDataURL())
imgLink.click()
}
And CSS, I don't know why:
body {
margin: 0;
}
a#imgLink {
display: none;
}
a#imgLink::before {
content: attr(href);
}
canvas#flippyGoesHere {
width: 480px;
height: 360px;
background-color: #85c9ff;
}
button { /* For all buttons! */
cursor: pointer;
}
Demo is here!
Here's the resulted image, when the turtle is not moving:

Building on KeroppiMomo's answer ...
Use the myGameArea.clear() method to colour the background too
var myGameArea = {
...
clear: function () {
myGameArea.context.fillStyle = "#85c9ff"
myGameArea.context.fillRect(0, 0, myGameArea.canvas.width,
myGameArea.canvas.height)
},
Get rid of all of the css for canvas#flippyGoesHere, that is just confusing things as it's affecting the display of the canvas.
You can set the canvas size in the html like KeroppiMomo suggested, or you can set it in the javascript (perhaps in your startGame() function):
myGameArea.canvas.height = 500
myGameArea.canvas.width = 500

You can see that the width and height of the canvas is not what you specified in CSS: myGameArea.canvas.width is 300 and myGameArea.canvas.height is 150. The problem is that the actual size of the canvas is different from its display size.
Setting the canvas size in HTML reveals that the exported image is the same as the canvas.
<canvas id="flippyGoesHere" width="480" height="360"></canvas>
The issue with the background color also lies in the CSS. Specifying the background color in CSS only displays that color, not rendering it in the canvas.
Filling the canvas with the background color (and for good practice, removing the background-color in CSS) should solve the problem.
this.update = function () {
ctx = myGameArea.context;
ctx.fillStyle = "#85c9ff";
ctx.fillRect(0, 0, width, height);
// ...
}

Related

Moving an image with arrow keys in JavaScript

I'm making a simple Javascript game for a school project. I'm trying to replace the red square with an image(in the following link).
enter link description here
How can i achieve this?
Great question! Use a snippet to post your code. This link should provide a complete answer add image
var myGamePiece;
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
}
function moveup() {
myGamePiece.speedY -= 1;
}
function movedown() {
myGamePiece.speedY += 1;
}
function moveleft() {
myGamePiece.speedX -= 1;
}
function moveright() {
myGamePiece.speedX += 1;
}
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body onload="startGame()">
<div style="text-align:center;width:480px;">
<button onclick="moveup()">UP</button><br><br>
<button onclick="moveleft()">LEFT</button>
<button onclick="moveright()">RIGHT</button><br><br>
<button onclick="movedown()">DOWN</button>
</div>
<p>If you click a button the red square will start moving. Click the same button many times, and it will move faster and faster.</p>
</body>
</html>

Start and Stop JS HTML animation with JS

So we pretty much have this program working fine, we just need a little help, or a good pointer in the right direction on how we would start and stop the animation. I have tried several methods and none seem to have worked. I have spent a good amount of time online attempting to find help for the solution. I have come to believe that the problem lies somewhere in the lines that tell the shape to move. Thank you for any help in advance.
JS:
var myGamePiece;
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
}
function moveup() {
myGamePiece.speedY -= 1;
}
function movedown() {
myGamePiece.speedY += 1;
}
function moveleft() {
myGamePiece.speedX -= 1;
}
function moveright() {
myGamePiece.speedX += 1;
}
HTML:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script type="text/javascript" src="HallettBrocatoLab2.js"></script>
<style>
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
</style>
</head>
<body onload="startGame()">
<div style="text-align:center;width:480px;">
<button onclick="moveup()">UP</button><br><br>
<button onclick="moveleft()">LEFT</button>
<button onclick="moveright()">RIGHT</button><br><br>
<button onclick="movedown()">DOWN</button><br><br>
<button onclick="start()">Start</button>
<button onclick="stop()">Stop</button>
</div>
<p>If you click a button the red square will start moving. Click the same button many times, and it will move faster and faster.</p>
</body>
</html>
The clearInterval() method clears a timer set with the setInterval() method.
The ID value returned by setInterval() is used as the parameter for the clearInterval() method.
add a function end pauseGame()
function pauseGame(){
clearInterval(this.interval);
}
change the definition of updateGameArea function
function updateGameArea() {
if(condition_to_stop){
myGameArea.pauseGame();
}
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
}

nothing is drawn on page using javascript and canvas

I am trying to develop a game and i am starting to dip my toes into the HTML <canvas> tag and using it with javascript. My program here is my work in progress clone of PONG. I have managed to add the two paddles with no error but as i have added the Ball function it simply refuses to draw anything on the screen and thus i am given a page covered in black.
Could it be because i am using classes?
Here is the code:
// ctx.fillStyle = 'rgba(red, green, blue, alpha)';
// ctx.fillRect(x, y, width, height);
var canvas;
var ctx;
var dx = 5;
var dy = 5;
//Class Definitions
function Game(width, height, colour) {
this.width = width;
this.height = height;
this.colour = colour;
}
function Player(width, height, colour, x, y, up, down) {
this.width = width;
this.height = height;
this.colour = colour;
this.x = x;
this.y = y;
this.up = up;
this.down = down;
this.move = function(ny) {
this.y = this.y + ny;
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
function Ball(width, height, colour, x , y, isTouched, isInGoal) {
this.width = width;
this.height = height;
this.colour = colour;
this.x = x;
this.y = y;
this.isTouched = isTouched;
this.isInGoal = isInGoal;
this.move = function() {
clear();
this.x = this.x + 1;
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
//Creating new Classes
var gameStage = new Game((window.innerWidth), (window.innerHeight), 'rgb(0,0,0)');
var paddleOne = new Player(10, 150, 'rgb(255,255,255)', (gameStage.width/10), (gameStage.height/2), 38, 40);
var paddleTwo = new Player(10, 150, 'rgb(255,255,255)', (gameStage.width/1.1), (gameStage.height/2), 87, 83);
var ball = new Ball(20, 20, 'rgb(255,255,255)', (gameStage.width/2), (gameStage.height/2), 0, 0);
//Initialisation
function init(){
canvas = document.getElementById('game');
canvas.setAttribute('width', gameStage.width);
canvas.setAttribute('height', gameStage.height);
canvas.setAttribute('tabindex', 0);
if (game.getContext){
ctx = canvas.getContext('2d');
return setInterval(ball.move, 10);
return setInterval(draw, 10);
}
}
//Canvas Functions
function clear(){
ctx.clearRect(0, 0, gameStage.width, gameStage.height);
}
function draw() {
clear();
ctx.fillStyle = gameStage.colour;
ctx.fillRect(0, 0, gameStage.width, gameStage.height);
ctx.fillStyle = paddleOne.colour;
ctx.fillRect(paddleOne.x, paddleOne.y, paddleOne.width, paddleOne.height);
ctx.fillStyle = paddleTwo.colour;
ctx.fillRect(paddleTwo.x, paddleTwo.y, paddleTwo.width, paddleTwo.height);
console.log("PlayerOne Y Coordinate: " + paddleOne.y + "\n");
console.log("PlayerTwo Y Coordinate: " + paddleTwo.y + "\n");
}
//Player Control
function doKeyDown(e) {
if (e.keyCode == paddleOne.up){
paddleOne.move(-5);
} else if (e.keyCode == paddleOne.down) {
paddleOne.move(5);
} else if (e.keyCode == paddleTwo.up) {
paddleTwo.move(-5);
} else if (e.keyCode == paddleTwo.down) {
paddleTwo.move(5);
}
}
//For HTML
function beginStuff(){
init();
window.addEventListener('keydown', doKeyDown, true);
}
* { margin: 0; padding: 0;}
body, html {height: 100%;}
#game {
position: absolute;
width:100%;
height:100%;
background-color: #000000;
}
<!DOCTYPE HTML>
<htmL>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>A game</title>
<script type="text/javascript" src="game.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body onload="beginStuff();" >
<canvas id="game">
Please upgrade your browser to support HTML5. <br/>
</canvas>
</body>
</htmL>
This looks wrong to me:
return setInterval(ball.move, 10);
return setInterval(draw, 10);
Firstly, you've got 2 returns. Secondly, you've lost the binding on the move method:
return setInterval(ball.move.bind(ball), 10);
If that doesn't fix it I suggest stepping through in a debugger, line-by-line, making sure that everything is doing exactly what you expect it to.
With help from #skirtle, i moved the ball.move(); to the draw() function and removed the clear() call from the ball.move() function.

HTML Canvas - Draw Shape after Interval

The script below draws 4 curved rectangles with images in them. It draws them all at once despite using a setInterval of 2500 milliseconds before calling the function that draws them. I would like the first rectangle (i.e. top-left) to be drawn immediately, and then the other rectangles to be drawn after that one (with one being drawn every 2.5 seconds). Why does this function not do this and how can it be done? Any help will be appreciated.
var c=document.getElementById('game'),
ctx=c.getContext('2d');
var images = ['https://i.stack.imgur.com/tXmPa.png', 'https://i.stack.imgur.com/KGhCL.png', 'https://i.stack.imgur.com/s5xu4.png', 'https://i.stack.imgur.com/g6BO0.jpg']
var curvedRect = function(id, selectionnum, x, y, w, h) {
this.id = id;
this.selectionnum = selectionnum;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
curvedRect.prototype.makeCurvedRect = function() {
var img=new Image();
img.src=images[this.selectionnum];
ctx.beginPath();
ctx.lineWidth='8';
ctx.strokeStyle='white';
ctx.moveTo(this.x+10, this.y);
ctx.lineTo(this.x+this.w-10, this.y);
ctx.quadraticCurveTo(this.x+this.w, this.y, this.x+this.w, this.y+10);
ctx.lineTo(this.x+this.w, this.y+this.h-10);
ctx.quadraticCurveTo(this.x+this.w, this.y+this.h, this.x+this.w-10, this.y+this.h);
ctx.lineTo(this.x+10, this.y+this.h);
ctx.quadraticCurveTo(this.x, this.y+this.h, this.x, this.y+this.h-10);
ctx.lineTo(this.x, this.y+10);
ctx.quadraticCurveTo(this.x, this.y, this.x+10, this.y);
ctx.stroke();
ctx.drawImage(img, this.x+2.5, this.y+2.5, this.w-5, this.h-5);
}
var Paint = function(element) {
this.element = element;
this.shapes = [];
}
Paint.prototype.addShape = function(shape) {
this.shapes.push(shape);
}
Paint.prototype.render = function() {
ctx.clearRect(0, 0, this.element.width, this.element.height);
for (var i=0; i<this.shapes.length; i++) {
try {
setInterval(this.shapes[i].makeCurvedRect(), 2500);
}
catch(err) {}
}
}
var paint = new Paint(c);
var img1 = new curvedRect(1, 0, 200, 55, 150, 150);
var img2 = new curvedRect(2, 1, 375, 55, 150, 150);
var img3 = new curvedRect(3, 2, 200, 230, 150, 150);
var img4 = new curvedRect(4, 3, 375, 230, 150, 150);
paint.addShape(img1);
paint.addShape(img2);
paint.addShape(img3);
paint.addShape(img4);
paint.render();
canvas {
z-index: -1;
margin: 1em auto;
border: 1px solid black;
display: block;
background: #FF9900;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>uTalk Demo</title>
<link rel='stylesheet' type='text/css' href='game.css' media='screen'></style>
</head>
<body>
<canvas id="game" width = "750" height = "500"></canvas>
</body>
</html>
Replace
setInterval(this.shapes[i].makeCurvedRect(), 2500);
which executes makeCurvedRect() immediately and supplies setInterval() with the return value with a bound function
setTimeout(curvedRect.prototype.makeCurvedRect.bind(this.shapes[i]), 2500 * i);
or a fat arrow function
setTimeout(() => this.shapes[i].makeCurvedRect(), 2500 * i);
where the delay increases by 2500 for each rectangle.

Issue with redrawing objects in HTML canvas

I am using HTML canvas to draw, then move a red square across the screen. However, when I change the x value of the square and redraw it, an error is thrown stating that "mg_player1 is not defined..." I can't seem to figure out the issue in the code, can anyone help?
<html>
<head>
<style>
#mg_canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 1600px;
height: 800px;
border: 4px solid black;
}
</style>
<body onload="mg_start()">
<div class="hideMultiGames">
<button class="button" onclick="mg_player1.moveUp()">Click me!</button>
<script>
function mg_start() {
multiGames_area.drawCanvas();
var mg_player1 = new mg_player("red", 0, 670);
}
var multiGames_area = {
canvas : document.createElement("canvas"),
drawCanvas : function() {
if (document.getElementById("mg_canvas")) {
}
else {
this.canvas.width = 1600;
this.canvas.height = 800;
this.canvas.id = "mg_canvas"
this.canvas.className = "hideMultiGames";
multiGames_area.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
}
},
mg_drawGround : function() {
var mg_ground;
mg_ground = document.getElementById("mg_canvas");
var ground = mg_ground.getContext("2d");
ground.moveTo(0,700);
ground.lineTo(1600,700);
ground.stroke();
},
mg_clear : function() {
this.context.clearRect(0, 0, 1600, 800);
},
}
function mg_player(color, x, y) { //stores general shared methods and properties of players
this.width = 30;
this.height = 30;
this.color = color;
this.x = x;
this.y = y;
ctx = multiGames_area.context;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
this.moveUp = function() { //function that is throwing errors
this.x = 1000;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
</script>
</div>
</body>
</html>
`
You need to define the mg_player1 object globaly. If you use the var keyword the object is created only in the current function context.
mg_player1 = new mg_player("red", 0, 670);
And you need to call mg_clear in the moveUp function to redraw to canvas. Also better read the width and height property from the canvas in your mg_clear function.
So the script should be like this.
<html>
<head>
<style>
#mg_canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 1600px;
height: 800px;
border: 4px solid black;
}
</style>
<body onload="mg_start()">
<div class="hideMultiGames">
<button class="button" onclick="mg_player1.moveUp()">Click me!</button>
<script>
function mg_start() {
multiGames_area.drawCanvas();
//define the `mg_player1` object global (in the `window` context)
mg_player1 = new mg_player("red", 0, 670);
}
var multiGames_area = {
canvas : document.createElement("canvas"),
drawCanvas : function() {
if (document.getElementById("mg_canvas")) {
}
else {
this.canvas.width = 1600;
this.canvas.height = 800;
this.canvas.id = "mg_canvas"
this.canvas.className = "hideMultiGames";
multiGames_area.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
}
},
mg_drawGround : function() {
var mg_ground;
mg_ground = document.getElementById("mg_canvas");
var ground = mg_ground.getContext("2d");
ground.moveTo(0,700);
ground.lineTo(1600,700);
ground.stroke();
},
mg_clear : function() {
//read the width and heigth from the canvas
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
}
function mg_player(color, x, y) { //stores general shared methods and properties of players
this.width = 30;
this.height = 30;
this.color = color;
this.x = x;
this.y = y;
ctx = multiGames_area.context;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
this.moveUp = function() {
//clear the canvas
multiGames_area.mg_clear();
this.x = 1000;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
</script>
</div>
</body>
</html>

Categories

Resources