HTML canvas move circle from a to b with animation - javascript

I was wondering what would be the best way to move a circle from point A to point B using smooth animation.
I get new coordinates with websocket every second and would like to animate the circle move from last point to the new point during that second.
I have visualized in this fiddle how the setup would look. I replaced the ws side with manual button input for this test purpose but its missing the function to move the circle.
jQuery is welcome too.
var x = 100;
var y = 50;
var r = 10;
var WIDTH = 600;
var HEIGHT = 400;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function circle(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function draw() {
clear(WIDTH, HEIGHT);
ctx.fillStyle = "purple";
circle(x, y, r);
}
draw();
https://jsfiddle.net/1g18rsqy/
Thanks :)

You can calculate the delta time between the current time of your animation, and its starting time. Then, you just have to move your circle by the difference between its original position and its next position, multiplied by this delta time :
var deltaTime = (currentTime - startTime) / duration;
var currentX = prevX + ((nextX - prevX) * deltaTime);
You can get this time directly from the argument passed in requestAnimationFrame callback.
var x = 100;
var y = 50;
var r = 10;
var duration = 1000; // in ms
var nextX, nextY;
var startTime;
function anim(time) {
if (!startTime) // it's the first frame
startTime = time || performance.now();
// deltaTime should be in the range [0 ~ 1]
var deltaTime = (time - startTime) / duration;
// currentPos = previous position + (difference * deltaTime)
var currentX = x + ((nextX - x) * deltaTime);
var currentY = y + ((nextY - y) * deltaTime);
if (deltaTime >= 1) { // this means we ended our animation
x = nextX; // reset x variable
y = nextY; // reset y variable
startTime = null; // reset startTime
draw(x, y); // draw the last frame, at required position
} else {
draw(currentX, currentY);
requestAnimationFrame(anim); // do it again
}
}
move.onclick = e => {
nextX = +x_in.value || 0;
nextY = +y_in.value || 0;
anim();
}
// OP's code
var WIDTH = 600;
var HEIGHT = 400;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function circle(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function draw(x, y) {
clear(WIDTH, HEIGHT);
ctx.fillStyle = "purple";
circle(x, y, r);
}
draw(x, y);
#canvas {
border: 1px solid black;
}
<label>X: </label><input type="number" id="x_in">
<label>Y: </label><input type="number" id="y_in">
<input type="button" id="move" value="MOVE">
<canvas id="canvas" width=600 height=400></canvas>

Related

draw an arc with two different colors in javascript

