Please check out this code :
(function() {
var cnv = document.getElementById('canvas');
if (cnv.getContext) {
var ctx = cnv.getContext('2d');
} else {
alert('God Damn it ...');
}
function initialize() {
window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
}
function draw() {
for (var i = 0; i < 25; i++) {
width = Math.random() * cnv.width;
height = Math.random() * cnv.height;
ctx.beginPath();
ctx.arc(width, height, 15, 0, Math.PI * 2);
ctx.strokeStyle = '#E1E1E1';
ctx.lineWidth = 1;
ctx.stroke();
}
}
function resizeCanvas() {
cnv.width = window.innerWidth;
cnv.height = window.innerHeight;
draw();
}
initialize();
})();
I have created 25 Circle shape with random position and I want to create an animation that scales up or down in a interval time. I know about setInterval but how should I call my shape to do something on it?
The first thing you will want to do is to have a place to store the position of your circles, since they are all going to be the same radius we can just store the x and y position. For that we can create a Circle function ("class") and have an array of circles:
var circles = []; // Array to store our circles
var minRadius = 1; // The smallest radius we can hit
var maxRadius = 100; // The largest radius we can hit
var currentRadius = 15;// The current radius of all our circles
var scaleBy = 1; // How the radius changes
var cnv = document.getElementById('canvas');
// ...
function initialize() {
window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
// Populating the array of circles to use when drawing
for (var i = 0; i < 25; i++) { // Make sure to do this after re-sizing the canvas
width = Math.random() * cnv.width;
height = Math.random() * cnv.height;
circles.push(new Circle(width, height));
}
}
// ...
function Circle(x, y){
this.x = x;
this.y = y;
}
Circle.prototype.draw = function(){
ctx.beginPath();
ctx.arc(this.x, this.y, currentRadius, 0, Math.PI * 2);
ctx.strokeStyle = '#E1E1E1';
ctx.lineWidth = 5;
ctx.stroke();
}
Now that you have some circles when you call draw you can iterate through the array and call circle.draw() for each circle element in your array:
function draw() {
// Clear the screen and draw the circles in our array
ctx.clearRect(0,0, cnv.width, cnv.height);
for (var i = 0; i < circles.length; i++) {
circles[i].draw();
}
}
One note is you will want to use ctx.clearRect(0,0, cnv.width, cnv.height) to clear the screen before drawing.
Finally you can now use setInterval to change the currentRadius (*While there is nothing wrong with setInterval I'd recommend using window.requestAnimationFrame for animation as it's a bit more smooth and efficient method). Then when you call draw it will draw the circles with the new value of currentRadius. In this example I'm going to have it start at 15. Then increase by 1 until it hits maxRadius, then we can flip the sign of scaleBy to start decreasing the radius to make them smaller. Finally when it his our minRadius you can flip the sign of scaleBy again to make it start scaling up again:
var timer = setInterval( function(){
// If we hit our min or max start scaling in the other direction
if(currentRadius > maxRadius || currentRadius < minRadius){
scaleBy *= -1;
}
currentRadius += scaleBy;
draw();
}, 50);
Below is a code snippet of the complete program:
(function() {
var circles = [];
var minRadius = 1;
var maxRadius = 100;
var currentRadius = 15;
var scaleBy = 1;
var cnv = document.getElementById('canvas');
if (cnv.getContext) {
var ctx = cnv.getContext('2d');
} else {
alert('God Damn it ...');
}
function initialize() {
window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
for (var i = 0; i < 25; i++) {
width = Math.random() * cnv.width;
height = Math.random() * cnv.height;
circles.push(new Circle(width, height));
}
}
function draw() {
ctx.clearRect(0,0, cnv.width, cnv.height);
for (var i = 0; i < circles.length; i++) {
circles[i].draw();
}
}
function resizeCanvas() {
cnv.width = window.innerWidth;
cnv.height = window.innerHeight;
}
function Circle(x, y){
this.x = x;
this.y = y;
}
Circle.prototype.draw = function(){
ctx.beginPath();
ctx.arc(this.x, this.y, currentRadius, 0, Math.PI * 2);
ctx.strokeStyle = '#E1E1E1';
ctx.lineWidth = 5;
ctx.stroke();
}
initialize();
var timer = setInterval( function(){
if(currentRadius > maxRadius || currentRadius < minRadius){
scaleBy *= -1;
}
currentRadius += scaleBy;
draw();
}, 50);
})();
<canvas id="canvas"></canvas>
I'm trying to make a simple canvas program where the user clicks to create bouncing moving circles. It keeps freezing but still creates the circles without updating. I'm not sure whats going on, please help!
I'm adding each circle to an array of circles with the constructor
The setInterval loop seems to be freezing but the circles are still created even when this is happening
I'm having a hard time debugging this, any advice is greatly appreciated
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Background Test</title>
<style>
* { margin: 0; padding: 0; overflow: hidden; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
// Request animation frame -> Optimizes animation speed
const requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
const c = document.getElementById('canvas');
const ctx = c.getContext('2d');
// Fullscreen
c.width = window.innerWidth;
c.height = window.innerHeight;
ctx.fillStyle = 'red';
let fps = 60;
// FOR MOBILE DEVICES
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
fps = 29;
// Options
const background = '#333';
const circleMinSpeed = 3;
const circleMaxSpeed = 6;
const circleMinSize = 3;
const circleMaxSize = 10;
const circles = [];
let circlesCounter = 0;
const circlesTimeAlive = 20 * fps; // seconds
let i = 0;
const interval = 1000 / fps;
let now, delta;
let then = Date.now();
// Coordinate variables
let mouseX, mouseY, clickX, clickY;
// Tracks mouse movement
c.onmousemove = function(event)
{
mouseX = event.clientX;
mouseY = event.clientY;
};
// Tracks mouse click
c.onmousedown = function(event)
{
clickX = event.clientX;
clickY = event.clientY;
circle(clickX, clickY);
};
function draw()
{
// Loop
requestAnimationFrame(draw);
// Set NOW and DELTA
now = Date.now();
delta = now - then;
// New frame
if (delta > interval) {
// Update THEN
then = now - (delta % interval);
// Our animation
// Clear canvas then draw
ctx.clearRect(0, 0, c.width, c.height);
drawBackground();
drawCos();
drawCircles();
drawTest();
}
}
// Circle constructor
function circle(x, y)
{
// Pick random color
let r = Math.floor(Math.random() * 255);
let g = Math.floor(Math.random() * 255);
let b = Math.floor(Math.random() * 255);
self.color = 'rgb(' + r + ', ' + g + ', ' + b + ')';
self.xCo = x;
self.yCo = y;
// Pick random size within ranges
self.size = circleMinSize + Math.floor(Math.random() *
(circleMaxSize - circleMinSize));
// Pick random direction & speed (spdX spdY)
self.speed = circleMinSpeed + Math.floor(Math.random() *
(circleMaxSpeed - circleMinSpeed));
self.spdX = self.speed * (Math.random() * 2) - 1; // picks -1 to 1
self.spdY = self.speed * (Math.random() * 2) - 1;
self.draw = function()
{
ctx.beginPath();
ctx.arc(self.xCo, self.yCo, self.size, 0, 2*Math.PI);
ctx.fillStyle = self.color;
ctx.fill();
};
circles[circlesCounter++] = self;
}
// Draw the background
function drawBackground()
{
ctx.fillStyle = background;
ctx.fillRect(0, 0, c.width, c.height);
}
function drawCircles()
{
for (let i = 0; i < circles.length; i++)
circles[i].draw();
}
function drawTest()
{
ctx.fillStyle = 'red';
ctx.fillRect(i++, i, 5, 5);
}
function drawCos()
{
ctx.fillStyle = 'white';
ctx.fillText("X: " + mouseX + " Y:" + mouseY, 10, 10, 200);
}
// Main loop
setInterval(function()
{
// Loop through circles and move them
for (let i = 0; i < circles.length; i++)
{
if (circle[i])
{
// Check left and right bounce
if (circle[i].xCo <= 0 || circle[i].xCo >= c.width)
circle[i].spdX = -circle[i].spdX;
circle[i].xCo += circle[i].spdX;
// Check left and right bounce
if (circle[i].yCo <= 0 || circle[i].yCo >= c.height)
circle[i].spdY = -circle[i].spdY;
circle[i].yCo += circle[i].spdY;
}
}
// Draw Everything
draw();
}, interval);
</script>
</body>
</html>
This code:
self.draw = function()
{
ctx.beginPath();
ctx.arc(self.xCo, self.yCo, self.size, 0, 2*Math.PI);
ctx.fillStyle = self.color;
ctx.fill();
};
Is overriding this function:
function draw()
{
// Loop
requestAnimationFrame(draw);
// Set NOW and DELTA
now = Date.now();
delta = now - then;
// New frame
if (delta > interval) {
// Update THEN
then = now - (delta % interval);
// Our animation
// Clear canvas then draw
ctx.clearRect(0, 0, c.width, c.height);
drawBackground();
drawCos();
drawCircles();
drawTest();
}
}
You need to rethink how you want to draw your circles because you're re-drawing the black canvas every time a click event is triggered. I mean, when a click is triggered, you're applying new coordinates, color, Etc, and probably that's not what you want to do.
My suggestion is create canvas per circle and append them into a DIV.
Hope it helps!
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();
I made this (run snippet below)
var Canvas = document.getElementById('c');
var ctx = Canvas.getContext('2d');
var resize = function() {
Canvas.width = Canvas.clientWidth;
Canvas.height = Canvas.clientHeight;
};
window.addEventListener('resize', resize);
resize();
var elements = [];
var presets = {};
presets.shard = function (x, y, s, random, color) {
return {
x: x,
y: y,
draw: function(ctx, t) {
this.x += 0;
this.y += 0;
var posX = this.x + + Math.sin((50 + x + (t / 10)) / 100) * 5;
var posy = this.y + + Math.sin((55 + x + (t / 10)) / 100) * 7;
ctx.beginPath();
ctx.fillStyle = color;
ctx.moveTo(posX, posy);
ctx.lineTo(posX+random,posy+random);
ctx.lineTo(posX+random,posy+random);
ctx.lineTo(posX+0,posy+50);
ctx.closePath();
ctx.fill();
}
}
};
for(var x = 0; x < Canvas.width; x++) {
for(var y = 0; y < Canvas.height; y++) {
if(Math.round(Math.random() * 60000) == 1) {
var s = ((Math.random() * 5) + 1) / 10;
if(Math.round(Math.random()) == 1){
var random = Math.floor(Math.random() * 100) + 10;
var colorRanges = ['#8c8886', '#9c9995'];
var color = colorRanges[Math.floor(Math.random() * colorRanges.length)];
elements.push(presets.shard(x, y, s, random, color));
}
}
}
}
setInterval(function() {
ctx.clearRect(0, 0, Canvas.width, Canvas.height);
var time = new Date().getTime();
for (var e in elements)
elements[e].draw(ctx, time);
}, 10);
<canvas id="c" width="1000" height="1000"\>
I just need to add one feature to be able to use it on the site I'm building it for. Some of the floating shards need to be blurred to give a sense of depth.
Can Canvas do this, and if so, how?
context.filter = 'blur(10px)';
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
I used this few months ago, maybe it could work for you as well :
var canvas = document.getElementById("heroCanvas");
var canvasContext = canvas.getContext("2d");
var canvasBackground = new Image();
canvasBackground.src = "image.jpg";
var drawBlur = function() {
// Store the width and height of the canvas for below
var w = canvas.width;
var h = canvas.height;
// This draws the image we just loaded to our canvas
canvasContext.drawImage(canvasBackground, 0, 0, w, h);
// This blurs the contents of the entire canvas
stackBlurCanvasRGBA("heroCanvas", 0, 0, w, h, 100);
}
canvasBackground.onload = function() {
drawBlur();
}
Here the source : http://zurb.com/playground/image-blur-texture
I am doing some work with HTML canvases. Unfortunately I have ran into a very weird problem. At some point during development of the code the web page started to hang the browser. There were no tight loops apart from the requestAnimFrame shim so I took it back to basics and have found a very odd thing.
The code below will animate a circle across the screen. This works perfectly fine. If I comment out the code to draw the circle (marked in the code) it then grinds the browser to a halt. What is happening?
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(lastTime, myCircle) {
//return;
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// update
var date = new Date();
var time = date.getTime();
var timeDiff = time - lastTime;
var linearSpeed = 100;
// pixels / second
var linearDistEachFrame = linearSpeed * timeDiff / 1000;
var currentX = myCircle.x;
if(currentX < canvas.width - myCircle.width - myCircle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myCircle.x = newX;
}
lastTime = time;
// clear
drawGrid();
//draw a circle
context.beginPath();
context.fillStyle = "#8ED6FF";
context.arc(myCircle.x, myCircle.y, myCircle.width, 0, Math.PI*2, true);
context.closePath();
context.fill();
context.lineWidth = myCircle.borderWidth;
context.strokeStyle = "black";
context.stroke();
// request new frame
requestAnimFrame(function() {
animate(lastTime, myCircle);
});
}
$(document).ready(function() {
var myCircle = {
x: 50,
y: 50,
width: 30,
height: 50,
borderWidth: 2
};
//drawGrid();
var date = new Date();
var time = date.getTime();
animate(time, myCircle);
});
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.strokeStyle = "#ddd";
context.stroke();
}
And my canvas is declared like so:
<canvas id="myCanvas" width="700" height="400"></canvas>
Turns out that the reason it worked when I draw the circle was because that code contained a closePath function. Adding that to the drawGrid function below fixes the issue.
function drawGrid(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.lineWidth = 1;
context.beginPath();
for (var x = 0; x <= canvas.width; x += 40) {
context.moveTo(0 + x, 0);
context.lineTo(0 + x, canvas.height);
}
for (var x = 0; x <= canvas.height; x += 40) {
context.moveTo(0, 0 + x);
context.lineTo(canvas.width, 0 + x);
}
context.closePath();
context.strokeStyle = "#ddd";
context.stroke();
}