|
| 1 | +import { ActiveDataPoint, ChartType, Plugin } from "chart.js"; |
| 2 | +import { lightenColor } from "../../../../helpers"; |
| 3 | +import { GHOST_SUNBURST_VALUE } from "../../../../helpers/figures/charts/runtime"; |
| 4 | +import { SunburstChartRawData } from "../../../../types/chart"; |
| 5 | + |
| 6 | +export interface ChartSunburstHoverPluginOptions { |
| 7 | + enabled: boolean; |
| 8 | +} |
| 9 | + |
| 10 | +declare module "chart.js" { |
| 11 | + interface PluginOptionsByType<TType extends ChartType> { |
| 12 | + sunburstHoverPlugin?: ChartSunburstHoverPluginOptions; |
| 13 | + } |
| 14 | +} |
| 15 | + |
| 16 | +/** |
| 17 | + * When a chart element is hovered (active), this plugin also activates all of its child elements and |
| 18 | + * lightens the color of the other elements. |
| 19 | + */ |
| 20 | +export const sunburstHoverPlugin: Plugin = { |
| 21 | + id: "sunburstHoverPlugin", |
| 22 | + afterEvent(chart, args, options: ChartSunburstHoverPluginOptions) { |
| 23 | + if (!options.enabled) { |
| 24 | + return; |
| 25 | + } |
| 26 | + const chartActiveElements = chart.getActiveElements(); |
| 27 | + let activeDataPoints: ActiveDataPoint[] = chartActiveElements.map((el) => ({ |
| 28 | + datasetIndex: el.datasetIndex, |
| 29 | + index: el.index, |
| 30 | + })); |
| 31 | + |
| 32 | + for (const activeEl of chartActiveElements) { |
| 33 | + const activeDataset = chart.data.datasets[activeEl.datasetIndex]; |
| 34 | + const activeData = activeDataset.data[activeEl.index] as unknown as SunburstChartRawData; |
| 35 | + |
| 36 | + for (let datasetIndex = 0; datasetIndex < chart.data.datasets.length; datasetIndex++) { |
| 37 | + const dataset = chart.data.datasets[datasetIndex]; |
| 38 | + for (let index = 0; index < dataset.data.length; index++) { |
| 39 | + const data = dataset.data[index] as unknown as SunburstChartRawData; |
| 40 | + if (isChildGroup(activeData.groups, data.groups)) { |
| 41 | + activeDataPoints.push({ datasetIndex, index }); |
| 42 | + } |
| 43 | + } |
| 44 | + } |
| 45 | + } |
| 46 | + |
| 47 | + activeDataPoints = activeDataPoints.filter((point) => { |
| 48 | + const { datasetIndex, index } = point; |
| 49 | + const data = chart.data.datasets[datasetIndex].data[index] as unknown as SunburstChartRawData; |
| 50 | + return data.label !== GHOST_SUNBURST_VALUE; |
| 51 | + }); |
| 52 | + |
| 53 | + chart.setActiveElements(activeDataPoints); |
| 54 | + |
| 55 | + for (const metaSet of chart.getSortedVisibleDatasetMetas()) { |
| 56 | + for (const arcElement of metaSet.data) { |
| 57 | + const context = arcElement["$context"]; |
| 58 | + const { datasetIndex, index, dataset, raw } = context; |
| 59 | + if (raw.label === GHOST_SUNBURST_VALUE) { |
| 60 | + continue; |
| 61 | + } |
| 62 | + |
| 63 | + const originalBackgroundColor = |
| 64 | + typeof dataset.backgroundColor === "function" |
| 65 | + ? dataset.backgroundColor(context) |
| 66 | + : dataset.backgroundColor; |
| 67 | + if ( |
| 68 | + activeDataPoints.length && |
| 69 | + !activeDataPoints.some((el) => el.datasetIndex === datasetIndex && el.index === index) |
| 70 | + ) { |
| 71 | + arcElement.options.backgroundColor = lightenColor(originalBackgroundColor, 0.5); |
| 72 | + } else { |
| 73 | + arcElement.options.backgroundColor = originalBackgroundColor; |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + }, |
| 78 | +}; |
| 79 | + |
| 80 | +function isChildGroup(parentGroup: string[], childGroup: string[]) { |
| 81 | + return ( |
| 82 | + childGroup.length > parentGroup.length && |
| 83 | + parentGroup.every((group, i) => group === childGroup[i]) |
| 84 | + ); |
| 85 | +} |
0 commit comments