Skip to content

Commit a1dd1ae

Browse files
.
1 parent a950c8b commit a1dd1ae

1 file changed

Lines changed: 112 additions & 50 deletions

File tree

Lines changed: 112 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,160 @@
1+
/**
2+
* Run animation.
3+
*/
14
window.onload = () => {
25
'use strict';
36

4-
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
5-
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
7+
const canvas = document.getElementById('canvas');
8+
const effectDisplacement = document.querySelector('filter feDisplacementMap');
9+
const effectOffset = document.querySelector('filter feOffset');
610

7-
const effectDisplacement = document.querySelector('filter feDisplacementMap') as SVGFEDisplacementMapElement;
8-
const effectOffset = document.querySelector('filter feOffset') as SVGFEOffsetElement;
11+
const animation = new SvgCanvasAnimation({
12+
canvasElement: canvas,
13+
effectDisplacementElement: effectDisplacement,
14+
effectOffsetElement: effectOffset,
15+
});
916

10-
const centerX: number = canvas.width / 2;
11-
const centerY: number = canvas.height / 2;
12-
let offsetFactor: number = 0;
13-
let radians: number = 0;
14-
let i: number = 0;
17+
animation.start();
18+
};
19+
20+
/**
21+
* SVG + Canvas animation class.
22+
*/
23+
class SvgCanvasAnimation {
24+
canvas: HTMLCanvasElement;
25+
ctx: CanvasRenderingContext2D;
26+
effectDisplacement: SVGFEDisplacementMapElement;
27+
effectOffset: SVGFEOffsetElement;
28+
centerX: number;
29+
centerY: number;
30+
offsetFactor: number = 0;
31+
rotation: number = 0; // Radians
32+
frame: number = 0;
1533

1634
/**
17-
* Bad math - Values are ok for this screen size.
18-
* Moving mouse to center (on X) increases factor; boundaries will become close to 0.
19-
*
20-
* - scaleFactor: Determines max. possible result.
21-
* - offset: Left or right from center (must be positive).
22-
* Higher offset will cancel out with scale factor and become close to 0.
35+
* Constructor sets canvas and filter effect elements
36+
* plus initial values for starting the animation.
2337
*/
24-
function onMouseMove(event: MouseEvent) {
25-
const scaleFactor = centerX / 100;
26-
const offset = (event.offsetX - centerX) / 100;
38+
constructor({ canvasElement, effectDisplacementElement, effectOffsetElement }) {
39+
this.canvas = canvasElement as HTMLCanvasElement;
40+
this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
41+
42+
this.effectDisplacement = effectDisplacementElement as SVGFEDisplacementMapElement;
43+
this.effectOffset = effectOffsetElement as SVGFEOffsetElement;
44+
45+
this.centerX = this.canvas.width / 2;
46+
this.centerY = this.canvas.height / 2;
47+
}
48+
49+
/**
50+
* Public API –
51+
* Bind mouse event and start animation.
52+
*/
53+
start() {
54+
this.canvas.addEventListener('mousemove', this.onMouseMove);
2755

28-
offsetFactor = Math.abs(Math.abs(offset) - scaleFactor);
56+
this.loop();
2957
}
3058

3159
/**
3260
* Frame-by-frame render process.
61+
*
62+
* 1) Optional feature demonstrated – Artificial delay for better visibility:
63+
* To render every N-th frame only; change expression 'i % 1' to higher numbers.
64+
*
65+
* @private
3366
*/
34-
function loop() {
35-
// Artificial delay for better visibility:
36-
// To render every N-th frame only; change expression 'i % 1' to higher numbers.
37-
const renderFrame = i === 0 || i % 1 === 0;
67+
loop() {
68+
const frame = this.frame;
69+
const renderFrame = frame === 0 || frame % 1 === 0; // *1
3870

3971
if (renderFrame) {
40-
update();
41-
reset();
42-
draw();
72+
this.update();
73+
this.reset();
74+
this.draw();
4375
}
4476

45-
window.requestAnimationFrame(loop);
46-
i++;
77+
window.requestAnimationFrame(this.loop.bind(this));
78+
this.frame++;
4779
}
4880

4981
/**
5082
* Update effect values.
83+
*
84+
* @private
5185
*/
52-
function update() {
86+
update() {
87+
const effectDisplacement = this.effectDisplacement;
88+
const effectOffset = this.effectOffset;
89+
90+
const rnd: string = Math.random().toString();
5391
let scale: string = effectDisplacement.getAttribute('scale') + '';
54-
let rnd: string = Math.random().toString();
5592

56-
// Effect size - Added random values = Stronger distortion and 'vibration' effect
57-
scale = (16 + Math.sin(+scale) * offsetFactor).toString();
93+
// Effect size:
94+
// - Define minimum size (arbitrary number, what looks good)
95+
// - Add random values for distortion and 'vibration' effect
96+
scale = (16 + Math.sin(+scale) * this.offsetFactor).toString();
5897

59-
// Rotation speed
60-
radians += 0.05;
98+
// Rotation movement
99+
this.rotation += 0.05;
61100

62101
effectOffset.setAttribute('dx', rnd);
63102
effectOffset.setAttribute('dy', rnd);
64103
effectDisplacement.setAttribute('scale', scale);
65104
}
66105

67-
/**
68-
* Reset screen by partly transparent filling for a fading effect.
69-
*/
70-
function reset() {
71-
ctx.fillStyle = 'rgba(255, 255, 255, 0.25)';
72-
73-
ctx.fillRect(0, 0, canvas.width, canvas.height);
74-
}
75-
76106
/**
77107
* Draw rectangle at screen center.
108+
*
109+
* @private
78110
*/
79-
function draw() {
111+
draw() {
112+
const ctx = this.ctx;
113+
80114
ctx.save();
81115

82116
ctx.lineWidth = 24;
83117
ctx.strokeStyle = 'rgba(255, 192, 0, 1)';
84118

85-
ctx.translate(centerX, centerY);
86-
ctx.rotate(radians);
119+
ctx.translate(this.centerX, this.centerY);
120+
ctx.rotate(this.rotation);
87121
ctx.beginPath();
88122
ctx.rect(-100, -100, 200, 200);
89123
ctx.stroke();
90124

91125
ctx.restore();
92126
}
93127

94-
// Start
95-
canvas.addEventListener('mousemove', onMouseMove);
128+
/**
129+
* Reset screen by partly transparent filling for a fading effect.
130+
*
131+
* @private
132+
*/
133+
reset() {
134+
const canvas = this.canvas;
135+
const ctx = this.ctx;
96136

97-
loop();
98-
};
137+
ctx.fillStyle = 'rgba(255, 255, 255, 0.25)';
138+
139+
ctx.fillRect(0, 0, canvas.width, canvas.height);
140+
}
141+
142+
/**
143+
* Moving mouse to center (on X) increases effect factor; boundaries will become close to 0.
144+
* Values are ok for this screen size. Bad math ;)
145+
*
146+
* - scaleFactor: Determines max. possible effect result.
147+
* - offset: Left or right from center (must be positive in all cases).
148+
* - Higher offset will cancel out with scale factor and become close to 0.
149+
*
150+
* @private
151+
*/
152+
onMouseMove(event: MouseEvent) {
153+
const centerX = this.centerX;
154+
155+
const scaleFactor = centerX / 100;
156+
const offset = (event.offsetX - centerX) / 100;
157+
158+
this.offsetFactor = Math.abs(Math.abs(offset) - scaleFactor);
159+
}
160+
}

0 commit comments

Comments
 (0)