UNPKG

ngx-acuw

Version:

Angular components using WEBGL (threejs)

587 lines 83.6 kB
import { Component, EventEmitter, HostListener, Input, Output, ViewChild, } from '@angular/core'; import { interval, NEVER, Observable, of, Subject, Subscription, zip, } from 'rxjs'; import { delay, switchMap, tap } from 'rxjs/operators'; import { DoubleSide, Mesh, PerspectiveCamera, PlaneBufferGeometry, Scene, ShaderMaterial, Vector4, WebGLRenderer, } from 'three'; import { TextureLoader } from 'three'; import { RxjsTween } from '../tween/rxjs-tween'; import { Direction } from './interfaces/direction'; import { ImageTransitionShaders } from './shaders/imageTransitionShaders'; import * as i0 from "@angular/core"; import * as i1 from "../performance-monitor/performance-monitor.component"; import * as i2 from "@angular/common"; export class ImageTransitionComponent { constructor(ngZone) { this.ngZone = ngZone; this.imageUrls = new Array(); this.transitionDuration = 1000; this.animationEnabled = true; this.startIndex = 0; this.showPerformanceMonitor = false; this.imageIndexChange = new EventEmitter(); this.pAutoPlay = false; this.pAutoPlayInterval = 5000; this.pImageSize = 'cover'; this.pTransitionType = 'split'; this.pIntensity = 40.0; this.pScaleX = 50.0; this.pScaleY = 50.0; this.pWidth = 0.5; this.pDistortionImageUrl = ''; this.renderer = new WebGLRenderer({ antialias: true, alpha: true, }); this.scene = new Scene(); this.textures = new Array(); this.nextImageIndex = 0; this.tranistionOngoing = false; this.shaders = new ImageTransitionShaders(); this.autoPlay$ = new Observable(); this.autoPlaySubscription = new Subscription(); this.subscriptions = new Subscription(); this.basicAssetsLoaded$$ = new Subject(); this.forwardTextureLoaded$$ = new Subject(); this.backwardTextureLoaded$$ = new Subject(); this.showLoadingSpinner$$ = new Subject(); this.transitToForwardTexture$$ = new Subject(); this.transitToBackwardTexture$$ = new Subject(); // When true -> show spinner after a delay // When false -> hide spinner immediatelly this.showLoadingSpinner$ = this.showLoadingSpinner$$.pipe(switchMap((show) => { if (show) { return of(show).pipe(delay(300)); } else { return of(show); } })); this.subscribeToInitScene(); this.subscribeTransistionToBackwardTexture(); this.subscribeTransistionToForwardTexture(); } get displacementImageUrl() { return this.pDistortionImageUrl; } set displacementImageUrl(displacementImageUrl) { this.pDistortionImageUrl = displacementImageUrl; if (this.material != null) { this.setShaderProperties(); } } get imageSize() { return this.pImageSize; } set imageSize(imageSize) { this.pImageSize = imageSize; if (this.mesh != null) { this.resize(); } } get autoPlay() { return this.pAutoPlay; } set autoPlay(autoplay) { this.pAutoPlay = autoplay; if (this.mesh != null) { if (this.pAutoPlay === true) { this.setAutoPlayInterval(); } else { this.stopAutoPlayInterval(); } } } get autoPlayInterval() { return this.pAutoPlayInterval; } set autoPlayInterval(autoPlayInterval) { this.pAutoPlayInterval = autoPlayInterval; if (this.mesh != null) { if (this.pAutoPlay === true) { this.setAutoPlayInterval(); } } } get transitionType() { return this.pTransitionType; } set transitionType(transitionType) { this.pTransitionType = transitionType; if (this.material != null) { this.setShaderProperties(); } } get sizeX() { return this.pScaleX; } set sizeX(sizeX) { this.pScaleX = sizeX; if (this.material != null) { this.setShaderProperties(); } } get sizeY() { return this.pScaleY; } set sizeY(sizeY) { this.pScaleY = sizeY; if (this.material != null) { this.setShaderProperties(); } } get width() { return this.pWidth; } set width(width) { this.pWidth = width; if (this.material != null) { this.setShaderProperties(); } } get intensity() { return this.intensity; } set intensity(intensity) { this.pIntensity = intensity; if (this.material != null) { this.setShaderProperties(); } } ngAfterViewInit() { if (this.imageUrls.length < 2) { throw new Error('At least two images are required'); } // Init camera this.camera = new PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.001, 1000); this.camera.position.set(0, 0, 2); // Init renderer this.renderer.setSize(this.threejsContainer.nativeElement.clientWidth, this.threejsContainer.nativeElement.clientHeight); this.renderer.setPixelRatio(window.devicePixelRatio); this.threejsContainer.nativeElement.appendChild(this.renderer.domElement); // Create scene this.scene = new Scene(); // Load currenct, backwards and forwards textures this.textures = new Array(this.imageUrls.length); this.loadBasicAssets(); const backwardImgIdx = this.startIndex === 0 ? this.imageUrls.length - 1 : this.startIndex - 1; this.loadTexture(backwardImgIdx, Direction.backward); const forwardImgIdx = this.startIndex === this.imageUrls.length - 1 ? 0 : this.startIndex + 1; this.loadTexture(forwardImgIdx, Direction.forward); // Init autoPlay Observable if (this.pAutoPlay === true) { this.setAutoPlayInterval(); } this.animate(); } ngOnDestroy() { // Cancel Animation cancelAnimationFrame(this.animationFrameId); // Stop autoplay animation this.stopAutoPlayInterval(); // Remove threejs container from DOM this.threejsContainer.nativeElement.removeChild(this.renderer.domElement); // Dispose textures this.textures.forEach((t) => { t.dispose(); }); // Dispose material if (this.material) { this.material.dispose(); } // Clear scene if (this.scene) { this.scene.clear(); } // Dispose renderer if (this.renderer) { this.renderer.dispose(); } this.subscriptions.unsubscribe(); } subscribeToInitScene() { this.subscriptions.add(this.basicAssetsLoaded$$ .pipe(tap(() => this.initBasiscScene())) .subscribe()); } subscribeTransistionToForwardTexture() { this.subscriptions.add(zip(this.transitToForwardTexture$$, this.forwardTextureLoaded$$) .pipe(tap(() => this.showLoadingSpinner$$.next(false)), tap(() => this.prepAndLoadNextImg(Direction.forward))) .subscribe()); } subscribeTransistionToBackwardTexture() { this.subscriptions.add(zip(this.transitToBackwardTexture$$, this.backwardTextureLoaded$$) .pipe(tap(() => this.showLoadingSpinner$$.next(false)), tap(() => this.prepAndLoadNextImg(Direction.backward))) .subscribe()); } loadBasicAssets() { this.showLoadingSpinner$$.next(true); const promises = new Array(); // Initial image to be shown promises.push(new Promise((resolve) => { this.textures[this.startIndex] = new TextureLoader().load(this.imageUrls[this.startIndex], resolve); })); if (this.displacementImageUrl !== '') { promises.push(new Promise((resolve) => { this.displacementTexture = new TextureLoader().load(this.displacementImageUrl, resolve); })); } Promise.all(promises) .then(() => this.basicAssetsLoaded$$.next()) .catch((err) => console.error(err)) .finally(() => this.showLoadingSpinner$$.next(false)); } loadTexture(index, direction) { new TextureLoader() .loadAsync(this.imageUrls[index]) .then((texture) => { this.textures[index] = texture; switch (direction) { case Direction.forward: this.forwardTextureLoaded$$.next(); break; case Direction.backward: this.backwardTextureLoaded$$.next(); break; } }) .catch((err) => console.error(err)); } initBasiscScene() { // Create geometry const geometry = new PlaneBufferGeometry(1, 1, 2, 2); this.nextImageIndex = this.startIndex; // Emit event to set current image index this.imageIndexChange.emit(this.nextImageIndex); this.material = new ShaderMaterial({ side: DoubleSide, uniforms: { time: { value: 0 }, progress: { value: 0 }, border: { value: 0 }, intensity: { value: 50.0 }, angle1: { value: Math.PI / 4 }, angle2: { value: -Math.PI + Math.PI / 4 }, scaleX: { value: 40.0 }, scaleY: { value: 40.0 }, transition: { value: 40.0 }, swipe: { value: 0 }, width: { value: 0.5 }, radius: { value: 0 }, texture1: { value: this.textures[this.startIndex] }, texture2: { value: null }, displacementTexture: { value: this.displacementTexture }, resolution1: { value: new Vector4() }, resolution2: { value: new Vector4() }, }, // wireframe: true, vertexShader: this.shaders.vertex, }); this.setShaderProperties(); this.mesh = new Mesh(geometry, this.material); this.scene.add(this.mesh); // Call the resize method once to set the texture resultion correclty this.resize(); } /** * Sets the autoPlay interval */ setAutoPlayInterval() { this.autoPlay$ = interval(this.pAutoPlayInterval); this.autoPlaySubscription = this.autoPlay$.pipe(tap(() => this.transitToForwardTexture$$.next())).subscribe(); } /** * Resets the autoPlay interval */ resetAutoPlayInterval() { this.autoPlay$ = NEVER; this.autoPlaySubscription.unsubscribe(); this.setAutoPlayInterval(); } /** * Stops the autoPlay interval */ stopAutoPlayInterval() { this.autoPlay$ = NEVER; this.autoPlaySubscription.unsubscribe(); } /** * Sets the shader properties depending on the transition type */ setShaderProperties() { switch (this.transitionType) { case 'split': this.material.uniforms.intensity.value = this.pIntensity; this.material.fragmentShader = this.shaders.splitTransitionFrag; break; case 'fade': this.material.fragmentShader = this.shaders.fadeFrag; break; case 'noise': this.material.uniforms.scaleX.value = this.pScaleX; this.material.uniforms.scaleY.value = this.pScaleY; this.material.uniforms.width.value = this.pWidth; this.material.fragmentShader = this.shaders.noiseFrag; break; case 'blur': this.material.uniforms.intensity.value = this.pIntensity; this.material.fragmentShader = this.shaders.blurFrag; break; case 'distortion': this.material.uniforms.displacementTexture.value = new TextureLoader().load(this.displacementImageUrl); this.material.uniforms.intensity.value = this.pIntensity; this.material.fragmentShader = this.shaders.distortionFrag; break; default: break; } this.material.needsUpdate = true; } /** * Animation */ animate() { if (this.animationEnabled === true) { this.renderer.render(this.scene, this.camera); } if (this.performanceMonitor && this.showPerformanceMonitor) { this.performanceMonitor.end(); } this.ngZone.runOutsideAngular(() => { this.animationFrameId = window.requestAnimationFrame(() => this.animate()); }); } /** * Resizes the canvas and updates the texture resulution information of the images */ resize() { // Get the with and height of the container const containerWidth = this.threejsContainer.nativeElement.offsetWidth; const containerHeight = this.threejsContainer.nativeElement.offsetHeight; // return the function, if eihter with or heigth is undefined if (!containerHeight || !containerHeight) { return; } this.renderer.setSize(containerWidth, containerHeight); this.camera.aspect = containerWidth / containerHeight; this.updateTextureResolution(this.nextImageIndex, 1); const dist = this.camera.position.z; const height = 1; this.camera.fov = 2 * (180 / Math.PI) * Math.atan(height / (2 * dist)); this.mesh.scale.x = this.camera.aspect; this.mesh.scale.y = 1; this.camera.updateProjectionMatrix(); } /** * Updates the resulution of the texture for the shader depending on the image size type * @param textureNumber Number of the texture */ updateTextureResolution(textureNumber, targetGlslTexture) { const texture = this.textures[textureNumber]; const containerWidth = this.threejsContainer.nativeElement.offsetWidth; const containerHeight = this.threejsContainer.nativeElement.offsetHeight; // Adapt the size of the image const imageAspect = texture.image.height / texture.image.width; const containerAspect = containerHeight / containerWidth; let a1; let a2; if (this.pImageSize === 'cover') { if (containerAspect > imageAspect) { a1 = (containerWidth / containerHeight) * imageAspect; a2 = 1; } else { a1 = 1; a2 = containerHeight / containerWidth / imageAspect; } } else if (this.pImageSize === 'contain') { if (containerAspect < imageAspect) { a1 = (containerWidth / containerHeight) * imageAspect; a2 = 1; } else { a1 = 1; a2 = containerHeight / containerWidth / imageAspect; } } if (targetGlslTexture === 1) { this.material.uniforms.resolution1.value.x = containerWidth; this.material.uniforms.resolution1.value.y = containerHeight; this.material.uniforms.resolution1.value.z = a1; this.material.uniforms.resolution1.value.w = a2; } else if (targetGlslTexture === 2) { this.material.uniforms.resolution2.value.x = containerWidth; this.material.uniforms.resolution2.value.y = containerHeight; this.material.uniforms.resolution2.value.z = a1; this.material.uniforms.resolution2.value.w = a2; } } /** * Starts the transition effect to the next image * @param posDirection indicator, if the next or previous image should be loaded */ transitionToNextTexture(direction) { // EventEmitter this.imageIndexChange.emit(this.nextImageIndex); this.ngZone.runOutsideAngular(() => { if (direction === Direction.backward) { this.material.uniforms.texture2.value = this.material.uniforms.texture1.value; this.material.uniforms.resolution2.value.x = this.material.uniforms.resolution1.value.x; this.material.uniforms.resolution2.value.y = this.material.uniforms.resolution1.value.y; this.material.uniforms.resolution2.value.z = this.material.uniforms.resolution1.value.z; this.material.uniforms.resolution2.value.w = this.material.uniforms.resolution1.value.w; this.material.uniforms.progress.value = 1; // Set the next image to texture1 and update the resolution this.material.uniforms.texture1.value = this.textures[this.nextImageIndex]; this.updateTextureResolution(this.nextImageIndex, 1); // Start the tween for doing the transition RxjsTween.createTween(RxjsTween.linear, 1, 0, this.transitionDuration).subscribe({ next: (val) => { this.material.uniforms.progress.value = val; }, complete: () => { // Set the transition flag to false to indicate that the transition animation is finished this.tranistionOngoing = false; // Reset progress to 1, thus the texture from texture 2 needs to be set to texture 1 this.material.uniforms.texture2.value = this.textures[this.nextImageIndex]; this.updateTextureResolution(this.nextImageIndex, 2); this.material.uniforms.progress.value = 0; }, }); } else { // Set the next image to texture2 and update the resolution this.material.uniforms.texture2.value = this.textures[this.nextImageIndex]; this.updateTextureResolution(this.nextImageIndex, 2); // Start the tween for doing the transition RxjsTween.createTween(RxjsTween.linear, 0, 1, this.transitionDuration).subscribe({ next: (val) => { this.material.uniforms.progress.value = val; }, complete: () => { // Set the transition flag to false to indicate that the transition animation is finished this.tranistionOngoing = false; // Reset progress to 0, thus the texture from texture 2 needs to be set to texture 1 this.material.uniforms.texture1.value = this.textures[this.nextImageIndex]; this.updateTextureResolution(this.nextImageIndex, 1); this.material.uniforms.progress.value = 0; }, }); } }); } prepAndLoadNextImg(direction) { // Set the flag to indicate that the transition animation is ongoing this.tranistionOngoing = true; let nextButOne = 0; if (direction === Direction.forward) { // Set the next index this.nextImageIndex = this.nextImageIndex < this.imageUrls.length - 1 ? this.nextImageIndex + 1 : 0; // Check if another texture needs to be loaded nextButOne = this.nextImageIndex + 1 > this.imageUrls.length - 1 ? 0 : this.nextImageIndex + 1; this.loadTexture(nextButOne, Direction.forward); } else { // Update the number of the current shown image this.nextImageIndex = this.nextImageIndex > 0 ? this.nextImageIndex - 1 : this.imageUrls.length - 1; // Check if another texture needs to be loaded nextButOne = this.nextImageIndex - 1 < 0 ? this.imageUrls.length - 1 : this.nextImageIndex - 1; this.loadTexture(nextButOne, Direction.backward); } this.transitionToNextTexture(direction); } nextImage(direction) { if (this.tranistionOngoing) { console.warn('cannot go to next image. transition still ongoing.'); return; } if (this.pAutoPlay) { this.resetAutoPlayInterval(); } this.showLoadingSpinner$$.next(true); switch (direction) { case Direction.backward: this.transitToBackwardTexture$$.next(); break; case Direction.forward: this.transitToForwardTexture$$.next(); break; } } //#region public methods next() { this.nextImage(Direction.forward); } prev() { this.nextImage(Direction.backward); } } ImageTransitionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ImageTransitionComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ImageTransitionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: ImageTransitionComponent, selector: "lib-image-transition", inputs: { imageUrls: "imageUrls", displacementImageUrl: "displacementImageUrl", imageSize: "imageSize", autoPlay: "autoPlay", autoPlayInterval: "autoPlayInterval", transitionDuration: "transitionDuration", transitionType: "transitionType", sizeX: "sizeX", sizeY: "sizeY", width: "width", intensity: "intensity", animationEnabled: "animationEnabled", startIndex: "startIndex", showPerformanceMonitor: "showPerformanceMonitor" }, outputs: { imageIndexChange: "imageIndexChange" }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "threejsContainer", first: true, predicate: ["threejsContainer"], descendants: true }, { propertyName: "performanceMonitor", first: true, predicate: ["performanceMonitor"], descendants: true }], ngImport: i0, template: "<div #threejsContainer class=\"threejs-container\">\r\n <div *ngIf=\"showLoadingSpinner$ | async\" class=\"loading-container\">\r\n <div class=\"lds-ripple\">\r\n <div></div>\r\n <div></div>\r\n </div>\r\n </div>\r\n</div>\r\n<acuw-performance-monitor\r\n *ngIf=\"showPerformanceMonitor\"\r\n #performanceMonitor\r\n></acuw-performance-monitor>\r\n", styles: [".threejs-container{position:relative;width:100%;height:100%}.loading-container{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center}.lds-ripple{display:inline-block;position:relative;width:80px;height:80px;background-color:#0006;border-radius:40px;box-shadow:0 0 24px 12px #00000080}.lds-ripple div{position:absolute;border:4px solid #fff;opacity:1;border-radius:50%;animation:lds-ripple 1s cubic-bezier(0,.2,.8,1) infinite}.lds-ripple div:nth-child(2){animation-delay:-.5s}@keyframes lds-ripple{0%{top:36px;left:36px;width:0;height:0;opacity:1}to{top:0px;left:0px;width:72px;height:72px;opacity:0}}\n"], components: [{ type: i1.PerformanceMonitorComponent, selector: "acuw-performance-monitor" }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i2.AsyncPipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ImageTransitionComponent, decorators: [{ type: Component, args: [{ selector: 'lib-image-transition', template: "<div #threejsContainer class=\"threejs-container\">\r\n <div *ngIf=\"showLoadingSpinner$ | async\" class=\"loading-container\">\r\n <div class=\"lds-ripple\">\r\n <div></div>\r\n <div></div>\r\n </div>\r\n </div>\r\n</div>\r\n<acuw-performance-monitor\r\n *ngIf=\"showPerformanceMonitor\"\r\n #performanceMonitor\r\n></acuw-performance-monitor>\r\n", styles: [".threejs-container{position:relative;width:100%;height:100%}.loading-container{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center}.lds-ripple{display:inline-block;position:relative;width:80px;height:80px;background-color:#0006;border-radius:40px;box-shadow:0 0 24px 12px #00000080}.lds-ripple div{position:absolute;border:4px solid #fff;opacity:1;border-radius:50%;animation:lds-ripple 1s cubic-bezier(0,.2,.8,1) infinite}.lds-ripple div:nth-child(2){animation-delay:-.5s}@keyframes lds-ripple{0%{top:36px;left:36px;width:0;height:0;opacity:1}to{top:0px;left:0px;width:72px;height:72px;opacity:0}}\n"] }] }], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { imageUrls: [{ type: Input }], displacementImageUrl: [{ type: Input }], imageSize: [{ type: Input }], autoPlay: [{ type: Input }], autoPlayInterval: [{ type: Input }], transitionDuration: [{ type: Input }], transitionType: [{ type: Input }], sizeX: [{ type: Input }], sizeY: [{ type: Input }], width: [{ type: Input }], intensity: [{ type: Input }], animationEnabled: [{ type: Input }], startIndex: [{ type: Input }], showPerformanceMonitor: [{ type: Input }], imageIndexChange: [{ type: Output }], threejsContainer: [{ type: ViewChild, args: ['threejsContainer'] }], performanceMonitor: [{ type: ViewChild, args: ['performanceMonitor'] }], resize: [{ type: HostListener, args: ['window:resize'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtdHJhbnNpdGlvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYWN1dy9zcmMvbGliL2ltYWdlLXRyYW5zaXRpb24vaW1hZ2UtdHJhbnNpdGlvbi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYWN1dy9zcmMvbGliL2ltYWdlLXRyYW5zaXRpb24vaW1hZ2UtdHJhbnNpdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsU0FBUyxFQUVULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUNMLFFBQVEsRUFDUixLQUFLLEVBQ0wsVUFBVSxFQUNWLEVBQUUsRUFDRixPQUFPLEVBQ1AsWUFBWSxFQUNaLEdBQUcsR0FDSixNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZELE9BQU8sRUFDTCxVQUFVLEVBQ1YsSUFBSSxFQUNKLGlCQUFpQixFQUNqQixtQkFBbUIsRUFDbkIsS0FBSyxFQUNMLGNBQWMsRUFFZCxPQUFPLEVBQ1AsYUFBYSxHQUNkLE1BQU0sT0FBTyxDQUFDO0FBQ2YsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUV0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ25ELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDOzs7O0FBTzFFLE1BQU0sT0FBTyx3QkFBd0I7SUF3S25DLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBdkt6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