I am working on a canvas. I want to draw an arc with a different two-color, like first half will be green second half will be red.
sample code
// CANVAS
const canvas = document.getElementById('bar'),
width = canvas.width,
height = canvas.height;
// CANVAS PROPERTIES
const ctx = canvas.getContext('2d');
ctx.lineWidth = 6;
ctx.strokeStyle = 'green';
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
const x = width / 2,
y = height / 2,
radius = 41,
circum = Math.PI * 2,
start = 2.37,
finish = 75;
let curr = 0;
const raf =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = raf;
function animate(draw_to) {
//ctx.clearRect(0, 0, width, height);
ctx.beginPath();
ctx.arc(x, y, radius, start, draw_to, false);
ctx.stroke();
curr++;
if (curr < finish + 1) {
requestAnimationFrame(function () {
animate(circum * curr / 100 + start);
});
}
}
animate();
code link https://jsfiddle.net/gowtham25/bp0myt21/11/
Something like this?
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const x = canvas.width / 2
const y = canvas.height / 2
const radius = 41
const start = -25
const end = 75
const width = 6
function DrawArc(x, y, radius, start, end, width, color) {
ctx.beginPath()
ctx.lineWidth = width
ctx.strokeStyle = color
ctx.arc(x, y, radius, start, end, false)
ctx.stroke()
}
function DrawGauge(percentage) {
const rotation = Math.PI * 0.75
const angle = Math.PI * 1.5
const current = angle * percentage / 100
DrawArc(x, y, radius, rotation, rotation + current, width, 'green')
DrawArc(x, y, radius, rotation + current, rotation + angle, width, 'red')
}
function Animate(percent = 0) {
if (percent < 0) return
if (percent > 100) return
DrawGauge(percent)
requestAnimationFrame(() => Animate(++percent))
}
Animate()
<canvas></canvas>
I recommend breaking down the things you want to draw into functions at the very least so you can easily draw the item by passing in the parameters each time and can reuse the function to draw multiple different versions of that item.
Personally I'd create a class for the arc drawing and a class for the gauge drawing and then the gauge would draw two arcs based on the value of its percentage property. That way the drawing is separated from your data logic which is extremely important as you start doing more complex things with more draw calls.
You need to change the startAngle parameter in
ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
Currently, if you modify the strokeStyle without changing the startAngle it will just draw on the same path.
https://jsfiddle.net/97ogkwas/4/
// CANVAS
const canvas = document.getElementById('bar'),
width = canvas.width,
height = canvas.height;
// CANVAS PROPERTIES
const ctx = canvas.getContext('2d');
ctx.lineWidth = 6;
ctx.strokeStyle = 'green';
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
let x = width / 2,
y = height / 2,
radius = 41,
circum = Math.PI * 2
start = 0.5* Math.PI
finish = 75;
let curr = 0;
const raf =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = raf;
function animate(draw_to) {
//ctx.clearRect(0, 0, width, height);
ctx.beginPath();
if(curr>45){
ctx.strokeStyle = 'red';
start = 1* Math.PI;
}
ctx.arc(x, y, radius, start, draw_to, false);
ctx.stroke();
curr++;
if (curr < finish + 1) {
requestAnimationFrame(function () {
animate(circum * curr / 100 + start);
});
}
}
animate();
#bar {
position: absolute;
top: 0;
left: 0;
}
<canvas id="bar" width="100" height="100"></canvas>
https://jsfiddle.net/97ogkwas/4/
// CANVAS
const canvas = document.getElementById('bar'),
width = canvas.width,
height = canvas.height;
// CANVAS PROPERTIES
const ctx = canvas.getContext('2d');
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// CANVAS PROPERTIES
const ctx2 = canvas.getContext('2d');
ctx2.lineWidth = 1;
ctx2.shadowOffsetX = 0;
ctx2.shadowOffsetY = 0;
var x = width / 2,
y = height / 2,
radius = 40,
circum = Math.PI * 2,
start = 2.37,
finish = 50;
let curr = 0;
const raf = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = raf;
function animate(draw_to) {
//ctx.clearRect(0, 0, width, height);
ctx.beginPath();
ctx.arc(x, y, radius, start, draw_to, false);
ctx.stroke();
curr++;
if (curr < finish + 5) {
requestAnimationFrame(function () {
animate(circum * curr / 100 + start);
});
}
}
function animate2(draw_to) {
//ctx.clearRect(0, 0, width, height);
ctx2.beginPath();
ctx2.arc(x, y, radius, start, draw_to, false);
ctx2.stroke();
curr++;
if (curr < finish + 5) {
requestAnimationFrame(function () {
animate2(circum * curr / 100 + start);
});
}
}
animate();
setTimeout(function(){
finish = 52;
start = 5.5;
ctx2.strokeStyle = 'red';
animate2();
}, 2000);
#bar {
position: absolute;
top: 0;
left: 0;
}
<canvas id="bar" width="100" height="100"></canvas>
The question is not clear at all! I am not sure but maybe someting like this:
https://jsfiddle.net/15srnh4w/

How to draw canvas trailing line with opacity

