Vis.js Timeline 按 payment code 垂直堆叠重叠 items
结论
可以用 Timeline 原生的 subgroup 机制实现。把 paymentCodeId 映射到 item 的 subgroup,并同时开启普通堆叠和 subgroup 内堆叠:
const options = {
stack: true,
stackSubgroups: true
};
同一个 group 中的 items 会按 payment code 分到不同的 subgroup。同一 payment code 内,时间重叠的 items 会垂直堆叠;不同 payment codes 不会共用同一行。
paymentCodeId 是业务字段,Timeline 不会自动用它控制布局,需要显式赋值给 Vis.js 能识别的 subgroup 属性。
实现方式
创建 Timeline 前,先转换 items:
const items = [
{
id: 1,
group: "section_1",
subgroup: "payment_1",
start: "2025-08-26 09:00",
end: "2025-08-26 11:00",
paymentCodeId: 1,
content: "Item A"
},
{
id: 2,
group: "section_1",
subgroup: "payment_1",
start: "2025-08-26 10:30",
end: "2025-08-26 12:00",
paymentCodeId: 1,
content: "Item B"
},
{
id: 3,
group: "section_1",
subgroup: "payment_2",
start: "2025-08-26 09:00",
end: "2025-08-26 10:00",
paymentCodeId: 2,
content: "Item C"
},
{
id: 4,
group: "section_1",
subgroup: "payment_2",
start: "2025-08-26 09:30",
end: "2025-08-26 10:30",
paymentCodeId: 2,
content: "Item D"
}
];
const groups = [
{
id: "section_1",
content: "Section 1"
}
];
const options = {
stack: true,
stackSubgroups: true
};
new vis.Timeline(
document.getElementById("timeline"),
items,
groups,
options
);
也可以根据原始数据自动生成 subgroup:
const timelineItems = reservations.map((reservation) => ({
...reservation,
subgroup: `payment_${reservation.paymentCodeId}`
}));
建议为值添加前缀,不要直接使用数字:
subgroup: `payment_${item.paymentCodeId}`
这样可以避免 1、"1" 或其他业务维度的值产生不易察觉的标识冲突。
为什么 stack: false 无法达到目标
stack: false 会关闭重叠 item 的自动垂直堆叠。即使设置了 subgroup,同一 subgroup 中互相重叠的 items 也无法按预期分层。
这两个配置的作用不同:
stack: true:允许重叠的 items 垂直堆叠。stackSubgroups: true:在每个 subgroup 内分别计算堆叠。
因此,这个场景不能使用 stack: false。
控制 payment code 的垂直顺序
如果需要固定 subgroup 的上下顺序,可以在 group 上设置 subgroupOrder。它不是 Timeline 的顶层 option,也不应直接作为普通 item 的布局参数使用。
一种常见做法是让 items 携带排序字段,再在 group 中指定这个字段:
const items = reservations.map((reservation) => ({
...reservation,
subgroup: `payment_${reservation.paymentCodeId}`,
subgroupSortOrder: Number(reservation.paymentCodeId)
}));
const groups = [
{
id: "section_1",
content: "Section 1",
subgroupOrder: "subgroupSortOrder"
}
];
完整配置仍需启用 subgroup stacking:
const options = {
stack: true,
stackSubgroups: true
};
不同 Vis.js/vis-timeline 版本支持的 subgroupOrder 形式可能不同。如果当前版本不接受字段名,可以按照该版本的 API 使用比较函数,例如:
const groups = [
{
id: "section_1",
content: "Section 1",
subgroupOrder(a, b) {
return Number(a.paymentCodeId) - Number(b.paymentCodeId);
}
}
];
比较函数接收的具体对象结构,应以项目实际使用版本为准。
注意事项
group和subgroup是两个层级。这里仍将section_1作为 group,将 payment code 作为 subgroup。- 同一 payment code 的所有 items 必须生成完全相同的
subgroup值。 - 不同 section 可以重复使用相同的 subgroup 标识,因为 subgroup 布局会在各自的 group 内计算。
subgroup只负责划分布局区域。如果需要显示 “Payment Code 1” 之类的标签,还要通过 item 内容、CSS、背景 item 或额外的 group 结构实现。subgroup 本身不一定会自动显示标题。- 如果使用的旧版
vis.js不支持stackSubgroups,需要升级到支持该选项的vis-timeline版本,或者把 payment code 提升为真正的 group。不要只根据报错猜测参数位置,应先核对项目实际安装版本的 API。
备注:内容仅供参考。
