跳到主要内容

构建场景布局

Scenes 支持两种布局类型:flex 布局和 grid 布局。在本指南中,您将学习如何使用和配置 SceneFlexLayoutSceneGridLayout

Flexbox 布局

SceneFlexLayout 允许您使用浏览器 CSS flexbox 布局构建灵活的场景。这使您可以定义非常动态的布局,其中面板的宽度和高度可以适应可用空间。

步骤 1. 创建场景

通过创建一个 body 配置为 SceneFlexLayout 的场景,开始使用 flexbox 布局

const scene = new EmbeddedScene({
body: new SceneFlexLayout({}),
});

步骤 2. 配置 flexbox 布局

SceneFlexLayout 允许 flexbox 行为配置。您可以配置以下属性

  • direction - 配置 flexbox 布局的主轴。布局中放置的子元素将遵循其方向。
  • wrap - 配置布局子元素的行为。默认情况下,子元素尝试适应一行。

默认情况下,SceneFlexLayout 使用 row 方向。要创建列布局,请使用以下代码

const scene = new EmbeddedScene({
body: new SceneFlexLayout({
direction: 'column',
}),
});

步骤 3. 添加布局子元素

SceneFlexLayout 具有 children 属性。它接受 SceneFlexItemSceneFlexLayout 对象的数组。创建一个场景,其中包含两个大小相等的列式布局项

const scene = new EmbeddedScene({
body: new SceneFlexLayout({
direction: 'column',
children: [new SceneFlexItem({ minHeight: 200 }), new SceneFlexItem({ minHeight: 300 })],
}),
});

SceneFlexLayoutSceneFlexItem 对象类型都接受以下配置选项,这些选项允许大小约束和行为

  flexGrow?: CSSProperties['flexGrow'];
alignSelf?: CSSProperties['alignSelf'];
width?: CSSProperties['width'];
height?: CSSProperties['height'];
minWidth?: CSSProperties['minWidth'];
minHeight?: CSSProperties['minHeight'];
maxWidth?: CSSProperties['maxWidth'];
maxHeight?: CSSProperties['maxHeight'];
xSizing?: 'fill' | 'content';
ySizing?: 'fill' | 'content';
// For sizing constaints on smaller screens
md?: SceneFlexItemPlacement;

我们强烈建议在所有使用 column 方向的布局子元素上设置 minHeight。这确保它们在较小的屏幕上不会过度压缩。如果在 SceneFlexLayout 对象上设置了 minHeightheight,则无需在每个子元素上设置,因为它们将继承这些约束。

步骤 4. 将面板添加到 flex 布局项

前面的示例为您的场景设置了一个布局。要可视化数据,请配置 SceneQueryRunner 并将其添加到您的场景中

const queryRunner = new SceneQueryRunner({
$timeRange: new SceneTimeRange()
datasource: {
type: 'prometheus',
uid: '<PROVIDE_GRAFANA_DS_UID>',
},
queries: [
{
refId: 'A',
expr: 'rate(prometheus_http_requests_total{}[5m])',
},
],
});

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneFlexLayout({
direction: 'column',
children: [new SceneFlexItem({}), new SceneFlexItem({})],
}),
});

接下来,将 VizPanel 对象添加为布局项的 body

const queryRunner = new SceneQueryRunner({
datasource: {
type: 'prometheus',
uid: '<PROVIDE_GRAFANA_DS_UID>',
},
queries: [
{
refId: 'A',
expr: 'rate(prometheus_http_requests_total{}[5m])',
},
],
});

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneFlexLayout({
direction: 'column',
children: [
new SceneFlexItem({
body: PanelBuilders.timeseries().setTitle('Time series').build(),
}),
new SceneFlexItem({
body: PanelBuilders.table().setTitle('Table').build(),
}),
],
}),
});

这将渲染两个面板,一个时间序列面板和一个表格面板。

注意

对于包含 VizPanel 对象的 SceneFlexItems,建议您设置 minHeightminWidth 约束,以使面板不会因屏幕空间有限而过度压缩。

响应式 flex 布局

默认情况下,SceneFlexLayout 对较小的屏幕具有一些响应式行为

  • SceneFlexLayout 方向从 row 更改为 column
  • SceneFlexLayout maxWidthmaxHeightheightwidth 约束被移除。
  • SceneFlexLayoutSceneFlexItem 使用父布局上设置的 minHeightheight(除非直接在其上指定)。这是为了强制在方向为 rowSceneFlexLayout 上设置的 heightminHeight 约束也应用于其子元素,以便在触发将方向更改为 column 的响应式媒体查询时,这些约束继续作用于子元素。

这些行为针对与 Grafana 主题的 breakpoints.down('md') 媒体查询匹配的屏幕触发。

您可以使用 SceneFlexLayoutSceneFlexItem 上都存在的 md 属性来覆盖这些行为并设置自定义方向和大小约束。例如

new SceneFlexLayout({
direction: 'row',
minHeight: 200,
md: {
minHeight: 100,
direction: 'row',
},
children: [getStatPanel({}), getStatPanel({})],
}),

在前面的示例中,我们使用 md 属性来覆盖将行布局更改为列布局的默认响应式行为。我们还应用了更严格的 minHeight 约束。

CSS grid 布局

作为 SceneFlexLayout 的替代方案,SceneCSSGridLayout 可用于将场景项包裹在 CSS Grid 中。

