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>
Found code here for metaballs using vanilla javascript. Is there a way I can change the opacity of the metaballs? I think it should be a quick fix but im not too sure. I tried changing to CSS class bubbles but that didnt work so im assuming in needs to be in the Javascript. Anything helps, thanks.
Found code here for metaballs using vanilla javascript. Is there a way I can change the opacity of the metaballs? I think it should be a quick fix but im not too sure. I tried changing to CSS class bubbles but that didnt work so im assuming in needs to be in the Javascript. Anything helps, thanks.
;(function() {
"use strict";
var lava0;
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
}
}
}
// Point constructor
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
};
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
};
// Ball constructor
var Ball = function(parent) {
var min = .1;
var max = 1.5;
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25), (Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
);
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
);
this.size = (parent.wh / 15) + ( Math.random() * (max - min) + min ) * (parent.wh / 15);
this.width = parent.width;
this.height = parent.height;
};
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x;
this.pos.x = this.width - this.size;
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x;
this.pos.x = this.size;
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y;
this.pos.y = this.height - this.size;
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y;
this.pos.y = this.size;
}
// velocity
this.pos = this.pos.add(this.vel);
};
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = createRadialGradient(width, height, width, c0, c1);
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this);
}
};
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign;
} else {
force = 0;
var cell = this.grid[id];
var i = 0;
var ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
};
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if (this.grid[id].computed === this.iter) {
return false;
}
var dir, mscase = 0;
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// inside
return [x, y - 1, false];
} else {
// ambiguous cases
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// lookup
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// draw line
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir]) + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// next
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
};
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move();
// reset grid
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = this.metaFill;
ctx.beginPath();
// compute metaballs
i = 0;
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while (ball = this.balls[i++]) {
// first cell
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// marching squares
do {
next = this.marchingSquares(next);
} while (next);
// fill and close path
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
};
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(
w / 1, h / 1, 0,
w / 1, h / 1, r
);
gradient.addColorStop(0, c0);
gradient.addColorStop(1, c1);
};
// main loop
var run = function() {
requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava0.renderMetaballs();
};
// canvas
var screen = ge1doot.screen.init("bubble", null, true),
ctx = screen.ctx;
screen.resize();
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, "#FF9298", "#E4008E");
run();
})();
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>
You can do it by changing the context alpha channel with RGBA (see at the very bottom ctx.fillStyle = 'rgba(0, 0, 255, 0.5)' // NEW! where 0.5 is the level of opacity - see ) :
;
(function() {
'use strict'
var lava0
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function(id, callback, initRes) {
this.elem = document.getElementById(id)
this.callback = callback || null
if (this.elem.tagName == 'CANVAS') this.ctx = this.elem.getContext('2d')
window.addEventListener(
'resize',
function() {
this.resize()
}.bind(this),
false
)
this.elem.onselectstart = function() {
return false
}
this.elem.ondrag = function() {
return false
}
initRes && this.resize()
return this
},
resize: function() {
var o = this.elem
this.width = o.offsetWidth
this.height = o.offsetHeight
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft
this.top += o.offsetTop
}
if (this.ctx) {
this.elem.width = this.width
this.elem.height = this.height
}
this.callback && this.callback()
},
},
}
// Point constructor
var Point = function(x, y) {
this.x = x
this.y = y
this.magnitude = x * x + y * y
this.computed = 0
this.force = 0
}
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y)
}
// Ball constructor
var Ball = function(parent) {
var min = 0.1
var max = 1.5
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25),
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
)
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
)
this.size = parent.wh / 15 + (Math.random() * (max - min) + min) * (parent.wh / 15)
this.width = parent.width
this.height = parent.height
}
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x
this.pos.x = this.width - this.size
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x
this.pos.x = this.size
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y
this.pos.y = this.height - this.size
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y
this.pos.y = this.size
}
// velocity
this.pos = this.pos.add(this.vel)
}
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5
this.width = width
this.height = height
this.wh = Math.min(width, height)
this.sx = Math.floor(this.width / this.step)
this.sy = Math.floor(this.height / this.step)
this.paint = false
this.metaFill = createRadialGradient(width, height, width, c0, c1)
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1]
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0]
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1]
this.grid = []
this.balls = []
this.iter = 0
this.sign = 1
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point((i % (this.sx + 2)) * this.step, Math.floor(i / (this.sx + 2)) * this.step)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this)
}
}
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force
var id = idx || x + y * (this.sx + 2)
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign
} else {
force = 0
var cell = this.grid[id]
var i = 0
var ball
while ((ball = this.balls[i++])) {
force +=
(ball.size * ball.size) /
(-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude)
}
force *= this.sign
}
this.grid[id].force = force
return force
}
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0]
var y = next[1]
var pdir = next[2]
var id = x + y * (this.sx + 2)
if (this.grid[id].computed === this.iter) {
return false
}
var dir,
mscase = 0
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = x + this.ix[i + 12] + (y + this.ix[i + 16]) * (this.sx + 2)
var force = this.grid[idn].force
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(x + this.ix[i + 12], y + this.ix[i + 16], idn)
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i)
}
if (mscase === 15) {
// inside
return [x, y - 1, false]
} else {
// ambiguous cases
if (mscase === 5) dir = pdir === 2 ? 3 : 1
else if (mscase === 10) dir = pdir === 3 ? 0 : 2
else {
// lookup
dir = this.mscases[mscase]
this.grid[id].computed = this.iter
}
// draw line
var ix =
this.step /
(Math.abs(
Math.abs(this.grid[x + this.plx[4 * dir + 2] + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1
) /
Math.abs(
Math.abs(this.grid[x + this.plx[4 * dir + 3] + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1
) +
1)
ctx.lineTo(
this.grid[x + this.plx[4 * dir] + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[x + this.plx[4 * dir + 1] + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
)
this.paint = true
// next
return [x + this.ix[dir + 4], y + this.ix[dir + 8], dir]
}
}
LavaLamp.prototype.renderMetaballs = function() {
var i = 0,
ball
while ((ball = this.balls[i++])) ball.move()
// reset grid
this.iter++
this.sign = -this.sign
this.paint = false
ctx.fillStyle = this.metaFill
ctx.beginPath()
// compute metaballs
i = 0
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while ((ball = this.balls[i++])) {
// first cell
var next = [Math.round(ball.pos.x / this.step), Math.round(ball.pos.y / this.step), false]
// marching squares
do {
next = this.marchingSquares(next)
} while (next)
// fill and close path
if (this.paint) {
ctx.fill()
ctx.closePath()
ctx.beginPath()
this.paint = false
}
}
}
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(w / 1, h / 1, 0, w / 1, h / 1, r)
gradient.addColorStop(0, c0)
gradient.addColorStop(1, c1)
}
// main loop
var run = function() {
requestAnimationFrame(run)
ctx.clearRect(0, 0, screen.width, screen.height)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)' // NEW!
lava0.renderMetaballs()
}
// canvas
var screen = ge1doot.screen.init('bubble', null, true),
ctx = screen.ctx
screen.resize()
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, '#FF9298', '#E4008E')
run()
})()
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>
Your Lava constructor takes two colors, these can be modified to fit your color needs. By using rgba() versions of your colors, you can set the alpha (ie the opacity) or your bubbles/meatballs. However, before you do that, you need to return the gradient created in createRadialGradient so that the colors can be used:
var createRadialGradient = function(w, h, r, c0, c1) {
// ... code ...
return gradient; // add this line
};
Now you can modify how you call your constructor:
// rgba versions of your colors -----------------------\/
lava0 = new LavaLamp(screen.width, screen.height, 6, "rgba(255, 146, 152, 0.5)", "rgba(228, 0, 142, 0.5)");
;(function() {
"use strict";
var lava0;
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
}
}
}
// Point constructor
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
};
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
};
// Ball constructor
var Ball = function(parent) {
var min = .1;
var max = 1.5;
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25), (Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
);
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
);
this.size = (parent.wh / 15) + ( Math.random() * (max - min) + min ) * (parent.wh / 15);
this.width = parent.width;
this.height = parent.height;
};
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x;
this.pos.x = this.width - this.size;
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x;
this.pos.x = this.size;
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y;
this.pos.y = this.height - this.size;
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y;
this.pos.y = this.size;
}
// velocity
this.pos = this.pos.add(this.vel);
};
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = createRadialGradient(width, height, width, c0, c1);
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this);
}
};
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign;
} else {
force = 0;
var cell = this.grid[id];
var i = 0;
var ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
};
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if (this.grid[id].computed === this.iter) {
return false;
}
var dir, mscase = 0;
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// inside
return [x, y - 1, false];
} else {
// ambiguous cases
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// lookup
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// draw line
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir]) + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// next
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
};
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move();
// reset grid
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = this.metaFill;
ctx.beginPath();
// compute metaballs
i = 0;
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while (ball = this.balls[i++]) {
// first cell
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// marching squares
do {
next = this.marchingSquares(next);
} while (next);
// fill and close path
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
};
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(
w / 1, h / 1, 0,
w / 1, h / 1, r
);
gradient.addColorStop(0, c0);
gradient.addColorStop(1, c1);
return gradient;
};
// main loop
var run = function() {
requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava0.renderMetaballs();
};
// canvas
var screen = ge1doot.screen.init("bubble", null, true),
ctx = screen.ctx;
screen.resize();
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, "rgba(255, 146, 152, 0.5)", "rgba(228, 0, 142, 0.5)");
run();
})();
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>
I have a top to bottom falling canvas animation, but I want to reverse it (go from bottom to top). I can't figure out how to change the direction
I have my code here
http://js.do/code/176399
sample:
function Ember(x, y, s /*radius*/ , p /*num points*/ ) {
this.x = x;
this.y = y;
this.s = s;
this.p = p;
this.img = document.createElement('canvas');
var context = this.img.getContext('2d'),
len = this.s / 1.45;
this.img.height = this.img.width = this.s * 2;
context.translate(this.s, this.s);
context.rotate((Math.PI * 1 / 10));
context.beginPath();
for (var i = 0; i < p; i++) {
context.lineTo(0, -s);
context.rotate((Math.PI * 2 / (p * 2)));
context.lineTo(0, s);
context.rotate((Math.PI * 2 / (p * 2)));
}
context.closePath();
context.shadowBlur = this.s / 3;
context.shadowColor = 'rgba(174, 12, 1, 0.9)';
context.fillStyle = 'rgba(133,80,33,.45)';
context.fill();
}
Just need to reverse the "fall" to bottom to top.
Update:
following off of Jared's suggestion
Changed:
embers[i].y += embers[i].vy;
to:
embers[i].y -= embers[i].vy;
However, I only get one animation cycle would like to have it continually animate new embers on the screen
Take a look at this line where you update the ember's Y position:
embers[i].y = -embers[i].s;
Try changing this to something like this:
embers[i].y = embers[i].s;
<canvas id="canvas"></canvas>
<script>
function Ember(x, y, s /*radius*/ , p /*num points*/ ) {
this.x = x;
this.y = y;
this.s = s;
this.p = p;
this.img = document.createElement('canvas');
var context = this.img.getContext('2d'),
len = this.s / 1.45;
this.img.height = this.img.width = this.s * 2;
context.translate(this.s, this.s);
context.rotate((Math.PI * 1 / 10));
context.beginPath();
for (var i = 0; i < p; i++) {
context.lineTo(0, -s);
context.rotate((Math.PI * 2 / (p * 2)));
context.lineTo(0, s);
context.rotate((Math.PI * 2 / (p * 2)));
}
context.closePath();
context.shadowBlur = this.s / 3;
context.shadowColor = 'rgba(174, 12, 1, 0.9)';
context.fillStyle = 'rgba(133,80,33,.45)';
context.fill();
}
window.requestAnimationFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas, context, height, width, embers;
setTimeout(init, 10);
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
height = canvas.height = document.body.offsetHeight;
width = canvas.width = document.body.offsetWidth;
embers = [];
for (var i = 0; i < 150; i++) {
var x = Math.random() * width,
y = Math.random() * height,
s = Math.random() * 5 + 5,
p = Math.random() * 8 + 8;
var s = new Ember(x, y, s, p);
s.vx = Math.random() * 2 - 1;
s.vy = Math.random() * 2 + 1;
s.r = Math.random() * 360;
embers.push(s);
}
update();
render();
}
function update() {
for (var i = 0, l = embers.length; i < l; i++) {
embers[i].r += embers[i].vx / 10;
embers[i].x += embers[i].vx;
embers[i].y -= embers[i].vy;
if (embers[i].y < 0) {
embers[i].y = Math.random()*height;
embers[i].vx = Math.random() * 2 - 1;
embers[i].vy = Math.random() * 2 + 1;
}
}
setTimeout(update, 1000 / 30);
}
function render() {
context.clearRect(0, 0, width, height);
for (var i = 0, l = embers.length; i < l; i++) {
context.save();
context.translate(embers[i].x, embers[i].y);
context.rotate(embers[i].r);
context.drawImage(embers[i].img, 0, 0);
context.restore();
}
requestAnimationFrame(render);
}
</script>
Wrong if condition in update function, change it to check if v(embers[i].y < 0), ans set appropriate new y position
if (embers[i].y < 0) {
embers[i].y = Math.random()*height;
I have a simple html page like this:
<html>
<head>
<title></title>
<link rel="icon" type="image/vnd.microsoft.icon" href="images/icon.png" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body bgcolor="ffffff"><br>
<img src="images/1.png" style="position:relative; left:4%; width:85%"></img>
<meta http-equiv="refresh" content="7; home.html" />
</body>
</html>
that displays an image and after 7 seconds redirects to the home page. I found a cool confetti code online that uses canvas and I would like to add it to this page in the foreground, but always being able to see the image or text I could add to the page in the future, but I can't find a way to do so. the confetti code is this:
(function() {
var COLORS, Confetti, NUM_CONFETTI, PI_2, canvas, confetti, context, drawCircle, i, range, resizeWindow, xpos;
NUM_CONFETTI = 350;
COLORS = [[85, 71, 106], [174, 61, 99], [219, 56, 83], [244, 92, 68], [248, 182, 70]];
PI_2 = 2 * Math.PI;
canvas = document.getElementById("world");
context = canvas.getContext("2d");
window.w = 0;
window.h = 0;
resizeWindow = function() {
window.w = canvas.width = window.innerWidth;
return window.h = canvas.height = window.innerHeight;
};
window.addEventListener('resize', resizeWindow, false);
window.onload = function() {
return setTimeout(resizeWindow, 0);
};
range = function(a, b) {
return (b - a) * Math.random() + a;
};
drawCircle = function(x, y, r, style) {
context.beginPath();
context.arc(x, y, r, 0, PI_2, false);
context.fillStyle = style;
return context.fill();
};
xpos = 0.5;
document.onmousemove = function(e) {
return xpos = e.pageX / w;
};
window.requestAnimationFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
})();
Confetti = (function() {
function Confetti() {
this.style = COLORS[~~range(0, 5)];
this.rgb = "rgba(" + this.style[0] + "," + this.style[1] + "," + this.style[2];
this.r = ~~range(2, 6);
this.r2 = 2 * this.r;
this.replace();
}
Confetti.prototype.replace = function() {
this.opacity = 0;
this.dop = 0.03 * range(1, 4);
this.x = range(-this.r2, w - this.r2);
this.y = range(-20, h - this.r2);
this.xmax = w - this.r;
this.ymax = h - this.r;
this.vx = range(0, 2) + 8 * xpos - 5;
return this.vy = 0.7 * this.r + range(-1, 1);
};
Confetti.prototype.draw = function() {
var _ref;
this.x += this.vx;
this.y += this.vy;
this.opacity += this.dop;
if (this.opacity > 1) {
this.opacity = 1;
this.dop *= -1;
}
if (this.opacity < 0 || this.y > this.ymax) {
this.replace();
}
if (!((0 < (_ref = this.x) && _ref < this.xmax))) {
this.x = (this.x + this.xmax) % this.xmax;
}
return drawCircle(~~this.x, ~~this.y, this.r, "" + this.rgb + "," + this.opacity + ")");
};
return Confetti;
})();
confetti = (function() {
var _i, _results;
_results = [];
for (i = _i = 1; 1 <= NUM_CONFETTI ? _i <= NUM_CONFETTI : _i >= NUM_CONFETTI; i = 1 <= NUM_CONFETTI ? ++_i : --_i) {
_results.push(new Confetti);
}
return _results;
})();
window.step = function() {
var c, _i, _len, _results;
requestAnimationFrame(step);
context.clearRect(0, 0, w, h);
_results = [];
for (_i = 0, _len = confetti.length; _i < _len; _i++) {
c = confetti[_i];
_results.push(c.draw());
}
return _results;
};
step();
}).call(this);
Any suggestion or idea on how to have the confetti animation in the foreground but keeping the page fully functional in the background?
Yes it is possible ...
DEMO
CSS
pointer-events: none
read more
like this
<canvas id="world" style="position:absolute;z-index:3;pointer-events:none;"></canvas>
just add this to your html and the confetti part to a .js(your customized js)