Adding LayoutManager to position videos as cleverly as possible
This commit is contained in:
parent
4b940a571c
commit
7232bbaef9
10
front/src/WebRtc/HtmlUtils.ts
Normal file
10
front/src/WebRtc/HtmlUtils.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export class HtmlUtils {
|
||||
public static getElementByIdOrFail<T extends HTMLElement>(id: string): T {
|
||||
const elem = document.getElementById(id);
|
||||
if (elem === null) {
|
||||
throw new Error("Cannot find HTML element with id '"+id+"'");
|
||||
}
|
||||
// FIXME: does not check the type of the returned type
|
||||
return elem as T;
|
||||
}
|
||||
}
|
94
front/src/WebRtc/LayoutManager.ts
Normal file
94
front/src/WebRtc/LayoutManager.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import {HtmlUtils} from "./HtmlUtils";
|
||||
|
||||
export enum LayoutMode {
|
||||
// All videos are displayed on the right side of the screen. If there is a screen sharing, it is displayed in the middle.
|
||||
Presentation = "Presentation",
|
||||
// Videos take the whole page.
|
||||
VideoChat = "VideoChat",
|
||||
}
|
||||
|
||||
export enum DivImportance {
|
||||
// For screen sharing
|
||||
Important = "Important",
|
||||
// For normal video
|
||||
Normal = "Normal",
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is in charge of the video-conference layout.
|
||||
* It receives positioning requests for videos and does its best to place them on the screen depending on the active layout mode.
|
||||
*/
|
||||
export class LayoutManager {
|
||||
private mode: LayoutMode = LayoutMode.Presentation;
|
||||
|
||||
private importantDivs: Map<string, HTMLDivElement> = new Map<string, HTMLDivElement>();
|
||||
private normalDivs: Map<string, HTMLDivElement> = new Map<string, HTMLDivElement>();
|
||||
|
||||
public add(importance: DivImportance, userId: string, html: string): void {
|
||||
const div = document.createElement('div');
|
||||
div.append(html);
|
||||
div.id = "user-"+userId;
|
||||
|
||||
if (importance === DivImportance.Important) {
|
||||
this.importantDivs.set(userId, div);
|
||||
|
||||
// If this is the first video with high importance, let's switch mode automatically.
|
||||
if (this.importantDivs.size === 1 && this.mode === LayoutMode.VideoChat) {
|
||||
this.switchLayoutMode(LayoutMode.Presentation);
|
||||
}
|
||||
} else if (importance === DivImportance.Normal) {
|
||||
this.normalDivs.set(userId, div);
|
||||
} else {
|
||||
throw new Error('Unexpected importance');
|
||||
}
|
||||
|
||||
this.positionDiv(div, importance);
|
||||
}
|
||||
|
||||
private positionDiv(elem: HTMLDivElement, importance: DivImportance): void {
|
||||
if (this.mode === LayoutMode.VideoChat) {
|
||||
const chatModeDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('chat-mode');
|
||||
chatModeDiv.appendChild(elem);
|
||||
} else {
|
||||
if (importance === DivImportance.Important) {
|
||||
const mainSectionDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-section');
|
||||
mainSectionDiv.appendChild(elem);
|
||||
} else if (importance === DivImportance.Normal) {
|
||||
const sideBarDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('sidebar');
|
||||
sideBarDiv.appendChild(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the DIV matching userId.
|
||||
*/
|
||||
public remove(userId: string): void {
|
||||
let div = this.importantDivs.get(userId);
|
||||
if (div !== undefined) {
|
||||
div.remove();
|
||||
this.importantDivs.delete(userId);
|
||||
return;
|
||||
}
|
||||
|
||||
div = this.normalDivs.get(userId);
|
||||
if (div !== undefined) {
|
||||
div.remove();
|
||||
this.normalDivs.delete(userId);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Could not find user ID "'+userId+'"');
|
||||
}
|
||||
|
||||
private switchLayoutMode(layoutMode: LayoutMode) {
|
||||
this.mode = layoutMode;
|
||||
|
||||
for (let div of this.importantDivs.values()) {
|
||||
this.positionDiv(div, DivImportance.Important);
|
||||
}
|
||||
for (let div of this.normalDivs.values()) {
|
||||
this.positionDiv(div, DivImportance.Normal);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
|
||||
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
||||
|
||||
const config: GameConfig = {
|
||||
title: "Office game",
|
||||
title: "WorkAdventure",
|
||||
width: window.innerWidth / RESOLUTION,
|
||||
height: window.innerHeight / RESOLUTION,
|
||||
parent: "game",
|
||||
|
Loading…
Reference in New Issue
Block a user