Resizing html canvas using javascript - javascript

I'm trying to smoothly resize an html5 canvas element. I've cobbled together bits of code and I think the following should work:
<body>
<header id='myheader' height='200'>
<canvas id='mycanvas' width='200' height='200'></canvas>
<script>
var mycanvas = document.getElementById('mycanvas');
var context = mycanvas.getContext('2d');
var centerX = mycanvas.width / 2;
var centerY = mycanvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'blue';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
var animate = function(prop, val, duration) {
var start = new Date().getTime();
var end = start + duration;
var current = mycanvas[prop];
var distance = val - current;
var step = function() {
var timestamp = new Date().getTime();
var progress = Math.min((duration - (end - timestamp)) / duration, 1);
mycanvas[prop] = current + (distance * progress);
if (progress < 1) requestAnimationFrame(step);
};
return step();
};
animate('mycanvas.height', 10, 1000);
</script>
</header>
</body>
...but obviously it doesn't! The result I'm looking for is a canvas that shrinks to just show the middle part of the circle (something more interesting than a circle will be added later). Is there anything obvious that I'm missing, or am I just doing this the wrong way? Ultimately I want to to resize both the canvas and the header together, so getting the canvas resizing to work is stage 1. Any help appreciated...
(Edit: actually, I ultimately want to resize both the canvas and header in response to a scroll event - which I think means avoiding a css solution - but I want to get this bit working first!)

Here are a few changes to your script that I believe do what you want:
var mycanvas = document.getElementById('mycanvas');
var context = mycanvas.getContext('2d');
var radius = 70;
function draw() {
var centerX = mycanvas.width / 2;
var centerY = mycanvas.height / 2;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'blue';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
}
var animate = function(target, prop, val, duration, action) {
var start = new Date().getTime();
var end = start + duration;
var current = target[prop];
var distance = val - current;
var step = function() {
var timestamp = new Date().getTime();
var progress = Math.min((duration - (end - timestamp)) / duration, 1);
target[prop] = current + (distance * progress);
action();
if (progress < 1) requestAnimationFrame(step);
};
return step();
};
animate(mycanvas, 'height', 10, 1000, draw);

Related

HTML canvas move circle from a to b with animation

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>

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

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>

Reusable JavaScript Component: How to make it?

I would like to create a reusable JavaScript component out of the following canvas spinner. Never done this before. How to achieve it and how to use the component?
http://codepen.io/anon/pen/tkpqc
HTML:
<canvas id="spinner"></canvas>
JS:
var canvas = document.getElementById('spinner');
var context = canvas.getContext('2d');
var start = new Date();
var lines = 8,
cW = context.canvas.width,
cH = context.canvas.height;
centerX = canvas.width / 2;
centerY = canvas.height / 2;
radius = 20;
var draw = function() {
var rotation = parseInt(((new Date() - start) / 1000) * lines) % lines;
context.save();
context.clearRect(0, 0, cW, cH);
for (var i = 0; i < lines; i++) {
context.beginPath();
//context.rotate(Math.PI * 2 / lines);
var rot = 2*Math.PI/lines;
var space = 2*Math.PI/(lines * 12);
context.arc(centerX,centerY,radius,rot * (i) + space,rot * (i+1) - space);
if (i == rotation)
context.strokeStyle="#ED3000";
else
context.strokeStyle="#CDCDCD";
context.lineWidth=10;
context.stroke();
}
context.restore();
};
window.setInterval(draw, 1000 / 30);
EDIT - SOLUTION:
Here comes a solution if anybody is interested
http://codepen.io/anon/pen/tkpqc
There are any number of ways to do this. Javascript is an object oriented language so you can easily write like:
var Spinner = function(canvas_context)
{
this.context = canvas_context;
// Whatever other properties you needed to create
this.timer = false;
}
Spinner.prototype.draw = function()
{
// Draw spinner
}
Spinner.prototype.start = function()
{
this.timer = setInterval(this.start, 1000 / 30);
}
Spinner.prototype.stop = function() {
clearInterval(this.timer);
}
Now you can use this object like so:
var canvas = document.getElementById('#canvas');
var context = canvas.getContext('2d');
var spinner = new Spinner(context);
spinner.start();
Basically, you are creating a class whose sole purpose in life is to draw a spinner on a canvas. In this example, you'll note that you're passing in the canvas's context into the object, since the details of the canvas itself is not relevant to this class's interest.

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