From 3c974763900686b2d307901e24113c5d75d3e375 Mon Sep 17 00:00:00 2001 From: Ihor Yeromin Date: Tue, 19 Mar 2024 17:56:10 +0100 Subject: [PATCH] Canvas: Support dashed connection lines (#84496) * feat(canvas): add connection types --- public/app/features/canvas/element.ts | 1 + .../components/connections/ConnectionSVG.tsx | 4 +++- .../panel/canvas/editor/LineStyleEditor.tsx | 24 +++++++++++++++++++ .../panel/canvas/editor/connectionEditor.tsx | 1 + .../plugins/panel/canvas/editor/options.ts | 18 ++++++++++++++ public/app/plugins/panel/canvas/types.ts | 10 ++++++++ public/app/plugins/panel/canvas/utils.ts | 5 ++-- 7 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx diff --git a/public/app/features/canvas/element.ts b/public/app/features/canvas/element.ts index 99b51e4df37..82dc4ad831f 100644 --- a/public/app/features/canvas/element.ts +++ b/public/app/features/canvas/element.ts @@ -49,6 +49,7 @@ export interface CanvasConnection { path: ConnectionPath; color?: ColorDimensionConfig; size?: ScaleDimensionConfig; + lineStyle?: string; vertices?: ConnectionCoordinates[]; // See https://github.com/anseki/leader-line#options for more examples of more properties } diff --git a/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx b/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx index f0d7c960a42..03fd8875ea2 100644 --- a/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx +++ b/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx @@ -134,7 +134,7 @@ export const ConnectionSVG = ({ const { x1, y1, x2, y2 } = calculateCoordinates(sourceRect, parentRect, info, target, transformScale); const midpoint = calculateMidpoint(x1, y1, x2, y2); - const { strokeColor, strokeWidth } = getConnectionStyles(info, scene, defaultArrowSize); + const { strokeColor, strokeWidth, lineStyle } = getConnectionStyles(info, scene, defaultArrowSize); const isSelected = selectedConnection === v && scene.panel.context.instanceState.selectedConnection; @@ -199,6 +199,7 @@ export const ConnectionSVG = ({ d={pathString} stroke={strokeColor} strokeWidth={strokeWidth} + strokeDasharray={lineStyle} fill={'none'} markerEnd={`url(#${CONNECTION_HEAD_ID})`} /> @@ -261,6 +262,7 @@ export const ConnectionSVG = ({ stroke={strokeColor} pointerEvents="auto" strokeWidth={strokeWidth} + strokeDasharray={lineStyle} markerEnd={`url(#${CONNECTION_HEAD_ID})`} x1={x1} y1={y1} diff --git a/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx new file mode 100644 index 00000000000..75a6b934c0d --- /dev/null +++ b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx @@ -0,0 +1,24 @@ +import React, { useCallback } from 'react'; + +import { SelectableValue, StandardEditorProps } from '@grafana/data'; +import { RadioButtonGroup } from '@grafana/ui/src'; + +import { LineStyle } from '../types'; + +const options: Array> = [ + { value: LineStyle.Solid, label: 'Solid' }, + { value: LineStyle.Dashed, label: 'Dashed' }, +]; + +export const LineStyleEditor = ({ value, onChange }: StandardEditorProps) => { + const lineStyle = value ?? LineStyle.Solid; + + const onLineStyleChange = useCallback( + (lineStyle: string) => { + onChange(lineStyle); + }, + [onChange] + ); + + return ; +}; diff --git a/public/app/plugins/panel/canvas/editor/connectionEditor.tsx b/public/app/plugins/panel/canvas/editor/connectionEditor.tsx index 480d5ac041f..87027fb82f6 100644 --- a/public/app/plugins/panel/canvas/editor/connectionEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/connectionEditor.tsx @@ -36,6 +36,7 @@ export function getConnectionEditor(opts: CanvasConnectionEditorOptions): Nested const ctx = { ...context, options: opts.connection.info }; optionBuilder.addColor(builder, ctx); optionBuilder.addSize(builder, ctx); + optionBuilder.addLineStyle(builder, ctx); }, }; } diff --git a/public/app/plugins/panel/canvas/editor/options.ts b/public/app/plugins/panel/canvas/editor/options.ts index 12858d18c7b..e09b5e049ae 100644 --- a/public/app/plugins/panel/canvas/editor/options.ts +++ b/public/app/plugins/panel/canvas/editor/options.ts @@ -3,11 +3,16 @@ import { CanvasConnection, CanvasElementOptions } from 'app/features/canvas'; import { ColorDimensionEditor, ResourceDimensionEditor, ScaleDimensionEditor } from 'app/features/dimensions/editors'; import { BackgroundSizeEditor } from 'app/features/dimensions/editors/BackgroundSizeEditor'; +import { LineStyle } from '../types'; + +import { LineStyleEditor } from './LineStyleEditor'; + interface OptionSuppliers { addBackground: PanelOptionsSupplier; addBorder: PanelOptionsSupplier; addColor: PanelOptionsSupplier; addSize: PanelOptionsSupplier; + addLineStyle: PanelOptionsSupplier; } const getCategoryName = (str: string, type: string | undefined) => { @@ -120,4 +125,17 @@ export const optionBuilder: OptionSuppliers = { }, }); }, + + addLineStyle: (builder, context) => { + const category = ['Line style']; + builder.addCustomEditor({ + category, + id: 'lineStyle', + path: 'lineStyle', + name: 'Line style', + editor: LineStyleEditor, + settings: {}, + defaultValue: { value: LineStyle.Solid, label: 'Solid' }, + }); + }, }; diff --git a/public/app/plugins/panel/canvas/types.ts b/public/app/plugins/panel/canvas/types.ts index 19df754159c..0c7dcf123e0 100644 --- a/public/app/plugins/panel/canvas/types.ts +++ b/public/app/plugins/panel/canvas/types.ts @@ -43,3 +43,13 @@ export interface ConnectionState { info: CanvasConnection; vertices?: ConnectionCoordinates[]; } + +export enum LineStyle { + Solid = 'solid', + Dashed = 'dashed', +} + +export enum StrokeDasharray { + Solid = '0', + Dashed = '8 8', +} diff --git a/public/app/plugins/panel/canvas/utils.ts b/public/app/plugins/panel/canvas/utils.ts index 71cf411c3e4..f9a4b3f9a73 100644 --- a/public/app/plugins/panel/canvas/utils.ts +++ b/public/app/plugins/panel/canvas/utils.ts @@ -17,7 +17,7 @@ import { FrameState } from 'app/features/canvas/runtime/frame'; import { Scene, SelectionParams } from 'app/features/canvas/runtime/scene'; import { DimensionContext } from 'app/features/dimensions'; -import { AnchorPoint, ConnectionState } from './types'; +import { AnchorPoint, ConnectionState, LineStyle, StrokeDasharray } from './types'; export function doSelect(scene: Scene, element: ElementState | FrameState) { try { @@ -379,7 +379,8 @@ export const getConnectionStyles = (info: CanvasConnection, scene: Scene, defaul const lastRowIndex = getRowIndex(info.size?.field, scene); const strokeColor = info.color ? scene.context.getColor(info.color).value() : defaultArrowColor; const strokeWidth = info.size ? scene.context.getScale(info.size).get(lastRowIndex) : defaultArrowSize; - return { strokeColor, strokeWidth }; + const lineStyle = info.lineStyle === LineStyle.Dashed ? StrokeDasharray.Dashed : StrokeDasharray.Solid; + return { strokeColor, strokeWidth, lineStyle }; }; export const getParentBoundingClientRect = (scene: Scene) => {