/** * 计算阻止点击的区域(分成多个矩形块) * 用于 Spotlight 和 Overlay 组件 */ export interface BlockingDiv { top: number left: number width: string | number height: string | number } export interface Rect { top: number left: number width: number height: number } /** * 根据高亮区域计算需要阻止点击的 div 块 * @param rects 高亮区域的矩形列表(视口坐标) * @param viewportWidth 视口宽度 * @param viewportHeight 视口高度 * @returns 阻止点击的 div 块列表 */ export function getBlockingDivs( rects: Rect[], viewportWidth: number, viewportHeight: number ): BlockingDiv[] { if (rects.length === 0) return [] const blocks: BlockingDiv[] = [] // 找出所有孔的边界 const minTop = Math.min(...rects.map((r) => r.top)) const maxBottom = Math.max(...rects.map((r) => r.top + r.height)) const minLeft = Math.min(...rects.map((r) => r.left)) const maxRight = Math.max(...rects.map((r) => r.left + r.width)) // 顶部大块 if (minTop > 0) { blocks.push({ top: 0, left: 0, width: '100%', height: minTop, }) } // 底部大块 if (maxBottom < viewportHeight) { blocks.push({ top: maxBottom, left: 0, width: '100%', height: viewportHeight - maxBottom, }) } // 左侧大块(中间部分) if (minLeft > 0) { blocks.push({ top: minTop, left: 0, width: minLeft, height: maxBottom - minTop, }) } // 右侧大块(中间部分) if (maxRight < viewportWidth) { blocks.push({ top: minTop, left: maxRight, width: viewportWidth - maxRight, height: maxBottom - minTop, }) } // 对于多个孔的情况,填充孔之间的间隙 if (rects.length > 1) { // 按位置排序 const sortedByTop = [...rects].sort((a, b) => a.top - b.top) const sortedByLeft = [...rects].sort((a, b) => a.left - b.left) // 填充垂直间隙 for (let i = 0; i < sortedByTop.length - 1; i++) { const current = sortedByTop[i]! const next = sortedByTop[i + 1]! const gap = next.top - (current.top + current.height) if (gap > 0) { blocks.push({ top: current.top + current.height, left: Math.max(current.left, next.left), width: Math.min(current.width, next.width), height: gap, }) } } // 填充水平间隙 for (let i = 0; i < sortedByLeft.length - 1; i++) { const current = sortedByLeft[i]! const next = sortedByLeft[i + 1]! const gap = next.left - (current.left + current.width) if (gap > 0) { blocks.push({ top: Math.max(current.top, next.top), left: current.left + current.width, width: gap, height: Math.min(current.height, next.height), }) } } } return blocks }