I'm attempting to draw the rotating line in this canvas animation with trailing opacity but it's not working. I've seen this effect with rectangles and arcs but never with a line, so I'm not sure what I need to add.
function radians(degrees) {
return degrees * (Math.PI / 180);
}
var timer = 0;
function sonar() {
var canvas = document.getElementById('sonar');
if (canvas) {
var ctx = canvas.getContext('2d');
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
//ctx.clearRect(0, 0, innerWidth, innerHeight);
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.fillRect(0, 0, innerWidth, innerHeight);
var radii = [cy, cy - 30, innerHeight / 3.33, innerHeight / 6.67];
for (var a = 0; a < 4; a++) {
ctx.beginPath();
ctx.arc(cx, cy, radii[a], radians(0), radians(360), false);
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
}
// draw grid lines
for (var i = 0; i < 12; i++) {
var x = cx + cy * Math.cos(radians(i * 30));
var y = cy + cy * Math.sin(radians(i * 30));
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(x, y);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(50, 205, 50, 0.45)';
ctx.stroke();
ctx.closePath();
}
if (timer <= 360) {
timer++;
ctx.beginPath();
ctx.fillstyle = 'limegreen';
ctx.moveTo(cx, cy);
ctx.lineTo(cx + cy * Math.cos(radians(timer)), cy + cy * Math.sin(radians(timer)));
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
} else {
timer = 0;
}
requestAnimationFrame(sonar);
}
}
sonar();
jsbin example
Here are two ways to do this: with a gradient and by adding translucent lines.
Sidenote, you should try and only redraw what you need to redraw. I separated the canvases and put one on top of the other so that we don't redraw the grid all the time.
function radians(degrees) {
return degrees * (Math.PI / 180);
}
var timer = 0;
function trail() {
var canvas = document.getElementById('trail');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, innerWidth, innerHeight);
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
if (timer <= 360) {
timer++;
ctx.beginPath();
ctx.fillstyle = 'limegreen';
ctx.moveTo(cx, cy);
ctx.arc(cx,cy,cy,radians(timer-30),radians(timer));
ctx.lineTo(cx + cy * Math.cos(radians(timer)), cy + cy * Math.sin(radians(timer)));
var gradient = ctx.createLinearGradient(
cx+cy*Math.cos(radians(timer)), cy+cy*Math.sin(radians(timer)),
cx+cy*0.9*Math.cos(radians(timer-30)), cy+cy*0.9*Math.sin(radians(timer-30)));
gradient.addColorStop(0,'limegreen');
gradient.addColorStop(1,'transparent');
ctx.strokeStyle='transparent';
ctx.fillStyle = gradient;
ctx.fill();
ctx.beginPath();
var fade = 10;
for(var i =0;i<fade;i++)
{
ctx.moveTo(cx, cy);
ctx.lineTo(cx+cy*Math.cos(radians(180+timer-i*1.3)),cy+cy*Math.sin(radians(180+timer-i*1.3)));
ctx.strokeStyle ="rgba(50,205,50,0.1)";
ctx.lineWidth=5;
ctx.closePath();
ctx.stroke();
}
} else {
timer = 0;
}
requestAnimationFrame(trail);
}
function sonar() {
var canvas = document.getElementById('sonar');
if (canvas) {
var ctx = canvas.getContext('2d');
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
//ctx.clearRect(0, 0, innerWidth, innerHeight);
var radii = [cy, cy - 30, innerHeight / 3.33, innerHeight / 6.67];
for (var a = 0; a < 4; a++) {
ctx.beginPath();
ctx.arc(cx, cy, radii[a], radians(0), radians(360), false);
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
}
// draw grid lines
for (var i = 0; i < 12; i++) {
var x = cx + cy * Math.cos(radians(i * 30));
var y = cy + cy * Math.sin(radians(i * 30));
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(x, y);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(50, 205, 50, 0.45)';
ctx.stroke();
ctx.closePath();
}
}
}
sonar();
trail();
canvas{
position: absolute;
}
<canvas id=sonar></canvas>
<canvas id=trail></canvas>
The problem is that to get this effect, you need to draw a triangle with a gradient along an arc, and you can't do that in a canvas. Gradients must be linear or radial.
The other option is to have an inner loop run each time you want to draw the sweeper, and go backwards from your sweeper line, drawing with slightly less opacity each time. But lets say you want your sweep to cover 15 degrees--obviously, if you have a 100% opacity line at d and a 5% opacity line at d - 15, that doesn't do the trick. So start filling in more lines, and more lines...you will have to draw so many lines to make it seem filled your performance would probably suffer.
My suggestion--you shouldn't have to redraw that on every frame. I would just make a PNG that looks like you want it to, and then place it and just rotate it around the center on each frame. No need to redraw it all the time then. That will be much faster than drawing a bunch of lines.
Canvas stack trails.
Below is a quick demo of how to use a stack of canvases to create a trailing effect.
You have a normal on screen canvas (this FX will not effect it) and then a stack of canvases for the trail FX. Each frame you move to the next canvas in the stack, first slightly clearing it then drawing to it what you want to trail. Then you render that canvas and the one just above it to the canvas.
A point to keep in mind is that the trails can also have a hugh range of FX, like blurring (just render each frame stack on itself slightly offset each time you render to it), zoom in and out trails. Trails on top or trails under. You can change the trail distance and much more.
It is overkill but over kill is fun.
The slider above the demo controls the trail length. Also the code need babel because I dont have time to write it for ES5.
Top slider is trail amount.One under that is trail distance. Trail dist does not transition well. Sorry about that.
//==============================================================================
// helper function
function $(query,q1){
if(q1 !== undefined){
if(typeof query === "string"){
var e = document.createElement(query);
if(typeof q1 !== "string"){
for(var i in q1){
e[i] = q1[i];
}
}else{
e.id = q1;
}
return e;
}
return [...query.querySelectorAll(q1)];
}
return [...document.querySelectorAll(query)];
}
function $$(element,e1){
if(e1 !== undefined){
if(typeof element === "string"){
$(element)[0].appendChild(e1);
return e1;
}
element.appendChild(e1);
return e1;
}
document.body.appendChild(element);
return element;
}
function $E(element,types,listener){
if(typeof types === "string"){
types = types.split(",");
}
element = $(element)[0];
types.forEach(t=>{
element.addEventListener(t,listener)
});
return element;
}
function R(I){
if(I === undefined){
return Math.random();
}
return Math.floor(Math.random()*I);
}
//==============================================================================
//==============================================================================
// answer code
// canvas size
const size = 512;
const trailDist = 10; // There is this many canvases so be careful
var trailDistCurrent = 10; // distance between trails
var clearAll = false;
// create a range slider for trail fade
$$($("input",{type:"range",width : size, min:0, max:100, step:0.1, value:50, id:"trail-amount",title:"Trail amount"}));
$("#trail-amount")[0].style.width = size + "px";
$E("#trail-amount","change,mousemove",function(e){fadeAmount = Math.pow(this.value / 100,2);});
// create a range slider trail distance
$$($("input",{type:"range",width : size, min:2, max:trailDist , step:1, value:trailDist , id:"trail-dist",title:"Trail seperation"}));
$("#trail-dist")[0].style.width = size + "px";
$E("#trail-dist","change,mousemove", function(e){
if(this.value !== trailDistCurrent){
trailDistCurrent= this.value;
clearAll = true;
}
});
$$($("br","")) // put canvas under the slider
// Main canvas
var canvas;
$$(canvas = $("canvas",{width:size,height:size})); // Not jquery. Just creates a canvas
// and adds canvas to the document
var ctx = canvas.getContext("2d");
// Trailing canvas
var trailCanvases=[];
var i =0; // create trail canvas
while(i++ < trailDist){trailCanvases.push($("canvas",{width:size,height:size}));}
var ctxT = trailCanvases.map(c=>c.getContext("2d")); // get context
var topCanvas = 0;
var fadeAmount = 0.5;
// Draw a shape
function drawShape(ctx,shape){
ctx.lineWidth = shape.width;
ctx.lineJoin = "round";
ctx.strokeStyle = shape.color;
ctx.setTransform(shape.scale,0,0,shape.scale,shape.x,shape.y);
ctx.rotate(shape.rot);
ctx.beginPath();
var i = 0;
ctx.moveTo(shape.shape[i++],shape.shape[i++]);
while(i < shape.shape.length){
ctx.lineTo(shape.shape[i++],shape.shape[i++]);
}
ctx.stroke();
}
// Create some random shapes
var shapes = (function(){
function createRandomShape(){
var s = [];
var len = Math.floor(Math.random()*5 +4)*2;
while(len--){
s[s.length] = (R() + R()) * 20 * (R() < 0.5 ? -1 : 1);
}
return s;
}
var ss = [];
var i = 10;
while(i--){
ss[ss.length] = createRandomShape();
}
ss[ss.length] = [0,0,300,0]; // create single line
return ss;
})();
// Create some random poits to move the shapes
var points = (function(){
function point(){
return {
color : "hsl("+R(360)+",100%,50%)",
shape : shapes[R(shapes.length)],
width : R(4)+1,
x : R(size),
y : R(size),
scaleMax : R()*0.2 + 1,
scale : 1,
s : 0,
rot : R()*Math.PI * 2,
dr : R()*0.2 -0.1,
dx : R()*2 - 1,
dy : R()*2 - 1,
ds : R() *0.02 + 0.01,
}
}
var line = shapes.pop();
var ss = [];
var i = 5;
while(i--){
ss[ss.length] = point();
}
var s = ss.pop();
s.color = "#0F0";
s.x = s.y = size /2;
s.dx = s.dy = s.ds = 0;
s.scaleMax = 0.5;
s.dr = 0.02;
s.shape = line;
s.width = 6;
ss.push(s);
return ss;
})();
var frameCount = 0; // used to do increamental fades for long trails
function update(){
// to fix the trail distance problem when fade is low and distance high
if(clearAll){
ctxT.forEach(c=>{
c.setTransform(1,0,0,1,0,0);
c.clearRect(0,0,size,size);
});
clearAll = false;
}
frameCount += 1;
// get the next canvas that the shapes are drawn to.
topCanvas += 1;
topCanvas %= trailDistCurrent;
var ctxTop = ctxT[topCanvas];
// clear the main canvas
ctx.setTransform(1,0,0,1,0,0); // reset transforms
// Fade the trail canvas
ctxTop.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,size,size); // clear main canvas
// slowly blendout trailing layer
if(fadeAmount < 0.1){ // fading much less than this leaves perminant trails
// so at low levels just reduce how often the fade is done
if(((Math.floor(frameCount/trailDistCurrent)+topCanvas) % Math.ceil(1 / (fadeAmount * 10))) === 0 ){
ctxTop.globalAlpha = 0.1;
ctxTop.globalCompositeOperation = "destination-out";
ctxTop.fillRect(0,0,size,size);
}
}else{
ctxTop.globalAlpha = fadeAmount;
ctxTop.globalCompositeOperation = "destination-out";
ctxTop.fillRect(0,0,size,size);
}
ctxTop.globalCompositeOperation = "source-over";
ctxTop.globalAlpha = 1;
// draw shapes
for(var i = 0; i < points.length; i ++){
var p = points[i];
p.x += p.dx; // move the point
p.y += p.dy;
p.rot += p.dr;
p.s += p.ds;
p.dr += Math.sin(p.s) * 0.001;
p.scale = Math.sin(p.s) * p.scaleMax+1;
p.x = ((p.x % size) + size) % size;
p.y = ((p.y % size) + size) % size;
drawShape(ctxTop,p); // draw trailing layer (middle)
}
// draw the trail the most distance from the current position
ctx.drawImage(trailCanvases[(topCanvas + 1)%trailDistCurrent],0,0);
// do it all again.
requestAnimationFrame(update);
}
update();

