Reputation: 3222
Problem: I want to arrange divs in a circle and animate the radius. Unfortunately, I seem to have some sort of binding issue with my variables. Trying to figure this out since 3 days. What can I do to get out of this predicament? I mean how do I solve this in an "elegant fashion"?
What I Tried: I did a few console logs and everything implies that javascript has problems interpreting what I mean with "this".
I also found out that I need to bind the parameter inside requestAnimationFrame but I cant imagine binding every variable and function name so I must be doing something wrong here.
Here is the JSFiddle: https://jsfiddle.net/Lh23pzvb/4/
Code:
function explodeRocket(obj) {
this.elem = document.getElementsByTagName('div');
this.particle = [];
this.radius = obj.radius;
this.color = ['red', 'yellow', 'cyan', 'orchid']
this.interval = 2 * Math.PI / obj.particles;
this.init = function() {
this.create();
this.blast();
}
this.init();
this.create = function() {
for(var i = 0; i < obj.particles; i++) {
document.body.appendChild(document.createElement('div'));
this.elem[i].style.background = this.color[obj.colorIndex];
this.particle.push(new this.Properties(0, obj.x, obj.y));
this.updatePosition(i);
}
}
this.Properties = function(angle, x, y) {
this.angle = angle;
this.x = x;
this.y = y;
}
this.updatePosition = function(index) {
this.elem[index].style.left = this.particle[index].x + 'px';
this.elem[index].style.top = this.particle[index].y + 'px';
}
this.blast = function() {
for(var i = 0; i < 10 - 1; i++) {
if(this.radius < obj.radiusMax) {
this.radius += 0.2;
}
this.particle[i].x = Math.round(window.innerWidth) / 2 + obj.radius * Math.cos(this.particle[i].angle) ;
this.particle[i].y = Math.round(window.innerHeight) / 2 + obj.radius * Math.sin(this.particle[i].angle);
this.updatePosition(i);
this.particle[i].angle += this.interval;
}
requestAnimationFrame(this.blast);
}
}
new explodeRocket({
particles: 4, colorIndex: 0, radius: 0, radiusMax: 200, x: 0, y: 0
})
Upvotes: 0
Views: 70
Reputation: 3130
Bug 1:
You call the init()
before the create()
function initialised, so you cannot call it. You can fix it by putting the init()
at the end of the explodeRocket
function, so all your functions exist when calling init()
.
Bug 2:
.blast()
runs the loop too many times. You only have 4 particles, but the loop runs 9 times. You can fix it by running the loop only particle.length
times:
for(var i = 0; i < this.particle.length; i++) {
Bug 3:
The this
bug. Your code loses this
, when you call requestAnimationFrame
. You can use the Function.call
, which takes the this
object as the first parameter. It's common to bind this
to some other variable (like self
) to overcome these issues:
var self = this;
requestAnimationFrame(function() {
self.blast.call(self);
});
Bug 4:
You're referring to obj.radius
, which is always 0. You should use this.radius
:
this.particle[i].x = Math.round(window.innerWidth) / 2 + this.radius * Math.cos(this.particle[i].angle);
this.particle[i].y = Math.round(window.innerHeight) / 2 + this.radius * Math.sin(this.particle[i].angle);
Bug 5:
You probably don't want to rotate full 1/4th of round always, so animate 1/40th of circle per frame:
this.particle[i].angle += this.interval * 0.1;
Bug 6:
You probably want the particles to be evenly spaced, so intialize the particle with proper radius:
this.particle.push(new this.Properties(this.interval * i, obj.x, obj.y));
Complete code:
function explodeRocket(obj) {
var self = this;
this.elem = document.getElementsByTagName('div');
this.particle = [];
this.radius = obj.radius;
this.color = ['red', 'yellow', 'cyan', 'orchid']
this.interval = 2 * Math.PI / obj.particles;
this.init = function() {
this.create();
this.blast();
}
this.create = function() {
for(var i = 0; i < obj.particles; i++) {
document.body.appendChild(document.createElement('div'));
this.elem[i].style.background = this.color[obj.colorIndex];
this.particle.push(new this.Properties(this.interval * i, obj.x, obj.y));
this.updatePosition(i);
}
}
this.Properties = function(angle, x, y) {
this.angle = angle;
this.x = x;
this.y = y;
}
this.updatePosition = function(index) {
this.elem[index].style.left = this.particle[index].x + 'px';
this.elem[index].style.top = this.particle[index].y + 'px';
}
this.blast = function() {
for(var i = 0; i < this.particle.length; i++) {
if(this.radius < obj.radiusMax) {
this.radius += 0.2;
}
this.particle[i].x = Math.round(window.innerWidth) / 2 + this.radius * Math.cos(this.particle[i].angle);
this.particle[i].y = Math.round(window.innerHeight) / 2 + this.radius * Math.sin(this.particle[i].angle);
this.updatePosition(i);
this.particle[i].angle += this.interval * 0.1;
}
requestAnimationFrame(function() {
self.blast.call(self);
});
}
this.init();
}
new explodeRocket({
particles: 4, colorIndex: 0, radius: 0, radiusMax: 200, x: 0, y: 0
})
That should do it!
Edit:
Working jsfiddle: https://jsfiddle.net/v3nt2kd0/
Upvotes: 2
Reputation: 9358
First of all, try moving your this.init();
at the end of the constructor.
After doing that there are some other errors thrown, inside your blast()
method, which probably has something to do with the fact that the this.particles
array only has 4 elements and you are trying to do 10 iterations or so.
As a tip, you could move most, if not all, of the methods on the explodeRocket.prototype
so that instances share the same method instance, like so:
function ExplodeRocket(obj) {
//yada yada
}
ExplodeRocket.prototype.blast = function blast() {
//yada yada
}
Upvotes: 1