日历应用中时间块重叠宽度计算算法优化问询
解决方案:基于并发列数计算宽度与偏移
核心问题在于你当前的宽度计算逻辑依赖单个时间块的重叠对象总数,但实际应该基于该时间块所在重叠组的最大并发数(即同一时间点最多同时存在的时间块数量)。以下是具体优化思路和实现方式:
1. 问题根源分析
你的重叠数据中:
- 时间块0与1、2都重叠,但1和2彼此不重叠
- 同一时间点最多仅存在2个重叠块(0+1 或 0+2),而非3个
因此,整个重叠组的最大并发数是2,所有块的宽度都应该是100% / 2 = 50%,而非基于单个块的重叠列表长度计算。
2. 优化算法思路
通过为重叠块分配"列"来实现布局:
- 同一列内的时间块彼此不重叠
- 列的总数就是最大并发数,宽度由列数决定
- 每个块的偏移量由其所在列的索引决定
具体步骤:
- 将所有时间块按开始时间排序
- 遍历块,为每个块分配到第一个无重叠的列中
- 列的总数即为最大并发数,以此计算宽度
- 根据块所在列的索引计算偏移量
3. 代码示例(伪代码)
// 假设时间块数据结构:包含id、start(开始时间)、end(结束时间) const blocks = [ { id: 0, start: 0, end: 4 }, { id: 1, start: 1, end: 2 }, { id: 2, start: 3, end: 4 } ]; // 第一步:按开始时间排序 const sortedBlocks = [...blocks].sort((a, b) => a.start - b.start); // 第二步:为每个块分配列 const columns = []; const blockColumnMap = {}; // 记录每个块所在的列索引 sortedBlocks.forEach(block => { // 查找第一个与当前块不重叠的列 const targetColumnIndex = columns.findIndex(col => { const lastBlockInCol = col[col.length - 1]; return lastBlockInCol.end <= block.start; }); if (targetColumnIndex === -1) { // 无可用列,新建列 columns.push([block]); blockColumnMap[block.id] = columns.length - 1; } else { // 将块放入目标列 columns[targetColumnIndex].push(block); blockColumnMap[block.id] = targetColumnIndex; } }); // 第三步:计算宽度与偏移量 const maxColumnCount = columns.length; const blockWidthPercent = 100 / maxColumnCount; const styledBlocks = blocks.map(block => ({ ...block, width: `${blockWidthPercent}%`, left: `${blockColumnMap[block.id] * blockWidthPercent}%` }));
4. 最终效果
运行上述代码后,得到的布局完全符合你的期望:
- 时间块0:
width 50%,left 0% - 时间块1:
width 50%,left 50% - 时间块2:
width 50%,left 50%
这种方式彻底避免了间隙问题,同时能适配更复杂的重叠场景(比如三层重叠时自动分配为33.33%宽度)。
内容的提问来源于stack exchange,提问作者Mads
相关产品推荐
相关产品推荐

