@bokeh/bokehjs
Version:
Interactive, novel data visualization
135 lines • 5.08 kB
JavaScript
import { LayoutDOM, LayoutDOMView } from "./layout_dom";
import { GridAlignmentLayout } from "./alignments";
import { GridSpacing } from "../common/kinds";
import { px } from "../../core/dom";
import { Container } from "../../core/layout/grid";
import { enumerate } from "../../core/util/iterator";
import { isNumber, isString, isArray } from "../../core/util/types";
const { max } = Math;
export class CSSGridBoxView extends LayoutDOMView {
static __name__ = "CSSGridBoxView";
connect_signals() {
super.connect_signals();
const { spacing } = this.model.properties;
this.on_change(spacing, () => this.invalidate_layout());
}
get child_models() {
return this._children.map(([child]) => child);
}
_intrinsic_display() {
return { inner: this.model.flow_mode, outer: "grid" };
}
_update_layout() {
super._update_layout();
const styles = {};
const [row_gap, column_gap] = (() => {
const { spacing } = this.model;
return isNumber(spacing) ? [spacing, spacing] : spacing;
})();
styles.row_gap = px(row_gap);
styles.column_gap = px(column_gap);
let nrows = 0;
let ncols = 0;
const layoutable = new Container();
for (const [[, row, col, row_span = 1, col_span = 1], i] of enumerate(this._children)) {
const view = this.child_views[i];
nrows = max(nrows, row + row_span);
ncols = max(ncols, col + col_span);
// CSS grid is 1-based, but layout is 0-based
const styles = {};
styles.grid_row_start = `${row + 1}`;
styles.grid_row_end = `span ${row_span}`;
styles.grid_column_start = `${col + 1}`;
styles.grid_column_end = `span ${col_span}`;
view.parent_style.append(":host", styles);
if (view instanceof LayoutDOMView && view.layout != null) {
const r0 = row;
const c0 = col;
const r1 = row + row_span - 1;
const c1 = col + col_span - 1;
layoutable.add({ r0, c0, r1, c1 }, view);
}
}
const { _rows: rows, _cols: cols } = this;
if (rows instanceof Map) {
nrows = max(nrows, ...rows.keys());
}
else if (isArray(rows)) {
nrows = max(nrows, rows.length);
}
if (cols instanceof Map) {
ncols = max(ncols, ...cols.keys());
}
else if (isArray(cols)) {
ncols = max(ncols, cols.length);
}
function parse_sizing(tracks, template) {
if (tracks instanceof Map) {
for (const [i, spec] of tracks.entries()) {
if (isString(spec)) {
template[i].size = spec;
}
else {
template[i] = spec;
}
}
}
else if (isArray(tracks)) {
for (const [spec, i] of enumerate(tracks)) {
if (isString(spec)) {
template[i].size = spec;
}
else {
template[i] = spec;
}
}
}
else if (tracks != null) {
for (const row of template) {
if (isString(tracks)) {
row.size = tracks;
}
else {
row.size = tracks.size;
row.align = tracks.align;
}
}
}
}
const rows_template = Array(nrows).fill(null).map(() => ({}));
const cols_template = Array(ncols).fill(null).map(() => ({}));
parse_sizing(rows, rows_template);
parse_sizing(cols, cols_template);
for (const [[, row, col], i] of enumerate(this._children)) {
const view = this.child_views[i];
const { halign, valign } = view.box_sizing();
view.parent_style.append(":host", {
justify_self: halign ?? cols_template[col].align,
align_self: valign ?? rows_template[row].align,
});
}
const default_size = "auto";
styles.grid_template_rows = rows_template.map(({ size }) => size ?? default_size).join(" ");
styles.grid_template_columns = cols_template.map(({ size }) => size ?? default_size).join(" ");
this.style.append(":host", styles);
if (layoutable.size != 0) {
this.layout = new GridAlignmentLayout(layoutable);
this.layout.set_sizing();
}
else {
delete this.layout;
}
}
}
export class CSSGridBox extends LayoutDOM {
static __name__ = "CSSGridBox";
constructor(attrs) {
super(attrs);
}
static {
this.define(() => ({
spacing: [GridSpacing, 0],
}));
}
}
//# sourceMappingURL=css_grid_box.js.map