]> git.r.bdr.sh - rbdr/heart/commitdiff
Add basic animator project
authorBen Beltran <redacted>
Thu, 10 Nov 2016 05:41:37 +0000 (23:41 -0600)
committerBen Beltran <redacted>
Thu, 10 Nov 2016 05:41:37 +0000 (23:41 -0600)
README.md
css/app.css [new file with mode: 0644]
index.html [new file with mode: 0644]
js/app.js [new file with mode: 0644]
js/lib/heart_renderer.js [new file with mode: 0644]

index e55907e63d303a171deee374277eff928da8a08f..6238f4662597d9834aa70f4412e61930a625300a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,2 +1,22 @@
-# heart
-The heart
+# Heart
+
+Renders a colorful heart
+
+## How to run
+
+Serve the files in the root directory. For example using: `python -m SimpleHTTPServer`
+
+## Setting up
+
+Though this project is mostly static you should run `yarn install` or
+`npm install` so you can lint and document the project.
+
+## Generating documentation
+
+1. Run `npm run document`.
+2. Serve the files that have been generated in the `doc` directory. If
+   already serving the files, just go to `/doc`
+
+## Linting
+
+1. Run `npm lint`
diff --git a/css/app.css b/css/app.css
new file mode 100644 (file)
index 0000000..5f63708
--- /dev/null
@@ -0,0 +1,9 @@
+* {
+  margin: 0;
+  padding: 0;
+}
+
+#heart-app-entry-point {
+  height: 100vh;
+  width: 100vw;
+}
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..cf7fa03
--- /dev/null
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+  <head>
+    <title>❤️</title>
+
+    <link href="/css/app.css" rel="stylesheet">
+
+    <script src="/js/lib/heart_renderer.js"></script>
+
+    <script src="/js/app.js"></script>
+  </head>
+  <body>
+    <div id="heart-app-entry-point"></div>
+  </body>
+</html>
diff --git a/js/app.js b/js/app.js
new file mode 100644 (file)
index 0000000..25d581d
--- /dev/null
+++ b/js/app.js
@@ -0,0 +1,31 @@
+'use strict';
+
+// Sets up the application
+
+((window) => {
+
+  const internals = {};
+
+  internals.onLoad = () => {
+
+    const mainElement = window.document.getElementById('heart-app-entry-point');
+    const heartRenderer = new HeartRenderer();
+
+    heartRenderer.render(mainElement);
+    heartRenderer.activate();
+
+    /**
+     * Exported global object. This will contain the instance of the heart
+     * renderer being used. It is set up on load.
+     *
+     * @name App
+     * @type Object
+     * @property {HeartRenderer} heartRenderer The instance of the heart renderer being used.
+     */
+    window.App = {
+      heartRenderer
+    };
+  };
+
+  window.addEventListener('load', internals.onLoad);
+})(window);
diff --git a/js/lib/heart_renderer.js b/js/lib/heart_renderer.js
new file mode 100644 (file)
index 0000000..f6ece86
--- /dev/null
@@ -0,0 +1,141 @@
+'use strict';
+
+((window) => {
+
+  const kColorIteratorLimit = 256;
+  const kRedSpeed = 0.1;
+  const kGreenSpeed = 0.2;
+  const kBlueSpeed = 0.15;
+
+  /**
+   * Renders a Heart, has its own canvas, which will be placed in the element
+   * set by calling #render.
+   *
+   * @class HeartRenderer
+   * @param {object} config configuration, extends any member of the renderer
+   */
+  const HeartRenderer = class HeartRenderer {
+
+    constructor(config) {
+
+      /**
+       * The instance of the heart renderer being used
+       *
+       * @memberof HeartRenderer
+       * @instance
+       * @name canvas
+       * @type HTMLCanvasElement
+       * @default A brand new full width and height canvas
+       */
+      this.canvas = window.document.createElement('canvas');
+      this.canvas.style.height = '100%';
+      this.canvas.style.width = '100%';
+
+      /**
+       * The maximum fps that will be used
+       *
+       * @memberof HeartRenderer
+       * @instance
+       * @name fps
+       * @type Number
+       * @default 60
+       */
+      this.fps = 60;
+
+      this._animating = false; // The status of the animation.
+      this._previousFrameTime = Date.now(); // The timestamp of the last frame for fps control
+      this._currentColor = { // The current color that will be painted
+        red: 100,
+        blue: 0,
+        green: 50
+      };
+
+      Object.assign(this, config);
+    }
+
+    /**
+     * Attaches the canvas to an HTML element
+     *
+     * @memberof HeartRenderer
+     * @function render
+     * @instance
+     * @param {HTMLElement} element the element where we will attach our canvas
+     */
+    render(element) {
+
+      element.appendChild(this.canvas);
+    }
+
+    /**
+     * Gets the context from the current canvas and starts the animation process
+     *
+     * @memberof HeartRenderer
+     * @function activate
+     * @instance
+     */
+    activate() {
+
+      const context = this.canvas.getContext('2d');
+      this._startAnimating(context);
+    }
+
+    /**
+     * Stops the animation process
+     *
+     * @memberof HeartRenderer
+     * @function deactivate
+     * @instance
+     */
+    deactivate() {
+
+      this._stopAnimating();
+    }
+
+    // Starts the animation loop
+    _startAnimating(context) {
+
+      this._frameDuration = 1000 / this.fps;
+      this._animating = true;
+
+      this._animate(context);
+    }
+
+    // Stops the animation on the next frame.
+    _stopAnimating() {
+
+      this._animating = false;
+    }
+
+    // Runs the animation step controlling the FPS
+    _animate(context) {
+
+      if (!this._animating) {
+        return;
+      }
+
+      window.requestAnimationFrame(this._animate.bind(this, context));
+
+      const currentFrameTime = Date.now();
+      const delta = currentFrameTime - this._previousFrameTime;
+
+      if (delta > this._frameDuration) {
+        this._previousFrameTime = Date.now();
+        this._animateStep(context, delta);
+      }
+    }
+
+    // The actual animation processing function.
+    _animateStep(context, delta) {
+
+      this._currentColor.red = Math.round(this._currentColor.red + delta * kRedSpeed) % kColorIteratorLimit;
+      this._currentColor.green = Math.round(this._currentColor.green + delta * kGreenSpeed) % kColorIteratorLimit;
+      this._currentColor.blue = Math.round(this._currentColor.blue + delta * kBlueSpeed) % kColorIteratorLimit;
+
+      context.fillStyle = `rgb(${this._currentColor.red}, ${this._currentColor.green}, ${this._currentColor.blue})`;
+      context.fillRect(0, 0, this.canvas.scrollWidth, this.canvas.scrollHeight);
+    }
+  };
+
+
+  window.HeartRenderer = HeartRenderer;
+})(window);