]>
git.r.bdr.sh - rbdr/sorting-hat-renderer/blob - lib/components/wave_renderer.js
2 import DataService
from '../services/data';
13 michaelangelo: 'orange',
25 scale(value
, min
, max
) {
27 return ((value
- min
) / (max
- min
)) * (internals
.kMaxValue
- internals
.kMinValue
) - internals
.kMinValue
;
32 * The wave renderer, draws some waves in a canvas to represent a set of
33 * cateogirzed averages
37 export default Vue
.component('waveRenderer', {
38 template: '<transition name="fade">' +
39 '<canvas v-show="state === 1" class="wave-renderer"></canvas>' +
42 data: DataService
.data
,
46 // Convert from the min / max value in the measurement to a
47 // predefined min value between 0 and 100 (see kMinValue and
48 // kMaxValue for actual values)
52 const keys
= Object
.keys(this.runningAverages
);
54 const averages
= keys
.reduce((averagesObject
, averageCategory
) => {
56 const runningAverage
= this.runningAverages
[averageCategory
];
57 averagesObject
[averageCategory
] = runningAverage
.average
;
58 return averagesObject
;
61 const max
= Math
.max(...Object
.values(averages
));
62 const min
= Math
.min(...Object
.values(averages
));
64 const scaledAverages
= Object
.keys(averages
).reduce((scaledAveragesObject
, averageCategory
) => {
66 const value
= averages
[averageCategory
];
67 scaledAveragesObject
[averageCategory
] = internals
.scale(value
, min
, max
);
68 return scaledAveragesObject
;
71 return scaledAverages
;
77 // Reset the size of the canvas on resize
81 this.$el
.width
= window
.innerWidth
;
82 this.$el
.height
= window
.innerHeight
;
86 // Initiates the animation loop
90 // Make sure we resize, do an initial sizing
92 window
.addEventListener('resize', this.onResize
.bind(this));
95 // Start the whole animation (Sorry it's a mess)
97 const canvas
= this.$el
;
99 const context
= canvas
.getContext('2d');
100 const interval
= 1000 / internals
.kTargetFPS
;
102 let lastTimestamp
= 0;
104 const animationHandler
= (timestamp
) => {
106 window
.requestAnimationFrame(animationHandler
);
107 const delta
= timestamp
- lastTimestamp
;
109 if (delta
> interval
) {
111 const keys
= Object
.keys(this.scaledAverages
);
112 const values
= Object
.values(this.scaledAverages
);
113 const segments
= keys
.length
;
114 const period
= canvas
.width
/ segments
;
116 const fillGradient
= context
.createLinearGradient(0, 0, canvas
.width
, 0);
117 const gradientBandWidth
= 1 / segments
;
119 // Position the drawing cursor left-center of screen
121 context
.clearRect(0, 0, canvas
.width
, canvas
.height
);
123 context
.moveTo(0, canvas
.height
);
124 context
.lineTo(0, canvas
.height
/ 2);
126 // Iterate over the segments
128 for (let i
= 0; i
< segments
; ++i
) {
129 const segmentStart
= i
* period
;
131 const category
= keys
[i
];
132 const magnitude
= values
[i
];
133 const segmentHeight
= Math
.round(Math
.random() * internals
.kRandomJitter
+ magnitude
* (canvas
.height
/ 2) / 100);
135 // Calculate the gradient using the correct color according to
138 const color
= internals
.kColors
[category
] || 'black';
139 let currentGradientPosition
= i
* gradientBandWidth
+ internals
.kGradientFade
;
140 fillGradient
.addColorStop(currentGradientPosition
, color
);
141 currentGradientPosition
= (i
+ 1) * gradientBandWidth
- internals
.kGradientFade
;
142 fillGradient
.addColorStop(currentGradientPosition
, color
);
144 // This draws the sine wave
146 for (let j
= 0; j
< 180; ++j
) {
147 const currentPixel
= segmentStart
+ j
* period
/ 180;
148 const currentAngle
= j
+ 180 * (i
% 2);
149 const currentRadians
= currentAngle
* Math
.PI
/ 180;
150 const currentHeight
= segmentHeight
* Math
.sin(internals
.kFrequency
* currentRadians
);
152 context
.lineTo(currentPixel
, currentHeight
+ canvas
.height
/ 2);
156 context
.lineTo(canvas
.width
, canvas
.height
/ 2);
157 context
.lineTo(canvas
.width
, canvas
.height
);
158 context
.fillStyle
= fillGradient
;
161 lastTimestamp
= timestamp
;
165 window
.requestAnimationFrame(animationHandler
);