UNPKG

ng-cw-v12

Version:

Angular UI Component Library

471 lines (438 loc) 19.5 kB
import * as i0 from '@angular/core'; import { Component, ViewChild, Input, HostListener, NgModule } from '@angular/core'; import * as THREE from 'three'; import { CommonModule } from '@angular/common'; const vertexShader = ` precision highp float; attribute vec3 position; attribute vec2 uv; varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0); } `; const fragmentShader = ` precision highp float; uniform float uTime; uniform vec3 uResolution; uniform vec2 uFocal; uniform vec2 uRotation; uniform float uStarSpeed; uniform float uDensity; uniform float uHueShift; uniform float uSpeed; uniform vec2 uMouse; uniform float uGlowIntensity; uniform float uSaturation; uniform bool uMouseRepulsion; uniform float uTwinkleIntensity; uniform float uRotationSpeed; uniform float uRepulsionStrength; uniform float uMouseActiveFactor; uniform float uAutoCenterRepulsion; varying vec2 vUv; #define NUM_LAYER 4.0 #define STAR_COLOR_CUTOFF 0.2 #define MAT45 mat2(0.7071, -0.7071, 0.7071, 0.7071) #define PERIOD 3.0 float Hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float tri(float x) { return abs(fract(x) * 2.0 - 1.0); } float tris(float x) { float t = fract(x); return 1.0 - smoothstep(0.0, 1.0, abs(2.0 * t - 1.0)); } float trisn(float x) { float t = fract(x); return 2.0 * (1.0 - smoothstep(0.0, 1.0, abs(2.0 * t - 1.0))) - 1.0; } vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } float Star(vec2 uv, float flare) { float d = length(uv); float m = (0.05 * uGlowIntensity) / d; float rays = smoothstep(0.0, 1.0, 1.0 - abs(uv.x * uv.y * 1000.0)); m += rays * flare * uGlowIntensity; uv *= MAT45; rays = smoothstep(0.0, 1.0, 1.0 - abs(uv.x * uv.y * 1000.0)); m += rays * 0.3 * flare * uGlowIntensity; m *= smoothstep(1.0, 0.2, d); return m; } vec3 StarLayer(vec2 uv) { vec3 col = vec3(0.0); vec2 gv = fract(uv) - 0.5; vec2 id = floor(uv); for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { vec2 offset = vec2(float(x), float(y)); vec2 si = id + vec2(float(x), float(y)); float seed = Hash21(si); float size = fract(seed * 345.32); float glossLocal = tri(uStarSpeed / (PERIOD * seed + 1.0)); float flareSize = smoothstep(0.9, 1.0, size) * glossLocal; float red = smoothstep(STAR_COLOR_CUTOFF, 1.0, Hash21(si + 1.0)) + STAR_COLOR_CUTOFF; float blu = smoothstep(STAR_COLOR_CUTOFF, 1.0, Hash21(si + 3.0)) + STAR_COLOR_CUTOFF; float grn = min(red, blu) * seed; vec3 base = vec3(red, grn, blu); float hue = atan(base.g - base.r, base.b - base.r) / (2.0 * 3.14159) + 0.5; hue = fract(hue + uHueShift / 360.0); float sat = length(base - vec3(dot(base, vec3(0.299, 0.587, 0.114)))) * uSaturation; float val = max(max(base.r, base.g), base.b); base = hsv2rgb(vec3(hue, sat, val)); vec2 pad = vec2(tris(seed * 34.0 + uTime * uSpeed / 10.0), tris(seed * 38.0 + uTime * uSpeed / 30.0)) - 0.5; float star = Star(gv - offset - pad, flareSize); vec3 color = base; float twinkle = trisn(uTime * uSpeed + seed * 6.2831) * 0.5 + 1.0; twinkle = mix(1.0, twinkle, uTwinkleIntensity); star *= twinkle; col += star * size * color; } } return col; } void main() { vec2 focalPx = uFocal * uResolution.xy; vec2 uv = (vUv * uResolution.xy - focalPx) / uResolution.y; vec2 mouseNorm = uMouse - vec2(0.5); if (uAutoCenterRepulsion > 0.0) { vec2 centerUV = vec2(0.0, 0.0); float centerDist = length(uv - centerUV); vec2 repulsion = normalize(uv - centerUV) * (uAutoCenterRepulsion / (centerDist + 0.1)); uv += repulsion * 0.05; } else if (uMouseRepulsion) { vec2 mousePosUV = (uMouse * uResolution.xy - focalPx) / uResolution.y; float mouseDist = length(uv - mousePosUV); vec2 repulsion = normalize(uv - mousePosUV) * (uRepulsionStrength / (mouseDist + 0.1)); uv += repulsion * 0.05 * uMouseActiveFactor; } else { vec2 mouseOffset = mouseNorm * 0.1 * uMouseActiveFactor; uv += mouseOffset; } float autoRotAngle = uTime * uRotationSpeed; mat2 autoRot = mat2(cos(autoRotAngle), -sin(autoRotAngle), sin(autoRotAngle), cos(autoRotAngle)); uv = autoRot * uv; uv = mat2(uRotation.x, -uRotation.y, uRotation.y, uRotation.x) * uv; vec3 col = vec3(0.0); for (float i = 0.0; i < 1.0; i += 1.0 / NUM_LAYER) { float depth = fract(i + uStarSpeed * uSpeed); float scale = mix(20.0 * uDensity, 0.5 * uDensity, depth); float fade = depth * smoothstep(1.0, 0.9, depth); col += StarLayer(uv * scale + i * 453.32) * fade; } float alpha = length(col); alpha = smoothstep(0.0, 0.3, alpha); alpha = min(alpha, 1.0); gl_FragColor = vec4(col, alpha); } `; class GalaxyBackgroundComponent { constructor(ngZone) { this.ngZone = ngZone; /** 将星系效应的焦点设置为 [x, y] 坐标(0-1) */ this.ncFocal = [0.5, 0.5]; /** 控制星系的旋转矩阵,其旋转值为[x, y] */ this.ncRotation = [1.0, 0.0]; /** 控制星星的移动速度和动画效果(0.1-2) */ this.ncStarSpeed = 0.5; /** 控制星星的密度(0.1-3) */ this.ncDensity = 1; /** 将所有星星的色调按指定的角度(0-360度)进行调整(在ncSaturation不为0时生效)*/ this.ncHueShift = 140; /** 为真时,停止所有基于时间的动画 */ this._disableAnimation = false; /** 所有动画的全局速度倍率(0.1-3) */ this.ncSpeed = 1.0; /** 是否启用鼠标交互 */ this._mouseInteraction = true; /** 控制星光效果的强度(0-1) */ this.ncGlowIntensity = 0.3; /** 控制星星的颜色饱和度(0-1,0:灰度 1:全彩) */ this.ncSaturation = 0.0; /** 是否启用鼠标排斥效果 */ this._mouseRepulsion = true; /** 鼠标排斥力度(0-10) */ this.ncRepulsionStrength = 2; /** 控制星星闪烁的程度(0-1,0:不闪烁 1:最大闪烁) */ this.ncTwinkleIntensity = 0.3; /** 星系自动旋转的速度(0-0.5) */ this.ncRotationSpeed = 0.1; /** 自动向中心排斥的强度(0-20,如果大于0则不使用鼠标位置) */ this.ncAutoCenterRepulsion = 0; this.animationId = null; this.targetMousePos = { x: 0.5, y: 0.5 }; this.smoothMousePos = { x: 0.5, y: 0.5 }; this.targetMouseActive = 0.0; this.smoothMouseActive = 0.0; this.animate = (t) => { this.animationId = requestAnimationFrame(this.animate); if (!this.ncDisableAnimation) { this.uniforms.uTime.value = t * 0.001; this.uniforms.uStarSpeed.value = (t * 0.001 * this.ncStarSpeed) / 10.0; } const lerpFactor = 0.05; this.smoothMousePos.x += (this.targetMousePos.x - this.smoothMousePos.x) * lerpFactor; this.smoothMousePos.y += (this.targetMousePos.y - this.smoothMousePos.y) * lerpFactor; this.smoothMouseActive += (this.targetMouseActive - this.smoothMouseActive) * lerpFactor; this.uniforms.uMouse.value[0] = this.smoothMousePos.x; this.uniforms.uMouse.value[1] = this.smoothMousePos.y; this.uniforms.uMouseActiveFactor.value = this.smoothMouseActive; this.renderer.render(this.scene, this.camera); }; this.handleMouseLeave = () => { this.targetMouseActive = 0.0; }; } set ncDisableAnimation(val) { this._disableAnimation = val !== null && val !== undefined && val !== false && val !== 'false'; } get ncDisableAnimation() { return this._disableAnimation; } set ncMouseInteraction(val) { this._mouseInteraction = val !== null && val !== undefined && val !== false && val !== 'false'; } get ncMouseInteraction() { return this._mouseInteraction; } set ncMouseRepulsion(val) { this._mouseRepulsion = val !== null && val !== undefined && val !== false && val !== 'false'; } get ncMouseRepulsion() { return this._mouseRepulsion; } ngOnInit() { } ngAfterViewInit() { this.initWebGL(); } ngOnDestroy() { this.cleanup(); } ngOnChanges(changes) { if (!this.uniforms) return; this.updateUniforms(); } initWebGL() { const container = this.containerRef.nativeElement; this.renderer = new THREE.WebGLRenderer({ alpha: true, premultipliedAlpha: false, antialias: false }); this.renderer.setClearColor(0x000000, 0); this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)); container.appendChild(this.renderer.domElement); this.scene = new THREE.Scene(); this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); this.uniforms = { uTime: { value: 0 }, uResolution: { value: new THREE.Vector3() }, uFocal: { value: new THREE.Vector2() }, uRotation: { value: new THREE.Vector2() }, uStarSpeed: { value: this.ncStarSpeed }, uDensity: { value: this.ncDensity }, uHueShift: { value: this.ncHueShift }, uSpeed: { value: this.ncSpeed }, uMouse: { value: [this.smoothMousePos.x, this.smoothMousePos.y] }, uGlowIntensity: { value: this.ncGlowIntensity }, uSaturation: { value: this.ncSaturation }, uMouseRepulsion: { value: this.ncMouseRepulsion }, uTwinkleIntensity: { value: this.ncTwinkleIntensity }, uRotationSpeed: { value: this.ncRotationSpeed }, uRepulsionStrength: { value: this.ncRepulsionStrength }, uMouseActiveFactor: { value: 0.0 }, uAutoCenterRepulsion: { value: this.ncAutoCenterRepulsion } }; this.updateUniforms(); const geometry = new THREE.PlaneGeometry(2, 2); this.material = new THREE.RawShaderMaterial({ vertexShader, fragmentShader, uniforms: this.uniforms, transparent: true, blending: THREE.NormalBlending }); const mesh = new THREE.Mesh(geometry, this.material); this.scene.add(mesh); this.resizeObserver = new ResizeObserver(() => this.resize()); this.resizeObserver.observe(container); this.resize(); this.ngZone.runOutsideAngular(() => { this.animate(0); }); } updateUniforms() { if (!this.uniforms || !this.renderer) return; this.renderer.setClearColor(0x000000, 0); this.material && (this.material.transparent = true); this.uniforms.uFocal.value.set(this.ncFocal[0], this.ncFocal[1]); this.uniforms.uRotation.value.set(this.ncRotation[0], this.ncRotation[1]); this.uniforms.uStarSpeed.value = this.ncStarSpeed; this.uniforms.uDensity.value = this.ncDensity; this.uniforms.uHueShift.value = this.ncHueShift; this.uniforms.uSpeed.value = this.ncSpeed; this.uniforms.uGlowIntensity.value = this.ncGlowIntensity; this.uniforms.uSaturation.value = this.ncSaturation; this.uniforms.uMouseRepulsion.value = this.ncMouseRepulsion; this.uniforms.uTwinkleIntensity.value = this.ncTwinkleIntensity; this.uniforms.uRotationSpeed.value = this.ncRotationSpeed; this.uniforms.uRepulsionStrength.value = this.ncRepulsionStrength; this.uniforms.uAutoCenterRepulsion.value = this.ncAutoCenterRepulsion; } resize() { if (!this.containerRef || !this.renderer) return; const container = this.containerRef.nativeElement; const width = container.offsetWidth; const height = container.offsetHeight; this.renderer.setSize(width, height); if (this.uniforms) { this.uniforms.uResolution.value.set(width, height, width / height); } } onMouseMove(e) { if (!this.ncMouseInteraction) return; this.updateMousePos(e.clientX, e.clientY); } onMouseLeave() { this.handleMouseLeave(); } onTouchMove(e) { if (!this.ncMouseInteraction || e.touches.length === 0) return; this.updateMousePos(e.touches[0].clientX, e.touches[0].clientY); } onTouchEnd() { this.handleMouseLeave(); } updateMousePos(clientX, clientY) { if (!this.containerRef) return; const rect = this.containerRef.nativeElement.getBoundingClientRect(); const x = (clientX - rect.left) / rect.width; const y = 1.0 - (clientY - rect.top) / rect.height; this.targetMousePos = { x, y }; this.targetMouseActive = 1.0; } cleanup() { var _a; if (this.animationId !== null) { cancelAnimationFrame(this.animationId); this.animationId = null; } if (this.resizeObserver) { this.resizeObserver.disconnect(); } const container = (_a = this.containerRef) === null || _a === void 0 ? void 0 : _a.nativeElement; if (container) { if (this.renderer && container.contains(this.renderer.domElement)) { container.removeChild(this.renderer.domElement); } } if (this.renderer) { this.renderer.dispose(); } if (this.material) { this.material.dispose(); } if (this.scene) { this.scene.clear(); } } } GalaxyBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GalaxyBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); GalaxyBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: GalaxyBackgroundComponent, selector: "nc-galaxy-background", inputs: { ncFocal: "ncFocal", ncRotation: "ncRotation", ncStarSpeed: "ncStarSpeed", ncDensity: "ncDensity", ncHueShift: "ncHueShift", ncDisableAnimation: "ncDisableAnimation", ncSpeed: "ncSpeed", ncMouseInteraction: "ncMouseInteraction", ncGlowIntensity: "ncGlowIntensity", ncSaturation: "ncSaturation", ncMouseRepulsion: "ncMouseRepulsion", ncRepulsionStrength: "ncRepulsionStrength", ncTwinkleIntensity: "ncTwinkleIntensity", ncRotationSpeed: "ncRotationSpeed", ncAutoCenterRepulsion: "ncAutoCenterRepulsion" }, host: { listeners: { "mousemove": "onMouseMove($event)", "mouseleave": "onMouseLeave()", "touchstart": "onTouchMove($event)", "touchmove": "onTouchMove($event)", "touchend": "onTouchEnd()" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-galaxy-canvas-container\"></div>\r\n<div class=\"nc-content-wrapper\">\r\n <ng-content></ng-content>\r\n</div>", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden}.nc-galaxy-canvas-container{position:absolute;inset:0;z-index:0;background-color:#000}.nc-content-wrapper{position:relative;z-index:1;width:100%;height:100%}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GalaxyBackgroundComponent, decorators: [{ type: Component, args: [{ selector: 'nc-galaxy-background', templateUrl: './galaxy-background.component.html', styleUrls: ['./galaxy-background.component.less'] }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{ type: ViewChild, args: ['container', { static: true }] }], ncFocal: [{ type: Input }], ncRotation: [{ type: Input }], ncStarSpeed: [{ type: Input }], ncDensity: [{ type: Input }], ncHueShift: [{ type: Input }], ncDisableAnimation: [{ type: Input }], ncSpeed: [{ type: Input }], ncMouseInteraction: [{ type: Input }], ncGlowIntensity: [{ type: Input }], ncSaturation: [{ type: Input }], ncMouseRepulsion: [{ type: Input }], ncRepulsionStrength: [{ type: Input }], ncTwinkleIntensity: [{ type: Input }], ncRotationSpeed: [{ type: Input }], ncAutoCenterRepulsion: [{ type: Input }], onMouseMove: [{ type: HostListener, args: ['mousemove', ['$event']] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }], onTouchMove: [{ type: HostListener, args: ['touchstart', ['$event']] }, { type: HostListener, args: ['touchmove', ['$event']] }], onTouchEnd: [{ type: HostListener, args: ['touchend'] }] } }); class NcGalaxyBackgroundModule { } NcGalaxyBackgroundModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGalaxyBackgroundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NcGalaxyBackgroundModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGalaxyBackgroundModule, declarations: [GalaxyBackgroundComponent], imports: [CommonModule], exports: [GalaxyBackgroundComponent] }); NcGalaxyBackgroundModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGalaxyBackgroundModule, imports: [[ CommonModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGalaxyBackgroundModule, decorators: [{ type: NgModule, args: [{ declarations: [ GalaxyBackgroundComponent ], imports: [ CommonModule ], exports: [ GalaxyBackgroundComponent ] }] }] }); /** * Generated bundle index. Do not edit. */ export { GalaxyBackgroundComponent, NcGalaxyBackgroundModule }; //# sourceMappingURL=ng-cw-v12-galaxy-background.js.map