diff --git a/.betterer.results b/.betterer.results index 14e3d5b1ebd..5193586a9e7 100644 --- a/.betterer.results +++ b/.betterer.results @@ -6563,16 +6563,11 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"] ], "public/app/plugins/panel/xychart/TooltipView.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"] + [0, 0, 0, "Do not use any type assertions.", "0"] ], - "public/app/plugins/panel/xychart/XYChartPanel2.tsx:5381": [ + "public/app/plugins/panel/xychart/XYChartPanel.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"] + [0, 0, 0, "Do not use any type assertions.", "1"] ], "public/app/plugins/panel/xychart/dims.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json b/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json new file mode 100644 index 00000000000..5ee05b7b7f9 --- /dev/null +++ b/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json @@ -0,0 +1,687 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "Miles_per_Gallon", + "y": "Horsepower" + } + ], + "seriesMapping": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Single color", + "type": "xychart" + }, + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "shades" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 7, + "x": 7, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "Miles_per_Gallon", + "y": "Horsepower" + } + ], + "seriesMapping": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Shades of a color", + "type": "xychart" + }, + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "yellow", + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 7, + "x": 14, + "y": 0 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "Miles_per_Gallon", + "y": "Horsepower" + } + ], + "seriesMapping": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Classic palette", + "type": "xychart" + }, + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 7, + "x": 0, + "y": 11 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "x", + "y": "y" + }, + { + "pointColor": { + "fixed": "green" + }, + "x": "x", + "y": "z" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Single color + Mapping: Fixed color", + "type": "xychart" + }, + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "shades" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 7, + "x": 7, + "y": 11 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "x", + "y": "y" + }, + { + "pointColor": { + "fixed": "green" + }, + "x": "x", + "y": "z" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Shades of color + Mapping: Fixed color", + "type": "xychart" + }, + { + "datasource": {}, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 32 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 7, + "x": 14, + "y": 11 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "fixed": "orange" + }, + "x": "x", + "y": "y" + }, + { + "pointColor": { + "fixed": "green" + }, + "x": "x", + "y": "z" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,z\n1,2,3\n3,4,5\n5,6,7", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "${DS_GDEV-TESTDATA}" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Standard options: Classic palette + Mapping: Fixed color", + "type": "xychart" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-BlYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 50 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 7, + "x": 0, + "y": 23 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "field": "c", + "fixed": "dark-green" + }, + "x": "x", + "y": "y" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "x,y,c\n0,0,0\n50,50,25\n100,100,50", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Panel Title", + "type": "xychart" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "XYChart tooltip color test", + "uid": "cb67db43-dd72-4ada-a313-53f46c20adcc", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/devenv/jsonnet/dev-dashboards.libsonnet b/devenv/jsonnet/dev-dashboards.libsonnet index 07726f41723..7ab736b308d 100644 --- a/devenv/jsonnet/dev-dashboards.libsonnet +++ b/devenv/jsonnet/dev-dashboards.libsonnet @@ -124,5 +124,6 @@ "timeseries-yaxis-ticks": (import '../dev-dashboards/panel-timeseries/timeseries-yaxis-ticks.json'), "trend_example": (import '../dev-dashboards/panel-trend/trend_example.json'), "xychart-example": (import '../dev-dashboards/panel-xychart/xychart-example.json'), + "xychart-tooltip-color-test": (import '../dev-dashboards/panel-xychart/xychart-tooltip-color-test.json'), }, } diff --git a/public/app/plugins/panel/xychart/TooltipView.tsx b/public/app/plugins/panel/xychart/TooltipView.tsx index 5bfe57ff54c..2ea5c1e4de9 100644 --- a/public/app/plugins/panel/xychart/TooltipView.tsx +++ b/public/app/plugins/panel/xychart/TooltipView.tsx @@ -163,22 +163,22 @@ function fmt(field: Field, val: number): string { } const getStyles = (theme: GrafanaTheme2) => ({ - infoWrap: css` - padding: 8px; - width: 100%; - th { - font-weight: ${theme.typography.fontWeightMedium}; - padding: ${theme.spacing(0.25, 2)}; - } - `, - highlight: css` - background: ${theme.colors.action.hover}; - `, - xVal: css` - font-weight: ${theme.typography.fontWeightBold}; - `, - icon: css` - margin-right: ${theme.spacing(1)}; - vertical-align: middle; - `, + infoWrap: css({ + padding: '8px', + width: '100%', + th: { + fontWeight: theme.typography.fontWeightMedium, + padding: theme.spacing(0.25, 2), + }, + }), + highlight: css({ + background: theme.colors.action.hover, + }), + xVal: css({ + fontWeight: theme.typography.fontWeightBold, + }), + icon: css({ + marginRight: theme.spacing(1), + verticalAlign: 'middle', + }), }); diff --git a/public/app/plugins/panel/xychart/XYChartPanel2.tsx b/public/app/plugins/panel/xychart/XYChartPanel.tsx similarity index 70% rename from public/app/plugins/panel/xychart/XYChartPanel2.tsx rename to public/app/plugins/panel/xychart/XYChartPanel.tsx index 81ba3d162c2..4e762802a42 100644 --- a/public/app/plugins/panel/xychart/XYChartPanel2.tsx +++ b/public/app/plugins/panel/xychart/XYChartPanel.tsx @@ -16,6 +16,7 @@ import { config } from '@grafana/runtime'; import { Portal, TooltipDisplayMode, + TooltipPlugin2, UPlotChart, UPlotConfigBuilder, VizLayout, @@ -23,10 +24,12 @@ import { VizLegendItem, VizTooltipContainer, } from '@grafana/ui'; +import { TooltipHoverMode } from '@grafana/ui/src/components/uPlot/plugins/TooltipPlugin2'; import { FacetedData } from '@grafana/ui/src/components/uPlot/types'; import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; import { TooltipView } from './TooltipView'; +import { XYChartTooltip } from './XYChartTooltip'; import { Options, SeriesMapping } from './panelcfg.gen'; import { prepData, prepScatter, ScatterPanelInfo } from './scatter'; import { ScatterHoverEvent, ScatterSeries } from './types'; @@ -34,13 +37,14 @@ import { ScatterHoverEvent, ScatterSeries } from './types'; type Props = PanelProps; const TOOLTIP_OFFSET = 10; -export const XYChartPanel2 = (props: Props) => { +export const XYChartPanel = (props: Props) => { const [error, setError] = useState(); const [series, setSeries] = useState([]); const [builder, setBuilder] = useState(); const [facets, setFacets] = useState(); const [hover, setHover] = useState(); const [shouldDisplayCloseButton, setShouldDisplayCloseButton] = useState(false); + const showNewVizTooltips = Boolean(config.featureToggles.newVizTooltips); const isToolTipOpen = useRef(false); const oldOptions = usePrevious(props.options); @@ -69,9 +73,9 @@ export const XYChartPanel2 = (props: Props) => { props.options, getData, config.theme2, - scatterHoverCallback, - onUPlotClick, - isToolTipOpen + showNewVizTooltips ? null : scatterHoverCallback, + showNewVizTooltips ? null : onUPlotClick, + showNewVizTooltips ? null : isToolTipOpen ); if (info.error) { @@ -82,7 +86,7 @@ export const XYChartPanel2 = (props: Props) => { setFacets(() => prepData(info, props.data.series)); setError(undefined); } - }, [props.data.series, props.options]); + }, [props.data.series, props.options, showNewVizTooltips]); const initFacets = useCallback(() => { setFacets(() => prepData({ error, series }, props.data.series)); @@ -187,11 +191,11 @@ export const XYChartPanel2 = (props: Props) => { } const legendStyle = { - flexStart: css` - div { - justify-content: flex-start !important; - } - `, + flexStart: css({ + div: { + justifyContent: 'flex-start', + }, + }), }; return ( @@ -218,47 +222,69 @@ export const XYChartPanel2 = (props: Props) => { <> {(vizWidth: number, vizHeight: number) => ( - + + {config.featureToggles.newVizTooltips && props.options.tooltip.mode !== TooltipDisplayMode.None && ( + { + return ( + + ); + }} + /> + )} + )} - - {hover && props.options.tooltip.mode !== TooltipDisplayMode.None && ( - - {shouldDisplayCloseButton && ( -
- + {hover && props.options.tooltip.mode !== TooltipDisplayMode.None && ( + + {shouldDisplayCloseButton && ( +
-
- )} - -
- )} - + > + +
+ )} + +
+ )} +
+ )} ); }; diff --git a/public/app/plugins/panel/xychart/XYChartTooltip.tsx b/public/app/plugins/panel/xychart/XYChartTooltip.tsx new file mode 100644 index 00000000000..190eb1b75ef --- /dev/null +++ b/public/app/plugins/panel/xychart/XYChartTooltip.tsx @@ -0,0 +1,136 @@ +import { css } from '@emotion/css'; +import React from 'react'; + +import { DataFrame, Field, getFieldDisplayName, GrafanaTheme2, LinkModel } from '@grafana/data'; +import { alpha } from '@grafana/data/src/themes/colorManipulator'; +import { useStyles2 } from '@grafana/ui'; +import { VizTooltipContent } from '@grafana/ui/src/components/VizTooltip/VizTooltipContent'; +import { VizTooltipFooter } from '@grafana/ui/src/components/VizTooltip/VizTooltipFooter'; +import { VizTooltipHeader } from '@grafana/ui/src/components/VizTooltip/VizTooltipHeader'; +import { ColorIndicator, LabelValue } from '@grafana/ui/src/components/VizTooltip/types'; +import { getTitleFromHref } from 'app/features/explore/utils/links'; + +import { Options } from './panelcfg.gen'; +import { ScatterSeries, YValue } from './types'; +import { fmt } from './utils'; + +export interface Props { + dataIdxs: Array; + seriesIdx: number | null | undefined; + isPinned: boolean; + dismiss: () => void; + options: Options; + data: DataFrame[]; // source data + allSeries: ScatterSeries[]; +} + +export const XYChartTooltip = ({ dataIdxs, seriesIdx, data, allSeries, dismiss, options, isPinned }: Props) => { + const styles = useStyles2(getStyles); + + const rowIndex = dataIdxs.find((idx) => idx !== null); + // @todo: remove -1 when uPlot v2 arrive + // context: first value in dataIdxs always null and represent X series + const hoveredPointIndex = seriesIdx! - 1; + + if (!allSeries || rowIndex == null) { + return null; + } + + const series = allSeries[hoveredPointIndex]; + const frame = series.frame(data); + const xField = series.x(frame); + const yField = series.y(frame); + + const getHeaderLabel = (): LabelValue => { + let label = series.name; + if (options.seriesMapping === 'manual') { + label = options.series?.[hoveredPointIndex]?.name ?? `Series ${hoveredPointIndex + 1}`; + } + + let colorThing = series.pointColor(frame); + + if (Array.isArray(colorThing)) { + colorThing = colorThing[rowIndex]; + } + + return { + label, + value: null, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + color: alpha(colorThing as string, 0.5), + colorIndicator: ColorIndicator.marker_md, + }; + }; + + const getContentLabel = (): LabelValue[] => { + let colorThing = series.pointColor(frame); + + if (Array.isArray(colorThing)) { + colorThing = colorThing[rowIndex]; + } + + const yValue: YValue = { + name: getFieldDisplayName(yField, frame), + val: yField.values[rowIndex], + field: yField, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + color: alpha(colorThing as string, 0.5), + }; + + const content: LabelValue[] = [ + { + label: getFieldDisplayName(xField, frame), + value: fmt(xField, xField.values[rowIndex]), + }, + { + label: yValue.name, + value: fmt(yValue.field, yValue.val), + }, + ]; + + // add extra fields + const extraFields: Field[] = frame.fields.filter((f) => f !== xField && f !== yField); + if (extraFields) { + extraFields.forEach((field) => { + content.push({ + label: field.name, + value: fmt(field, field.values[rowIndex]), + }); + }); + } + + return content; + }; + + const getLinks = (): Array> => { + let links: Array> = []; + if (yField.getLinks) { + const v = yField.values[rowIndex]; + const disp = yField.display ? yField.display(v) : { text: `${v}`, numeric: +v }; + links = yField.getLinks({ calculatedValue: disp, valueRowIndex: rowIndex }).map((linkModel) => { + if (!linkModel.title) { + linkModel.title = getTitleFromHref(linkModel.href); + } + + return linkModel; + }); + } + return links; + }; + + return ( +
+ + + {isPinned && } +
+ ); +}; + +const getStyles = (theme: GrafanaTheme2) => ({ + wrapper: css({ + display: 'flex', + flexDirection: 'column', + width: '280px', + }), +}); diff --git a/public/app/plugins/panel/xychart/module.tsx b/public/app/plugins/panel/xychart/module.tsx index 5d383a7d750..930755e40aa 100644 --- a/public/app/plugins/panel/xychart/module.tsx +++ b/public/app/plugins/panel/xychart/module.tsx @@ -3,11 +3,11 @@ import { commonOptionsBuilder } from '@grafana/ui'; import { AutoEditor } from './AutoEditor'; import { ManualEditor } from './ManualEditor'; -import { XYChartPanel2 } from './XYChartPanel2'; +import { XYChartPanel } from './XYChartPanel'; import { getScatterFieldConfig } from './config'; import { Options, FieldConfig, defaultFieldConfig } from './panelcfg.gen'; -export const plugin = new PanelPlugin(XYChartPanel2) +export const plugin = new PanelPlugin(XYChartPanel) .useFieldConfig(getScatterFieldConfig(defaultFieldConfig)) .setPanelOptions((builder) => { builder @@ -38,6 +38,6 @@ export const plugin = new PanelPlugin(XYChartPanel2) showIf: (cfg) => cfg.seriesMapping === 'manual', }); - commonOptionsBuilder.addTooltipOptions(builder); + commonOptionsBuilder.addTooltipOptions(builder, true); commonOptionsBuilder.addLegendOptions(builder); }); diff --git a/public/app/plugins/panel/xychart/scatter.ts b/public/app/plugins/panel/xychart/scatter.ts index d136ee28c6b..03fc40fb4c6 100644 --- a/public/app/plugins/panel/xychart/scatter.ts +++ b/public/app/plugins/panel/xychart/scatter.ts @@ -46,9 +46,9 @@ export function prepScatter( options: Options, getData: () => DataFrame[], theme: GrafanaTheme2, - ttip: ScatterHoverCallback, + ttip: null | ScatterHoverCallback, onUPlotClick: null | ((evt?: Object) => void), - isToolTipOpen: MutableRefObject + isToolTipOpen: null | MutableRefObject ): ScatterPanelInfo { let series: ScatterSeries[]; let builder: UPlotConfigBuilder; @@ -294,14 +294,13 @@ interface DrawBubblesOpts { }; } -//const prepConfig: UPlotConfigPrepFnXY = ({ frames, series, theme }) => { const prepConfig = ( getData: () => DataFrame[], scatterSeries: ScatterSeries[], theme: GrafanaTheme2, - ttip: ScatterHoverCallback, + ttip: null | ScatterHoverCallback, onUPlotClick: null | ((evt?: Object) => void), - isToolTipOpen: MutableRefObject + isToolTipOpen: null | MutableRefObject ) => { let qt: Quadtree; let hRect: Rect | null; @@ -522,8 +521,10 @@ const prepConfig = ( }); const clearPopupIfOpened = () => { - if (isToolTipOpen.current) { - ttip(undefined); + if (isToolTipOpen?.current) { + if (ttip) { + ttip(undefined); + } if (onUPlotClick) { onUPlotClick(); } @@ -534,7 +535,9 @@ const prepConfig = ( // clip hover points/bubbles to plotting area builder.addHook('init', (u, r) => { - u.over.style.overflow = 'hidden'; + if (!config.featureToggles.newVizTooltips) { + u.over.style.overflow = 'hidden'; + } ref_parent = u.root.parentElement; if (onUPlotClick) { @@ -556,26 +559,28 @@ const prepConfig = ( rect = r; }); - builder.addHook('setLegend', (u) => { - if (u.cursor.idxs != null) { - for (let i = 0; i < u.cursor.idxs.length; i++) { - const sel = u.cursor.idxs[i]; - if (sel != null && !isToolTipOpen.current) { - ttip({ - scatterIndex: i - 1, - xIndex: sel, - pageX: rect.left + u.cursor.left!, - pageY: rect.top + u.cursor.top!, - }); - return; // only show the first one + if (ttip) { + builder.addHook('setLegend', (u) => { + if (u.cursor.idxs != null) { + for (let i = 0; i < u.cursor.idxs.length; i++) { + const sel = u.cursor.idxs[i]; + if (sel != null && !isToolTipOpen?.current) { + ttip({ + scatterIndex: i - 1, + xIndex: sel, + pageX: rect.left + u.cursor.left!, + pageY: rect.top + u.cursor.top!, + }); + return; // only show the first one + } } } - } - if (!isToolTipOpen.current) { - ttip(undefined); - } - }); + if (!isToolTipOpen?.current) { + ttip(undefined); + } + }); + } builder.addHook('drawClear', (u) => { clearPopupIfOpened(); @@ -598,8 +603,8 @@ const prepConfig = ( const frames = getData(); let xField = scatterSeries[0].x(scatterSeries[0].frame(frames)); - let config = xField.config; - let customConfig = config.custom; + let fieldConfig = xField.config; + let customConfig = fieldConfig.custom; let scaleDistr = customConfig?.scaleDistribution; builder.addScale({ @@ -610,12 +615,12 @@ const prepConfig = ( distribution: scaleDistr?.type, log: scaleDistr?.log, linearThreshold: scaleDistr?.linearThreshold, - min: config.min, - max: config.max, + min: fieldConfig.min, + max: fieldConfig.max, softMin: customConfig?.axisSoftMin, softMax: customConfig?.axisSoftMax, centeredZero: customConfig?.axisCenteredZero, - decimals: config.decimals, + decimals: fieldConfig.decimals, }); // why does this fall back to '' instead of null or undef? diff --git a/public/app/plugins/panel/xychart/types.ts b/public/app/plugins/panel/xychart/types.ts index bd44ef4b27e..bbaf107d4d2 100644 --- a/public/app/plugins/panel/xychart/types.ts +++ b/public/app/plugins/panel/xychart/types.ts @@ -50,3 +50,17 @@ export interface ScatterSeries { }; }; } + +export interface YValue { + name: string; + val: number; + field: Field; + color: string; +} + +export interface ExtraFacets { + colorFacetFieldName: string; + sizeFacetFieldName: string; + colorFacetValue: number; + sizeFacetValue: number; +} diff --git a/public/app/plugins/panel/xychart/utils.ts b/public/app/plugins/panel/xychart/utils.ts new file mode 100644 index 00000000000..512a46d3d7a --- /dev/null +++ b/public/app/plugins/panel/xychart/utils.ts @@ -0,0 +1,9 @@ +import { Field, formattedValueToString } from '@grafana/data'; + +export function fmt(field: Field, val: number): string { + if (field.display) { + return formattedValueToString(field.display(val)); + } + + return `${val}`; +}