From e9dfc9ad9f646c3e546f598115fa78c2a03be95e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Sat, 8 Oct 2022 15:04:18 +0100 Subject: [PATCH] Throttle updates to prevent all jank and revert to component center breakboints for DND candidates --- .../client/src/components/Component.svelte | 3 +- .../src/components/preview/DNDHandler.svelte | 111 ++++++++++++++---- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 005eb12f2d..e6dbbf8579 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -495,7 +495,8 @@ transition: padding 250ms ease, border 250ms ease; } .component.explode :global(> *) { - padding: 16px !important; + padding: 32px !important; + gap: 16px !important; border: 2px dashed var(--spectrum-global-color-gray-400) !important; border-radius: 4px !important; } diff --git a/packages/client/src/components/preview/DNDHandler.svelte b/packages/client/src/components/preview/DNDHandler.svelte index fbfdf06310..20bbc8bada 100644 --- a/packages/client/src/components/preview/DNDHandler.svelte +++ b/packages/client/src/components/preview/DNDHandler.svelte @@ -3,6 +3,7 @@ import IndicatorSet from "./IndicatorSet.svelte" import { builderStore } from "stores" import PlaceholderOverlay from "./PlaceholderOverlay.svelte" + import { Utils } from "@budibase/frontend-core" let dragInfo let dropInfo @@ -75,15 +76,34 @@ }, 0) } - const handleEvent = e => { + let lastX + let lastY + let lastTime + + const processEvent = (mouseX, mouseY) => { if (!dropInfo) { return null } - e.preventDefault() let { id, parent, node, acceptsChildren, empty } = dropInfo - const mouseY = e.clientY - const mouseX = e.clientX + + // Debounce by 10px difference + // if (lastX != null && lastY != null) { + // const delta = Math.abs(mouseY - lastY) + Math.abs(mouseX - lastX) + // if (delta < 10) { + // console.log("delta fail") + // return + // } + // } + // lastX = mouseX + // lastY = mouseY + + // Debounce by time + // if (Date.now() - (lastTime || 0) < 100) { + // console.log("time fail") + // return + // } + // lastTime = Date.now() // If we're over something that does not accept children then we go up a // level and consider the mouse position relative to the parent @@ -112,7 +132,7 @@ const childCoords = [...(node.children || [])].map(node => { const bounds = node.children[0].getBoundingClientRect() return { - // placeholder: node.classList.contains("placeholder"), + placeholder: node.classList.contains("placeholder"), centerX: bounds.left + bounds.width / 2, centerY: bounds.top + bounds.height / 2, left: bounds.left, @@ -139,36 +159,79 @@ const column = ["centerX", "left", "right"].includes(variances[0].side) console.log(column ? "COL" : "ROW") - // Calculate breakpoints between children - let midpoints = [] - for (let i = 0; i < childCoords.length - 1; i++) { - const child1 = childCoords[i] - const child2 = childCoords[i + 1] - let midpoint - if (column) { - const top = Math.min(child1.top, child2.top) - const bottom = Math.max(child1.bottom, child2.bottom) - midpoint = (top + bottom) / 2 - } else { - const left = Math.min(child1.left, child2.left) - const right = Math.max(child1.right, child2.right) - midpoint = (left + right) / 2 - } - midpoints.push(midpoint) - } - // let midpoints = childCoords.map(x => (column ? x.centerY : x.centerX)) + /** SYMMETRICAL BREAKPOINTS **/ + // let breakpoints = [] + // for (let i = 0; i < childCoords.length - 1; i++) { + // const child1 = childCoords[i] + // const child2 = childCoords[i + 1] + // let breakpoint + // if (column) { + // const top = Math.min(child1.top, child2.top) + // const bottom = Math.max(child1.bottom, child2.bottom) + // breakpoint = (top + bottom) / 2 + // } else { + // const left = Math.min(child1.left, child2.left) + // const right = Math.max(child1.right, child2.right) + // breakpoint = (left + right) / 2 + // } + // breakpoints.push(breakpoint) + // } + + /** CENTER BREAKPOINTS **/ + let breakpoints = childCoords + .filter(x => !x.placeholder) + .map(x => { + return column ? x.centerY : x.centerX + }) + + /** NEXT EDGE BREAKPOINTS **/ + // let breakpoints = [] + // for (let i = 0; i < childCoords.length; i++) { + // let breakpoint + // if (column) { + // if (mouseY > childCoords[i].top && mouseY < childCoords[i].bottom) { + // // Inside this container + // if (childCoords[i + 1]) { + // breakpoint = childCoords[i + 1].top + // } else { + // breakpoint = childCoords[i].top + // } + // } else { + // breakpoint = + // mouseY < childCoords[i].bottom + // ? childCoords[i].top + // : childCoords[i].bottom + // } + // } else { + // breakpoint = + // mouseX < childCoords[i].left + // ? childCoords[i].left + // : childCoords[i].right + // } + // breakpoints.push(breakpoint) + // } // Determine the index to drop the component in const mousePosition = column ? mouseY : mouseX + let idx = 0 - while (idx < midpoints.length && midpoints[idx] < mousePosition) { + while (idx < breakpoints.length && breakpoints[idx] < mousePosition) { idx++ } + + // console.log(mousePosition, breakpoints.map(Math.round), idx) + placeholderInfo = { parent: id, index: idx, } } + const throttledProcessEvent = Utils.throttle(processEvent, 250) + + const handleEvent = e => { + e.preventDefault() + throttledProcessEvent(e.clientX, e.clientY) + } // Callback when on top of a component const onDragOver = e => {