Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/component/1d/ranges/Ranges.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ function useStackRangesAssignmentsLabels(ranges: RangeType[]) {
processedRanges.push({
...range,
labelWidth,
startPosition,
startPosition: startPosition - labelWidth / 2,
signalId: id,
assignment,
});
}
}
processedRanges.sort((a, b) => a.startPosition - b.startPosition);

processedRanges.sort((a, b) => b.startPosition - a.startPosition);
return stackOverlappingLabelsMap(processedRanges, {
startPositionKey: 'startPosition',
labelWidthKey: 'labelWidth',
Expand Down
30 changes: 24 additions & 6 deletions src/component/utility/stackOverlappingLabels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,46 @@ export function stackOverlappingLabelsArray<T extends Record<string, any>>(
});
});
}

/**
* Assigns a stack index (vertical lane) to each item so that horizontally
* overlapping labels are pushed to different lanes, while non-overlapping
* labels reuse the lowest available lane.
* */
export function stackOverlappingLabelsMap<T extends Record<string, any>>(
items: T[],
options: StackOverlappingLabelsOptions<T> & { idKey: keyof T },
): StackOverlappingLabelsMapReturnType {
const { idKey } = options;
const { idKey, startPositionKey, labelWidthKey, padding = 0 } = options;
const groups = stackOverlappingLabels(items, options);

const stackMap: StackOverlappingLabelsMapReturnType = {};

for (const group of groups) {
let i = 0;
const laneEdges: number[] = [];

for (const item of group) {
const key = item[idKey];
if (key === undefined || key === null) {
throw new Error(
`Invalid or missing idKey value for item: ${JSON.stringify(item)}`,
);
}
stackMap[key as string | number] = i;
if (item.assignment) i++;

const startPosition = item[startPositionKey];
const itemEnd = startPosition + item[labelWidthKey] + padding;

// Find the first lane whose right edge does not overlap this item is start.
// If no such lane exists, open a new one.
let assignedLane = laneEdges.findIndex((edge) => edge <= startPosition);
if (assignedLane === -1) {
assignedLane = laneEdges.length;
}

laneEdges[assignedLane] = itemEnd;
stackMap[key] = assignedLane;
}
}

return stackMap;
}

Expand All @@ -84,7 +102,7 @@ function stackOverlappingLabels<T extends Record<string, any>>(
}
currentGroup = [item];
}
lastInPixel = startPosition + labelWidth + padding;
lastInPixel = Math.max(lastInPixel, startPosition + labelWidth + padding);
}

if (currentGroup.length > 0) {
Expand Down
Loading