Added infinite dragging and some css updates to make the canvas drag UX more consistent

This commit is contained in:
Dean 2024-11-26 16:45:29 +00:00
parent 1505476fe1
commit 293abc80e1
5 changed files with 61 additions and 28 deletions

View File

@ -11,6 +11,9 @@
import { Utils, memo } from "@budibase/frontend-core" import { Utils, memo } from "@budibase/frontend-core"
import { selectedAutomation, automationStore } from "stores/builder" import { selectedAutomation, automationStore } from "stores/builder"
// CSS classes that, on mouse down, will trigger the view drag behaviour
export let draggableClasses = []
export function toFocus() { export function toFocus() {
viewToFocusEle() viewToFocusEle()
} }
@ -161,6 +164,10 @@
// Scale prop for the icon // Scale prop for the icon
let dotDefault = 0.006 let dotDefault = 0.006
let viewDragStart = { x: 0, y: 0 }
let viewDragOffset = [0, 0]
let startPos = [0, 0]
$: bgSize = Math.max(bgDim * $view.scale, 10) $: bgSize = Math.max(bgDim * $view.scale, 10)
$: bgWidth = bgSize $: bgWidth = bgSize
$: bgHeight = bgSize $: bgHeight = bgSize
@ -275,14 +282,17 @@
y, y,
})) }))
if (down && !$view.dragging && dragOffset) { if (down && !$view.dragging) {
// Determine how much the view has moved since
viewDragOffset = [x - viewDragStart.x, y - viewDragStart.y]
contentPos.update(state => ({ contentPos.update(state => ({
...state, ...state,
x: x - dragOffset[0], x: startPos[0] + viewDragOffset[0],
y: y - dragOffset[1], y: startPos[1] + viewDragOffset[1],
})) }))
offsetX = x - dragOffset[0] offsetX = startPos[0] + viewDragOffset[0]
offsetY = y - dragOffset[1] offsetY = startPos[1] + viewDragOffset[1]
} }
const clearScrollInterval = () => { const clearScrollInterval = () => {
@ -367,6 +377,9 @@
const globalMouseUp = () => { const globalMouseUp = () => {
down = false down = false
viewDragStart = { x: 0, y: 0 }
viewDragOffset = [0, 0]
if ($view.dragging) { if ($view.dragging) {
dragOffset = [0, 0] dragOffset = [0, 0]
view.update(state => ({ view.update(state => ({
@ -482,6 +495,11 @@
dragOffset = [Math.abs(x - $contentPos.x), Math.abs(y - $contentPos.y)] dragOffset = [Math.abs(x - $contentPos.x), Math.abs(y - $contentPos.y)]
} }
const isDraggable = e => {
const draggable = ["draggable-view", ...draggableClasses]
return draggable.some(cls => e.target.classList.contains(cls))
}
const viewToFocusEle = () => { const viewToFocusEle = () => {
if ($focusElement) { if ($focusElement) {
const viewWidth = viewDims.width const viewWidth = viewDims.width
@ -566,31 +584,31 @@
<div <div
class="draggable-view" class="draggable-view"
class:dragging={down}
bind:this={viewPort} bind:this={viewPort}
on:wheel={Utils.domDebounce(onViewScroll)} on:wheel={Utils.domDebounce(onViewScroll)}
on:mousemove={Utils.domDebounce(onViewMouseMove)} on:mousemove={Utils.domDebounce(onViewMouseMove)}
on:mouseup={onViewDragEnd}
>
<div
class="content-wrap"
style={wrapStyles}
bind:this={contentWrap}
class:dragging={down}
>
<div
class="content"
bind:this={mainContent}
on:mousemove={Utils.domDebounce(onMoveContent)}
on:mousedown={e => { on:mousedown={e => {
if (e.which === 1 || e.button === 0) { if ((e.which === 1 || e.button === 0) && isDraggable(e)) {
const { x, y } = eleXY(e, viewPort)
viewDragStart = { x, y }
startPos = [$contentPos.x, $contentPos.y]
down = true down = true
} }
}} }}
on:mouseup={e => { on:mouseup={e => {
if (e.which === 1 || e.button === 0) { viewDragOffset = [0, 0]
if ((e.which === 1 || e.button === 0) && isDraggable(e)) {
down = false down = false
} }
onViewDragEnd()
}} }}
>
<div class="content-wrap" style={wrapStyles} bind:this={contentWrap}>
<div
class="content"
bind:this={mainContent}
on:mousemove={Utils.domDebounce(onMoveContent)}
> >
<slot name="content" /> <slot name="content" />
</div> </div>
@ -608,7 +626,12 @@
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
cursor: grab;
} }
.draggable-view.dragging {
cursor: grabbing;
}
.content { .content {
transform-origin: 50% 50%; transform-origin: 50% 50%;
transform: scale(var(--scale)); transform: scale(var(--scale));
@ -623,14 +646,9 @@
left: 0; left: 0;
width: var(--wrapW); width: var(--wrapW);
height: var(--wrapH); height: var(--wrapH);
cursor: grab;
transform: translate(var(--posX), var(--posY)); transform: translate(var(--posX), var(--posY));
} }
.content-wrap.dragging {
cursor: grabbing;
}
.draggable-background { .draggable-background {
position: absolute; position: absolute;
width: 100%; width: 100%;

View File

@ -223,6 +223,7 @@
.branch-actions { .branch-actions {
display: flex; display: flex;
gap: var(--spacing-l); gap: var(--spacing-l);
cursor: default;
} }
.footer { .footer {
display: flex; display: flex;
@ -261,6 +262,7 @@
background-color: var(--background); background-color: var(--background);
border: 1px solid var(--spectrum-global-color-gray-300); border: 1px solid var(--spectrum-global-color-gray-300);
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
cursor: default;
} }
.blockSection { .blockSection {

View File

@ -127,7 +127,18 @@
</div> </div>
<div class="root" bind:this={treeEle}> <div class="root" bind:this={treeEle}>
<DraggableCanvas bind:this={draggable}> <DraggableCanvas
bind:this={draggable}
draggableClasses={[
"main-content",
"content",
"block",
"branched",
"branch",
"flow-item",
"branch-wrap",
]}
>
<span class="main-content" slot="content"> <span class="main-content" slot="content">
{#if Object.keys(blockRefs).length} {#if Object.keys(blockRefs).length}
{#each blocks as block, idx (block.id)} {#each blocks as block, idx (block.id)}

View File

@ -400,6 +400,7 @@
width: 480px; width: 480px;
font-size: 16px; font-size: 16px;
border-radius: 4px; border-radius: 4px;
cursor: default;
} }
.block .wrap { .block .wrap {
width: 100%; width: 100%;

View File

@ -47,5 +47,6 @@
display: flex; display: flex;
gap: var(--spacing-m); gap: var(--spacing-m);
padding: 8px 12px; padding: 8px 12px;
cursor: default;
} }
</style> </style>