1
0
Fork 0
mirror of synced 2024-09-20 19:33:10 +12:00

Simply and improve performance of indicators

This commit is contained in:
Andrew Kingston 2024-08-09 21:21:59 +01:00
parent 376192e85a
commit 863fafa1d0
No known key found for this signature in database

View file

@ -32,15 +32,8 @@
let interval let interval
let state = defaultState() let state = defaultState()
let nextState = null
let updating = false
let observers = []
let callbackCount = 0
$: offset = $builderStore.inBuilder ? 5 : -1 $: offset = $builderStore.inBuilder ? 5 : -1
$: visibleIndicators = state.indicators.filter(x => x.visible)
// Update position when any props change
$: config.set({ $: config.set({
componentId, componentId,
color, color,
@ -48,43 +41,21 @@
prefix, prefix,
allowResizeAnchors, allowResizeAnchors,
}) })
// Update position when any props change
$: $config, debouncedUpdate() $: $config, debouncedUpdate()
const checkInsideGrid = id => { const checkInsideGrid = id => {
return isGridChild(document.getElementsByClassName(id)[0]) return isGridChild(document.getElementsByClassName(id)[0])
} }
const createIntersectionCallback = idx => entries => {
if (callbackCount >= observers.length) {
return
}
nextState.indicators[idx].visible =
nextState.indicators[idx].insideModal ||
nextState.indicators[idx].insideSidePanel ||
entries[0].isIntersecting
if (++callbackCount === observers.length) {
state = nextState
updating = false
}
}
const updatePosition = () => { const updatePosition = () => {
if (updating) {
return
}
// Sanity check // Sanity check
if (!componentId) { if (!componentId) {
state = defaultState() state = defaultState()
return return
} }
let nextState = defaultState()
// Reset state
updating = true
callbackCount = 0
observers.forEach(o => o.disconnect())
observers = []
nextState = defaultState()
// Check if we're inside a grid // Check if we're inside a grid
if (allowResizeAnchors) { if (allowResizeAnchors) {
@ -109,7 +80,7 @@
const scrollY = window.scrollY const scrollY = window.scrollY
// Extract valid children // Extract valid children
// Sanity limit of 100 active indicators // Sanity limit of active indicators
const className = nextState.insideGrid ? componentId : `${componentId}-dom` const className = nextState.insideGrid ? componentId : `${componentId}-dom`
const children = Array.from(document.getElementsByClassName(className)) const children = Array.from(document.getElementsByClassName(className))
.filter(x => x != null) .filter(x => x != null)
@ -118,32 +89,21 @@
// If there aren't any nodes then reset // If there aren't any nodes then reset
if (!children.length) { if (!children.length) {
state = defaultState() state = defaultState()
updating = false
return return
} }
const device = document.getElementById("app-root") const device = document.getElementById("app-root")
const deviceBounds = device.getBoundingClientRect() const deviceBounds = device.getBoundingClientRect()
children.forEach((child, idx) => { nextState.indicators = children.map(child => {
const callback = createIntersectionCallback(idx)
const threshold = children.length > 1 ? 1 : 0
const observer = new IntersectionObserver(callback, {
threshold,
root: device,
})
observer.observe(child)
observers.push(observer)
const elBounds = child.getBoundingClientRect() const elBounds = child.getBoundingClientRect()
nextState.indicators.push({ return {
top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset), top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset),
left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset), left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset),
width: Math.round(elBounds.width + 2), width: Math.round(elBounds.width + 2),
height: Math.round(elBounds.height + 2), height: Math.round(elBounds.height + 2),
visible: false, }
insideSidePanel: !!child.closest(".side-panel"),
insideModal: !!child.closest(".modal-content"),
})
}) })
state = nextState
} }
const debouncedUpdate = Utils.domDebounce(updatePosition) const debouncedUpdate = Utils.domDebounce(updatePosition)
@ -156,11 +116,10 @@
onDestroy(() => { onDestroy(() => {
clearInterval(interval) clearInterval(interval)
document.removeEventListener("scroll", debouncedUpdate, true) document.removeEventListener("scroll", debouncedUpdate, true)
observers.forEach(o => o.disconnect())
}) })
</script> </script>
{#each visibleIndicators as indicator, idx} {#each state.indicators as indicator, idx}
<Indicator <Indicator
top={indicator.top} top={indicator.top}
left={indicator.left} left={indicator.left}