import { Component, Input, ViewChild, ElementRef, OnDestroy } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { Subscription, Subject } from 'rxjs'; import { BaseComponent } from 'app/base.component'; import { ConfigService } from 'app/core/ui-services/config.service'; import { ViewProjector } from 'app/site/projector/models/view-projector'; import { Size } from 'app/site/projector/size'; import { OfflineService } from 'app/core/core-services/offline.service'; import { SlideData, ProjectorDataService } from 'app/core/core-services/projector-data.service'; import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service'; /** * THE projector. Cares about scaling and the right size and resolution. * Watches the given projector and creates slide-containers for each projectorelement. */ @Component({ selector: 'os-projector', templateUrl: './projector.component.html', styleUrls: ['./projector.component.scss'] }) export class ProjectorComponent extends BaseComponent implements OnDestroy { /** * The current projector id. */ private projectorId: number | null = null; /** * The projector. Accessors are below. */ private _projector: ViewProjector; @Input() public set projector(projector: ViewProjector) { this._projector = projector; // check, if ID changed: const newId = projector ? projector.id : null; if (this.projectorId !== newId) { this.projectorIdChanged(this.projectorId, newId); this.projectorId = newId; } // Update scaling, if projector is set. if (projector) { const oldSize: Size = { ...this.currentProjectorSize }; this.currentProjectorSize.height = projector.height; this.currentProjectorSize.width = projector.width; if ( oldSize.height !== this.currentProjectorSize.height || oldSize.width !== this.currentProjectorSize.width ) { this.updateScaling(); } this.projectorStyle['background-color'] = projector.background_color; this.headerFooterStyle.color = projector.header_font_color; this.headerFooterStyle['background-color'] = projector.header_background_color; // alter the local scope css variable with the header_h1_color document.documentElement.style.setProperty('--header-h1-color', this.projector.header_h1_color); } } public get projector(): ViewProjector { return this._projector; } /** * The current projector size. This is for checking, * if the size actually has changed. */ private currentProjectorSize: Size = { width: 0, height: 0 }; /** * Ths subscription to the projectordata. */ private dataSubscription: Subscription; /** * The container element. THis is neede to get the size of the element, * in which the projector must fit and be scaled to. */ @ViewChild('container') private containerElement: ElementRef; /** * Dynamic style attributes for the projector. */ public projectorStyle: { transform?: string; width: string; height: string; 'background-color': string; } = { width: '0px', height: '0px', 'background-color': 'white' }; /** * Dynamic style attributes for the header and footer. */ public headerFooterStyle: { 'background-image': string; 'background-color': string; color: string } = { 'background-image': 'none', 'background-color': 'blue', color: 'white' }; /** * Dynamic style attributes for the container. */ public containerStyle: { height?: string } = {}; /** * All slides to show on this projector */ public slides: SlideData[] = []; /** * The scroll for this projector. 0 is the default. */ public scroll = 0; /** * The scale for this projector. 0 is the default. */ public scale = 0; /** * The subscription to the projector. */ private projectorSubscription: Subscription; /** * A subject that fires, if the container is resized. */ public resizeSubject = new Subject(); // Some settings for the view from the config. public enableHeaderAndFooter = true; public enableTitle = true; public enableLogo = true; public projectorLogo; public eventName; public eventDescription; public eventDate; public eventLocation; /** * Listen to all related config variables. Register the resizeSubject. * * @param titleService * @param translate * @param projectorDataService * @param projectorRepository * @param configService */ public constructor( titleService: Title, translate: TranslateService, private projectorDataService: ProjectorDataService, private projectorRepository: ProjectorRepositoryService, private configService: ConfigService, private offlineService: OfflineService ) { super(titleService, translate); // projector logo / background-image this.configService.get('projector_enable_logo').subscribe(val => (this.enableLogo = val)); this.configService.get<{ path?: string }>('logo_projector_main').subscribe(val => { if (val && val.path) { this.projectorLogo = val.path; } }); this.configService.get<{ path?: string }>('logo_projector_header').subscribe(val => { if (val && val.path) { this.headerFooterStyle['background-image'] = "url('" + val.path + "')"; } else { this.headerFooterStyle['background-image'] = 'none'; } }); // event data this.configService.get('general_event_name').subscribe(val => (this.eventName = val)); this.configService.get('general_event_description').subscribe(val => (this.eventDescription = val)); this.configService.get('general_event_date').subscribe(val => (this.eventDate = val)); this.configService.get('general_event_location').subscribe(val => (this.eventLocation = val)); // Watches for resizing of the container. this.resizeSubject.subscribe(() => { if (this.containerElement) { this.updateScaling(); } }); } /** * determine if the server is offline * * @returns whether the client is offlien */ public isOffline(): boolean { return this.offlineService.isOffline(); } /** * Scales the projector to the right format. */ private updateScaling(): void { if ( !this.containerElement || this.currentProjectorSize.width === 0 || this.containerElement.nativeElement.offsetWidth === 0 ) { return; } const scale = this.containerElement.nativeElement.offsetWidth / this.currentProjectorSize.width; if (isNaN(scale)) { return; } this.projectorStyle.transform = 'scale(' + scale + ')'; this.projectorStyle.width = this.currentProjectorSize.width + 'px'; this.projectorStyle.height = this.currentProjectorSize.height + 'px'; this.containerStyle.height = Math.round(scale * this.currentProjectorSize.height) + 'px'; } /** * Called, if the projector id changes. */ private projectorIdChanged(from: number, to: number): void { // Unsubscribe form data and projector subscriptions. if (this.dataSubscription) { this.dataSubscription.unsubscribe(); } if (this.projectorSubscription) { this.projectorSubscription.unsubscribe(); } if (to > 0) { if (from > 0) { this.projectorDataService.projectorClosed(from); } this.dataSubscription = this.projectorDataService.getProjectorObservable(to).subscribe(data => { this.slides = data || []; }); this.projectorSubscription = this.projectorRepository.getViewModelObservable(to).subscribe(projector => { if (projector) { this.scroll = projector.scroll || 0; this.scale = projector.scale || 0; } }); } else if (!to && from > 0) { // no new projector this.projectorDataService.projectorClosed(from); } } /** * Deregister the projector from the projectordataservice. */ public ngOnDestroy(): void { if (this.projectorId > 0) { this.projectorDataService.projectorClosed(this.projectorId); } } }