Equalizer bar for muted audio - javascript

I am trying to create an audio equalizer through the guidance of this tutorial.
This works fine until you mute the audio through the controls(as shown in the image). Muting it also stops the equalizer bars.
How would I go about implementing the equalizer bars so that the bars don't stop even when the audio is muted?
let canvas,
ctx,
source,
context,
analyser,
fbc_array,
bar_count,
bar_pos,
bar_width,
bar_height;
let audio = new Audio();
audio.src = "test.mp3";
audio.controls = true; // Show audio controls so we can pause and play at will
audio.loop = true;
audio.autoplay = true;
window.addEventListener(
"load", // only executes after loading page fully
function() {
document.getElementById("audio").appendChild(audio); // putting the audio element inside the another HTML element
audio.onplay = function() {
if (typeof(context) === "undefined") {
context = new AudioContext();
analyser = context.createAnalyser();
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d"); // returns a drawing context
source = context.createMediaElementSource(audio); // creates an audio object which can be manipulated
canvas.width = window.innerWidth * 0.80;
canvas.height = window.innerHeight * 0.60;
source.connect(analyser);
analyser.connect(context.destination); // connect the analyzer and the context(which is used to draw)
}
FrameLooper(); // will handle all the animation and output
};
},
false
);
function FrameLooper() {
window.requestAnimationFrame(FrameLooper);
fbc_array = new Uint8Array(analyser.frequencyBinCount); // array for containing frequencies
bar_count = window.innerWidth / 2;
analyser.getByteFrequencyData(fbc_array);
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear old visual data
ctx.fillStyle = "#ffffff"; // fill it with white
/* For repainting */
for (let i = 0; i < bar_count; i++) {
bar_pos = i;
bar_width = 1;
bar_height = -(fbc_array[i] / 2);
ctx.fillRect(bar_pos, canvas.height, bar_width, bar_height);
}
}
body {
background: black;
padding: 0px;
margin: 0px;
}
div#player {
width: 80vw;
height: 60vh;
background: black;
margin: 20vh auto 0px auto;
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="styles.css">
<title>Equalizer bar</title>
</head>
<body>
<div id="player">
<div id="audio"></div>
<canvas id="canvas"></canvas>
</div>
</body>
<script type="text/javascript" src="functions.js"></script>
</html>

Related

Audio is playing without visualization

I am trying to play audio without any visualisation. I have used the code below :
<!doctype html>
<html>
<head>
<style>
div#mp3_player{ width:500px; height:120px; background:#000; padding:5px; margin:50px auto; border-radius: 10px; }
div#mp3_player > div > audio{ width:500px; background:#000; float:left; }
div#mp3_player > canvas{ width:500px; height:60px; padding: 0px; background:#ffffff; float:left; border-radius: 10px;}
</style>
<script>
window.AudioContext = window.AudioContext || window.webkitAudioContext;
// Create a new instance of an audio object and adjust some of its properties
var audio = new Audio();
audio.src = 'UncleFlexxx - Camry 3.5.mp3';
audio.controls = true;
audio.loop = true;
audio.autoplay = true;
// Establish all variables that your Analyser will use
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
// Initialize the MP3 player after the page loads all of its HTML into the window
window.addEventListener("load", initMp3Player, false);
function initMp3Player(){
document.getElementById('audio_box').appendChild(audio);
context = new webkitAudioContext(); // AudioContext object instance
analyser = context.createAnalyser(); // AnalyserNode method
canvas = document.getElementById('analyser_render');
ctx = canvas.getContext('2d');
// Re-route audio playback into the processing graph of the AudioContext
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frameLooper();
}
// frameLooper() animates any style of graphics you wish to the audio frequency
// Looping at the default frame rate that the browser provides(approx. 60 FPS)
function frameLooper(){
window.webkitRequestAnimationFrame(frameLooper);
fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array);
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
ctx.fillStyle = 'white'; // Color of the bars
bars = 100;
for (var i = 0; i < bars; i++) {
bar_x = i * 3;
bar_width = 4;
bar_height = -(fbc_array[i] / 2.5);
// fillRect( x, y, width, height ) // Explanation of the parameters below
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
}
</script>
</head>
<body>
<div id="mp3_player">
<div id="audio_box"></div>
<canvas id="analyser_render"></canvas>
</div>
</body>
</html>
I do not know what to do! I've tried injecting window.AudioContext = window.AudioContext || window.webkitAudioContext; but nothing has changed! I have no familiar programmers, so I came here, please help. Looks like google can't read this code or what I don't know.
Google considers context = new webkitAudioContext(); as an error !
Just add the audio tag into the dom
var audio = new Audio();
audio.src = 'UncleFlexxx - Camry 3.5.mp3';
audio.controls = true;
audio.loop = true;
audio.autoplay = true;
document.getElementById("mp3_player").appendChild(audio);

