mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PieChart: Unify tooltip to look the way it looks in TimeSeries (#33032)
* feat(piechart): align styles between piechart and graph * feat(piechart): introduce tooltip options to panel and visualisation * feat(piechart): get tooltip options working * feat(piechart): add SeriesTable to visx TooltipInPortal * refactor(piechart): move getTooltipData out of PieSlice * docs(piechart): fix storybook story errors * feat(viztooltip): initial commit of common tooltip types and components * refactor(viztooltip): rename type as enum and update usage * refactor(viztooltip): move chart.tooltip into viztooltip and fix imports and typings * refactor(viztooltip): update import paths and names where used * docs(infotooltip): fix story import paths * docs(piechart): fix typings in story * docs(viztooltip): add public annotations to exported components and types
This commit is contained in:
parent
5f54f2dc00
commit
c2953f3a06
@ -23,7 +23,7 @@ TableSortByFieldState: {
|
|||||||
desc?: bool
|
desc?: bool
|
||||||
} @cuetsy(targetType="interface")
|
} @cuetsy(targetType="interface")
|
||||||
|
|
||||||
TooltipMode: "single" | "multi" | "none" @cuetsy(targetType="type")
|
TooltipDisplayMode: "single" | "multi" | "none" @cuetsy(targetType="enum")
|
||||||
FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(targetType="type")
|
FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(targetType="type")
|
||||||
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(targetType="enum")
|
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(targetType="enum")
|
||||||
PointVisibility: "auto" | "never" | "always" @cuetsy(targetType="enum")
|
PointVisibility: "auto" | "never" | "always" @cuetsy(targetType="enum")
|
||||||
@ -72,9 +72,6 @@ HideSeriesConfig: {
|
|||||||
} @cuetsy(targetType="interface")
|
} @cuetsy(targetType="interface")
|
||||||
LegendPlacement: "bottom" | "right" @cuetsy(targetType="type")
|
LegendPlacement: "bottom" | "right" @cuetsy(targetType="type")
|
||||||
LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(targetType="enum")
|
LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(targetType="enum")
|
||||||
GraphTooltipOptions: {
|
|
||||||
mode: TooltipMode
|
|
||||||
} @cuetsy(targetType="interface")
|
|
||||||
TableFieldOptions: {
|
TableFieldOptions: {
|
||||||
width?: number
|
width?: number
|
||||||
align: FieldTextAlignment | *"auto"
|
align: FieldTextAlignment | *"auto"
|
||||||
@ -91,3 +88,6 @@ VizLegendOptions: {
|
|||||||
placement: LegendPlacement
|
placement: LegendPlacement
|
||||||
calcs: [string]
|
calcs: [string]
|
||||||
} @cuetsy(targetType="interface")
|
} @cuetsy(targetType="interface")
|
||||||
|
VizTooltipOptions: {
|
||||||
|
mode: TooltipDisplayMode
|
||||||
|
} @cuetsy(targetType="interface")
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { Tooltip } from './Tooltip';
|
|
||||||
|
|
||||||
const Chart = {
|
|
||||||
Tooltip,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Chart;
|
|
@ -1,3 +0,0 @@
|
|||||||
package grafanaschema
|
|
||||||
|
|
||||||
TooltipMode: "single" | "multi" | "none" @cuetsy(targetType="type")
|
|
@ -1,6 +0,0 @@
|
|||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// NOTE: This file will be auto generated from models.cue
|
|
||||||
// It is currenty hand written but will serve as the target for cuetsy
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
export type TooltipMode = 'single' | 'multi' | 'none';
|
|
@ -1,11 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Graph } from '@grafana/ui';
|
import { Graph } from '@grafana/ui';
|
||||||
import Chart from '../Chart';
|
|
||||||
import { dateTime, ArrayVector, FieldType, GraphSeriesXY, FieldColorModeId } from '@grafana/data';
|
import { dateTime, ArrayVector, FieldType, GraphSeriesXY, FieldColorModeId } from '@grafana/data';
|
||||||
import { Story } from '@storybook/react';
|
import { Story } from '@storybook/react';
|
||||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
import { TooltipContentProps } from '../Chart/Tooltip';
|
import { VizTooltip, TooltipDisplayMode, VizTooltipContentProps } from '../VizTooltip';
|
||||||
import { TooltipMode } from '../Chart/models.gen';
|
|
||||||
import { JSONFormatter } from '../JSONFormatter/JSONFormatter';
|
import { JSONFormatter } from '../JSONFormatter/JSONFormatter';
|
||||||
import { GraphProps } from './Graph';
|
import { GraphProps } from './Graph';
|
||||||
|
|
||||||
@ -114,15 +112,15 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithTooltip: Story<GraphProps & { tooltipMode: TooltipMode }> = ({ tooltipMode, ...args }) => {
|
export const WithTooltip: Story<GraphProps & { tooltipMode: TooltipDisplayMode }> = ({ tooltipMode, ...args }) => {
|
||||||
return (
|
return (
|
||||||
<Graph {...args}>
|
<Graph {...args}>
|
||||||
<Chart.Tooltip mode={tooltipMode} />
|
<VizTooltip mode={tooltipMode} />
|
||||||
</Graph>
|
</Graph>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomGraphTooltip = ({ activeDimensions }: TooltipContentProps) => {
|
const CustomGraphTooltip = ({ activeDimensions }: VizTooltipContentProps) => {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: '200px' }}>
|
<div style={{ height: '200px' }}>
|
||||||
<div>Showing currently active active dimensions:</div>
|
<div>Showing currently active active dimensions:</div>
|
||||||
@ -131,10 +129,13 @@ const CustomGraphTooltip = ({ activeDimensions }: TooltipContentProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithCustomTooltip: Story<GraphProps & { tooltipMode: TooltipMode }> = ({ tooltipMode, ...args }) => {
|
export const WithCustomTooltip: Story<GraphProps & { tooltipMode: TooltipDisplayMode }> = ({
|
||||||
|
tooltipMode,
|
||||||
|
...args
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Graph {...args}>
|
<Graph {...args}>
|
||||||
<Chart.Tooltip mode={tooltipMode} tooltipComponent={CustomGraphTooltip} />
|
<VizTooltip mode={tooltipMode} tooltipComponent={CustomGraphTooltip} />
|
||||||
</Graph>
|
</Graph>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import Graph from './Graph';
|
import Graph from './Graph';
|
||||||
import Chart from '../Chart';
|
import { VizTooltip, TooltipDisplayMode } from '../VizTooltip';
|
||||||
import { GraphSeriesXY, FieldType, ArrayVector, dateTime, FieldColorModeId } from '@grafana/data';
|
import { GraphSeriesXY, FieldType, ArrayVector, dateTime, FieldColorModeId } from '@grafana/data';
|
||||||
|
|
||||||
const series: GraphSeriesXY[] = [
|
const series: GraphSeriesXY[] = [
|
||||||
@ -92,7 +92,7 @@ describe('Graph', () => {
|
|||||||
it("doesn't render tooltip when not hovering over a datapoint", () => {
|
it("doesn't render tooltip when not hovering over a datapoint", () => {
|
||||||
const graphWithTooltip = (
|
const graphWithTooltip = (
|
||||||
<Graph {...mockGraphProps()}>
|
<Graph {...mockGraphProps()}>
|
||||||
<Chart.Tooltip mode="single" />
|
<VizTooltip mode={TooltipDisplayMode.Single} />
|
||||||
</Graph>
|
</Graph>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ describe('Graph', () => {
|
|||||||
// Given
|
// Given
|
||||||
const graphWithTooltip = (
|
const graphWithTooltip = (
|
||||||
<Graph {...mockGraphProps()}>
|
<Graph {...mockGraphProps()}>
|
||||||
<Chart.Tooltip mode="single" />
|
<VizTooltip mode={TooltipDisplayMode.Single} />
|
||||||
</Graph>
|
</Graph>
|
||||||
);
|
);
|
||||||
const container = mount(graphWithTooltip);
|
const container = mount(graphWithTooltip);
|
||||||
@ -145,7 +145,7 @@ describe('Graph', () => {
|
|||||||
// Given
|
// Given
|
||||||
const graphWithTooltip = (
|
const graphWithTooltip = (
|
||||||
<Graph {...mockGraphProps(true)}>
|
<Graph {...mockGraphProps(true)}>
|
||||||
<Chart.Tooltip mode="multi" />
|
<VizTooltip mode={TooltipDisplayMode.Multi} />
|
||||||
</Graph>
|
</Graph>
|
||||||
);
|
);
|
||||||
const container = mount(graphWithTooltip);
|
const container = mount(graphWithTooltip);
|
||||||
|
@ -6,11 +6,12 @@ import uniqBy from 'lodash/uniqBy';
|
|||||||
import { TimeRange, GraphSeriesXY, TimeZone, createDimension } from '@grafana/data';
|
import { TimeRange, GraphSeriesXY, TimeZone, createDimension } from '@grafana/data';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { FlotPosition, FlotItem } from './types';
|
import { FlotPosition, FlotItem } from './types';
|
||||||
import { TooltipProps, TooltipContentProps, ActiveDimensions, Tooltip } from '../Chart/Tooltip';
|
import { VizTooltipProps, VizTooltipContentProps, ActiveDimensions, VizTooltip } from '../VizTooltip';
|
||||||
import { GraphTooltip } from './GraphTooltip/GraphTooltip';
|
import { GraphTooltip } from './GraphTooltip/GraphTooltip';
|
||||||
import { GraphContextMenu, GraphContextMenuProps, ContextDimensions } from './GraphContextMenu';
|
import { GraphContextMenu, GraphContextMenuProps, ContextDimensions } from './GraphContextMenu';
|
||||||
import { GraphDimensions } from './GraphTooltip/types';
|
import { GraphDimensions } from './GraphTooltip/types';
|
||||||
import { graphTimeFormat, graphTickFormatter } from './utils';
|
import { graphTimeFormat, graphTickFormatter } from './utils';
|
||||||
|
import { TooltipDisplayMode } from '../VizTooltip/models.gen';
|
||||||
|
|
||||||
export interface GraphProps {
|
export interface GraphProps {
|
||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
@ -124,7 +125,7 @@ export class Graph extends PureComponent<GraphProps, GraphState> {
|
|||||||
renderTooltip = () => {
|
renderTooltip = () => {
|
||||||
const { children, series, timeZone } = this.props;
|
const { children, series, timeZone } = this.props;
|
||||||
const { pos, activeItem, isTooltipVisible } = this.state;
|
const { pos, activeItem, isTooltipVisible } = this.state;
|
||||||
let tooltipElement: React.ReactElement<TooltipProps> | null = null;
|
let tooltipElement: React.ReactElement<VizTooltipProps> | null = null;
|
||||||
|
|
||||||
if (!isTooltipVisible || !pos || series.length === 0) {
|
if (!isTooltipVisible || !pos || series.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -139,15 +140,15 @@ export class Graph extends PureComponent<GraphProps, GraphState> {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const childType = c && c.type && (c.type.displayName || c.type.name);
|
const childType = c && c.type && (c.type.displayName || c.type.name);
|
||||||
|
|
||||||
if (childType === Tooltip.displayName) {
|
if (childType === VizTooltip.displayName) {
|
||||||
tooltipElement = c as React.ReactElement<TooltipProps>;
|
tooltipElement = c as React.ReactElement<VizTooltipProps>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// If no tooltip provided, skip rendering
|
// If no tooltip provided, skip rendering
|
||||||
if (!tooltipElement) {
|
if (!tooltipElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const tooltipElementProps = (tooltipElement as React.ReactElement<TooltipProps>).props;
|
const tooltipElementProps = (tooltipElement as React.ReactElement<VizTooltipProps>).props;
|
||||||
|
|
||||||
const tooltipMode = tooltipElementProps.mode || 'single';
|
const tooltipMode = tooltipElementProps.mode || 'single';
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ export class Graph extends PureComponent<GraphProps, GraphState> {
|
|||||||
yAxis: activeItem ? [activeItem.series.seriesIndex, activeItem.dataIndex] : null,
|
yAxis: activeItem ? [activeItem.series.seriesIndex, activeItem.dataIndex] : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tooltipContentProps: TooltipContentProps<GraphDimensions> = {
|
const tooltipContentProps: VizTooltipContentProps<GraphDimensions> = {
|
||||||
dimensions: {
|
dimensions: {
|
||||||
// time/value dimension columns are index-aligned - see getGraphSeriesModel
|
// time/value dimension columns are index-aligned - see getGraphSeriesModel
|
||||||
xAxis: createDimension(
|
xAxis: createDimension(
|
||||||
@ -186,13 +187,13 @@ export class Graph extends PureComponent<GraphProps, GraphState> {
|
|||||||
},
|
},
|
||||||
activeDimensions,
|
activeDimensions,
|
||||||
pos,
|
pos,
|
||||||
mode: tooltipElementProps.mode || 'single',
|
mode: tooltipElementProps.mode || TooltipDisplayMode.Single,
|
||||||
timeZone,
|
timeZone,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tooltipContent = React.createElement(tooltipContentRenderer, { ...tooltipContentProps });
|
const tooltipContent = React.createElement(tooltipContentRenderer, { ...tooltipContentProps });
|
||||||
|
|
||||||
return React.cloneElement<TooltipProps>(tooltipElement as React.ReactElement<TooltipProps>, {
|
return React.cloneElement<VizTooltipProps>(tooltipElement as React.ReactElement<VizTooltipProps>, {
|
||||||
content: tooltipContent,
|
content: tooltipContent,
|
||||||
position: { x: pos.pageX, y: pos.pageY },
|
position: { x: pos.pageX, y: pos.pageY },
|
||||||
offset: { x: 10, y: 10 },
|
offset: { x: 10, y: 10 },
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TooltipContentProps } from '../../Chart/Tooltip';
|
import { VizTooltipContentProps } from '../../VizTooltip';
|
||||||
import { SingleModeGraphTooltip } from './SingleModeGraphTooltip';
|
import { SingleModeGraphTooltip } from './SingleModeGraphTooltip';
|
||||||
import { MultiModeGraphTooltip } from './MultiModeGraphTooltip';
|
import { MultiModeGraphTooltip } from './MultiModeGraphTooltip';
|
||||||
import { GraphDimensions } from './types';
|
import { GraphDimensions } from './types';
|
||||||
|
|
||||||
export const GraphTooltip: React.FC<TooltipContentProps<GraphDimensions>> = ({
|
export const GraphTooltip: React.FC<VizTooltipContentProps<GraphDimensions>> = ({
|
||||||
mode = 'single',
|
mode = 'single',
|
||||||
dimensions,
|
dimensions,
|
||||||
activeDimensions,
|
activeDimensions,
|
||||||
|
@ -3,7 +3,7 @@ import { mount } from 'enzyme';
|
|||||||
import { MultiModeGraphTooltip } from './MultiModeGraphTooltip';
|
import { MultiModeGraphTooltip } from './MultiModeGraphTooltip';
|
||||||
import { createDimension, ArrayVector, FieldType } from '@grafana/data';
|
import { createDimension, ArrayVector, FieldType } from '@grafana/data';
|
||||||
import { GraphDimensions } from './types';
|
import { GraphDimensions } from './types';
|
||||||
import { ActiveDimensions } from '../../Chart/Tooltip';
|
import { ActiveDimensions } from '../../VizTooltip';
|
||||||
|
|
||||||
let dimensions: GraphDimensions;
|
let dimensions: GraphDimensions;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SeriesTable } from './SeriesTable';
|
import { SeriesTable } from '../../VizTooltip';
|
||||||
import { GraphTooltipContentProps } from './types';
|
import { GraphTooltipContentProps } from './types';
|
||||||
import { getMultiSeriesGraphHoverInfo } from '../utils';
|
import { getMultiSeriesGraphHoverInfo } from '../utils';
|
||||||
import { FlotPosition } from '../types';
|
import { FlotPosition } from '../types';
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
getDisplayProcessor,
|
getDisplayProcessor,
|
||||||
getFieldDisplayName,
|
getFieldDisplayName,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { SeriesTable } from './SeriesTable';
|
import { SeriesTable } from '../../VizTooltip';
|
||||||
import { GraphTooltipContentProps } from './types';
|
import { GraphTooltipContentProps } from './types';
|
||||||
|
|
||||||
export const SingleModeGraphTooltip: React.FC<GraphTooltipContentProps> = ({
|
export const SingleModeGraphTooltip: React.FC<GraphTooltipContentProps> = ({
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package grafanaschema
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Relative imports are flatly disallowed by CUE, but that's what's
|
|
||||||
// currently done in the corresponding typescript code. We'll have to make
|
|
||||||
// cuetsy handle this with import mappings.
|
|
||||||
import tooltip "github.com/grafana/grafana/packages/grafana-ui/src/components/Chart:grafanaschema"
|
|
||||||
|
|
||||||
GraphTooltipOptions: {
|
|
||||||
mode: tooltip.TooltipMode
|
|
||||||
} @cuetsy(targetType="interface")
|
|
@ -1,10 +1,5 @@
|
|||||||
import { ActiveDimensions } from '../../Chart/Tooltip';
|
import { ActiveDimensions } from '../../VizTooltip';
|
||||||
import { Dimension, Dimensions, TimeZone } from '@grafana/data';
|
import { Dimension, Dimensions, TimeZone } from '@grafana/data';
|
||||||
import { TooltipMode } from '../../Chart/models.gen';
|
|
||||||
|
|
||||||
export interface GraphTooltipOptions {
|
|
||||||
mode: TooltipMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GraphDimensions extends Dimensions {
|
export interface GraphDimensions extends Dimensions {
|
||||||
xAxis: Dimension<number>;
|
xAxis: Dimension<number>;
|
||||||
|
@ -2,11 +2,11 @@ import React from 'react';
|
|||||||
|
|
||||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
import { InfoTooltip } from './InfoTooltip';
|
import { InfoTooltip } from './InfoTooltip';
|
||||||
import { Tooltip } from '../Chart/Tooltip';
|
import { VizTooltip } from '../VizTooltip';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Overlays/TooltipInternal',
|
title: 'Overlays/TooltipInternal',
|
||||||
component: Tooltip,
|
component: VizTooltip,
|
||||||
decorators: [withCenteredStory],
|
decorators: [withCenteredStory],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { select, number, boolean } from '@storybook/addon-knobs';
|
import { select, number, boolean } from '@storybook/addon-knobs';
|
||||||
import { PieChart, PieChartType } from '@grafana/ui';
|
import { PieChart, PieChartType, TooltipDisplayMode } from '@grafana/ui';
|
||||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
import {
|
import {
|
||||||
FieldColorModeId,
|
FieldColorModeId,
|
||||||
@ -52,15 +52,16 @@ const getKnobs = () => {
|
|||||||
return {
|
return {
|
||||||
width: number('Width', 500),
|
width: number('Width', 500),
|
||||||
height: number('Height', 500),
|
height: number('Height', 500),
|
||||||
pieType: select('pieType', [PieChartType.Pie, PieChartType.Donut], PieChartType.Pie),
|
pieType: select('pieType', Object.values(PieChartType), PieChartType.Pie),
|
||||||
showLabelName: boolean('Label.showName', true),
|
showLabelName: boolean('Label.showName', true),
|
||||||
showLabelValue: boolean('Label.showValue', false),
|
showLabelValue: boolean('Label.showValue', false),
|
||||||
showLabelPercent: boolean('Label.showPercent', false),
|
showLabelPercent: boolean('Label.showPercent', false),
|
||||||
|
tooltipMode: select('Tooltip mode', Object.values(TooltipDisplayMode), TooltipDisplayMode.Single),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const basic = () => {
|
export const basic = () => {
|
||||||
const { pieType, width, height } = getKnobs();
|
const { pieType, width, height, tooltipMode } = getKnobs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PieChart
|
<PieChart
|
||||||
@ -71,12 +72,13 @@ export const basic = () => {
|
|||||||
fieldConfig={fieldConfig}
|
fieldConfig={fieldConfig}
|
||||||
data={datapoints}
|
data={datapoints}
|
||||||
pieType={pieType}
|
pieType={pieType}
|
||||||
|
tooltipOptions={{ mode: tooltipMode }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const donut = () => {
|
export const donut = () => {
|
||||||
const { width, height } = getKnobs();
|
const { width, height, tooltipMode } = getKnobs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PieChart
|
<PieChart
|
||||||
@ -87,6 +89,7 @@ export const donut = () => {
|
|||||||
fieldConfig={fieldConfig}
|
fieldConfig={fieldConfig}
|
||||||
data={datapoints}
|
data={datapoints}
|
||||||
pieType={PieChartType.Donut}
|
pieType={PieChartType.Donut}
|
||||||
|
tooltipOptions={{ mode: tooltipMode }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { FC, ReactNode } from 'react';
|
import React, { FC, ReactNode } from 'react';
|
||||||
import {
|
import {
|
||||||
DisplayValue,
|
|
||||||
FALLBACK_COLOR,
|
FALLBACK_COLOR,
|
||||||
FieldDisplay,
|
FieldDisplay,
|
||||||
formattedValueToString,
|
formattedValueToString,
|
||||||
@ -29,6 +28,8 @@ import {
|
|||||||
PieChartSvgProps,
|
PieChartSvgProps,
|
||||||
PieChartType,
|
PieChartType,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import { getTooltipContainerStyles } from '../../themes/mixins';
|
||||||
|
import { SeriesTable, SeriesTableRowProps, VizTooltipOptions } from '../VizTooltip';
|
||||||
|
|
||||||
const defaultLegendOptions: PieChartLegendOptions = {
|
const defaultLegendOptions: PieChartLegendOptions = {
|
||||||
displayMode: LegendDisplayMode.List,
|
displayMode: LegendDisplayMode.List,
|
||||||
@ -44,6 +45,7 @@ export const PieChart: FC<PieChartProps> = ({
|
|||||||
fieldConfig,
|
fieldConfig,
|
||||||
replaceVariables,
|
replaceVariables,
|
||||||
legendOptions = defaultLegendOptions,
|
legendOptions = defaultLegendOptions,
|
||||||
|
tooltipOptions,
|
||||||
onSeriesColorChange,
|
onSeriesColorChange,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@ -112,7 +114,13 @@ export const PieChart: FC<PieChartProps> = ({
|
|||||||
<VizLayout width={width} height={height} legend={getLegend(fieldDisplayValues, legendOptions)}>
|
<VizLayout width={width} height={height} legend={getLegend(fieldDisplayValues, legendOptions)}>
|
||||||
{(vizWidth: number, vizHeight: number) => {
|
{(vizWidth: number, vizHeight: number) => {
|
||||||
return (
|
return (
|
||||||
<PieChartSvg width={vizWidth} height={vizHeight} fieldDisplayValues={fieldDisplayValues} {...restProps} />
|
<PieChartSvg
|
||||||
|
width={vizWidth}
|
||||||
|
height={vizHeight}
|
||||||
|
fieldDisplayValues={fieldDisplayValues}
|
||||||
|
tooltipOptions={tooltipOptions}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</VizLayout>
|
</VizLayout>
|
||||||
@ -126,11 +134,12 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
height,
|
height,
|
||||||
useGradients = true,
|
useGradients = true,
|
||||||
displayLabels = [],
|
displayLabels = [],
|
||||||
|
tooltipOptions,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const componentInstanceId = useComponentInstanceId('PieChart');
|
const componentInstanceId = useComponentInstanceId('PieChart');
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles(getStyles);
|
||||||
const tooltip = useTooltip<DisplayValue>();
|
const tooltip = useTooltip<SeriesTableRowProps[]>();
|
||||||
const { containerRef, TooltipInPortal } = useTooltipInPortal({
|
const { containerRef, TooltipInPortal } = useTooltipInPortal({
|
||||||
detectBounds: true,
|
detectBounds: true,
|
||||||
scroll: true,
|
scroll: true,
|
||||||
@ -147,6 +156,7 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const showLabel = displayLabels.length > 0;
|
const showLabel = displayLabels.length > 0;
|
||||||
|
const showTooltip = tooltipOptions.mode !== 'none' && tooltip.tooltipOpen;
|
||||||
const total = fieldDisplayValues.reduce((acc, item) => item.display.numeric + acc, 0);
|
const total = fieldDisplayValues.reduce((acc, item) => item.display.numeric + acc, 0);
|
||||||
const layout = getPieLayout(width, height, pieType);
|
const layout = getPieLayout(width, height, pieType);
|
||||||
const colors = [
|
const colors = [
|
||||||
@ -204,6 +214,7 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
pie={pie}
|
pie={pie}
|
||||||
fill={getGradientColor(color)}
|
fill={getGradientColor(color)}
|
||||||
openMenu={api.openMenu}
|
openMenu={api.openMenu}
|
||||||
|
tooltipOptions={tooltipOptions}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</PieSlice>
|
</PieSlice>
|
||||||
@ -212,7 +223,14 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<PieSlice key={arc.index} tooltip={tooltip} arc={arc} pie={pie} fill={getGradientColor(color)}>
|
<PieSlice
|
||||||
|
key={arc.index}
|
||||||
|
tooltip={tooltip}
|
||||||
|
arc={arc}
|
||||||
|
pie={pie}
|
||||||
|
fill={getGradientColor(color)}
|
||||||
|
tooltipOptions={tooltipOptions}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</PieSlice>
|
</PieSlice>
|
||||||
);
|
);
|
||||||
@ -222,16 +240,18 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
</Pie>
|
</Pie>
|
||||||
</Group>
|
</Group>
|
||||||
</svg>
|
</svg>
|
||||||
{tooltip.tooltipOpen && (
|
{showTooltip ? (
|
||||||
<TooltipInPortal
|
<TooltipInPortal
|
||||||
key={Math.random()}
|
key={Math.random()}
|
||||||
top={tooltip.tooltipTop}
|
top={tooltip.tooltipTop}
|
||||||
className={styles.tooltipPortal}
|
className={styles.tooltipPortal}
|
||||||
left={tooltip.tooltipLeft}
|
left={tooltip.tooltipLeft}
|
||||||
|
unstyled={true}
|
||||||
|
applyPositionStyle={true}
|
||||||
>
|
>
|
||||||
{tooltip.tooltipData!.title} {formattedValueToString(tooltip.tooltipData!)}
|
<SeriesTable series={tooltip.tooltipData!} />
|
||||||
</TooltipInPortal>
|
</TooltipInPortal>
|
||||||
)}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -241,18 +261,19 @@ const PieSlice: FC<{
|
|||||||
arc: PieArcDatum<FieldDisplay>;
|
arc: PieArcDatum<FieldDisplay>;
|
||||||
pie: ProvidedProps<FieldDisplay>;
|
pie: ProvidedProps<FieldDisplay>;
|
||||||
fill: string;
|
fill: string;
|
||||||
tooltip: UseTooltipParams<DisplayValue>;
|
tooltip: UseTooltipParams<SeriesTableRowProps[]>;
|
||||||
|
tooltipOptions: VizTooltipOptions;
|
||||||
openMenu?: (event: React.MouseEvent<SVGElement>) => void;
|
openMenu?: (event: React.MouseEvent<SVGElement>) => void;
|
||||||
}> = ({ arc, children, pie, openMenu, fill, tooltip }) => {
|
}> = ({ arc, children, pie, openMenu, fill, tooltip, tooltipOptions }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles(getStyles);
|
||||||
|
|
||||||
const onMouseMoveOverArc = (event: any, datum: any) => {
|
const onMouseMoveOverArc = (event: any) => {
|
||||||
const coords = localPoint(event.target.ownerSVGElement, event);
|
const coords = localPoint(event.target.ownerSVGElement, event);
|
||||||
tooltip.showTooltip({
|
tooltip.showTooltip({
|
||||||
tooltipLeft: coords!.x,
|
tooltipLeft: coords!.x,
|
||||||
tooltipTop: coords!.y,
|
tooltipTop: coords!.y,
|
||||||
tooltipData: datum,
|
tooltipData: getTooltipData(pie, arc, tooltipOptions),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,7 +281,7 @@ const PieSlice: FC<{
|
|||||||
<g
|
<g
|
||||||
key={arc.data.display.title}
|
key={arc.data.display.title}
|
||||||
className={styles.svgArg}
|
className={styles.svgArg}
|
||||||
onMouseMove={(event) => onMouseMoveOverArc(event, arc.data.display)}
|
onMouseMove={tooltipOptions.mode !== 'none' ? onMouseMoveOverArc : undefined}
|
||||||
onMouseOut={tooltip.hideTooltip}
|
onMouseOut={tooltip.hideTooltip}
|
||||||
onClick={openMenu}
|
onClick={openMenu}
|
||||||
>
|
>
|
||||||
@ -321,6 +342,30 @@ const PieLabel: FC<{
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getTooltipData(
|
||||||
|
pie: ProvidedProps<FieldDisplay>,
|
||||||
|
arc: PieArcDatum<FieldDisplay>,
|
||||||
|
tooltipOptions: VizTooltipOptions
|
||||||
|
) {
|
||||||
|
if (tooltipOptions.mode === 'multi') {
|
||||||
|
return pie.arcs.map((pieArc) => {
|
||||||
|
return {
|
||||||
|
color: pieArc.data.display.color ?? FALLBACK_COLOR,
|
||||||
|
label: pieArc.data.display.title,
|
||||||
|
value: formattedValueToString(pieArc.data.display),
|
||||||
|
isActive: pieArc.index === arc.index,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
color: arc.data.display.color ?? FALLBACK_COLOR,
|
||||||
|
label: arc.data.display.title,
|
||||||
|
value: formattedValueToString(arc.data.display),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function getLabelPos(arc: PieArcDatum<FieldDisplay>, outerRadius: number, innerRadius: number) {
|
function getLabelPos(arc: PieArcDatum<FieldDisplay>, outerRadius: number, innerRadius: number) {
|
||||||
const r = (outerRadius + innerRadius) / 2;
|
const r = (outerRadius + innerRadius) / 2;
|
||||||
const a = (+arc.startAngle + +arc.endAngle) / 2 - Math.PI / 2;
|
const a = (+arc.startAngle + +arc.endAngle) / 2 - Math.PI / 2;
|
||||||
@ -382,7 +427,7 @@ const getStyles = (theme: GrafanaTheme) => {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
tooltipPortal: css`
|
tooltipPortal: css`
|
||||||
z-index: 1050;
|
${getTooltipContainerStyles(theme)}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { DataFrame, FieldConfigSource, FieldDisplay, InterpolateFunction, ReduceDataOptions } from '@grafana/data';
|
import { DataFrame, FieldConfigSource, FieldDisplay, InterpolateFunction, ReduceDataOptions } from '@grafana/data';
|
||||||
|
import { VizTooltipOptions } from '../VizTooltip';
|
||||||
import { VizLegendOptions } from '..';
|
import { VizLegendOptions } from '..';
|
||||||
|
|
||||||
export interface PieChartSvgProps {
|
export interface PieChartSvgProps {
|
||||||
@ -9,10 +10,12 @@ export interface PieChartSvgProps {
|
|||||||
displayLabels?: PieChartLabels[];
|
displayLabels?: PieChartLabels[];
|
||||||
useGradients?: boolean;
|
useGradients?: boolean;
|
||||||
onSeriesColorChange?: (label: string, color: string) => void;
|
onSeriesColorChange?: (label: string, color: string) => void;
|
||||||
|
tooltipOptions: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PieChartProps extends Omit<PieChartSvgProps, 'fieldDisplayValues'> {
|
export interface PieChartProps extends Omit<PieChartSvgProps, 'fieldDisplayValues'> {
|
||||||
legendOptions?: PieChartLegendOptions;
|
legendOptions?: PieChartLegendOptions;
|
||||||
|
tooltipOptions: VizTooltipOptions;
|
||||||
reduceOptions: ReduceDataOptions;
|
reduceOptions: ReduceDataOptions;
|
||||||
fieldConfig: FieldConfigSource<any>;
|
fieldConfig: FieldConfigSource<any>;
|
||||||
replaceVariables: InterpolateFunction;
|
replaceVariables: InterpolateFunction;
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Story, Meta } from '@storybook/react';
|
||||||
|
import { SeriesTable, SeriesTableProps } from './SeriesTable';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'VizTooltip/SeriesTable',
|
||||||
|
component: SeriesTable,
|
||||||
|
argTypes: {
|
||||||
|
timestamp: {
|
||||||
|
control: 'date',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<SeriesTableProps> = (args) => {
|
||||||
|
const date = new Date(args.timestamp!).toLocaleString();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SeriesTable {...args} timestamp={date} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const basic = Template.bind({});
|
||||||
|
|
||||||
|
basic.args = {
|
||||||
|
timestamp: new Date('2021-01-01T00:00:00').toISOString(),
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
color: '#299c46',
|
||||||
|
label: 'label 1',
|
||||||
|
value: '100 W',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const multi = Template.bind({});
|
||||||
|
|
||||||
|
multi.args = {
|
||||||
|
timestamp: new Date('2021-01-01T00:00:00').toISOString(),
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
color: '#299c46',
|
||||||
|
label: 'label 1',
|
||||||
|
value: '100 W',
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#9933cc',
|
||||||
|
label: 'label yes',
|
||||||
|
value: '25 W',
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#eb7b18',
|
||||||
|
label: 'label 3',
|
||||||
|
value: '150 W',
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -1,10 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { stylesFactory } from '../../../themes/stylesFactory';
|
|
||||||
import { GrafanaTheme, GraphSeriesValue } from '@grafana/data';
|
import { GrafanaTheme, GraphSeriesValue } from '@grafana/data';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { SeriesIcon } from '../../VizLegend/SeriesIcon';
|
import { SeriesIcon } from '../VizLegend/SeriesIcon';
|
||||||
import { useTheme } from '../../../themes';
|
import { useStyles } from '../../themes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
export interface SeriesTableRowProps {
|
export interface SeriesTableRowProps {
|
||||||
color?: string;
|
color?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
@ -12,10 +14,11 @@ export interface SeriesTableRowProps {
|
|||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSeriesTableRowStyles = stylesFactory((theme: GrafanaTheme) => {
|
const getSeriesTableRowStyles = (theme: GrafanaTheme) => {
|
||||||
return {
|
return {
|
||||||
icon: css`
|
icon: css`
|
||||||
margin-right: ${theme.spacing.xs};
|
margin-right: ${theme.spacing.xs};
|
||||||
|
vertical-align: middle;
|
||||||
`,
|
`,
|
||||||
seriesTable: css`
|
seriesTable: css`
|
||||||
display: table;
|
display: table;
|
||||||
@ -41,11 +44,11 @@ const getSeriesTableRowStyles = stylesFactory((theme: GrafanaTheme) => {
|
|||||||
font-size: ${theme.typography.size.sm};
|
font-size: ${theme.typography.size.sm};
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
});
|
};
|
||||||
|
|
||||||
const SeriesTableRow: React.FC<SeriesTableRowProps> = ({ color, label, value, isActive }) => {
|
const SeriesTableRow: React.FC<SeriesTableRowProps> = ({ color, label, value, isActive }) => {
|
||||||
const theme = useTheme();
|
const styles = useStyles(getSeriesTableRowStyles);
|
||||||
const styles = getSeriesTableRowStyles(theme);
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.seriesTableRow, isActive && styles.activeSeries)}>
|
<div className={cx(styles.seriesTableRow, isActive && styles.activeSeries)}>
|
||||||
{color && (
|
{color && (
|
||||||
@ -59,14 +62,19 @@ const SeriesTableRow: React.FC<SeriesTableRowProps> = ({ color, label, value, is
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface SeriesTableProps {
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface SeriesTableProps {
|
||||||
timestamp?: string | GraphSeriesValue;
|
timestamp?: string | GraphSeriesValue;
|
||||||
series: SeriesTableRowProps[];
|
series: SeriesTableRowProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
export const SeriesTable: React.FC<SeriesTableProps> = ({ timestamp, series }) => {
|
export const SeriesTable: React.FC<SeriesTableProps> = ({ timestamp, series }) => {
|
||||||
const theme = useTheme();
|
const styles = useStyles(getSeriesTableRowStyles);
|
||||||
const styles = getSeriesTableRowStyles(theme);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
@ -3,9 +3,9 @@ import { css } from '@emotion/css';
|
|||||||
import { Portal } from '../Portal/Portal';
|
import { Portal } from '../Portal/Portal';
|
||||||
import { Dimensions, TimeZone } from '@grafana/data';
|
import { Dimensions, TimeZone } from '@grafana/data';
|
||||||
import { FlotPosition } from '../Graph/types';
|
import { FlotPosition } from '../Graph/types';
|
||||||
import { TooltipContainer } from './TooltipContainer';
|
import { VizTooltipContainer } from './VizTooltipContainer';
|
||||||
import { useStyles } from '../../themes';
|
import { useStyles } from '../../themes';
|
||||||
import { TooltipMode } from './models.gen';
|
import { TooltipDisplayMode } from './models.gen';
|
||||||
|
|
||||||
// Describes active dimensions user interacts with
|
// Describes active dimensions user interacts with
|
||||||
// It's a key-value pair where:
|
// It's a key-value pair where:
|
||||||
@ -14,7 +14,7 @@ import { TooltipMode } from './models.gen';
|
|||||||
// If row is undefined, it means that we are not hovering over a datapoint
|
// If row is undefined, it means that we are not hovering over a datapoint
|
||||||
export type ActiveDimensions<T extends Dimensions = any> = { [key in keyof T]: [number, number | undefined] | null };
|
export type ActiveDimensions<T extends Dimensions = any> = { [key in keyof T]: [number, number | undefined] | null };
|
||||||
|
|
||||||
export interface TooltipContentProps<T extends Dimensions = any> {
|
export interface VizTooltipContentProps<T extends Dimensions = any> {
|
||||||
// Each dimension is described by array of fields representing it
|
// Each dimension is described by array of fields representing it
|
||||||
// I.e. for graph there are two dimensions: x and y axis:
|
// I.e. for graph there are two dimensions: x and y axis:
|
||||||
// { xAxis: [<array of time fields>], yAxis: [<array of value fields>]}
|
// { xAxis: [<array of time fields>], yAxis: [<array of value fields>]}
|
||||||
@ -23,15 +23,15 @@ export interface TooltipContentProps<T extends Dimensions = any> {
|
|||||||
activeDimensions?: ActiveDimensions<T>;
|
activeDimensions?: ActiveDimensions<T>;
|
||||||
timeZone?: TimeZone;
|
timeZone?: TimeZone;
|
||||||
pos: FlotPosition;
|
pos: FlotPosition;
|
||||||
mode: TooltipMode;
|
mode: TooltipDisplayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TooltipProps {
|
export interface VizTooltipProps {
|
||||||
/** Element used as tooltips content */
|
/** Element used as tooltips content */
|
||||||
content?: React.ReactElement<any>;
|
content?: React.ReactElement<any>;
|
||||||
|
|
||||||
/** Optional component to be used as a tooltip content */
|
/** Optional component to be used as a tooltip content */
|
||||||
tooltipComponent?: React.ComponentType<TooltipContentProps>;
|
tooltipComponent?: React.ComponentType<VizTooltipContentProps>;
|
||||||
|
|
||||||
/** x/y position relative to the window */
|
/** x/y position relative to the window */
|
||||||
position?: { x: number; y: number };
|
position?: { x: number; y: number };
|
||||||
@ -42,24 +42,27 @@ export interface TooltipProps {
|
|||||||
// Mode in which tooltip works
|
// Mode in which tooltip works
|
||||||
// - single - display single series info
|
// - single - display single series info
|
||||||
// - multi - display all series info
|
// - multi - display all series info
|
||||||
mode?: TooltipMode;
|
mode?: TooltipDisplayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Tooltip: React.FC<TooltipProps> = ({ content, position, offset }) => {
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const VizTooltip: React.FC<VizTooltipProps> = ({ content, position, offset }) => {
|
||||||
const styles = useStyles(getStyles);
|
const styles = useStyles(getStyles);
|
||||||
if (position) {
|
if (position) {
|
||||||
return (
|
return (
|
||||||
<Portal className={styles.portal}>
|
<Portal className={styles.portal}>
|
||||||
<TooltipContainer position={position} offset={offset || { x: 0, y: 0 }}>
|
<VizTooltipContainer position={position} offset={offset || { x: 0, y: 0 }}>
|
||||||
{content}
|
{content}
|
||||||
</TooltipContainer>
|
</VizTooltipContainer>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
Tooltip.displayName = 'ChartTooltip';
|
VizTooltip.displayName = 'VizTooltip';
|
||||||
|
|
||||||
const getStyles = () => {
|
const getStyles = () => {
|
||||||
return {
|
return {
|
@ -1,24 +1,29 @@
|
|||||||
import React, { useState, useLayoutEffect, useRef, HTMLAttributes, useMemo } from 'react';
|
import React, { useState, useLayoutEffect, useRef, HTMLAttributes, useMemo } from 'react';
|
||||||
import { stylesFactory } from '../../themes/stylesFactory';
|
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { useTheme } from '../../themes/ThemeContext';
|
import { useStyles } from '../../themes';
|
||||||
|
import { getTooltipContainerStyles } from '../../themes/mixins';
|
||||||
import useWindowSize from 'react-use/lib/useWindowSize';
|
import useWindowSize from 'react-use/lib/useWindowSize';
|
||||||
import { Dimensions2D, GrafanaTheme } from '@grafana/data';
|
import { Dimensions2D, GrafanaTheme } from '@grafana/data';
|
||||||
|
|
||||||
interface TooltipContainerProps extends HTMLAttributes<HTMLDivElement> {
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface VizTooltipContainerProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
position: { x: number; y: number };
|
position: { x: number; y: number };
|
||||||
offset: { x: number; y: number };
|
offset: { x: number; y: number };
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TooltipContainer: React.FC<TooltipContainerProps> = ({
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const VizTooltipContainer: React.FC<VizTooltipContainerProps> = ({
|
||||||
position: { x: positionX, y: positionY },
|
position: { x: positionX, y: positionY },
|
||||||
offset: { x: offsetX, y: offsetY },
|
offset: { x: offsetX, y: offsetY },
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
...otherProps
|
...otherProps
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
|
||||||
const tooltipRef = useRef<HTMLDivElement>(null);
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
||||||
const tooltipMeasurementRef = useRef<Dimensions2D>({ width: 0, height: 0 });
|
const tooltipMeasurementRef = useRef<Dimensions2D>({ width: 0, height: 0 });
|
||||||
const { width, height } = useWindowSize();
|
const { width, height } = useWindowSize();
|
||||||
@ -80,7 +85,7 @@ export const TooltipContainer: React.FC<TooltipContainerProps> = ({
|
|||||||
});
|
});
|
||||||
}, [width, height, positionX, offsetX, positionY, offsetY]);
|
}, [width, height, positionX, offsetX, positionY, offsetY]);
|
||||||
|
|
||||||
const styles = getTooltipContainerStyles(theme);
|
const styles = useStyles(getStyles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -99,18 +104,10 @@ export const TooltipContainer: React.FC<TooltipContainerProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
TooltipContainer.displayName = 'TooltipContainer';
|
VizTooltipContainer.displayName = 'VizTooltipContainer';
|
||||||
|
|
||||||
const getTooltipContainerStyles = stylesFactory((theme: GrafanaTheme) => {
|
const getStyles = (theme: GrafanaTheme) => ({
|
||||||
return {
|
wrapper: css`
|
||||||
wrapper: css`
|
${getTooltipContainerStyles(theme)}
|
||||||
overflow: hidden;
|
`,
|
||||||
background: ${theme.colors.bg2};
|
|
||||||
/* max-width is set up based on .grafana-tooltip class that's used in dashboard */
|
|
||||||
max-width: 800px;
|
|
||||||
padding: ${theme.spacing.sm};
|
|
||||||
border-radius: ${theme.border.radius.sm};
|
|
||||||
z-index: ${theme.zIndex.tooltip};
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
});
|
});
|
4
packages/grafana-ui/src/components/VizTooltip/index.tsx
Normal file
4
packages/grafana-ui/src/components/VizTooltip/index.tsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export { VizTooltip, VizTooltipContentProps, VizTooltipProps, ActiveDimensions } from './VizTooltip';
|
||||||
|
export { VizTooltipContainer, VizTooltipContainerProps } from './VizTooltipContainer';
|
||||||
|
export { SeriesTable, SeriesTableProps, SeriesTableRowProps } from './SeriesTable';
|
||||||
|
export { TooltipDisplayMode, VizTooltipOptions } from './models.gen';
|
7
packages/grafana-ui/src/components/VizTooltip/models.cue
Normal file
7
packages/grafana-ui/src/components/VizTooltip/models.cue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package grafanaschema
|
||||||
|
|
||||||
|
TooltipDisplayMode: "single" | "multi" | "none" @cuetsy(targetType="enum")
|
||||||
|
|
||||||
|
VizTooltipOptions: {
|
||||||
|
mode: TooltipDisplayMode
|
||||||
|
} @cuetsy(targetType="interface")
|
@ -3,8 +3,18 @@
|
|||||||
// It is currenty hand written but will serve as the target for cuetsy
|
// It is currenty hand written but will serve as the target for cuetsy
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
import { TooltipMode } from '../../Chart/models.gen';
|
/**
|
||||||
|
* @public
|
||||||
export interface GraphTooltipOptions {
|
*/
|
||||||
mode: TooltipMode;
|
export enum TooltipDisplayMode {
|
||||||
|
Single = 'single',
|
||||||
|
Multi = 'multi',
|
||||||
|
None = 'none',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export type VizTooltipOptions = {
|
||||||
|
mode: TooltipDisplayMode;
|
||||||
|
};
|
@ -74,7 +74,15 @@ export { Graph } from './Graph/Graph';
|
|||||||
export { GraphWithLegend } from './Graph/GraphWithLegend';
|
export { GraphWithLegend } from './Graph/GraphWithLegend';
|
||||||
export { GraphContextMenu, GraphContextMenuHeader } from './Graph/GraphContextMenu';
|
export { GraphContextMenu, GraphContextMenuHeader } from './Graph/GraphContextMenu';
|
||||||
export { BarGauge, BarGaugeDisplayMode } from './BarGauge/BarGauge';
|
export { BarGauge, BarGaugeDisplayMode } from './BarGauge/BarGauge';
|
||||||
export { GraphTooltipOptions } from './Graph/GraphTooltip/types';
|
export {
|
||||||
|
VizTooltip,
|
||||||
|
VizTooltipContainer,
|
||||||
|
SeriesTable,
|
||||||
|
VizTooltipOptions,
|
||||||
|
TooltipDisplayMode,
|
||||||
|
SeriesTableProps,
|
||||||
|
SeriesTableRowProps,
|
||||||
|
} from './VizTooltip';
|
||||||
export { VizRepeater, VizRepeaterRenderValueProps } from './VizRepeater/VizRepeater';
|
export { VizRepeater, VizRepeaterRenderValueProps } from './VizRepeater/VizRepeater';
|
||||||
export { graphTimeFormat, graphTickFormatter } from './Graph/utils';
|
export { graphTimeFormat, graphTickFormatter } from './Graph/utils';
|
||||||
export {
|
export {
|
||||||
@ -132,8 +140,6 @@ export { Spinner } from './Spinner/Spinner';
|
|||||||
export { FadeTransition } from './transitions/FadeTransition';
|
export { FadeTransition } from './transitions/FadeTransition';
|
||||||
export { SlideOutTransition } from './transitions/SlideOutTransition';
|
export { SlideOutTransition } from './transitions/SlideOutTransition';
|
||||||
export { Segment, SegmentAsync, SegmentInput, SegmentSelect } from './Segment/';
|
export { Segment, SegmentAsync, SegmentInput, SegmentSelect } from './Segment/';
|
||||||
export { default as Chart } from './Chart';
|
|
||||||
export { TooltipContainer } from './Chart/TooltipContainer';
|
|
||||||
export { Drawer } from './Drawer/Drawer';
|
export { Drawer } from './Drawer/Drawer';
|
||||||
export { Slider } from './Slider/Slider';
|
export { Slider } from './Slider/Slider';
|
||||||
export { RangeSlider } from './Slider/RangeSlider';
|
export { RangeSlider } from './Slider/RangeSlider';
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { Portal } from '../../Portal/Portal';
|
import { Portal } from '../../Portal/Portal';
|
||||||
import { usePlotContext } from '../context';
|
import { usePlotContext } from '../context';
|
||||||
import { CursorPlugin } from './CursorPlugin';
|
import { CursorPlugin } from './CursorPlugin';
|
||||||
import { SeriesTable, SeriesTableRowProps } from '../../Graph/GraphTooltip/SeriesTable';
|
import { VizTooltipContainer, SeriesTable, SeriesTableRowProps, TooltipDisplayMode } from '../../VizTooltip';
|
||||||
import {
|
import {
|
||||||
DataFrame,
|
DataFrame,
|
||||||
FieldType,
|
FieldType,
|
||||||
@ -11,12 +11,10 @@ import {
|
|||||||
getFieldDisplayName,
|
getFieldDisplayName,
|
||||||
TimeZone,
|
TimeZone,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { TooltipContainer } from '../../Chart/TooltipContainer';
|
|
||||||
import { TooltipMode } from '../../Chart/models.gen';
|
|
||||||
import { useGraphNGContext } from '../../GraphNG/hooks';
|
import { useGraphNGContext } from '../../GraphNG/hooks';
|
||||||
|
|
||||||
interface TooltipPluginProps {
|
interface TooltipPluginProps {
|
||||||
mode?: TooltipMode;
|
mode?: TooltipDisplayMode;
|
||||||
timeZone: TimeZone;
|
timeZone: TimeZone;
|
||||||
data: DataFrame[];
|
data: DataFrame[];
|
||||||
}
|
}
|
||||||
@ -121,9 +119,9 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<TooltipContainer position={{ x: coords.viewport.x, y: coords.viewport.y }} offset={{ x: 10, y: 10 }}>
|
<VizTooltipContainer position={{ x: coords.viewport.x, y: coords.viewport.y }} offset={{ x: 10, y: 10 }}>
|
||||||
{tooltip}
|
{tooltip}
|
||||||
</TooltipContainer>
|
</VizTooltipContainer>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -4,13 +4,13 @@ import tinycolor from 'tinycolor2';
|
|||||||
|
|
||||||
export function cardChrome(theme: GrafanaTheme): string {
|
export function cardChrome(theme: GrafanaTheme): string {
|
||||||
return `
|
return `
|
||||||
background: ${theme.colors.bg2};
|
background: ${theme.colors.bg2};
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${hoverColor(theme.colors.bg2, theme)};
|
background: ${hoverColor(theme.colors.bg2, theme)};
|
||||||
}
|
}
|
||||||
box-shadow: ${theme.shadows.listItem};
|
box-shadow: ${theme.shadows.listItem};
|
||||||
border-radius: ${theme.border.radius.md};
|
border-radius: ${theme.border.radius.md};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hoverColor(color: string, theme: GrafanaTheme): string {
|
export function hoverColor(color: string, theme: GrafanaTheme): string {
|
||||||
@ -30,9 +30,9 @@ export function listItem(theme: GrafanaTheme): string {
|
|||||||
|
|
||||||
export function listItemSelected(theme: GrafanaTheme): string {
|
export function listItemSelected(theme: GrafanaTheme): string {
|
||||||
return `
|
return `
|
||||||
background: ${hoverColor(theme.colors.bg2, theme)};
|
background: ${hoverColor(theme.colors.bg2, theme)};
|
||||||
color: ${theme.colors.textStrong};
|
color: ${theme.colors.textStrong};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mediaUp(breakpoint: string) {
|
export function mediaUp(breakpoint: string) {
|
||||||
@ -61,3 +61,13 @@ export function getFocusStyles(theme: GrafanaThemeV2): CSSObject {
|
|||||||
transition: `all 0.2s cubic-bezier(0.19, 1, 0.22, 1)`,
|
transition: `all 0.2s cubic-bezier(0.19, 1, 0.22, 1)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// max-width is set up based on .grafana-tooltip class that's used in dashboard
|
||||||
|
export const getTooltipContainerStyles = (theme: GrafanaTheme) => `
|
||||||
|
overflow: hidden;
|
||||||
|
background: ${theme.colors.bg2};
|
||||||
|
max-width: 800px;
|
||||||
|
padding: ${theme.spacing.sm};
|
||||||
|
border-radius: ${theme.border.radius.sm};
|
||||||
|
z-index: ${theme.zIndex.tooltip};
|
||||||
|
`;
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
useStyles,
|
useStyles,
|
||||||
useTheme,
|
useTheme,
|
||||||
ZoomPlugin,
|
ZoomPlugin,
|
||||||
|
TooltipDisplayMode,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
||||||
import { hideSeriesConfigFactory } from 'app/plugins/panel/timeseries/overrides/hideSeriesConfigFactory';
|
import { hideSeriesConfigFactory } from 'app/plugins/panel/timeseries/overrides/hideSeriesConfigFactory';
|
||||||
@ -129,7 +130,7 @@ export function ExploreGraphNGPanel({
|
|||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
>
|
>
|
||||||
<ZoomPlugin onZoom={onUpdateTimeRange} />
|
<ZoomPlugin onZoom={onUpdateTimeRange} />
|
||||||
<TooltipPlugin data={data} mode="single" timeZone={timeZone} />
|
<TooltipPlugin data={data} mode={TooltipDisplayMode.Single} timeZone={timeZone} />
|
||||||
<ContextMenuPlugin data={data} timeZone={timeZone} />
|
<ContextMenuPlugin data={data} timeZone={timeZone} />
|
||||||
{annotations && <ExemplarsPlugin exemplars={annotations} timeZone={timeZone} getFieldLinks={getFieldLinks} />}
|
{annotations && <ExemplarsPlugin exemplars={annotations} timeZone={timeZone} getFieldLinks={getFieldLinks} />}
|
||||||
</GraphNG>
|
</GraphNG>
|
||||||
|
@ -11,8 +11,9 @@ import {
|
|||||||
Collapse,
|
Collapse,
|
||||||
GraphSeriesToggler,
|
GraphSeriesToggler,
|
||||||
GraphSeriesTogglerAPI,
|
GraphSeriesTogglerAPI,
|
||||||
Chart,
|
VizTooltip,
|
||||||
Icon,
|
Icon,
|
||||||
|
TooltipDisplayMode,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
|
|
||||||
const MAX_NUMBER_OF_TIME_SERIES = 20;
|
const MAX_NUMBER_OF_TIME_SERIES = 20;
|
||||||
@ -130,7 +131,7 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
|
|||||||
onHorizontalRegionSelected={this.onChangeTime}
|
onHorizontalRegionSelected={this.onChangeTime}
|
||||||
>
|
>
|
||||||
{/* For logs we are using mulit mode until we refactor logs histogram to use barWidth instead of lineWidth to render bars */}
|
{/* For logs we are using mulit mode until we refactor logs histogram to use barWidth instead of lineWidth to render bars */}
|
||||||
<Chart.Tooltip mode={showBars ? 'multi' : 'single'} />
|
<VizTooltip mode={showBars ? TooltipDisplayMode.Multi : TooltipDisplayMode.Single} />
|
||||||
</GraphWithLegend>
|
</GraphWithLegend>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { GraphTooltipOptions, LegendDisplayMode, LegendPlacement } from '@grafana/ui';
|
import { VizTooltipOptions, TooltipDisplayMode, LegendDisplayMode, LegendPlacement } from '@grafana/ui';
|
||||||
import { YAxis } from '@grafana/data';
|
import { YAxis } from '@grafana/data';
|
||||||
|
|
||||||
export interface SeriesOptions {
|
export interface SeriesOptions {
|
||||||
@ -21,7 +21,7 @@ export interface Options {
|
|||||||
series: {
|
series: {
|
||||||
[alias: string]: SeriesOptions;
|
[alias: string]: SeriesOptions;
|
||||||
};
|
};
|
||||||
tooltipOptions: GraphTooltipOptions;
|
tooltipOptions: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaults: Options = {
|
export const defaults: Options = {
|
||||||
@ -35,7 +35,7 @@ export const defaults: Options = {
|
|||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
},
|
},
|
||||||
series: {},
|
series: {},
|
||||||
tooltipOptions: { mode: 'single' },
|
tooltipOptions: { mode: TooltipDisplayMode.Single },
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface GraphLegendEditorLegendOptions {
|
export interface GraphLegendEditorLegendOptions {
|
||||||
|
@ -36,6 +36,7 @@ export const PieChartPanel: React.FC<Props> = ({
|
|||||||
pieType={options.pieType}
|
pieType={options.pieType}
|
||||||
displayLabels={options.displayLabels}
|
displayLabels={options.displayLabels}
|
||||||
legendOptions={options.legend}
|
legendOptions={options.legend}
|
||||||
|
tooltipOptions={options.tooltip}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,19 @@ export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
.addRadio({
|
||||||
|
name: 'Tooltip mode',
|
||||||
|
path: 'tooltip.mode',
|
||||||
|
description: '',
|
||||||
|
defaultValue: 'single',
|
||||||
|
settings: {
|
||||||
|
options: [
|
||||||
|
{ value: 'single', label: 'Single' },
|
||||||
|
{ value: 'multi', label: 'All' },
|
||||||
|
{ value: 'none', label: 'Hidden' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
.addRadio({
|
.addRadio({
|
||||||
path: 'legend.displayMode',
|
path: 'legend.displayMode',
|
||||||
name: 'Legend mode',
|
name: 'Legend mode',
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { PieChartType, SingleStatBaseOptions, PieChartLabels, PieChartLegendOptions } from '@grafana/ui';
|
import {
|
||||||
|
PieChartType,
|
||||||
|
SingleStatBaseOptions,
|
||||||
|
PieChartLabels,
|
||||||
|
PieChartLegendOptions,
|
||||||
|
VizTooltipOptions,
|
||||||
|
} from '@grafana/ui';
|
||||||
export interface PieChartOptions extends SingleStatBaseOptions {
|
export interface PieChartOptions extends SingleStatBaseOptions {
|
||||||
pieType: PieChartType;
|
pieType: PieChartType;
|
||||||
displayLabels: PieChartLabels[];
|
displayLabels: PieChartLabels[];
|
||||||
legend: PieChartLegendOptions;
|
legend: PieChartLegendOptions;
|
||||||
|
tooltip: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
LineStyle,
|
LineStyle,
|
||||||
PointVisibility,
|
PointVisibility,
|
||||||
StackingMode,
|
StackingMode,
|
||||||
|
TooltipDisplayMode,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { Options } from './types';
|
import { Options } from './types';
|
||||||
import omitBy from 'lodash/omitBy';
|
import omitBy from 'lodash/omitBy';
|
||||||
@ -291,7 +292,7 @@ export function flotToGraphOptions(angular: any): { fieldConfig: FieldConfigSour
|
|||||||
calcs: [],
|
calcs: [],
|
||||||
},
|
},
|
||||||
tooltipOptions: {
|
tooltipOptions: {
|
||||||
mode: 'single',
|
mode: TooltipDisplayMode.Single,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
import { HorizontalGroup, Portal, Tag, TooltipContainer, useStyles } from '@grafana/ui';
|
import { HorizontalGroup, Portal, Tag, VizTooltipContainer, useStyles } from '@grafana/ui';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
interface AnnotationMarkerProps {
|
interface AnnotationMarkerProps {
|
||||||
@ -38,7 +38,7 @@ export const AnnotationMarker: React.FC<AnnotationMarkerProps> = ({ time, text,
|
|||||||
const elBBox = el.getBoundingClientRect();
|
const elBBox = el.getBoundingClientRect();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipContainer
|
<VizTooltipContainer
|
||||||
position={{ x: elBBox.left, y: elBBox.top + elBBox.height }}
|
position={{ x: elBBox.left, y: elBBox.top + elBBox.height }}
|
||||||
offset={{ x: 0, y: 0 }}
|
offset={{ x: 0, y: 0 }}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
@ -61,7 +61,7 @@ export const AnnotationMarker: React.FC<AnnotationMarkerProps> = ({ time, text,
|
|||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TooltipContainer>
|
</VizTooltipContainer>
|
||||||
);
|
);
|
||||||
}, [onMouseEnter, onMouseLeave, styles, time, text, tags]);
|
}, [onMouseEnter, onMouseLeave, styles, time, text, tags]);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
systemDateFormats,
|
systemDateFormats,
|
||||||
TimeZone,
|
TimeZone,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { FieldLinkList, Portal, TooltipContainer, useStyles } from '@grafana/ui';
|
import { FieldLinkList, Portal, VizTooltipContainer, useStyles } from '@grafana/ui';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export const ExemplarMarker: React.FC<ExemplarMarkerProps> = ({ timeZone, dataFr
|
|||||||
const elBBox = el.getBoundingClientRect();
|
const elBBox = el.getBoundingClientRect();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipContainer
|
<VizTooltipContainer
|
||||||
position={{ x: elBBox.left, y: elBBox.top + elBBox.height }}
|
position={{ x: elBBox.left, y: elBBox.top + elBBox.height }}
|
||||||
offset={{ x: 0, y: 0 }}
|
offset={{ x: 0, y: 0 }}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
@ -93,7 +93,7 @@ export const ExemplarMarker: React.FC<ExemplarMarkerProps> = ({ timeZone, dataFr
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TooltipContainer>
|
</VizTooltipContainer>
|
||||||
);
|
);
|
||||||
}, [dataFrame.fields, getFieldLinks, index, onMouseEnter, onMouseLeave, styles, timeFormatter]);
|
}, [dataFrame.fields, getFieldLinks, index, onMouseEnter, onMouseLeave, styles, timeFormatter]);
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { VizLegendOptions, GraphTooltipOptions } from '@grafana/ui';
|
import { VizLegendOptions, VizTooltipOptions } from '@grafana/ui';
|
||||||
|
|
||||||
export interface OptionsWithLegend {
|
export interface OptionsWithLegend {
|
||||||
legend: VizLegendOptions;
|
legend: VizLegendOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Options extends OptionsWithLegend {
|
export interface Options extends OptionsWithLegend {
|
||||||
tooltipOptions: GraphTooltipOptions;
|
tooltipOptions: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { GraphTooltipOptions } from '@grafana/ui';
|
import { VizTooltipOptions } from '@grafana/ui';
|
||||||
import { OptionsWithLegend } from '../timeseries/types';
|
import { OptionsWithLegend } from '../timeseries/types';
|
||||||
|
|
||||||
export interface XYDimensionConfig {
|
export interface XYDimensionConfig {
|
||||||
@ -9,5 +9,5 @@ export interface XYDimensionConfig {
|
|||||||
|
|
||||||
export interface Options extends OptionsWithLegend {
|
export interface Options extends OptionsWithLegend {
|
||||||
dims: XYDimensionConfig;
|
dims: XYDimensionConfig;
|
||||||
tooltipOptions: GraphTooltipOptions;
|
tooltipOptions: VizTooltipOptions;
|
||||||
}
|
}
|
||||||
|
@ -46,13 +46,13 @@ cue def -s $(find packages/grafana-data -type f -name "*.cue") > cue/data/gen.cu
|
|||||||
#
|
#
|
||||||
# It's important to understand why this is necessary, though. We are expecting
|
# It's important to understand why this is necessary, though. We are expecting
|
||||||
# that these core components may depend on each other - e.g., how
|
# that these core components may depend on each other - e.g., how
|
||||||
# GraphTooltipOptions composes in TooltipMode. We have to preserve those
|
# VizTooltipOptions composes in TooltipDisplayMode. We have to preserve those
|
||||||
# literal identifiers in our assembled CUE, so that when a panel plugin's
|
# literal identifiers in our assembled CUE, so that when a panel plugin's
|
||||||
# models.cue imports and references something like GraphTooltipOptions in CUE,
|
# models.cue imports and references something like VizTooltipOptions in CUE,
|
||||||
# it's still the same identifier as appeared in the original core models.cue
|
# it's still the same identifier as appeared in the original core models.cue
|
||||||
# files, AND therefore is exactly the identifier that appears in
|
# files, AND therefore is exactly the identifier that appears in
|
||||||
# cuetsy-generated @grafana/{ui,data} packages. That is, as long as we preserve
|
# cuetsy-generated @grafana/{ui,data} packages. That is, as long as we preserve
|
||||||
# the relation between the identifier "GraphTooltipOptions" as a top-level
|
# the relation between the identifier "VizTooltipOptions" as a top-level
|
||||||
# importable thing at all stages on the CUE side, then everything on the
|
# importable thing at all stages on the CUE side, then everything on the
|
||||||
# TypeScript side will line up.
|
# TypeScript side will line up.
|
||||||
sed -i -e 's/^import.*//g' {cue/ui/gen.cue,cue/data/gen.cue}
|
sed -i -e 's/^import.*//g' {cue/ui/gen.cue,cue/data/gen.cue}
|
||||||
|
Loading…
Reference in New Issue
Block a user