|
|
@ -14,69 +14,96 @@ import { PanelData, TimeRange, PanelProps } from '@grafana/data'; |
|
|
|
import { VizLegend } from '@grafana/ui'; |
|
|
|
import { VizLegend } from '@grafana/ui'; |
|
|
|
import { LegendDisplayMode } from '@grafana/schema'; |
|
|
|
import { LegendDisplayMode } from '@grafana/schema'; |
|
|
|
|
|
|
|
|
|
|
|
import React, { useCallback, useRef } from 'react'; |
|
|
|
import React, { useRef, useEffect, useMemo } from 'react'; |
|
|
|
import { css } from 'emotion'; |
|
|
|
import { css } from 'emotion'; |
|
|
|
import * as _ from 'lodash'; |
|
|
|
import * as _ from 'lodash'; |
|
|
|
|
|
|
|
|
|
|
|
interface Props extends PanelProps<PanelOptions> {} |
|
|
|
interface Props extends PanelProps<PanelOptions> {} |
|
|
|
|
|
|
|
|
|
|
|
export function Panel({ options, data, width, height, timeRange, onChangeTimeRange, replaceVariables }: Props) { |
|
|
|
export function Panel({ options, data, width, height, timeRange, onChangeTimeRange, replaceVariables }: Props) { |
|
|
|
const grafanaSeriesList = getGrafanaSeriesList(data, timeRange); |
|
|
|
const grafanaSeriesList = useMemo(() => getGrafanaSeriesList(data, timeRange), [data, timeRange]); |
|
|
|
let chartContainer = useRef(null); |
|
|
|
const podContainerRef = useRef<HTMLDivElement>(null); |
|
|
|
|
|
|
|
|
|
|
|
// we request animation frame here because we need an existing DOM-element at the moment we render the pod
|
|
|
|
const podContainer = useMemo(() => { |
|
|
|
window.requestAnimationFrame(() => { |
|
|
|
const chartHeight = height - 20; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chartClickHandler = (event: React.MouseEvent<HTMLDivElement>) => { |
|
|
|
|
|
|
|
event.preventDefault(); |
|
|
|
|
|
|
|
if (options.gauge.link === undefined || options.gauge.link === '') { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const link = replaceVariables(options.gauge.link); |
|
|
|
|
|
|
|
window.open(link, '_self'); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const isLinkActive = options.gauge.link !== undefined && options.gauge.link !== ''; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<div |
|
|
|
|
|
|
|
ref={podContainerRef} |
|
|
|
|
|
|
|
className={css` |
|
|
|
|
|
|
|
width: ${width}px; |
|
|
|
|
|
|
|
height: ${chartHeight}px; |
|
|
|
|
|
|
|
cursor: ${isLinkActive ? 'pointer' : 'default'}; |
|
|
|
|
|
|
|
`}
|
|
|
|
|
|
|
|
onClick={chartClickHandler} |
|
|
|
|
|
|
|
></div> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}, [width, height, options.gauge.link, replaceVariables]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
let pod; |
|
|
|
let pod; |
|
|
|
|
|
|
|
if (podContainerRef.current === null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
switch (options.visualizationType) { |
|
|
|
switch (options.visualizationType) { |
|
|
|
case Pod.GAUGE: |
|
|
|
case Pod.GAUGE: |
|
|
|
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries(); |
|
|
|
const series = new Series(grafanaSeriesList, options.gauge.value).getChartwerkSeries(); |
|
|
|
const chartwerkGaugeOptions = new GaugeOptions(grafanaSeriesList, options).getChartwerkOptions(); |
|
|
|
const chartwerkGaugeOptions = new GaugeOptions(grafanaSeriesList, options).getChartwerkOptions(); |
|
|
|
pod = new ChartwerkGaugePod((chartContainer as any).current, series, chartwerkGaugeOptions); |
|
|
|
pod = new ChartwerkGaugePod(podContainerRef.current, series, chartwerkGaugeOptions); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case Pod.BAR: |
|
|
|
case Pod.BAR: |
|
|
|
const barSeries = new BarSeries(grafanaSeriesList).getChartwerkSeries(); |
|
|
|
const barSeries = new BarSeries(grafanaSeriesList).getChartwerkSeries(); |
|
|
|
const chartwerkBarOptions = new BarOptions(grafanaSeriesList, onChangeTimeRange).getChartwerkOptions(); |
|
|
|
const chartwerkBarOptions = new BarOptions(grafanaSeriesList, onChangeTimeRange).getChartwerkOptions(); |
|
|
|
pod = new ChartwerkBarPod((chartContainer as any).current, barSeries, chartwerkBarOptions); |
|
|
|
pod = new ChartwerkBarPod(podContainerRef.current, barSeries, chartwerkBarOptions); |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new Error(`Unknown visualization type: ${options.visualizationType}`); |
|
|
|
throw new Error(`Unknown visualization type: ${options.visualizationType}`); |
|
|
|
} |
|
|
|
} |
|
|
|
pod.render(); |
|
|
|
pod.render(); |
|
|
|
}); |
|
|
|
}, [podContainer, grafanaSeriesList, onChangeTimeRange, options]); |
|
|
|
|
|
|
|
|
|
|
|
const isLinkActive = !_.isEmpty(options.gauge.link); |
|
|
|
const legendItems = useMemo( |
|
|
|
const chartClickHandler = useCallback((event: React.MouseEvent<HTMLDivElement>) => { |
|
|
|
() => |
|
|
|
event.preventDefault(); |
|
|
|
_.map(grafanaSeriesList, (serie) => { |
|
|
|
if (!isLinkActive) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const link = replaceVariables(options.gauge.link as string); |
|
|
|
|
|
|
|
window.open(link, '_self'); |
|
|
|
|
|
|
|
}, [options.gauge.link]); |
|
|
|
|
|
|
|
const legendItems = _.map(grafanaSeriesList, (serie) => { |
|
|
|
|
|
|
|
return { |
|
|
|
return { |
|
|
|
label: serie.alias, |
|
|
|
label: serie.alias, |
|
|
|
color: serie.color, |
|
|
|
color: serie.color, |
|
|
|
yAxis: 1, |
|
|
|
yAxis: 1, |
|
|
|
}; |
|
|
|
}; |
|
|
|
}); |
|
|
|
}), |
|
|
|
const chartHeight = options.visualizationType !== Pod.GAUGE ? height - 20 : height; |
|
|
|
[grafanaSeriesList] |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (options.visualizationType) { |
|
|
|
|
|
|
|
case Pod.LINE: |
|
|
|
|
|
|
|
case Pod.BAR: |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<div |
|
|
|
{podContainer} |
|
|
|
ref={chartContainer} |
|
|
|
|
|
|
|
className={css` |
|
|
|
|
|
|
|
width: ${width}px; |
|
|
|
|
|
|
|
height: ${chartHeight}px; |
|
|
|
|
|
|
|
cursor: ${isLinkActive ? 'pointer' : 'default'}; |
|
|
|
|
|
|
|
`}
|
|
|
|
|
|
|
|
onClick={chartClickHandler} |
|
|
|
|
|
|
|
></div> |
|
|
|
|
|
|
|
{options.visualizationType !== Pod.GAUGE && ( |
|
|
|
|
|
|
|
<VizLegend placement={'bottom'} items={legendItems} displayMode={LegendDisplayMode.List} /> |
|
|
|
<VizLegend placement={'bottom'} items={legendItems} displayMode={LegendDisplayMode.List} /> |
|
|
|
)} |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
case Pod.GAUGE: |
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{podContainer} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
throw new Error(`Unknown visualization type: ${options.visualizationType}`); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function getGrafanaSeriesList(grafanaData: PanelData, timeRange: TimeRange): any[] { |
|
|
|
function getGrafanaSeriesList(grafanaData: PanelData, timeRange: TimeRange): any[] { |
|
|
|