Canvas: Improve anchor UX (#62409)

Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
Drew Slobodnjak 2023-02-03 09:02:37 -08:00 committed by GitHub
parent 43ce077133
commit bbb572e73f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 20 deletions

View File

@ -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<HTMLDivElement>(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;
`,

View File

@ -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);