;
+ private ctx!: CanvasRenderingContext2D;
+ private resizeObserver?: ResizeObserver;
+
+ private canvasNativeSize: [number, number] = [0, 0];
+
+ private animation: {
+ id?: number;
+ startTime: number;
+ progress: number;
+ gridDimension: [number, number];
+
+ duration: number;
+ gridSquareSize: number;
+ } = {
+ startTime: 0,
+ progress: 0,
+ gridDimension: [0, 0],
+
+ duration: 30,
+ gridSquareSize: 100,
+ };
+
+ constructor(private ngZone: NgZone) {
+ afterNextRender(() => {
+ this.ctx = this.canvasRef.nativeElement.getContext('2d')!;
+
+ this.ngZone.runOutsideAngular(() => {
+ this.resizeObserver = new ResizeObserver(() => this.resize());
+ this.resizeObserver.observe(this.canvasRef.nativeElement);
+
+ this.resize(); // Safe Initialization
+ this.animation.startTime = performance.now();
+ this.draw();
+
+ this.animate(performance.now());
+ });
+ });
+ }
+
+ private resize() {
+ const canvas = this.canvasRef.nativeElement;
+ const dpr = window.devicePixelRatio || 1;
+ const rect = canvas.getBoundingClientRect();
+
+ canvas.width = rect.width * dpr;
+ canvas.height = rect.height * dpr;
+
+ this.ctx.scale(dpr, dpr);
+ this.updateAnimationInfo();
+ }
+
+ private updateAnimationInfo() {
+ this.canvasNativeSize = [this.canvasRef.nativeElement.clientWidth, this.canvasRef.nativeElement.clientHeight];
+
+ this.animation.gridDimension = [
+ Math.trunc(this.canvasNativeSize[0] / this.animation.gridSquareSize) + 3,
+ Math.trunc(this.canvasNativeSize[1] / this.animation.gridSquareSize) + 3,
+ ];
+ }
+
+ private animate = (currentTime: number) => {
+ this.animation.id = requestAnimationFrame(this.animate);
+
+ this.update(currentTime);
+ this.draw();
+ };
+
+ private update(currentTime: number) {
+ let elapsedTime: number;
+ elapsedTime = (currentTime - this.animation.startTime) / 1000;
+
+ const animationTime = elapsedTime % this.animation.duration;
+ this.animation.progress = animationTime / this.animation.duration;
+ }
+
+ private draw() {
+ this.ctx.clearRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
+ const linearGradient = this.ctx.createLinearGradient(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
+
+ linearGradient.addColorStop(0, 'oklch(1 0 0 / 0.6)');
+ linearGradient.addColorStop(1, 'oklch(0.7938 0.1292 47.77 / 0.6)');
+
+ this.ctx.fillStyle = linearGradient;
+ this.ctx.fillRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
+
+ this.ctx.globalCompositeOperation = 'multiply';
+
+ this.ctx.beginPath();
+ this.ctx.lineWidth = 2;
+ this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
+ this.ctx.lineCap = 'round';
+
+ const lineRenderMargin = this.animation.gridSquareSize * 2;
+
+ const xOffset = (this.canvasNativeSize[0] - this.animation.gridDimension[0] * this.animation.gridSquareSize) / 2;
+ const yOffset = (this.canvasNativeSize[1] - this.animation.gridDimension[1] * this.animation.gridSquareSize) / 2;
+ const movingOffset = -(this.animation.gridSquareSize * this.animation.progress);
+
+ for (let y = 0; y < this.animation.gridDimension[1]; y++) {
+ this.ctx.moveTo(-lineRenderMargin, y * this.animation.gridSquareSize + yOffset + movingOffset);
+ this.ctx.lineTo(this.canvasNativeSize[0] + lineRenderMargin, y * this.animation.gridSquareSize + yOffset + movingOffset);
+ }
+
+ for (let x = 0; x < this.animation.gridDimension[0]; x++) {
+ this.ctx.moveTo(x * this.animation.gridSquareSize + xOffset + movingOffset, -lineRenderMargin);
+ this.ctx.lineTo(x * this.animation.gridSquareSize + xOffset + movingOffset, this.canvasNativeSize[1] + lineRenderMargin);
+ }
+
+ this.ctx.stroke()
+ }
+
+ ngOnDestroy() {
+ if (this.animation.id) {
+ cancelAnimationFrame(this.animation.id);
+ }
+ this.resizeObserver?.disconnect();
+ }
+}
diff --git a/src/app/pages/main/main.html b/src/app/pages/main/main.html
index dfb081a..0048483 100644
--- a/src/app/pages/main/main.html
+++ b/src/app/pages/main/main.html
@@ -1,4 +1,6 @@
+
+
AEF Component Test
diff --git a/src/app/pages/main/main.scss b/src/app/pages/main/main.scss
index 966ee6a..5fd92d9 100644
--- a/src/app/pages/main/main.scss
+++ b/src/app/pages/main/main.scss
@@ -7,3 +7,15 @@ section#dropdown-test {
.test-container {
max-width: 100%;
}
+
+brand-accent {
+ position: absolute;
+
+ width: 100%;
+ height: 100%;
+
+ top: 0;
+ left: 0;
+
+ z-index: -999999;
+}
diff --git a/src/app/pages/main/main.ts b/src/app/pages/main/main.ts
index 8f6e8b4..36fb22b 100644
--- a/src/app/pages/main/main.ts
+++ b/src/app/pages/main/main.ts
@@ -1,11 +1,12 @@
import { Component, signal } from '@angular/core';
import { Switch } from '../../components/switch/switch';
import { Dropdown, DropdownOption } from '../../components/dropdown/dropdown';
+import { BrandAccent } from '../../components/brand-accent/brand-accent';
@Component({
selector: 'app-main-page',
standalone: true,
- imports: [Switch, Dropdown],
+ imports: [Switch, Dropdown, BrandAccent],
templateUrl: './main.html',
styleUrl: './main.scss',
})
diff --git a/src/styles.scss b/src/styles.scss
index 417c5f8..4e84fd0 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -66,6 +66,10 @@ section {
padding: 20px;
border: 2px solid oklch(0 0 0 / 20%); // rgba(0, 0, 0, 0.2)
border-radius: 8px;
+
+ background-color: oklch(1 0 0 / 60%);
+
+ backdrop-filter: blur(20px);
}
.container {