> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.97Z3tT21JbK/rev.242
 * 
 * authors: 
 *   Amado
 *   
 *   
 *   
 *   
 *   Jim Connell
 *   

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



// Pressing Control-R will render this sketch.

      var IMAGE_SIDE = 300;

      // Step counts per hour
      var STEPS = [2182, 2277, 686, 139,
                   0, 0, 0, 0,
                   0, 0, 452, 12,
                   204, 896, 1505, 3218,
                   3530, 63, 74, 230,
                   8, 0, 0];


      // NOTE(jim): Needed so that the loadImage call in resetScene will work. This
      //            works around processing being a synchronous I/O language, while
      //            JavaScript is not.
      /* @pjs preload="http://iliketowastemytime.com/sites/default/files/mountain-peak-hd-wallpaper.jpg"; */
      PImage img;

      /** List of Drawable sprites in our scene. */
      ArrayList sprites;
      float FRAME_RATE = 32 / 4;

      /** The current frame of the scene (e.g. the number of times "draw()" has been called. */
      int frameCount = 0;

      /**
      * The sprite representing the background of the scene. Normally, this will erase
      * all other sprites.
      */
      var backgroundSprite = new Background();

      /**
       * An interface for an object we draw on the scene.
       */
      class Drawable {
        void computeNextStep(int width, int height, float frameRate) { }

        void draw() { }

        void reset() { }
      }

      class Background extends Drawable {
        void draw() {
          background(230);
          color(0, 0, 0);
          stroke(0, 0, 0);
          fill(255);

          // img = loadImage("mountain-peak-hd-wallpaper.jpg");
          img = loadImage("http://iliketowastemytime.com/sites/default/files/mountain-peak-hd-wallpaper.jpg")
          image(img, (IMAGE_SIDE - img.width) / 2 + 200, (IMAGE_SIDE - img.height) / 2);
        }
      }

      class StepCount extends Drawable {
        int stepCount;
        int height;
        int width;
        static int MAIN_STEP_CIRCLE_RADIUS = 60;

        StepCount(int stepCount) {
          this.stepCount = stepCount;
        }

        void computeNextStep(int width, int height, float frameRate) {
          this.width = width;
          this.height = height;
        }

        void draw() {
          ellipse(this.width / 2, this.height / 2, 2 * MAIN_STEP_CIRCLE_RADIUS, 2 * MAIN_STEP_CIRCLE_RADIUS);
          fill(0, 0, 0);
          textSize(32);
          var tw = textWidth(this.stepCount);
          text(this.stepCount, width / 2 - tw / 2, height / 2 + 10);
        }
      }

      class StepBubble {
        int x;
        int y;
        static int STEP_CIRCLE_RADIUS = 7;

        StepBubble(float angle, int position, int mainCircleRadius) {
          this.angle = angle;
          this.position = position;
          this.mainCircleRadius = mainCircleRadius;
        }

        void computeNextStep(int width, int height, float frameRate) {
          var length = (this.mainCircleRadius + 20 * (this.position + 1));
          this.x = width / 2 + sin(this.angle) * length;
          this.y = height / 2 + cos(this.angle) * length;
        }

        void draw() {
          fill(255);
          ellipse(this.x, this.y, 2 * STEP_CIRCLE_RADIUS, 2 * STEP_CIRCLE_RADIUS);
        }
      }

      class HourlySteps {
        int hour;
        int steps;
        StepBubble[] stepBubbles;

        HourlySteps(int hour, int steps) {
          this.hour = hour;
          this.steps = steps;

          var angle = TWO_PI * (STEPS.length / 2 - hour) / STEPS.length;
          this.stepBubbles = new StepBubble[Math.ceil(steps / 300)];
          for (var i = 0; i < this.stepBubbles.length; i++) {
            this.stepBubbles[i] = new StepBubble(angle, i, StepCount.MAIN_STEP_CIRCLE_RADIUS);
          }
        }

        void computeNextStep(int width, int height, float frameRate) {
          for (var i = 0; i < this.stepBubbles.length; i++) {
            this.stepBubbles[i].computeNextStep(width, height, frameRate);
          }
        }

        void draw() {
          for (var i = 0; i < this.stepBubbles.length; i++) {
            this.stepBubbles[i].draw();
          }
        }
      }

      void setup() {
        size(IMAGE_SIDE, IMAGE_SIDE);
        frameRate(FRAME_RATE);

        frameCount = 0;
        sprites = new ArrayList();
        var total = 0;

        for (var hour = 0; hour < STEPS.length; hour++) {
          var steps = STEPS[hour];
          if (steps < 1) {
            continue;
          }
          total += steps;
          sprites.add(new HourlySteps(hour, steps));
        }

        // Insert the step count as the first frame.
        sprites.add(0, new StepCount(total));
      }

      void draw() {
        var relativeFrame = frameCount % sprites.size();
        if (relativeFrame == 0) {
          backgroundSprite.computeNextStep(width, height, FRAME_RATE);
          backgroundSprite.draw();
        }

        sprites.get(relativeFrame).computeNextStep(width, height, FRAME_RATE);
        sprites.get(relativeFrame).draw();

        frameCount++;
      }