Implement the new one-on-one layout
This commit is contained in:
@@ -19,22 +19,36 @@ import { ComponentType } from "react";
|
||||
|
||||
import { MediaViewModel } from "../state/MediaViewModel";
|
||||
import { LayoutProps } from "./Grid";
|
||||
import { Alignment } from "../room/InCallView";
|
||||
|
||||
export interface Bounds {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface Alignment {
|
||||
inline: "start" | "end";
|
||||
block: "start" | "end";
|
||||
}
|
||||
|
||||
export const defaultSpotlightAlignment: Alignment = {
|
||||
inline: "end",
|
||||
block: "end",
|
||||
};
|
||||
export const defaultPipAlignment: Alignment = { inline: "end", block: "start" };
|
||||
|
||||
export interface CallLayoutInputs {
|
||||
/**
|
||||
* The minimum bounds of the layout area.
|
||||
*/
|
||||
minBounds: Observable<Bounds>;
|
||||
/**
|
||||
* The alignment of the floating tile, if any.
|
||||
* The alignment of the floating spotlight tile, if present.
|
||||
*/
|
||||
floatingAlignment: BehaviorSubject<Alignment>;
|
||||
spotlightAlignment: BehaviorSubject<Alignment>;
|
||||
/**
|
||||
* The alignment of the small picture-in-picture tile, if present.
|
||||
*/
|
||||
pipAlignment: BehaviorSubject<Alignment>;
|
||||
}
|
||||
|
||||
export interface GridTileModel {
|
||||
@@ -67,3 +81,68 @@ export interface CallLayoutOutputs<Model> {
|
||||
export type CallLayout<Model> = (
|
||||
inputs: CallLayoutInputs,
|
||||
) => CallLayoutOutputs<Model>;
|
||||
|
||||
export interface GridArrangement {
|
||||
tileWidth: number;
|
||||
tileHeight: number;
|
||||
gap: number;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
const tileMinHeight = 130;
|
||||
const tileMaxAspectRatio = 17 / 9;
|
||||
const tileMinAspectRatio = 4 / 3;
|
||||
|
||||
/**
|
||||
* Determine the ideal arrangement of tiles into a grid of a particular size.
|
||||
*/
|
||||
export function arrangeTiles(
|
||||
width: number,
|
||||
minHeight: number,
|
||||
tileCount: number,
|
||||
): GridArrangement {
|
||||
// The goal here is to determine the grid size and padding that maximizes
|
||||
// use of screen space for n tiles without making those tiles too small or
|
||||
// too cropped (having an extreme aspect ratio)
|
||||
const gap = width < 800 ? 16 : 20;
|
||||
const tileMinWidth = width < 500 ? 150 : 180;
|
||||
|
||||
let columns = Math.min(
|
||||
// Don't create more columns than we have items for
|
||||
tileCount,
|
||||
// The ideal number of columns is given by a packing of equally-sized
|
||||
// squares into a grid.
|
||||
// width / column = height / row.
|
||||
// columns * rows = number of squares.
|
||||
// ∴ columns = sqrt(width / height * number of squares).
|
||||
// Except we actually want 16:9-ish tiles rather than squares, so we
|
||||
// divide the width-to-height ratio by the target aspect ratio.
|
||||
Math.ceil(Math.sqrt((width / minHeight / tileMaxAspectRatio) * tileCount)),
|
||||
);
|
||||
let rows = Math.ceil(tileCount / columns);
|
||||
|
||||
let tileWidth = (width - (columns - 1) * gap) / columns;
|
||||
let tileHeight = (minHeight - (rows - 1) * gap) / rows;
|
||||
|
||||
// Impose a minimum width and height on the tiles
|
||||
if (tileWidth < tileMinWidth) {
|
||||
// In this case we want the tile width to determine the number of columns,
|
||||
// not the other way around. If we take the above equation for the tile
|
||||
// width (w = (W - (c - 1) * g) / c) and solve for c, we get
|
||||
// c = (W + g) / (w + g).
|
||||
columns = Math.floor((width + gap) / (tileMinWidth + gap));
|
||||
rows = Math.ceil(tileCount / columns);
|
||||
tileWidth = (width - (columns - 1) * gap) / columns;
|
||||
tileHeight = (minHeight - (rows - 1) * gap) / rows;
|
||||
}
|
||||
if (tileHeight < tileMinHeight) tileHeight = tileMinHeight;
|
||||
// Impose a minimum and maximum aspect ratio on the tiles
|
||||
const tileAspectRatio = tileWidth / tileHeight;
|
||||
if (tileAspectRatio > tileMaxAspectRatio)
|
||||
tileWidth = tileHeight * tileMaxAspectRatio;
|
||||
else if (tileAspectRatio < tileMinAspectRatio)
|
||||
tileHeight = tileWidth / tileMinAspectRatio;
|
||||
// TODO: We might now be hitting the minimum height or width limit again
|
||||
|
||||
return { tileWidth, tileHeight, gap, columns };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user