I was able to visualize the aforementioned functions successfully, then I tried to use Object Oriented Programming and compress my code into one function, it seems to not give any result, it doesn't show any errors but in same time, it doesn't display anything except the background when I run it, I am using the p5js library, How can I fix this issue?
I just started working with JS a few months ago, sorry for my ignorance
Here is my code:
var step = 1;
var scl = 1;
//amplitude for each visualization
var sa, ca, ta;
var ssld, csld, tsld;
//to hold x-values and y-values of the three functions
var sx = [], sy = [], cx = [], cy = [], tx = [], ty = [];
function setup() {
angleMode(DEGREES);
createCanvas(640, 480);
background(55);
ssld = createSlider(0, 150, 75);
ssld.position(10, 10);
csld = createSlider(0, 150, 75);
csld.position(10, 35);
tsld = createSlider(0, 150, 75);
tsld.position(10, 60);
var s_ = generateValues("sin");
var c_ = generateValues("cos");
var t_ = generateValues("tan");
sx = s_[0]
sy = s_[1]
cx = c_[0]
cy = c_[1]
tx = t_[0]
ty = t_[1]
}
function draw() {
var sa = ssld.value();
var ca = csld.value();
var ta = tsld.value();
strokeWeight(scl);
stroke(255, 0, 0);
renderWave(sx, sy);
stroke(0, 255, 0);
renderWave(cx, cy);
stroke(0, 255, 255);
renderWave(tx, ty);
}
//given the wave type, it returns a two-dimensional array containing the x-values, and y-values
function generateValues(wave_type) {
var xvalues = [];
var yvalues = [];
for (var i = 0; i < width; i += step) {
append(xvalues, i)
}
if (wave_type === "sin") {
for (var i = 0; i < xvalues.length; i++) {
var y = sin(xvalues[i]);
append(yvalues, y * sa);
}
return [xvalues, yvalues];
} else if (wave_type === "cos") {
for (var i = 0; i < xvalues.length; i++) {
var y = cos(xvalues[i]);
append(yvalues, y * ca);
}
return [xvalues, yvalues];
} else if (wave_type === "tan") {
for (var i = 0; i < xvalues.length; i++) {
var y = tan(xvalues[i]);
append(yvalues, y * ta);
}
return [xvalues, yvalues];
}
}
function renderWave (array_x, array_y) {
for (var i = 0; i < width; i++) {
point(array_x[i], array_y[i] + (height / 2));
}
}
You don't have initial values for sa, ca and ta. So when you call generateValues, those are all undefined, and your y-values are all NaN. Here I've assigned values to them in the setup function, before the call to generateValues. I also removed the var keyword from the assignments in draw(), because you want to use/affect the global variables not create new local variables.
Your sliders don't work - this is because you only use the sa, ca, ta values in generateValues, which you only call on setup, not each time it redraws. You'll need to re-think that part.
var step = 1;
var scl = 1;
//amplitude for each visualization
var sa, ca, ta;
var ssld, csld, tsld;
//to hold x-values and y-values of the three functions
var sx = [], sy = [], cx = [], cy = [], tx = [], ty = [];
function setup() {
angleMode(DEGREES);
createCanvas(640, 480);
background(55);
ssld = createSlider(0, 150, 75);
ssld.position(10, 10);
sa = 10;
csld = createSlider(0, 150, 75);
csld.position(10, 35);
ca = 10;
tsld = createSlider(0, 150, 75);
tsld.position(10, 60);
ta = 10;
var s_ = generateValues("sin");
var c_ = generateValues("cos");
var t_ = generateValues("tan");
sx = s_[0]
sy = s_[1]
cx = c_[0]
cy = c_[1]
tx = t_[0]
ty = t_[1]
}
function draw() {
sa = ssld.value();
ca = csld.value();
ta = tsld.value();
strokeWeight(scl);
stroke(255, 0, 0);
renderWave(sx, sy);
stroke(0, 255, 0);
renderWave(cx, cy);
stroke(0, 255, 255);
renderWave(tx, ty);
}
//given the wave type, it returns a two-dimensional array containing the x-values, and y-values
function generateValues(wave_type) {
var xvalues = [];
var yvalues = [];
for (var i = 0; i < width; i += step) {
append(xvalues, i)
}
if (wave_type === "sin") {
for (var i = 0; i < xvalues.length; i++) {
var y = sin(xvalues[i]);
append(yvalues, y * sa);
}
return [xvalues, yvalues];
} else if (wave_type === "cos") {
for (var i = 0; i < xvalues.length; i++) {
var y = cos(xvalues[i]);
append(yvalues, y * ca);
}
return [xvalues, yvalues];
} else if (wave_type === "tan") {
for (var i = 0; i < xvalues.length; i++) {
var y = tan(xvalues[i]);
append(yvalues, y * ta);
}
return [xvalues, yvalues];
}
}
function renderWave (array_x, array_y) {
for (var i = 0; i < width; i++) {
point(array_x[i], array_y[i] + (height / 2));
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/addons/p5.dom.min.js"></script>
Related
I am trying to achieve effect as shown in the picture below:
Im using p5.js library but im not a graphics programmer and thats why its very difficult to achieve this particular graphical effect. I am sharing my code with you and also I followed this tutorial.
Index.html
<html>
<head>
<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
<script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
<script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<script language="javascript" type="text/javascript" src="particle.js"></script>
</head>
<body>
</body>
</html>
particle.js
function Particle() {
this.pos = createVector(random(width), random(height));
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.maxspeed = 4;
this.h = 0;
this.alphaPower = 20;
this.prevPos = this.pos.copy();
this.update = function() {
this.vel.add(this.acc);
this.vel.limit(this.maxspeed);
this.pos.add(this.vel);
this.acc.mult(0);
}
this.follow = function(vectors) {
var x = floor(this.pos.x / scl);
var y = floor(this.pos.y / scl);
var index = x + y * cols;
var force = vectors[index];
this.applyForce(force);
}
this.applyForce = function(force) {
this.acc.add(force);
}
this.showBlue = function() {
stroke(0, 76, 153, this.alphaPower);
strokeWeight(1);
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();
}
this.showMaroon = function() {
stroke(165, 0, 68, this.alphaPower); // maroon
strokeWeight(1);
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();
}
this.showYellow = function() {
stroke(237, 188, 0, this.alphaPower);
//stroke(1,2);
strokeWeight(1);
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();
}
this.updatePrev = function() {
this.prevPos.x = this.pos.x;
this.prevPos.y = this.pos.y;
}
this.edges = function() {
if (this.pos.x > width) {
this.pos.x = 0;
this.updatePrev();
}
if (this.pos.x < 0) {
this.pos.x = width;
this.updatePrev();
}
if (this.pos.y > height) {
this.pos.y = 0;
this.updatePrev();
}
if (this.pos.y < 0) {
this.pos.y = height;
this.updatePrev();
}
}
}
sketch.js
var inc = 0.01;
var scl = 10;
var cols, rows;
var zoff = 0;
var fr;
var particles = [];
var particlesMaroon = [];
var particlesBlue = [];
var particlesYellow = [];
var flowfield;
var flowfieldMaroon;
var flowfieldBlue;
var flowfieldYellow;
var gamma_is_high = false;
var beta_is_high = false;
var alpha_is_high = false;
var maroon_data=1000;
var blue_data = 1000;
var yellow_data = 1000;
setInterval(function() {
ChangeLines();
}, 5000);
function dataRequest(){
socket.emit('datarequest', {data: "request"});
}
function ChangeLines(){
maroon_data = random(500, 2000);
blue_data = random(500, 2000);
yellow_data = random(500, 2000);
gamma_is_high = true;
alpha_is_high = true;
beta_is_high = true;
}
function setup() {
slider = createSlider(0.01, 0.1, 0.02,0);
slider.position(10, 10);
slider.style('width', '80px');
ChangeLines();
createCanvas(windowWidth-15, windowHeight-20);
cols = floor(width / scl);
rows = floor(height / scl);
fr = createP('');
flowfield = new Array(cols * rows);
flowfieldMaroon = new Array(cols * rows);
flowfieldBlue = new Array(cols * rows);
flowfieldYellow = new Array(cols * rows);
for (var i = 0; i < 1000; i++) {
particles[i] = new Particle();
particlesMaroon[i] = new Particle();
particlesBlue[i] = new Particle();
particlesYellow[i] = new Particle();
}
background(255);
}
function draw() {
let val = slider.value();
inc = val;
var yoff = 0;
for (var y = 0; y < rows; y++) {
var xoff = 0;
for (var x = 0; x < cols; x++) {
var index = x + y * cols;
var angle = noise(xoff, yoff, zoff) * TWO_PI;
var angleMaroon = noise(xoff, yoff, zoff) * TWO_PI;
var angleBlue = noise(xoff, yoff, zoff) * TWO_PI;
var angleYellow = noise(xoff, yoff, zoff) * TWO_PI;
var v = p5.Vector.fromAngle(angle);
var vm = p5.Vector.fromAngle(angleMaroon);
var vb = p5.Vector.fromAngle(angleBlue);
var vy = p5.Vector.fromAngle(angleYellow);
v.setMag(5);
vm.setMag(5);
vb.setMag(5);
vy.setMag(5);
flowfield[index] = v;
flowfieldMaroon[index] = vm;
flowfieldBlue[index] = vb;
flowfieldYellow[index] = vy;
xoff += inc;
}
yoff += inc;
}
zoff += 0.0003;
for (var i = 0; i < particles.length; i++) {
if(gamma_is_high==true){
particlesMaroon[i].follow(flowfieldMaroon);
particlesMaroon[i].update();
particlesMaroon[i].edges();
particlesMaroon[i].showMaroon();
}
if(beta_is_high){
particlesBlue[i].follow(flowfieldBlue);
particlesBlue[i].update();
particlesBlue[i].edges();
particlesBlue[i].showBlue();
}
if(alpha_is_high){
particlesYellow[i].follow(flowfieldYellow);
particlesYellow[i].update();
particlesYellow[i].edges();
particlesYellow[i].showYellow();
}
}
fr.html(floor(frameRate()));
}
The variables maroon_data, blue_dataand yellow_data are data coming from EEG device which will be calculated later but for now its hard coded values for prototype only. Also booleans gamma_is_high, beta_is_high and alpha_is_high are set to true for now. But with this much effort I only manage to achieve this as shown below:
And the actual output is like this:
Kindly help me get this actual output. Any help would be appreciated. Thanks.
Ive sorta done this before. I only had one array of particles and just changed their rgb values by a small random amount. I used an object to store the colour values.
function setup() {
//Do all the normal stuff
var c = {r: 100, g:100, b:100)
}
function draw() {
//All the other stuff
c.r += random(-3,3);
c.g += random(-3,3);
c.b += random(-3,3);
}
And then in the particle:
show() {
fill(c.r,c.g,c.b, whateverAlphaYouWant);
//Do all the rest
}
You can always tweak the values to get whatever colour you want.
I have the following code that i've roughly redone from someone else to help learn javascript. I am getting the following error:
Uncaught TypeError: flock.addBoid is not a function
at setup (boids.js:15)
at boids.js:1
The function in question is called at the beginning in setup() and defined shortly after in the section labeled FLOCK. It is definitely not misspelled and these are the only occurrences of addBoid in the document. I'll include the whole document in case its relevant but the problem should just lie in the beginning.
I am not looking for any advice about my code other than the source and solution to this error, thanks.
setup();
draw();
//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;
function setup(){
c = document.getElementById("boidCanvas");
ctx = c.getContext("2d");
flock = new Flock();
for(var i = 0; i < 100; i++){
var b = new Boid(ctx.width / 2, ctx.height / 2);
flock.addBoid(b);
}
}
function draw() {
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,c.width,c.height);
//flock.run()
}
//////////////////// FLOCK ///////////////////////
function Flock(){
this.boids = [];
}
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
//////////////////// BOID ///////////////////////
function Boid(setx,sety){
this.acceleration = { x:0, y:0 };
this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
this.position = { x:setx, y:sety };
this.r = 3;
this.maxSpeed = 3;
this.maxForce = .05;
}
Boid.prototype.run = function(boids){
this.evaluate(boids);
this.update();
this.wrap();
this.render();
}
// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
this.acceleration.x += force[0];
this.acceleration.y += force[1];
}
Boid.prototype.evaluate = function(boids){
var seperate = this.seperate(boids);
var align = this.align(boids);
var cohesion = this.cohesion(boids);
// Arbitrary Weights
seperate *= 1.5;
align *= 1.0;
cohesion *= 1.0;
this.applyForce(seperate);
this.applyForce(align);
this.applyForce(cohesion);
}
Boid.prototype.update = function(){
//update velocity
this.velocity += this.acceleration;
//fix velocity to max speed
var normal = normalize([this.velocity.x, this.velocity.y]);
this.velocity = constantMult(normal, this.maxSpeed);
//update position
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
//reset acceleration;
this.acceleration.x = 0;
this.acceleration.y = 0;
}
// target is a vector [x,y]
Boid.prototype.seek = function(target){
var desired = sub(target, [this.position.x, this.position.y]);
var normal = normalize(desired);
desired = constantMult(normal, this.maxSpeed);
var steer = sub(desired,[this.velocity.x, this.velocity.y])
normal = normalize(steer);
steer[0] = normal[0] * this.maxForce;
steer[1] = normal[1] * this.maxForce;
return steer;
}
Boid.prototype.render = function(){
var triangle = drawTriangle(this.velocity);
for(var i = 0; i < triangle.length; i++){
triangle[i] = constantMult(triangle[i], this.r);
}
for(i = 0; i < triangle.length; i++){
triangle[i] = add(triangle[i], this.position);
}
ctx.beginPath();
ctx.moveTo(triangle[0][0], triangle[0][1]);
for(i = 1; i < triangle.length; i++){
ctx.lineTo(triangle[i][0], triangle[i][1]);
}
ctx.closePath();
ctx.fillStyle = "White";
ctx.fill();
}
Boid.prototype.wrap = function(){
if(this.position.x < -this.r)
this.position.x = c.width + this.r;
else if(this.position.x > c.width + this.r)
this.position.x = -this.r;
if(this.position.y < -this.r)
this.position.y = c.height + this.r;
else if(this.position.y > c.height + this.r)
this.position.y = -this.r;
}
Boid.prototype.seperate = function(boids){
var desiredSeperation = 25.0;
var steer = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(d < desiredSeperation){
var normalDiff = normalize(difference);
normalDiff = constantMult(normalDiff, 1/d);
steer = add(steer, normalDiff);
count++;
}
}
if(count > 0){
steer = constantMult(steer, 1/count);
steer = normalize(steer);
steer = constantMult(steer, this.maxSpeed);
steer = sub(steer, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
}
return steer;
}
Boid.prototype.align = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = sum(sum, boids[i].velocity);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
sum = normalize(sum);
sum = constantMult(this.maxSpeed);
var steer = sub(sum, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
return steer;
}
else
return [0,0];
}
Boid.prototype.cohesion = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = add(sum, boids[i].position);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
return this.seek(sum);
}
else
return [0,0];
}
//////////////////// HELPERS ///////////////////////
// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
var normalX = v[0] / magnitude;
var normalY = v[1] / magnitude;
return [normalX, normalY];
}
function add(a,b){
var x = a[0]+b[0];
var y = a[1]+b[1];
return [x,y];
}
// returns a-b, [ax-bx, ay-by]
function sub(a,b){
var x = a[0]-b[0];
var y = a[1]-b[1];
return [x,y];
}
function mult(a,b){
var x = a[0]*b[0];
var y = a[1]*b[1];
return [x,y];
}
function constantMult(a, n){
for(var i = 0; i < a.length; i++){
a[i] *= n;
}
}
// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
heading = normalize(heading);
var v1 = [1,0];
var v2 = [-1, .5];
var v3 = [-1,-.5];
var thetaX = Math.acos(heading[0]);
var thetaY = Math.asin(heading[1]);
var theta;
if(thetaX >= 0)
theta = (Math.PI / 2) - thetaY;
else
theta = (Math.PI / 2) - thetaX;
function rotate(v){
var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
return [xp, yp];
}
v1 = rotate(v1);
v2 = rotate(v2);
v3 = rotate(v3);
return [v1,v2,v3];
}
Move the functions setup(); and draw(); to the end of the JavaScript file. The issue was that the function addBoid() was not hoisted to the top, making it undefined by setup(); and draw();.
You function declaration gets hoisted on the top of block.
function Flock(){
this.boids = [];
}
when you add properties to prototype those properties are not eligible for hoisting, its like accessing variables (let declared cause var is eligible for hoisting) before declaring them.
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
Add above lines before you call flock.addBoid i.e. move setup and draw call to the end of Javascript
//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;
//////////////////// FLOCK ///////////////////////
function Flock(){
this.boids = [];
}
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
function setup(){
c = document.getElementById("boidCanvas");
ctx = c.getContext("2d");
flock = new Flock();
for(var i = 0; i < 100; i++){
var b = new Boid(ctx.width / 2, ctx.height / 2);
flock.addBoid(b);
}
}
function draw() {
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,c.width,c.height);
//flock.run()
}
//////////////////// BOID ///////////////////////
function Boid(setx,sety){
this.acceleration = { x:0, y:0 };
this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
this.position = { x:setx, y:sety };
this.r = 3;
this.maxSpeed = 3;
this.maxForce = .05;
}
Boid.prototype.run = function(boids){
this.evaluate(boids);
this.update();
this.wrap();
this.render();
}
// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
this.acceleration.x += force[0];
this.acceleration.y += force[1];
}
Boid.prototype.evaluate = function(boids){
var seperate = this.seperate(boids);
var align = this.align(boids);
var cohesion = this.cohesion(boids);
// Arbitrary Weights
seperate *= 1.5;
align *= 1.0;
cohesion *= 1.0;
this.applyForce(seperate);
this.applyForce(align);
this.applyForce(cohesion);
}
Boid.prototype.update = function(){
//update velocity
this.velocity += this.acceleration;
//fix velocity to max speed
var normal = normalize([this.velocity.x, this.velocity.y]);
this.velocity = constantMult(normal, this.maxSpeed);
//update position
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
//reset acceleration;
this.acceleration.x = 0;
this.acceleration.y = 0;
}
// target is a vector [x,y]
Boid.prototype.seek = function(target){
var desired = sub(target, [this.position.x, this.position.y]);
var normal = normalize(desired);
desired = constantMult(normal, this.maxSpeed);
var steer = sub(desired,[this.velocity.x, this.velocity.y])
normal = normalize(steer);
steer[0] = normal[0] * this.maxForce;
steer[1] = normal[1] * this.maxForce;
return steer;
}
Boid.prototype.render = function(){
var triangle = drawTriangle(this.velocity);
for(var i = 0; i < triangle.length; i++){
triangle[i] = constantMult(triangle[i], this.r);
}
for(i = 0; i < triangle.length; i++){
triangle[i] = add(triangle[i], this.position);
}
ctx.beginPath();
ctx.moveTo(triangle[0][0], triangle[0][1]);
for(i = 1; i < triangle.length; i++){
ctx.lineTo(triangle[i][0], triangle[i][1]);
}
ctx.closePath();
ctx.fillStyle = "White";
ctx.fill();
}
Boid.prototype.wrap = function(){
if(this.position.x < -this.r)
this.position.x = c.width + this.r;
else if(this.position.x > c.width + this.r)
this.position.x = -this.r;
if(this.position.y < -this.r)
this.position.y = c.height + this.r;
else if(this.position.y > c.height + this.r)
this.position.y = -this.r;
}
Boid.prototype.seperate = function(boids){
var desiredSeperation = 25.0;
var steer = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(d < desiredSeperation){
var normalDiff = normalize(difference);
normalDiff = constantMult(normalDiff, 1/d);
steer = add(steer, normalDiff);
count++;
}
}
if(count > 0){
steer = constantMult(steer, 1/count);
steer = normalize(steer);
steer = constantMult(steer, this.maxSpeed);
steer = sub(steer, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
}
return steer;
}
Boid.prototype.align = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = sum(sum, boids[i].velocity);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
sum = normalize(sum);
sum = constantMult(this.maxSpeed);
var steer = sub(sum, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
return steer;
}
else
return [0,0];
}
Boid.prototype.cohesion = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = add(sum, boids[i].position);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
return this.seek(sum);
}
else
return [0,0];
}
//////////////////// HELPERS ///////////////////////
// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
var normalX = v[0] / magnitude;
var normalY = v[1] / magnitude;
return [normalX, normalY];
}
function add(a,b){
var x = a[0]+b[0];
var y = a[1]+b[1];
return [x,y];
}
// returns a-b, [ax-bx, ay-by]
function sub(a,b){
var x = a[0]-b[0];
var y = a[1]-b[1];
return [x,y];
}
function mult(a,b){
var x = a[0]*b[0];
var y = a[1]*b[1];
return [x,y];
}
function constantMult(a, n){
for(var i = 0; i < a.length; i++){
a[i] *= n;
}
}
// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
heading = normalize(heading);
var v1 = [1,0];
var v2 = [-1, .5];
var v3 = [-1,-.5];
var thetaX = Math.acos(heading[0]);
var thetaY = Math.asin(heading[1]);
var theta;
if(thetaX >= 0)
theta = (Math.PI / 2) - thetaY;
else
theta = (Math.PI / 2) - thetaX;
function rotate(v){
var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
return [xp, yp];
}
v1 = rotate(v1);
v2 = rotate(v2);
v3 = rotate(v3);
return [v1,v2,v3];
}
setup();
draw();
I'm currently working on a particle system where the particles move around and create pictures with some seconds in between (almost like a slide). I know where to put the color code to change the color on the particles forming the pictures bur for some reason it doesn't work. I therefore suspect that the problem is somewhere else in the script but the question is where...
You can see the code below (tried to make a codepen but it didn't work):
var dispersed = false;
var firstDone = false;
var secondDone = false;
var thirdDone = false;
var fRgba = []; // first img rgba data
var sRgba = []; // second img rgba data
var tRgba = []; // third img rgba data
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.01,
FAR = 10000;
var $container = $("#container");
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
scene.add(camera);
camera.position.z = 900;
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
var particleCount = 5200,
particles = new THREE.Geometry();
var pMaterial = new THREE.PointsMaterial({
size: 6,
map: createCircleTexture('#CACACA', 256),
transparent: true,
depthWrite: false
});
function createCircleTexture(color, size) {
var matCanvas = document.createElement('canvas');
matCanvas.width = matCanvas.height = size;
var matContext = matCanvas.getContext('2d');
var texture = new THREE.Texture(matCanvas);
var center = size / 2;
matContext.beginPath();
matContext.arc(center, center, size/2, 0, 2 * Math.PI, false);
matContext.closePath();
matContext.fillStyle = color;
matContext.fill();
texture.needsUpdate = true;
return texture;
}
for (var i = 0; i < particleCount; i++) {
var x = Math.random() * 1600 - 800;
var y = getRandomInt(600, 1500)
var z = Math.random() * 30 - 15;
var particle = new THREE.Vector3(x, y, z);
particle.updated = 0;
particles.vertices.push(particle);
};
var particleSystem = new THREE.Points(particles, pMaterial);
particleSystem.sortParticles = true;
scene.add(particleSystem);
function drawImage(imageObj, array) {
var canvas = $("#canvas")[0];
var context = canvas.getContext("2d");
var imageX = 0;
var imageY = 0;
var imageWidth = imageObj.width;
var imageHeight = imageObj.height;
context.drawImage(imageObj, imageX, imageY);
var imageData = context.getImageData(imageX, imageY, imageWidth,
imageHeight);
var data = imageData.data;
for(var y = 0; y < imageHeight; y+= 4) {
for(var x = 0; x < imageWidth; x+= 4) {
var red = data[((imageWidth * y) + x) * 4];
var green = data[((imageWidth * y) + x) * 4 + 1];
var blue = data[((imageWidth * y) + x) * 4 + 2];
var alpha = data[((imageWidth * y) + x) * 4 + 3];
if (red < 100) {
var pX = (x % 500) - 249;
var pY = 249 - y;
array.push([pX, pY, red, green, blue, alpha]);
}
}
}
};
var addDestination = function(particle, x, y, z) {
var dest = new THREE.Vector3(x, y, z);
particle.destination = dest;
};
var addVelocity = function(particle) {
var xDiff = (particle.destination.x - particle.x) / 180;
var yDiff = (particle.destination.y - particle.y) / 180;
var zDiff = (particle.destination.z - particle.z) / 180;
var vel = new THREE.Vector3(xDiff, yDiff, zDiff);
particle.velocity = vel;
};
var move = function(particle) {
particle.x += particle.velocity.x;
particle.y += particle.velocity.y;
particle.z += particle.velocity.z;
particle.updated += 1;
};
var slowDown = function(particle) {
particle.velocity.x -= (particle.velocity.x / 300)
particle.velocity.y -= (particle.velocity.y / 300)
particle.velocity.z -= (particle.velocity.z / 160)
};
var resetProperties = function() {
var pCount = particleCount;
while (pCount--) {
var particle = particles.vertices[pCount];
particle.destination = null
particle.updated = 0;
};
};
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
};
var distributedZ = function(level) {
var z;
if (level === 1) {
z = getRandomInt(50, 100);
} else if (level === 2) {
z = getRandomInt(350, 400);
} else {
z = getRandomInt(650, 700);
}
return z;
};
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
};
var disperse = function() {
pCount = particleCount;
for (var i = 0; i < pCount; i++) {
var particle = particles.vertices[i];
if (typeof(particle.destination) === "undefined") {
var nums = [-1, 1];
var x = particle.x + nums[Math.round(Math.random())];
var y = particle.y - 1000;
var z = Math.random() * 30 - 15;
addDestination(particle, x, y, z);
particle.velocity = new THREE.Vector3(x - particle.x, -3, z -
particle.z);
}
if (particle.updated <= 300) {
move(particle);
} else {
particles.vertices = shuffle(particles.vertices);
resetProperties();
dispersed = true;
return;
}
}
}
var morphImageParticles = function(imageParticles, rgba) {
for (var i = 0; i < imageParticles.length; i++) {
var particle = imageParticles[i]
if (particle.destination === null) {
var pixelData = rgba[i];
var x = pixelData[0];
var y = pixelData[1];
var z = Math.random() * 15 - 7;
addDestination(particle, x, y, z);
addVelocity(particle);
}
if (particle.updated <= 180) {
move(particle);
}
}
};
var morphOuterParticles = function(outerParticles, ord) {
for (var i = 0; i < outerParticles.length; i++) {
var nums = [-1, 1];
var particle = outerParticles[i];
if (particle.destination === null) {
var x = Math.random() * 1000 - 500;
var y = Math.random() * 1000 - 500;
var z;
if (i <= Math.round(outerParticles.length * 0.6)) {
z = distributedZ(1)
} else if (i > Math.round(outerParticles.length * 0.6) && i <
Math.round(outerParticles.length * 0.9)) {
z = distributedZ(2)
} else {
z = distributedZ(3);
}
addDestination(particle, x, y, z);
addVelocity(particle);
}
if (particle.updated <= 600) {
move(particle);
slowDown(particle);
} else {
particles.vertices = shuffle(particles.vertices);
resetProperties();
if (ord === 1) {
firstDone = true;
} else if (ord === 2) {
secondDone = true;
} else {
thirdDone = true;
}
return;
}
}
};
var makeImg = function(rgba, ord) {
var pCount = particleCount;
var imagePs = particles.vertices.slice(0, rgba.length);
var outerPs = particles.vertices.slice(rgba.length, pCount);
morphImageParticles(imagePs, rgba);
morphOuterParticles(outerPs, ord);
};
var update = function() {
if (thirdDone) {
} else if (secondDone) {
makeImg(tRgba, 3);
} else if (firstDone) {
makeImg(sRgba, 2);
} else if (dispersed) {
makeImg(fRgba, 1);
} else {
disperse();
}
particleSystem.geometry.verticesNeedUpdate = true;
renderer.render(scene, camera);
requestAnimationFrame(update);
TWEEN.update();
};
var rotXScale = d3.scale.linear().domain([0, window.innerHeight]).range([15,
-15]);
var rotYScale = d3.scale.linear().domain([0, window.innerWidth]).range([25,
-25]);
d3.select("body").on("mousemove", function() {
var scaledX = rotXScale(d3.mouse(this)[1]) * Math.PI / 180;
var scaledY = rotYScale(d3.mouse(this)[0]) * Math.PI / 180;
var tween = new TWEEN.Tween(particleSystem.rotation).to({ x: scaledX, y:
scaledY, z: 0 });
tween.easing( TWEEN.Easing.Quartic.Out);
tween.start();
transparency: true
});
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
img1.onload = function() {
drawImage(this, fRgba);
img2.onload = function() {
drawImage(this, sRgba);
img3.onload = function() {
drawImage(this, tRgba);
}
img3.src = "images/p1.png";
}
img2.src = "images/p2.png";
update();
}
img1.src = "images/p3.png";
update();
I thought I only need to add the code below, for example ['0xffffff'], that's how it should work at least but it didn't. Therefore I guess the problem is somewhere else in the script.
var fRgba = []; // first img rgba data
var sRgba = []; // second img rgba data
var tRgba = []; // third img rgba data
As on the attached fiddle, the background image on the canvas is just coming and getting disappearing
I tried both createPattern and drawImage both are having same issue.
I am not an expert in Canvas. Any help would be appreciated
(function(){
var canvas = document.getElementById('c'),
/** #type {CanvasRenderingContext2D} */
ctx = canvas.getContext('2d'),
width = 400,
height = 400,
half_width = width >> 1,
half_height = height >> 1,
size = width * (height + 2) * 2,
delay = 30,
oldind = width,
newind = width * (height + 3),
riprad = 3,
ripplemap = [],
last_map = [],
ripple,
texture,
line_width = 20,
step = line_width * 2,
count = height / line_width;
canvas.width = width;
canvas.height = height;
/*
* Water ripple demo can work with any bitmap image
*/
var imageObj = new Image();
imageObj.onload = function() {
var pattern = ctx.createPattern(imageObj, 'repeat');
ctx.rect(0, 0, width, height);
ctx.fillStyle = pattern;
ctx.fill();
ctx.save();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/wood-pattern.png';
with (ctx) {
fillStyle = '#ccc';
fillRect(0, 0, width, height);
fillStyle = '#999999';
save();
rotate(-0.785);
for (var i = 0; i < count; i++) {
fillRect(-width, i * step, width * 3, line_width);
}
}
texture = ctx.getImageData(0, 0, width, height);
ripple = ctx.getImageData(0, 0, width, height);
for (var i = 0; i < size; i++) {
last_map[i] = ripplemap[i] = 0;
}
/**
* Main loop
*/
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
}
/**
* Disturb water at specified point
*/
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var j = dy - riprad; j < dy + riprad; j++) {
for (var k = dx - riprad; k < dx + riprad; k++) {
ripplemap[oldind + (j * width) + k] += 128;
}
}
}
/**
* Generates new ripples
*/
function newframe() {
var a, b, data, cur_pixel, new_pixel, old_data;
var t = oldind; oldind = newind; newind = t;
var i = 0;
// create local copies of variables to decrease
// scope lookup time in Firefox
var _width = width,
_height = height,
_ripplemap = ripplemap,
_last_map = last_map,
_rd = ripple.data,
_td = texture.data,
_half_width = half_width,
_half_height = half_height;
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
data -= _ripplemap[_newind];
data -= data >> 5;
_ripplemap[_newind] = data;
//where data=0 then still, where data>0 then wave
data = 1024 - data;
old_data = _last_map[i];
_last_map[i] = data;
if (old_data != data) {
//offsets
a = (((x - _half_width) * data / 1024) << 0) + _half_width;
b = (((y - _half_height) * data / 1024) << 0) + _half_height;
//bounds check
if (a >= _width) a = _width - 1;
if (a < 0) a = 0;
if (b >= _height) b = _height - 1;
if (b < 0) b = 0;
new_pixel = (a + (b * _width)) * 4;
cur_pixel = i * 4;
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
}
++i;
}
}
}
canvas.onmousemove = function(/* Event */ evt) {
disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
};
setInterval(run, delay);
// generate random ripples
var rnd = Math.random;
var timeOut;
var intrvl = setInterval(function() {
clearTimeout(timeOut);
disturb(0, (height/40));
disturb((width/2.67), (height/40));
disturb((width/1.33), (height/40));
disturb(0, (height/2.67));
disturb((width/2.67), (height/2.67));
disturb((width/1.33), (height/2.67));
disturb(0, (height/1.33));
disturb((width/2.67), (height/1.33));
disturb((width/1.33), (height/1.33));
timeOut= setTimeout(function(){
disturb((width/1.8), (height/8));
disturb((width/-1.2), (height/8));
disturb((width/1.14), (height/8));
disturb((width/1.8), (height/2.13));
disturb((width/-1.2), (height/2.13));
disturb((width/1.14), (height/2.13));
disturb((width/1.8), (height/1.03));
disturb((width/-1.2), (height/1.03));
disturb((width/1.14), (height/1.03));;
},300);
}, 700);
setTimeout(function(){
clearInterval(intrvl);
},3000);
})();
this is the link to the fiddle
I have this animation which moves a row of circles from A(x,y) to B(x,y). ButI'm having trouble trying to replicate this into an array of circles where each row moves (one after another) from A to B. However, I also want to maintain the original location of the array so that essentially, it makes a copy of the row and moves the copy. Any help would be greatly appreciated!
EDIT: I have edited the code so that it now has two rows that remain stationary when one is moving - but now, I want to be able to move more than one row (as described in the example below).
EDIT 2: Here's a jsfiddle instead so it's easier to understand what I mean.
https://jsfiddle.net/vLvk1bsc/2/
For example, I want to emulate something like this.
ORIGINAL ----------------- NEW
r r r r r r. --------------- A. g g g g g g
p p p p p p ------------ B. r r r r r r
g g g g g g ------------ C. r r r r r r
The sequence of the animation would therefore be as follows:
3 --- a. A copy of row 3 moves to row A
1 --- b. A copy of row 1 moves to row B
1 --- c. A copy of row 1 moves to row C
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
setTimeout(function () {
draw();
animate(movingRow2);
}, 100);
var movingRow = [];
var frozenRow = [];
var cx = 50;
var cy = 70;
for (var i = 0; i < 6; i++) {
movingRow.push({ x: cx, y: cy, borderWidth: 1, color: "orange"});
frozenRow.push({ x: cx, y: cy, borderWidth: 1, color: "blue"});
cx += 40;
}
var movingRow2 = [];
var frozenRow2 = [];
var cx = 50;
var cy = 110;
for (var i = 0; i < 6; i++) {
movingRow2.push({ x: cx, y: cy, borderWidth: 1, color: "green"});
frozenRow2.push({ x: cx, y: cy, borderWidth: 1, color: "pink"});
cx += 40;
}
function drawCircle(myCircle, context) {
context.beginPath();
context.arc(myCircle.x, myCircle.y, 15, 0, 2 * Math.PI);
context.fillStyle = myCircle.color;
context.fill();
context.stroke();
context.closePath();
}
function draw() {
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < movingRow.length; i++) {
drawCircle(movingRow[i], context);
drawCircle(frozenRow[i], context);
drawCircle(movingRow2[i], context);
drawCircle(frozenRow2[i], context);
}
}
var newX = 320;
var newY = 70;
var pathArray = [];
pathArray.push({
x: movingRow2[0].x,
y: movingRow2[0].y
});
pathArray.push({
x: newX,
y: newY
});
var polyPoints = makePolyPoints(pathArray);
var position = 0;
var speed = 1;
function animate(m) {
// calculate the new position
position += speed;
if (position > polyPoints.length - 1) {
return;
}
// a single point in the array
var pt = polyPoints[position];
var step = 0;
// update x and y
for (var i = 0; i < m.length; i++) {
m[i].x = pt.x + step;
m[i].y = pt.y;
step += 40;
}
draw();
// request new frame
requestAnimationFrame(function() {
animate(m);
});
}
function makePolyPoints(pathArray) {
// list of points for each frame of the shape
var points = [];
// how quickly the transition occurs
var speed = 150;
for (var i = 1; i < pathArray.length; i++) {
var startPt = pathArray[i - 1];
var endPt = pathArray[i];
// calculate difference between start and end points
var dx = endPt.x - startPt.x;
var dy = endPt.y - startPt.y;
for (var n = 0; n <= speed; n++) {
// calculate the x and y positions for each frame
var x = startPt.x + dx * n / speed;
var y = startPt.y + dy * n / speed;
// append the points to the array to be used in the animation
points.push({
x: x,
y: y
});
}
}
return points;
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
setTimeout(function () {
draw();
var a = anims[anims_i];
animate(a[0], a[1]);
}, 100);
var rowA = [];
var rowB = [];
var rowC = [];
var cx = 50;
var cy = 70;
for (var i = 0; i < 6; i++) {
rowA.push({ x: cx, y: cy-40, borderWidth: 1, color: "orange"});
rowB.push({ x: cx, y: cy, borderWidth: 1, color: "blue"});
rowC.push({ x: cx, y: cy+40, borderWidth: 1, color: "pink"});
cx += 40;
}
var rowACopy1 = JSON.parse(JSON.stringify(rowA));
var rowACopy2 = JSON.parse(JSON.stringify(rowA));
var rowCCopy = JSON.parse(JSON.stringify(rowC));
var offsetX = 270;
var polyPointsA1 = makePolyPoints([
{x: rowA[0].x, y: rowA[0].y},
{x: rowB[0].x+offsetX, y: rowB[0].y}
]);
var polyPointsA2 = makePolyPoints([
{x: rowA[0].x, y: rowA[0].y},
{x: rowC[0].x+offsetX, y: rowC[0].y}
]);
var polyPointsC = makePolyPoints([
{x: rowC[0].x, y: rowC[0].y},
{x: rowA[0].x+offsetX, y: rowA[0].y}
]);
var anims = [
[rowCCopy, polyPointsC],
[rowACopy1, polyPointsA1],
[rowACopy2, polyPointsA2]
];
var anims_i = 0;
function drawCircle(myCircle, context) {
context.beginPath();
context.arc(myCircle.x, myCircle.y, 15, 0, 2 * Math.PI);
context.fillStyle = myCircle.color;
context.fill();
context.stroke();
context.closePath();
}
function draw() {
context.save();
context.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < rowA.length; i++) {
drawCircle(rowA[i], context);
drawCircle(rowB[i], context);
drawCircle(rowC[i], context);
drawCircle(rowACopy1[i], context);
drawCircle(rowACopy2[i], context);
drawCircle(rowCCopy[i], context);
}
}
var position = 0;
var speed = 1;
function animate(m, polyPoints) {
// calculate the new position
position += speed;
if (position > polyPoints.length - 1) {
position = 0;
anims_i++;
if (anims_i < anims.length) {
var a = anims[anims_i];
requestAnimationFrame(function() {
animate(a[0], a[1]);
});
}
return;
}
// a single point in the array
var pt = polyPoints[position];
var step = 0;
// update x and y
for (var i = 0; i < m.length; i++) {
m[i].x = pt.x + step;
m[i].y = pt.y;
step += 40;
}
draw();
// request new frame
requestAnimationFrame(function() {
animate(m, polyPoints);
});
}
function makePolyPoints(pathArray) {
// list of points for each frame of the shape
var points = [];
// how quickly the transition occurs
var speed = 150;
for (var i = 1; i < pathArray.length; i++) {
var startPt = pathArray[i - 1];
var endPt = pathArray[i];
// calculate difference between start and end points
var dx = endPt.x - startPt.x;
var dy = endPt.y - startPt.y;
for (var n = 0; n <= speed; n++) {
// calculate the x and y positions for each frame
var x = startPt.x + dx * n / speed;
var y = startPt.y + dy * n / speed;
// append the points to the array to be used in the animation
points.push({
x: x,
y: y
});
}
}
return points;
}
#canvas {
border:1px solid red;
}
<canvas id="canvas" width="580"></canvas>