UNPKG

ngx-screen-saver

Version:
363 lines (348 loc) 14 kB
import * as i0 from '@angular/core'; import { Injectable, Component, Input, NgModule } from '@angular/core'; import p5 from 'p5'; import { BehaviorSubject, merge, fromEvent, timer } from 'rxjs'; import { startWith, throttleTime, tap, switchMap } from 'rxjs/operators'; const reverseLoop = (arr, callback) => { for (let i = arr.length - 1; i >= 0; i--) { callback(arr[i], i); } }; class Star { constructor(p5, x, y) { this.p5 = p5; this.x = x; this.y = y; this.MAX_SIZE = 5; this.size = 1; this.decay = false; this.destroy = false; this.growth = this.p5.random(15, 50) / 500; } update() { if (this.decay === false) { this.size = this.size + this.growth; } if (this.decay === true) { this.size = this.size - this.growth; } if (this.size >= this.MAX_SIZE) { this.decay = true; } if (this.size <= 0) { this.destroy = true; } } draw() { this.p5.noStroke(); this.p5.fill(255); this.p5.circle(this.x, this.y, this.size); } } const MAX_STARS = 100; const starsArr = []; const stars = (p5) => { const width = p5.windowWidth; const height = p5.windowHeight; let backgroundImage; // PRELOAD p5.preload = () => { backgroundImage = p5.loadImage('assets/ngx-screen-saver/galaxy.jpg'); }; // SETUP p5.setup = () => { p5.createCanvas(width, height).addClass('ngx-screen-saver'); p5.image(backgroundImage, 0, 0); for (let i = 0; i < MAX_STARS; i++) { const star = new Star(p5, p5.random(0, width), p5.random(0, height)); starsArr.push(star); } }; // DRAW p5.draw = () => { p5.image(backgroundImage, 0, 0); reverseLoop(starsArr, (star, idx) => { star.update(); star.draw(); if (star.destroy) { starsArr.splice(idx, 1); const newStar = new Star(p5, p5.random(0, width), p5.random(0, height)); starsArr.push(newStar); } }); }; }; const dvd = (p5) => { const width = p5.windowWidth; const height = p5.windowHeight; let dvdLogo; let posX = 300; let posY = 100; let velX; let velY; // PRELOAD p5.preload = () => { dvdLogo = p5.loadImage('assets/ngx-screen-saver/dvd_logo.png'); }; // SETUP p5.setup = () => { p5.createCanvas(width, height).addClass('ngx-screen-saver'); p5.background(0); velX = 7; velY = 5; }; // DRAW p5.draw = () => { p5.background(0); p5.image(dvdLogo, posX, posY); posX = posX + velX; posY = posY + velY; if (posX + dvdLogo.width >= width || posX <= 0) { velX = -velX; } if (posY + dvdLogo.height >= height || posY <= 0) { velY = -velY; } }; }; const randomHslFromRange = (p5, hue, margin) => { let randomNumber = p5.random(hue - margin, hue + margin); if (randomNumber < 0) { randomNumber = 360 - randomNumber; } if (randomNumber > 360) { randomNumber = randomNumber - 360; } p5.colorMode(p5.HSL); return p5.color(randomNumber, 100, 50); }; class Particle { constructor(p5, pos, vel, size, color, rotation) { this.p5 = p5; this.pos = pos; this.vel = vel; this.size = size; this.color = color; this.rotation = rotation; if (this.rotation) { this.vel.rotate(this.rotation); this.vel.setMag(this.p5.random(1, 2)); } } update() { this.pos.add(this.vel); } draw() { this.p5.noStroke(); this.p5.fill(this.color); this.p5.circle(this.pos.x, this.pos.y, this.size); } } class Firework { constructor(p5, posX, maxHeight) { this.p5 = p5; this.posX = posX; this.maxHeight = maxHeight; this.pos = this.p5.createVector(this.posX, 0); this.vel = this.p5.createVector(0, this.p5.random(1.5, 2.5)); this.randomHue = this.p5.random(0, 360); this.phase = 'fly'; this.explosionParticlesCreated = false; this.fireParticles = []; this.explosionParticles = []; } update() { this.p5.push(); this.p5.colorMode(this.p5.HSL); if (this.phase === 'fly') { this.pos.add(this.vel); this.fireParticles.push(new Particle(this.p5, this.p5.createVector(this.pos.x + this.p5.random(-2, 2), this.pos.y + this.p5.random(-2, 2)), this.p5.createVector(0, 0), 3, randomHslFromRange(this.p5, 30, 20))); if (this.fireParticles.length > 30) { this.fireParticles.splice(0, 1); } if (this.pos.y >= this.maxHeight) { this.phase = 'explode'; } } if (this.phase === 'explode') { if (this.fireParticles.length > 0) { this.fireParticles.splice(0, 1); } if (this.explosionParticlesCreated === false) { for (let i = 0; i < 150; i++) { const newParticle = new Particle(this.p5, this.pos.copy(), this.p5.createVector(1, 0), 5, randomHslFromRange(this.p5, this.randomHue, 20), this.p5.random(0, 360)); this.explosionParticles.push(newParticle); } this.explosionParticlesCreated = true; } if (this.explosionParticles.length <= 0) { this.phase = 'dispose'; } } this.p5.pop(); } draw() { this.p5.noStroke(); if (this.fireParticles.length > 0) { reverseLoop(this.fireParticles, (particle, idx) => { particle.update(); particle.draw(); }); } if (this.explosionParticles.length > 0) { reverseLoop(this.explosionParticles, (particle, idx) => { if (this.pos.dist(particle.pos) <= 50) { particle.update(); particle.draw(); } else { this.explosionParticles.splice(idx, 1); } }); } } } const fireworks = (p5) => { const WIDTH = p5.windowWidth; const HEIGHT = p5.windowHeight; const MAX_FIREWORKS = 10; const SAFE_MARGIN = 40; const SAFE_SPACE = { xStart: SAFE_MARGIN, xEnd: WIDTH - SAFE_MARGIN, yStart: 0, yEnd: HEIGHT - SAFE_MARGIN, }; const fireworksArr = []; let backgroundImg; // PRELOAD p5.preload = () => { backgroundImg = p5.loadImage('assets/ngx-screen-saver/fireworks_bg.jpg'); }; // SETUP p5.setup = () => { p5.createCanvas(WIDTH, HEIGHT).addClass('ngx-screen-saver'); p5.angleMode(p5.DEGREES); backgroundImg.resize(WIDTH, HEIGHT); for (let i = 0; i < MAX_FIREWORKS; i++) { fireworksArr.push(new Firework(p5, p5.random(SAFE_SPACE.xStart, SAFE_SPACE.xEnd), p5.random(SAFE_SPACE.yStart, SAFE_SPACE.yEnd))); } }; // DRAW p5.draw = () => { const heightOffset = HEIGHT - backgroundImg.height; p5.image(backgroundImg, 0, heightOffset); p5.translate(0, HEIGHT); // moves the origin to bottom left p5.scale(1, -1); // flips the y values so y increases "up" reverseLoop(fireworksArr, (firework, idx) => { firework.update(); firework.draw(); if (firework.phase === 'dispose') { fireworksArr.splice(idx, 1); fireworksArr.push(new Firework(p5, p5.random(SAFE_SPACE.xStart, SAFE_SPACE.xEnd), p5.random(SAFE_SPACE.yStart, SAFE_SPACE.yEnd))); } }); }; }; class IdleDetectionService { constructor() { this.isIdleSubject = new BehaviorSubject(false); this.isIdle$ = this.isIdleSubject.asObservable(); this.activityEvents$ = merge(fromEvent(window, 'mousemove'), fromEvent(window, 'resize'), fromEvent(document, 'keydown'), fromEvent(document, 'mousedown'), fromEvent(document, 'touchstart')); } startIdleDetection(idleAfterMs) { this.idleAfterMs = idleAfterMs; this.idleDetectionSubscription = this.activityEvents$ .pipe( // trigger idle detection before any user activity events startWith(undefined), throttleTime(100), tap(() => { this.isIdleSubject.next(false); }), switchMap(() => { return timer(this.idleAfterMs).pipe(tap(() => { this.isIdleSubject.next(true); })); })) .subscribe(); } stopIdleDetection() { this.idleDetectionSubscription?.unsubscribe(); } } IdleDetectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: IdleDetectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); IdleDetectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: IdleDetectionService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: IdleDetectionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return []; } }); class NgxScreenSaverComponent { constructor(idleDetectionService) { this.idleDetectionService = idleDetectionService; this.idleAfterMs = 10000; this.variant = 'fireworks'; this.opacity = 1; this.zIndex = 1; this.showScreenSaver = false; this.screenSavers = { stars, dvd, fireworks, }; } ngOnInit() { document.documentElement.style.setProperty('--ngx-screen-saver-opacity', this.opacity.toString()); document.documentElement.style.setProperty('--ngx-screen-saver-z-index', this.zIndex.toString()); this.idleDetectionService.startIdleDetection(this.idleAfterMs); this.isIdleSubscription = this.idleDetectionService.isIdle$.subscribe((isIdle) => { if (isIdle === true) { this.showScreenSaver = true; this.screenSaver = new p5(this.screenSavers[this.variant], document.querySelector('ngx-screen-saver')); } else { this.showScreenSaver = false; this.screenSaver?.remove(); this.screenSaver = undefined; } }); } ngOnDestroy() { this.idleDetectionService.stopIdleDetection(); this.isIdleSubscription.unsubscribe(); } } NgxScreenSaverComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverComponent, deps: [{ token: IdleDetectionService }], target: i0.ɵɵFactoryTarget.Component }); NgxScreenSaverComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.3", type: NgxScreenSaverComponent, selector: "ngx-screen-saver", inputs: { idleAfterMs: "idleAfterMs", variant: "variant", opacity: "opacity", zIndex: "zIndex" }, ngImport: i0, template: '', isInline: true, styles: ["::ng-deep :root{--ngx-screen-saver-opacity: 1;--ngx-screen-saver-z-index: 1}::ng-deep .ngx-screen-saver{position:fixed;top:0;left:0;opacity:var(--ngx-screen-saver-opacity);z-index:var(--ngx-screen-saver-z-index)}::ng-deep #p5_loading{display:none}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-screen-saver', template: '', styles: ["::ng-deep :root{--ngx-screen-saver-opacity: 1;--ngx-screen-saver-z-index: 1}::ng-deep .ngx-screen-saver{position:fixed;top:0;left:0;opacity:var(--ngx-screen-saver-opacity);z-index:var(--ngx-screen-saver-z-index)}::ng-deep #p5_loading{display:none}\n"] }] }], ctorParameters: function () { return [{ type: IdleDetectionService }]; }, propDecorators: { idleAfterMs: [{ type: Input }], variant: [{ type: Input }], opacity: [{ type: Input }], zIndex: [{ type: Input }] } }); class NgxScreenSaverModule { } NgxScreenSaverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NgxScreenSaverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverModule, declarations: [NgxScreenSaverComponent], exports: [NgxScreenSaverComponent] }); NgxScreenSaverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverModule, imports: [[]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: NgxScreenSaverModule, decorators: [{ type: NgModule, args: [{ declarations: [NgxScreenSaverComponent], imports: [], exports: [NgxScreenSaverComponent], }] }] }); /* * Public API Surface of ngx-screen-saver */ /** * Generated bundle index. Do not edit. */ export { NgxScreenSaverComponent, NgxScreenSaverModule }; //# sourceMappingURL=ngx-screen-saver.mjs.map