构建场景布局
场景支持两种布局类型:弹性布局和网格布局。在本指南中,你将学习如何使用和配置 SceneFlexLayout
和 SceneGridLayout
。
弹性盒布局
SceneFlexLayout
允许你构建灵活的场景,其布局由浏览器的 CSS 弹性盒布局驱动。这使得你可以定义非常动态的布局,其中面板的宽度和高度可以根据可用空间进行调整。
步骤 1. 创建场景
通过创建一个场景来开始使用弹性盒布局,将其 body
配置为 SceneFlexLayout
const scene = new EmbeddedScene({
body: new SceneFlexLayout({}),
});
步骤 2. 配置弹性盒布局
SceneFlexLayout
允许配置弹性盒行为。你可以配置以下属性
direction
- 配置弹性盒布局的主轴。布局中的子元素将遵循其方向。wrap
- 配置布局子元素的行为。默认情况下,子元素会尝试在一行内排列。
默认情况下,SceneFlexLayout
使用 row
方向。要创建列布局,使用以下代码
const scene = new EmbeddedScene({
body: new SceneFlexLayout({
direction: 'column',
}),
});
步骤 3. 添加布局子元素
SceneFlexLayout
有一个 children
属性。它接受 SceneFlexItem
或 SceneFlexLayout
对象的数组。创建一个场景,其中包含两个大小相等的布局项,排列成列
const scene = new EmbeddedScene({
body: new SceneFlexLayout({
direction: 'column',
children: [new SceneFlexItem({ minHeight: 200 }), new SceneFlexItem({ minHeight: 300 })],
}),
});
SceneFlexLayout
和 SceneFlexItem
对象类型都接受以下配置选项,这些选项允许设置大小约束和行为
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
对象上设置了 minHeight
或 height
,则无需在每个子元素上单独设置,因为它们会继承这些约束。
步骤 4. 将面板添加到弹性布局项
前面的示例为你的场景设置了一个布局。要可视化数据,请配置 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
,建议设置 minHeight
或 minWidth
约束,以便面板不会因屏幕空间有限而过度压缩。
响应式弹性布局
默认情况下,SceneFlexLayout
对较小的屏幕有一些响应式行为
SceneFlexLayout
方向从row
变为column
。SceneFlexLayout
的maxWidth
、maxHeight
、height
或width
约束被移除。SceneFlexLayout
和SceneFlexItem
使用父布局上设置的minHeight
或height
(除非直接在其上指定)。这是为了强制将设置在方向为row
的SceneFlexLayout
上的height
或minHeight
约束也应用于其子元素,以便在触发将方向更改为column
的响应式媒体查询时,这些约束继续作用于子元素。
对于匹配 Grafana 的 theme.breakpoints.down('md') 媒体查询的屏幕,会触发这些行为。
你可以使用 md
属性覆盖这些行为,并设置自定义方向和大小约束,该属性存在于 SceneFlexLayout
和 SceneFlexItem
上。例如
new SceneFlexLayout({
direction: 'row',
minHeight: 200,
md: {
minHeight: 100,
direction: 'row',
},
children: [getStatPanel({}), getStatPanel({})],
}),
在前面的示例中,我们使用 md
属性覆盖了将行布局更改为列布局的默认响应式行为。我们还应用了更严格的 minHeight
约束。
CSS 网格布局
作为 SceneFlexLayout
的替代方案,可以使用 SceneCSSGridLayout
将场景项包裹在 CSS 网格中。
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 网格样式
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 网格可以轻松构建动态面板网格,其中面板大小约束可以在网格本身上指定,而不是在每个面板上指定。这对于构建大小相等的面板网格非常有用。
下面的网格布局配置为子元素的最小大小为 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 包装器是可选的。
网格布局
SceneGridLayout
允许你将场景构建为可拖动和移动的元素网格。这是 Grafana 核心 Dashboard 体验使用的默认布局。除非你需要用户能够移动面板,否则不建议将其用于场景应用插件。
步骤 1. 创建场景
通过创建一个场景来开始使用网格布局,将其 body
配置为 SceneGridLayout
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({}),
});
步骤 2. 配置网格布局
SceneGridLayout
允许配置网格行为。提供的网格有 24 列。
你可以配置以下属性
isDraggable
- 配置网格项是否可以移动。isLazy
- 配置网格项在视口外部时是否应该被初始化。
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SceneGridLayout({
isDraggable: false,
isLazy: true,
}),
});
步骤 3. 添加布局子元素
SceneGridLayout
有一个 children
属性。它接受 SceneGridItem
或 SceneGridRow
对象的数组。创建一个场景,其中包含两行网格项
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. 将面板添加到网格布局项
将 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
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SplitLayout({}),
});
步骤 2. 配置拆分布局
SplitLayout
允许多种配置选项
direction
- 配置窗格是按行还是按列排列。primary
- 第一个窗格。secondary
- 第二个窗格
const scene = new EmbeddedScene({
$data: queryRunner,
body: new SplitLayout({
direction: 'column',
}),
});
步骤 3. 提供 primary
和 secondary
对象
primary
和 secondary
都接受一个 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(),
}),
});