const scene = new EmbeddedScene({
body: new SceneCSSGridLayout({
templateColumns: `repeat(auto-fit, minmax(400px, 1fr))`,
children: [
PanelBuilders.timeseries().setTitle('Graph 1').build(),
PanelBuilders.timeseries().setTitle('Graph 2').build(),
],
}),
});

SceneCSSGridLayout 接受与 SceneFlexLayout 相同的 children,并具有以下属性用于应用 CSS grid 样式

autoRows?: CSSProperties['gridAutoRows'];
templateRows?: CSSProperties['gridTemplateRows'];
templateColumns: CSSProperties['gridTemplateColumns'];
/** In Grafana design system grid units (8px) */
rowGap: number;
/** In Grafana design system grid units (8px) */
columnGap: number;
justifyItems?: CSSProperties['justifyItems'];
alignItems?: CSSProperties['alignItems'];
justifyContent?: CSSProperties['justifyContent'];
// For sizing constaints on smaller screens
md?: SceneCSSGridLayoutState;

使用 CSS Grid,可以轻松构建动态的面板网格,其中面板大小约束可以在网格本身上指定,而不是在每个面板上指定。对于构建大小相等的面板网格非常有用。

下面的网格布局配置为使子元素具有 400px 的最小尺寸,如果还有更多可用空间,则将其均分。高度使用 autoRows 设置。此配置将启用大小相等的面板的非常响应式的布局。

const scene = new EmbeddedScene({
body: new SceneCSSGridLayout({
templateColumns: `repeat(auto-fit, minmax(400px, 1fr))`,
autoRows: '150px',
rowGap: 2,
columnGap: 2,
children: [
new SceneCSSGridItem({
body: PanelBuilders.timeseries().setTitle('Time series').build(),
}),
new SceneCSSGridItem({
body: PanelBuilders.table().setTitle('Table').build(),
}),
new SceneCSSGridItem({
body: PanelBuilders.timeseries().setTitle('Time series').build(),
}),
new SceneCSSGridItem({
body: PanelBuilders.table().setTitle('Table').build(),
}),
],
}),
});

每个子元素周围的 SceneCSSGridItem 包装器是可选的。

Grid 布局

SceneGridLayout 允许您将场景构建为可以拖动和移动的元素网格。这是 Grafana 核心仪表板体验使用的默认布局。除非您需要用户能够移动面板,否则不建议将其用于场景应用插件。

步骤 1. 创建场景

通过创建一个 body 配置为 SceneGridLayout 的场景,开始使用 grid 布局

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({}),
});

步骤 2. 配置 grid 布局

SceneGridLayout 允许 grid 行为配置。提供的网格有 24 列。

您可以配置以下属性

  • isDraggable - 配置是否可以移动网格项。
  • isLazy - 配置是否应在网格项位于视口之外时对其进行初始化。
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({
isDraggable: false,
isLazy: true,
}),
});

步骤 3. 添加布局子元素

SceneGridLayout 具有 children 属性。它接受 SceneGridItemSceneGridRow 对象的数组。创建一个场景,其中包含两个行式网格项

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({
children: [
new SceneGridItem({
x: 0,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
}),
new SceneGridItem({
x: 12,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
}),
],
}),
});

SceneGridItem 接受以下配置选项,这些选项以 24 列网格单位表示

  x?: number;
y?: number;
width?: number;
height?: number;

步骤 4. 将面板添加到 grid 布局项

VizPanel 添加到 SceneGridItem 以显示可视化数据

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({
children: [
new SceneGridItem({
x: 0,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
body: PanelBuilders.timeseries().setTitle('Time series').build(),
}),
new SceneGridItem({
x: 12,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
body: PanelBuilders.table().setTitle('Table').build(),
}),
],
}),
});

步骤 5. 添加网格行

网格行是一种布局项,它将其他 SceneGridItems 分组到一个可折叠的行中。使用 SceneGridRow 向场景添加行

注意

SceneGridRow 中,x 和 y 坐标相对于行。

const row = new SceneGridRow({
x: 0,
y: 0,
children: [
new SceneGridItem({
x: 0,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
body: PanelBuilders.timeseries().setTitle('Time series').build(),
}),
new SceneGridItem({
x: 12,
y: 0,
width: 12,
height: 10,
isResizable: false,
isDraggable: false,
body: PanelBuilders.table().setTitle('Table').build(),
}),
],
});

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({
children: [row],
}),
});

拆分布局

SplitLayout 允许您将场景构建为独立的、可调整大小的窗格的组合,这些窗格可以是垂直或水平方向的。

步骤 1. 创建场景

通过创建一个 body 配置为 SplitLayout 的场景,开始使用 split 布局

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SplitLayout({}),
});

步骤 2. 配置 split 布局

SplitLayout 允许几个配置选项

  • direction - 配置窗格是按行还是按列方向排列。
  • primary - 第一个窗格。
  • secondary - 第二个窗格
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SplitLayout({
direction: 'column',
}),
});

步骤 3. 提供 primary 和 secondary 对象

primarysecondary 都接受 SceneFlexItemLike 对象。

const scene = new EmbeddedScene({
$data: queryRunner,
body: new SplitLayout({
direction: 'column',
primary: PanelBuilders.timeseries().setTitle('Primary panel').build(),
secondary: PanelBuilders.table().setTitle('Secondary panel').build(),
}),
});

源代码

查看示例源代码