From 9f6c6e0ce18172b5c57c4a391bc4c275a55978ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Thu, 13 Aug 2020 18:21:48 +0200 Subject: [PATCH] Adding CoWebsiteManager + first working version of flex video --- front/dist/index.html | 52 ++++++- front/dist/resources/style/style.css | 196 ++++++++++++++++++++++----- front/src/WebRtc/CoWebsiteManager.ts | 56 ++++++++ front/src/WebRtc/LayoutManager.ts | 22 ++- front/src/WebRtc/MediaManager.ts | 31 ++++- front/src/index.ts | 20 ++- 6 files changed, 326 insertions(+), 51 deletions(-) create mode 100644 front/src/WebRtc/CoWebsiteManager.ts diff --git a/front/dist/index.html b/front/dist/index.html index a680c59a..92a7bf3c 100644 --- a/front/dist/index.html +++ b/front/dist/index.html @@ -39,7 +39,53 @@ WorkAdventure -
+
+
+
+
+ +
+ + + + +
+
+ +
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+
+
+ -->
diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css index 5f0e1cab..45b61679 100644 --- a/front/dist/resources/style/style.css +++ b/front/dist/resources/style/style.css @@ -27,7 +27,7 @@ video{ -webkit-transform: scaleX(-1); transform: scaleX(-1); } -.webrtc{ +/*.webrtc{ display: none; position: absolute; right: 0px; @@ -36,21 +36,22 @@ video{ } .webrtc.active{ display: block; -} +}*/ -.webrtc, .activeCam{} -.activeCam .video-container{ - position: absolute; - height: 25%; +/*.webrtc, .activeCam{}*/ +/*.activeCam*/ .video-container{ + position: relative; + /*height: 25%; top: 10px; margin: 5px; right: -100px; - transition: all 0.2s ease; - border-color: black; + transition: all 0.2s ease;*/ + /*border-color: black; border-style: solid; - border-width: 0.2px; + border-width: 0.2px;*/ + background-color: #00000099; } -.activeCam .video-container i{ +/*.activeCam*/ .video-container i{ position: absolute; width: 100px; height: 65px; @@ -63,10 +64,10 @@ video{ font-size: 28px; color: white; } -.activeCam .video-container img.active{ +/*.activeCam*/ .video-container img.active{ display: block; } -.activeCam .video-container img{ +/*.activeCam*/ .video-container img{ position: absolute; display: none; width: 15px; @@ -78,34 +79,28 @@ video{ padding: 10px; z-index: 2; } -.activeCam .video-container video{ +/*.activeCam*/ .video-container video{ height: 100%; } -.webrtc:hover .activeCam .video-container{ +/*.webrtc:hover .activeCam .video-container{ right: 10px; -} -.activeCam .video-container#div-myCamVideo{ +}*/ +/*.activeCam*/ .video-container#div-myCamVideo{ border: none; } -.activeCam .video-container video#myCamVideo{ - width: 200px; - height: 113px; +/*.activeCam*/ + +#div-myCamVideo { + position: fixed; + right: 0; + bottom: 0; } -/*CSS size for 2 - 3 elements*/ -.activeCam .video-container:nth-child(1){ - /*this is for camera of user*/ - top: 75%; -} -.activeCam .video-container:nth-child(2){ - top: 0%; -} -.activeCam .video-container:nth-child(3){ - top: 25%; -} -.activeCam .video-container:nth-child(4) { - top: 50%; +video#myCamVideo{ + width: 15vw; + /*width: 200px;*/ + /*height: 113px;*/ } /*btn animation*/ @@ -122,7 +117,7 @@ video{ transition-timing-function: ease-in-out; bottom: 20px; } -.webrtc:hover .btn-cam-action div{ +#activeCam:hover .btn-cam-action div{ transform: translateY(0); } .btn-cam-action div:hover{ @@ -237,3 +232,138 @@ video{ .webrtcsetup.active{ display: block; } + + +/* New layout */ +body { + margin: 0; + height: 100vh; + width: 100vw; +} +.main-container { + height: 100vh; + width: 100vw; + display: flex; + align-items: stretch; +} + +@media (min-aspect-ratio: 1/1) { + .main-container { + flex-direction: row + } + + .game-overlay { + flex-direction: row + } + + .sidebar { + flex-direction: column + } +} +@media (max-aspect-ratio: 1/1) { + .main-container { + flex-direction: column + } + + .game-overlay { + flex-direction: column + } + + .sidebar { + flex-direction: row + } +} + +.game { + flex-basis: 100%; + position: relative; /* Position relative is needed for the game-overlay. */ +} + +/* A potentially shared website could appear in an iframe in the cowebsite space. */ +.cowebsite { + flex-basis: 100%; + transition: flex-basis 0.5s; +} + +/*.cowebsite:hover { + flex-basis: 100%; +}*/ + +.cowebsite iframe { + width: 100%; + height: 100%; +} + + +.game-overlay { + display: none; + position: absolute; + width: 100%; + height: 100%; + /* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */ +} + +.game-overlay.active { + display: flex; +} + +.game-overlay video { + width: 100% +} + +.main-section { + flex: 0 0 75%; + display: flex; + justify-content: start; + /*align-items: flex-start;*/ + flex-wrap: wrap; +} + +.main-section div { + margin: 5%; + flex-basis: 90%; + /*flex-shrink: 2;*/ +} + +.sidebar { + flex: 0 0 25%; + display: flex; +} + +.sidebar > div { + height: 15%; + margin: 5%; +} + +.chat-mode { + display: flex; + width: 100%; + + flex-wrap: wrap; + + padding: 1%; +} + +.chat-mode div { + margin: 1%; +} + +.chat-mode.one-col div { + flex-basis: 98%; +} + +.chat-mode.two-col div { + flex-basis: 48%; +} + +.chat-mode.three-col div { + flex-basis: 31.333333%; +} + +.chat-mode.four-col div { + flex-basis: 23%; +} + +.chat-mode div:last-child { + flex-grow: 5; +} diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts new file mode 100644 index 00000000..0150760c --- /dev/null +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -0,0 +1,56 @@ +import {HtmlUtils} from "./HtmlUtils"; + +export type CoWebsiteStateChangedCallback = () => void; + +export class CoWebsiteManager { + + private static observers = new Array(); + + public static loadCoWebsite(url: string): void { + const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite"); + cowebsiteDiv.innerHTML = ''; + + const iframe = document.createElement('iframe'); + iframe.id = 'cowebsite-iframe'; + iframe.src = url; + cowebsiteDiv.appendChild(iframe); + CoWebsiteManager.fire(); + } + + public static closeCoWebsite(): void { + const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite"); + cowebsiteDiv.innerHTML = ''; + CoWebsiteManager.fire(); + } + + public static getGameSize(): {width: number, height: number} { + const iframe = document.getElementById('cowebsite-iframe'); + if (iframe === null) { + return { + width: window.innerWidth, + height: window.innerHeight + } + } + if (window.innerWidth >= window.innerHeight) { + return { + width: window.innerWidth / 2, + height: window.innerHeight + } + } else { + return { + width: window.innerWidth, + height: window.innerHeight / 2 + } + } + } + + public static onStateChange(observer: CoWebsiteStateChangedCallback) { + CoWebsiteManager.observers.push(observer); + } + + private static fire(): void { + for (const callback of CoWebsiteManager.observers) { + callback(); + } + } +} diff --git a/front/src/WebRtc/LayoutManager.ts b/front/src/WebRtc/LayoutManager.ts index 63a02356..670e05bd 100644 --- a/front/src/WebRtc/LayoutManager.ts +++ b/front/src/WebRtc/LayoutManager.ts @@ -18,7 +18,7 @@ export enum DivImportance { * 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 { +class LayoutManager { private mode: LayoutMode = LayoutMode.Presentation; private importantDivs: Map = new Map(); @@ -26,7 +26,7 @@ export class LayoutManager { public add(importance: DivImportance, userId: string, html: string): void { const div = document.createElement('div'); - div.append(html); + div.innerHTML = html; div.id = "user-"+userId; if (importance === DivImportance.Important) { @@ -65,6 +65,7 @@ export class LayoutManager { * Removes the DIV matching userId. */ public remove(userId: string): void { + console.log('Removing video for userID '+userId+'.'); let div = this.importantDivs.get(userId); if (div !== undefined) { div.remove(); @@ -81,7 +82,8 @@ export class LayoutManager { return; } - throw new Error('Could not find user ID "'+userId+'"'); + console.log('Cannot remove userID '+userId+'. Already removed?'); + //throw new Error('Could not find user ID "'+userId+'"'); } private adjustVideoChatClass(): void { @@ -104,6 +106,16 @@ export class LayoutManager { private switchLayoutMode(layoutMode: LayoutMode) { this.mode = layoutMode; + if (layoutMode === LayoutMode.Presentation) { + HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'block'; + HtmlUtils.getElementByIdOrFail('main-section').style.display = 'block'; + HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'none'; + } else { + HtmlUtils.getElementByIdOrFail('sidebar').style.display = 'none'; + HtmlUtils.getElementByIdOrFail('main-section').style.display = 'none'; + HtmlUtils.getElementByIdOrFail('chat-mode').style.display = 'block'; + } + for (let div of this.importantDivs.values()) { this.positionDiv(div, DivImportance.Important); } @@ -112,3 +124,7 @@ export class LayoutManager { } } } + +const layoutManager = new LayoutManager(); + +export { layoutManager }; diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index e69850a2..fb7c34f1 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -1,3 +1,5 @@ +import {DivImportance, layoutManager} from "./LayoutManager"; + const videoConstraint: boolean|MediaTrackConstraints = { width: { ideal: 1280 }, height: { ideal: 720 }, @@ -73,8 +75,8 @@ export class MediaManager { } activeVisio(){ - const webRtc = this.getElementByIdOrFail('webRtc'); - webRtc.classList.add('active'); + const gameOverlay = this.getElementByIdOrFail('game-overlay'); + gameOverlay.classList.add('active'); } enabledCamera() { @@ -184,10 +186,11 @@ export class MediaManager { */ addActiveVideo(userId : string, userName: string = ""){ this.webrtcInAudio.play(); - const elementRemoteVideo = this.getElementByIdOrFail("activeCam"); + + //const elementRemoteVideo = this.getElementByIdOrFail("activeCam"); userName = userName.toUpperCase(); const color = this.getColorByString(userName); - elementRemoteVideo.insertAdjacentHTML('beforeend', ` + /*elementRemoteVideo.insertAdjacentHTML('beforeend', `
@@ -195,7 +198,20 @@ export class MediaManager {
- `); + `);*/ + + const html = ` +
+
+ + ${userName} + + +
+ `; + + layoutManager.add(DivImportance.Normal, userId, html); + this.remoteVideo.set(userId, this.getElementByIdOrFail(userId)); } @@ -274,11 +290,12 @@ export class MediaManager { * @param userId */ removeActiveVideo(userId : string){ - const element = document.getElementById(`div-${userId}`); + /*const element = document.getElementById(`div-${userId}`); if(!element){ return; } - element.remove(); + element.remove();*/ + layoutManager.remove(userId); this.remoteVideo.delete(userId); } diff --git a/front/src/index.ts b/front/src/index.ts index d64a8f2e..75ad0fe6 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -4,16 +4,21 @@ import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable"; import {cypressAsserter} from "./Cypress/CypressAsserter"; import {LoginScene} from "./Phaser/Login/LoginScene"; import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene"; -import {gameManager} from "./Phaser/Game/GameManager"; import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene"; import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene"; import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene"; import {CustomizeScene} from "./Phaser/Login/CustomizeScene"; +import {HtmlUtils} from "./WebRtc/HtmlUtils"; +import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager"; + +//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com'); + +const {width, height} = CoWebsiteManager.getGameSize(); const config: GameConfig = { title: "WorkAdventure", - width: window.innerWidth / RESOLUTION, - height: window.innerHeight / RESOLUTION, + width: width / RESOLUTION, + height: height / RESOLUTION, parent: "game", scene: [LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, FourOFourScene, CustomizeScene], zoom: RESOLUTION, @@ -30,5 +35,12 @@ cypressAsserter.gameStarted(); const game = new Phaser.Game(config); window.addEventListener('resize', function (event) { - game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION); + const {width, height} = CoWebsiteManager.getGameSize(); + + game.scale.resize(width / RESOLUTION, height / RESOLUTION); +}); +CoWebsiteManager.onStateChange(() => { + const {width, height} = CoWebsiteManager.getGameSize(); + + game.scale.resize(width / RESOLUTION, height / RESOLUTION); });