Removed zoom output, added focus element registration to allow centering the automations to the trigger on load.Stopped dragging when editing steps or branches and other minor fixes
This commit is contained in:
parent
95069ef59f
commit
2b982ab2d0
|
@ -82,14 +82,14 @@
|
|||
//focus - node to center on?
|
||||
})
|
||||
|
||||
setContext("view", view)
|
||||
setContext("draggableView", view)
|
||||
|
||||
// View internal pos tracking
|
||||
const internalPos = writable({ x: 0, y: 0 })
|
||||
setContext("viewPos", internalPos)
|
||||
|
||||
// Content pos tracking
|
||||
const contentPos = writable({ x: 0, y: 0 })
|
||||
const contentPos = writable({ x: 0, y: 0, scrollX: 0, scrollY: 0 })
|
||||
setContext("contentPos", contentPos)
|
||||
|
||||
// Elements
|
||||
|
@ -112,8 +112,14 @@
|
|||
// When dragging the content, maintain the drag start offset
|
||||
let dragOffset
|
||||
|
||||
// Used when focusing the UI on trigger
|
||||
let loaded = false
|
||||
|
||||
// Edge around the draggable content
|
||||
let contentDragPadding = 200
|
||||
|
||||
// Auto scroll
|
||||
let scrollInterval
|
||||
// let scrollInterval
|
||||
|
||||
const onScale = async () => {
|
||||
dispatch("zoom", $view.scale)
|
||||
|
@ -167,9 +173,15 @@
|
|||
...state,
|
||||
x: state.x - xBump,
|
||||
y: state.y,
|
||||
// If scrolling *and* dragging, maintain a record of the scroll offset
|
||||
...($view.dragging
|
||||
? {
|
||||
scrollX: state.scrollX - xBump,
|
||||
}
|
||||
: {}),
|
||||
}))
|
||||
} else if (e.ctrlKey || e.metaKey) {
|
||||
// Scale
|
||||
// Scale the content on scrolling
|
||||
let updatedScale
|
||||
if (e.deltaY < 0) {
|
||||
updatedScale = Math.min(1, currentScale + 0.05)
|
||||
|
@ -187,6 +199,12 @@
|
|||
...state,
|
||||
x: state.x,
|
||||
y: state.y - yBump,
|
||||
// If scrolling *and* dragging, maintain a record of the scroll offset
|
||||
...($view.dragging
|
||||
? {
|
||||
scrollY: state.scrollY - yBump,
|
||||
}
|
||||
: {}),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -211,22 +229,26 @@
|
|||
// Needs to handle when the mouse leaves the screen
|
||||
// Needs to know the direction of movement and accelerate/decelerate
|
||||
if (y < (viewDims.height / 100) * 20 && $view.dragging) {
|
||||
if (!scrollInterval) {
|
||||
// if (!scrollInterval) {
|
||||
// scrollInterval = setInterval(() => {
|
||||
// contentPos = { x: contentPos.x, y: contentPos.y + 35 }
|
||||
// contentPos.update(state => ({
|
||||
// ...state,
|
||||
// x: contentPos.x,
|
||||
// y: contentPos.y + 35,
|
||||
// }))
|
||||
// }, 100)
|
||||
}
|
||||
} else {
|
||||
if (scrollInterval) {
|
||||
clearInterval(scrollInterval)
|
||||
scrollInterval = undefined
|
||||
}
|
||||
// }
|
||||
// } else {
|
||||
// if (scrollInterval) {
|
||||
// clearInterval(scrollInterval)
|
||||
// scrollInterval = undefined
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
const onViewDragEnd = () => {
|
||||
down = false
|
||||
dragOffset = []
|
||||
dragOffset = [0, 0]
|
||||
}
|
||||
|
||||
const handleDragDrop = () => {
|
||||
|
@ -256,6 +278,13 @@
|
|||
dropzones: {},
|
||||
droptarget: null,
|
||||
}))
|
||||
|
||||
// Clear the scroll offset for dragging
|
||||
contentPos.update(state => ({
|
||||
...state,
|
||||
scrollY: 0,
|
||||
scrollX: 0,
|
||||
}))
|
||||
}
|
||||
|
||||
const onMouseMove = async e => {
|
||||
|
@ -279,7 +308,6 @@
|
|||
}
|
||||
|
||||
if ($view.dragging) {
|
||||
// TODO - Need to adjust content pos
|
||||
const adjustedX =
|
||||
(e.clientX - viewDims.left - $view.moveStep.offsetX) / $view.scale
|
||||
const adjustedY =
|
||||
|
@ -325,23 +353,49 @@
|
|||
dragOffset = [Math.abs(x - $contentPos.x), Math.abs(y - $contentPos.y)]
|
||||
}
|
||||
|
||||
const focusOnLoad = () => {
|
||||
if ($view.focusEle && !loaded) {
|
||||
const focusEleDims = $view.focusEle
|
||||
const viewWidth = viewDims.width
|
||||
|
||||
// The amount to shift the content in order to center the trigger on load.
|
||||
// The content is also padded with `contentDragPadding`
|
||||
// The sidebar offset factors into the left positioning of the content here.
|
||||
const targetX =
|
||||
contentWrap.getBoundingClientRect().x -
|
||||
focusEleDims.x +
|
||||
(viewWidth / 2 - focusEleDims.width / 2)
|
||||
|
||||
// Update the content position state
|
||||
// Shift the content up slightly to accommodate the padding
|
||||
contentPos.update(state => ({
|
||||
...state,
|
||||
x: targetX,
|
||||
y: -(contentDragPadding / 2),
|
||||
}))
|
||||
|
||||
loaded = true
|
||||
}
|
||||
}
|
||||
|
||||
// Update dims after scaling
|
||||
$: {
|
||||
$view.scale
|
||||
onScale()
|
||||
}
|
||||
|
||||
// Focus on a registered element
|
||||
$: {
|
||||
$view.focusEle
|
||||
focusOnLoad()
|
||||
}
|
||||
|
||||
// Content mouse pos and scale to css variables.
|
||||
// The wrap is set to match the content size
|
||||
$: wrapStyles = buildWrapStyles($contentPos, $view.scale, contentDims)
|
||||
|
||||
onMount(() => {
|
||||
observer = new ResizeObserver(entries => {
|
||||
if (!entries?.[0]) {
|
||||
return
|
||||
}
|
||||
getDims()
|
||||
})
|
||||
observer = new ResizeObserver(getDims)
|
||||
observer.observe(viewPort)
|
||||
})
|
||||
|
||||
|
@ -358,6 +412,7 @@
|
|||
aria-label="Viewport for building automations"
|
||||
on:mouseup={onMouseUp}
|
||||
on:mousemove={Utils.domDebounce(onMouseMove)}
|
||||
style={`--dragPadding: ${contentDragPadding}px;`}
|
||||
>
|
||||
<div
|
||||
class="draggable-view"
|
||||
|
@ -367,6 +422,17 @@
|
|||
on:mouseup={onViewDragEnd}
|
||||
on:mouseleave={onViewDragEnd}
|
||||
>
|
||||
<!-- <div class="debug">
|
||||
<span>
|
||||
View Pos [{$internalPos.x}, {$internalPos.y}]
|
||||
</span>
|
||||
<span>View Dims [{viewDims.width}, {viewDims.height}]</span>
|
||||
<span>Mouse Down [{down}]</span>
|
||||
<span>Drag [{$view.dragging}]</span>
|
||||
<span>Dragging [{$view?.moveStep?.id || "no"}]</span>
|
||||
<span>Scale [{$view.scale}]</span>
|
||||
<span>Content [{JSON.stringify($contentPos)}]</span>
|
||||
</div> -->
|
||||
<div
|
||||
class="content-wrap"
|
||||
style={wrapStyles}
|
||||
|
@ -423,16 +489,24 @@
|
|||
width: var(--wrapW);
|
||||
height: var(--wrapH);
|
||||
cursor: grab;
|
||||
transform: translate(var(--posX), var(--posY));
|
||||
}
|
||||
.content {
|
||||
/* transition: all 0.1s ease-out; */
|
||||
transform: translate(var(--posX), var(--posY)) scale(var(--scale));
|
||||
transform: scale(var(--scale));
|
||||
user-select: none;
|
||||
padding: 200px;
|
||||
padding-top: 200px;
|
||||
padding: var(--dragPadding);
|
||||
}
|
||||
|
||||
.content-wrap.dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.debug {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
position: fixed;
|
||||
padding: 8px;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
export let bindings
|
||||
export let automation
|
||||
|
||||
const view = getContext("view")
|
||||
const view = getContext("draggableView")
|
||||
|
||||
let drawer
|
||||
let condition
|
||||
|
@ -87,7 +87,14 @@
|
|||
</Drawer>
|
||||
|
||||
<div class="flow-item">
|
||||
<div class={`block branch-node hoverable`} class:selected={false}>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class={`block branch-node hoverable`}
|
||||
class:selected={false}
|
||||
on:mousedown={e => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<FlowItemHeader
|
||||
{automation}
|
||||
{open}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
let dropEle
|
||||
let dzid = generate()
|
||||
|
||||
const view = getContext("view")
|
||||
const view = getContext("draggableView")
|
||||
|
||||
onMount(() => {
|
||||
// Always return up-to-date values
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
let blockRefs = {}
|
||||
let treeEle
|
||||
let draggable
|
||||
let zoom = 100
|
||||
|
||||
// Memo auto - selectedAutomation
|
||||
$: memoAutomation.set(automation)
|
||||
|
@ -89,7 +88,6 @@
|
|||
<ActionButton icon="Add" quiet on:click={draggable.zoomIn} />
|
||||
<ActionButton icon="Remove" quiet on:click={draggable.zoomOut} />
|
||||
</div>
|
||||
<div class="zoom-display">{`${zoom}%`}</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
|
@ -140,17 +138,7 @@
|
|||
</div>
|
||||
|
||||
<div class="root" bind:this={treeEle}>
|
||||
<DraggableCanvas
|
||||
bind:this={draggable}
|
||||
on:zoom={e => {
|
||||
const baseZoom = Math.round(e.detail * 100)
|
||||
|
||||
// Fit to zoom shifts the zoom to explicit values
|
||||
// The interval is in 5 or 10 so rounding to the closest 5 should flatten this out
|
||||
const roundedZoom = 5 * Math.floor((baseZoom + 2) / 5)
|
||||
zoom = roundedZoom
|
||||
}}
|
||||
>
|
||||
<DraggableCanvas bind:this={draggable}>
|
||||
<span class="main-content" slot="content">
|
||||
{#if Object.keys(blockRefs).length}
|
||||
{#each blocks as block, idx (block.id)}
|
||||
|
@ -183,12 +171,6 @@
|
|||
</Modal>
|
||||
|
||||
<style>
|
||||
.zoom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
|
||||
.toggle-active :global(.spectrum-Switch) {
|
||||
margin: 0px;
|
||||
}
|
||||
|
|
|
@ -35,22 +35,23 @@
|
|||
export let bindings
|
||||
export let draggable = true
|
||||
|
||||
const view = getContext("view")
|
||||
const view = getContext("draggableView")
|
||||
const pos = getContext("viewPos")
|
||||
const contentPos = getContext("contentPos")
|
||||
|
||||
let webhookModal
|
||||
let open = true
|
||||
let showLooping = false
|
||||
let role
|
||||
let blockEle
|
||||
|
||||
$: pathSteps = loadSteps(blockRef)
|
||||
let positionStyles
|
||||
|
||||
const loadSteps = blockRef => {
|
||||
return blockRef
|
||||
? automationStore.actions.getPathSteps(blockRef.pathTo, automation)
|
||||
: []
|
||||
}
|
||||
$: pathSteps = loadSteps(blockRef)
|
||||
|
||||
$: collectBlockExists = pathSteps.some(
|
||||
step => step.stepId === ActionStepID.COLLECT
|
||||
|
@ -76,18 +77,23 @@
|
|||
$: blockDims = blockEle?.getBoundingClientRect()
|
||||
$: placeholderDims = buildPlaceholderStyles(blockDims)
|
||||
|
||||
let positionStyles
|
||||
|
||||
// Move the selected item
|
||||
$: move(blockEle, $view?.dragSpot, selected)
|
||||
// Listen for scrolling in the content. As its scrolled this will be updated
|
||||
$: move(
|
||||
blockEle,
|
||||
$view?.dragSpot,
|
||||
selected,
|
||||
$contentPos?.scrollX,
|
||||
$contentPos?.scrollY
|
||||
)
|
||||
|
||||
const move = (block, dragPos, selected) => {
|
||||
const move = (block, dragPos, selected, scrollX, scrollY) => {
|
||||
if ((!block && !selected) || !dragPos) {
|
||||
return
|
||||
}
|
||||
positionStyles = `
|
||||
--blockPosX: ${Math.round(dragPos.x)}px;
|
||||
--blockPosY: ${Math.round(dragPos.y)}px;
|
||||
--blockPosX: ${Math.round(dragPos.x - scrollX / $view.scale)}px;
|
||||
--blockPosY: ${Math.round(dragPos.y - scrollY / $view.scale)}px;
|
||||
`
|
||||
}
|
||||
|
||||
|
@ -184,6 +190,9 @@
|
|||
class="block-content"
|
||||
class:dragging={$view.dragging && selected}
|
||||
style={positionStyles}
|
||||
on:mousedown={e => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{#if draggable}
|
||||
<div
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { environment } from "stores/portal"
|
||||
import { cloneDeep } from "lodash"
|
||||
import { memo } from "@budibase/frontend-core"
|
||||
import { getContext, onMount } from "svelte"
|
||||
|
||||
export let step = {}
|
||||
export let stepIdx
|
||||
|
@ -15,6 +16,9 @@
|
|||
export let isLast = false
|
||||
|
||||
const memoEnvVariables = memo($environment.variables)
|
||||
const view = getContext("draggableView")
|
||||
|
||||
let stepEle
|
||||
|
||||
$: memoEnvVariables.set($environment.variables)
|
||||
$: blockRef = blocks?.[step.id]
|
||||
|
@ -34,6 +38,17 @@
|
|||
|
||||
// Combine all bindings for the step
|
||||
$: bindings = [...availableBindings, ...environmentBindings]
|
||||
|
||||
onMount(() => {
|
||||
// Register the trigger as the focus element for the automation
|
||||
// Onload, the canvas will use the dimensions to center the step
|
||||
if (stepEle && step.type === "TRIGGER" && !$view.focusEle) {
|
||||
view.update(state => ({
|
||||
...state,
|
||||
focusEle: stepEle.getBoundingClientRect(),
|
||||
}))
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if isBranch}
|
||||
|
@ -105,7 +120,7 @@
|
|||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="block">
|
||||
<div class="block" bind:this={stepEle}>
|
||||
<FlowItem
|
||||
block={step}
|
||||
idx={stepIdx}
|
||||
|
|
Loading…
Reference in New Issue