JS HTMLCanvas help required

I am trying to create a game (at beginning stages). I am trying to create balls that bounce around a canvas, I have created balls, randomized them and have animated them.
But when trying to add a boundary I can only seem to get the balls to act as one object rather than separate ones. If NumShapes is changed to 1 it works perfectly.
if( shapes[i].x<0 || shapes[i].x>width) dx=-dx;
if( shapes[i].y<0 || shapes[i].y>height) dy=-dy;
For movement:
shapes[i].x+=dx;
shapes[i].y+=dy;
See this:
var ctx;
var numShapes;
var shapes;
var dx = 5; // speed on the X axis
var dy = 5; // speed on the Y axis
var ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
function init() // draws on the Canvas in the HTML
// calling functions here would not run them in the setInterval
{
numShapes = 10;
shapes = [];
drawScreen();
ctx = canvas.getContext('2d');
setInterval(draw, 10); // Runs the Draw function with nestled functions
makeShapes();
}
function draw() {
clear();
drawShapes();
}
function clear() {
ctx.clearRect(0, 0, width, height); // clears the canvas by WIDTH and HEIGHT variables
}
function makeShapes() {
var i;
var tempRad;
var tempR;
var tempG;
var tempB;
var tempX;
var tempY;
var tempColor;
for (i = 0; i < numShapes; i++) { // runs while i is less than numShapes
tempRad = 10 + Math.floor(Math.random() * 25); // random radius number
tempX = Math.random() * (width - tempRad); // random X value
tempY = Math.random() * (height - tempRad); // random Y value
tempR = Math.floor(Math.random() * 255); // random red value
tempG = Math.floor(Math.random() * 255); // random green value
tempB = Math.floor(Math.random() * 255); // random blue value
tempColor = "rgb(" + tempR + "," + tempG + "," + tempB + ")"; // creates a random colour
tempShape = {
x: tempX,
y: tempY,
rad: tempRad,
color: tempColor
}; // creates a random shape based on X, Y and R
shapes.push(tempShape); // pushes the shape into the array
}
}
function drawShapes() {
var i;
for (i = 0; i < numShapes; i++) {
ctx.fillStyle = shapes[i].color;
ctx.beginPath();
ctx.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
shapes[i].x += dx; // increases the X value of Shape
shapes[i].y += dy; // increases the Y value of Shape
// Boundary, but applies to all shapes as one shape
if (shapes[i].x < 0 || shapes[i].x > width) dx = -dx;
if (shapes[i].y < 0 || shapes[i].y > height) dy = -dy;
}
}
function drawScreen() {
//bg
ctx.fillStyle = '#EEEEEE';
ctx.fillRect(0, 0, width, height);
//Box
ctx.strokeStyle = '#000000';
ctx.strokeRect(1, 1, width - 2, height - 2);
}
canvas {
border: 1px solid #333;
}
<body onLoad="init();">
<div class="container container-main">
<div class="container-canvas">
<canvas id="canvas" width="800" height="600">
This is my fallback content.
</canvas>
</div>
</div>
</body>
Your dx and dy are globals, they should be unique for each ball object that you are simulating. Either clear them to 0 in your rendering loop (draw) or actually implement a ball object/class to hold variables unique to that object.
When you do your collision detection you change dx and dy which then persists to the next ball object as they are global.
Your fiddle, edited to add local dx and dy per shape: https://jsfiddle.net/a9b3rm5u/3/
tempDx = Math.random()*5; // random DX value
tempDy = Math.random()*5; // random DY value
shapes[i].x+=shapes[i].dx;// increases the X value of Shape
shapes[i].y+=shapes[i].dy;// increases the Y value of Shape
if( shapes[i].x<0 || shapes[i].x>width) shapes[i].dx= - shapes[i].dx;
if( shapes[i].y<0 || shapes[i].y>height) shapes[i].dy= -shapes[i].dy;

