Skip to content

Commit

Permalink
chore(charts): import minimum requirements for Sankey
Browse files Browse the repository at this point in the history
  • Loading branch information
dlabrecq committed Feb 6, 2025
1 parent 149faca commit d2c5809
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 373 deletions.
154 changes: 64 additions & 90 deletions packages/react-charts/src/echarts/components/Sankey/Sankey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,40 @@ import chart_voronoi_flyout_stroke_Fill from '@patternfly/react-tokens/dist/esm/
import chart_voronoi_labels_Fill from '@patternfly/react-tokens/dist/esm/chart_voronoi_labels_Fill';

import * as React from 'react';
import * as echarts from 'echarts';
import { useCallback, useRef, useState } from 'react';
import defaultsDeep from 'lodash/defaultsDeep';
import { getMutationObserver } from '../utils/observe';
import { getComputedValue } from '../utils/styles';

// import { BarChart, SankeyChart } from 'echarts/charts';
// import { CanvasRenderer } from 'echarts/renderers';
import * as echarts from 'echarts/core';
import { EChartsOption } from 'echarts/types/dist/option';
import { SankeyChart } from 'echarts/charts';
import { TitleComponent, TooltipComponent } from 'echarts/components';
import { SVGRenderer } from 'echarts/renderers';

// import {
// TitleComponent,
// TooltipComponent,
// GridComponent,
// DatasetComponent,
// TransformComponent
// } from 'echarts/components';

// Register the required components
// echarts.use([
// BarChart,
// SankeyChart,
// TitleComponent,
// TooltipComponent,
// GridComponent,
// DatasetComponent,
// TransformComponent,
// LabelLayout,
// UniversalTransition,
// CanvasRenderer
// ]);
// Register minimal required components
echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]);

import { EChartsInitOpts } from 'echarts/types/dist/echarts';
import { ThemeDefinition } from '../themes/Theme';
import { getClassName } from '../utils/styles';
import { getTheme } from '../utils/theme';

