ng-cw-v12
Version:
Angular UI Component Library
382 lines (363 loc) • 17 kB
JavaScript
import * as i0 from '@angular/core';
import { Component, ViewChild, Input, NgModule } from '@angular/core';
import * as THREE from 'three';
import { CommonModule } from '@angular/common';
// ─── 着色器代码 ─────────────────────────────────────────────────────────────
const vertex = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`;
const fragment = `
precision highp float;
uniform vec2 iResolution;
uniform float iTime;
uniform float uTimeSpeed;
uniform float uColorBalance;
uniform float uWarpStrength;
uniform float uWarpFrequency;
uniform float uWarpSpeed;
uniform float uWarpAmplitude;
uniform float uBlendAngle;
uniform float uBlendSoftness;
uniform float uRotationAmount;
uniform float uNoiseScale;
uniform float uGrainAmount;
uniform float uGrainScale;
uniform float uGrainAnimated;
uniform float uContrast;
uniform float uGamma;
uniform float uSaturation;
uniform vec2 uCenterOffset;
uniform float uZoom;
uniform vec3 uColor1;
uniform vec3 uColor2;
uniform vec3 uColor3;
#define S(a,b,t) smoothstep(a,b,t)
mat2 Rot(float a) {
float s = sin(a), c = cos(a);
return mat2(c, -s, s, c);
}
vec2 hash(vec2 p) {
p = vec2(dot(p, vec2(2127.1, 81.17)), dot(p, vec2(1269.5, 283.37)));
return fract(sin(p) * 43758.5453);
}
float noise(vec2 p) {
vec2 i = floor(p), f = fract(p), u = f * f * (3.0 - 2.0 * f);
float n = mix(mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),
dot(-1.0 + 2.0 * hash(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),
mix(dot(-1.0 + 2.0 * hash(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),
dot(-1.0 + 2.0 * hash(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y);
return 0.5 + 0.5 * n;
}
void mainImage(out vec4 o, vec2 C) {
float t = iTime * uTimeSpeed;
vec2 uv = C / iResolution.xy;
float ratio = iResolution.x / iResolution.y;
vec2 tuv = uv - 0.5 + uCenterOffset;
tuv /= max(uZoom, 0.001);
float degree = noise(vec2(t * 0.1, tuv.x * tuv.y) * uNoiseScale);
tuv.y *= 1.0 / ratio;
tuv *= Rot(radians((degree - 0.5) * uRotationAmount + 180.0));
tuv.y *= ratio;
float frequency = uWarpFrequency;
float ws = max(uWarpStrength, 0.001);
float amplitude = uWarpAmplitude / ws;
float warpTime = t * uWarpSpeed;
tuv.x += sin(tuv.y * frequency + warpTime) / amplitude;
tuv.y += sin(tuv.x * (frequency * 1.5) + warpTime) / (amplitude * 0.5);
vec3 colLav = uColor1;
vec3 colOrg = uColor2;
vec3 colDark = uColor3;
float b = uColorBalance;
float s = max(uBlendSoftness, 0.0);
mat2 blendRot = Rot(radians(uBlendAngle));
float blendX = (tuv * blendRot).x;
float edge0 = -0.3 - b - s;
float edge1 = 0.2 - b + s;
float v0 = 0.5 - b + s;
float v1 = -0.3 - b - s;
vec3 layer1 = mix(colDark, colOrg, S(edge0, edge1, blendX));
vec3 layer2 = mix(colOrg, colLav, S(edge0, edge1, blendX));
vec3 col = mix(layer1, layer2, S(v0, v1, tuv.y));
vec2 grainUv = uv * max(uGrainScale, 0.001);
if (uGrainAnimated > 0.5) {
grainUv += vec2(iTime * 0.05);
}
float grain = fract(sin(dot(grainUv, vec2(12.9898, 78.233))) * 43758.5453);
col += (grain - 0.5) * uGrainAmount;
col = (col - 0.5) * uContrast + 0.5;
float luma = dot(col, vec3(0.2126, 0.7152, 0.0722));
col = mix(vec3(luma), col, uSaturation);
col = pow(max(col, 0.0), vec3(1.0 / max(uGamma, 0.001)));
col = clamp(col, 0.0, 1.0);
o = vec4(col, 1.0);
}
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;
class GrainientBackgroundComponent {
constructor(ngZone) {
this.ngZone = ngZone;
/** 渐变混合中使用的主色(十六进制字符串) */
this.ncColor1 = '#FF9FFC';
/** 渐变混合中使用的辅助强调色(十六进制字符串) */
this.ncColor2 = '#5227FF';
/** 渐变混合中使用了深色底色(十六进制字符串) */
this.ncColor3 = '#B19EEF';
/** 渐变动画的速度倍增器(0-5) */
this.ncTimeSpeed = 0.25;
/** 将色调平衡向深色或浅色方向调整(-1.0 到 1.0) */
this.ncColorBalance = 0.0;
/** 波扭曲变形强度(0-4) */
this.ncWarpStrength = 1.0;
/** 波的弯曲频率(0-12) */
this.ncWarpFrequency = 5.0;
/** 弯曲动画的速度倍率(0-6)*/
this.ncWarpSpeed = 2.0;
/** 扭曲变形的基准振幅(5-80) */
this.ncWarpAmplitude = 50.0;
/** 颜色混合轴的旋转角度(deg -180-180) */
this.ncBlendAngle = 0.0;
/** 柔化颜色图层之间的过渡边缘(0-0.4) */
this.ncBlendSoftness = 0.05;
/** 旋转量受噪声驱动(0-1440) */
this.ncRotationAmount = 500.0;
/** 调整驱动旋转的噪声频率(0-4) */
this.ncNoiseScale = 2.0;
/** 颗粒感强度(0-0.4) */
this.ncGrainAmount = 0.1;
/** 颗粒感尺度(0.2-8) */
this.ncGrainScale = 2.0;
/** 让谷物随时间变化呈现动画效果 */
this._grainAnimated = false;
/** 对最终颜色进行整体对比度调整(0-2.5) */
this.ncContrast = 1.5;
/** 最终颜色的伽马校正(0.4-2.5) */
this.ncGamma = 1.0;
/** 最终颜色的饱和度(0-2.5) */
this.ncSaturation = 1.0;
/** 渐变中心的水平偏移量(-1-1) */
this.ncCenterX = 0.0;
/** 渐变中心垂直偏移量(-1-1) */
this.ncCenterY = 0.0;
/** 渐变场的缩放级别(0.3-3) */
this.ncZoom = 0.9;
this.time0 = performance.now();
this.rafId = null;
}
set ncGrainAnimated(val) {
this._grainAnimated = val !== null && val !== undefined && val !== false && val !== 'false';
}
get ncGrainAnimated() {
return this._grainAnimated;
}
ngOnInit() { }
ngAfterViewInit() {
this.ngZone.runOutsideAngular(() => {
this.initScene();
this.setupResizeObserver();
this.animate();
});
}
ngOnDestroy() {
if (this.rafId)
cancelAnimationFrame(this.rafId);
if (this.resizeObserver)
this.resizeObserver.disconnect();
if (this.renderer) {
this.renderer.dispose();
this.renderer.forceContextLoss();
this.renderer.domElement.remove();
}
}
ngOnChanges(changes) {
if (!this.material)
return;
this.updateUniforms();
}
initScene() {
const container = this.containerRef.nativeElement;
const { width, height } = container.getBoundingClientRect();
this.renderer = new THREE.WebGLRenderer({ antialias: false, alpha: true });
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
this.renderer.setSize(width || 1, height || 1);
container.appendChild(this.renderer.domElement);
this.scene = new THREE.Scene();
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const geometry = new THREE.PlaneGeometry(2, 2);
this.material = new THREE.ShaderMaterial({
vertexShader: vertex,
fragmentShader: fragment,
uniforms: {
iTime: { value: 0 },
iResolution: { value: new THREE.Vector2(width, height) },
uTimeSpeed: { value: this.ncTimeSpeed },
uColorBalance: { value: this.ncColorBalance },
uWarpStrength: { value: this.ncWarpStrength },
uWarpFrequency: { value: this.ncWarpFrequency },
uWarpSpeed: { value: this.ncWarpSpeed },
uWarpAmplitude: { value: this.ncWarpAmplitude },
uBlendAngle: { value: this.ncBlendAngle },
uBlendSoftness: { value: this.ncBlendSoftness },
uRotationAmount: { value: this.ncRotationAmount },
uNoiseScale: { value: this.ncNoiseScale },
uGrainAmount: { value: this.ncGrainAmount },
uGrainScale: { value: this.ncGrainScale },
uGrainAnimated: { value: this.ncGrainAnimated ? 1.0 : 0.0 },
uContrast: { value: this.ncContrast },
uGamma: { value: this.ncGamma },
uSaturation: { value: this.ncSaturation },
uCenterOffset: { value: new THREE.Vector2(this.ncCenterX, this.ncCenterY) },
uZoom: { value: this.ncZoom },
uColor1: { value: new Float32Array(this.hexToRgb(this.ncColor1)) },
uColor2: { value: new Float32Array(this.hexToRgb(this.ncColor2)) },
uColor3: { value: new Float32Array(this.hexToRgb(this.ncColor3)) }
}
});
this.mesh = new THREE.Mesh(geometry, this.material);
this.scene.add(this.mesh);
}
updateUniforms() {
const u = this.material.uniforms;
u['uTimeSpeed'].value = this.ncTimeSpeed;
u['uColorBalance'].value = this.ncColorBalance;
u['uWarpStrength'].value = this.ncWarpStrength;
u['uWarpFrequency'].value = this.ncWarpFrequency;
u['uWarpSpeed'].value = this.ncWarpSpeed;
u['uWarpAmplitude'].value = this.ncWarpAmplitude;
u['uBlendAngle'].value = this.ncBlendAngle;
u['uBlendSoftness'].value = this.ncBlendSoftness;
u['uRotationAmount'].value = this.ncRotationAmount;
u['uNoiseScale'].value = this.ncNoiseScale;
u['uGrainAmount'].value = this.ncGrainAmount;
u['uGrainScale'].value = this.ncGrainScale;
u['uGrainAnimated'].value = this.ncGrainAnimated ? 1.0 : 0.0;
u['uContrast'].value = this.ncContrast;
u['uGamma'].value = this.ncGamma;
u['uSaturation'].value = this.ncSaturation;
u['uCenterOffset'].value.set(this.ncCenterX, this.ncCenterY);
u['uZoom'].value = this.ncZoom;
u['uColor1'].value = new Float32Array(this.hexToRgb(this.ncColor1));
u['uColor2'].value = new Float32Array(this.hexToRgb(this.ncColor2));
u['uColor3'].value = new Float32Array(this.hexToRgb(this.ncColor3));
}
hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (!result)
return [1, 1, 1];
return [parseInt(result[1], 16) / 255, parseInt(result[2], 16) / 255, parseInt(result[3], 16) / 255];
}
setupResizeObserver() {
this.resizeObserver = new ResizeObserver(() => {
this.ngZone.runOutsideAngular(() => {
this.onResize();
});
});
this.resizeObserver.observe(this.containerRef.nativeElement);
}
onResize() {
const container = this.containerRef.nativeElement;
const { width, height } = container.getBoundingClientRect();
if (width === 0 || height === 0)
return;
this.renderer.setSize(width, height);
this.material.uniforms['iResolution'].value.set(width, height);
}
animate() {
this.rafId = requestAnimationFrame((t) => {
this.animate();
this.render(t);
});
}
render(t) {
this.material.uniforms['iTime'].value = (t - this.time0) * 0.001;
this.renderer.render(this.scene, this.camera);
}
}
GrainientBackgroundComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: GrainientBackgroundComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
GrainientBackgroundComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: GrainientBackgroundComponent, selector: "nc-grainient-background", inputs: { ncColor1: "ncColor1", ncColor2: "ncColor2", ncColor3: "ncColor3", ncTimeSpeed: "ncTimeSpeed", ncColorBalance: "ncColorBalance", ncWarpStrength: "ncWarpStrength", ncWarpFrequency: "ncWarpFrequency", ncWarpSpeed: "ncWarpSpeed", ncWarpAmplitude: "ncWarpAmplitude", ncBlendAngle: "ncBlendAngle", ncBlendSoftness: "ncBlendSoftness", ncRotationAmount: "ncRotationAmount", ncNoiseScale: "ncNoiseScale", ncGrainAmount: "ncGrainAmount", ncGrainScale: "ncGrainScale", ncGrainAnimated: "ncGrainAnimated", ncContrast: "ncContrast", ncGamma: "ncGamma", ncSaturation: "ncSaturation", ncCenterX: "ncCenterX", ncCenterY: "ncCenterY", ncZoom: "ncZoom" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #container class=\"nc-grainient-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-grainient-canvas-container{position:absolute;inset:0;z-index:0}.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: GrainientBackgroundComponent, decorators: [{
type: Component,
args: [{
selector: 'nc-grainient-background',
templateUrl: './grainient-background.component.html',
styleUrls: ['./grainient-background.component.less']
}]
}], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { containerRef: [{
type: ViewChild,
args: ['container', { static: true }]
}], ncColor1: [{
type: Input
}], ncColor2: [{
type: Input
}], ncColor3: [{
type: Input
}], ncTimeSpeed: [{
type: Input
}], ncColorBalance: [{
type: Input
}], ncWarpStrength: [{
type: Input
}], ncWarpFrequency: [{
type: Input
}], ncWarpSpeed: [{
type: Input
}], ncWarpAmplitude: [{
type: Input
}], ncBlendAngle: [{
type: Input
}], ncBlendSoftness: [{
type: Input
}], ncRotationAmount: [{
type: Input
}], ncNoiseScale: [{
type: Input
}], ncGrainAmount: [{
type: Input
}], ncGrainScale: [{
type: Input
}], ncGrainAnimated: [{
type: Input
}], ncContrast: [{
type: Input
}], ncGamma: [{
type: Input
}], ncSaturation: [{
type: Input
}], ncCenterX: [{
type: Input
}], ncCenterY: [{
type: Input
}], ncZoom: [{
type: Input
}] } });
class NcGrainientBackgroundModule {
}
NcGrainientBackgroundModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NcGrainientBackgroundModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, declarations: [GrainientBackgroundComponent], imports: [CommonModule], exports: [GrainientBackgroundComponent] });
NcGrainientBackgroundModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, imports: [[
CommonModule
]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcGrainientBackgroundModule, decorators: [{
type: NgModule,
args: [{
declarations: [
GrainientBackgroundComponent
],
imports: [
CommonModule
],
exports: [
GrainientBackgroundComponent
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { GrainientBackgroundComponent, NcGrainientBackgroundModule };
//# sourceMappingURL=ng-cw-v12-grainient-background.js.map