(rects: DOMRect[] | DOMRectList)
| 30 | * @param rects |
| 31 | */ |
| 32 | const splitRectsIntoLines = (rects: DOMRect[] | DOMRectList) => { |
| 33 | const lines: Map<LineRectangle, DOMRect[]> = new Map() |
| 34 | if (rects.length === 0) return lines |
| 35 | |
| 36 | const lineKeys: LineRectangle[] = [] |
| 37 | |
| 38 | /** |
| 39 | * Finds the line that the rectangle belongs to. |
| 40 | * @param rect |
| 41 | */ |
| 42 | const findLineKey = (rect: DOMRect) => { |
| 43 | for (const lineKey of lineKeys) { |
| 44 | const { right } = lineKey |
| 45 | const previousRects = lines.get(lineKey) |
| 46 | const lastRect = previousRects |
| 47 | ? previousRects |
| 48 | .concat() |
| 49 | .reverse() |
| 50 | .find(p => p.width > 0) ?? previousRects[previousRects.length - 1] |
| 51 | : null |
| 52 | if (isRectInLine(rect, lineKey) && rect.left <= (lastRect ? lastRect.right : right) + 1) { |
| 53 | return lineKey |
| 54 | } |
| 55 | } |
| 56 | return null |
| 57 | } |
| 58 | |
| 59 | // Loop through each rectangle and find its line |
| 60 | for (let r = 0; r < rects.length; r++) { |
| 61 | const rect = rects[r] |
| 62 | const key = findLineKey(rect) |
| 63 | if (key) { |
| 64 | lines.get(key)?.push(rect) |
| 65 | } else { |
| 66 | const lineRect = { |
| 67 | top: rect.top, |
| 68 | height: rect.height, |
| 69 | bottom: rect.bottom, |
| 70 | left: rect.left, |
| 71 | right: rect.right, |
| 72 | } |
| 73 | lines.set(lineRect, [rect]) |
| 74 | lineKeys.push(lineRect) |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | // Find the minimum top, maximum bottom, and maximum right for each line |
| 79 | for (const [line, rects] of lines) { |
| 80 | // If there's only one rectangle in the line, skip |
| 81 | if (rects.length === 1) continue |
| 82 | |
| 83 | let minTop = line.top, |
| 84 | maxBottom = line.bottom, |
| 85 | maxRight = line.right |
| 86 | |
| 87 | // Compare each rectangle |
| 88 | for (const rect of rects) { |
| 89 | const { top, bottom, right } = rect |
no test coverage detected
searching dependent graphs…