]>
git.r.bdr.sh - rbdr/heart/blob - js/lib/heart_renderer.js
fd4adf6452e511e7090b1b0e7519dd467ef6829b
5 const kColorIteratorLimit
= 256;
7 const kGreenSpeed
= 0.2;
8 const kBlueSpeed
= 0.15;
11 * Renders a Heart, has its own canvas, which will be placed in the element
12 * set by calling #render.
14 * @class HeartRenderer
15 * @param {object} config configuration, extends any member of the renderer
17 const HeartRenderer
= class HeartRenderer
{
22 * The instance of the heart renderer being used
24 * @memberof HeartRenderer
27 * @type HTMLCanvasElement
28 * @default A brand new canvas
30 this.canvas
= window
.document
.createElement('canvas');
33 * The maximum fps that will be used
35 * @memberof HeartRenderer
44 * The size of the heart as a percentage of the canvas smallest dimension
46 * @memberof HeartRenderer
54 this._animating
= false; // The status of the animation.
55 this._previousFrameTime
= Date
.now(); // The timestamp of the last frame for fps control
56 this._currentColor
= { // The current color that will be painted
62 Object
.assign(this, config
);
66 * Attaches the canvas to an HTML element
68 * @memberof HeartRenderer
71 * @param {HTMLElement} element the element where we will attach our canvas
75 element
.appendChild(this.canvas
);
82 * @memberof HeartRenderer
85 * @param {HTMLElement} element the element where we will attach our canvas
89 if (this.canvas
.parentElement
) {
90 this.canvas
.width
= this.canvas
.parentElement
.offsetWidth
;
91 this.canvas
.height
= this.canvas
.parentElement
.offsetHeight
;
96 * Gets the context from the current canvas and starts the animation process
98 * @memberof HeartRenderer
104 const context
= this.canvas
.getContext('2d');
105 this._startAnimating(context
);
109 * Stops the animation process
111 * @memberof HeartRenderer
112 * @function deactivate
117 this._stopAnimating();
120 // Starts the animation loop
121 _startAnimating(context
) {
123 this._frameDuration
= 1000 / this.fps
;
124 this._animating
= true;
126 this._animate(context
);
129 // Stops the animation on the next frame.
132 this._animating
= false;
135 // Runs the animation step controlling the FPS
138 if (!this._animating
) {
142 window
.requestAnimationFrame(this._animate
.bind(this, context
));
144 const currentFrameTime
= Date
.now();
145 const delta
= currentFrameTime
- this._previousFrameTime
;
147 if (delta
> this._frameDuration
) {
148 this._previousFrameTime
= Date
.now();
149 this._animateStep(context
, delta
);
153 // The actual animation processing function.
154 _animateStep(context
, delta
) {
156 this._updateColor(delta
);
157 this._drawHeart(context
, delta
);
160 // Updates the current color
161 _updateColor(delta
) {
163 this._currentColor
.red
= Math
.round(this._currentColor
.red
+ delta
* kRedSpeed
) % kColorIteratorLimit
;
164 this._currentColor
.green
= Math
.round(this._currentColor
.green
+ delta
* kGreenSpeed
) % kColorIteratorLimit
;
165 this._currentColor
.blue
= Math
.round(this._currentColor
.blue
+ delta
* kBlueSpeed
) % kColorIteratorLimit
;
169 _drawHeart(context
, delta
) {
171 const canvasHeight
= this.canvas
.height
;
172 const canvasWidth
= this.canvas
.width
;
174 const referenceDimension
= canvasWidth
< canvasHeight
? canvasWidth : canvasHeight
;
176 const heartSize
= Math
.round(referenceDimension
* this.heartSize
* .01);
177 const radius
= heartSize
/ 2;
178 const canvasCenterX
= Math
.round(canvasWidth
/ 2);
179 const canvasCenterY
= Math
.round(canvasHeight
/ 2);
180 const centerX
= -radius
;
181 const centerY
= -radius
;
184 // translate and rotate, adjusting for weight of the heart.
185 context
.translate(canvasCenterX
, canvasCenterY
+ radius
/ 4);
186 context
.rotate(-45 * Math
.PI
/ 180);
188 // Fill the ventricles of the heart
189 context
.fillStyle
= `rgb(${this._currentColor.red}, ${this._currentColor.green}, ${this._currentColor.blue})`;
190 context
.fillRect(centerX
, centerY
, heartSize
, heartSize
);
194 context
.arc(centerX
+ radius
, centerY
, radius
, 0, 2 * Math
.PI
, false);
200 context
.arc(centerX
+ heartSize
, centerY
+ radius
, radius
, 0, 2 * Math
.PI
, false);
204 context
.setTransform(1, 0, 0, 1, 0, 0);
209 window
.HeartRenderer
= HeartRenderer
;