mirror of https://github.com/OpenVidu/openvidu.git
ov-components: enhance layout service with responsive viewport handling and layout options adjustment
parent
bd74184799
commit
1cef3c17a4
|
@ -1,8 +1,9 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, effect } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { LayoutAlignment, LayoutClass, OpenViduLayout, OpenViduLayoutOptions } from '../../models/layout.model';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { LoggerService } from '../logger/logger.service';
|
||||
import { ViewportService } from '../viewport/viewport.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -16,14 +17,19 @@ export class LayoutService {
|
|||
captionsTogglingObs: Observable<boolean>;
|
||||
protected layoutWidth: BehaviorSubject<number> = new BehaviorSubject(0);
|
||||
protected openviduLayout: OpenViduLayout | undefined;
|
||||
protected openviduLayoutOptions: OpenViduLayoutOptions;
|
||||
protected openviduLayoutOptions!: OpenViduLayoutOptions;
|
||||
protected captionsToggling: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
protected log: ILogger;
|
||||
|
||||
constructor(protected loggerSrv: LoggerService) {
|
||||
constructor(
|
||||
protected loggerSrv: LoggerService,
|
||||
protected viewportSrv: ViewportService
|
||||
) {
|
||||
this.layoutWidthObs = this.layoutWidth.asObservable();
|
||||
this.captionsTogglingObs = this.captionsToggling.asObservable();
|
||||
this.log = this.loggerSrv.get('LayoutService');
|
||||
this.openviduLayoutOptions = this.getOptions();
|
||||
this.setupViewportListener();
|
||||
}
|
||||
|
||||
initialize(container: HTMLElement) {
|
||||
|
@ -43,6 +49,7 @@ export class LayoutService {
|
|||
update(timeout: number | undefined = undefined) {
|
||||
const updateAux = () => {
|
||||
if (this.openviduLayout && this.layoutContainer) {
|
||||
this.openviduLayoutOptions = this.getOptions();
|
||||
this.openviduLayout.updateLayout(this.layoutContainer, this.openviduLayoutOptions);
|
||||
this.sendLayoutWidthEvent();
|
||||
}
|
||||
|
@ -54,6 +61,10 @@ export class LayoutService {
|
|||
}
|
||||
}
|
||||
|
||||
updateResponsive() {
|
||||
this.updateLayoutOptions();
|
||||
}
|
||||
|
||||
getLayout() {
|
||||
return this.openviduLayout;
|
||||
}
|
||||
|
@ -62,27 +73,33 @@ export class LayoutService {
|
|||
this.openviduLayout = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layout options adjusted to the current viewport
|
||||
* @returns Layout options adjusted to the current viewport
|
||||
*/
|
||||
protected getOptions(): OpenViduLayoutOptions {
|
||||
const options = {
|
||||
maxRatio: 3 / 2, // The narrowest ratio that will be used (default 2x3)
|
||||
minRatio: 9 / 16, // The widest ratio that will be used (default 16x9)
|
||||
fixedRatio: false /* If this is true then the aspect ratio of the video is maintained
|
||||
and minRatio and maxRatio are ignored (default false) */,
|
||||
bigClass: LayoutClass.BIG_ELEMENT, // The class to add to elements that should be sized bigger
|
||||
const ratios = this.getResponsiveRatios();
|
||||
const percentages = this.getResponsivePercentages();
|
||||
|
||||
return {
|
||||
maxRatio: ratios.maxRatio,
|
||||
minRatio: ratios.minRatio,
|
||||
fixedRatio: false,
|
||||
bigClass: LayoutClass.BIG_ELEMENT,
|
||||
smallClass: LayoutClass.SMALL_ELEMENT,
|
||||
ignoredClass: LayoutClass.IGNORED_ELEMENT,
|
||||
bigPercentage: 0.8, // The maximum percentage of space the big ones should take up
|
||||
minBigPercentage: 0, // If this is set then it will scale down the big space if there is left over whitespace down to this minimum size
|
||||
bigFixedRatio: false, // fixedRatio for the big ones
|
||||
bigMaxRatio: 9 / 16, // The narrowest ratio to use for the big elements (default 2x3)
|
||||
bigMinRatio: 9 / 16, // The widest ratio to use for the big elements (default 16x9)
|
||||
bigFirst: true, // Whether to place the big one in the top left (true) or bottom right
|
||||
animate: true, // Whether you want to animate the transitions. Deprecated property, to disable it remove the transaction property on OV_publisher css class
|
||||
bigPercentage: percentages.bigPercentage,
|
||||
minBigPercentage: percentages.minBigPercentage,
|
||||
bigFixedRatio: false,
|
||||
bigMaxRatio: ratios.bigMaxRatio,
|
||||
bigMinRatio: ratios.bigMinRatio,
|
||||
bigFirst: true,
|
||||
animate: true,
|
||||
alignItems: LayoutAlignment.CENTER,
|
||||
bigAlignItems: LayoutAlignment.CENTER,
|
||||
smallAlignItems: LayoutAlignment.CENTER,
|
||||
maxWidth: Infinity, // The maximum width of the elements
|
||||
maxHeight: Infinity, // The maximum height of the elements
|
||||
maxWidth: Infinity,
|
||||
maxHeight: Infinity,
|
||||
smallMaxWidth: Infinity,
|
||||
smallMaxHeight: Infinity,
|
||||
bigMaxWidth: Infinity,
|
||||
|
@ -90,7 +107,134 @@ export class LayoutService {
|
|||
scaleLastRow: true,
|
||||
bigScaleLastRow: true
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
protected getResponsiveRatios() {
|
||||
const isMobile = this.viewportSrv.isMobile();
|
||||
const isTablet = this.viewportSrv.isTablet();
|
||||
const isPortrait = this.viewportSrv.isPortrait();
|
||||
|
||||
if (isMobile && isPortrait) {
|
||||
return {
|
||||
maxRatio: 5 / 4,
|
||||
minRatio: 4 / 5,
|
||||
bigMaxRatio: 5 / 4,
|
||||
bigMinRatio: 3 / 4
|
||||
};
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
return {
|
||||
maxRatio: 16 / 9,
|
||||
minRatio: 3 / 4,
|
||||
bigMaxRatio: 16 / 9,
|
||||
bigMinRatio: 4 / 3
|
||||
};
|
||||
}
|
||||
|
||||
if (isTablet && isPortrait) {
|
||||
return {
|
||||
maxRatio: 4 / 3,
|
||||
minRatio: 3 / 5,
|
||||
bigMaxRatio: 4 / 3,
|
||||
bigMinRatio: 9 / 16
|
||||
};
|
||||
}
|
||||
|
||||
if (isTablet) {
|
||||
return {
|
||||
maxRatio: 16 / 9,
|
||||
minRatio: 2 / 3,
|
||||
bigMaxRatio: 16 / 9,
|
||||
bigMinRatio: 9 / 16
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
maxRatio: 16 / 9,
|
||||
minRatio: 9 / 16,
|
||||
bigMaxRatio: 16 / 9,
|
||||
bigMinRatio: 9 / 16
|
||||
};
|
||||
}
|
||||
|
||||
protected getResponsivePercentages() {
|
||||
const isMobile = this.viewportSrv.isMobile();
|
||||
const isTablet = this.viewportSrv.isTablet();
|
||||
const isPortrait = this.viewportSrv.isPortrait();
|
||||
|
||||
if (isMobile && isPortrait) {
|
||||
return {
|
||||
bigPercentage: 0.85,
|
||||
minBigPercentage: 0.7
|
||||
};
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
return {
|
||||
bigPercentage: 0.82,
|
||||
minBigPercentage: 0.65
|
||||
};
|
||||
}
|
||||
|
||||
if (isTablet && isPortrait) {
|
||||
return {
|
||||
bigPercentage: 0.83,
|
||||
minBigPercentage: 0.6
|
||||
};
|
||||
}
|
||||
|
||||
if (isTablet) {
|
||||
return {
|
||||
bigPercentage: 0.81,
|
||||
minBigPercentage: 0.55
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
bigPercentage: 0.8,
|
||||
minBigPercentage: 0.5
|
||||
};
|
||||
}
|
||||
|
||||
protected setupViewportListener(): void {
|
||||
effect(() => {
|
||||
const viewportInfo = this.viewportSrv.viewportInfo();
|
||||
const isMobile = this.viewportSrv.isMobile();
|
||||
const orientation = this.viewportSrv.orientation();
|
||||
this.updateLayoutOptions();
|
||||
});
|
||||
}
|
||||
|
||||
protected updateLayoutOptions(): void {
|
||||
const newOptions = this.getOptions();
|
||||
|
||||
if (this.hasSignificantChanges(this.openviduLayoutOptions, newOptions)) {
|
||||
this.openviduLayoutOptions = newOptions;
|
||||
|
||||
if (this.openviduLayout && this.layoutContainer) {
|
||||
this.openviduLayout.updateLayout(this.layoutContainer, this.openviduLayoutOptions);
|
||||
this.sendLayoutWidthEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected hasSignificantChanges(oldOptions: OpenViduLayoutOptions, newOptions: OpenViduLayoutOptions): boolean {
|
||||
if (!oldOptions) return true;
|
||||
|
||||
const significantProps: (keyof OpenViduLayoutOptions)[] = [
|
||||
'maxRatio',
|
||||
'minRatio',
|
||||
'bigMaxRatio',
|
||||
'bigMinRatio',
|
||||
'bigPercentage',
|
||||
'alignItems',
|
||||
'bigAlignItems'
|
||||
];
|
||||
|
||||
return significantProps.some(
|
||||
(prop) => Math.abs((oldOptions[prop] as number) - (newOptions[prop] as number)) > 0.01 || oldOptions[prop] !== newOptions[prop]
|
||||
);
|
||||
}
|
||||
|
||||
protected sendLayoutWidthEvent() {
|
||||
|
|
Loading…
Reference in New Issue