I have a canvas that I have in html that is supposed to be 25% of the page. I made a variable named width in javascript, and put it's value as 25%. When I make a context.clearRect(); with the width variable as the width parameter, it doesn't fix it what I was trying to do (which I have done tons of times) which is when the player rectangle moves, the clearRect keeps the background circulating so the rectangle isn't drawing (leaving a mark). Here is my width variable:
var width = 25%;
Here is my clearRect();
context.clearRect(0, 0, width, height);
Edit: I guess I will also post my whole entire code, to be easier.
<html>
<head>
<title></title>
<style type="text/css">
body {
background-color: #222222;
}
canvas {
background-color: #000000;
width: 25%;
height: 400px;
}
</style>
</head>
<body>
<canvas id="mainCanvas"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("mainCanvas");
var context = canvas.getContext("2d");
var keys = [];
var speed = 4;
var width = 25%;
var height = 400;
window.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
}, false);
window.addEventListener("keyup", function(e) {
delete keys[e.keyCode];
}, false);
var player = {
x: 10,
y: 10,
width: 30,
height: 30
};
function game() {
update();
render();
}
function update() {
if (keys[40]) player.y++ * speed;
if (keys[38]) player.y-- * speed;
if (keys[37]) player.x-- * speed;
if (keys[39]) player.x++ * speed;
}
function render() {
context.clearRect(0, 0, (canvas.width * 0.25)), height);
context.fillStyle = "white";
context.fillRect(player.x, player.y, player.width, player.height);
}
setInterval(function() {
game();
}, 1000/30);
</script>
You need to use something like this:
context.clearRect(0, 0, (canvas.width * 0.25), height);
Try this?
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
body {
background-color: #222222;
}
canvas {
background-color: #000000;
width: 25%;
height: 400px;
}
</style>
</head>
<body>
<canvas id="mainCanvas"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("mainCanvas");
var context = canvas.getContext("2d");
var keys = [];
var speed = 4;
// var width = 25%;
var height = 400;
window.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
}, false);
window.addEventListener("keyup", function(e) {
delete keys[e.keyCode];
}, false);
var player = {
x: 10,
y: 10,
width: 30,
height: 30
};
function game() {
update();
render();
}
function update() {
if (keys[40]) player.y++ * speed;
if (keys[38]) player.y-- * speed;
if (keys[37]) player.x-- * speed;
if (keys[39]) player.x++ * speed;
}
function render() {
context.clearRect(0, 0, (canvas.width * 0.25), height);
context.fillStyle = "white";
context.fillRect(player.x, player.y, player.width, player.height);
}
setInterval(function() {
game();
}, 1000/30);
</script>
</body>
</html>
Not sure what you actually wanted to ask yet your code has two syntax errors - thus it does not execute correctly:
var keys = [];
var speed = 4;
//var width = 25%; //This is no valid assignment and the value is not used..
var height = 400;
and
function render() {
//context.clearRect(0, 0, (canvas.width * 0.25)), height); //One bracket too much, can skip both tho..
context.clearRect(0, 0, canvas.width * 0.25, height);
You need to put your canvas in a container, and set up the container the way you want, then you make your canvas 100% of the containers properties using
clientHeight
and
clientWidth
JSFiddle: https://jsfiddle.net/53n2s0s9/
Related
I am trying to make the canvas area and image fill the viewport without the image stretching and retain its aspect ratio when you resize the page. Below is my current code.
var ctx = $("#demo")[0].getContext("2d"),
img = new Image(),
radius = 35,
blurryImageSrc = "https://s9.postimg.cc/u9nsmzlwf/image.jpg";
img.src = blurryImageSrc;
$(img).on("load", function() {
resizeCanvas();
$("#demo").on("mousemove", function(e) {
erase(getXY(e));
});
$("#reset").on("click", function() {
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(img, 0, 0);
ctx.globalCompositeOperation = "destination-out";
});
ctx.drawImage(img, 0, 0, window.innerWidth, window.innerHeight);
ctx.globalCompositeOperation = "destination-out";
});
function getXY(e) {
var r = $("#demo")[0].getBoundingClientRect();
return { x: e.clientX - r.left, y: e.clientY - r.top };
}
function erase(pos) {
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
var can = document.getElementById('demo');
function resizeCanvas() {
can.style.width = window.innerWidth + 'px';
setTimeout(function() {
can.style.height = window.innerHeight + 'px';
}, 0);
}
window.onresize = resizeCanvas;
resizeCanvas();
https://jsfiddle.net/65fph0mn/8/
To retain the image's correct proportions, you need to query it's 'natural' width and height. The image object itself has two properties for this purpose: naturalWidth and naturalHeight.
As the image finished loading you must decide by which factor to scale the image based on the dimensions of the browser window and the longer side of your image.
Let's have a look at a simple example. Say your browser window's width is 1200 pixel and the image 250. If we now divide 1200 by 250 we get 4.8 - that's the factor we need to multiply the image's width and height to fill the current browser window in one direction while maintaining it's correct aspect ratio.
Here's an example:
var ctx = $("#demo")[0].getContext("2d"),
img = new Image(),
radius = 35,
blurryImageSrc = "https://s9.postimg.cc/u9nsmzlwf/image.jpg";
/// setup logic
img.src = blurryImageSrc;
$(img).on("load", function() {
resizeCanvas();
});
var can = document.getElementById('demo');
function resizeCanvas() {
can.width = window.innerWidth;
can.height = window.innerHeight;
if (img.width > 0) {
let factor = can.width / img.naturalWidth * img.naturalHeight > window.innerHeight ? can.height / img.naturalHeight : can.width / img.naturalWidth;
ctx.drawImage(img, 0, 0, img.naturalWidth * factor, img.naturalHeight * factor);
}
}
window.onresize = resizeCanvas;
resizeCanvas();
body {
background: lightgrey;
margin: 0;
}
.container {
position: relative;
background: blue;
width: 100vw;
height: 100vh;
}
#demo {
cursor: crosshair;
width: 100vw;
height: 100vh;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<div class="container">
<canvas id="demo" width=640 height=640></canvas>
</div>
Here I'm waiting for the image to load. Then I can add the eventlistener for window resize and call the function resizeCanvas. This function will then resize the canvas and paint the image in the canvas.
The image must be repainted every time the window is resized.
To keep the aspect ratio the height of the image is calculated from the scaled width.
const canvas = document.getElementById('demo');
var ctx = canvas.getContext("2d"),
img = new Image(),
blurryImageSrc = "https://s9.postimg.cc/u9nsmzlwf/image.jpg";
img.src = blurryImageSrc;
img.addEventListener("load", e => {
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
});
function paint() {
var newHeight = Math.round(img.width/canvas.width*img.height);
ctx.drawImage(img, 0, 0, img.width, newHeight, 0, 0, canvas.width, canvas.height);
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
paint();
}
body {
background: lightgrey;
margin: 0;
}
.container {
position: relative;
background: blue;
width: 100vw;
height: 100vh;
}
#demo {
cursor: crosshair;
width: 100vw;
height: 100vh;
}
<div class="container">
<canvas id="demo" width="640" height="640"></canvas>
</div>
I am trying to make a simple game. The green block is my game character. I used a the keydown event to make my character able to move right and left. When I hold down the right or left arrow key, the character keeps on accelerating. If you start by tapping the right or left arrow key, you will see that the space interval between where the character was and where it is increases as you click more. How can I make my character move at a constant speed with constant space intervals.
//variables
var canvas = document.getElementById("canvas");
var draw = canvas.getContext("2d");
var characterx = 20;
var charactery = window.innerHeight - 60;
var dx = 0.01;
var dy = 0.01;
//canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//main game function
function run() {
//loops the function
requestAnimationFrame(run);
//clears the screen
draw.clearRect(0, 0, canvas.width, canvas.height)
//draws the ground
draw.beginPath();
draw.fillStyle = "#823819";
draw.fillRect(0, canvas.height - 20, canvas.width, 20);
draw.fill();
draw.closePath();
//draws the main character
draw.beginPath();
draw.fillStyle = "#128522";
draw.fillRect(characterx, charactery, 40, 40);
draw.fill();
draw.closePath();
//key evevnts
window.addEventListener("keydown",function(event) {
if(event.keyCode == 39) {
characterx += dx;
}
});
window.addEventListener("keydown",function(event) {
if(event.keyCode == 37) {
characterx -= dx;
}
});
};
run();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css">
body {
margin: 0;
overflow: hidden;
}
canvas {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Your event listeners should be added outside of your game loop.
Currently you are adding an extra listener for each keypress on every frame, meaning that on the first frame you will move dx * 1 for a keypress, but on frame 100 you will move dx * 100 for a single keypress.
This is also why your dx value had to be so low - I've increased it in the sample below, but you can adjust it as needed.
//variables
var canvas = document.getElementById("canvas");
var draw = canvas.getContext("2d");
var characterx = 20;
var charactery = window.innerHeight - 60;
var dx = 3.0;
var dy = 3.0;
//canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//key evevnts
window.addEventListener("keydown",function(event) {
if(event.keyCode == 39) {
characterx += dx;
}
});
window.addEventListener("keydown",function(event) {
if(event.keyCode == 37) {
characterx -= dx;
}
});
//main game function
function run() {
//loops the function
requestAnimationFrame(run);
//clears the screen
draw.clearRect(0, 0, canvas.width, canvas.height)
//draws the ground
draw.beginPath();
draw.fillStyle = "#823819";
draw.fillRect(0, canvas.height - 20, canvas.width, 20);
draw.fill();
draw.closePath();
//draws the main character
draw.beginPath();
draw.fillStyle = "#128522";
draw.fillRect(characterx, charactery, 40, 40);
draw.fill();
draw.closePath();
};
run();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css">
body {
margin: 0;
overflow: hidden;
}
canvas {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
I want to be able to run a certain function when my mouse is clicked on a certain area of the canvas but i do not understand how to do it. (I am new to programming) for example, if i wanted to click in within an area of a rectangle in the top right of the canvas, such as the coordinates of "172,58,269,166"
<!DOCTYPE HTML>
<html>
<head>
<style>
canvas{
margin-top: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
/*display:block;*/
}
</style>
</head>
<body background="MANCALA-start_bg_texture.jpg">
<div class="container">
<canvas id="myCanvas" width="1141" height="479" usemap="Canvas"></canvas>
<script>
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// identifies what each of the pictures
var sources = {
background: 'MANCALA-game_bg_combined3.png',
pit1marble1: 'MANCALA-game_marble.png',
pit1marble2: 'MANCALA-game_marble.png',
pit1marble3: 'MANCALA-game_marble.png',
pit1marble4: 'MANCALA-game_marble.png',
pit1marble5: 'MANCALA-game_marble.png',
pit1marble6: 'MANCALA-game_marble.png',
};
//loading the images on the canvas
loadImages(sources, function(images) {
context.drawImage(images.background, 0, 0, 1141, 479);
context.drawImage(images.pit1marble1, 200, 70, 50, 50);
context.drawImage(images.pit1marble2, 160, 85, 50, 50);
context.drawImage(images.pit1marble3, 175, 75, 50, 50);
context.drawImage(images.pit1marble4, 190, 80, 50, 50);
context.drawImage(images.pit1marble5, 200, 100, 50, 50);
context.drawImage(images.pit1marble6, 160, 100, 50, 50);
//mouse positioning
document.getElementById("myCanvas").onclick = function() {pasDiKlik()};
function pasDiKlik() {
context.beginPath();
context.arc(event.clientX-10, event.clientY-10,10, 0, 2 * Math.PI, false);
You could add a eventlistener to the canvas, get the position of the mouse on the canvas, and perform a action based on that. for example:
var canvas = document.getElementById("MyCanvas")
var canvasLeft = canvas.offsetLeft,
var canvasTop = canvas.offsetTop
canvas.addEventListener("click", function(event){
var x = event.pageX - canvasLeft
var y = event.pageY - canvasTop;
};
The variables x and y are now the pixel position on the canvas.
for example, to check on your first box(top left:200px, 70px, bottom right: 250px, 120px).
if (x >= 200 && x <= 250 && y >= 70 && y <= 120) {
//perform action here
};
i want to move html canvas horizontally, then rotate it, and then again move it horizontally. problem is, that after i rotate it and want to move it again, rotation dissapear. what i am doing wrong ? thanks, my code is below
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1250">
<meta name="generator" content="PSPad editor, www.pspad.com">
<title></title>
</head>
<body>
<style type="text/css">
#canvas {
width:400px;
height:400px;
border:1px solid red;
}
</style>
<canvas id="canvas"></canvas>
<script type="text/javascript">
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
var counterx = 0;
var canvasWidth = 400;
var canvasHeight = 400;
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(imageObj, counterx,0 ,69, 50);
};
imageObj.src = 'test.png';
function moveRight() {
ctx.save();
counterx += 5;
ctx.clearRect(0 ,0 ,canvasWidth, canvasHeight);
ctx.drawImage(imageObj, counterx,0 ,69, 50);
ctx.restore();
}
function rotate() {
ctx.save();
ctx.translate(counterx, 0);
ctx.rotate(Math.PI / 4);
ctx.clearRect(0 ,0 ,canvasWidth, canvasHeight);
ctx.drawImage(imageObj, counterx,0 ,69, 50);
ctx.restore();
}
</script>
<a onclick="moveRight(); return false;" href="#">move right</a>
<a onclick="rotate(); return false;" href="#">rotate</a>
</body>
</html>
I would recommend accumulating the values, then do an absolute transform only when needed. A little refactoring can also make it easier to track these changes, here that would be to use a common update method.
For example:
var rotation = 0;
var counterx = 0;
function moveRight() {
counterx += 5;
update();
}
function rotate() {
rotation += Math.PI / 4
update();
}
function update() {
ctx.clearRect(0 ,0 ,canvasWidth, canvasHeight);
ctx.translate(counterx, 0); // absolute translate
ctx.rotate(rotation); // absolute rotation
ctx.drawImage(imageObj, 0, 0, 69, 50); // we are already at counterx
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset all transformations
}
And if you want to rotate by image's center, just replace the drawImage line above with:
ctx.drawImage(imageObj, -69/2, -50/2, 69, 50);
Live demo
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var canvasWidth = 400;
var canvasHeight = 400;
var imageObj = new Image();
var rotation = 0;
var counterx = 0;
c.width = canvasWidth;
c.height = canvasHeight;
imageObj.onload = update;
imageObj.src = 'http://i.imgur.com/mP58PXJ.png';
function moveRight() {
counterx += 5;
update();
}
function rotate() {
rotation += Math.PI / 4
update();
}
function update() {
var iw = imageObj.width, ih = imageObj.height;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.translate(counterx, ih); // absolute translate
ctx.rotate(rotation); // absolute rotation
ctx.drawImage(imageObj, -iw*0.5, -ih*0.5); // we are already at counterx
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset all transformations
}
#canvas {
width: 400px;
height: 400px;
border: 1px solid red;
}
<canvas id="canvas"></canvas>
<a onclick="moveRight(); return false;" href="#">move right</a>
<a onclick="rotate(); return false;" href="#">rotate</a>
When you put a picture named logo.png in the same directory as this html file and try to run it in a web browser the picture only appears 1 times out of 10 refreshes in IE and doesn't appear the first time in Firefox but does appear after further refreshes.
What the heck is going on ?
(drawImage() method is called in the showIntro() function)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Example 1 - Title Screen</title>
<script>
window.onload = function () {
var canvas = document.getElementById('myCanvas');
var c = canvas.getContext('2d');
var State = {
_current: 0,
INTRO: 0,
LOADING: 1,
LOADED: 2
}
window.addEventListener('click', handleClick, false);
window.addEventListener('resize', doResize, false);
doResize();
function handleClick() {
State._current = State.LOADING;
fadeToWhite();
}
function doResize() {
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
switch (State._current) {
case State.INTRO:
showIntro();
break;
}
}
function fadeToWhite(alphaVal) {
// If the function hasn't received any parameters, start with 0.02
var alphaVal = (alphaVal == undefined) ? 0.02 : parseFloat(alphaVal) + 0.02;
// Set the color to white
c.fillStyle = '#FFFFFF';
// Set the Global Alpha
c.globalAlpha = alphaVal;
// Make a rectangle as big as the canvas
c.fillRect(0, 0, canvas.width, canvas.height);
if (alphaVal < 1.0) {
setTimeout(function () {
fadeToWhite(alphaVal);
}, 30);
}
}
function showIntro() {
var phrase = "Click or tap the screen to start the game";
// Clear the canvas
c.clearRect(0, 0, canvas.width, canvas.height);
// Make a nice blue gradient
var grd = c.createLinearGradient(0, canvas.height, canvas.width, 0);
grd.addColorStop(0, '#ceefff');
grd.addColorStop(1, '#52bcff');
c.fillStyle = grd;
c.fillRect(0, 0, canvas.width, canvas.height);
var logoImg = new Image();
logoImg.src = './logo.png';
// Store the original width value so that we can keep
// the same width/height ratio later
var originalWidth = logoImg.width;
// Compute the new width and height values
logoImg.width = Math.round((50 * document.body.clientWidth) / 100);
logoImg.height = Math.round((logoImg.width * logoImg.height) / originalWidth);
// Create an small utility object
var logo = {
img: logoImg,
x: (canvas.width / 2) - (logoImg.width / 2),
y: (canvas.height / 2) - (logoImg.height / 2)
}
// Present the image
c.drawImage(logo.img, logo.x, logo.y, logo.img.width, logo.img.height);
// Change the color to black
c.fillStyle = '#000000';
c.font = 'bold 16px Arial, sans-serif';
var textSize = c.measureText(phrase);
var xCoord = (canvas.width / 2) - (textSize.width / 2);
c.fillText(phrase, xCoord, (logo.y + logo.img.height) + 50);
}
}
</script>
<style type="text/css" media="screen">
html { height: 100%; overflow: hidden }
body {
margin: 0px;
padding: 0px;
height: 100%;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="100" height="100">
Your browser doesn't include support for the canvas tag.
</canvas>
</body>
</html>
The problem is that you aren't waiting for the image to load when you call drawImage().
You could use something like:
logo.img.onload = function(){
c.drawImage(logo.img, logo.x, logo.y, logo.img.width, logo.img.height);
};
Although make sure you don't start modifying the canvas until this has happened.