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

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);

Related

Projectile Motion Simulation in HTML5 JavaScript canvas

I'm looking to simulate projectile motion (off the ground with a certain velocity, continuing until the ball lands on the ground again) ignoring air resistance. I'm using the canvas feature of HTML5 and JavaScript to do it. I'm a novice with JavaScript, so any help is appreciated.
This is my code so far. I'm running into the same error again and again: unexpected end of input. I'm also trying to include start, stop, and reset buttons, as well as the option for the user to input their own angle, so they can see the final horizontal distance change.
I've tried many different ways to get rid of this error; what am I missing?
<html>
<head>
<title>
Projectile Motion
</title>
</head>
<body>
<button onclick=settimer()>Start</button><br>
<button onclick=reset()>Reset</button><br>
<button onclick=cleartimer()>Stop</button><br>
Angle=<input type="text" id="Angle in Degrees" value=45></input>
<canvas id="mycanvas" height="600" width="600"></canvas>
<script>
function rectang() {
co.beginPath();
co.rect(0,0,600,600);
co.stroke();
}
var gravity
var Angle
var velocity
var velocityx
var velocityy
var distance
var co
var inc
var time
var x
var y
var radius
//list variables
function init() {
var can;
can = document.getElementById("mycanvas");
co = can.getContext("2d");
reset();
}
function reset() {
gravity = 5;
Angle = (45*(Math.PI)/180);
velocity = 10;
velocityx = velocity*Math.cos(Angle);
velocityy = velocity*Math.sin(Angle);
time = 0;
distance = velocityx*time;
inc = 0.5;
x = 0;
y = 600;
radius = 10;
}
function draw() {
co.clearRect(0,0,600,600);
circle(co,x,y,radius,"yellow",false)
time = time + inc;
x = x + velocityx*time;
y = y + velocityy*time;
velocityx = velocityx;
velocityy = velocityy + velocityy*time;
}
function settimer() {
if (timer == null) timer = setInterval(draw,time);
Angle = document.getElementById("Angle").value;
}
function cleartimer(){
clearInterval(timer);
timer = null;
}
init();
function circle(context,x,y,r,color,fill) {
if (fill == true) {
//if fill is true, fill the circle
var temp = context.fillStyle;
context.fillStyle = color;
context.beginPath();
context.arc(x,y,r,0,2*Math.PI);
context.fill();
context.fillStyle = temp;
}
else {
//if fill is false, don't fill the circle
var temp = context.strokeStyle;
context.strokeStyle = color;
context.beginPath();
context.arc(x,y,r,0,2*Math.PI);
context.stroke();
context.strokeStyle = temp;
}
</script>
</body>
</html>
There are some issues, mainly some kind of double-incrementing, where "time" was getting larger each loop, and x/y values were incrementing itself too. Also, for "velocityy" you should rather use negative value at start (bullet getting higher) and then add something based on gravity. And yellow isn't very readable here.
function rectang() {
co.beginPath();
co.rect(0,0,600,600);
co.stroke();
}
var gravity
var Angle
var velocity
var velocityx
var velocityy
var distance
var co
var inc
var time
var x
var y
var radius
//list variables
function init() {
var can;
can = document.getElementById("mycanvas");
co = can.getContext("2d");
reset();
}
function reset() {
gravity = 5;
Angle = (45*(Math.PI)/180);
velocity = 10;
velocityx = velocity*Math.cos(Angle);
velocityy = velocity*Math.sin(Angle)*-1;
time = 0;
distance = velocityx*time;
inc = 0.5;
x = 0;
y = 300;
radius = 10;
}
function draw() {
//console.log(x,y)
co.clearRect(0,0,600,300);
circle(co,x,y,radius,"yellow",false)
time = time + inc;
x = x + velocityx*inc;
y = y + velocityy*inc;
velocityx = velocityx;
velocityy = velocityy + gravity*inc*0.1;
}
var timer = null;
function settimer() {
if (timer == null) timer = setInterval(draw,time);
Angle = document.getElementById("Angle").value;
}
function cleartimer(){
clearInterval(timer);
timer = null;
}
init();
function circle(context,x,y,r,color,fill) {
x = Math.round(x)
y = Math.round(y)
//console.log(x,y,r,color,fill)
if (fill == true) {
//if fill is true, fill the circle
var temp = context.fillStyle;
context.fillStyle = color;
context.beginPath();
context.arc(x,y,r,0,2*Math.PI);
context.fill();
context.fillStyle = temp;
}
else {
//if fill is false, don't fill the circle
var temp = context.strokeStyle;
context.beginPath();
context.arc(x,y,r,0,2*Math.PI);
context.strokeStyle = color;
context.lineWidth = 4;
context.stroke();
context.strokeStyle = temp;
}
}
<button onclick=settimer()>Start</button><br>
<button onclick=reset()>Reset</button><br>
<button onclick=cleartimer()>Stop</button><br>
Angle=<input type="text" id="Angle" value=45></input>
<canvas id="mycanvas" height="300" width="600"></canvas>

animated shapes at the same time using canvas

1.I want to be able to animated shapes at the same time using canvas, but each to one side.
2.Then when the mouse was placed on each circle appears around it with a text.My canvas knowledge isn't amazing, Here is an image to display what i want.
anyone shed some light on how to do it? Here is a fiddle of what I've managed
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvas01 = document.getElementById("canvas01");
var ctx01 = canvas01.getContext("2d");
canvas.width = 600;
canvas.height = 600;
canvas01.width = 600;
canvas01.height = 600;
var centerX = canvas01.width / 2;
var centerY = canvas01.height / 2;
var cw = canvas.width;
var ch = canvas.height;
var nextTime = 0;
var duration = 2000;
var start = Date.now();
var end = start + duration;
var endingPct = 100;
var endingPct1 = 510;
var pct = 0;
var pct1 = 0;
var i = 0;
var increment = duration;
var angle = 0;
var background = new Image();
var img = new Image();
img.src = "http://uupload.ir/files/2fhw_adur-d-01.jpg";
//http://uupload.ir/files/2fhw_adur-d-01.jpg
background.src = "http://uupload.ir/files/9a2q_adur-d-00.jpg";
//http://uupload.ir/files/9a2q_adur-d-00.jpg
Math.inOutQuart = function(n) {
n *= 2;
if (n < 1)
return 0.5 * n * n * n * n;
return -0.5 * ((n -= 2) * n * n * n - 2);
};
background.onload = function() {
ctx.drawImage(background, 0, 0);
};
function animate() {
var now = Date.now();
var p = (now - start) / duration;
val = Math.inOutQuart(p);
pct = 101 * val;
draw(pct);
if (pct >= (endingPct )) {
start = Date.now();
return animate1();
}
if (pct < (endingPct )) {
requestAnimationFrame(animate);
}
}
function animate1() {
var now1 = Date.now();
var p1 = (now1 - start) / duration;
val = Math.inOutQuart(p1);
pct1 = centerY + 211 * val;
SmallCircle(pct1);
if (pct1 < (endingPct1 )) {
requestAnimationFrame(animate1);
}
}
function draw(pct) {
var endRadians = -Math.PI / 2 + Math.PI * 2 * pct / 100;
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, 180, -Math.PI / 2, endRadians);
ctx.lineTo(canvas.width / 2, canvas.height / 2);
ctx.fillStyle = 'white';
ctx.fill();
ctx.save();
ctx.clip();
ctx.drawImage(img, 0, 0);
ctx.restore();
}
animate();
function SmallCircle(pctt) {
ctx01.clearRect(0, 0, canvas01.width, canvas01.height);
ctx01.beginPath();
ctx01.arc(centerX, pctt, 7, 0, 2 * Math.PI, false);
ctx01.closePath();
ctx01.fillStyle = 'green';
ctx01.fill();
}
You can use transformations to draw your small circles extending at a radius from the logo center.
Here is example code and a Demo:
The smallCircle function let you specify these settings:
X & Y of the logo center: cx,cy,
The current radius which the small circle is from the logo center: pctt,
The angle of the smallCircle vs the logo center: angle,
The text to draw: text,
The smallCircle fill color: circlecolor,
The arc-circle stroke color: arccolor (if you don't want the arc-circle to appear you can specify transparent as the arccolor),
The text color: textcolor (if you don't want the text to appear you can specify transparent as the textcolor),
var canvas=document.getElementById("canvas01");
var ctx01=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
var cx=canvas.width/2;
var cy=canvas.height/2;
var PI2=Math.PI*2;
var smallCount=8;
var pctt=0;
var chars=['A','B','C','D','E','F','G','H'];
var circleFill='green';
var arcStroke='lawngreen';
var textFill='white';
ctx01.textAlign='center';
ctx01.textBaseline='middle';
animate(performance.now());
function animate(time){
ctx01.clearRect(0, 0, canvas01.width, canvas01.height);
for(var i=0;i<smallCount;i++){
smallCircle(
cx,cy,pctt,PI2/smallCount*i,
chars[i],circleFill,'transparent','transparent');
}
pctt+=1;
if(pctt<100){
requestAnimationFrame(animate);
}else{
for(var i=0;i<smallCount;i++){
smallCircle(
cx,cy,pctt,PI2/smallCount*i,
chars[i],circleFill,arcStroke,textFill);
}
}
}
function hilightCircle(n){}
function smallCircle(cx,cy,pctt,angle,text,circlecolor,arccolor,textcolor){
// move to center canvas
ctx01.translate(cw/2,ch/2);
// rotate by the specified angle
ctx01.rotate(angle);
// move to the center of the circle
ctx01.translate(pctt,0);
// draw the filled small circle
ctx01.beginPath();
ctx01.arc(0,0,7,0,PI2);
ctx01.closePath();
ctx01.fillStyle = circlecolor;
ctx01.fill();
// stroke the outside circle
ctx01.beginPath();
ctx01.arc(0,0,7+5,0,PI2);
ctx01.closePath();
ctx01.strokeStyle=arccolor;
ctx01.stroke();
// unrotate so the text is upright
ctx01.rotate(-angle);
// draw the text
ctx01.fillStyle=textcolor;
ctx01.fillText(text,0,0);
// reset all transforms to default
ctx01.setTransform(1,0,0,1,0,0);
}
body{ background-color:gray; }
canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>After animation, click the mouse.</h4>
<canvas id="canvas01" width=300 height=300></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();
}
}

dynamic rectangles on canvas

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.

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