import { get, writable } from "svelte/store"; import type { Box } from "../WebRtc/LayoutManager"; import { HtmlUtils } from "../WebRtc/HtmlUtils"; import { LayoutMode } from "../WebRtc/LayoutManager"; import { layoutModeStore } from "./StreamableCollectionStore"; /** * Tries to find the biggest available box of remaining space (this is a space where we can center the character) */ function findBiggestAvailableArea(): Box { const game = HtmlUtils.querySelectorOrFail("#game canvas"); if (get(layoutModeStore) === LayoutMode.VideoChat) { const children = document.querySelectorAll("div.chat-mode > div"); const htmlChildren = Array.from(children.values()); // No chat? Let's go full center if (htmlChildren.length === 0) { return { xStart: 0, yStart: 0, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } const lastDiv = htmlChildren[htmlChildren.length - 1]; // Compute area between top right of the last div and bottom right of window const area1 = (game.offsetWidth - (lastDiv.offsetLeft + lastDiv.offsetWidth)) * (game.offsetHeight - lastDiv.offsetTop); // Compute area between bottom of last div and bottom of the screen on whole width const area2 = game.offsetWidth * (game.offsetHeight - (lastDiv.offsetTop + lastDiv.offsetHeight)); if (area1 < 0 && area2 < 0) { // If screen is full, let's not attempt something foolish and simply center character in the middle. return { xStart: 0, yStart: 0, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } if (area1 <= area2) { return { xStart: 0, yStart: lastDiv.offsetTop + lastDiv.offsetHeight, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } else { return { xStart: lastDiv.offsetLeft + lastDiv.offsetWidth, yStart: lastDiv.offsetTop, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } } else { // Possible destinations: at the center bottom or at the right bottom. const mainSectionChildren = Array.from( document.querySelectorAll("div.main-section > div").values() ); const sidebarChildren = Array.from(document.querySelectorAll("aside.sidebar > div").values()); // No presentation? Let's center on the screen if (mainSectionChildren.length === 0) { return { xStart: 0, yStart: 0, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } // At this point, we know we have at least one element in the main section. const lastPresentationDiv = mainSectionChildren[mainSectionChildren.length - 1]; const presentationArea = (game.offsetHeight - (lastPresentationDiv.offsetTop + lastPresentationDiv.offsetHeight)) * (lastPresentationDiv.offsetLeft + lastPresentationDiv.offsetWidth); let leftSideBar: number; let bottomSideBar: number; if (sidebarChildren.length === 0) { leftSideBar = HtmlUtils.getElementByIdOrFail("sidebar").offsetLeft; bottomSideBar = 0; } else { const lastSideBarChildren = sidebarChildren[sidebarChildren.length - 1]; leftSideBar = lastSideBarChildren.offsetLeft; bottomSideBar = lastSideBarChildren.offsetTop + lastSideBarChildren.offsetHeight; } const sideBarArea = (game.offsetWidth - leftSideBar) * (game.offsetHeight - bottomSideBar); if (presentationArea <= sideBarArea) { return { xStart: leftSideBar, yStart: bottomSideBar, xEnd: game.offsetWidth, yEnd: game.offsetHeight, }; } else { return { xStart: 0, yStart: lastPresentationDiv.offsetTop + lastPresentationDiv.offsetHeight, xEnd: /*lastPresentationDiv.offsetLeft + lastPresentationDiv.offsetWidth*/ game.offsetWidth, // To avoid flickering when a chat start, we center on the center of the screen, not the center of the main content area yEnd: game.offsetHeight, }; } } } /** * A store that contains the list of (video) peers we are connected to. */ function createBiggestAvailableAreaStore() { const { subscribe, set } = writable({ xStart: 0, yStart: 0, xEnd: 1, yEnd: 1 }); return { subscribe, recompute: () => { set(findBiggestAvailableArea()); }, }; } export const biggestAvailableAreaStore = createBiggestAvailableAreaStore();