dynamic rectangles on canvas - javascript

I'm trying to make each rectangle in this fiddle to move up and down so it looks like a music equalizer. I wants the bars to animate up and down, and have absolutely no idea how to do animations. Fiddles would really help :)
http://jsfiddle.net/kiransh/1jqhznt6/
HTML
<canvas id="myCanvas" height="100"> </canvas>
JavaScript
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total/2+52;
var min = total/2-60;
ctx.fillStyle = "black";
ctx.globalAlpha=0.3;
for(var x = 0; x<total; x+=12)
{
if(x<= max && x>=min)
{
var height= Math.floor(Math.random()*40)+5;
}
else
{
var height= Math.floor(Math.random()*100)+5;
}
ctx.fillRect(x,100-height,width,height);
}

I don't know if this is the effect you need, but it should help you to start.
requestAnimationFrame is used to execute draw() at each frame. Each bar is re-defined after the specified delay, and then goes down.
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total/2+52;
var min = total/2-60;
ctx.fillStyle = "black";
ctx.globalAlpha=0.3;
var bars = [];
var barsCount = Math.floor(total / 12);
var barsLastRefreshTime = null;
var barsRefreshInterval = 500;
setInterval(function() {
for(var i = 0; i<barsCount; i++) {
var x = i * 12;
if(x<= max && x>=min) {
var height= Math.floor(Math.random()*40)+5;
} else {
var height= Math.floor(Math.random()*100)+5;
}
bars[i] = height;
}
barsLastRefreshTime = (new Date()).getTime();
}, barsRefreshInterval);
function draw() {
var currentTime = (new Date()).getTime();
var timePassedRate = (barsRefreshInterval - (currentTime - barsLastRefreshTime)) / barsRefreshInterval;
ctx.clearRect(0,0,c.width,c.height);
for(var i = 0; i<bars.length; i++) {
var x = i * 12;
var height = bars[i] * timePassedRate;
ctx.fillRect(x,100-height,width,height);
}
requestAnimationFrame(draw);
}
draw();
(I can't find a way to save the fiddle ?!?)

You need to use a tick function to update your canvas. You can use requestAnimationFrame() and choose a time interval you'd like to animate on (you can determine this using Date.now()).
Then, keep a list of your bars and change their height. Then re-render it to your canvas.
Here is some quick hacky code...
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total / 2 + 52;
var min = total / 2 - 60;
ctx.fillStyle = "black";
ctx.globalAlpha = 0.3;
var lastDrawTime = Date.now();
var draw = function () {
if (Date.now() - lastDrawTime < 60) {
return webkitRequestAnimationFrame(draw);
}
ctx.clearRect(0, 0, c.width, c.height);
for (var x = 0; x < total; x += 12) {
if (x <= max && x >= min) {
var height = Math.floor(Math.random() * 40) + 5;
} else {
var height = Math.floor(Math.random() * 100) + 5;
}
ctx.fillRect(x, 100 - height, width, height);
}
lastDrawTime = Date.now();
webkitRequestAnimationFrame(draw);
};
draw();

To do animation you have to clear the canvas and redraw the rectangles in their new position at each frame, using either setInterval() or setTimeout() or requestAnimationFrame().
The best is to use requestAnimationFrame() for adapation of frames per second.

Related

How to change speed based on gravity, and angle of movement

I am making a simple project where a dot is orbiting another dot. I could not find a mathematical formula to change the speed of the dot based on its movement direction proportional to the gravity. I have not taken physics yet so all of this is still very hard to me.
var c = document.createElement("canvas");
c.width = window.innerWidth;
c.height = window.innerHeight;
c.style = "position:absolute; top: 0; left: 0; background-color: black;";
document.body.appendChild(c);
var ctx = c.getContext("2d");
var shipX = 50;
var shipY = 0;
var moveDir = 0;
var speed = 8;
var halfX = window.innerWidth/2;
var halfY = window.innerHeight/2;
var gravSpeed = 0.7;
function pixelOn(x,y){
ctx.fillStyle = "white";
ctx.fillRect(x,y,2,2);
}
function draw(){
pixelOn(halfX,halfY);
pixelOn(shipX+halfX,halfY-shipY);
shipX += Math.sin(moveDir*Math.PI/180)*speed;
shipY += Math.cos(moveDir*Math.PI/180)*speed;
var gravDir = Math.atan2(-shipX,-shipY);
var nd = Math.atan2(Math.sin(moveDir*Math.PI/180-gravDir), Math.cos(moveDir*Math.PI/180-gravDir))*180/Math.PI;
moveDir -= nd/(speed/gravSpeed);
//change speed on movement direction here
}
setInterval(function(){
draw();
},50);

How to set onclick event in moving object in canvas?

How to set on click event in moving object in canvas? Also how to move the object bottom to top in canvas.I am newly in javascript i am going to develop the sample like when the page open, objects like square and circle randomly come from bottom of the page and move to top automatically.
You need to establish an array that will have your moving objects in it. When the onclick handler fires, check to see if the coordinates of the click are inside any of the objects in the array.
On each animation frame, move your objects up by subtracting some of the y coordinate from each object.
//width and height of canvas...
var rW = 400;
var rH = 500;
var coinImage = getCoinImage();
var coinsOnScreen = [];
var risingSpeed = 100; //pixels per second...
var coinSize = 75;
var lastAnimationTime = 0;
var howLongUntilNextCoin = 1000;
var nextCoinOnScreen = 0;
function doDraw() {
var can = document.getElementById("myCanvas");
can.width = rW;
can.height = rH;
var context = can.getContext("2d");
//Erase the canvas
context.fillStyle = "#FFFFFF";
context.fillRect(0, 0, rW, rH);
if (new Date().getTime() - nextCoinOnScreen > 0) {
var newX = Math.floor(Math.random() * rW) + 1;
var newY = rH + 50;
var newCoin = {
x: newX,
y: newY
};
coinsOnScreen.push(newCoin);
nextCoinOnScreen = new Date().getTime() + howLongUntilNextCoin;
}
//Now draw the coins
if (lastAnimationTime != 0) {
var deltaTime = new Date().getTime() - lastAnimationTime;
var coinRisePixels = Math.floor((deltaTime * risingSpeed) / 1000);
var survivingCoins = [];
for (var i = 0; i < coinsOnScreen.length; i++) {
var coin = coinsOnScreen[i];
coin.y = coin.y - coinRisePixels;
//the stl variable controlls the alpha of the image
if (coin.y + 50 > 0) {
context.drawImage(coinImage, coin.x, coin.y);
//this coin is still on the screen, so promote it to the new array...
survivingCoins.push(coin);
}
}
coinsOnScreen = survivingCoins;
}
lastAnimationTime = new Date().getTime();
//Wait, and then call this function again to animate:
setTimeout(function() {
doDraw();
}, 30);
}
function setupClickHandler() {
var can = document.getElementById("myCanvas");
//Here is the onclick handler
can.onclick = function(e) {
var x = e.clientX;
var y = e.clientY;
var survivingCoins = [];
for (var i = 0; i < coinsOnScreen.length; i++) {
var coin = coinsOnScreen[i];
//check to see if this coin has been clicked...
if (x > coin.x && x < coin.x + coinSize && y > coin.y && y < coin.y + coinSize) {
//ths coin will disappear because it is not inserted into the new array...
console.log("Coin was clicked!! " + x + " " + y);
} else {
survivingCoins.push(coin);
}
}
coinsOnScreen = survivingCoins;
};
}
doDraw();
setupClickHandler();
function getCoinImage() {
var image = new Image(50, 50);
image.src = "data:image/png;base64,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";
return image;
}
<canvas id="myCanvas"></canvas>

Create color gradient describing discrete distribution of points

I am making a map that renders position of game objects (Project Zomboid zombies):
As user zooms out, single dots are no longer useful. Instead, I'd like to render distribution of zombies on an area using red color gradient. I tried to loop over all zombies for every rendered pixel and color it reciprocally to the sum of squared distances to the zombies. The result:
That's way too blurry. Also the results are more influenced by the zombies that are AWAY from the points - I need to influence them more by the zombies that are CLOSE. So what this is is just math. Here's the code I used:
var h = canvas.height;
var w = canvas.width;
// To loop over more than 1 pixel (performance)
var tileSize = 10;
var halfRadius = Math.floor(tileSize/2);
var time = performance.now();
// "Squared" because we didnt unsquare it
function distanceSquared(A, B) {
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}
// Loop for every x,y pixel (or region of pixels)
for(var y=0; y<h; y+=tileSize) {
for(var x=0; x<w; x+=tileSize) {
// Time security - stop rendering after 1 second
if(performance.now()-time>1000) {
x=w;y=h;break;
}
// Convert relative canvas offset to absolute point on the map
var point = canvasPixeltoImagePixel(x, y);
// For every zombie add sqrt(distance from this point to zombie)
var distancesRoot = 0;
// Loop over the zombies
var zombieCoords;
for(var i=0; i<zombies_length; i++) {
// Get single zombie coordinates as {x:0, y:0}
if((coords=zombies[i].pixel)==null)
coords = zombies[i].pixel = tileToPixel(zombies[i].coordinates[0], zombies[i].coordinates[1], drawer);
// square root is a) slow and b) probably not what I want anyway
var dist = distanceSquared(coords, point);
distancesRoot+=dist;
}
// The higher the sum of distances is, the more intensive should the color be
var style = 'rgba(255,0,0,'+300000000/distancesRoot+')';
// Kill the console immediatelly
//console.log(style);
// Maybe we should sample and cache the transparency styles since there's limited ammount of colors?
ctx.fillStyle = style;
ctx.fillRect(x-halfRadius,y-halfRadius,tileSize,tileSize);
}
}
I'm pretty fine with theoretical explanation how to do it, though if you make simple canvas example with some points, what would be awesome.
This is an example of a heat map. It's basically gradient orbs over points and then ramping the opacity through a heat ramp. The more orbs cluster together the more solid the color which can be shown as an amplified region with the proper ramp.
update
I cleaned up the variables a bit and put the zeeks in an animation loop. There's an fps counter to see how it's performing. The gradient circles can be expensive. We could probably do bigger worlds if we downscale the heat map. It won't be as smooth looking but will compute a lot faster.
update 2
The heat map now has an adjustable scale and as predicted we get an increase in fps.
if (typeof app === "undefined") {
var app = {};
}
app.zeeks = 200;
app.w = 600;
app.h = 400;
app.circleSize = 50;
app.scale = 0.25;
init();
function init() {
app.can = document.getElementById('can');
app.ctx = can.getContext('2d');
app.can.height = app.h;
app.can.width = app.w;
app.radius = Math.floor(app.circleSize / 2);
app.z = genZ(app.zeeks, app.w, app.h);
app.flip = false;
// Make temporary layer once.
app.layer = document.createElement('canvas');
app.layerCtx = app.layer.getContext('2d');
app.layer.width = Math.floor(app.w * app.scale);
app.layer.height = Math.floor(app.h * app.scale);
// Make the gradient canvas once.
var sCircle = Math.floor(app.circleSize * app.scale);
app.radius = Math.floor(sCircle / 2);
app.gCan = genGradientCircle(sCircle);
app.ramp = genRamp();
// fps counter
app.frames = 0;
app.fps = "- fps";
app.fpsInterval = setInterval(calcFps, 1000);
// start animation
ani();
flicker();
}
function calcFps() {
app.fps = app.frames + " fps";
app.frames = 0;
}
// animation loop
function ani() {
app.frames++;
var ctx = app.ctx;
var w = app.w;
var h = app.h;
moveZ();
//ctx.clearRect(0, 0, w, h);
ctx.fillStyle = "#006600";
ctx.fillRect(0, 0, w, h);
if (app.flip) {
drawZ2();
drawZ();
} else {
drawZ2();
}
ctx.fillStyle = "#FFFF00";
ctx.fillText(app.fps, 10, 10);
requestAnimationFrame(ani);
}
function flicker() {
app.flip = !app.flip;
if (app.flip) {
setTimeout(flicker, 500);
} else {
setTimeout(flicker, 5000);
}
}
function genGradientCircle(size) {
// gradient image
var gCan = document.createElement('canvas');
gCan.width = gCan.height = size;
var gCtx = gCan.getContext('2d');
var radius = Math.floor(size / 2);
var grad = gCtx.createRadialGradient(radius, radius, radius, radius, radius, 0);
grad.addColorStop(1, "rgba(255,255,255,.65)");
grad.addColorStop(0, "rgba(255,255,255,0)");
gCtx.fillStyle = grad;
gCtx.fillRect(0, 0, gCan.width, gCan.height);
return gCan;
}
function genRamp() {
// Create heat gradient
var heat = document.createElement('canvas');
var hCtx = heat.getContext('2d');
heat.width = 256;
heat.height = 5;
var linGrad = hCtx.createLinearGradient(0, 0, heat.width, heat.height);
linGrad.addColorStop(1, "rgba(255,0,0,.75)");
linGrad.addColorStop(0.5, "rgba(255,255,0,.03)");
linGrad.addColorStop(0, "rgba(255,255,0,0)");
hCtx.fillStyle = linGrad;
hCtx.fillRect(0, 0, heat.width, heat.height);
// create ramp from gradient
var ramp = [];
var imageData = hCtx.getImageData(0, 0, heat.width, 1);
var d = imageData.data;
for (var x = 0; x < heat.width; x++) {
var i = x * 4;
ramp[x] = [d[i], d[i + 1], d[i + 2], d[i + 3]];
}
return ramp;
}
function genZ(n, w, h) {
var a = [];
for (var i = 0; i < n; i++) {
a[i] = [
Math.floor(Math.random() * w),
Math.floor(Math.random() * h),
Math.floor(Math.random() * 3) - 1,
Math.floor(Math.random() * 3) - 1
];
}
return a;
}
function moveZ() {
var w = app.w
var h = app.h;
var z = app.z;
for (var i = 0; i < z.length; i++) {
var s = z[i];
s[0] += s[2];
s[1] += s[3];
if (s[0] > w || s[0] < 0) s[2] *= -1;
if (s[1] > w || s[1] < 0) s[3] *= -1;
}
}
function drawZ() {
var ctx = app.ctx;
var z = app.z;
ctx.fillStyle = "#FFFF00";
for (var i = 0; i < z.length; i++) {
ctx.fillRect(z[i][0] - 2, z[i][1] - 2, 4, 4);
}
}
function drawZ2() {
var ctx = app.ctx;
var layer = app.layer;
var layerCtx = app.layerCtx;
var gCan = app.gCan;
var z = app.z;
var radius = app.radius;
// render gradients at coords onto layer
for (var i = 0; i < z.length; i++) {
var x = Math.floor((z[i][0] * app.scale) - radius);
var y = Math.floor((z[i][1] * app.scale) - radius);
layerCtx.drawImage(gCan, x, y);
}
// adjust layer for heat ramp
var ramp = app.ramp;
// apply ramp to layer
var imageData = layerCtx.getImageData(0, 0, layer.width, layer.height);
d = imageData.data;
for (var i = 0; i < d.length; i += 4) {
if (d[i + 3] != 0) {
var c = ramp[d[i + 3]];
d[i] = c[0];
d[i + 1] = c[1];
d[i + 2] = c[2];
d[i + 3] = c[3];
}
}
layerCtx.putImageData(imageData, 0, 0);
// draw layer on world
ctx.drawImage(layer, 0, 0, layer.width, layer.height, 0, 0, app.w, app.h);
}
<canvas id="can" width="600" height="400"></canvas>

Random polygon shapes on HTML5 Canvas

I'm still very new to the canvas element and I'm trying to draw random polygon shapes (triangular shapes) in random places on the canvas element. But I have trouble getting my head around it.
I have this so far, which draws a ploygon nicely, but how to add the randomness and positioning completely eludes me
var c = document.getElementById('c');
if (c.getContext) {
c2 = c.getContext('2d');
var width = c2.width;
var height = c2.height;
var maxAmount = 20;
for (i = 0; i < maxAmount; i++) {
var polySize = 50;
var posx = (Math.random() * (width - polySize)).toFixed();
var posy = (Math.random() * (height - polySize)).toFixed();
c2.fillStyle = '#f00';
c2.beginPath();
c2.moveTo(posx, posy);
c2.lineTo(100, 50);
c2.lineTo(50, 100);
c2.lineTo(0, 90);
c2.closePath();
c2.fill();
}
}
<canvas id="c" \>
You are trying to get the width and height properties of the Context2D property of your canvas, which both returned undefined.
What you need instead is the canvas element's width and height properties.
Now, since your comment to the other answer, if you need to move the whole shape, just use the first point you saved in posx and posy variables and then adjust the other points positions :
var c = document.getElementById('c');
c.width =500;
c.height= 500;
if (c.getContext) {
var c2 = c.getContext('2d');
var width = c.width;
var height = c.height;
var maxAmount = 20;
for (var i = 0; i < maxAmount; i++) {
var polySize = 50;
var posx = (Math.random() * (width - polySize));
var posy = (Math.random() * (height - polySize));
c2.fillStyle = '#f00';
c2.beginPath();
c2.moveTo(posx, posy);
c2.lineTo(posx+100, posy+50);
c2.lineTo(posx+50,posy+100);
c2.lineTo(posx+0, posy+90);
c2.closePath();
c2.stroke();
c2.fill();
}
}
<canvas id="c"><\canvas>
Here canvas width and height properties are not set. so when invoke code following line of code, it returns NaN
var width = c2.width;
var height = c2.height;
To get random position try following code base
<canvas id="c" width="250" height="250" \>
var c = document.getElementById('c');
if (c.getContext)
{
c2 = c.getContext('2d');
var width = c.width;
var height = c.height;
var maxAmount = 5;
for (i = 0; i < maxAmount; i++) {
var polySize = 50;
var posx = (Math.random() * (width - polySize)).toFixed();
var posy = (Math.random() * (height - polySize)).toFixed();
c2.fillStyle = '#f00';
c2.beginPath();
c2.moveTo(posx, posy);
c2.lineTo(100, 50);
c2.lineTo(50, 100);
c2.lineTo(0, 90);
c2.closePath();
c2.fill();
}
}

Animating sine wave in js

I'm trying to animate a sine wave in JS but it's not acting as expected. I'm using a <canvas> element along with window.requestAnimationFrame() method but it's a CPU hog and as i change frequency with the slider it just break and show random waveforms. I also don't know if drawing adjacent lines is the best way to represent a sine wave. Please note that i'll use vanilla JS and that the sine's frequency and amplitude are variables set by sliders. Thanks in advance.
This is what i got so far: http://cssdeck.com/labs/8cq5vclp
UPDATE: i worked on it and this is the new version: http://cssdeck.com/labs/sbfynjkr
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
cHeight = canvas.height,
cWidth = canvas.width,
frequency = document.querySelector("#f").value,
amplitude = 80,
x = 0,
y = cHeight / 2,
point_y = 0;
window.onload = init;
function init() {
document.querySelector("#f").addEventListener("input", function() {
frequency = this.value;
document.querySelector("#output_f").value = frequency;
}, false);
drawSine();
}
function drawSine() {
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.beginPath();
ctx.moveTo(0, y);
ctx.strokeStyle = "red";
ctx.lineTo(cWidth, y);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = "black";
for (x = 0; x < 600; x++) {
point_y = amplitude * -Math.sin((frequency / 95.33) * x) + y;
ctx.lineTo(x, point_y);
}
ctx.stroke();
ctx.closePath();
requestAnimationFrame(drawSine);
}
canvas {
border: 1px solid red;
margin: 10px;
}
<input id="f" type="range" min="0" max="20000" value="20" step="1">
<output for="f" id="output_f">20</output>
<canvas width="600px" height="200px"></canvas>
I've messed around with sine waves quite a bit, because I'm working on a little project that involves animated sine waves. I've got some code you might be interested in taking a look at. Like mentioned earlier, you need to make sure you are using the right increment in your loop so the lines do not look jagged.
https://jsfiddle.net/uawLvymc/
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(f) {
return setTimeout(f, 1000 / 60)
};
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var startTime = new Date().getTime();
function getPath(height) {
var width = canvas.width;
var spacing = 0.08;
var loopNum = 0;
var pointList = [];
var i = 0;
for (i = 0; i < width / 2; i++) {
pointList[loopNum] = [loopNum, Math.sin(loopNum * spacing) * (i * height) + 100];
loopNum++;
}
for (i = width / 2; i > 0; i--) {
pointList[loopNum] = [loopNum, Math.sin(loopNum * spacing) * (i * height) + 100];
loopNum++;
}
return pointList;
}
function draw() {
var currentTime = new Date().getTime();
var runTime = currentTime - startTime;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(80, 100, 230)";
var height = Math.sin(runTime * 0.008) * 0.2;
var pointList = getPath(height);
for (var i = 0; i < 500; i++) {
if (i === 0) {
ctx.moveTo(pointList[0][0], pointList[0][1]);
} else {
ctx.lineTo(pointList[i][0], pointList[i][1]);
}
}
ctx.stroke();
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
Sorry I didn't really edit down the code, it's just a direct copy from what I was working on. Hope it helps though.
See if this example could help you a little
Sine Wave Example canvas
function init()
{
setInterval(OnDraw, 200);
}
var time = 0;
var color = "#ff0000";
function OnDraw()
{
time = time + 0.2;
var canvas = document.getElementById("mycanvas");
var dataLine = canvas.getContext("2d");
var value = document.getElementById("lineWidth");
dataLine.clearRect(0, 0, canvas.width, canvas.height);
dataLine.beginPath();
for(cnt = -1; cnt <= canvas.width; cnt++)
{
dataLine.lineTo(cnt, canvas.height * 0.5 - (Math.random() * 2 + Math.cos(time + cnt * 0.05) * 20 ));
}
dataLine.lineWidth = value.value * 0.1;
dataLine.strokeStyle = color;
dataLine.stroke();
}

Categories