From e2044cde1391380a509684d023b6af405f420c14 Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Thu, 28 Jul 2022 16:55:31 -0700 Subject: [PATCH] Canvas: Enable ability to instantly select and drag an element (#52861) Co-authored-by: nmarrs --- .../app/features/canvas/runtime/element.tsx | 21 ++++++++--- public/app/features/canvas/runtime/scene.tsx | 37 ++++++++++++++----- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/public/app/features/canvas/runtime/element.tsx b/public/app/features/canvas/runtime/element.tsx index c886728429b..6fc7b7a0938 100644 --- a/public/app/features/canvas/runtime/element.tsx +++ b/public/app/features/canvas/runtime/element.tsx @@ -71,7 +71,7 @@ export class ElementState implements LayerElement { } /** Use the configured options to update CSS style properties directly on the wrapper div **/ - applyLayoutStylesToDiv() { + applyLayoutStylesToDiv(disablePointerEvents?: boolean) { if (this.isRoot()) { // Root supersedes layout engine and is always 100% width + height of panel return; @@ -85,6 +85,7 @@ export class ElementState implements LayerElement { const style: React.CSSProperties = { cursor: editingEnabled ? 'grab' : 'auto', + pointerEvents: disablePointerEvents ? 'none' : 'auto', position: 'absolute', // Minimum element size is 10x10 minWidth: '10px', @@ -196,18 +197,28 @@ export class ElementState implements LayerElement { if (!elementContainer) { elementContainer = this.div && this.div.getBoundingClientRect(); } + let parentBorderWidth = 0; if (!parentContainer) { parentContainer = this.div && this.div.parentElement?.getBoundingClientRect(); + parentBorderWidth = parseFloat(getComputedStyle(this.div?.parentElement!).borderWidth); } const relativeTop = - elementContainer && parentContainer ? Math.round(elementContainer.top - parentContainer.top) : 0; + elementContainer && parentContainer + ? Math.round(elementContainer.top - parentContainer.top - parentBorderWidth) + : 0; const relativeBottom = - elementContainer && parentContainer ? Math.round(parentContainer.bottom - elementContainer.bottom) : 0; + elementContainer && parentContainer + ? Math.round(parentContainer.bottom - parentBorderWidth - elementContainer.bottom) + : 0; const relativeLeft = - elementContainer && parentContainer ? Math.round(elementContainer.left - parentContainer.left) : 0; + elementContainer && parentContainer + ? Math.round(elementContainer.left - parentContainer.left - parentBorderWidth) + : 0; const relativeRight = - elementContainer && parentContainer ? Math.round(parentContainer.right - elementContainer.right) : 0; + elementContainer && parentContainer + ? Math.round(parentContainer.right - parentBorderWidth - elementContainer.right) + : 0; const placement = {} as Placement; diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx index b7ea2502521..2d713ec594a 100644 --- a/public/app/features/canvas/runtime/scene.tsx +++ b/public/app/features/canvas/runtime/scene.tsx @@ -253,6 +253,22 @@ export class Scene { return undefined; }; + setNonTargetPointerEvents = (target: HTMLElement | SVGElement, disablePointerEvents: boolean) => { + const stack = [...this.root.elements]; + while (stack.length > 0) { + const currentElement = stack.shift(); + + if (currentElement && currentElement.div && currentElement.div !== target) { + currentElement.applyLayoutStylesToDiv(disablePointerEvents); + } + + const nestedElements = currentElement instanceof FrameState ? currentElement.elements : []; + for (const nestedElement of nestedElements) { + stack.unshift(nestedElement); + } + } + }; + setRef = (sceneContainer: HTMLDivElement) => { this.div = sceneContainer; }; @@ -266,7 +282,6 @@ export class Scene { private updateSelection = (selection: SelectionParams) => { this.moveable!.target = selection.targets; - if (this.skipNextSelectionBroadcast) { this.skipNextSelectionBroadcast = false; return; @@ -332,6 +347,7 @@ export class Scene { }) .on('dragStart', (event) => { this.ignoreDataUpdate = true; + this.setNonTargetPointerEvents(event.target, true); }) .on('dragGroupStart', (event) => { this.ignoreDataUpdate = true; @@ -365,6 +381,7 @@ export class Scene { this.moved.next(Date.now()); this.ignoreDataUpdate = false; + this.setNonTargetPointerEvents(event.target, false); }) .on('resizeStart', (event) => { const targetedElement = this.findElementByTarget(event.target); @@ -428,15 +445,15 @@ export class Scene { targets = event.selected; this.updateSelection({ targets }); - // @TODO Figure out click-drag functionality without phantom mouseup issue - // https://github.com/daybrush/moveable/issues/481 - - // if (event.isDragStart) { - // event.inputEvent.preventDefault(); - // setTimeout(() => { - // this.moveable!.dragStart(event.inputEvent); - // }); - // } + if (event.isDragStart) { + if (this.isEditingEnabled && this.selecto?.getSelectedTargets().length) { + this.selecto.getSelectedTargets()[0].style.cursor = 'grabbing'; + } + event.inputEvent.preventDefault(); + setTimeout(() => { + this.moveable!.dragStart(event.inputEvent); + }); + } }); };