diff --git a/public/app/plugins/panel/canvas/ConnectionAnchors.tsx b/public/app/plugins/panel/canvas/ConnectionAnchors.tsx index 199cec648cd..d618ae1fcbc 100644 --- a/public/app/plugins/panel/canvas/ConnectionAnchors.tsx +++ b/public/app/plugins/panel/canvas/ConnectionAnchors.tsx @@ -14,6 +14,9 @@ type Props = { export const CONNECTION_ANCHOR_DIV_ID = 'connectionControl'; export const CONNECTION_ANCHOR_ALT = 'connection anchor'; +export const CONNECTION_ANCHOR_HIGHLIGHT_OFFSET = 8; + +const ANCHOR_PADDING = 3; export const ConnectionAnchors = ({ setRef, handleMouseLeave }: Props) => { const highlightEllipseRef = useRef(null); @@ -30,8 +33,8 @@ export const ConnectionAnchors = ({ setRef, handleMouseLeave }: Props) => { if (highlightEllipseRef.current && event.target.style) { highlightEllipseRef.current.style.display = 'block'; - highlightEllipseRef.current.style.top = `calc(${event.target.style.top} - ${halfSizeHighlightEllipse}px)`; - highlightEllipseRef.current.style.left = `calc(${event.target.style.left} - ${halfSizeHighlightEllipse}px)`; + highlightEllipseRef.current.style.top = `calc(${event.target.style.top} - ${halfSizeHighlightEllipse}px + ${ANCHOR_PADDING}px)`; + highlightEllipseRef.current.style.left = `calc(${event.target.style.left} - ${halfSizeHighlightEllipse}px + ${ANCHOR_PADDING}px)`; } }; @@ -78,8 +81,8 @@ export const ConnectionAnchors = ({ setRef, handleMouseLeave }: Props) => { // Convert anchor coords to relative percentage const style = { - top: `calc(${-anchor.y * 50 + 50}% - ${halfSize}px)`, - left: `calc(${anchor.x * 50 + 50}% - ${halfSize}px)`, + top: `calc(${-anchor.y * 50 + 50}% - ${halfSize}px - ${ANCHOR_PADDING}px)`, + left: `calc(${anchor.x * 50 + 50}% - ${halfSize}px - ${ANCHOR_PADDING}px)`, }; return ( @@ -122,10 +125,11 @@ const getStyles = (theme: GrafanaTheme2) => ({ height: calc(100% + 60px); `, anchor: css` + padding: ${ANCHOR_PADDING}px; position: absolute; cursor: cursor; - width: 5px; - height: 5px; + width: calc(5px + 2 * ${ANCHOR_PADDING}px); + height: calc(5px + 2 * ${ANCHOR_PADDING}px); z-index: 100; pointer-events: auto !important; `, diff --git a/public/app/plugins/panel/canvas/Connections.tsx b/public/app/plugins/panel/canvas/Connections.tsx index a7cb726b72c..fa106ad31e1 100644 --- a/public/app/plugins/panel/canvas/Connections.tsx +++ b/public/app/plugins/panel/canvas/Connections.tsx @@ -4,7 +4,7 @@ import { ConnectionPath } from 'app/features/canvas'; import { ElementState } from 'app/features/canvas/runtime/element'; import { Scene } from 'app/features/canvas/runtime/scene'; -import { CONNECTION_ANCHOR_ALT, ConnectionAnchors } from './ConnectionAnchors'; +import { CONNECTION_ANCHOR_ALT, ConnectionAnchors, CONNECTION_ANCHOR_HIGHLIGHT_OFFSET } from './ConnectionAnchors'; import { ConnectionSVG } from './ConnectionSVG'; import { isConnectionSource, isConnectionTarget } from './utils'; @@ -16,6 +16,7 @@ export class Connections { connectionSource?: ElementState; connectionTarget?: ElementState; isDrawingConnection?: boolean; + didConnectionLeaveHighlight?: boolean; constructor(scene: Scene) { this.scene = scene; @@ -118,11 +119,19 @@ export class Connections { this.connectionLine.setAttribute('x2', `${x}`); this.connectionLine.setAttribute('y2', `${y}`); + const connectionLineX1 = this.connectionLine.x1.baseVal.value; + const connectionLineY1 = this.connectionLine.y1.baseVal.value; + if (!this.didConnectionLeaveHighlight) { + const connectionLength = Math.hypot(x - connectionLineX1, y - connectionLineY1); + if (connectionLength > CONNECTION_ANCHOR_HIGHLIGHT_OFFSET && this.connectionSVG) { + this.didConnectionLeaveHighlight = true; + this.connectionSVG.style.display = 'block'; + this.isDrawingConnection = true; + } + } + if (!event.buttons) { if (this.connectionSource && this.connectionSource.div && this.connectionSource.div.parentElement) { - const connectionLineX1 = this.connectionLine.x1.baseVal.value; - const connectionLineY1 = this.connectionLine.y1.baseVal.value; - const sourceRect = this.connectionSource.div.getBoundingClientRect(); const parentRect = this.connectionSource.div.parentElement.getBoundingClientRect(); @@ -174,9 +183,10 @@ export class Connections { if (!options.connections) { options.connections = []; } - this.connectionSource.options.connections = [...options.connections, connection]; - - this.connectionSource.onChange(this.connectionSource.options); + if (this.didConnectionLeaveHighlight) { + this.connectionSource.options.connections = [...options.connections, connection]; + this.connectionSource.onChange(this.connectionSource.options); + } } if (this.connectionSVG) { @@ -198,10 +208,8 @@ export class Connections { const connectionStartTargetBox = selectedTarget.getBoundingClientRect(); const parentBoundingRect = this.scene.div.parentElement.getBoundingClientRect(); - // TODO: Make this not as magic numbery -> related to the height / width of highlight ellipse - const connectionAnchorHighlightOffset = 8; - const x = connectionStartTargetBox.x - parentBoundingRect.x + connectionAnchorHighlightOffset; - const y = connectionStartTargetBox.y - parentBoundingRect.y + connectionAnchorHighlightOffset; + const x = connectionStartTargetBox.x - parentBoundingRect.x + CONNECTION_ANCHOR_HIGHLIGHT_OFFSET; + const y = connectionStartTargetBox.y - parentBoundingRect.y + CONNECTION_ANCHOR_HIGHLIGHT_OFFSET; const mouseX = clientX - parentBoundingRect.x; const mouseY = clientY - parentBoundingRect.y; @@ -210,9 +218,7 @@ export class Connections { this.connectionLine.setAttribute('y1', `${y}`); this.connectionLine.setAttribute('x2', `${mouseX}`); this.connectionLine.setAttribute('y2', `${mouseY}`); - this.connectionSVG.style.display = 'block'; - - this.isDrawingConnection = true; + this.didConnectionLeaveHighlight = false; } this.scene.selecto?.rootContainer?.addEventListener('mousemove', this.connectionListener);