UNPKG

@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
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