diff --git a/.changeset/kind-radios-attend.md b/.changeset/kind-radios-attend.md new file mode 100644 index 0000000000..3a32f9c67d --- /dev/null +++ b/.changeset/kind-radios-attend.md @@ -0,0 +1,5 @@ +--- +'livekit-client': patch +--- + +compute initial visible value for element infos manually diff --git a/src/room/track/RemoteVideoTrack.ts b/src/room/track/RemoteVideoTrack.ts index 6143234d81..badbf4e87f 100644 --- a/src/room/track/RemoteVideoTrack.ts +++ b/src/room/track/RemoteVideoTrack.ts @@ -110,6 +110,8 @@ export default class RemoteVideoTrack extends RemoteTrack { // the tab comes into focus for the first time. this.debouncedHandleResize(); this.updateVisibility(); + } else { + log.warn('visibility resize observer not triggered'); } } @@ -294,9 +296,9 @@ class HTMLElementInfo implements ElementInfo { handleVisibilityChanged?: () => void; - constructor(element: HTMLMediaElement, visible: boolean = false) { + constructor(element: HTMLMediaElement, visible?: boolean) { this.element = element; - this.visible = visible; + this.visible = visible ?? isElementInViewport(element); this.visibilityChangedAt = 0; } @@ -332,3 +334,29 @@ class HTMLElementInfo implements ElementInfo { getResizeObserver()?.unobserve(this.element); } } + +// does not account for occlusion by other elements +function isElementInViewport(el: HTMLElement) { + let top = el.offsetTop; + let left = el.offsetLeft; + const width = el.offsetWidth; + const height = el.offsetHeight; + const { hidden } = el; + const { opacity, display } = getComputedStyle(el); + + while (el.offsetParent) { + el = el.offsetParent as HTMLElement; + top += el.offsetTop; + left += el.offsetLeft; + } + + return ( + top < window.pageYOffset + window.innerHeight && + left < window.pageXOffset + window.innerWidth && + top + height > window.pageYOffset && + left + width > window.pageXOffset && + !hidden && + (opacity !== '' ? parseFloat(opacity) > 0 : true) && + display !== 'none' + ); +}