Hugely improve performance of selection and highlight indicators in builder preview

This commit is contained in:
Andrew Kingston 2021-06-10 09:05:08 +01:00
parent 9040a0bd1c
commit 8576166d03
5 changed files with 60 additions and 21 deletions

View File

@ -2,6 +2,7 @@
import { onMount, onDestroy } from "svelte"
import { builderStore } from "../store"
import Indicator from "./Indicator.svelte"
import { domDebounce } from "../utils/domDebounce"
let indicators = []
let interval
@ -34,11 +35,17 @@
indicators = newIndicators
}
const debouncedUpdate = domDebounce(updatePosition)
const onMouseOver = e => {
const element = e.target.closest("[data-type='component']")
componentId = element?.dataset?.id
componentName = element?.dataset?.name
const newId = element?.dataset?.id
const newName = element?.dataset?.name
if (newId !== componentId) {
componentId = newId
componentName = newName
debouncedUpdate()
}
}
const onMouseLeave = () => {
@ -47,27 +54,33 @@
}
onMount(() => {
interval = setInterval(updatePosition, 100)
window.addEventListener("mouseover", onMouseOver)
document.documentElement.addEventListener("mouseleave", onMouseLeave)
debouncedUpdate()
interval = setInterval(debouncedUpdate, 100)
document.addEventListener("mouseover", onMouseOver)
document.addEventListener("mouseleave", onMouseLeave)
document.addEventListener("scroll", debouncedUpdate, true)
})
onDestroy(() => {
clearInterval(interval)
window.removeEventListener("mouseover", onMouseOver)
document.documentElement.removeEventListener("mouseleave", onMouseLeave)
document.removeEventListener("mouseover", onMouseOver)
document.removeEventListener("mouseleave", onMouseLeave)
document.removeEventListener("scroll", debouncedUpdate, true)
})
</script>
{#if componentId !== $builderStore.selectedComponentId}
{#each indicators as indicator, idx}
<Indicator
top={indicator.top}
left={indicator.left}
width={indicator.width}
height={indicator.height}
text={idx === 0 ? componentName : null}
color="rgb(120, 170, 244)"
/>
{/each}
{/if}
{#key componentId}
{#if componentId !== $builderStore.selectedComponentId}
{#each indicators as indicator, idx}
<Indicator
top={indicator.top}
left={indicator.left}
width={indicator.width}
height={indicator.height}
text={idx === 0 ? componentName : null}
color="rgb(120, 170, 244)"
transition
/>
{/each}
{/if}
{/key}

View File

@ -1,13 +1,17 @@
<script>
import { fade } from "svelte/transition"
export let top
export let left
export let width
export let height
export let text
export let color
export let transition = false
</script>
<div
in:fade={{ delay: transition ? 65 : 0, duration: transition ? 130 : 0 }}
class="indicator"
style="top: {top}px; left: {left}px; width: {width}px; height: {height}px; --color: {color};"
>

View File

@ -2,6 +2,7 @@
import { onMount, onDestroy } from "svelte"
import { builderStore } from "../store"
import Indicator from "./Indicator.svelte"
import { domDebounce } from "../utils/domDebounce"
let indicators = []
let interval
@ -29,13 +30,17 @@
}
indicators = newIndicators
}
const debouncedUpdate = domDebounce(updatePosition)
onMount(() => {
interval = setInterval(updatePosition, 100)
debouncedUpdate()
interval = setInterval(debouncedUpdate, 100)
document.addEventListener("scroll", debouncedUpdate, true)
})
onDestroy(() => {
clearInterval(interval)
document.removeEventListener("scroll", debouncedUpdate, true)
})
</script>

View File

@ -2,6 +2,7 @@
import { onMount, onDestroy } from "svelte"
import SettingsButton from "./SettingsButton.svelte"
import { builderStore } from "../store"
import { domDebounce } from "../utils/domDebounce"
const verticalOffset = 28
const horizontalOffset = 2
@ -63,13 +64,17 @@
measured = true
}
}
const debouncedUpdate = domDebounce(updatePosition)
onMount(() => {
interval = setInterval(updatePosition, 100)
debouncedUpdate()
interval = setInterval(debouncedUpdate, 100)
document.addEventListener("scroll", debouncedUpdate, true)
})
onDestroy(() => {
clearInterval(interval)
document.removeEventListener("scroll", debouncedUpdate, true)
})
</script>

View File

@ -0,0 +1,12 @@
export const domDebounce = callback => {
let active = false
return e => {
if (!active) {
window.requestAnimationFrame(() => {
callback(e)
active = false
})
active = true
}
}
}