I have a canvas
(check in Chrome only)
$(function() {
var Fire = function(){
this.canvas = document.getElementById('fire');
this.ctx = this.canvas.getContext('2d');
this.canvas.height = window.innerHeight;
this.canvas.width = window.innerWidth;
this.aFires = [];
this.aSpark = [];
this.aSpark2 = [];
this.mouse = {
x : this.canvas.width * .5,
y : this.canvas.height * .75,
}
this.init();
}
Fire.prototype.init = function()
{
//this.canvas.addEventListener('mousemove', this.updateMouse.bind( this ), false);
}
Fire.prototype.run = function(){
this.update();
this.draw();
if( this.bRuning )
requestAnimationFrame( this.run.bind( this ) );
}
Fire.prototype.start = function(){
this.bRuning = true;
this.run();
}
Fire.prototype.update = function(){
this.aFires.push( new Flame( this.mouse ) );
this.aSpark.push( new Spark( this.mouse ) );
this.aSpark2.push( new Spark( this.mouse ) );
for (var i = this.aFires.length - 1; i >= 0; i--) {
if( this.aFires[i].alive )
this.aFires[i].update();
else
this.aFires.splice( i, 1 );
}
for (var i = this.aSpark.length - 1; i >= 0; i--) {
if( this.aSpark[i].alive )
this.aSpark[i].update();
else
this.aSpark.splice( i, 1 );
}
for (var i = this.aSpark2.length - 1; i >= 0; i--) {
if( this.aSpark2[i].alive )
this.aSpark2[i].update();
else
this.aSpark2.splice( i, 1 );
}
}
Fire.prototype.draw = function(){
this.ctx.globalCompositeOperation = "source-over";
this.ctx.fillStyle = "rgba( 15, 5, 2, 1 )";
this.ctx.fillRect( 0, 0, window.innerWidth, window.innerHeight );
this.grd = this.ctx.createRadialGradient( this.mouse.x, this.mouse.y - 200,200,this.mouse.x, this.mouse.y - 100,0 );
this.grd.addColorStop(0,"rgb( 15, 5, 2 )");
this.grd.addColorStop(1,"rgb(30, 10, 2 )");
this.ctx.beginPath();
this.ctx.arc( this.mouse.x, this.mouse.y - 100, 200, 0, 2*Math.PI );
this.ctx.fillStyle= this.grd;
this.ctx.fill();
this.ctx.globalCompositeOperation = "overlay";//or lighter or soft-light
for (var i = this.aFires.length - 1; i >= 0; i--) {
this.aFires[i].draw( this.ctx );
}
this.ctx.globalCompositeOperation = "soft-light";//"soft-light";//"color-dodge";
for (var i = this.aSpark.length - 1; i >= 0; i--) {
if( ( i % 2 ) === 0 )
this.aSpark[i].draw( this.ctx );
}
this.ctx.globalCompositeOperation = "color-dodge";//"soft-light";//"color-dodge";
for (var i = this.aSpark2.length - 1; i >= 0; i--) {
this.aSpark2[i].draw( this.ctx );
}
}
// Flame
var Flame = function( mouse ){
this.cx = mouse.x;
this.cy = mouse.y;
this.x = rand( this.cx - 600, this.cx + 600);
this.y = rand( this.cy - -200, this.cy + 5);
this.vy = rand( 1, 3 );
this.vx = rand( -1, 1 );
this.r = rand( 20, 30 );
this.life = rand( 3, 6 );
this.alive = true;
this.c = {
h : Math.floor( rand( 2, 40) ),
s : 1000,
l : rand( 80, 100 ),
a : 0,
ta : rand( 0.8, 0.9 )
}
}
Flame.prototype.update = function()
{
this.y -= this.vy;
this.vy += 0.05;
this.x += this.vx;
if( this.x < this.cx )
this.vx += 0.1;
else
this.vx -= 0.1;
if( this.r > 0 )
this.r -= 0.1;
if( this.r <= 0 )
this.r = 0;
this.life -= 0.15;
if( this.life <= 0 ){
this.c.a -= 0.05;
if( this.c.a <= 0 )
this.alive = false;
}else if( this.life > 0 && this.c.a < this.c.ta ){
this.c.a += .08;
}
}
Flame.prototype.draw = function( ctx ){
ctx.beginPath();
ctx.arc( this.x, this.y, this.r * 3, 0, 2*Math.PI );
ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a/20) + ")";
ctx.fill();
ctx.beginPath();
ctx.arc( this.x, this.y, this.r, 0, 2*Math.PI );
ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
ctx.fill();
}
// Spark
var Spark = function( mouse ){
this.cx = mouse.x;
this.cy = mouse.y;
this.x = rand( this.cx -600, this.cx + 600);
this.y = rand( this.cy - -200, this.cy + 5);
this.lx = this.x;
this.ly = this.y;
<!-- Edit Value -->
this.vy = rand( 1, 3 );
this.vx = rand( -4, 4 );
this.r = rand( 0, 1 );
this.life = rand( 4, 5 );
this.alive = true;
this.c = {
h : Math.floor( rand( 2, 40) ),
s : 100,
l : rand( 40, 100 ),
a : rand( 0.8, 0.9 )
}
}
Spark.prototype.update = function()
{
this.lx = this.x;
this.ly = this.y;
this.y -= this.vy;
this.x += this.vx;
if( this.x < this.cx )
this.vx += 0.2;
else
this.vx -= 0.2;
this.vy += 0.08;
this.life -= 0.1;
if( this.life <= 0 ){
this.c.a -= 0.05;
if( this.c.a <= 0 )
this.alive = false;
}
}
Spark.prototype.draw = function( ctx ){
ctx.beginPath();
ctx.moveTo( this.lx , this.ly);
ctx.lineTo( this.x, this.y);
ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a / 2) + ")";
ctx.lineWidth = this.r * 2;
ctx.lineCap = 'round';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo( this.lx , this.ly);
ctx.lineTo( this.x, this.y);
ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
ctx.lineWidth = this.r;
ctx.stroke();
ctx.closePath();
}
rand = function( min, max ){ return Math.random() * ( max - min) + min; };
onresize = function () { oCanvas.canvas.width = window.innerWidth; oCanvas.canvas.height = window.innerHeight; };
var oCanvas;
init = function()
{
oCanvas = new Fire();
oCanvas.start();
}
window.onload = init;
});
h1
{
position:relative;
z-index:1;
float:right;
width:100%;
color:#fff;
}
#fire
{
position:fixed;
height:100%;
top:0;
right:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<canvas id="fire"></canvas>
<h1>Hover Me!</h1>
I want to change the amount of canvas every time the Hover Me! is hoverd.
For example, this value is this.vy = rand (1, 3); To this value this.vy = rand (1, 30); When the hover changes.
Another thing to note is why the Mozilla browser is extremely difficult to execute and the colors in the Internet Explorer are not supported.
please help me!
Related
im trying to implement this
https://codepen.io/Mertl/pen/XWdyRwJ into a hugo template https://themes.gohugo.io/somrat/ ;
I dont know where to put the html file; put only the no cursor part into style.css; and copy the .js into script.js, nothing happens on the localhost website when I do this, any help is appreciated <3
code: (html, css and js)
<canvas id="canvas"></canvas>
body,
html {
margin: 0px;
padding: 0px;
position: fixed;
background: rgb(30, 30, 30);
cursor: none;
}
window.onload = function () {
//functions definition
//class definition
class segm {
constructor(x, y, l) {
this.b = Math.random()*1.9+0.1;
this.x0 = x;
this.y0 = y;
this.a = Math.random() * 2 * Math.PI;
this.x1 = this.x0 + l * Math.cos(this.a);
this.y1 = this.y0 + l * Math.sin(this.a);
this.l = l;
}
update(x, y) {
this.x0 = x;
this.y0 = y;
this.a = Math.atan2(this.y1 - this.y0, this.x1 - this.x0);
this.x1 = this.x0 + this.l * Math.cos(this.a);
this.y1 = this.y0 + this.l * Math.sin(this.a);
}
}
class rope {
constructor(tx, ty, l, b, slq, typ) {
if(typ == "l"){
this.res = l / 2;
}else{
this.res = l / slq;
}
this.type = typ;
this.l = l;
this.segm = [];
this.segm.push(new segm(tx, ty, this.l / this.res));
for (let i = 1; i < this.res; i++) {
this.segm.push(
new segm(this.segm[i - 1].x1, this.segm[i - 1].y1, this.l / this.res)
);
}
this.b = b;
}
update(t) {
this.segm[0].update(t.x, t.y);
for (let i = 1; i < this.res; i++) {
this.segm[i].update(this.segm[i - 1].x1, this.segm[i - 1].y1);
}
}
show() {
if(this.type == "l"){
c.beginPath();
for (let i = 0; i < this.segm.length; i++) {
c.lineTo(this.segm[i].x0, this.segm[i].y0);
}
c.lineTo(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1
);
c.strokeStyle = "white";
c.lineWidth = this.b;
c.stroke();
c.beginPath();
c.arc(this.segm[0].x0, this.segm[0].y0, 1, 0, 2 * Math.PI);
c.fillStyle = "white";
c.fill();
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2,
0,
2 * Math.PI
);
c.fillStyle = "white";
c.fill();
}else{
for (let i = 0; i < this.segm.length; i++) {
c.beginPath();
c.arc(this.segm[i].x0, this.segm[i].y0, this.segm[i].b, 0, 2*Math.PI);
c.fillStyle = "white";
c.fill();
}
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2, 0, 2*Math.PI
);
c.fillStyle = "white";
c.fill();
}
}
}
//setting up canvas
let c = init("canvas").c,
canvas = init("canvas").canvas,
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
ropes = [];
//variables definition
let nameOfVariable = "value",
mouse = {},
last_mouse = {},
rl = 50,
randl = [],
target = { x: w/2, y: h/2 },
last_target = {},
t = 0,
q = 10,
da = [],
type = "l";
for (let i = 0; i < 100; i++) {
if(Math.random() > 0.25){
type = "l";
}else{
type = "o";
}
ropes.push(
new rope(
w / 2,
h / 2,
(Math.random() * 1 + 0.5) * 500,
Math.random() * 0.4 + 0.1,
Math.random()*15+5,
type
)
);
randl.push(Math.random() * 2 - 1);
da.push(0);
}
//place for objects in animation
function draw() {
if (mouse.x) {
target.errx = mouse.x - target.x;
target.erry = mouse.y - target.y;
} else {
target.errx =
w / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.x;
target.erry =
h / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) *
Math.sin(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.y;
}
target.x += target.errx / 10;
target.y += target.erry / 10;
t += 0.01;
for (let i = 0; i < ropes.length; i++) {
if (randl[i] > 0) {
da[i] += (1 - randl[i]) / 10;
} else {
da[i] += (-1 - randl[i]) / 10;
}
ropes[i].update({
x:
target.x +
randl[i] * rl * Math.cos((i * 2 * Math.PI) / ropes.length + da[i]),
y:
target.y +
randl[i] * rl * Math.sin((i * 2 * Math.PI) / ropes.length + da[i])
});
ropes[i].show();
}
last_target.x = target.x;
last_target.y = target.y;
}
//mouse position
canvas.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
canvas.addEventListener("mouseleave", function(e) {
mouse.x = false;
mouse.y = false;
});
//animation frame
function loop() {
window.requestAnimFrame(loop);
c.clearRect(0, 0, w, h);
draw();
}
//window resize
window.addEventListener("resize", function () {
(w = canvas.width = window.innerWidth),
(h = canvas.height = window.innerHeight);
loop();
});
//animation runner
loop();
setInterval(loop, 1000 / 60);
};
Try to implement like this
window.init = function(elemid) {
let canvas = document.getElementById(elemid),
c = canvas.getContext("2d"),
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight);
c.fillStyle = "rgba(30,30,30,1)";
c.fillRect(0, 0, w, h);
return {c:c,canvas:canvas};
}
window.requestAnimFrame = function() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback);
}
);
};
window.spaceworm = function () {
//functions definition
//class definition
class segm {
constructor(x, y, l) {
this.b = Math.random()*1.9+0.1;
this.x0 = x;
this.y0 = y;
this.a = Math.random() * 2 * Math.PI;
this.x1 = this.x0 + l * Math.cos(this.a);
this.y1 = this.y0 + l * Math.sin(this.a);
this.l = l;
}
update(x, y) {
this.x0 = x;
this.y0 = y;
this.a = Math.atan2(this.y1 - this.y0, this.x1 - this.x0);
this.x1 = this.x0 + this.l * Math.cos(this.a);
this.y1 = this.y0 + this.l * Math.sin(this.a);
}
}
class rope {
constructor(tx, ty, l, b, slq, typ) {
if(typ == "l"){
this.res = l / 2;
}else{
this.res = l / slq;
}
this.type = typ;
this.l = l;
this.segm = [];
this.segm.push(new segm(tx, ty, this.l / this.res));
for (let i = 1; i < this.res; i++) {
this.segm.push(
new segm(this.segm[i - 1].x1, this.segm[i - 1].y1, this.l / this.res)
);
}
this.b = b;
}
update(t) {
this.segm[0].update(t.x, t.y);
for (let i = 1; i < this.res; i++) {
this.segm[i].update(this.segm[i - 1].x1, this.segm[i - 1].y1);
}
}
show() {
if(this.type == "l"){
c.beginPath();
for (let i = 0; i < this.segm.length; i++) {
c.lineTo(this.segm[i].x0, this.segm[i].y0);
}
c.lineTo(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1
);
c.strokeStyle = "white";
c.lineWidth = this.b;
c.stroke();
c.beginPath();
c.arc(this.segm[0].x0, this.segm[0].y0, 1, 0, 2 * Math.PI);
c.fillStyle = "white";
c.fill();
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2,
0,
2 * Math.PI
);
c.fillStyle = "white";
c.fill();
}else{
for (let i = 0; i < this.segm.length; i++) {
c.beginPath();
c.arc(this.segm[i].x0, this.segm[i].y0, this.segm[i].b, 0, 2*Math.PI);
c.fillStyle = "white";
c.fill();
}
c.beginPath();
c.arc(
this.segm[this.segm.length - 1].x1,
this.segm[this.segm.length - 1].y1,
2, 0, 2*Math.PI
);
c.fillStyle = "white";
c.fill();
}
}
}
//setting up canvas
let c = init("canvas").c,
canvas = init("canvas").canvas,
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
ropes = [];
//variables definition
let nameOfVariable = "value",
mouse = {},
last_mouse = {},
rl = 50,
randl = [],
target = { x: w/2, y: h/2 },
last_target = {},
t = 0,
q = 10,
da = [],
type = "l";
for (let i = 0; i < 100; i++) {
if(Math.random() > 0.25){
type = "l";
}else{
type = "o";
}
ropes.push(
new rope(
w / 2,
h / 2,
(Math.random() * 1 + 0.5) * 500,
Math.random() * 0.4 + 0.1,
Math.random()*15+5,
type
)
);
randl.push(Math.random() * 2 - 1);
da.push(0);
}
//place for objects in animation
function draw() {
if (mouse.x) {
target.errx = mouse.x - target.x;
target.erry = mouse.y - target.y;
} else {
target.errx =
w / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.x;
target.erry =
h / 2 +
(h / 2 - q) *
Math.sqrt(2) *
Math.cos(t) *
Math.sin(t) /
(Math.pow(Math.sin(t), 2) + 1) -
target.y;
}
target.x += target.errx / 10;
target.y += target.erry / 10;
t += 0.01;
for (let i = 0; i < ropes.length; i++) {
if (randl[i] > 0) {
da[i] += (1 - randl[i]) / 10;
} else {
da[i] += (-1 - randl[i]) / 10;
}
ropes[i].update({
x:
target.x +
randl[i] * rl * Math.cos((i * 2 * Math.PI) / ropes.length + da[i]),
y:
target.y +
randl[i] * rl * Math.sin((i * 2 * Math.PI) / ropes.length + da[i])
});
ropes[i].show();
}
last_target.x = target.x;
last_target.y = target.y;
}
//mouse position
canvas.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
canvas.addEventListener("mouseleave", function(e) {
mouse.x = false;
mouse.y = false;
});
//animation frame
function loop() {
window.requestAnimFrame(loop);
c.clearRect(0, 0, w, h);
draw();
}
//window resize
window.addEventListener("resize", function () {
(w = canvas.width = window.innerWidth),
(h = canvas.height = window.innerHeight);
loop();
});
//animation runner
loop();
setInterval(loop, 1000 / 60);
};
window.onload = spaceworm;
body,
html {
margin: 0px;
padding: 0px;
position: fixed;
background: rgb(30, 30, 30);
cursor: none;
}
<canvas id="canvas"></canvas>
I'm starting to work with some canvas animations and am having trouble understanding what's happening in a CodePen. Here is the animation in question: https://codepen.io/towc/pen/mJzOWJ
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
len: 20,
count: 50,
baseTime: 10,
addedTime: 10,
dieChance: .05,
spawnChance: 1,
sparkChance: .1,
sparkDist: 10,
sparkSize: 2,
color: 'hsl(hue,100%,light%)',
baseLight: 50,
addedLight: 10, // [50-10,50+10]
shadowToTimePropMult: 6,
baseLightInputMultiplier: .01,
addedLightInputMultiplier: .02,
cx: w / 2,
cy: h / 2,
repaintAlpha: .04,
hueChange: .1
},
tick = 0,
lines = [],
dieX = w / 2 / opts.len,
dieY = h / 2 / opts.len,
baseRad = Math.PI * 2 / 6;
ctx.fillStyle = 'black';
ctx.fillRect( 0, 0, w, h );
function loop() {
window.requestAnimationFrame( loop );
++tick;
ctx.globalCompositeOperation = 'source-over';
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,alp)'.replace( 'alp', opts.repaintAlpha );
ctx.fillRect( 0, 0, w, h );
ctx.globalCompositeOperation = 'lighter';
if( lines.length < opts.count && Math.random() < opts.spawnChance )
lines.push( new Line );
lines.map( function( line ){ line.step(); } );
}
function Line(){
this.reset();
}
Line.prototype.reset = function(){
this.x = 0;
this.y = 0;
this.addedX = 0;
this.addedY = 0;
this.rad = 0;
this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();
this.color = opts.color.replace( 'hue', tick * opts.hueChange );
this.cumulativeTime = 0;
this.beginPhase();
}
Line.prototype.beginPhase = function(){
this.x += this.addedX;
this.y += this.addedY;
this.time = 0;
this.targetTime = ( opts.baseTime + opts.addedTime * Math.random() ) |0;
this.rad += baseRad * ( Math.random() < .5 ? 1 : -1 );
this.addedX = Math.cos( this.rad );
this.addedY = Math.sin( this.rad );
if( Math.random() < opts.dieChance || this.x > dieX || this.x < -dieX || this.y > dieY || this.y < -dieY )
this.reset();
}
Line.prototype.step = function(){
++this.time;
++this.cumulativeTime;
if( this.time >= this.targetTime )
this.beginPhase();
var prop = this.time / this.targetTime,
wave = Math.sin( prop * Math.PI / 2 ),
x = this.addedX * wave,
y = this.addedY * wave;
ctx.shadowBlur = prop * opts.shadowToTimePropMult;
ctx.fillStyle = ctx.shadowColor = this.color.replace( 'light', opts.baseLight + opts.addedLight * Math.sin( this.cumulativeTime * this.lightInputMultiplier ) );
ctx.fillRect( opts.cx + ( this.x + x ) * opts.len, opts.cy + ( this.y + y ) * opts.len, 2, 2 );
if( Math.random() < opts.sparkChance )
ctx.fillRect( opts.cx + ( this.x + x ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.cy + ( this.y + y ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.sparkSize, opts.sparkSize )
}
loop();
window.addEventListener( 'resize', function(){
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
ctx.fillStyle = 'black';
ctx.fillRect( 0, 0, w, h );
opts.cx = w / 2;
opts.cy = h / 2;
dieX = w / 2 / opts.len;
dieY = h / 2 / opts.len;
});
canvas {
position: absolute;
top: 0;
left: 0;
}
<canvas id=c></canvas>
If you let the animation run for a while so the "sparks" spread out they leave behind a faint gray-ish trail. What is causing this trail and is it possible to prevent it?
Thank you!
i'm trying to use this Fireworks javascript. But when i write some text in the middle of the HTML page, the fireworks will not go over it and is limited by the text position...how can i override this and keep the fireworks go up to the top of the page ?
i tryed to fix the SCREEN_WIDTH and SCREEN_HEIGHT position but it doesn't work...
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight,
mousePos = {
x: 400,
y: 300
},
// create canvas
canvas = document.createElement('canvas'),
context = canvas.getContext('2d'),
particles = [],
rockets = [],
MAX_PARTICLES = 400,
colorCode = 0;
// init
$(document).ready(function() {
document.body.appendChild(canvas);
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
setInterval(launch, 800);
setInterval(loop, 1000 / 50);
});
// update mouse position
$(document).mousemove(function(e) {
e.preventDefault();
mousePos = {
x: e.clientX,
y: e.clientY
};
});
// launch more rockets!!!
$(document).mousedown(function(e) {
for (var i = 0; i < 5; i++) {
launchFrom(Math.random() * SCREEN_WIDTH * 2 / 3 + SCREEN_WIDTH / 6);
}
});
function launch() {
launchFrom(mousePos.x);
}
function launchFrom(x) {
if (rockets.length < 10) {
var rocket = new Rocket(x);
rocket.explosionColor = Math.floor(Math.random() * 360 / 10) * 10;
rocket.vel.y = Math.random() * -3 - 4;
rocket.vel.x = Math.random() * 6 - 3;
rocket.size = 8;
rocket.shrink = 0.999;
rocket.gravity = 0.01;
rockets.push(rocket);
}
}
function loop() {
// update screen size
if (SCREEN_WIDTH != window.innerWidth) {
canvas.width = SCREEN_WIDTH = window.innerWidth;
}
if (SCREEN_HEIGHT != window.innerHeight) {
canvas.height = SCREEN_HEIGHT = window.innerHeight;
}
// clear canvas
context.fillStyle = "rgba(0, 0, 0, 0.05)";
context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
var existingRockets = [];
for (var i = 0; i < rockets.length; i++) {
// update and render
rockets[i].update();
rockets[i].render(context);
// calculate distance with Pythagoras
var distance = Math.sqrt(Math.pow(mousePos.x - rockets[i].pos.x, 2) + Math.pow(mousePos.y - rockets[i].pos.y, 2));
// random chance of 1% if rockets is above the middle
var randomChance = rockets[i].pos.y < (SCREEN_HEIGHT * 2 / 3) ? (Math.random() * 100 <= 1) : false;
/* Explosion rules
- 80% of screen
- going down
- close to the mouse
- 1% chance of random explosion
*/
if (rockets[i].pos.y < SCREEN_HEIGHT / 5 || rockets[i].vel.y >= 0 || distance < 50 || randomChance) {
rockets[i].explode();
} else {
existingRockets.push(rockets[i]);
}
}
rockets = existingRockets;
var existingParticles = [];
for (var i = 0; i < particles.length; i++) {
particles[i].update();
// render and save particles that can be rendered
if (particles[i].exists()) {
particles[i].render(context);
existingParticles.push(particles[i]);
}
}
// update array with existing particles - old particles should be garbage collected
particles = existingParticles;
while (particles.length > MAX_PARTICLES) {
particles.shift();
}
}
function Particle(pos) {
this.pos = {
x: pos ? pos.x : 0,
y: pos ? pos.y : 0
};
this.vel = {
x: 0,
y: 0
};
this.shrink = .97;
this.size = 2;
this.resistance = 1;
this.gravity = 0;
this.flick = false;
this.alpha = 1;
this.fade = 0;
this.color = 0;
}
Particle.prototype.update = function() {
// apply resistance
this.vel.x *= this.resistance;
this.vel.y *= this.resistance;
// gravity down
this.vel.y += this.gravity;
// update position based on speed
this.pos.x += this.vel.x;
this.pos.y += this.vel.y;
// shrink
this.size *= this.shrink;
// fade out
this.alpha -= this.fade;
};
Particle.prototype.render = function(c) {
if (!this.exists()) {
return;
}
c.save();
c.globalCompositeOperation = 'lighter';
var x = this.pos.x,
y = this.pos.y,
r = this.size / 2;
var gradient = c.createRadialGradient(x, y, 0.1, x, y, r);
gradient.addColorStop(0.1, "rgba(255,255,255," + this.alpha + ")");
gradient.addColorStop(0.8, "hsla(" + this.color + ", 100%, 50%, " + this.alpha + ")");
gradient.addColorStop(1, "hsla(" + this.color + ", 100%, 50%, 0.1)");
c.fillStyle = gradient;
c.beginPath();
c.arc(this.pos.x, this.pos.y, this.flick ? Math.random() * this.size : this.size, 0, Math.PI * 2, true);
c.closePath();
c.fill();
c.restore();
};
Particle.prototype.exists = function() {
return this.alpha >= 0.1 && this.size >= 1;
};
function Rocket(x) {
Particle.apply(this, [{
x: x,
y: SCREEN_HEIGHT}]);
this.explosionColor = 0;
}
Rocket.prototype = new Particle();
Rocket.prototype.constructor = Rocket;
Rocket.prototype.explode = function() {
var count = Math.random() * 10 + 80;
for (var i = 0; i < count; i++) {
var particle = new Particle(this.pos);
var angle = Math.random() * Math.PI * 2;
// emulate 3D effect by using cosine and put more particles in the middle
var speed = Math.cos(Math.random() * Math.PI / 2) * 15;
particle.vel.x = Math.cos(angle) * speed;
particle.vel.y = Math.sin(angle) * speed;
particle.size = 10;
particle.gravity = 0.2;
particle.resistance = 0.92;
particle.shrink = Math.random() * 0.05 + 0.93;
particle.flick = true;
particle.color = this.explosionColor;
particles.push(particle);
}
};
Rocket.prototype.render = function(c) {
if (!this.exists()) {
return;
}
c.save();
c.globalCompositeOperation = 'lighter';
var x = this.pos.x,
y = this.pos.y,
r = this.size / 2;
var gradient = c.createRadialGradient(x, y, 0.1, x, y, r);
gradient.addColorStop(0.1, "rgba(255, 255, 255 ," + this.alpha + ")");
gradient.addColorStop(1, "rgba(0, 0, 0, " + this.alpha + ")");
c.fillStyle = gradient;
c.beginPath();
c.arc(this.pos.x, this.pos.y, this.flick ? Math.random() * this.size / 2 + this.size / 2 : this.size, 0, Math.PI * 2, true);
c.closePath();
c.fill();
c.restore();
};
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Fireworks!</title>
</head>
<body/>
</html>
The problem is the canvas used by the script is positioned relative by default. To make it always visible completely on screen we have to make it fixed and set the top and left CSS values to 0.
Now because its fixed the canvas renders on top of everything. To get it in the background set z-index to -1.
All additions together:
canvas.style.position="fixed";
canvas.style.top="0";
canvas.style.left="0";
canvas.style.zIndex="-1";
Complete Source:
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight,
mousePos = {
x: 400,
y: 300
},
// create canvas
canvas = document.createElement('canvas'),
context = canvas.getContext('2d'),
particles = [],
rockets = [],
MAX_PARTICLES = 400,
colorCode = 0;
// init
$(document).ready(function() {
document.body.appendChild(canvas);
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
canvas.style.position = "fixed";
canvas.style.top = "0";
canvas.style.left = "0";
canvas.style.zIndex = "-1";
setInterval(launch, 800);
setInterval(loop, 1000 / 50);
});
// update mouse position
$(document).mousemove(function(e) {
e.preventDefault();
mousePos = {
x: e.clientX,
y: e.clientY
};
});
// launch more rockets!!!
$(document).mousedown(function(e) {
for (var i = 0; i < 5; i++) {
launchFrom(Math.random() * SCREEN_WIDTH * 2 / 3 + SCREEN_WIDTH / 6);
}
});
function launch() {
launchFrom(mousePos.x);
}
function launchFrom(x) {
if (rockets.length < 10) {
var rocket = new Rocket(x);
rocket.explosionColor = Math.floor(Math.random() * 360 / 10) * 10;
rocket.vel.y = Math.random() * -3 - 4;
rocket.vel.x = Math.random() * 6 - 3;
rocket.size = 8;
rocket.shrink = 0.999;
rocket.gravity = 0.01;
rockets.push(rocket);
}
}
function loop() {
// update screen size
if (SCREEN_WIDTH != window.innerWidth) {
canvas.width = SCREEN_WIDTH = window.innerWidth;
}
if (SCREEN_HEIGHT != window.innerHeight) {
canvas.height = SCREEN_HEIGHT = window.innerHeight;
}
// clear canvas
context.fillStyle = "rgba(0, 0, 0, 0.05)";
context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
var existingRockets = [];
for (var i = 0; i < rockets.length; i++) {
// update and render
rockets[i].update();
rockets[i].render(context);
// calculate distance with Pythagoras
var distance = Math.sqrt(Math.pow(mousePos.x - rockets[i].pos.x, 2) + Math.pow(mousePos.y - rockets[i].pos.y, 2));
// random chance of 1% if rockets is above the middle
var randomChance = rockets[i].pos.y < (SCREEN_HEIGHT * 2 / 3) ? (Math.random() * 100 <= 1) : false;
/* Explosion rules
- 80% of screen
- going down
- close to the mouse
- 1% chance of random explosion
*/
if (rockets[i].pos.y < SCREEN_HEIGHT / 5 || rockets[i].vel.y >= 0 || distance < 50 || randomChance) {
rockets[i].explode();
} else {
existingRockets.push(rockets[i]);
}
}
rockets = existingRockets;
var existingParticles = [];
for (var i = 0; i < particles.length; i++) {
particles[i].update();
// render and save particles that can be rendered
if (particles[i].exists()) {
particles[i].render(context);
existingParticles.push(particles[i]);
}
}
// update array with existing particles - old particles should be garbage collected
particles = existingParticles;
while (particles.length > MAX_PARTICLES) {
particles.shift();
}
}
function Particle(pos) {
this.pos = {
x: pos ? pos.x : 0,
y: pos ? pos.y : 0
};
this.vel = {
x: 0,
y: 0
};
this.shrink = .97;
this.size = 2;
this.resistance = 1;
this.gravity = 0;
this.flick = false;
this.alpha = 1;
this.fade = 0;
this.color = 0;
}
Particle.prototype.update = function() {
// apply resistance
this.vel.x *= this.resistance;
this.vel.y *= this.resistance;
// gravity down
this.vel.y += this.gravity;
// update position based on speed
this.pos.x += this.vel.x;
this.pos.y += this.vel.y;
// shrink
this.size *= this.shrink;
// fade out
this.alpha -= this.fade;
};
Particle.prototype.render = function(c) {
if (!this.exists()) {
return;
}
c.save();
c.globalCompositeOperation = 'lighter';
var x = this.pos.x,
y = this.pos.y,
r = this.size / 2;
var gradient = c.createRadialGradient(x, y, 0.1, x, y, r);
gradient.addColorStop(0.1, "rgba(255,255,255," + this.alpha + ")");
gradient.addColorStop(0.8, "hsla(" + this.color + ", 100%, 50%, " + this.alpha + ")");
gradient.addColorStop(1, "hsla(" + this.color + ", 100%, 50%, 0.1)");
c.fillStyle = gradient;
c.beginPath();
c.arc(this.pos.x, this.pos.y, this.flick ? Math.random() * this.size : this.size, 0, Math.PI * 2, true);
c.closePath();
c.fill();
c.restore();
};
Particle.prototype.exists = function() {
return this.alpha >= 0.1 && this.size >= 1;
};
function Rocket(x) {
Particle.apply(this, [{
x: x,
y: SCREEN_HEIGHT
}]);
this.explosionColor = 0;
}
Rocket.prototype = new Particle();
Rocket.prototype.constructor = Rocket;
Rocket.prototype.explode = function() {
var count = Math.random() * 10 + 80;
for (var i = 0; i < count; i++) {
var particle = new Particle(this.pos);
var angle = Math.random() * Math.PI * 2;
// emulate 3D effect by using cosine and put more particles in the middle
var speed = Math.cos(Math.random() * Math.PI / 2) * 15;
particle.vel.x = Math.cos(angle) * speed;
particle.vel.y = Math.sin(angle) * speed;
particle.size = 10;
particle.gravity = 0.2;
particle.resistance = 0.92;
particle.shrink = Math.random() * 0.05 + 0.93;
particle.flick = true;
particle.color = this.explosionColor;
particles.push(particle);
}
};
Rocket.prototype.render = function(c) {
if (!this.exists()) {
return;
}
c.save();
c.globalCompositeOperation = 'lighter';
var x = this.pos.x,
y = this.pos.y,
r = this.size / 2;
var gradient = c.createRadialGradient(x, y, 0.1, x, y, r);
gradient.addColorStop(0.1, "rgba(255, 255, 255 ," + this.alpha + ")");
gradient.addColorStop(1, "rgba(0, 0, 0, " + this.alpha + ")");
c.fillStyle = gradient;
c.beginPath();
c.arc(this.pos.x, this.pos.y, this.flick ? Math.random() * this.size / 2 + this.size / 2 : this.size, 0, Math.PI * 2, true);
c.closePath();
c.fill();
c.restore();
};
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Fireworks!</title>
</head>
<body>
<p>
test
</p>
<br />
<p>
test2
</p>
</body>
</html>
I have the following canvas. I want it so that when the user clicks the canvas, I will go to google.com, and I want to keep the button element. This is my code:
//set the variables
var a = document.getElementById('canvas'),
c = a.getContext('2d'),
a.style.width = '200px';
a.style.height = '50px';
area = w * h,
particleNum = 300,
ANIMATION;
var particles = [];
//create the particles
function Particle(i) {
this.id = i;
this.hue = rand(50, 0, 1);
this.active = false;
}
Particle.prototype.build = function() {
this.x = w / 2;
this.y = h / 2;
this.r = rand(7, 2, 1);
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = .01;
this.opacity = Math.random() + .5;
this.active = true;
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
};
Particle.prototype.draw = function() {
this.active = true;
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.hue -= 0.5;
this.r = Math.abs(this.r - .05);
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
// reset particle
if(this.r <= .05) {
this.active = false;
}
};
//functionality
function drawScene() {
c.fillStyle = "black";
c.fillRect(0,0,w,h);
for(var i = 0; i < particles.length; i++) {
if(particles[i].active === true) {
particles[i].draw();
} else {
particles[i].build();
}
}
ANIMATION = requestAnimationFrame(drawScene);
}
function initCanvas() {
var s = getComputedStyle(a);
if(particles.length) {
particles = [];
cancelAnimationFrame(ANIMATION);
ANIMATION;
console.log(ANIMATION);
}
w = a.width = window.innerWidth;
h = a.height = window.innerHeight;
for(var i = 0; i < particleNum; i++) {
particles.push(new Particle(i));
}
drawScene();
console.log(ANIMATION);
}
//init
(function() {
initCanvas();
addEventListener('resize', initCanvas, false);
})();
//helper functions
function rand(max, min, _int) {
var max = (max === 0 || max)?max:1,
min = min || 0,
gen = min + (max - min) * Math.random();
return (_int) ? Math.round(gen) : gen;
};
#canvas{
width: 200;
height: 50;
}
<div class="wrapper">
<a href="index.html">
<button align=center onclick="handleClick()">
<canvas width="200" height="50" id="canvas" align=center></canvas>
<span class="text">SUBMIT</span>
</button>
</a>
</div>
Although, I only see the button, and no the canvas. How can I fix this?
You got a lot of errors actually buddy (variable declaration is the biggest problem) but by following the errors will give you a way to fix it, I don't know if this is the fix you want.
//set the variables
var a = document.getElementById('canvas'),
c = a.getContext('2d');
a.style.width = '200px';
a.style.height = '50px';
var w, h;
var area = w * h,
particleNum = 300,
ANIMATION;
var particles = [];
//create the particles
function Particle(i) {
this.id = i;
this.hue = rand(50, 0, 1);
this.active = false;
}
Particle.prototype.build = function() {
this.x = w / 2;
this.y = h / 2;
this.r = rand(7, 2, 1);
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.01;
this.opacity = Math.random() + .5;
this.active = true;
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
};
Particle.prototype.draw = function() {
this.active = true;
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.hue -= 0.5;
this.r = Math.abs(this.r - 0.05);
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
// reset particle
if (this.r <= 0.05) {
this.active = false;
}
};
//functionality
function drawScene() {
c.fillStyle = "black";
c.fillRect(0, 0, w, h);
for (var i = 0; i < particles.length; i++) {
if (particles[i].active === true) {
particles[i].draw();
} else {
particles[i].build();
}
}
ANIMATION = requestAnimationFrame(drawScene);
}
function initCanvas() {
var s = getComputedStyle(a);
if (particles.length) {
particles = [];
cancelAnimationFrame(ANIMATION);
ANIMATION;
console.log(ANIMATION);
}
w = a.width = window.innerWidth;
h = a.height = window.innerHeight;
for (var i = 0; i < particleNum; i++) {
particles.push(new Particle(i));
}
drawScene();
console.log(ANIMATION);
}
//init
(function() {
initCanvas();
addEventListener('resize', initCanvas, false);
})();
//helper functions
function rand(max, min, _int) {
var max = (max === 0 || max) ? max : 1,
min = min || 0,
gen = min + (max - min) * Math.random();
return (_int) ? Math.round(gen) : gen;
};
#canvas {
width: 200px;
height: 50px;
}
<div class="wrapper">
<a href="index.html">
<button align=center onclick="handleClick()">
<canvas width="200" height="50" id="canvas" align=center> </canvas>
<span class="text">SUBMIT</span>
</button>
</a>
</div>
I'm trying to wrap my head around the globalCompositeOperation property by attempting to combine these two examples: JSFiddle and Codepen.
The former is using destination-outand the latter is using source-over. Would it be possible to use the fiery cursor in the Codepen, but also have it remove the portion of the overlay fill that the user clicks on, as in the Fiddle?
Any assistance would be most appreciated. I can combine the demos on Codepen to use the same methods if necessary.
Relevant Fiddle code:
function drawDot(mouseX,mouseY){
bridgeCanvas.beginPath();
bridgeCanvas.arc(mouseX, mouseY, brushRadius, 0, 2*Math.PI, true);
bridgeCanvas.fillStyle = '#000';
bridgeCanvas.globalCompositeOperation = "destination-out";
bridgeCanvas.fill();
}
Relevant Codepen code:
Fire.prototype.clearCanvas = function(){
this.ctx.globalCompositeOperation = "source-over";
this.ctx.fillStyle = "rgba( 15, 5, 2, 1 )";
this.ctx.fillRect( 0, 0, window.innerWidth, window.innerHeight );
this.ctx.globalCompositeOperation = "lighter";
this.ctx.rect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.fillStyle = this.pattern;
this.ctx.fill();/**/
}
As I said in comments, you'll have to divide your code in at least two parts.
The cropper function uses "destination-out" compositing operation to remove the already drawn pixels of the canvas where the new ones should be drawn. In your version, it uses a background-image, and once the foreground pixels are removed, you can see this background since in the now transparent areas of the canvas.
The flame one in the other hand, uses '"lighter"', "color-dodge" and "soft-light" blending operations. This will add the colors of both the already there and the new drawn pixels.
At least the first one, if used on a transparent area, will be the same as the default "source-over" composite operation. So you need to have the background image drawn onto the canvas to be able to use it in the blending.
For this, you've got to use a second, off-screen canvas, where you will only apply the eraser "destination-out" operation. Then, on the visible canvas, at each new eraser frame, you'll have to draw the background image on your visible canvas, then the eraser one, with the holes, and finally the blending one, which will mix all together.
Here is a quick code dump, where I rewrote a bit the eraser, and modified the Fire one, in order to make our main function handles both events and animation loop.
function MainDrawing(){
this.canvas = document.getElementById('main');
this.ctx = this.canvas.getContext('2d');
this.background = new Image();
this.background.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943.jpg"
this.eraser = new Eraser(this.canvas);
this.fire = new Fire(this.canvas);
this.attachEvents();
}
MainDrawing.prototype = {
anim: function(){
if(this.stopped)
return;
this.ctx.globalCompositeOperation = 'source-over';
this.ctx.drawImage(this.background, 0,0);
this.ctx.drawImage(this.eraser.canvas, 0,0);
this.fire.run();
requestAnimationFrame(this.anim.bind(this));
},
stop: function(){
this.stopped = true;
},
attachEvents: function(){
var mouseDown = false;
this.canvas.onmousedown = function(){
mouseDown = true;
};
this.canvas.onmouseup = function(){
mouseDown = false;
};
this.canvas.onmousemove = function(e){
if(mouseDown){
this.eraser.handleClick(e);
}
this.fire.updateMouse(e);
}.bind(this);
}
};
function Eraser(canvas){
this.main = canvas;
this.canvas = canvas.cloneNode();
var ctx = this.ctx = this.canvas.getContext('2d');
this.img = new Image();
this.img.onload = function(){
ctx.drawImage(this, 0, 0);
ctx.globalCompositeOperation = 'destination-out';
};
this.img.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-2013.jpg";
this.getRect();
}
Eraser.prototype = {
getRect: function(){
this.rect = this.main.getBoundingClientRect();
},
handleClick: function(evt){
var x = evt.clientX - this.rect.left;
var y = evt.clientY - this.rect.top;
this.draw(x,y);
},
draw: function(x, y){
this.ctx.beginPath();
this.ctx.arc(x, y, 30, 0, Math.PI*2);
this.ctx.fill();
}
};
var Fire = function(canvas){
this.canvas = canvas;
this.ctx = this.canvas.getContext('2d');
this.aFires = [];
this.aSpark = [];
this.aSpark2 = [];
this.mouse = {
x : this.canvas.width * .5,
y : this.canvas.height * .75,
}
}
Fire.prototype.run = function(){
this.update();
this.draw();
}
Fire.prototype.start = function(){
this.bRuning = true;
this.run();
}
Fire.prototype.stop = function(){
this.bRuning = false;
}
Fire.prototype.update = function(){
this.aFires.push( new Flame( this.mouse ) );
this.aSpark.push( new Spark( this.mouse ) );
this.aSpark2.push( new Spark( this.mouse ) );
for (var i = this.aFires.length - 1; i >= 0; i--) {
if( this.aFires[i].alive )
this.aFires[i].update();
else
this.aFires.splice( i, 1 );
}
for (var i = this.aSpark.length - 1; i >= 0; i--) {
if( this.aSpark[i].alive )
this.aSpark[i].update();
else
this.aSpark.splice( i, 1 );
}
for (var i = this.aSpark2.length - 1; i >= 0; i--) {
if( this.aSpark2[i].alive )
this.aSpark2[i].update();
else
this.aSpark2.splice( i, 1 );
}
}
Fire.prototype.draw = function(){
this.drawHalo();
this.ctx.globalCompositeOperation = "overlay";//or lighter or soft-light
for (var i = this.aFires.length - 1; i >= 0; i--) {
this.aFires[i].draw( this.ctx );
}
this.ctx.globalCompositeOperation = "soft-light";//"soft-light";//"color-dodge";
for (var i = this.aSpark.length - 1; i >= 0; i--) {
if( ( i % 2 ) === 0 )
this.aSpark[i].draw( this.ctx );
}
this.ctx.globalCompositeOperation = "color-dodge";//"soft-light";//"color-dodge";
for (var i = this.aSpark2.length - 1; i >= 0; i--) {
this.aSpark2[i].draw( this.ctx );
}
}
Fire.prototype.updateMouse = function( e ){
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
}
Fire.prototype.drawHalo = function(){
var r = rand( 300, 350 );
this.ctx.globalCompositeOperation = "lighter";
this.grd = this.ctx.createRadialGradient( this.mouse.x, this.mouse.y,r,this.mouse.x, this.mouse.y, 0 );
this.grd.addColorStop(0,"transparent");
this.grd.addColorStop(1,"rgb( 50, 2, 0 )");
this.ctx.beginPath();
this.ctx.arc( this.mouse.x, this.mouse.y - 100, r, 0, 2*Math.PI );
this.ctx.fillStyle= this.grd;
this.ctx.fill();
}
var Flame = function( mouse ){
this.cx = mouse.x;
this.cy = mouse.y;
this.x = rand( this.cx - 25, this.cx + 25);
this.y = rand( this.cy - 5, this.cy + 5);
this.lx = this.x;
this.ly = this.y;
this.vy = rand( 1, 3 );
this.vx = rand( -1, 1 );
this.r = rand( 30, 40 );
this.life = rand( 2, 7 );
this.alive = true;
this.c = {
h : Math.floor( rand( 2, 40) ),
s : 100,
l : rand( 80, 100 ),
a : 0,
ta : rand( 0.8, 0.9 )
}
}
Flame.prototype.update = function()
{
this.lx = this.x;
this.ly = this.y;
this.y -= this.vy;
this.vy += 0.08;
this.x += this.vx;
if( this.x < this.cx )
this.vx += 0.2;
else
this.vx -= 0.2;
if( this.r > 0 )
this.r -= 0.3;
if( this.r <= 0 )
this.r = 0;
this.life -= 0.12;
if( this.life <= 0 ){
this.c.a -= 0.05;
if( this.c.a <= 0 )
this.alive = false;
}else if( this.life > 0 && this.c.a < this.c.ta ){
this.c.a += .08;
}
}
Flame.prototype.draw = function( ctx ){
this.grd1 = ctx.createRadialGradient( this.x, this.y, this.r*3, this.x, this.y, 0 );
this.grd1.addColorStop( 0.5, "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a/20) + ")" );
this.grd1.addColorStop( 0, "transparent" );
this.grd2 = ctx.createRadialGradient( this.x, this.y, this.r, this.x, this.y, 0 );
this.grd2.addColorStop( 0.5, "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")" );
this.grd2.addColorStop( 0, "transparent" );
ctx.beginPath();
ctx.arc( this.x, this.y, this.r * 3, 0, 2*Math.PI );
ctx.fillStyle = this.grd1;
//ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a/20) + ")";
ctx.fill();
ctx.globalCompositeOperation = "overlay";
ctx.beginPath();
ctx.arc( this.x, this.y, this.r, 0, 2*Math.PI );
ctx.fillStyle = this.grd2;
ctx.fill();
ctx.beginPath();
ctx.moveTo( this.lx , this.ly);
ctx.lineTo( this.x, this.y);
ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, 1)";
ctx.lineWidth = rand( 1, 2 );
ctx.stroke();
ctx.closePath();
}
var Spark = function( mouse ){
this.cx = mouse.x;
this.cy = mouse.y;
this.x = rand( this.cx -40, this.cx + 40);
this.y = rand( this.cy, this.cy + 5);
this.lx = this.x;
this.ly = this.y;
this.vy = rand( 1, 3 );
this.vx = rand( -4, 4 );
this.r = rand( 0, 1 );
this.life = rand( 4, 8 );
this.alive = true;
this.c = {
h : Math.floor( rand( 2, 40) ),
s : 100,
l : rand( 40, 100 ),
a : rand( 0.8, 0.9 )
}
}
Spark.prototype.update = function()
{
this.lx = this.x;
this.ly = this.y;
this.y -= this.vy;
this.x += this.vx;
if( this.x < this.cx )
this.vx += 0.2;
else
this.vx -= 0.2;
this.vy += 0.08;
this.life -= 0.1;
if( this.life <= 0 ){
this.c.a -= 0.05;
if( this.c.a <= 0 )
this.alive = false;
}
}
Spark.prototype.draw = function( ctx ){
ctx.beginPath();
ctx.moveTo( this.lx , this.ly);
ctx.lineTo( this.x, this.y);
ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a / 2) + ")";
ctx.lineWidth = this.r * 2;
ctx.lineCap = 'round';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo( this.lx , this.ly);
ctx.lineTo( this.x, this.y);
ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
ctx.lineWidth = this.r;
ctx.stroke();
ctx.closePath();
}
rand = function( min, max ){ return Math.random() * ( max - min) + min; };
var app = new MainDrawing();
app.anim();
<canvas id="main" width="750" height="465"></canvas>