How to create a moving waveform for a audio file/tag in HTML?
When play button is clicked,the audio HTML element must be played and a corresponding moving waveform for the same should be generated....how to implement this?
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title id='title'>HTML Page setup Tutorial</title>
<script src='riffwave.js'></script>
<script type="text/javascript">
function myFunction()
{
var data = []; // just an array
for (var i=0; i<10000; i++) data[i] = /*Math.round(255 * Math.random())*/i; // fill data with random samples
var wave = new RIFFWAVE(data); // create the wave file
var audio = new Audio(wave.dataURI); // create the HTML5 audio element
audio.play();
}
</script>
</head>
<body>
<button type="button" onclick="myFunction()">Click Me!</button>
</body>
</html>
I want to create a waveform like this
Same as below but then with canvasjs:
Demo: http://seapip.com/canvas/visualizer4/
/*
Speed has to be bigger then refresh!!!
*/
//Speed to move from right to left, also the visible amount of time on the x axis (in milliseconds)
var speed = 10000;
//Time in milliseconds to redraw chart
var refresh = 30;
//Without var to make it a global variable accessable by the html onclick attribute
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
//Get frequency data
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
//The animation reference
var animation;
//Create chart
var dps = []; // dataPoints
var chart = new CanvasJS.Chart("chart", {
interactivityEnabled: false,
width: 500,
height: 200,
axisX: {
title: "Time",
valueFormatString: "mm:ss"
},
axisY: {
title: "dB"
},
data: [{
type: "line",
dataPoints: dps
}]
});
chart.render();
//On play
audioElement.onplay = function() {
//Start drawing
animation = setInterval(function() {
drawWave();
}, refresh);
};
//On pause
audioElement.onpause = function() {
//Stop drawing
clearInterval(animation);
};
//On ended
audioElement.onended = function() {
//Stop drawing
clearInterval(animation);
//Reset time
time = 0;
//Reset dataPoints
dps = [];
//Prevent audio from looping (you can remove this if you want it to loop)
audioElement.pause();
};
//Max dB
var max = analyser.maxDecibels;
//Min dB
var min = analyser.minDecibels;
//Time
var time = 0;
//Our drawing method
function drawWave() {
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
//Total loudness of all frequencies in frequencyData
var totalLoudness = 0;
for(var i = 0; i < frequencyData.length; i++) {
totalLoudness += frequencyData[i];
}
//Average loudness of all frequencies in frequencyData on scale from 0 to 255
var averageLoudness = totalLoudness / frequencyData.length / 255;
//Decibels
var decibels = min + averageLoudness * Math.abs(min - max);
//Increase time
time += refresh;
//Add to chart
dps.push({
x: new Date(time),
y: decibels
});
//Maximum x values to draw based on speed ad refresh
if(dps.length > speed / refresh) {
dps.shift();
}
//Draw new chart
chart.render();
}
<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<div id="chart"></div>
<div>
<button onclick="audioElement.play()">Play the Audio</button>
<button onclick="audioElement.pause()">Pause the Audio</button>
<button onclick="audioElement.volume+=0.1">Increase Volume</button>
<button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>
Keep in mind that #chart is a div instead of a canvas element, it took me a few minutes to find out why the chart wasn't showing at first :P
Same as below but with plotting from right to left. The stepSize variable sets both the animation speed and the size of the steps, if you want bigger steps to be drawn in then it needs to move faster and if you want smaller steps to be drawn it needs to move slower.
Demo: http://seapip.com/canvas/visualizer3
//Step size (pixels per 20ms)
var stepSize = 0.5;
//Without var to make it a global variable accessable by the html onclick attribute
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
//Get frequency data (800 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);
//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "500px";
canvas.style.height = "100px";
//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;
//Get canvas context
var ctx = canvas.getContext("2d");
//Stroke color
ctx.strokeStyle = "#ffff00";
//Draw thicker lines due to high dpi scaling
ctx.lineWidth = 2;
//Store y values
var drawY = [canvas.height];
//The animation reference
var animation;
//On play
audioElement.onplay = function() {
//Start drawing
animation = setInterval(function() {
drawWave();
}, 20);
};
//On pause
audioElement.onpause = function() {
//Stop drawing
clearInterval(animation);
};
//On ended
audioElement.onended = function() {
//Stop drawing
clearInterval(animation);
//Clear previous y values
drawY = [canvas.height];
//Prevent audio from looping (you can remove this if you want it to loop)
audioElement.pause();
};
//Our drawing method
function drawWave() {
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
//Total loudness of all frequencies in frequencyData
var totalLoudness = 0;
for(var i = 0; i < frequencyData.length; i++) {
totalLoudness += frequencyData[i];
}
//Average loudness of all frequencies in frequencyData
var averageLoudness = totalLoudness / frequencyData.length;
//Scale of average loudness from (0 to 1), frequency loudness scale is (0 to 255)
var y = averageLoudness / 255;
//Multiply with canvas height to get scale from (0 to canvas height)
y *= canvas.height;
//Since a canvas y axis is inverted from a normal y axis we have to flip it to get a normal y axis value
y = canvas.height - y;
//Store new y value
drawY.push(y);
//Clear previous drawing
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Draw line
for(var i = drawY.length; i > 0; i--) {
//calculate x values
var x1 = canvas.width - (drawY.length - i - 1) * stepSize;
var x2 = canvas.width - (drawY.length - i) * stepSize;
//Stop drawing y values if the x value is outside the canvas
if(!x2) {
break;
}
ctx.beginPath();
ctx.moveTo(x1, drawY[i - 1]);
ctx.lineTo(x2, drawY[i]);
ctx.stroke();
}
}
<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
<button onclick="audioElement.play()">Play the Audio</button>
<button onclick="audioElement.pause()">Pause the Audio</button>
<button onclick="audioElement.volume+=0.1">Increase Volume</button>
<button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>
Here's what I think you probably wanted, x axis is the time and y axis is the average loudness of all frequencies. Keep in mind that browsers like chrome don't draw the graph properly in a background tab because it limits the refresh interval and audio analyzer output.
Demo: http://seapip.com/canvas/visualizer2
//Without var to make it a global variable accessable by the html onclick attribute
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
//Get frequency data (800 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);
//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "1000px";
canvas.style.height = "100px";
//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;
//Get canvas context
var ctx = canvas.getContext("2d");
//Set stroke color to yellow
ctx.strokeStyle = "#ffff00";
//Draw twice as thick lines due to high dpi scaling
ctx.lineWidth = 2;
//Save x and y from the previous drawing
var drawX = 0;
var drawY = 0;
//Total duration (Seconds)
var duration;
//The animation reference
var animation;
//Audio is loaded
audioElement.oncanplaythrough = function() {
//Get duration
duration = audioElement.duration;
//On play
audioElement.onplay = function() {
//Start drawing
drawWave();
};
//On pause
audioElement.onpause = function() {
//Stop drawing
cancelAnimationFrame(animation);
};
//On ended
audioElement.onended = function() {
//Stop drawing
cancelAnimationFrame(animation);
//Clear previous drawing
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Clear previous x and y values
drawX = 0;
drawY = 0;
//Prevent audio from looping (you can remove this if you want it to loop)
audioElement.pause();
};
};
//Our drawing method
function drawWave() {
//Current time (seconds)
var currentTime = audioElement.currentTime;
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
//Total loudness of all frequencies in frequencyData
var totalLoudness = 0;
for(var i = 0; i < frequencyData.length; i++) {
totalLoudness += frequencyData[i];
}
//Average loudness of all frequencies in frequencyData
var averageLoudness = totalLoudness / frequencyData.length;
//Get the previous x axis value
var previousDrawX = drawX;
//Scale of progress in song (from 0 to 1)
drawX = currentTime / duration;
//Multiply with canvas width to get x axis value
drawX *= canvas.width;
//Get the previous y axis value
var previousDrawY = drawY;
//Scale of average loudness from (0 to 1), frequency loudness scale is (0 to 255)
drawY = averageLoudness / 255;
//Multiply with canvas height to get scale from (0 to canvas height)
drawY *= canvas.height;
//Since a canvas y axis is inverted from a normal y axis we have to flip it to get a normal y axis value
drawY = canvas.height - drawY;
//Draw line
ctx.beginPath();
ctx.moveTo(previousDrawX, previousDrawY);
ctx.lineTo(drawX, drawY);
ctx.stroke();
//Animate
animation = requestAnimationFrame(drawWave);
}
<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
<button onclick="audioElement.play()">Play the Audio</button>
<button onclick="audioElement.pause()">Pause the Audio</button>
<button onclick="audioElement.volume+=0.1">Increase Volume</button>
<button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>
Canvas visualizer example
Demo: http://seapip.com/canvas/visualizer/
//Without var to make it a global variable accessable by the html onclick attribute
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
//Get frequency data (400 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);
//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "500px";
canvas.style.height = "100px";
//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;
//Get canvas context
var ctx = canvas.getContext("2d");
//Set stroke color
ctx.strokeStyle = "#ffff00"
//Draw twice as thick lines due to high dpi scaling
ctx.lineWidth = 2;
//Animation reference
var animation;
//On play
audioElement.onplay = funtion() {
drawWave();
};
//On pause
audioElement.onpause = funtion() {
cancelAnimationFrame(animation);
};
//On ended
audioElement.onended = funtion() {
cancelAnimationFrame(animation);
};
//Our drawing method
function drawWave() {
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
//Draw the wave
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 1; i < frequencyData.length; i++) {
var x1 = canvas.width / (frequencyData.length - 1) * (i - 1);
var x2 = canvas.width / (frequencyData.length - 1) * i;
var y1 = canvas.height - frequencyData[i - 1] / 255 * canvas.height;
var y2 = canvas.height - frequencyData[i] / 255 * canvas.height;
if(x1 && y1 && x2 && y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
}
//Animate
animation = requestAnimationFrame(drawWave);
}
<audio id="audioElement" src="audio/Odesza - Above The Middle.mp3"></audio>
<canvas id="wave"></canvas>
<div>
<button onclick="document.getElementById('audioElement').play()">Play the Audio</button>
<button onclick="document.getElementById('audioElement').pause()">Pause the Audio</button>
<button onclick="document.getElementById('audioElement').volume+=0.1">Increase Volume</button>
<button onclick="document.getElementById('audioElement').volume-=0.1">Decrease Volume</button>
</div>
Plugins and tutorials about audio visualization:
https://wavesurfer-js.org/
http://waveformjs.org/#weird
https://www.bignerdranch.com/blog/music-visualization-with-d3-js/
https://github.com/wayou/HTML5_Audio_Visualizer
https://www.patrick-wied.at/blog/how-to-create-audio-visualizations-with-javascript-html
https://p5js.org/examples/examples/Sound_Frequency_Spectrum.php
Related
I found these two pieces of code and I'm quite new to Java. Essentially I'd like to be able to select the image from a file selector (like the first piece of code) instead of specifying the url of an image. Also, is there a way that I could output a list of all the coordinates to the console pr ideally create a txt file with the coords in?
I've left links to jsfiddle for both
thank you!!
http://jsfiddle.net/edprattt/m2a1j8yf/
https://jsfiddle.net/edprattt/8xqo71Lk/
##1
function showImage(src, target) {
var fr = new FileReader();
fr.onload = function(){
target.src = fr.result;
}
fr.readAsDataURL(src.files[0]);
}
function putImage() {
var src = document.getElementById("select_image");
var target = document.getElementById("target");
showImage(src, target);
}
##2
var canvas = document.getElementById('Canvas');
var context = canvas.getContext("2d");
var mapSprite = new Image();
mapSprite.src = "http://www.retrogameguide.com/images/screenshots/snes-legend-of-zelda-linkto-the-past-8.jpg";
var Marker = function () {
this.Sprite = new Image();
this.Sprite.src = "http://www.clker.com/cliparts/w/O/e/P/x/i/map-marker-hi.png"
this.Width = 12;
this.Height = 20;
this.XPos = 0;
this.YPos = 0;
}
var Markers = new Array();
var mouseClicked = function (mouse) {
// Get corrent mouse coords
var rect = canvas.getBoundingClientRect();
var mouseXPos = (mouse.x - rect.left);
var mouseYPos = (mouse.y - rect.top);
console.log("Marker added");
var marker = new Marker();
marker.XPos = mouseXPos - (marker.Width / 2);
marker.YPos = mouseYPos - marker.Height;
Markers.push(marker);
}
canvas.addEventListener("mousedown", mouseClicked, false);
var firstLoad = function () {
context.font = "15px Georgia";
context.textAlign = "center";
}
firstLoad();
var main = function () {
draw();
};
var draw = function () {
// Clear Canvas
context.fillStyle = "#000";
context.fillRect(0, 0, canvas.width, canvas.height);
// Draw map
// Sprite, X location, Y location, Image width, Image height
// You can leave the image height and width off, if you do it will draw the image at default size
context.drawImage(mapSprite, 0, 0, 700, 700);
// Draw markers
for (var i = 0; i < Markers.length; i++) {
var tempMarker = Markers[i];
// Draw marker
context.drawImage(tempMarker.Sprite, tempMarker.XPos, tempMarker.YPos, tempMarker.Width, tempMarker.Height);
// Calculate postion text
var markerText = "Postion (X:" + tempMarker.XPos + ", Y:" + tempMarker.YPos;
// Draw a simple box so you can see the position
var textMeasurements = context.measureText(markerText);
context.fillStyle = "#666";
context.globalAlpha = 0.7;
context.fillRect(tempMarker.XPos - (textMeasurements.width / 2), tempMarker.YPos - 15, textMeasurements.width, 20);
context.globalAlpha = 1;
// Draw position above
context.fillStyle = "#000";
context.fillText(markerText, tempMarker.XPos, tempMarker.YPos);
}
};
setInterval(main, (1000 / 60)); // Refresh 60 times a second
I tried to make Audio Wave Visualization through this Post
Play a moving waveform for wav audio file in html
HERE IS CODE
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Audio Visualizer</title>
<script type="text/javascript" src="visualization.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<audio id="audioElement" src="bensound-perception.mp3"></audio>
<canvas id="wave"></canvas>
<div>
<button onclick="audioElement.play()">Play the Audio</button>
<button onclick="audioElement.pause()">Pause the Audio</button>
<button onclick="audioElement.volume+=0.1">Increase Volume</button>
<button onclick="audioElement.volume-=0.1">Decrease Volume</button>
</div>
<figure>
<figcaption>Listen to the Track:</figcaption>
<audio
controls
src="bensound-perception.mp3">
Your browser does not support the
<code>audio</code> element.
</audio>
</figure>
</body>
</html>
HERE IS JS CODE
audioElement = document.getElementById('audioElement');
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var audioSrc = audioCtx.createMediaElementSource(audioElement);
var analyser = audioCtx.createAnalyser();
// Bind our analyser to the media element source.
audioSrc.connect(analyser);
audioSrc.connect(audioCtx.destination);
//Get frequency data (800 = max frequency)
var frequencyData = new Uint8Array(400);
//Use below to show all frequencies
//var frequencyData = new Uint8Array(analyser.frequencyBinCount);
//Create canvas
var canvas = document.getElementById("wave");
canvas.style.width = "1000px";
canvas.style.height = "100px";
//High dpi stuff
canvas.width = parseInt(canvas.style.width) * 2;
canvas.height = parseInt(canvas.style.height) * 2;
//Get canvas context
var ctx = canvas.getContext("2d");
//Set stroke color to yellow
ctx.strokeStyle = "#ffff00";
//Draw twice as thick lines due to high dpi scaling
ctx.lineWidth = 2;
//Save x and y from the previous drawing
var drawX = 0;
var drawY = 0;
//Total duration (Seconds)
var duration;
//The animation reference
var animation;
//Audio is loaded
audioElement.oncanplaythrough = function() {
//Get duration
duration = audioElement.duration;
//On play
audioElement.onplay = function() {
//Start drawing
drawWave();
};
//On pause
audioElement.onpause = function() {
//Stop drawing
cancelAnimationFrame(animation);
};
//On ended
audioElement.onended = function() {
//Stop drawing
cancelAnimationFrame(animation);
//Clear previous drawing
ctx.clearRect(0, 0, canvas.width, canvas.height);
//Clear previous x and y values
drawX = 0;
drawY = 0;
//Prevent audio from looping (you can remove this if you want it to loop)
audioElement.pause();
};
};
//Our drawing method
function drawWave() {
//Current time (seconds)
var currentTime = audioElement.currentTime;
// Copy frequency data to frequencyData array.
analyser.getByteFrequencyData(frequencyData);
//Total loudness of all frequencies in frequencyData
var totalLoudness = 0;
for(var i = 0; i < frequencyData.length; i++) {
totalLoudness += frequencyData[i];
}
//Average loudness of all frequencies in frequencyData
var averageLoudness = totalLoudness / frequencyData.length;
//Get the previous x axis value
var previousDrawX = drawX;
//Scale of progress in song (from 0 to 1)
drawX = currentTime / duration;
//Multiply with canvas width to get x axis value
drawX *= canvas.width;
//Get the previous y axis value
var previousDrawY = drawY;
//Scale of average loudness from (0 to 1), frequency loudness scale is (0 to 255)
drawY = averageLoudness / 255;
//Multiply with canvas height to get scale from (0 to canvas height)
drawY *= canvas.height;
//Since a canvas y axis is inverted from a normal y axis we have to flip it to get a normal y axis value
drawY = canvas.height - drawY;
//Draw line
ctx.beginPath();
ctx.moveTo(previousDrawX, previousDrawY);
ctx.lineTo(drawX, drawY);
ctx.stroke();
//Animate
animation = requestAnimationFrame(drawWave);
}
HERE IS CSS
figure {
margin: 0;
}
But it doesn't work for me, and shows Some Errors on Console also on Page it only Shows Buttons but not Audio Visualization and Audio works perfectly thats why i used figure block to test it.....
Please see the Screenshots i attached.
Console Error and Output
I also Tried other Posts already discussed on Stackoverflow but didn't found any relevent and easy like above one.
If anyone can help me with this then i would be Thankful.
Thanks in Advance
The error indicates that your JS code cannot find the <audio /> element. Make sure you have this element on the page and you reference it in document.getElementById(...) using the actual element's ID.
I'm using a simple clearInterval draw animation to animate a spritesheet. I have two animations and have set the canvas size the same for both. I have checked the width of the spritesheet to make sure it's correct. For some reason the animation executes but my character slides left and part of the next frame becomes visible before starting the animation over. I've checked over and over for bugs. Hopefully just missed something easy. Here is my code. Spritesheet with issue is posted in a link at the bottom of post. Thank you so much.
// QUIZGAME ANIMATION
var canvasWidth = 200;
var canvasHeight = 250;
var canvas2Height = 250;
var canvas2Width = 200;
var canvas1 = document.getElementById("canvas1");
var canvas2 = document.getElementById("canvas2");
document.addEventListener("DOMContentLoaded", function(event) {
canvas1.width = canvasWidth;
canvas1.height = canvasHeight;
canvas2.height = canvas2Height;
canvas2.width = canvas2Width;
});
var spriteWidth = 605;
var spriteHeight = 200;
var sprite2Width = 1632;
var sprite2Height = 200;
var columns = 3;
var rows = 1;
var columns2 = 11;
var rows2 = 1;
var width = spriteWidth / columns;
var height = spriteHeight / rows;
var height2 = sprite2Height / rows2;
var width2 = sprite2Width / columns2;
var curFrame = 0;
var curFrame2 = 0;
var frameCount = 3;
var frameCount2 = 11;
var x = 0;
var y = 0;
var x2 = 0;
var y2 = 0;
var frameX = 0;
var frameY = 0;
var frameX2 = 0;
var frameY2 = 0;
var ctx = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var character = new Image();
var character2 = new Image();
character.src = "img/testanimation.png";
character2.src = "https://i.stack.imgur.com/7uRCO.png";
function changeFrameIndex() {
curFrame = ++curFrame % frameCount;
frameX = curFrame * width;
ctx.clearRect(x, y, width, height);
}
function changeFrame2Index() {
curFrame2 = ++curFrame2 % frameCount2;
frameX2 = curFrame2 * width2;
ctx2.clearRect(x2, y2, width2, height2);
}
function draw() {
//Updating the frame
changeFrameIndex();
//Drawing the image
ctx.drawImage(character, frameX, frameY, width, height, x, y, width, height);
}
function draw2() {
changeFrame2Index();
ctx2.drawImage(character2, frameX2, frameY2, width2, height2, x2, y2, width2, height2);
}
//setInterval(draw, 140); // disabled by editor because source is unavailable
setInterval(draw2, 100);
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
spritesheet with issue
I have partially resolved the issue but I'm still a little confused. I cropped some empty space off the end of the spritesheet (making sprite2Width = 1604 instead of the original 1632) which helped, reducing the motion to next to none, but for some reason I still have to clarify a width that is 4-6 px shorter than the actual png. The animation is working now after cropping spritesheet width at 1604px and setting the sprite2Width = 1598; (as opposed to 1604). Anyone have any idea why there is a 6 px difference here? CSS related maybe? Atleast it is working.
The first thing you should do when troubleshooting something like that is simplify your code...
Take it to the bare basic, then start playing with the variables that build each frame, yes like you find out there is a 6px padding on each sprite, you can compensate that on code see the calculation of the width.
var character = new Image();
character.src = "https://i.stack.imgur.com/7uRCO.png";
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var spriteWidth = 1632;
var columns = 11;
var width = (spriteWidth / columns) - 3;
var curFrame = 0;
function draw() {
ctx.clearRect(0, 0, 900, 900);
curFrame = ++curFrame % columns;
ctx.drawImage(character, curFrame * width, 0, width, 200, 0, 0, width, 200);
}
setInterval(draw, 100);
<canvas id="canvas" height=175></canvas>
...and for the record that sprite is not the best looking one
I've made an attempt at creating a simple audio visualizer for an mp3 track using canvas to draw/ animate circles in sync with the audio track using the web audio API.
What i've done so far:
What I want to do basically now is change the colours of the circles at a certain amount of time (eg. at a different part of the track - the drop etc). How would I go about doing this? setTimeout? I had a search but could not find anything (and I'm still quite new to JavaScript).
Here is the full code.
// Estabilish all variables tht analyser will use
var analyser, canvas, ctx, random = Math.random, circles = [];
// begins once all the page resources are loaded.
window.onload = function() {
canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
ctx = canvas.getContext('2d', {alpha: false});
setupWebAudio(); //loads audio track
for (var i = 0; i < 20; i++) { // loop runs 50 times - creating 49 circles
circles[i] = new Circle();
circles[i].draw();
}
draw();
};
function setupWebAudio() {
var audio = document.createElement('audio');
audio.src = 'rustie.mp3';
audio.controls = true;
document.body.appendChild(audio);
var audioContext = new AudioContext(); // AudioContext object instance (WEB AUDIO API)
//contains an audio signal graph representing connections betweens AudioNodes
analyser = audioContext.createAnalyser(); // Analyser method
var source = audioContext.createMediaElementSource(audio);
// Re-route audio playback into the processing graph of the AudioContext
source.connect(analyser);
analyser.connect(audioContext.destination);
audio.play();
}
function draw() {
requestAnimationFrame(draw);
var freqByteData = new Uint8Array(analyser.frequencyBinCount); //Array of the frequency data from the audio track (representation of the sound frequency)
analyser.getByteFrequencyData(freqByteData); //take the analyser variable run it through the getByteFrequencyData method - passing through the array
ctx.fillStyle = "#ff00ed";
ctx.fillRect(0, 0, canvas.width, canvas.height); //fill the canvas with colour
for (var i = 1; i < circles.length; i++) {
circles[i].radius = freqByteData[i] * 1;
circles[i].y = circles[i].y > canvas.height ? 0 : circles[i].y + 1;
circles[i].draw();
}
}
function Circle() {
this.x = random() * canvas.width; // creates random placement of circle on canvas
this.y = random() * canvas.height;
this.radius = random() * 20 + 20; //creates random radius of circle
this.color = 'rgb(6,237,235)'; //colour of circles
}
Circle.prototype.draw = function() { //Drawing path
var that = this;
ctx.save();
ctx.beginPath();
ctx.globalAlpha = 0.75; //Transparency level
ctx.arc(that.x, that.y, that.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.restore();
}
Another thing to add also - where in the code is it setting the movement/path of the circles? As they are going from the top to the bottom of the canvas. Wanted to know if I could change this.
Question 1
Instead of hard coding the circle color to this.color = 'rgb(6,237,235)';, you can use a global variable to hold the hue var hue = 0; and then use that in your Circle.draw() like this: ctx.fillStyle = 'hsla(' + hue + ', 50%, 50%, 0.75)';
Note 1: by defining the alpha in the color, you no longer need to set ctx.globalAlpha.
Note 2: you don't need this.color any more.
As you say, you can use setTimeout to change the hue variable at a certain point in time. Or you can use the data in freqByteData to change the hue variable continuously.
More info about hsl color: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#hsl()_and_hsla()
Question 2
You are updating the y coordinate of each circle with this line:
circles[i].y = circles[i].y > canvas.height ? 0 : circles[i].y + 1;
Which means: if current y position is greater than the canvas height: set the new value to zero, otherwise increment by one.
I'm trying to create a sinusoidal text scrolling animation in HTML5 canvas, but I can't figure out how to animate each letter differently.
I know I can use .split('') to get an array that contains all the characters in the string. I tried using a for loop for (var i = 0; i < chars.length; i++) but that didn't do what I was expecting (all characters in the array were smooshed together). I was hoping somebody with the experience could help me out with the code and write comments in it, so that I can learn this.
What I already have is below. As you can see, it doesn't animate each letter. See this video for what I am trying to do.
// Canvas
var c = document.getElementById('c');
var ctx = c.getContext('2d');
var seconds = Date.now();
var offsetY = 220;
var offsetX = 490;
var chars = 'abc';
var amplitude = 50;
var textcolor ='#fff';
var backgroundcolor = '#000';
// Options
c.height = 500; // Canvas HEIGHT
c.width = 500; // Canvas WIDTH
function animate() {
var y = Math.floor((Date.now() - seconds) / 10) / 30;
var yPos = Math.sin((y)) * amplitude;
ctx.fillStyle = backgroundcolor;
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = textcolor;
ctx.fillText(chars, offsetX--, offsetY + yPos);
if (offsetX == 0) {
offsetX = 490;
}
// Loop it
requestAnimationFrame(animate);
}
// Start animation
requestAnimationFrame(animate);
<!doctype html>
<html>
<head>
<title>Sinus Scroller</title>
</head>
<body>
<canvas id="c">
</canvas>
</body>
</html>
It's desirable to warp the letters to the sine wave because the distance from one character to the next grows as the slope of the wave increases. If you avoid warping and simply implement the wave with constant speed in x and with y = sin(x) for each letter, you'll see inter-character gaps growing on the steep portions of the sine wave and shrinking near the optima.
At any rate, here is the simple implementation:
var text = 'Savor the delightful flavor of Bubba-Cola',
canvasWidth = 620,
canvasHeight = 200,
rightEdgeBuffer = 50;
WebFont.load({ // Web Font Loader: https://github.com/typekit/webfontloader
google: {
families: ['Source Sans Pro']
},
active: function () { // Gets called when font loading is done.
var canvas = document.getElementsByTagName('canvas')[0],
context = canvas.getContext('2d'),
yZero = canvasHeight / 2, // Set axis position and amplitude
amplitude = canvasHeight / 4, // according to canvas dimensions.
textColor ='#fff',
backgroundColor = '#000';
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.font = "32px 'Source Sans Pro', monospace";
var pos = canvasWidth; // Split the text into characters.
var units = text.split('').map(function (char) {
var width = context.measureText(char).width,
unit = { char: char, width: width, pos: pos };
pos += width; // Calculate the pixel offset of each character.
return unit;
});
var running = true,
lapTime; // Set this before the first animation call.
function animate() {
var currentTime = Date.now(),
dp = (currentTime - lapTime) / 15; // Displacement in pixels.
lapTime = currentTime;
context.fillStyle = backgroundColor;
context.fillRect(0, 0, canvasWidth, canvasHeight);
units.forEach(function (unit) {
unit.pos -= dp; // Update char position.
if (unit.pos < -unit.width) { // Wrap around from left to right.
unit.pos += canvasWidth + rightEdgeBuffer;
}
var y = Math.sin(unit.pos / 45) * amplitude;
context.fillStyle = textColor;
context.fillText(unit.char, unit.pos, yZero + y);
});
if (running) {
requestAnimationFrame(animate);
}
}
document.getElementById('stopButton').onclick = function () {
running = false;
};
lapTime = Date.now();
requestAnimationFrame(animate);
}
});
<script
src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js"
></script>
<canvas></canvas>
<button id="stopButton"> stop </button>
Here is a more complete implementation with rectilinearly warped characters:
https://github.com/michaellaszlo/wavy-text