How to move a canvas element up and down for a certain amount of time with javascript

I'm trying to make 6 guitars strings move when they are clicked on. I tried doing a simple animation by moving the string 2.5 px up and 2.5 px down for 3 seconds. but I don't really know how to do that.
This is what I've tried:
function onLoad(){
snaren();
snaarAanraken();
}
function snaren(){
var c = document.getElementById("strings");
var ctx = c.getContext("2d");
for (var i=1;i<7;i++){ //drawing the 6 strings
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0,42.5*i);
ctx.lineTo(700,42.5*i);
ctx.stroke();
}
}
function snaarAanraken(){
var canvas = document.getElementById("strings");
var ctx = canvas.getContext("2d");
var canvasLeft = canvas.offsetLeft;
var canvasTop = canvas.offsetTop;
canvas.addEventListener('click', function(event) {
var x = event.pageX - canvasLeft;
var y = event.pageY - canvasTop;
console.log(x, y);
if (x >= 0 && x<= 700) {
if (y >= 35 && y<= 50) {//check if clicked on first string
var e = new Audio("e2.mp3");
e.play();
var canvas_y = 42.5;
var bewegen = setInterval(function () {
if (canvas_y > 44) {
canvas_y = 40
}
if (canvas_y < 41) {
canvas_y = 45;
}
ctx.clearRect(0, 0, 700, 60);
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0,canvas_y);
ctx.lineTo(700,canvas_y);
ctx.stroke();
console.log(canvas_y);
}, 100);
clearInterval(bewegen, 3000);
}
}
For a guitar string you could use quadratic curve coupled with a sine function. The radius for the sine function could be controlled with time.
Also use requestAnimationFrame for good fluid animation. You're not using setTimeout correctly (rAF also provide a high-resolution time as argument which you can use instead of Date.now or performance.now() - not shown).
Example
var ctx = document.querySelector("canvas").getContext("2d");
(function play() {
renderString(75, 20, 5000, function() {
setTimeout(play, 250);
});
})();
// provide y position, max radius, time in ms and a callback function for done
function renderString(y, max, ms, callback) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
f = 0, // fake frequency (demo)
startTime = Date.now();
(function loop() {
var t = 1 - ((Date.now() - startTime) / ms); // normalized time progress
ctx.clearRect(0, 0, w, h); // clear frame
ctx.beginPath(); // new path
ctx.moveTo(0, y); // start of curve
ctx.quadraticCurveTo(w * 0.5, y + getSine() * t, w, y); // quad. curve
ctx.stroke(); // stroke it
if (t > 0) requestAnimationFrame(loop);
else callback();
})();
function getSine() {
return Math.sin((f=f+2)) * max; // todo: use real frequency
}
}
<canvas></canvas>
Here, I made a small example of a vibrating guitar string. It waits 2 seconds then strums the string, which vibrates for half a second.
The problem you have in your code is that you're adding a time-variable to your clearInterval, which isn't possible. If you want a delay on clearing an interval, you need to couple it with setTimeout, kind of like:
setTimeout(function() {
clearInterval(bewegen);
},3000);
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
c.width = 300;
c.height = 400;
var tremble = 2;
var myInterval;
function strum() {
ctx.clearRect(0,0,c.width,c.height);
drawString();
ctx.beginPath();
ctx.moveTo(0,50+tremble);
ctx.lineTo(c.width,50+tremble);
ctx.stroke();
tremble*=-1;
}
function drawString() {
ctx.beginPath();
ctx.moveTo(0,50);
ctx.lineTo(c.width,50);
ctx.stroke();
}
drawString();
setTimeout(function() {
myInterval = setInterval(strum,16);
setTimeout(function() {
clearInterval(myInterval);
ctx.clearRect(0,0,c.width,c.height);
drawString();
},500);
},2000);
<canvas id="canvas"></canvas>

How to move the square to the destination?

How to move the square to the destination? Square moves one pixel only when click the mouse? Sorry for my english.
window.onload = function(){
var x = 50;
var y = 50;
var c = document.getElementById("game");
var ctx = c.getContext("2d");
init();
draw();
function init()
{
document.addEventListener("click",paint,false);
}
function paint(e)
{
if(x<e.clientX) x++;
}
function draw()
{
ctx.clearRect(x-1,y,1,15);
ctx.fillStyle = "blue";
ctx.fillRect(x,y,15,15);
window.requestAnimationFrame(draw);
}
}
Here is one way to do it, adapted from this article that I wrote a few months back.
The following is the piece to get it working
var tx = targetX - x,
ty = targetY - y,
dist = Math.sqrt(tx*tx+ty*ty);
velX = (tx/dist)*thrust;
velY = (ty/dist)*thrust;
We need to get the difference between the current position and targeted position (clicked area), we then get the distance, and make the velocity for x and y equal to the difference divided by the total distance multiplied by the speed of the object.
Full working example and code
Live demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 500,
mX = width/2,
mY = height/2;
canvas.width = width;
canvas.height = height;
canvas.addEventListener("click", function (e) {
mX = e.pageX;
mY = e.pageY;
});
var Ball = function (x, y, radius, color) {
this.x = x || 0;
this.y = y || 0;
this.radius = radius || 10;
this.speed = 5;
this.color = color || "rgb(255,0,0)";
this.velX = 0;
this.velY = 0;
}
Ball.prototype.update = function (x, y) {
// get the target x and y
this.targetX = x;
this.targetY = y;
// We need to get the distance this time around
var tx = this.targetX - this.x,
ty = this.targetY - this.y,
dist = Math.sqrt(tx * tx + ty * ty);
/*
* we calculate a velocity for our object this time around
* divide the target x and y by the distance and multiply it by our speed
* this gives us a constant movement speed.
*/
this.velX = (tx / dist) * this.speed;
this.velY = (ty / dist) * this.speed;
// Stop once we hit our target. This stops the jittery bouncing of the object.
if (dist > this.radius / 2) {
// add our velocities
this.x += this.velX;
this.y += this.velY;
}
};
Ball.prototype.render = function () {
ctx.fillStyle = this.color;
ctx.beginPath();
// draw our circle with x and y being the center
ctx.arc(this.x - this.radius / 2, this.y - this.radius / 2, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
};
var ball1 = new Ball(width / 2, height / 2, 10);
function render() {
ctx.clearRect(0, 0, width, height);
ball1.update(mX, mY);
ball1.render();
requestAnimationFrame(render);
}
render();

Categories