]>
git.r.bdr.sh - rbdr/heart/blob - js/lib/heart_renderer.js
78ca182e96f4a38c061685ea66c255a488dc154c
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._following
= null; // The status of mouse follow.
56 this._animating
= false; // The status of the animation.
57 this._previousFrameTime
= Date
.now(); // The timestamp of the last frame for fps control
58 this._currentColor
= { // The current color that will be painted
64 this.startFollowingMouse();
66 Object
.assign(this, config
);
70 * Attaches the canvas to an HTML element
72 * @memberof HeartRenderer
75 * @param {HTMLElement} element the element where we will attach our canvas
79 element
.appendChild(this.canvas
);
86 * @memberof HeartRenderer
92 if (this.canvas
.parentElement
) {
93 this.canvas
.width
= this.canvas
.parentElement
.offsetWidth
;
94 this.canvas
.height
= this.canvas
.parentElement
.offsetHeight
;
101 * @memberof HeartRenderer
102 * @function startFollowingMouse
105 startFollowingMouse() {
107 if (!this._following
) {
108 console
.log('Start Following Mouse');
109 this._following
= this._setCenterFromMouse
.bind(this);
110 this.canvas
.addEventListener('mousemove', this._following
);
115 * Stop following the mouse
117 * @memberof HeartRenderer
118 * @function stopFollowingMouse
121 stopFollowingMouse() {
123 if (this._following
) {
124 console
.log('Stop Following Mouse');
125 this.canvas
.removeEventListener('mouseover', this._following
);
126 this._following
= null;
132 * Gets the context from the current canvas and starts the animation process
134 * @memberof HeartRenderer
140 const context
= this.canvas
.getContext('2d');
141 this._startAnimating(context
);
145 * Stops the animation process
147 * @memberof HeartRenderer
148 * @function deactivate
153 this._stopAnimating();
156 // Starts the animation loop
157 _startAnimating(context
) {
159 this._frameDuration
= 1000 / this.fps
;
160 this._animating
= true;
162 this._animate(context
);
165 // Stops the animation on the next frame.
168 this._animating
= false;
171 // Runs the animation step controlling the FPS
174 if (!this._animating
) {
178 window
.requestAnimationFrame(this._animate
.bind(this, context
));
180 const currentFrameTime
= Date
.now();
181 const delta
= currentFrameTime
- this._previousFrameTime
;
183 if (delta
> this._frameDuration
) {
184 this._previousFrameTime
= Date
.now();
185 this._animateStep(context
, delta
);
189 // The actual animation processing function.
190 _animateStep(context
, delta
) {
192 this._updateColor(delta
);
193 this._drawHeart(context
, delta
);
196 // Updates the current color
197 _updateColor(delta
) {
199 this._currentColor
.red
= Math
.round(this._currentColor
.red
+ delta
* kRedSpeed
) % kColorIteratorLimit
;
200 this._currentColor
.green
= Math
.round(this._currentColor
.green
+ delta
* kGreenSpeed
) % kColorIteratorLimit
;
201 this._currentColor
.blue
= Math
.round(this._currentColor
.blue
+ delta
* kBlueSpeed
) % kColorIteratorLimit
;
205 _drawHeart(context
, delta
) {
207 const canvasHeight
= this.canvas
.height
;
208 const canvasWidth
= this.canvas
.width
;
210 const referenceDimension
= canvasWidth
< canvasHeight
? canvasWidth : canvasHeight
;
212 const heartSize
= Math
.round(referenceDimension
* this.heartSize
* .01);
213 const radius
= heartSize
/ 2;
214 let canvasCenterX
= this._center
? this._center
.x : Math
.round(canvasWidth
/ 2);
215 let canvasCenterY
= this._center
? this._center
.y : Math
.round(canvasHeight
/ 2);
216 const centerX
= -radius
;
217 const centerY
= -radius
;
220 // translate and rotate, adjusting for weight of the heart.
221 context
.translate(canvasCenterX
, canvasCenterY
+ radius
/ 4);
222 context
.rotate(-45 * Math
.PI
/ 180);
224 // Fill the ventricles of the heart
225 context
.fillStyle
= `rgb(${this._currentColor.red}, ${this._currentColor.green}, ${this._currentColor.blue})`;
226 context
.fillRect(centerX
, centerY
, heartSize
, heartSize
);
230 context
.arc(centerX
+ radius
, centerY
, radius
, 0, 2 * Math
.PI
, false);
236 context
.arc(centerX
+ heartSize
, centerY
+ radius
, radius
, 0, 2 * Math
.PI
, false);
240 context
.setTransform(1, 0, 0, 1, 0, 0);
243 // Sets the center from mouse
244 _setCenterFromMouse (event
) {
245 this._center
= this._center
|| {};
247 console
.log('tracking');
249 this._center
.x
= event
.offsetX
;
250 this._center
.y
= event
.offsetY
;
255 window
.HeartRenderer
= HeartRenderer
;