Eduard Kuzmenko
3 years ago
6 changed files with 156 additions and 74 deletions
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
/* |
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/ |
||||
|
||||
import getVisibleRect from "./getVisibleRect"; |
||||
|
||||
export type ViewportSlicePart = {element: HTMLElement, rect: DOMRect, visibleRect: ReturnType<typeof getVisibleRect>}[]; |
||||
|
||||
export default function getViewportSlice({overflowElement, selector, extraSize}: { |
||||
overflowElement: HTMLElement, |
||||
selector: string, |
||||
extraSize?: number |
||||
}) { |
||||
const perf = performance.now(); |
||||
const overflowRect = overflowElement.getBoundingClientRect(); |
||||
const elements = Array.from(overflowElement.querySelectorAll<HTMLElement>(selector)); |
||||
|
||||
const invisibleTop: ViewportSlicePart = [], |
||||
visible: typeof invisibleTop = [], |
||||
invisibleBottom: typeof invisibleTop = []; |
||||
let foundVisible = false; |
||||
for(const element of elements) { |
||||
const rect = element.getBoundingClientRect(); |
||||
const visibleRect = getVisibleRect(element, overflowElement, false, rect, overflowRect); |
||||
|
||||
const isVisible = !!visibleRect; |
||||
let array: typeof invisibleTop; |
||||
if(isVisible) { |
||||
foundVisible = true; |
||||
array = visible; |
||||
} else if(foundVisible) { |
||||
array = invisibleBottom; |
||||
} else { |
||||
array = invisibleTop; |
||||
} |
||||
|
||||
array.push({ |
||||
element, |
||||
rect, |
||||
visibleRect |
||||
}); |
||||
} |
||||
|
||||
if(extraSize && visible.length) { |
||||
const maxTop = visible[0].rect.top; |
||||
const minTop = maxTop - extraSize; |
||||
const minBottom = visible[visible.length - 1].rect.bottom; |
||||
const maxBottom = minBottom + extraSize; |
||||
|
||||
for(let length = invisibleTop.length, i = length - 1; i >= 0; --i) { |
||||
const element = invisibleTop[i]; |
||||
if(element.rect.top >= minTop) { |
||||
invisibleTop.splice(i, 1); |
||||
visible.unshift(element); |
||||
} |
||||
} |
||||
|
||||
for(let i = 0, length = invisibleBottom.length; i < length; ++i) { |
||||
const element = invisibleBottom[i]; |
||||
if(element.rect.bottom <= maxBottom) { |
||||
invisibleBottom.splice(i--, 1); |
||||
--length; |
||||
visible.push(element); |
||||
} |
||||
} |
||||
} |
||||
|
||||
console.log('getViewportSlice time:', performance.now() - perf); |
||||
|
||||
return {invisibleTop, visible, invisibleBottom}; |
||||
} |
Loading…
Reference in new issue