I'm looking for a simple method which can able me to draw in a canvas a paint splash like this on :
One method will be to fire a lot of small particles which will paint a little circle, but I don't want to manage a lot of particle objects.
EDIT : example here: jsfiddle.net/MK73j/4/
A second method will be to have few images and manipulate scale and rotation, but I want to have a good random on the effect.
A third method will be to make some random litte points, join them with bezier curves and fill the content, but I will have only a single mark.
Well I don't know if there is a better method to have an effect which looks like this image or if I have to choose on of the 3 I thought about.
You can use illusion to create a nice splat effect.
Since objects “grow” as they approach, you can animate an increasing size plus a little motion to create your splat effect.
You can use context.drawImage to handle the resizing:
context.drawImage(splashImg, 0 ,0, splashImg.width, splashImg.height,
newX, newY, newWidth, newHeight);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/r8Grf/
<!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 canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
$("go").html("Loading...");
var count=80;
var win=new Image();
var splash;
win.onload=function(){
splash=new Image();
splash.onload=function(){
ctx.drawImage(win,0,0);
}
splash.src="http://dl.dropbox.com/u/139992952/splash2.svg";
}
win.src="http://dl.dropbox.com/u/139992952/window.png";
$("#go").click(function(){ count=80; animate(); });
function animate() {
// drawings
if(--count>1){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.drawImage(win,0,0);
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(splash,0,0,splash.width,splash.height,25,25,splash.width/count,splash.height/count);
ctx.restore();
}
// request new frame
requestAnimFrame(function() {
animate();
});
}
}); // end $(function(){});
</script>
</head>
<body>
<br/><button id="go">Splash!</button><br/><br/>
<canvas id="canvas" width=326 height=237></canvas>
</body>
</html>
Related
today i've got a problem regarding JavaScript.
I was given an exercise which consists on create a circle on the screen, using JavaScript, and then make it move to the right.
So the problem comes when i put in the function animate().
The code by itself works, it creates a circle, but when i insert the function animate() , put the code in it, and then try to recall it with requestFrameAnimation(animate), it just doesn't draw on the screen.
Code right down here. I've tried everything i am capable of, but couldn't fix it.
Thanks for the replies.
HTML:
<head>
<style type="text/css">
canvas{
border:1px solid black;
}
body{
margin:0px;
background-color:red;
</style>
</head>
<body>
<canvas></canvas>
<script src="canvas.js"></script>
</script>
</body>
JS:
canvas = document.querySelector('canvas'); //CANVAS SELECTOR
canvas.width = window.innerWidth; //MATCHING THE CANVAS WIDTH WITH THE WINDOW WIDTH
canvas.height = window.innerHeight; //********************HEIGHT***************HEIGHT
context=canvas.getContext("2d");
var x=200;
function animate(){ //Starting the function
context.beginPath(); //Initializing a Path of drawings
context.arc(x,200,100,0,Math.PI*2, true); //drawing the circle
context.fillStyle="rgba(120,10,200,0.5)"; //filling the circle
context.fill();
context.strokeStyle = 'blue'; //giving the circle a strokeline
context.stroke();
x+=1; //increasing the circle x so that it keeps moving towards right
requestAnimationFrame(animate); //calling back to the function so it keeps drawing infinitely.
}
I have a multipage site that the main home page simply has a single image logo on it. When this page is visited I need the image to move around like a screensaver. When any touch is registered the page will go to a second page. That second page has other data and info but nothing is touched for ten minutes it will default and go back to the entry page and the screensaver.
So, two things.
One, move an image around like a screensaver using jQuery.
Two, the other page has a timeout of ten minutes if no touch is registered that knocks the person back to the first page that has the screensaver.
This is an HTML5 page so if jQuery will not work, something using HTML5 and Canvas might.
This is for a site that will be used as a kiosk and a touch screen.
On the screensaver page:
You can use an html canvas that floats your logo image around the screen. Here's a link:
http://jsfiddle.net/m1erickson/E3Qda/
On the second page:
How about starting a 10 minute setTimeout when the page first loads.
If the user triggers a touch event before 10 minutes, (1) clearTimeout the original timeout (2) setTimeout for a new 10 minutes.
Here's example code for the screensaver page:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
img{border:1px solid purple;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var ball;
var ballX=60;
var ballY=150;
var ballRadius=50;
var image=new Image();
image.onload=function(){
// resize the image to fit inside the ball's radius
var c=document.createElement("canvas");
var cctx=c.getContext("2d");
// calc the max side length of a square that fits the ball
var maxSide=Math.sqrt(2*ballRadius*ballRadius);
// calc the max rect size that fits in the ball
var iw=image.width;
var ih=image.height;
var maxW,maxH;
if(iw>=ih){
maxW=maxSide;
maxH=maxSide*iw/ih;
}else{
maxW=maxSide*ih/iw;
maxH=maxSide;
}
// size the temp canvas to the max rect size
c.width=maxW;
c.height=maxH;
// draw the image to the temp canvas
cctx.drawImage(image,0,0,iw,ih,0,0,maxW,maxH);
var ballimg=new Image();
ballimg.onload=function(){
ball={x:ballX,y:ballY,r:ballRadius,img:ballimg,imgSide:maxSide,directionX:1,directionY:1};
drawBall(ball);
}
ballimg.src=c.toDataURL();
requestAnimationFrame(animate);
}
image.src="ship.png";
function drawBall(ball){
// clip image inside ball
ctx.save();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.clip();
ctx.fillStyle="white";
ctx.fillRect(ball.x-ball.r,ball.y-ball.r,ball.r*2,ball.r*2);
ctx.drawImage(ball.img, ball.x-ball.imgSide/2,ball.y-ball.imgSide/2);
ctx.restore();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="lightgray";
ctx.lineWidth=2;
ctx.stroke();
ctx.beginPath();
ctx.arc(ball.x,ball.y,ball.r+2,0,Math.PI*2,false);
ctx.closePath();
ctx.strokeStyle="gray";
ctx.lineWidth=2;
ctx.stroke();
}
function animate(time) {
requestAnimationFrame(animate);
// move with collision detection
ball.x+=ball.directionX;
if(ball.x-ball.r<0 || ball.x+ball.r>canvas.width){
ball.directionX*=-1;
ball.x+=ball.directionX;
}
ball.y+=ball.directionY;
if(ball.y-ball.r<0 || ball.y+ball.r>canvas.height){
ball.directionY*=-1;
ball.y+=ball.directionY;
}
// Draw
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall(ball);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
Here's my objective. I want to literally paint on a canvas element then automatically erase it in a quick gradual manner. The similar implementation is somewhat like this: http://mario.ign.com/3D-era/super-mario-sunshine
I want to make it simple. I just simply want to paint and then erase the recently painted stroke. Where do I start? Is there a simple approach on painting on a canvas without using any kind of plugin? I am currently using wPaint.js and it's not really what I want. Is there a way of painting on a canvas and undoing without too much complex code?
Here is how to let the user draw a self-disappearing line:
Create a polyline by saving points to an array when the user drags the mouse.
In an animation loop, clear the screen and redraw that polyline.
But each loop, leave out the earliest points (making the earliest points “disappear”).
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/LT6Ln/
<!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(){
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.lineWidth=15;
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isDown=false;
var points=[];
var minPoint=0;
var PI2=Math.PI*2
var radius=20;
var fps = 20;
var lastTime=0;
animate();
function animate() {
setTimeout(function() {
requestAnimFrame(animate);
// draw a polyline using the saved points array
// but start later in the array each animation loop
if(minPoint<points.length){
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.beginPath();
ctx.moveTo(points[minPoint].x,points[minPoint.y]);
for(var i=minPoint+1;i<points.length;i++){
var pt=points[i];
ctx.lineTo(pt.x,pt.y);
}
ctx.stroke();
minPoint++;
}
}, 1000 / fps);
}
function handleMouseDown(e){
isDown=true;
}
function handleMouseUp(e){
isDown=false;
}
function handleMouseOut(e){
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// accumulate points for the polyline but throttle
// the capture to prevent clustering of points
if(Date.now()-lastTime>20){
points.push({x:mouseX,y:mouseY});
lastTime=Date.now();
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h3>Drag to create a self-clearing line.</h3>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[ Update: Using complex effects instead of a simple line ]
Sure. You can use a spraypaint effect instead of a line.
However, this effect requires some expensive processing!
The spraypaint effect is often created by drawing multiple random 1x1 pixels around a centerpoint.
Assuming 10 droplets per “spray”, every point along your polyline requires:
10 X fillRect(x,y,1,1) draws on the canvas (instead of 1 X lineTo for the simple line).
20 X Math.random,
10 X Math.cos and
10 X Math.sin.
Here’s an example fiddle of a “spraypaint” effect: http://jsfiddle.net/m1erickson/zJ2ZR/
Keep in mind that all this processing must take place within the small time allowed by requestAnimationFrame (often 16-50 milliseconds per frame).
Doing the expensive spraypaint on each of 20-50 accumulated points along the polyline will likely not fit inside the time of an RAF frame.
To make spraypainting fit inside the time allowed by RAF, you will need to “cache” the effect:
Create 1 random “spray” in a 10px by 10px offscreen canvas.
Create an image from that canvas using canvas.toDataURL.
Add that image to an array.
Repeat step #1 maybe a dozen times (to get a good variety of random spray images)
Then instead of context.lineTo or spraypainting on-the-fly, just do this:
context.drawImage(myCachedSprays[nextSprayIndex],point.x,point.y);
Use Kinetic.js . Its is very easy to learn. By this you can add or remove any painted stroke very easly.
See the working of it from here : http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-batch-draw/
So I have an idea for a site design where the background is a grid of small (say 10px) color-shifting squares. Ideally, I'd like to have the elements on the page line up with this grid, however most of the guides for website grids revolve around the 960 grid system, which isn't small enough for my purposes.
Anyone have any suggestions for how to achieve this? Also, if anyone has any ideas for how to do the color-shifting grid thing, I'd definitely appreciate that as well!
Here's how to create a constantly changing, multi-colored grid
You can fill an 8x8 grid with rectangles (one at a time) like this:
var n=parseInt(Math.random()*64);
var r=parseInt(n/8);
var c=n-r*8;
ctx.fillStyle=randomColor();
ctx.fillRect(c*20,r*20,20,20);
You can generate a random color like this:
function randomColor(){
return("#"+Math.floor(Math.random()*16777215).toString(16));
}
Add an animation loop and you’re good to go!
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/n2ymp/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var fps = 30;
function animate() {
setTimeout(function() {
requestAnimFrame(animate);
// Drawing code goes here
var n=parseInt(Math.random()*64);
var r=parseInt(n/8);
var c=n-r*8;
ctx.fillStyle=randomColor();
ctx.fillRect(c*20,r*20,20,20);
}, 1000 / fps);
}
// create a random color object {red,green,blue}
function randomColor(){
return("#"+Math.floor(Math.random()*16777215).toString(16));
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=600 height=400></canvas>
</body>
</html>
On my main bottom layer where the player moves and elevators move I use this frame rate:
var requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000/60);
};
When the player dies I use this frame rate for the explosion animation.
var requestAnimFrameExplode = function(callback) {
window.setTimeout(callback, 1000/15);
};
Now all this works fine, however on one of my levels I have elevators moving up and down etc that use the main bottom layer frame rate, but when the player dies the explosion frame rate players(makes things slower so you can see the animation for 1 sec) so this makes the elevators slow down for 1 sec and makes it look glitchy.
In my game Loop I have:
if(Death ==true)
{
requestAnimFrameExplode(Loop); //calls loop again but slower so animation explode shows
DrawSpawnAnimation(); //this draws the explode animation
}
else
{
requestAnimFrame(Loop); //when Death is false it calls at normal fast framerate for player movement etc
}
My question is how to stop this glitching? How can I Make the elevators and other thing sin the loop run the same time even if the animation is playing?
Here’s an animation illustration that uses both requestAnimationFrame and setTimeout.
It would be more performant to use RAF to drive both animations, but both are presented here for illustration purposes.
This RAF animation loop runs your elevator and looks like this:
var fps1 = 60;
function runElevator() {
setTimeout(function() {
// request another loop
raf1=requestAnimFrame(runElevator);
// update the elevator properties (current Y and directon)
elevatorY+=elevatorSpeed*elevatorDirection;
if(elevatorY+elevatorHeight>canvasB.height || elevatorY<30){
elevatorDirection= -elevatorDirection;
}
// call the function that draws the elevator frame
drawElevator(elevatorX,elevatorY,elevatorWidth,elevatorHeight)
}, 1000 / fps1);
}
The setTimeout animation loop runs your explosion and looks like this:
var fps2 = 30;
function runExplosion() {
// update the explosion properties (the current radius of the explosion)
explosionRadius+=1.5;
// check if the explosion is done
if(explosionRadius<explosionMaxRadius){
// the explosion is not done, draw another explosion frame
drawExplosion(explosionX,explosionY,explosionRadius);
// and request another loop
setTimeout(runExplosion, 1000/fps2);
}else{
// the explosion is done, clear the top canvas and “we’re outta here!”
ctxT.clearRect(0,0,canvasT.width,canvasT.width);
}
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/YzqUF/
<!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; padding:20px;}
#container{position:relative;}
canvas{border:1px solid red; position:absolute; top:0; left:0}
</style>
<script>
$(function(){
var canvasT=document.getElementById("canvasTop");
var ctxT=canvasT.getContext("2d");
var canvasB=document.getElementById("canvasBottom");
var ctxB=canvasB.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var elevatorX=30;
var elevatorY=30;
var elevatorWidth=40;
var elevatorHeight=60;
var elevatorSpeed=2;
var elevatorDirection=1;
ctxT.strokeStyle="orange";
var explosionX=100;
var explosionY=200;
var explosionStartingRadius=10;
var explosionEndingRadius=25;
var explosionRadius=explosionStartingRadius;
var raf1;
var raf2;
runElevator();
function explode(x,y,maxRadius){
explosionX=x;
explosionY=y;
explosionMaxRadius=maxRadius
explosionRadius=10;
ctxT.clearRect(0,0,canvasB.width,canvasB.height);
ctxT.beginPath();
ctxT.arc(x,y,explosionRadius,0,Math.PI*2,false)
ctxT.closePath();
ctxT.fillStyle="yellow"
ctxT.fill();
ctxT.stroke();
ctxT.fillStyle="orange";
runExplosion();
}
var fps1 = 60;
function runElevator() {
setTimeout(function() {
raf1=requestAnimFrame(runElevator);
elevatorY+=elevatorSpeed*elevatorDirection;
if(elevatorY+elevatorHeight>canvasB.height || elevatorY<30){
elevatorDirection= -elevatorDirection;
}
drawElevator(elevatorX,elevatorY,elevatorWidth,elevatorHeight)
}, 1000 / fps1);
}
var fps2 = 30;
function runExplosion() {
explosionRadius+=1.5;
if(explosionRadius<explosionMaxRadius){
drawExplosion(explosionX,explosionY,explosionRadius);
setTimeout(runExplosion, 1000/fps2);
}else{
ctxT.clearRect(0,0,canvasT.width,canvasT.width);
}
}
function drawElevator(x,y,width,height){
ctxB.clearRect(0,0,canvasB.width,canvasB.height);
ctxB.beginPath();
ctxB.moveTo(x+width/2,0);
ctxB.lineTo(x+width/2,y);
ctxB.rect(x,y,width,height);
ctxB.stroke();
ctxB.fill();
}
function drawExplosion(x,y,radius){
ctxT.beginPath();
ctxT.arc(x,y,radius,0,Math.PI*2,false);
ctxT.closePath()
ctxT.stroke();
}
$("#explode").click(function(){ explode(150,150,75); });
}); // end $(function(){});
</script>
</head>
<body>
<button id="explode">Explode</button>
<div id="container">
<canvas id="canvasTop" width=300 height=300></canvas>
<canvas id="canvasBottom" width=300 height=300></canvas>
</div>
</body>
</html>
It sounds like you're trying to control the speed of your animation by controlling the framerate. I recommend refactoring so that framerate is independent of animation speed.
In other words, don't slow down your explosion by lowering your framerate. You should slow it down by making the flames / debris move less between each frame.
That said, slowing the whole level down (elevators and all) when you die sounds like kind of a neat effect ;)