/**
* Sankey diagram is a specific type of streamgraph (can also be seen as a directed acyclic graph) in which the width
* of each branch is shown proportionally to the flow quantity. These graphs are typically used to visualize energy or
* material or cost transfers between processes. They can also visualize the energy accounts, material flow accounts
* on a regional or national level, and also the breakdown of cost of item or services.
* The Sankey diagram is a specific type of streamgraph (can also be seen as a directed acyclic graph) in which the
* width of each branch is shown proportionally to the flow quantity. These graphs are typically used to visualize
* energy or material or cost transfers between processes. They can also visualize the energy accounts, material flow
* accounts on a regional or national level, and also the breakdown of cost of item or services.
*
* Note: Only the minimum requirements for Samkey are imported from echarts. This includes components to support
* the series, title, and tooltip properties. To include a toolbox; for example, you must include the component
* (in addition to toolbox props) like so:
*
* import * as echarts from 'echarts/core';
* import { ToolboxComponent } from 'echarts/components';
* echarts.use([ToolboxComponent]);
*
* @beta
*/
export interface SankeyProps {
/**
Expand All @@ -58,12 +51,6 @@ export interface SankeyProps {
* The id prop specifies an ID that will be applied to outermost element.
*/
id?: string;
/**
* Legend component properties
*
* See https://echarts.apache.org/en/option.html#legend
*/
legend?: any;
/**
* This creates a Mutation Observer to watch the given DOM selector.
*
Expand All @@ -83,17 +70,17 @@ export interface SankeyProps {
*/
nodeSelector?: string;
/**
* Optional chart configuration
* ECharts uses this object to configure its properties; for example, series, title, and tooltip
*
* See https://echarts.apache.org/en/api.html#echarts.init
* See https://echarts.apache.org/en/option.html
*/
opts?: EChartsInitOpts;
option?: EChartsOption;
/**
* Series component properties
* Optional chart configuration
*
* See https://echarts.apache.org/en/option.html#series-sankey
* See https://echarts.apache.org/en/api.html#echarts.init
*/
series: any[];
opts?: EChartsInitOpts;
/**
* The theme prop specifies a theme to use for determining styles and layout properties for a component. Any styles or
* props defined in theme may be overwritten by props specified on the component instance.
Expand All @@ -110,19 +97,7 @@ export interface SankeyProps {
*/
themeColor?: string;
/**
* Title component properties
*
* See https://echarts.apache.org/en/option.html#title
*/
title?: any;
/**
* Tooltip component properties
*
* See https://echarts.apache.org/en/option.html#tooltip
*/
tooltip?: any;
/**
* This is the destination label shown in the tooltip
* The destination label shown in the tooltip
*/
tooltipDestinationLabel?: string;
/**
Expand All @@ -139,16 +114,11 @@ export const Sankey: React.FunctionComponent<SankeyProps> = ({
className,
height,
id,
legend,
nodeSelector,
option,
opts,
series,
theme,
themeColor,
title,
tooltip = {
valueFormatter: (value: number | string) => value
},
tooltipDestinationLabel = 'Destination',
tooltipSourceLabel = 'Source',
width
Expand All @@ -159,14 +129,14 @@ export const Sankey: React.FunctionComponent<SankeyProps> = ({

const getItemColor = useCallback(
(params: any) => {
const serie = series[params.seriesIndex];
const serie = option?.series[params.seriesIndex];
const sourceData = serie?.data.find((datum: any) => datum.name === params.data?.source);
const targetData = serie?.data.find((datum: any) => datum.name === params.data?.target);
const sourceColor = sourceData?.itemStyle?.color;
const targetColor = targetData?.itemStyle?.color;
return { sourceColor, targetColor };
},
[series]
[option?.series]
);

const getSize = () => ({
Expand All @@ -176,6 +146,8 @@ export const Sankey: React.FunctionComponent<SankeyProps> = ({

const getTooltip = useCallback(() => {
const symbolSize = '10px';
const tooltip: any = option?.tooltip; // Workaround for CommonTooltipOption
const valueFormatter = tooltip?.valueFormatter ? tooltip.valueFormatter : (value: number | string) => value;
const defaults = {
backgroundColor: getComputedValue(chart_voronoi_flyout_stroke_Fill),
confine: true,
Expand All @@ -195,7 +167,7 @@ export const Sankey: React.FunctionComponent<SankeyProps> = ({
<div style="display: inline-block; background-color: ${targetColor}; height: ${symbolSize}; width: ${symbolSize};"></div>
${params.data.target}
<strong style="float:right;">
${tooltip.valueFormatter(params.value, params.dataIndex)}
${valueFormatter(params.value, params.dataIndex)}
</strong>
</p>
`;
Expand All @@ -208,44 +180,46 @@ export const Sankey: React.FunctionComponent<SankeyProps> = ({
trigger: 'item',
triggerOn: 'mousemove'
};
return defaultsDeep(tooltip, defaults);
}, [getItemColor, tooltipDestinationLabel, tooltipSourceLabel, tooltip]);
return defaultsDeep(option?.tooltip, defaults);
}, [getItemColor, option?.tooltip, tooltipDestinationLabel, tooltipSourceLabel]);

React.useEffect(() => {
echarts.registerTheme('pf-sankey', chartTheme);
echart.current = echarts.init(containerRef.current, 'pf-v5-sankey', defaultsDeep(opts, { renderer: 'svg' }));

const newSeries = series.map((serie: any) => {
const defaults = {
data: serie.data.map((datum: any, index: number) => ({
itemStyle: {
color: chartTheme?.color[index % chartTheme?.color.length]
}
})),
emphasis: {
focus: 'adjacency'
},
layout: 'none',
lineStyle: {
color: 'source',
opacity: 0.6
},
type: 'sankey'
};
return defaultsDeep(serie, defaults);
});

echart.current = echarts.init(containerRef.current, 'pf-v6-sankey', defaultsDeep(opts, { renderer: 'svg' }));

const getSeries = () => {
const series: any = option?.series; // Workaround for SeriesOption type
return series.map((serie: any) => {
const defaults = {
data: serie.data.map((datum: any, index: number) => ({
itemStyle: {
color: chartTheme?.color[index % chartTheme?.color.length]
}
})),
emphasis: {
focus: 'adjacency'
},
layout: 'none',
lineStyle: {
color: 'source',
opacity: 0.6
},
type: 'sankey'
};
return defaultsDeep(serie, defaults);
});
};
echart.current?.setOption({
series: newSeries,
legend,
title,
...option,
series: getSeries(),
title: option?.title,
tooltip: getTooltip()
});

return () => {
echart.current?.dispose();
};
}, [chartTheme, containerRef, getTooltip, legend, opts, series, title, tooltip]);
}, [chartTheme, containerRef, getTooltip, option, opts]);

// Resize observer
React.useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@ export const FormBasic: React.FunctionComponent = () => {
<div>
<Sankey
height={400}
id="chart1"
id="basic-chart"
nodeSelector="html"
series={[{ data, links }]}
title={{
subtext: 'This is a Sankey chart',
left: 'center'
}}
tooltip={{
valueFormatter: (value) => `${value} GiB`
option={{
series: [{ data, links }],
title: {
subtext: 'This is a Sankey chart',
left: 'center'
},
tooltip: {
valueFormatter: (value) => `${value} GiB`
}
}}
width={825}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ export const FormBasic: React.FunctionComponent = () => {
}
];

const legend = {
orient: 'vertical',
left: 'left',
data: ['a', 'a1', 'b', 'b1', 'c']
};

// let observer = () => {};
const containerRef = React.useRef<HTMLDivElement>();
const [width, setWidth] = React.useState(0);
Expand All @@ -85,18 +79,19 @@ export const FormBasic: React.FunctionComponent = () => {
<div ref={containerRef}>
<Sankey
height={400}
id="chart1"
legend={legend}
id="multi-color-responsive-chart"
nodeSelector="html"
series={[{ data, links }]}
themeColor={ThemeColor.multiUnordered}
title={{
subtext: 'This is a Sankey chart',
left: 'center'
}}
tooltip={{
valueFormatter: (value) => `${value} GiB`
option={{
series: [{ data, links }],
title: {
subtext: 'This is a Sankey chart',
left: 'center'
},
tooltip: {
valueFormatter: (value) => `${value} GiB`
}
}}
themeColor={ThemeColor.multiUnordered}
width={width}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ beta: true

import { Sankey, ThemeColor } from '@patternfly/react-charts/echarts';

import * as echarts from 'echarts/core';
import { ToolboxComponent } from 'echarts/components';

## Introduction
Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)!

Expand All @@ -23,6 +26,14 @@ PatternFly React charts are based on the [Apache ECharts](https://echarts.apache

### Multi-color (unordered) with responsive container

```ts file="./MultiColorResponsive.tsx"
```ts file="./MultiColor.tsx"

```

### Teal color with responsive container and toolbox

This demonstrates how to import `ToolboxComponent` for use with ECharts

```ts file="./Toolbox.tsx"

```
Loading

0 comments on commit d2c5809

Please sign in to comment.