Load file and play audio on page load

I have have code that allows me to input an mp3 file, and output the audio and display a visual representation of the music. (Loading the file is done manually through an input type="file")
I no longer want to load a file from my computer, but instead automatically play the music on page load. The file is called song.mp3.
I not sure how to adjust my code to allow for the automatic play (I would like the visual representation to also work on load).
window.onload = function() {
var file = document.getElementById("thefile");
var audio = document.getElementById("audio");
file.onchange = function() {
var files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
var context = new AudioContext();
var src = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + (25 * (i/bufferLength));
var g = 250 * (i/bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + 0 + "," + 0 + "," + 0 + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
audio.play();
renderFrame();
};
};
#thefile {
position: fixed;
top: 10px;
left: 10px;
z-index: 100;
}
#canvas {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 50%;
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-o-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
}
audio {
position: fixed;
left: 10px;
bottom: 10px;
width: calc(100% - 20px);
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>JS Audio Visualizer</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="content">
<input type="file" id="thefile" accept="audio/*" />
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
</div>
<script src="./script.js"></script>
</body>
</html>
You just need to load and play audio file after you got audio tag from document.
var audio = document.getElementById("audio");
audio.src = URL.createObjectURL("song.mp3");
audio.load();
audio.play();
Because Chrome don't allow autoplay audio onload until user has an interactive with the webpage. So you need to add an hidden autoplay iframe with silence sound.
<iframe src="silence.mp3" allow="autoplay" id="audio" style="display:none"></iframe>
You can get silence sound file from here https://github.com/anars/blank-audio/blob/master/250-milliseconds-of-silence.mp3
Your js
window.onload = function() {
function renderVisual() {
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + (25 * (i/bufferLength));
var g = 250 * (i/bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + 0 + "," + 0 + "," + 0 + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
renderFrame();
}
var context = new AudioContext();
var file = document.getElementById("thefile");
var audio = document.getElementById("audio");
audio.src = "song.mp3";
audio.load();
var src = context.createMediaElementSource(audio);
audio.play();
renderVisual();
file.onchange = function() {
var files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
renderVisual();
};
};
Your html
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>JS Audio Visualizer</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="content">
<input type="file" id="thefile" accept="audio/*" />
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
<iframe src="silence.mp3" allow="autoplay" id="silence_audio" style="display:none"></iframe>
</div>
<script src="./script.js"></script>
</body>
</html>
Note: This will get error on Chrome if you open file directly on your local because of CORS. You need to host your website to a server (Nginx or Apache).
Here is the easiest way to play mp3 on page load
You just need to add control and autoplay attributes on the audio tag and then you can play autoplay music
<audio id="myAudio" controls autoplay>
<source src="music.mp3" type="audio/mpeg">
</audio>
Note: It will not work in local you need to host your file on the server
Reference Link: https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_audio_autoplay

Javascript Audio API Visualizer not showing in canvas

So i followed this tutorial: https://youtu.be/IBHpSkGZtNM
And a while back (about a year ago or so) it worked. Now however it doesn't visualize anything. The sound plays but thats it.
I changed the old webkit functions to the new ones as i was getting errors. However now i don't have any errors and still nothing shows up.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
div#mp3_player{ width: 500px; height: 60px; background: #000000; padding: 5px; margin: 50px auto;}
div#mp3_player > div > audio{ width: 500px; background: #000000; float: left;}
div#mp3_player > canvas{width: 500px; height: 30px; background: #002D3C; float: left;}
</style>
<script>
var audio = new Audio();
audio.src = "audio/DieForYou-Starset.mp3";
audio.controls = true;
audio.loop = true;
audio.autoplay = false;
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
window.addEventListener("load", initMp3Player, false);
function initMp3Player(){
document.getElementById("audio_box").appendChild(audio);
context = new AudioContext();
analyser = context.createAnalyser();
canvas = document.getElementById("analyser_renderer");
ctx = canvas.getContext("2d");
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frameLooper()
}
function frameLooper(){
window.requestAnimationFrame(frameLooper);
fbc_array = new Uint8Array(analyser.frequencyBinCount);
ctx.clearRect(0,0 ,canvas.width, canvas.height)
ctx.fillStyle= "#2DCC70";
bars = 100;
for(var i = 0; i < bars; i++){
bar_x = i * 3;
bar_width = 2;
bar_height = -(fbc_array[1] / 2);
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
}
</script>
</head>
<body>
<div id="mp3_player">
<div id="audio_box"></div>
<canvas id="analyser_renderer"></canvas>
</div>
</body>
</html>
I put everything in the html file because it was easier to post like that. I know it's bad practise.
Note: the sound wont play in the snippet because the audio file is stored locally.
I am also running this trough a local server as just opening the html file would result in MediaElementAudioSource outputs zeroes due to CORS access restrictions for file:///C:/xampp/htdocs/audio/DieForYou-Starset.mp3
You need to populate your array with one of the AnalyserNode methods, here you are only creating an empty one.
For example, you can call analyser.getByteFrequencyData(fbc_array); to get the current frequency data.
var audio = new Audio();
audio.crossOrigin = 'anonymous';
audio.src = "https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3";
audio.controls = true;
audio.loop = true;
audio.autoplay = false;
window.onload = initMp3Player;
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x, bar_width, bar_height;
function initMp3Player() {
document.getElementById("audio_box").appendChild(audio);
context = new AudioContext();
analyser = context.createAnalyser();
canvas = document.getElementById("analyser_renderer");
ctx = canvas.getContext("2d");
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
// initialise the Uint8Array only once
fbc_array = new Uint8Array(analyser.frequencyBinCount);
frameLooper()
}
function frameLooper() {
window.requestAnimationFrame(frameLooper);
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = "#2DCC70";
bars = 100;
// here fill the Uint8Array with audio data
analyser.getByteFrequencyData(fbc_array);
for (var i = 0; i < bars; i++) {
bar_x = i * 3;
bar_width = 2;
bar_height = -(fbc_array[i] / 2); // there was a typo
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
}
div#mp3_player {
width: 500px;
height: 60px;
background: #000000;
padding: 5px;
margin: 50px auto;
}
div#mp3_player>div>audio {
width: 500px;
background: #000000;
float: left;
}
div#mp3_player>canvas {
width: 500px;
height: 30px;
background: #002D3C;
float: left;
}
<div id="mp3_player">
<div id="audio_box"></div>
<canvas id="analyser_renderer"></canvas>
</div>

Creating an audio visualizer using HTML5

I am trying to use an audio visualisation for the stream of my online radio using the example that I found on this page.
However, similar to the problem found in this post , my audio file (even when testing with a local file) just does not sound and of course the visualisation does nothing as well.
My HTML is the following:
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<audio src="http://50.22.218.101:38838/;steam.mp3" id="audio"
controls>HTML5 Audio element not supported</audio>
<canvas id="canvas" width="800" height="350"></canvas>
<script src="main.js"></script>
</body>
</html>
This is "main.js":
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
window.onload = function() {
var audio = document.getElementById('audio');
var ctx = new AudioContext();
var analyser = ctx.createAnalyser();
var audioSrc = ctx.createMediaElementSource(audio);
// we have to connect the MediaElementSource with the analyser
audioSrc.connect(analyser);
analyser.connect(ctx.destination);
// we could configure the analyser: e.g. analyser.fftSize (for further infos read the spec)
// analyser.fftSize = 64;
// frequencyBinCount tells you how many values you'll receive from the analyser
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
// we're ready to receive some data!
var canvas = document.getElementById('canvas'),
cwidth = canvas.width,
cheight = canvas.height - 2,
meterWidth = 10, //width of the meters in the spectrum
gap = 2, //gap between meters
capHeight = 2,
capStyle = '#fff',
meterNum = 800 / (10 + 2), //count of the meters
capYPositionArray = []; ////store the vertical position of hte caps for the preivous frame
ctx = canvas.getContext('2d'),
gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(1, '#0f0');
gradient.addColorStop(0.5, '#ff0');
gradient.addColorStop(0, '#f00');
// loop
function renderFrame() {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var step = Math.round(array.length / meterNum); //sample limited data from the total array
ctx.clearRect(0, 0, cwidth, cheight);
for (var i = 0; i < meterNum; i++) {
var value = array[i * step];
if (capYPositionArray.length < Math.round(meterNum)) {
capYPositionArray.push(value);
};
ctx.fillStyle = capStyle;
//draw the cap, with transition effect
if (value < capYPositionArray[i]) {
ctx.fillRect(i * 12, cheight - (--capYPositionArray[i]), meterWidth, capHeight);
} else {
ctx.fillRect(i * 12, cheight - value, meterWidth, capHeight);
capYPositionArray[i] = value;
};
ctx.fillStyle = gradient; //set the filllStyle to gradient for a better look
ctx.fillRect(i * 12 /*meterWidth+gap*/ , cheight - value + capHeight, meterWidth, cheight); //the meter
}
requestAnimationFrame(renderFrame);
}
renderFrame();
audio.play();
};
Any idea what am I doing wrong?
You can usually fix this by simply adding a crossorigin option to your html audio tag
so this:
<audio src="http://50.22.218.101:38838/;steam.mp3" id="audio" controls>
becomes this:
<audio src="http://50.22.218.101:38838/;steam.mp3" crossorigin="anonymous" id="audio" controls>
Visualize stream using HTML5
Here's full example, combining #miknik's answer, your display code (which is awesome by the way), and a public web radio station
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
let audio = document.getElementById('audio')
let ctx = ""
let audioSrc = ""
function start(){
if (!ctx){
ctx = new AudioContext();
analyser = ctx.createAnalyser();
audioSrc = ctx.createMediaElementSource(audio)
// we have to connect the MediaElementSource with the analyser
audioSrc.connect(analyser)
analyser.connect(ctx.destination)
}
// we could configure the analyser: e.g. analyser.fftSize (for further infos read the spec)
// analyser.fftSize = 64;
// frequencyBinCount tells you how many values you'll receive from the analyser
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
// we're ready to receive some data!
var canvas = document.getElementById('canvas'),
cwidth = canvas.width,
cheight = canvas.height - 2,
meterWidth = 10, //width of the meters in the spectrum
gap = 2, //gap between meters
capHeight = 2,
capStyle = '#fff',
meterNum = 800 / (10 + 2), //count of the meters
capYPositionArray = []; ////store the vertical position of hte caps for the preivous frame
ctx = canvas.getContext('2d'),
gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(1, '#0f0');
gradient.addColorStop(0.5, '#ff0');
gradient.addColorStop(0, '#f00');
// loop
function renderFrame() {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var step = Math.round(array.length / meterNum); //sample limited data from the total array
ctx.clearRect(0, 0, cwidth, cheight);
for (var i = 0; i < meterNum; i++) {
var value = array[i * step];
if (capYPositionArray.length < Math.round(meterNum)) {
capYPositionArray.push(value);
};
ctx.fillStyle = capStyle;
//draw the cap, with transition effect
if (value < capYPositionArray[i]) {
ctx.fillRect(i * 12, cheight - (--capYPositionArray[i]), meterWidth, capHeight);
} else {
ctx.fillRect(i * 12, cheight - value, meterWidth, capHeight);
capYPositionArray[i] = value;
};
ctx.fillStyle = gradient; //set the filllStyle to gradient for a better look
ctx.fillRect(i * 12 /*meterWidth+gap*/ , cheight - value + capHeight, meterWidth, cheight); //the meter
}
requestAnimationFrame(renderFrame);
}
renderFrame();
audio.play();
}
function stop(){
audio.pause()
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#container {
position: absolute;
top: 0;
left: 0;
background: #000;
width: 100%;
height: 100%;
}
#canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
z-index: -1;
opacity: .8;
}
.button-container{
padding-top: 5px;
display: grid;
grid-template-columns: repeat(2,300px);
grid-gap: 1px;
width: 100%;
align-items: center;
justify-content: center;
}
button{
width: 300px;
text-align: center;
}
<html>
<link rel="stylesheet" type="text/css" href="style.css">
<body>
<audio src="https://rfcmedia.streamguys1.com/MusicPulse.mp3" crossorigin="anonymous" id="audio" >HTML5 Audio element not supported</audio>
<div class="button-container">
<button onclick="start()">Stream Radio</button>
<button onclick="stop()">Stop Radio</button>
</div>
<canvas id="canvas"></canvas>
<script src="main.js"></script>
</body>
</html>

