I've been following various guides and have the base code up for a simple animation but for the life of me I cannot get the canvas to reset correctly. The clearRect() function is working perfectly but when I try to draw an arc again immediatly afterwards it draws the sum of all the paths again rather than just drawing the single segment of the circle.
Can someone tell me what I'm doing wrong here, I know it's a simple solution! In short I would like the test page below to produce a kind of spinning segment instead of just drawing a circle:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<span id="degrees_output" style="display:block;width:60px"></span>
<button onclick="continue_animation=false;">Stop</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var degrees = 0;
var continue_animation = true;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var output = document.getElementById('degrees_output');
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() {
// update
output.innerHTML = degrees;
var radians = (degrees / 180) * Math.PI;
if (degrees >= 360)
degrees = 0;
else
degrees += 1;
// clear
if (degrees % 20 == 0)
{
context.clearRect(0, 0, 578, 200);
}
context.beginPath();
// setup the line style
context.strokeStyle = '#fa00ff';
context.lineWidth = 5;
context.lineCap = 'round';
context.arc(50, 50, 20, 0, radians, false);
// colour the path
context.stroke();
context.closePath();
// request new frame
requestAnimFrame(function() {
if (continue_animation)
animate();
});
}
animate();
</script>
If you want a fixed length arc to sweep around your circle, you'll want to specify both the starting and ending angles in your context.arc like this:
context.arc(50, 50, 20, startRadians, radians, false);
and startRadians can just be any angle behind your "radians" value:
var startRadians= (degrees-45) * Math.PI/180;
and, Yes, you will need to clear the canvas (at least the previous arc) before drawing the arc in a new position:
context.clearRect(0,0,canvas.width,canvas.height);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/VFhzX/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var degrees = 0;
var continue_animation = true;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var output = document.getElementById('degrees_output');
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate() {
// update
output.innerHTML = degrees;
var radians = (degrees / 180) * Math.PI;
var startRadians= (degrees-45) * Math.PI/180;
if (degrees >= 360)
degrees = 0;
else
degrees += 1;
// clear
if (degrees % 20 == 0)
{
context.clearRect(0, 0, 578, 200);
}
context.clearRect(0,0,canvas.width,canvas.height);
context.beginPath();
// setup the line style
context.strokeStyle = '#fa00ff';
context.lineWidth = 5;
context.lineCap = 'round';
context.arc(50, 50, 20, startRadians, radians, false);
// colour the path
context.stroke();
context.closePath();
// request new frame
requestAnimFrame(function() {
if (continue_animation)
animate();
});
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<span id="degrees_output" style="display:block;width:60px"></span>
<button onclick="continue_animation=false;">Stop</button>
<canvas id="myCanvas" width="578" height="200"></canvas>
</body>
</html>
Related
in my code, how the lineTo() method is working even i didn't call moveTo() method. also i am trying to create an animation using canvas lines, but i can't make it properly. here's the work in progress
the css -> body {margin: 0; overflow: hidden;}
the html ->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="main.js"></script>
</body>
</html>
the jquery ->
$(document).ready(function () {
// make canvas fullpage
var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');
var innerWidth = $(window).width();
var innerHeight = $(window).height();
canvas.attr('width', innerWidth);
canvas.attr('height', innerHeight);
var x = 0;
var y = 0;
var dx = 10;
var dy = 10;
// animate function
$.fn.animate = function () {
requestAnimationFrame($.fn.animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
// for diagonal motion
ctx.lineTo((innerWidth / 1000) * x, (innerHeight / 1000) * y);
ctx.stroke();
// for horizontal motion
// ctx.lineTo((innerWidth / 1000) * x, innerHeight / 2);
// ctx.stroke();
// for vartical motion
// ctx.lineTo(innerWidth / 2, (innerHeight / 1000) * y);
// ctx.stroke();
if (x > innerWidth || x < 0) {
dx = -dx;
}
if (y > innerHeight || y < 0) {
dy = -dy;
}
x += dx;
y += dy;
}
$.fn.animate();
});
how to make this animation in correct form and how to stop the animate function ?
In order to stop the animation you need to use cancelAnimationFrame. This method takes as argument the animation id. Now if you click the canvas you can stop the animation or start the animation if it's stopped.
$(document).ready(function() {
var rid = null;
// make canvas fullpage
var canvas = $("canvas");
var ctx = canvas[0].getContext("2d");
var innerWidth = $(window).width();
var innerHeight = $(window).height();
canvas.attr("width", innerWidth);
canvas.attr("height", innerHeight);
var x = 0;
var y = 0;
var dx = 10;
var dy = 10;
// animate function
$.fn.animate = function() {
rid = requestAnimationFrame($.fn.animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
// for diagonal motion
ctx.lineTo(innerWidth / 1000 * x, innerHeight / 1000 * y);
ctx.stroke();
if (x > innerWidth || x < 0) {
dx = -dx;
}
if (y > innerHeight || y < 0) {
dy = -dy;
}
x += dx;
y += dy;
};
$.fn.animate();
canvas.click(function() {
if (rid) {
cancelAnimationFrame(rid);
rid = null;
} else {
rid = requestAnimationFrame($.fn.animate);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas></canvas>
I am using Firefox 19.0.2 on Ubuntu Linux.
I'm learning HTML5 but find that the following code's image
flashes repeatedly. Furthermore, I would like for the image
to finish downloading before the script stars:
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var Debugger = function() { };
Debugger.log = function(message) {
try {
console.log(message);
} catch (exception) {
return;
}
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
var platypus = new Image();
platypus.onload = function() {
context.drawImage(platypus, x, y);
}
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
window.setTimeout(drawCanvas, 200);
x = x + 5;
y = y + 5;
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</c
</body>
</html>
How can I solve these two problems. Do I need to double-buffer and how can I do it?
How do I detect an onload event for the images to finish being downloaded?
Thanks.
This will load the image first then create and draw the canvas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var platypus = new Image();
platypus.onload = function () {
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
context.drawImage(this, x, y);
}
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</canvas>
</body>
</html>
I suspect the issue is the setTimeout call. The first run of the drawCanvas function causes the image to start loading. Once the image is loaded, it'll draw on the canvas, but the subsequent drawCanvas calls caused by the timeout will cause the whole canvas to get filled with the rect you're drawing and thus making the image disappear.
The onload callback will not fire again due to the image already having been loaded.
The simplest way to fix it would be to use a preloader for the images. Basically instead of using your current window.onload handler, use another function which loads your images and stores them in some variables. Once it has finished loading the images, have it call drawCanvas which you would modify to use one of the stored images instead.
The following did it for me.
<!DOCTYPE html>
<html lang="en">
<head>
<meta encoding="UTF-8" />
<title>Hello Canvas</title>
<script type="text/javascript">
window.onload = drawCanvas;
function canvasSupportEnabled() {
return !!document.createElement('canvas').getContext;
}
var x = 0;
var y = 0;
function drawCanvas() {
if (!canvasSupportEnabled())
return;
var platypus = new Image();
platypus.onload = function () {
var theCanvas = document.getElementById("myCanvas");
var context = theCanvas.getContext("2d");
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
context.textBaseLine = "top";
context.fillText("Hello World!", 195, 80);
context.strokeStyle = "#000000";
context.strokeRect(x, y, 490, 290);
context.drawImage(this, x, y);
}
x = x + 5;
y = y + 5;
setTimeout(drawCanvas, 200);
platypus.src = "http://www.wildwatch.com.au/uploads/Platypus/PLATYPUSweb1.jpg"
}
</script>
</head>
<body>
<h1>Hello Canvas.</h1>
<canvas id="myCanvas" width="500" height="300">Your browser does not support HTML5 canvas.</
</body>
</html>
I want to have a animated canvas rotation of a word, while another word on the canvas does not move. But somehow both stand still. What do I have to change?
[link]http://jsfiddle.net/2dszD/8/
var canvas;
var ctx;
var canvasWidth;
var canvasHeight;
var interval = 10;
function init(){
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
canvasWidth = canvas.width;
canvasHeight = canvas.height;
setInterval(redraw, interval);
}
init();
function redraw() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.translate( (200 ), (150 ) );
ctx.rotate( 1*Math.PI/180 );
ctx.fillStyle = '#f00';
ctx.font = '40px san-serif';
ctx.textBaseline = 'top';
ctx.fillText("Hello rotated", 0, 0);
ctx.rotate(-( 1*Math.PI/180 ));
ctx.translate( -(200), -(150) );
ctx.fillStyle = '#f00';
ctx.font = '40px san-serif';
ctx.textBaseline = 'top';
ctx.fillText("Hello still", 0, 0);
}
Actually, your text is rotated by a tiny 1.0 degree.
1*Math.PI/180 represents 1 tiny degree of rotation
So this would be a more noticeable 5 degrees:
ctx.rotate( 5.0 * Math.PI/180 );
A few coding glitches:
You need to increment the rotation angle so your text actually animates
angleInDegrees+=5;
ctx.rotate( angleInDegrees * Math.PI/180 );
setInterval requires a full function as an argument, not just a function name, like this:
setInterval( function(){redraw();}, interval);
And here’s easier way to handle translate/rotate
Instead of un-translating and un-rotating like this:
ctx.translate( (200 ), (150 ) );
ctx.rotate( 1*Math.PI/180 );
// draw stuff here
ctx.rotate(-( 1*Math.PI/180 ));
ctx.translate( -(200), -(150) );
You can instead context.save() and context.restore() which is cleaner and doesn’t require un-doing:
// save the canvas context—including its un-translated and un-rotated setting
ctx.save();
ctx.translate(200,150);
ctx.rotate( angleInDegrees * Math.PI/180 );
// draw stuff here
// after restore() the canvas is back to its starting position before save()
ctx.restore();
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/5XTcn/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvasWidth;
var canvasHeight;
var interval = 350;
var angleInDegrees=0;
function init(){
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
canvasWidth = canvas.width;
canvasHeight = canvas.height;
setInterval( function(){redraw();}, interval);
}
init();
function redraw() {
angleInDegrees+=5;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.beginPath();
ctx.rect(200,150,5,5);
ctx.fill();
ctx.save();
ctx.translate(200,150);
ctx.rotate( angleInDegrees * Math.PI/180 );
ctx.fillStyle = '#f00';
ctx.font = '40px san-serif';
ctx.textBaseline = 'top';
ctx.fillText("Hello rotated", 0, 0);
ctx.restore();
ctx.fillStyle = '#f00';
ctx.font = '40px san-serif';
ctx.textBaseline = 'top';
ctx.fillText("Hello still", 0, 0);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=500 height=300></canvas>
</body>
</html>
I am trying to animate a circle across the canvas in diagonal direction. I am using requestanimationframe. It works smoothly in all browsers but not in firefox. There is constant flickering while the animation is going on. Please someone tell me what wrong I am doing. I need smooth animatin with atleast reasonable speed in firefox.
Here is my simple code, maybe someone can point out what I am missing here..:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
/*html { background: #000; }*/
</style>
<title>Test</title>
</head>
<body>
<script type="text/javascript">
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
window.cancelRequestAnimFrame = ( function() {
return window.cancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout
} )();
var canvas, context, toggle;
var ctr = 0;
var request;
var x = 10;
var y = 10;
init();
animate();
function init() {
canvas = document.createElement( 'canvas' );
canvas.width = 512;
canvas.height = 512;
context = canvas.getContext( '2d' );
document.body.appendChild( canvas );
}
function animate() {
request = requestAnimFrame( animate );
draw();
}
function draw() {
context.clearRect(0,0,canvas.width,canvas.height);
y+=2;
x+=2;
context.beginPath();
context.arc(x, y, 3, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
//cancelRequestAnimFrame(request);
}
</script>
</body>
</html>
There are two things in your code which you need to be revised:
First try the new requestAnimationFrame polyfill.
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelRequestAnimationFrame = window[vendors[x]+
'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}())
For an in-depth explanation read this article: http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
The second is that you need to calculate the delta between one time stamp and the next one. You are working with a fixed value which on each rendering iteration got increased by one. Because your browser can not keep up the the pace it might happen to skip one or two frames. This way you get a smooth time.
This is the way you calculate the delta time:
end = Date.now();
delta = ( end - start ) / 1000.0 * 60;
end = start;
http://jsfiddle.net/p5c6c/1/
Hello all can we place drag and drop functionality inside canvas using html5??
My actual requirement is to drag the image into textbox that should be done inside the canvas...
please share your ideas..The following link i used to learn drag and drop but it should be done inside the canvas..
http://www.w3schools.com/html5/tryit.asp?filename=tryhtml5_draganddrop
You can learn more in this tutorial: http://html5.litten.com/how-to-drag-and-drop-on-an-html5-canvas/
From your limited description in your question, it sounds like you drag items over the canvas and this tutorial is likely the best match.
This is the actual code you can paste into file and open in HTML5 compliant browser and it will work:
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Canvas Drag and Drop Test</title>
</head>
<body>
<section>
<div>
<canvas id="canvas" width="400" height="300">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
<script type="text/javascript">
var canvas;
var ctx;
var x = 75;
var y = 50;
var WIDTH = 400;
var HEIGHT = 300;
var dragok = false;
function rect(x,y,w,h) {
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(draw, 10);
}
function draw() {
clear();
ctx.fillStyle = "#FAF7F8";
rect(0,0,WIDTH,HEIGHT);
ctx.fillStyle = "#444444";
rect(x - 15, y - 15, 30, 30);
}
function myMove(e){
if (dragok){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
}
}
function myDown(e){
if (e.pageX < x + 15 + canvas.offsetLeft && e.pageX > x - 15 +
canvas.offsetLeft && e.pageY < y + 15 + canvas.offsetTop &&
e.pageY > y -15 + canvas.offsetTop){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
dragok = true;
canvas.onmousemove = myMove;
}
}
function myUp(){
dragok = false;
canvas.onmousemove = null;
}
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
</script>
</section>
</body>
</html>