I am trying to setup two different canvas containing their own entity, movable with different keyboard inputs. Each canvas has its own script file. However only the second canvas seems active, by testing I have come to the conclusion that the document.onkeydown() function of the second canvas makes my first canvas "non-active" (draw function is fine, but document.onkeydown and onkeyup not working), but I cannot find why.
Here is the code for the first canvas :
var canvas;
var player_y = 480/2;
const paddle_height = 100;
const paddle_width = 20;
document.addEventListener('DOMContentLoaded', function () {
canvas = document.getElementById('canvas');
draw();
});
function draw() {
var context = canvas.getContext('2d');
//canvas
context.fillStyle = color[3];
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw middle line
context.strokeStyle = color[1];
context.beginPath();
context.moveTo(canvas.width / 2, 0);
context.lineTo(canvas.width / 2, canvas.height);
context.stroke();
//draw left paddle
context.fillStyle = color[1];
context.beginPath();
context.fillRect(10, player_y-paddle_height/2, paddle_width, paddle_height);
context.fill();
}
var UP = false;
var DOWN = false;
function move() {
if(UP && player_y > paddle_height/2 ) {
player_y -= 5;
}
if(DOWN && player_y < 480 - paddle_height/2) {
player_y += 5;
}
draw();
}
document.onkeydown = function(e) {
if(e.keyCode == 38) UP = true;
if(e.keyCode == 40) DOWN = true;
}
document.onkeyup = function(e) {
if(e.keyCode == 38) UP = false;
if (e.keyCode == 40) DOWN = false;
}
setInterval (update, 10);
function update() {
move();
}
And here is the code of the second canvas:
var canvas_exemple;
var cube = {
sz: 50,
x: 400/2,
y: 200/2,
sp: 5
}
document.addEventListener('DOMContentLoaded', function () {
canvas_exemple = document.getElementById('canvas_exemple');
draw_exemple();
});
function draw_exemple() {
var context = canvas_exemple.getContext('2d');
//canvas
context.fillStyle = "#242423";
context.fillRect(0, 0, canvas_exemple.width, canvas_exemple.height);
//draw cube
context.fillStyle = "#c70e0e";
context.beginPath();
context.fillRect(cube.x, cube.y, cube.sz, cube.sz);
context.fill();
}
function move_exemple() {
document.onkeydown = function (e) {
if (e.keyCode == 90 && cube.y > 0) cube.y -= cube.sp;
if (e.keyCode == 83 && cube.y < 200 - cube.sz) cube.y += cube.sp;
if (e.keyCode == 81 && cube.x > 0) cube.x -= cube.sp;
if (e.keyCode == 68 && cube.x < 400 - cube.sz) cube.x += cube.sp;
draw_exemple();
}
}
...but I cannot find why
Because you overwrite it:
// First file:
document.onkeydown = function (e) { /*...*/ };
// Second file:
document.onkeydown = function (e) { /*...*/ }; // <=== Overwrites the first
That's an assignment to a property. A property can have only one value (though there are some weird properties in the DOM, like document.cookie
).
If you want to have multiple keydown handlers on document
, use addEventListener
, not assignment, but you probably don't want that. If you put two event handlers for keydown
on the same document, both will get called. How do you determine which should do something?
Instead, put the handler on the canvas
element, not document
. That does mean that the user will have to focus the canvas in order for the keyboard events to go to it, but you have two canvases, so you needed some way for the user to indicate which one they were directing input to. (Note that to make it easier to focus the canvas
element, you might want to put tabindex="0"
on it [details here].)
(You could still use the handler on document
if you wanted, but looking to see whether the event travelled through the relevant canvas
, but in this case it's simpler just to add the handler to the canvas
.)
I've included an example below. In the example, there's a lot of repeated code which normally I'd make a function I could pass things into, but I've kept it separate because the code is separate in your question and sometimes repeated code is simpler to read than parameterized code. You can use the mouse or tab to switch between the canvases. The active canvas has a green border around it.
// Canvas 1
const canvas1 = document.getElementById("canvas1");
const ctx1 = canvas1.getContext("2d");
let x1 = Math.floor(canvas1.width / 2);
let y1 = Math.floor(canvas1.height / 2);
draw1();
canvas1.addEventListener("keydown", (event) => {
switch (event.key) {
case "ArrowLeft":
x1 = x1 > 0 ? x1 - 1 : x1;
break;
case "ArrowRight":
x1 = x1 < 300 ? x1 + 1 : x1;
break;
case "ArrowUp":
y1 = y1 > 0 ? y1 - 1 : y1;
break;
case "ArrowDown":
y1 = y1 < 300 ? y1 + 1 : y1;
break;
default:
return;
}
event.preventDefault();
draw1();
});
function draw1() {
ctx1.fillRect(x1, y1, 1, 1);
}
// Canvas 2
const canvas2 = document.getElementById("canvas2");
const ctx2 = canvas2.getContext("2d");
let x2 = Math.floor(canvas2.width / 2);
let y2 = Math.floor(canvas2.height / 2);
ctx2.fillRect(x2, y2, 1, 1);
canvas2.addEventListener("keydown", (event) => {
let originalX = x2;
let originalY = y2;
switch (event.key) {
case "ArrowLeft":
x2 = x2 > 0 ? x2 - 5 : x2;
break;
case "ArrowRight":
x2 = x2 < 300 ? x2 + 5 : x2;
break;
case "ArrowUp":
y2 = y2 > 0 ? y2 - 5 : y2;
break;
case "ArrowDown":
y2 = y2 < 300 ? y2 + 5 : y2;
break;
default:
return;
}
event.preventDefault();
if (x2 !== originalX || y2 !== originalY) {
ctx2.strokeStyle = "blue";
ctx2.beginPath();
ctx2.moveTo(originalX, originalY);
ctx2.lineTo(x2, y2);
ctx2.closePath();
ctx2.stroke();
}
});
// Focus the first canvas by default
canvas1.focus();
html {
box-sizing: border-box;
font-family: sans-serif;
}
*, *:before, *:after {
box-sizing: inherit;
}
canvas {
border: 1px solid grey;
margin: 8px;
}
canvas:focus {
outline: green solid 3px;
}
<div>Canvas 1:</div>
<canvas id="canvas1" tabindex="0" width="200" height="200"></canvas>
<div>Canvas 2:</div>
<canvas id="canvas2" tabindex="0" width="200" height="200"></canvas>