Javascript becomes unresponsive after button presses

When I push the buttons (N and O ) maybe 10 times, the script becomes very unresponsive, does anyone have a solution for this?
What I'm trying to do is to have 2 menus in a game. This is a test which should have the same effect.
//html code
<!DOCTYPE html>
<html lang ="en">
<head>
<meta charset="UTF-8">
<title>Snake</title>
</head>
<body>
<style>
canvas{
display: block;
position: absolute;
border: 1px solid "Black";
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
</style>
<script type = "text/javascript" src = "menu2.js"></script>
<script type = "text/javascript" src = "menu1.js"></script>
<script type = "text/javascript" src = "main.js"></script>
<script type = "text/javascript">
main();
</script>
</body>
</html>
//main function
var
COLS = 20,
ROWS = 20,
canvas,
ctx,
keystate,
KEY_O = 79,
KEY_N = 78;
var main = function()
{
// create and initiate the canvas element
canvas = document.createElement("canvas");
canvas.width = COLS*20;
canvas.height = ROWS*20;
ctx = canvas.getContext("2d");
// add the canvas element to the body of the document
document.body.appendChild(canvas);
// sets an base font for bigger score display
ctx.font = "12px Ariel";
keystate = {};
// keeps track of the keybourd input
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
});
menu1();
};
//first menu
var menu1 = function()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "Red";
ctx.fillRect(0,0,canvas.height, canvas.width);
document.addEventListener('keydown', function(event) {
if (keystate[KEY_N]) {
menu2();
}});
};
//second menu
var menu2 = function()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,canvas.height, canvas.width);
document.addEventListener('keydown', function(event) {
if (keystate[KEY_O]) {
menu1();
}});
};
Each time you call menu2(); or menu1(); you are adding a new EventListener, which again calls menu2(); or menu1(); ...and more event listeners get added every time. This means that your number of event listeners grows at an enormous rate as you keep pressing keys, and slows the script down. You only need one EventListener per key, set it outside of the menu function.
issue is with adding eventListeners on each call of menu1 and menu2 .what you need is simply put it out side of both in main like this:
document.addEventListener('keydown', function(event) {
if (keystate[KEY_N]) {
menu2();
}
if (keystate[KEY_O]) {
menu1();
}
});
<!DOCTYPE html>
<html lang ="en">
<head>
<meta charset="UTF-8">
<title>Snake</title>
</head>
<body>
<style>
canvas{
display: block;
position: absolute;
border: 1px solid "Black";
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
</style>
<script type = "text/javascript">
var
COLS = 20,
ROWS = 20,
canvas,
ctx,
keystate,
KEY_O = 79,
KEY_N = 78;
var main = function()
{
// create and initiate the canvas element
canvas = document.createElement("canvas");
canvas.width = COLS*20;
canvas.height = ROWS*20;
ctx = canvas.getContext("2d");
// add the canvas element to the body of the document
document.body.appendChild(canvas);
// sets an base font for bigger score display
ctx.font = "12px Ariel";
keystate = {};
// keeps track of the keybourd input
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
if (keystate[KEY_N]) {
menu2();
}
if (keystate[KEY_O]) {
menu1();
}
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
});
menu1();
};
//first menu
var menu1 = function()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "Red";
ctx.fillRect(0,0,canvas.height, canvas.width);
};
//second menu
var menu2 = function()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,canvas.height, canvas.width);
};
main();
</script>
</body>
</html>
Note: open snippet window then click inside it then press o and n to see the effect.

Categories