grafana/public/app/plugins/panel/nodeGraph/Edge.tsx
Rob 677b765dab
NodeGraph: Edge color and stroke-dasharray support (#83855)
* Adds color and stroke-dasharray support for node graph edges

Adds support for providing color, highlighted color, and visual display of node graph edges as dashed lines via stroke-dasharray.

* Updates node graph documentation

* Updates documentation

Adds default for `highlightedColor`

* Update docs/sources/panels-visualizations/visualizations/node-graph/index.md

Co-authored-by: Fabrizio <135109076+fabrizio-grafana@users.noreply.github.com>

* Update packages/grafana-data/src/utils/nodeGraph.ts

Co-authored-by: Fabrizio <135109076+fabrizio-grafana@users.noreply.github.com>

* Update docs/sources/panels-visualizations/visualizations/node-graph/index.md

Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>

* Removes highlightedColor; deprecates highlighted

Per [request](https://github.com/grafana/grafana/pull/83855#issuecomment-1999810826), deprecates `highlighted` in code and documentation, and removes `highlightedColor` as an additional property. `highlighted` will continue to be supported in its original state (makes the edge red), but is superseded if `color` is provided.

* Update types.ts

Missed a file in my last commit. Removes `highlightedColor` and deprecates `highlighted`.

* Add test scenario in test data source

---------

Co-authored-by: Fabrizio <135109076+fabrizio-grafana@users.noreply.github.com>
Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com>
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
2024-03-18 16:26:22 +01:00

90 lines
2.9 KiB
TypeScript

import React, { MouseEvent, memo } from 'react';
import { EdgeArrowMarker } from './EdgeArrowMarker';
import { computeNodeCircumferenceStrokeWidth, nodeR } from './Node';
import { EdgeDatum, NodeDatum } from './types';
import { shortenLine } from './utils';
export const defaultHighlightedEdgeColor = '#a00';
export const defaultEdgeColor = '#999';
interface Props {
edge: EdgeDatum;
hovering: boolean;
onClick: (event: MouseEvent<SVGElement>, link: EdgeDatum) => void;
onMouseEnter: (id: string) => void;
onMouseLeave: (id: string) => void;
}
export const Edge = memo(function Edge(props: Props) {
const { edge, onClick, onMouseEnter, onMouseLeave, hovering } = props;
// Not great typing but after we do layout these properties are full objects not just references
const { source, target, sourceNodeRadius, targetNodeRadius } = edge as {
source: NodeDatum;
target: NodeDatum;
sourceNodeRadius: number;
targetNodeRadius: number;
};
const arrowHeadHeight = 10 + edge.thickness * 2; // resized value, just to make the UI nicer
// As the nodes have some radius we want edges to end outside of the node circle.
const line = shortenLine(
{
x1: source.x!,
y1: source.y!,
x2: target.x!,
y2: target.y!,
},
sourceNodeRadius + computeNodeCircumferenceStrokeWidth(sourceNodeRadius) / 2 || nodeR,
targetNodeRadius + computeNodeCircumferenceStrokeWidth(targetNodeRadius) / 2 || nodeR,
arrowHeadHeight
);
const edgeColor = edge.color || defaultEdgeColor;
// @deprecated -- until 'highlighted' is removed we'll prioritize 'color'
// in case both are provided
const highlightedEdgeColor = edge.color || defaultHighlightedEdgeColor;
const markerId = `triangle-${edge.id}`;
const coloredMarkerId = `triangle-colored-${edge.id}`;
return (
<>
<EdgeArrowMarker id={markerId} fill={edgeColor} headHeight={arrowHeadHeight} />
<EdgeArrowMarker id={coloredMarkerId} fill={highlightedEdgeColor} headHeight={arrowHeadHeight} />
<g
onClick={(event) => onClick(event, edge)}
style={{ cursor: 'pointer' }}
aria-label={`Edge from: ${source.id} to: ${target.id}`}
>
<line
strokeWidth={(hovering ? 1 : 0) + (edge.highlighted ? 1 : 0) + edge.thickness}
stroke={edge.highlighted ? highlightedEdgeColor : edgeColor}
x1={line.x1}
y1={line.y1}
x2={line.x2}
y2={line.y2}
strokeDasharray={edge.strokeDasharray}
markerEnd={`url(#${edge.highlighted ? coloredMarkerId : markerId})`}
/>
<line
stroke={'transparent'}
x1={line.x1}
y1={line.y1}
x2={line.x2}
y2={line.y2}
strokeWidth={20}
onMouseEnter={() => {
onMouseEnter(edge.id);
}}
onMouseLeave={() => {
onMouseLeave(edge.id);
}}
/>
</g>
</>
);
});