The goal is to have fireworks come up over top of an existing web page, so that you can see both the existing page, and the fireworks exploding over top of it. I successfully got them over top of the page, however, now they do not fade out. I'm left with white build up over top of web page.
I have this jsfiddle:
http://jsfiddle.net/2EQ2w/1/
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.insertBefore(canvas, document.body.firstChild);
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.001)";
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%, 0)");
gradient.addColorStop(1, "hsla(" + this.color + ", 100%, 50%, 0)");
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 ,255)");
gradient.addColorStop(0.1, "rgba(0, 0, 0, 0)");
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();
};
Which was built off this base:
http://jsfiddle.net/dtrooper/AceJJ/
Does anyone know how I can get these fireworks to fade out? Or get the particle to fade out after it hasn't moved for a few milliseconds?
You can definitely have this with fading trails:
http://jsfiddle.net/LgjG8/
Just set up a second off-screen canvas that has a reduced global alpha:
// create 2nd canvas
var canvas2 = document.createElement('canvas'),
context2 = canvas2.getContext('2d');
canvas2.width = canvas.width;
canvas2.height = canvas.height;
// reduce alpha of second canvas
context2.globalAlpha = 0.8;
Then instead of simply wiping the canvas clean each frame, copy the first on-screen canvas to the second. This will produce a faded copy of the visible canvas due to the lowered global alpha value. Then wipe the first canvas before copying the faded version back. Finally, just update the canvas as normal. This will produce a trail.
// produce faded copy of current canvas
context2.clearRect(0, 0, canvas2.width, canvas2.height);
context2.drawImage(canvas, 0, 0);
// redraw faded copy on original canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(canvas2, 0, 0);
I didn't really look through your code so you might need to play with this a little, but you get the idea.
The fireworks use fillRect() with a low opacity to clear (fade out) old fireworks. As a result, nothing behind the canvas will show.
However, you can use clearRect() instead so that the canvas does not have a solid background. The problem with this is that the fireworks don't leave nice trails because there is no low opacity fill to fade them out.
Not optimal, but at least the fireworks are in front of the other page content. I wish there was a clearStyle you could set to low opacity but, sadly, no.
// clear canvas
//context.fillStyle = "rgba(0, 0, 0, 0.05)";
//context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
context.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
WORKING EXAMPLE
Since you want to have the content visible, you can try to change the way the trails are generated and use the clearRect. Instead to have the trails done by the c.fill() you can make it to be done by particles, so you can view them.
In the Rocket.prototype.render you can do this:
//c.fill();
var particle = new Particle(this.pos);
particle.shrink = Math.random() * 0.05 + 0.93;
particle.size = 10;
particles.push(particle);
And the trails will be visible then.
Example
Before edited answer (not working as asker expected):
In the loop() function you have a really small alpha, making that the fireworks are not fading out.
Try to change:
context.fillStyle = "rgba(0, 0, 0, 0.001)";
to
context.fillStyle = "rgba(0, 0, 0, 0.05)";
Hope it helps!
Related
After adding the animation, the canvas gets pixelated. I've tried to fix this with adding context.clearRect(0, 0, canvas.width, canvas.height); but it hides the previous segments
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = x - 40;
var endPercent = 45;
var curPerc = 0,
mybeg;
var counterClockwise = false;
var circ = Math.PI * 2;
var quart = Math.PI / 2;
var col = ['#000', '#ff0000', '#002bff'];
function animate(current, colr, mybeg) {
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, mybeg, ((circ) * current));
context.fillStyle = colr;
context.fill();
//console.log(x, y, radius, mybeg, ((circ) * current));
curPerc++;
if (curPerc <= endPercent) {
mybeg = 0;
requestAnimationFrame(function() {
animate(curPerc / 100, col[0], mybeg)
});
} else if (curPerc > 44 && curPerc <= 65) {
const mybeg1 = ((circ) * 45 / 100);
requestAnimationFrame(function() {
animate(curPerc / 100, col[1], mybeg1)
});
} else if (curPerc > 64 && curPerc <= 100) {
const mybeg2 = ((circ) * 65 / 100);
requestAnimationFrame(function() {
animate(curPerc / 100, col[2], mybeg2)
});
}
}
animate();
<canvas id="myCanvas" height="300" width="300"></canvas>
You are redrawing the same arc over itself a lot of times.
To render a smooth arc, we need semi-transparent pixels (antialiasing), and drawing semi-transparent pixels over other semi-transparent pixels will make them more an more opaque.
So the solution here is to clear everything and redraw everything at every frame.
There are several ways to do it, but one of the simplest might be to render your complete pie every-time and only animate a mask over it, using compositing:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = x - 40;
var stops = [
//[ begin, end , color ]
[ 0, 45, '#000' ],
[ 45, 65, '#ff0000' ],
[ 65, 100, '#002bff' ]
];
var current = 0;
animate();
function drawFullPie() {
stops.forEach( function( stop , i) {
var begin = (stop[0] / 100 ) * Math.PI * 2;
var end = (stop[1] / 100 ) * Math.PI * 2;
context.beginPath();
context.moveTo( x, y );
context.arc( x, y, radius, begin, end );
context.fillStyle = stop[2];
context.fill();
} );
}
function drawMask() {
var begin = 0;
var end = (current / 100) * Math.PI * 2;
// Keep whatever is currently painted to the canvas
// only where our next drawings will appear
context.globalCompositeOperation = 'destination-in';
context.beginPath();
context.moveTo( x, y );
context.arc( x, y, radius, begin, end );
context.fill();
// disable masking
context.globalCompositeOperation = 'source-over';
}
function animate() {
// clear at every frame
context.clearRect( 0, 0, canvas.width, canvas.height );
// draw the full pie
drawFullPie();
// mask it as needed
drawMask();
// until complete
if( current ++ < 100 ) {
// do it again
requestAnimationFrame( animate );
}
}
<canvas id="myCanvas" height="300" width="300"></canvas>
<!DOCTYPE html5>
<html>
<head>
<title>disturbed</title>
<script>
window.onload = function() {
// create the canvas
var canvas = document.createElement("canvas"),
c = canvas.getContext("2d");
var particles = {};
var particleIndex = 0;
var particleNum = 15;
// set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// add canvas to body
document.body.appendChild(canvas);
// style the canvas
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
function Particle() {
this.x = canvas.width / 2;
this.y = canvas.height / 2;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.3;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.life = 0;
this.maxLife = Math.random() * 30 + 60;
this.color = "hsla(" + parseInt(Math.random() * 360, 10) + ",90%,60%,0.5";
}
Particle.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
if (Math.random() < 0.1) {
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
}
this.life++;
if (this.life >= this.maxLife) {
delete particles[this.id];
}
c.fillStyle = this.color;
//c.fillRect(this.x, this.y, 5, 10);
c.beginPath();
c.arc(this.x, this.y, 2.5, 0, 2 * Math.PI);
c.fill();
};
setInterval(function() {
//normal setting before drawing over canvas w/ black background
c.globalCompositeOperation = "source-over";
c.fillStyle = "rgba(0,0,0,0.5)";
c.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
}
// c.globalCompositeOperation = "darken";
for (var i in particles) {
particles[i].draw();
}
}, 30);
};
</script>
</head>
<body>
</body>
</html>
The code below is all correct but its just two densed i want to make it easier and not to populated . what i want to do is make the script that i have into a separate file like "anything.js" so that i can load it into my html main file by just calling out the main functions like particle() in ,window.onload = function() which will be on the main page .
The reason is because i want to add this script to many html pages and i dont want to copy all of the lengthy script in to my code again and again .
Please answer this , it would be really helful.
HTML :
<!DOCTYPE html5>
<html>
<head>
<title>disturbed</title>
</head>
<body>
<script src="toto.js" type="text/javascript"></script>
<script type="text/javascript">
window.onload = function() {
Particle();
};
</script>
</body>
</html>
toto.js :
//create the canvas
var canvas = document.createElement("canvas"),
c = canvas.getContext("2d");
var particles = {};
var particleIndex = 0;
var particleNum = 15;
// set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// add canvas to body
document.body.appendChild(canvas);
// style the canvas
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
function Particle() {
this.x = canvas.width / 2;
this.y = canvas.height / 2;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.3;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.life = 0;
this.maxLife = Math.random() * 30 + 60;
this.color = "hsla(" + parseInt(Math.random() * 360, 10) + ",90%,60%,0.5";
}
Particle.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
if (Math.random() < 0.1) {
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
}
this.life++;
if (this.life >= this.maxLife) {
delete particles[this.id];
}
c.fillStyle = this.color;
//c.fillRect(this.x, this.y, 5, 10);
c.beginPath();
c.arc(this.x, this.y, 2.5, 0, 2 * Math.PI);
c.fill();
};
setInterval(function() {
//normal setting before drawing over canvas w/ black background
c.globalCompositeOperation = "source-over";
c.fillStyle = "rgba(0,0,0,0.5)";
c.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
}
// c.globalCompositeOperation = "darken";
for (var i in particles) {
particles[i].draw();
}
}, 30);
I see you have a scope issue.
Variables are passed from script to script. However, in your case, you declare Particle inside window.onload so it only gets defined inside it and you can't use it elsewhere.
The right way to export your script into a separate file would be to declare Particle in the scope of the whole script, as in:
// anything.js
function Particle() {
...
}
Note that you'd need a bit of rewriting, since I can see that you use variables like canvas (which are only defined in the scope of window.onload) inside Particle's code.
I am new learner of animation using HTML5 Canvas. I am struggling to create line drawing animation in a canvas with desired length of a line.
Here is the code
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
width = canvas.width = window.innerWidth,
height = canvas.height = window.innerHeight;
var x = 200;
var y = 200;
draw();
update();
function draw() {
context.beginPath();
context.moveTo(100, 100);
context.lineTo(x, y);
context.stroke();
}
function update() {
context.clearRect(0, 0, width, height);
x = x + 1;
y = y + 1;
draw();
requestAnimationFrame(update);
}
html,
body {
margin: 0px;
}
canvas {
display: block;
}
<canvas id="canvas"></canvas>
The line is growing on Canvas in the above code. But how to achieve that the 200px wide line and animate the movement in x and y direction. And the same animation with multiple lines using for loop and move them in different direction.
Check the reference image ....
Need to move each line in a different direction
Thanks in advance
Find a new reference image which i want to achieve
You need to either use transforms or a bit of trigonometry.
Transforms
For each frame:
Reset transforms and translate to center
Clear canvas
Draw line from center to the right
Rotate x angle
Repeat from step 2 until all lines are drawn
var ctx = c.getContext("2d");
var centerX = c.width>>1;
var centerY = c.height>>1;
var maxLength = Math.min(centerX, centerY); // use the shortest direction for demo
var currentLength = 0; // current length, for animation
var lenStep = 1; // "speed" of animation
function render() {
ctx.setTransform(1,0,0,1, centerX, centerY);
ctx.clearRect(-centerX, -centerY, c.width, c.height);
ctx.beginPath();
for(var angle = 0, step = 0.1; angle < Math.PI * 2; angle += step) {
ctx.moveTo(0, 0);
ctx.lineTo(currentLength, 0);
ctx.rotate(step);
}
ctx.stroke(); // stroke all at once
}
(function loop() {
render();
currentLength += lenStep;
if (currentLength < maxLength) requestAnimationFrame(loop);
})();
<canvas id=c></canvas>
You can use transformation different ways, but since you're learning I kept it simple in the above code.
Trigonometry
You can also calculate the line angles manually using trigonometry. Also here you can use different approaches, ie. if you want to use delta values, vectors or brute force using the math implicit.
For each frame:
Reset transforms and translate to center
Clear canvas
Calculate angle and direction for each line
Draw line
var ctx = c.getContext("2d");
var centerX = c.width>>1;
var centerY = c.height>>1;
var maxLength = Math.min(centerX, centerY); // use the shortest direction for demo
var currentLength = 0; // current length, for animation
var lenStep = 1; // "speed" of animation
ctx.setTransform(1,0,0,1, centerX, centerY);
function render() {
ctx.clearRect(-centerX, -centerY, c.width, c.height);
ctx.beginPath();
for(var angle = 0, step = 0.1; angle < Math.PI * 2; angle += step) {
ctx.moveTo(0, 0);
ctx.lineTo(currentLength * Math.cos(angle), currentLength * Math.sin(angle));
}
ctx.stroke(); // stroke all at once
}
(function loop() {
render();
currentLength += lenStep;
if (currentLength < maxLength) requestAnimationFrame(loop);
})();
<canvas id=c></canvas>
Bonus animation to play around with (using the same basis as above):
var ctx = c.getContext("2d", {alpha: false});
var centerX = c.width>>1;
var centerY = c.height>>1;
ctx.setTransform(1,0,0,1, centerX, centerY);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(0,0,0,0.8)";
ctx.shadowBlur = 16;
function render(time) {
ctx.globalAlpha=0.77;
ctx.fillRect(-500, -500, 1000, 1000);
ctx.globalAlpha=1;
ctx.beginPath();
ctx.rotate(0.025);
ctx.shadowColor = "hsl(" + time*0.1 + ",100%,75%)";
ctx.shadowBlur = 16;
for(var angle = 0, step = Math.PI / ((time % 200) + 50); angle < Math.PI * 2; angle += step) {
ctx.moveTo(0, 0);
var len = 150 + 150 * Math.cos(time*0.0001618*angle*Math.tan(time*0.00025)) * Math.sin(time*0.01);
ctx.lineTo(len * Math.cos(angle), len * Math.sin(angle));
}
ctx.stroke();
ctx.globalCompositeOperation = "lighter";
ctx.shadowBlur = 0;
ctx.drawImage(ctx.canvas, -centerX, -centerY);
ctx.drawImage(ctx.canvas, -centerX, -centerY);
ctx.globalCompositeOperation = "source-over";
}
function loop(time) {
render(time);
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
body {margin:0;background:#222}
<canvas id=c width=640 height=640></canvas>
Here is what I think you are describing...
window.onload = function() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
width = canvas.width = 400,
height = canvas.height = 220,
xcenter = 200,
ycenter = 110,
radius = 0,
radiusmax = 100,
start_angle1 = 0,
start_angle2 = 0;
function toRadians(angle) {
return angle * (Math.PI / 180);
}
function draw(x1, y1, x2, y2) {
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
}
function drawWheel(xc, yc, start_angle, count, rad) {
var inc = 360 / count;
for (var angle = start_angle; angle < start_angle + 180; angle += inc) {
var x = Math.cos(toRadians(angle)) * rad;
var y = Math.sin(toRadians(angle)) * rad;
draw(xc - x, yc - y, xc + x, yc + y);
}
}
function update() {
start_angle1 += 0.1;
start_angle2 -= 0.1;
if(radius<radiusmax) radius++;
context.clearRect(0, 0, width, height);
drawWheel(xcenter, ycenter, start_angle1, 40, radius);
drawWheel(xcenter, ycenter, start_angle2, 40, radius);
requestAnimationFrame(update);
}
update();
};
html,
body {
margin: 0px;
}
canvas {
display: block;
}
<canvas id="canvas"></canvas>
This is one that is a variable length emerging pattern. It has a length array element for each spoke in the wheel that grows at a different rate. You can play with the settings to vary the results:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
var xcenter = width/4;
var ycenter = height/2;
var radius;
var time;
if(width>height) {
radius = height*0.4;
}
else {
radius = width*0.4;
}
var start_angle1 = 0;
var start_angle2 = 0;
function toRadians (angle) {
return angle * (Math.PI / 180);
}
function draw(x1,y1,x2,y2) {
context.beginPath();
context.moveTo(x1,y1);
context.lineTo(x2,y2);
context.stroke();
}
var radmax=width;
var rads = [];
var radsinc = [];
function drawWheel(xc,yc,start_angle,count,rad) {
var inc = 360/count;
var i=0;
for(var angle=start_angle; angle < start_angle+180; angle +=inc) {
var x = Math.cos(toRadians(angle)) * rads[rad+i];
var y = Math.sin(toRadians(angle)) * rads[rad+i];
draw(xc-x,yc-y,xc+x,yc+y);
rads[rad+i] += radsinc[i];
if(rads[rad+i] > radmax) rads[rad+i] = 1;
i++;
}
}
function update() {
var now = new Date().getTime();
var dt = now - (time || now);
time = now;
start_angle1 += (dt/1000) * 10;
start_angle2 -= (dt/1000) * 10;
context.clearRect(0,0,width,height);
drawWheel(xcenter,ycenter,start_angle1,50,0);
drawWheel(xcenter,ycenter,start_angle2,50,50);
requestAnimationFrame(update);
}
function init() {
for(var i=0;i<100;i++) {
rads[i] = 0;
radsinc[i] = Math.random() * 10;
}
}
window.onload = function() {
init();
update();
};
html, body {
margin: 0px;
}
canvas {
width:100%;
height:200px;
display: block;
}
<canvas id="canvas"></canvas>
I am trying to build something like this site hero-unit: http://www.nodeplus.com.cn/
My approach is to make a temporary 2d canvas, print out my message to it, scan the pixels and then use them to position the meshes in 3d space:
// STEP 1: if a pixel is detected on every gridX / gridY step, put it in the pos array
for (y = 0; y <= height; y += gridY) {
for (x = 0; x <= width; x += gridX) {
if (buffer32[y * width + x]) {
positions.push({x: x, y: y});
}
}
}
then i put them in 3d space accordingly
for (i = 0; i < len; i++) {
pos = positions[i];
shape = new Shape({
x: pos.x / 10,
y: -pos.y / 10,
z: Math.random() * 4
});
shape.init(scene);
shapes.push(shape);
}
Thats all fine and good, but i want them to be positioned at the scene center.
Because of the way im scanning the 2d canvas and getting the positions from there (starting at 0, 0), they get some very weird positioning in 3d space with three.js (because i have pixels that are positioned like {x: 1600, y:500} on bigger screens)
I had to put a strange camera.lookAt position just to look at it, something like:
camera.position.set(100, 0, 80);
camera.lookAt({
x: 95,
y: -50,
z: scene.position.z
});
This kinda works for now, but its not a good option for me. I want to rotate the camera around the letters and dont want to rotate it around some weird position like this.
You can check out the code here:
var heroUnit = (function(self) {
function Shape(pos) {
this.pos = pos;
this.mesh = null;
this.radius = 2 + Math.random() * 2;
this.speed = 0.4 + Math.random() * 0.4;
}
Shape.prototype.init = function(scene) {
var geometry, material, mesh,
v1, v2, v3;
geometry = new THREE.Geometry();
v1 = new THREE.Vector3(this.pos.x - this.radius / 2, this.pos.y - this.radius / 2, this.pos.z - this.radius / 2);
v2 = new THREE.Vector3(this.pos.x + this.radius / 2, this.pos.y - this.radius / 2, this.pos.z - this.radius / 2);
v3 = new THREE.Vector3(this.pos.x + this.radius / 2, this.pos.y + this.radius / 2, this.pos.z + this.radius / 2);
geometry.vertices.push(v1);
geometry.vertices.push(v2);
geometry.vertices.push(v3);
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.computeFaceNormals();
material = new THREE.MeshLambertMaterial({color: Math.random() * 0xFFFFFF});
mesh = new THREE.Mesh(geometry, material);
this.mesh = mesh;
this.mesh.receiveShadow = true;
//this.mesh.scale.set(Math.random() * 20, Math.random() * 20, Math.random() * 20);
this.mesh.rotation.set(0, 0, 0)
scene.add(this.mesh);
}
var width, height,
aspectRatio, pov,
near, far,
scene, camera,
renderer,
effectPositions,
shapes, light;
function init(string) {
// constants
width = window.innerWidth;
height = window.innerHeight;
pov = 45;
aspectRatio = width / height;
near = 0.1;
far = 1000;
// three.js specific stuff
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(pov, aspectRatio, near, far);
renderer = new THREE.WebGLRenderer();
light = new THREE.DirectionalLight(0x000000, 0.6);
// containers
effectPositions = getPixels(string);
shapes = [];
// set up light
light.position.set(100, 0, 200);
light.castShadow = true;
scene.add(light);
// set size to renderer, color it in dark blue & append it to dom
renderer.setSize(width, height);
renderer.setClearColor(0x17293a);
document.body.appendChild(renderer.domElement);
// set up camera
camera.position.set(100, 0, 80);
camera.lookAt({
x: 50,
y: -50,
z: scene.position.z
});
scene.add(camera);
generateShapes(effectPositions);
}
// generate 3d shapes according to our 2d positions array
function generateShapes(positions) {
var i, n, len,
pos, shape,
maxIterations
len = positions.length;
maxIterations = 2;
for (n = 0; n <= maxIterations; n++) {
for (i = 0; i < len; i++) {
pos = positions[i];
shape = new Shape({
x: pos.x / 10,
y: -pos.y / 10,
z: Math.random() * 4
});
shape.init(scene);
shapes.push(shape);
}
}
}
// get 2d positions
function getPixels(string) {
var canvas, ctx,
idata, buffer32,
x, y,
gridX, gridY,
positions;
//make temp canvas on which to draw and get pixel data
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
positions = [];
string = string.toUpperCase().split("").join(String.fromCharCode(8202));
canvas.width = width;
canvas.height = height;
//document.body.appendChild(canvas);
ctx.fillStyle = '#000';
ctx.font = 'bold 260px Arial';
ctx.fillText(string, width / 2 - ctx.measureText(string).width / 2, height / 2);
idata = ctx.getImageData(0, 0, width, height);
buffer32 = new Uint32Array(idata.data.buffer);
gridX = gridY = 14;
// if a pixel is detected on every gridX / gridY step, put it in the pos array
for (y = 0; y <= height; y += gridY) {
for (x = 0; x <= width; x += gridX) {
if (buffer32[y * width + x]) {
positions.push({x: x, y: y});
}
}
}
// return pos array
return positions;
}
// render function
function render(ts) {
renderer.render(scene, camera);
shapes.forEach(function(shape) {
// shape.mesh.position.x = shape.dist + (Math.sin(ts / 500)) * shape.speed;
})
}
return {
init: init,
render: render
}
}(heroUnit || {}))
// init our program
heroUnit.init('100');
// redraw each frame
(function drawFrame(ts) {
window.requestAnimationFrame(drawFrame);
heroUnit.render(ts);
}());
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.js"></script>
Any ideas and suggestions are more then welcome, cheers
How I can add Html content on a moving element in the Canvas, like this one
http://www.html5canvastutorials.com/labs/html5-canvas-harmonic-oscillator/
where I need to display my link or button on the moving block attached to the spring. Generally for static canvas elements we can use Z-index or overlapping techniques, but these don't work in this case.
Any solutions ?
Check if the following script works:
<script src="http://www.html5canvastutorials.com/libraries/kinetic2d-v1.0.3.js">
</script>
<script>
var button = {
x: 0,
y: 0,
size: 16,
width: 0,
height: 0,
padding: 4,
hover: false,
text: "Click Me",
onclick: function (e) {
// put your event handler code here
}
};
function drawSpring(canvas, context){
context.beginPath();
context.moveTo(0, 0);
for (var y = 0; y < 200; y++) {
// Sine wave equation
var x = 30 * Math.sin(y / 9.05);
context.lineTo(x, y);
}
}
function drawWeight(canvas, context, y){
var size = 100;
context.save();
context.fillStyle = "red";
context.fillRect(-size / 2, 0, size, size);
context.restore();
canvas.fillText(button.text, 0, 0);
button.x = ((canvas.width - button.width) / 2) - button.padding;
button.y = (y + (size - button.height) / 2) - button.padding;
}
window.onload = function(){
var kin = new Kinetic_2d("myCanvas");
var canvas = kin.getCanvas();
var context = kin.getContext();
context.font = button.size + "px Verdana";
context.textAlign = "center";
context.textBaseline = "top";
button.width = 2 * button.padding + context.measureText(button.text);
button.height = 2 * button.padding + button.size;
var theta = 0;
var curleft = 0;
var curtop = 0;
var obj = canvas;
do {
curleft += object.offsetLeft;
curtop += object.offsetTop;
} while (obj = obj.offsetParent);
canvas.addEventListener("mousemove", function (e) {
context.beginPath();
context.rect(button.x, button.y, button.width, button.height);
button.hover = context.isPointInPath(e.pageX - curleft, e.pageY - curtop);
}, false);
canvas.addEventListener("click", function (e) {
if (button.hover) button.onclick(e);
}, false);
kin.setDrawStage(function(){
theta += this.getTimeInterval() / 400;
var scale = 0.8 * (Math.sin(theta) + 1.3);
this.clear();
context.save();
context.translate(canvas.width / 2, 0);
context.save();
context.scale(1, scale);
drawSpring(canvas, context);
context.restore();
context.lineWidth = 6;
context.strokeStyle = "#0096FF"; // blue-ish color
context.stroke();
context.translate(0, 200 * scale);
drawWeight(canvas, context, 200 * scale);
context.restore();
});
kin.startAnimation();
};
</script>