skip overlapping labels using greedy placement algorithm
Labels are placed in DOM order, skipping any that would overlap with already-placed labels. Uses AABB intersection test.
This commit is contained in:
@@ -202,7 +202,7 @@ export async function showAriaRefLabels({ page, interactiveOnly = true }: {
|
|||||||
// Using 'any' types here since this code runs in browser context
|
// Using 'any' types here since this code runs in browser context
|
||||||
const labelCount = await page.evaluate(
|
const labelCount = await page.evaluate(
|
||||||
({ refs, containerId, containerStyles, labelStyles }: {
|
({ refs, containerId, containerStyles, labelStyles }: {
|
||||||
refs: Array<{ ref: string; element: { getBoundingClientRect(): { width: number; height: number; left: number; top: number } } }>
|
refs: Array<{ ref: string; element: { getBoundingClientRect(): { width: number; height: number; left: number; top: number; right: number; bottom: number } } }>
|
||||||
containerId: string
|
containerId: string
|
||||||
containerStyles: string
|
containerStyles: string
|
||||||
labelStyles: string
|
labelStyles: string
|
||||||
@@ -223,6 +223,22 @@ export async function showAriaRefLabels({ page, interactiveOnly = true }: {
|
|||||||
style.textContent = labelStyles
|
style.textContent = labelStyles
|
||||||
container.appendChild(style)
|
container.appendChild(style)
|
||||||
|
|
||||||
|
// Track placed label rectangles for overlap detection
|
||||||
|
// Each rect is { left, top, right, bottom } in viewport coordinates
|
||||||
|
const placedLabels: Array<{ left: number; top: number; right: number; bottom: number }> = []
|
||||||
|
|
||||||
|
// Estimate label dimensions (11px font + padding)
|
||||||
|
const LABEL_HEIGHT = 16
|
||||||
|
const LABEL_CHAR_WIDTH = 7 // approximate width per character
|
||||||
|
|
||||||
|
// Check if two rectangles overlap
|
||||||
|
const rectsOverlap = (
|
||||||
|
a: { left: number; top: number; right: number; bottom: number },
|
||||||
|
b: { left: number; top: number; right: number; bottom: number }
|
||||||
|
) => {
|
||||||
|
return a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top
|
||||||
|
}
|
||||||
|
|
||||||
// Create label for each interactive element
|
// Create label for each interactive element
|
||||||
let count = 0
|
let count = 0
|
||||||
for (const { ref, element } of refs) {
|
for (const { ref, element } of refs) {
|
||||||
@@ -233,16 +249,34 @@ export async function showAriaRefLabels({ page, interactiveOnly = true }: {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate label position and dimensions
|
||||||
|
const labelWidth = ref.length * LABEL_CHAR_WIDTH + 8 // +8 for padding
|
||||||
|
const labelLeft = rect.left
|
||||||
|
const labelTop = Math.max(0, rect.top - LABEL_HEIGHT)
|
||||||
|
const labelRect = {
|
||||||
|
left: labelLeft,
|
||||||
|
top: labelTop,
|
||||||
|
right: labelLeft + labelWidth,
|
||||||
|
bottom: labelTop + LABEL_HEIGHT,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if this label would overlap with any already-placed label
|
||||||
|
const overlaps = placedLabels.some((placed) => rectsOverlap(labelRect, placed))
|
||||||
|
if (overlaps) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the label
|
||||||
const label = doc.createElement('div')
|
const label = doc.createElement('div')
|
||||||
label.className = '__pw_label__'
|
label.className = '__pw_label__'
|
||||||
label.textContent = ref
|
label.textContent = ref
|
||||||
|
|
||||||
// Position above element, accounting for scroll
|
// Position above element, accounting for scroll
|
||||||
// Use scrollX/scrollY so labels scroll with the page
|
label.style.left = `${win.scrollX + labelLeft}px`
|
||||||
label.style.left = `${win.scrollX + rect.left}px`
|
label.style.top = `${win.scrollY + labelTop}px`
|
||||||
label.style.top = `${win.scrollY + Math.max(0, rect.top - 16)}px`
|
|
||||||
|
|
||||||
container.appendChild(label)
|
container.appendChild(label)
|
||||||
|
placedLabels.push(labelRect)
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 237 KiB |
@@ -31,7 +31,7 @@
|
|||||||
- generic [ref=e55]:
|
- generic [ref=e55]:
|
||||||
- text: "Google offered in:"
|
- text: "Google offered in:"
|
||||||
- link [ref=e56] [cursor=pointer]:
|
- link [ref=e56] [cursor=pointer]:
|
||||||
- /url: https://www.google.com/setprefs?sig=0_WWAwchirMrWB5pgMRu-Ccbzsvw0%3D&hl=it&source=homepage&sa=X&ved=0ahUKEwiz58mLyO-RAxVON94AHXxmKlkQ2ZgBCBU
|
- /url: https://www.google.com/setprefs?sig=0_uKW2_iLdDvITPr98P8jjLIgrMiY%3D&hl=it&source=homepage&sa=X&ved=0ahUKEwjeh4Llye-RAxVrJNAFHaspBugQ2ZgBCBU
|
||||||
- text: Italiano
|
- text: Italiano
|
||||||
- contentinfo [ref=e58]:
|
- contentinfo [ref=e58]:
|
||||||
- generic [ref=e59]: Italy
|
- generic [ref=e59]: Italy
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 189 KiB |
Reference in New Issue
Block a user