123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import { css } from '@emotion/css';
- import { identity } from 'lodash';
- import React, { useCallback } from 'react';
- import { Field, FieldColorModeId, GrafanaTheme } from '@grafana/data';
- import { LegendDisplayMode } from '@grafana/schema';
- import { Icon, useStyles, useTheme, VizLegend, VizLegendItem, VizLegendListItem } from '@grafana/ui';
- import { Config } from './layout';
- import { NodeDatum } from './types';
- function getStyles() {
- return {
- item: css`
- label: LegendItem;
- flex-grow: 0;
- `,
- legend: css`
- label: Legend;
- pointer-events: all;
- `,
- };
- }
- interface Props {
- nodes: NodeDatum[];
- onSort: (sort: Config['sort']) => void;
- sort?: Config['sort'];
- sortable: boolean;
- }
- export const Legend = function Legend(props: Props) {
- const { nodes, onSort, sort, sortable } = props;
- const theme = useTheme();
- const styles = useStyles(getStyles);
- const colorItems = getColorLegendItems(nodes, theme);
- const onClick = useCallback(
- (item) => {
- onSort({
- field: item.data!.field,
- ascending: item.data!.field === sort?.field ? !sort?.ascending : false,
- });
- },
- [sort, onSort]
- );
- return (
- <VizLegend<ItemData>
- className={styles.legend}
- displayMode={LegendDisplayMode.List}
- placement={'bottom'}
- items={colorItems}
- itemRenderer={(item) => {
- return (
- <>
- <VizLegendListItem item={item} className={styles.item} onLabelClick={sortable ? onClick : undefined} />
- {sortable &&
- (sort?.field === item.data!.field ? <Icon name={sort!.ascending ? 'arrow-up' : 'arrow-down'} /> : '')}
- </>
- );
- }}
- />
- );
- };
- interface ItemData {
- field: Field;
- }
- function getColorLegendItems(nodes: NodeDatum[], theme: GrafanaTheme): Array<VizLegendItem<ItemData>> {
- if (!nodes.length) {
- return [];
- }
- const fields = [nodes[0].mainStat, nodes[0].secondaryStat].filter(identity) as Field[];
- const node = nodes.find((n) => n.arcSections.length > 0);
- if (node) {
- if (node.arcSections[0]!.config?.color?.mode === FieldColorModeId.Fixed) {
- // We assume in this case we have a set of fixed colors which map neatly into a basic legend.
- // Lets collect and deduplicate as there isn't a requirement for 0 size arc section to be defined
- fields.push(...new Set(nodes.map((n) => n.arcSections).flat()));
- }
- }
- if (nodes[0].color) {
- fields.push(nodes[0].color);
- }
- return fields.map((f) => {
- const item: VizLegendItem = {
- label: f.config.displayName || f.name,
- yAxis: 0,
- data: { field: f },
- };
- if (f.config.color?.mode === FieldColorModeId.Fixed && f.config.color?.fixedColor) {
- item.color = theme.visualization.getColorByName(f.config.color?.fixedColor || '');
- } else if (f.config.color?.mode) {
- item.gradient = f.config.color?.mode;
- }
- if (!(item.color || item.gradient)) {
- // Defaults to gray color
- item.color = theme.visualization.getColorByName('');
- }
- return item;
- });
- }
|