@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
111 lines (110 loc) • 4.57 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { isStreetViewProviderConfigured } from '../configuration/streetviewconfig.js';
/**
* The available Layouts of the Map Grid, defined by the Cells of each of their rows:
* each number is the number of columns the Cell spans.
* The name of a Layout is <number of columns>x<number of rows> when all its Cells have the same size,
* or <cells of the first row>+<cells of the second row> when a Cell spans the whole width.
*/
const LAYOUTS = {
'1x1': [[1]],
'2x1': [[1, 1]],
'1x2': [[1], [1]],
'2x2': [
[1, 1],
[1, 1]
],
'2+1': [[1, 1], [2]],
'1+2': [[2], [1, 1]]
};
export const LAYOUT_TYPES = Object.keys(LAYOUTS);
/** Minimal size of a Column or of a Row of the Grid, in percent of the Grid. */
export const MIN_CELL_SIZE = 15;
/** Maximal size of a Column or of a Row of the Grid, in percent of the Grid. */
export const MAX_CELL_SIZE = 85;
/**
* The Components that can be displayed in a Cell of the Grid.
* To make a new Component available to the user, it is enough to add it to this list
* (and to add its Element to the Grid in the HTML of the application).
* A StreetView is only available when its provider is configured.
*/
export const AVAILABLE_CELL_COMPONENTS = [
{ id: 'map-2d', tagName: 'girafe-map-2d', label: '2D Map' },
{ id: 'map-3d', tagName: 'girafe-map-3d', label: '3D Map' },
{ id: 'streetview-google', tagName: 'girafe-streetview-google', label: 'Google Street View', provider: 'google' }
];
export function isLayoutType(value) {
return LAYOUT_TYPES.includes(value);
}
export function isCellComponent(value) {
return AVAILABLE_CELL_COMPONENTS.some((component) => component.id === value);
}
function getProvider(component) {
return 'provider' in component ? component.provider : undefined;
}
/** Whether a Component can be offered to the user: a StreetView needs the configuration of its provider. */
export function isCellComponentAvailable(id, streetviewConfig) {
const component = AVAILABLE_CELL_COMPONENTS.find((candidate) => candidate.id === id);
const provider = component ? getProvider(component) : undefined;
return provider === undefined || isStreetViewProviderConfigured(streetviewConfig, provider);
}
function getLayoutRows(type) {
return LAYOUTS[type];
}
function sumOf(values) {
return values.reduce((total, value) => total + value, 0);
}
/** The number of columns and of rows of a Layout. */
export function getGridSize(type) {
const rows = getLayoutRows(type);
const columns = Math.max(...rows.map((spans) => sumOf(spans)));
return { columns: columns, rows: rows.length };
}
/** The Cells of a Layout, in the order they are indexed: row by row, from left to right. */
export function getLayoutCells(type) {
const cells = [];
for (const [row, spans] of getLayoutRows(type).entries()) {
let column = 0;
for (const columnSpan of spans) {
cells.push({ row: row, column: column, columnSpan: columnSpan });
column += columnSpan;
}
}
return cells;
}
/** The sizes, in percent, of the equally distributed columns and rows of a Layout. */
export function getDefaultSizes(type) {
const { columns, rows } = getGridSize(type);
return {
columns: new Array(columns).fill(100 / columns),
rows: new Array(rows).fill(100 / rows)
};
}
/**
* Distributes the Components on the Cells of a Layout.
* The Components that are already placed keep their Cell as long as it still exists,
* and the Cells that are added by the new Layout are left empty: a Component is only
* displayed when the user explicitly chooses it, so that the libraries it needs
* (Cesium, Google Maps, ...) are not loaded unnecessarily.
*/
export function distributeCells(type, currentCells) {
const cellCount = getLayoutCells(type).length;
const cells = currentCells.slice(0, cellCount);
while (cells.length < cellCount) {
cells.push(null);
}
return cells;
}
/**
* The Layout of the Map Grid: which Layout is displayed, which Component is displayed
* in each of its Cells, and the sizes of its columns and rows (in percent),
* which the user can change by dragging the splitters.
*
* The Cells are indexed row by row: in a 2x2 Layout, the Cell 0 is the top-left one,
* the Cell 1 the top-right one, the Cell 2 the bottom-left one and the Cell 3 the bottom-right one.
*/
export default class LayoutState {
type = '1x1';
cells = ['map-2d'];
sizes = { columns: [100], rows: [100] };
}