]> git.r.bdr.sh - rbdr/heart/blob - js/lib/heart_renderer.js
Add CI status to README
[rbdr/heart] / js / lib / heart_renderer.js
1 'use strict';
2
3 ((window) => {
4
5 const kColorIteratorLimit = 256;
6 const kRedSpeed = 0.1;
7 const kGreenSpeed = 0.2;
8 const kBlueSpeed = 0.15;
9
10 /**
11 * Renders a Heart, has its own canvas, which will be placed in the element
12 * set by calling #render.
13 *
14 * @class HeartRenderer
15 * @param {object} config configuration, extends any member of the renderer
16 */
17 const HeartRenderer = class HeartRenderer {
18
19 constructor(config) {
20
21 /**
22 * The instance of the heart renderer being used
23 *
24 * @memberof HeartRenderer
25 * @instance
26 * @name canvas
27 * @type HTMLCanvasElement
28 * @default A brand new full width and height canvas
29 */
30 this.canvas = window.document.createElement('canvas');
31 this.canvas.style.height = '100%';
32 this.canvas.style.width = '100%';
33
34 /**
35 * The maximum fps that will be used
36 *
37 * @memberof HeartRenderer
38 * @instance
39 * @name fps
40 * @type Number
41 * @default 60
42 */
43 this.fps = 60;
44
45 this._animating = false; // The status of the animation.
46 this._previousFrameTime = Date.now(); // The timestamp of the last frame for fps control
47 this._currentColor = { // The current color that will be painted
48 red: 100,
49 blue: 0,
50 green: 50
51 };
52
53 Object.assign(this, config);
54 }
55
56 /**
57 * Attaches the canvas to an HTML element
58 *
59 * @memberof HeartRenderer
60 * @function render
61 * @instance
62 * @param {HTMLElement} element the element where we will attach our canvas
63 */
64 render(element) {
65
66 element.appendChild(this.canvas);
67 }
68
69 /**
70 * Gets the context from the current canvas and starts the animation process
71 *
72 * @memberof HeartRenderer
73 * @function activate
74 * @instance
75 */
76 activate() {
77
78 const context = this.canvas.getContext('2d');
79 this._startAnimating(context);
80 }
81
82 /**
83 * Stops the animation process
84 *
85 * @memberof HeartRenderer
86 * @function deactivate
87 * @instance
88 */
89 deactivate() {
90
91 this._stopAnimating();
92 }
93
94 // Starts the animation loop
95 _startAnimating(context) {
96
97 this._frameDuration = 1000 / this.fps;
98 this._animating = true;
99
100 this._animate(context);
101 }
102
103 // Stops the animation on the next frame.
104 _stopAnimating() {
105
106 this._animating = false;
107 }
108
109 // Runs the animation step controlling the FPS
110 _animate(context) {
111
112 if (!this._animating) {
113 return;
114 }
115
116 window.requestAnimationFrame(this._animate.bind(this, context));
117
118 const currentFrameTime = Date.now();
119 const delta = currentFrameTime - this._previousFrameTime;
120
121 if (delta > this._frameDuration) {
122 this._previousFrameTime = Date.now();
123 this._animateStep(context, delta);
124 }
125 }
126
127 // The actual animation processing function.
128 _animateStep(context, delta) {
129
130 this._currentColor.red = Math.round(this._currentColor.red + delta * kRedSpeed) % kColorIteratorLimit;
131 this._currentColor.green = Math.round(this._currentColor.green + delta * kGreenSpeed) % kColorIteratorLimit;
132 this._currentColor.blue = Math.round(this._currentColor.blue + delta * kBlueSpeed) % kColorIteratorLimit;
133
134 context.fillStyle = `rgb(${this._currentColor.red}, ${this._currentColor.green}, ${this._currentColor.blue})`;
135 context.fillRect(0, 0, this.canvas.scrollWidth, this.canvas.scrollHeight);
136 }
137 };
138
139
140 window.HeartRenderer = HeartRenderer;
141 })(window);