> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.nCmKPgZDmM9/rev.180
 * 
 * authors: 
 *   
 *   Fun Programming

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// Infinite draggable space. Use your mouse to drag the screen.

// The Java version has better colors: 
// http://www.openprocessing.org/sketch/64760
// I think it's because the noise() implementation is different
// in Java and in JavaScript

ThingCollection t;
int margin = 80;
int startDragX;
int startDragY;
int deltaX = 0;
int deltaY = 0;
int totDeltaX = 0;
int totDeltaY = 0;
int CX;
int CY;

void setup() {
  size(480, 400);
  noStroke();
  smooth();
  colorMode(HSB, 1);
  t = new ThingCollection();
  CX = width / 2;
  CY = height / 2;
  noLoop();
  draw();
}
void draw() {
  background(0);
  t.draw(deltaX, deltaY);
}
void mousePressed() {
  loop();
  startDragX = mouseX;
  startDragY = mouseY;
}
void mouseDragged() {
  deltaX = mouseX - startDragX;
  deltaY = mouseY - startDragY;
}
void mouseReleased() {
  totDeltaX += deltaX;
  totDeltaY += deltaY;
  t.move(deltaX, deltaY);
  deltaX = 0;
  deltaY = 0;
  noLoop();
}


class ThingCollection {
  Thing[] things;
  int amount;
  
  ThingCollection() {
    int sz = 40;
    int amtX = ((width+margin*2) / sz);
    int amtY = ((height+margin*2) / sz);
    int i = 0;
    float rSz = (width+margin*2) / float(amtX);
    amount = amtX * amtY;
    things = new Thing[amount];
    for(int x=0; x<amtX; x++) {
      for(int y=0; y<amtY; y++) {
        things[i++] = new Thing(x*rSz, y*rSz, rSz);
      }
    } 
  }
  
  void draw(int x, int y) {
    for(int i=0; i<amount; i++) {
      float nX = x + things[i].x;
      float nY = y + things[i].y;
      
      things[i].checkLimits(nX, nY);
      
      float a = atan2(nY-CY, nX-CX);
      float d = dist(CX, CY, nX, nY);
        
      things[i].setVector(d*cos(a), d*sin(a));
    }
    for(int n=0; n<10; n++) {
      for(int i=0; i<amount; i++) {
        things[i].draw(n);        
      }
    }    
  }
  void move(int x, int y) {
    for(int i=0; i<amount; i++) {
      things[i].move(x, y);
    }
  }
}


class Thing {
  float x;
  float y;
  float ax;
  float ay;
  float maxSz;
  float[] sizes = new float[int(random(1, 10))];

  Thing(float x, float y, float maxSz) {
    this.x = x;
    this.y = y;
    this.maxSz = maxSz;

    for(int i=0; i<sizes.length; i++) {
      sizes[i] = random(1);      
    }
    sizes[0] = 1.0;
    sizes = reverse(sort(sizes));
  }
  void setVector(float x, float y) {
    ax = x;
    ay = y;
  }
  void draw(int i) {
    if(i < sizes.length) { 
      float d = (1-sizes[i])*0.2+0.8;
      float s = sizes[i] * maxSz;      

      float hx = x-totDeltaX;
      float hy = y-totDeltaY;
      float hu = (noise(s/110, hx/666, hy/666) * 4) % 1;
      float sa = noise(hu*4 + hy/668, hx/668) * 1.2 - 0.2;
      float br = noise(hu*7 + hy/670, hx/670);
      fill(color(hu, sa, br));

      ellipse(CX+ax*d, CY+ay*d, s, s);
    }
  }
  void checkLimits(float x, float y) {
    if(x > width+margin) {
      this.x -= width+margin*2;
    } else if(x < -margin) {
      this.x += width+margin*2;
    }
    if(y > height+margin) {
      this.y -= height+margin*2;
    } else if(y < -margin) {
      this.y += height+margin*2;
    }
  }
  void move(int x, int y) {
    this.x += x;
    this.y += y;
  }
}