@omnedia/ngx-background-beams
Version:
<a href="https://ngxui.com" target="_blank" style="display: flex;gap: .5rem;align-items: center;cursor: pointer; padding: 0 0 0 0; height: fit-content;"> <img src="https://ngxui.com/assets/img/ngxui-logo.png" style="width: 64px;height: 64px;"> </a>
200 lines (195 loc) • 14.9 kB
JavaScript
import * as i0 from '@angular/core';
import { signal, PLATFORM_ID, Input, ViewChild, Inject, ChangeDetectionStrategy, Component } from '@angular/core';
import { isPlatformBrowser, CommonModule } from '@angular/common';
class NgxBackgroundBeamsComponent {
platformId;
componentRef;
set gradientColorValues(colors) {
if (colors.length !== 3) {
throw new Error('om-background-beams: gradient colors need to be exactly 3 values.');
}
this.gradientColors.set(colors);
}
pathColor = '#00000025';
pathQuantity = 50;
gradientColors = signal(['#18CCFC', '#6344F5', '#AE48FF']);
paths = signal([]);
x1 = signal([]);
x2 = signal([]);
y1 = signal([]);
y2 = signal([]);
delays = signal([]);
durations = signal([]);
inViewport = signal(false);
animationFrameId;
observer;
constructor(platformId) {
this.platformId = platformId;
}
ngAfterViewInit() {
if (isPlatformBrowser(this.platformId)) {
this.generatePaths();
this.initializeIntersectionObserver();
}
}
ngOnDestroy() {
if (this.observer && this.componentRef.nativeElement) {
this.observer.unobserve(this.componentRef.nativeElement);
}
}
generatePaths() {
this.paths.set([]);
this.x1.set([]);
this.x2.set([]);
this.y1.set([]);
this.y2.set([]);
this.delays.set([]);
this.durations.set([]);
const firstPath = {
mX1: -380, mY1: -189, cX1: -380, cY1: -189, cX2: -312, cY2: 216,
cX3: 152, cY3: 343, cX4: 616, cY4: 470, cX5: 684, cY5: 875
};
const lastPath = {
mX1: -37, mY1: -581, cX1: -37, cY1: -581, cX2: 31, cY2: -176,
cX3: 495, cY3: -49, cX4: 959, cY4: 78, cX5: 1027, cY5: 483
};
const paths = [];
const x1 = [];
const x2 = [];
const y1 = [];
const y2 = [];
const delays = [];
const durations = [];
for (let i = 0; i < this.pathQuantity; i++) {
const t = i / (this.pathQuantity - 1);
const mX1 = firstPath.mX1 + t * (lastPath.mX1 - firstPath.mX1);
const mY1 = firstPath.mY1 + t * (lastPath.mY1 - firstPath.mY1);
const cX1 = firstPath.cX1 + t * (lastPath.cX1 - firstPath.cX1);
const cY1 = firstPath.cY1 + t * (lastPath.cY1 - firstPath.cY1);
const cX2 = firstPath.cX2 + t * (lastPath.cX2 - firstPath.cX2);
const cY2 = firstPath.cY2 + t * (lastPath.cY2 - firstPath.cY2);
const cX3 = firstPath.cX3 + t * (lastPath.cX3 - firstPath.cX3);
const cY3 = firstPath.cY3 + t * (lastPath.cY3 - firstPath.cY3);
const cX4 = firstPath.cX4 + t * (lastPath.cX4 - firstPath.cX4);
const cY4 = firstPath.cY4 + t * (lastPath.cY4 - firstPath.cY4);
const cX5 = firstPath.cX5 + t * (lastPath.cX5 - firstPath.cX5);
const cY5 = firstPath.cY5 + t * (lastPath.cY5 - firstPath.cY5);
const path = `M${mX1} ${mY1}` +
`C${cX1} ${cY1} ${cX2} ${cY2} ${cX3} ${cY3}` +
`C${cX4} ${cY4} ${cX5} ${cY5} ${cX5} ${cY5}`;
paths.push(path);
x1.push('0%');
x2.push('0%');
y1.push('0%');
y2.push('0%');
delays.push(Math.random() * 10);
durations.push(Math.random() * 10 + 10);
}
this.paths.set(paths);
this.x1.set(x1);
this.x2.set(x2);
this.y1.set(y1);
this.y2.set(y2);
this.delays.set(delays);
this.durations.set(durations);
}
initializeIntersectionObserver() {
let observerTimeout;
this.observer = new IntersectionObserver(([entry]) => {
clearTimeout(observerTimeout);
observerTimeout = setTimeout(() => {
if (entry.isIntersecting) {
this.inViewport.set(true);
this.startAnimations();
}
else {
this.inViewport.set(false);
this.generatePaths();
}
}, 100);
});
// Observe the component
if (this.observer && this.componentRef.nativeElement) {
this.observer.observe(this.componentRef.nativeElement);
}
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
}
}
startAnimations() {
this.paths().forEach((_, index) => {
const delay = this.delays()[index] * 1000;
const duration = this.durations()[index] * 1000;
setTimeout(() => {
this.animateGradient(index, duration);
}, delay);
});
}
animateGradient(index, duration) {
const startTime = performance.now();
const randomY2Value = 93 + Math.random() * 8;
const animate = (currentTime) => {
if (!this.inViewport()) {
return;
}
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
this.x1.update(a => (a[index] = `${progress * 100}%`, a));
this.x2.update(a => (a[index] = `${progress * 95}%`, a));
this.y1.update(a => (a[index] = `${progress * 100}%`, a));
this.y2.update(a => (a[index] = `${progress * randomY2Value}%`, a));
this.updateGradientAttributes(index);
if (progress < 1) {
this.animationFrameId = requestAnimationFrame(animate);
}
else {
this.restartAnimation(index, duration);
}
};
this.animationFrameId = requestAnimationFrame(animate);
}
updateGradientAttributes(index) {
const gradientElement = document.getElementById(`linearGradient-${index}`);
if (gradientElement) {
gradientElement.setAttribute('x1', this.x1()[index]);
gradientElement.setAttribute('x2', this.x2()[index]);
gradientElement.setAttribute('y1', this.y1()[index]);
gradientElement.setAttribute('y2', this.y2()[index]);
}
}
restartAnimation(index, duration) {
setTimeout(() => {
this.x1.update(a => (a[index] = `0%`, a));
this.x2.update(a => (a[index] = `0%`, a));
this.y1.update(a => (a[index] = `0%`, a));
this.y2.update(a => (a[index] = `0%`, a));
this.animateGradient(index, duration);
}, Math.random() * 10000);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxBackgroundBeamsComponent, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.2", type: NgxBackgroundBeamsComponent, isStandalone: true, selector: "om-background-beams", inputs: { gradientColorValues: "gradientColorValues", pathColor: "pathColor", pathQuantity: "pathQuantity" }, viewQueries: [{ propertyName: "componentRef", first: true, predicate: ["OmBackgroundBeams"], descendants: true }], ngImport: i0, template: "<div class=\"om-background-beams\" #OmBackgroundBeams>\r\n <div class=\"om-background-beams-background\">\r\n <div class=\"custom-svg-wrapper\">\r\n <svg\r\n class=\"custom-svg\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n viewBox=\"0 0 696 316\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875\"\r\n stroke=\"url(#paint0_radial_242_278)\"\r\n stroke-opacity=\"0.05\"\r\n stroke-width=\"0.5\"\r\n ></path>\r\n\r\n <!-- Dynamic motion path generation with Angular -->\r\n @for (path of paths(); track $index) {\r\n <path\r\n [attr.d]=\"path\"\r\n [attr.stroke]=\"pathColor\"\r\n stroke-opacity=\"1\"\r\n stroke-width=\"0.5\"\r\n ></path>\r\n\r\n <path\r\n [attr.d]=\"path\"\r\n [attr.stroke]=\"'url(#linearGradient-' + $index + ')'\"\r\n stroke-opacity=\"1\"\r\n stroke-width=\"0.5\"\r\n [attr.id]=\"'path-' + $index\"\r\n ></path>\r\n }\r\n\r\n <!-- Definitions for gradients -->\r\n <defs>\r\n @for (path of paths(); track $index) {\r\n <linearGradient\r\n [attr.id]=\"'linearGradient-' + $index\"\r\n [attr.x1]=\"x1()[$index]\"\r\n [attr.x2]=\"x2()[$index]\"\r\n [attr.y1]=\"y1()[$index]\"\r\n [attr.y2]=\"y2()[$index]\"\r\n >\r\n <stop [attr.stop-color]=\"gradientColors()[0]\" stop-opacity=\"0\"></stop>\r\n <stop [attr.stop-color]=\"gradientColors()[0]\"></stop>\r\n <stop offset=\"32.5%\" [attr.stop-color]=\"gradientColors()[1]\"></stop>\r\n <stop offset=\"100%\" [attr.stop-color]=\"gradientColors()[2]\" stop-opacity=\"0\"></stop>\r\n </linearGradient>\r\n }\r\n\r\n <!-- Radial Gradient -->\r\n <radialGradient\r\n id=\"paint0_radial_242_278\"\r\n cx=\"0\"\r\n cy=\"0\"\r\n r=\"1\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n gradientTransform=\"translate(352 34) rotate(90) scale(555 1560.62)\"\r\n >\r\n <stop offset=\"0.0666667\" stop-color=\"#d1d5db\"></stop>\r\n <stop offset=\"0.243243\" stop-color=\"#d1d5db\"></stop>\r\n <stop offset=\"0.43594\" stop-color=\"white\" stop-opacity=\"0\"></stop>\r\n </radialGradient>\r\n </defs>\r\n </svg>\r\n </div>\r\n </div>\r\n <ng-content></ng-content>\r\n</div>\r\n", styles: [".om-background-beams{position:relative;overflow:hidden;width:100%;height:100%}.om-background-beams .om-background-beams-background{position:absolute;width:150%;height:120%;top:0;left:0;pointer-events:none}.om-background-beams .custom-svg-wrapper{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;-webkit-mask-size:40px;mask-size:40px;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.om-background-beams .custom-svg{position:absolute;width:100%;height:100%;z-index:0;pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxBackgroundBeamsComponent, decorators: [{
type: Component,
args: [{ selector: 'om-background-beams', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"om-background-beams\" #OmBackgroundBeams>\r\n <div class=\"om-background-beams-background\">\r\n <div class=\"custom-svg-wrapper\">\r\n <svg\r\n class=\"custom-svg\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n viewBox=\"0 0 696 316\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <path\r\n d=\"M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875\"\r\n stroke=\"url(#paint0_radial_242_278)\"\r\n stroke-opacity=\"0.05\"\r\n stroke-width=\"0.5\"\r\n ></path>\r\n\r\n <!-- Dynamic motion path generation with Angular -->\r\n @for (path of paths(); track $index) {\r\n <path\r\n [attr.d]=\"path\"\r\n [attr.stroke]=\"pathColor\"\r\n stroke-opacity=\"1\"\r\n stroke-width=\"0.5\"\r\n ></path>\r\n\r\n <path\r\n [attr.d]=\"path\"\r\n [attr.stroke]=\"'url(#linearGradient-' + $index + ')'\"\r\n stroke-opacity=\"1\"\r\n stroke-width=\"0.5\"\r\n [attr.id]=\"'path-' + $index\"\r\n ></path>\r\n }\r\n\r\n <!-- Definitions for gradients -->\r\n <defs>\r\n @for (path of paths(); track $index) {\r\n <linearGradient\r\n [attr.id]=\"'linearGradient-' + $index\"\r\n [attr.x1]=\"x1()[$index]\"\r\n [attr.x2]=\"x2()[$index]\"\r\n [attr.y1]=\"y1()[$index]\"\r\n [attr.y2]=\"y2()[$index]\"\r\n >\r\n <stop [attr.stop-color]=\"gradientColors()[0]\" stop-opacity=\"0\"></stop>\r\n <stop [attr.stop-color]=\"gradientColors()[0]\"></stop>\r\n <stop offset=\"32.5%\" [attr.stop-color]=\"gradientColors()[1]\"></stop>\r\n <stop offset=\"100%\" [attr.stop-color]=\"gradientColors()[2]\" stop-opacity=\"0\"></stop>\r\n </linearGradient>\r\n }\r\n\r\n <!-- Radial Gradient -->\r\n <radialGradient\r\n id=\"paint0_radial_242_278\"\r\n cx=\"0\"\r\n cy=\"0\"\r\n r=\"1\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n gradientTransform=\"translate(352 34) rotate(90) scale(555 1560.62)\"\r\n >\r\n <stop offset=\"0.0666667\" stop-color=\"#d1d5db\"></stop>\r\n <stop offset=\"0.243243\" stop-color=\"#d1d5db\"></stop>\r\n <stop offset=\"0.43594\" stop-color=\"white\" stop-opacity=\"0\"></stop>\r\n </radialGradient>\r\n </defs>\r\n </svg>\r\n </div>\r\n </div>\r\n <ng-content></ng-content>\r\n</div>\r\n", styles: [".om-background-beams{position:relative;overflow:hidden;width:100%;height:100%}.om-background-beams .om-background-beams-background{position:absolute;width:150%;height:120%;top:0;left:0;pointer-events:none}.om-background-beams .custom-svg-wrapper{position:absolute;inset:0;display:flex;justify-content:center;align-items:center;-webkit-mask-size:40px;mask-size:40px;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.om-background-beams .custom-svg{position:absolute;width:100%;height:100%;z-index:0;pointer-events:none}\n"] }]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }], propDecorators: { componentRef: [{
type: ViewChild,
args: ['OmBackgroundBeams']
}], gradientColorValues: [{
type: Input
}], pathColor: [{
type: Input
}], pathQuantity: [{
type: Input
}] } });
/*
* Public API Surface of ngx-background-beams
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgxBackgroundBeamsComponent };
//# sourceMappingURL=omnedia-ngx-background-beams.mjs.map