Skip to content

Commit 4db3e4e

Browse files
tycupjoshwooding
andcommitted
Highcharts | Waterfall Chart (#5728)
Co-authored-by: Josh Wooding <[email protected]>
1 parent cf4f603 commit 4db3e4e

File tree

11 files changed

+338
-6
lines changed

11 files changed

+338
-6
lines changed

packages/highcharts-theme/css/salt-fill-patterns.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,15 @@
7878
.highcharts-theme-salt.salt-fill-patterns .highcharts-color-19:not(.highcharts-data-label-connector) {
7979
fill: url(#squares);
8080
}
81+
82+
.highcharts-theme-salt.salt-fill-patterns .highcharts-waterfall-series .highcharts-point {
83+
fill: url(#positive-sentiment);
84+
}
85+
86+
.highcharts-theme-salt.salt-fill-patterns .highcharts-waterfall-series .highcharts-point.highcharts-negative {
87+
fill: url(#negative-sentiment);
88+
}
89+
90+
.highcharts-theme-salt.salt-fill-patterns .highcharts-waterfall-series .highcharts-point.highcharts-sum {
91+
fill: url(#neutral-sentiment);
92+
}

packages/highcharts-theme/css/salt-highcharts-theme.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@
173173
.highcharts-theme-salt .highcharts-bubble-series .highcharts-data-label text,
174174
.highcharts-theme-salt .highcharts-bubble-series text.highcharts-data-label {
175175
fill: var(--salt-content-primary-foreground);
176+
font-weight: var(--salt-text-label-fontWeight-strong);
177+
}
178+
179+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-data-label text,
180+
.highcharts-theme-salt .highcharts-waterfall-series text.highcharts-data-label {
181+
font-weight: var(--salt-text-label-fontWeight-strong);
176182
}
177183

178184
.highcharts-theme-salt .highcharts-legend-item-hidden > text,
@@ -287,3 +293,33 @@
287293
.highcharts-theme-salt .highcharts-boxplot-median {
288294
stroke: var(--salt-content-primary-foreground);
289295
}
296+
297+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-point {
298+
fill: var(--salt-sentiment-positive-foreground-decorative);
299+
stroke: var(--salt-sentiment-positive-foreground-decorative);
300+
}
301+
302+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-point.highcharts-negative {
303+
fill: var(--salt-sentiment-negative-foreground-decorative);
304+
stroke: var(--salt-sentiment-negative-foreground-decorative);
305+
}
306+
307+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-point.highcharts-sum {
308+
fill: var(--salt-category-15-bold-background);
309+
stroke: var(--salt-category-15-subtle-borderColor);
310+
}
311+
312+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-point.highcharts-intermediate-sum {
313+
fill: var(--salt-category-15-bold-background);
314+
stroke: var(--salt-category-15-subtle-borderColor);
315+
}
316+
317+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-graph {
318+
stroke: var(--salt-content-primary-foreground);
319+
stroke-width: var(--salt-size-fixed-100);
320+
stroke-dasharray: 2, 2;
321+
}
322+
323+
.highcharts-theme-salt .highcharts-waterfall-series .highcharts-data-label text {
324+
fill: var(--salt-content-bold-foreground);
325+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useChart } from "@salt-ds/highcharts-theme";
2+
import { clsx } from "clsx";
3+
import Highcharts, { type Options } from "highcharts";
4+
import HighchartsReact from "highcharts-react-official";
5+
import { type FC, useRef } from "react";
6+
import { waterfallOptions } from "./dependencies";
7+
8+
export interface WaterfallChartProps {
9+
patterns?: boolean;
10+
options: Options;
11+
}
12+
13+
const WaterfallChart: FC<WaterfallChartProps> = ({
14+
patterns = false,
15+
options = waterfallOptions,
16+
}) => {
17+
const chartRef = useRef<HighchartsReact.RefObject>(null);
18+
19+
const chartOptions = useChart(chartRef, options);
20+
21+
return (
22+
<div
23+
className={clsx("highcharts-theme-salt", {
24+
"salt-fill-patterns": patterns,
25+
})}
26+
>
27+
<HighchartsReact
28+
highcharts={Highcharts}
29+
options={chartOptions}
30+
ref={chartRef}
31+
/>
32+
</div>
33+
);
34+
};
35+
36+
export default WaterfallChart;

packages/highcharts-theme/src/examples/dependencies/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export { lineOptions } from "./lineOptions";
99
export { pieOptions } from "./pieOptions";
1010
export { scatterOptions } from "./scatterOptions";
1111
export { stackedBarOptions } from "./stackedBarOptions";
12+
export { waterfallOptions } from "./waterfallOptions";
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { Options } from "highcharts";
2+
3+
export const waterfallOptions: Options = {
4+
chart: {
5+
type: "waterfall",
6+
},
7+
title: {
8+
text: "Regional revenue by product",
9+
},
10+
accessibility: {
11+
description:
12+
"A waterfall chart showing the cumulative effect of sequential positive and negative values on revenue.",
13+
},
14+
xAxis: {
15+
categories: [
16+
"Start",
17+
"Product Sales",
18+
"Service Revenue",
19+
"Operating Costs",
20+
"Marketing",
21+
"Total",
22+
],
23+
title: {
24+
text: "Category",
25+
},
26+
},
27+
yAxis: {
28+
title: {
29+
text: "Revenue ($ millions)",
30+
},
31+
},
32+
tooltip: {
33+
headerFormat: "<span>{point.key}</span><br/>",
34+
pointFormat:
35+
'<span>{series.name}: </span><span class="value">${point.y}M</span>',
36+
},
37+
legend: {
38+
enabled: false,
39+
},
40+
plotOptions: {
41+
waterfall: {
42+
dataLabels: {
43+
enabled: true,
44+
formatter: function () {
45+
return `$${this.y}M`;
46+
},
47+
},
48+
},
49+
},
50+
series: [
51+
{
52+
name: "Revenue",
53+
type: "waterfall",
54+
data: [
55+
{ y: 50 },
56+
{ y: 25 },
57+
{ y: 15 },
58+
{ y: -20 },
59+
{ y: -10 },
60+
{ isSum: true },
61+
],
62+
},
63+
],
64+
};

packages/highcharts-theme/src/examples/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export { default as LineChart } from "./LineChart";
99
export { default as PieChart } from "./PieChart";
1010
export { default as ScatterChart } from "./ScatterChart";
1111
export { default as StackedBarChart } from "./StackedBarChart";
12+
export { default as WaterfallChart } from "./WaterfallChart";

packages/highcharts-theme/src/patterns.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ const fillPatterns = [
257257
},
258258
];
259259

260-
export const saltPatternDef = fillPatterns.reduce<Record<string, object>>(
261-
(prev, curr, index) => {
260+
export const saltPatternDef = {
261+
...fillPatterns.reduce<Record<string, object>>((prev, curr, index) => {
262262
prev[curr.id] = {
263263
...curr,
264264
tagName: "pattern",
@@ -276,6 +276,56 @@ export const saltPatternDef = fillPatterns.reduce<Record<string, object>>(
276276
],
277277
};
278278
return prev;
279+
}, {}),
280+
"positive-sentiment": {
281+
...fillPatterns[0],
282+
id: "positive-sentiment",
283+
tagName: "pattern",
284+
patternUnits: "userSpaceOnUse",
285+
width: 10,
286+
height: 10,
287+
children: [
288+
{
289+
tagName: "rect",
290+
width: 10,
291+
height: 10,
292+
style: { fill: "var(--salt-sentiment-positive-foreground-decorative)" },
293+
},
294+
...fillPatterns[0].children,
295+
],
296+
},
297+
"negative-sentiment": {
298+
...fillPatterns[1],
299+
id: "negative-sentiment",
300+
tagName: "pattern",
301+
patternUnits: "userSpaceOnUse",
302+
width: 10,
303+
height: 10,
304+
children: [
305+
{
306+
tagName: "rect",
307+
width: 10,
308+
height: 10,
309+
style: { fill: "var(--salt-sentiment-negative-foreground-decorative)" },
310+
},
311+
...fillPatterns[1].children,
312+
],
313+
},
314+
"neutral-sentiment": {
315+
...fillPatterns[2],
316+
id: "neutral-sentiment",
317+
tagName: "pattern",
318+
patternUnits: "userSpaceOnUse",
319+
width: 10,
320+
height: 10,
321+
children: [
322+
{
323+
tagName: "rect",
324+
width: 10,
325+
height: 10,
326+
style: { fill: "var(--salt-category-15-bold-background)" },
327+
},
328+
...fillPatterns[2].children,
329+
],
279330
},
280-
{},
281-
);
331+
};

packages/highcharts-theme/stories/highcharts-theme.stories.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
PieChart as PieChartComponent,
1414
ScatterChart as ScatterChartComponent,
1515
StackedBarChart as StackedBarChartComponent,
16+
WaterfallChart as WaterfallChartComponent,
1617
} from "../src/examples";
1718
import {
1819
areaOptions,
@@ -26,6 +27,7 @@ import {
2627
pieOptions,
2728
scatterOptions,
2829
stackedBarOptions,
30+
waterfallOptions,
2931
} from "../src/examples/dependencies";
3032

3133
accessibility(Highcharts);
@@ -143,3 +145,11 @@ export const ScatterChart = {
143145
options: scatterOptions,
144146
},
145147
};
148+
149+
export const WaterfallChart = {
150+
render: (args: ChartStoryArgs) => <WaterfallChartComponent {...args} />,
151+
args: {
152+
patterns: false,
153+
options: waterfallOptions,
154+
},
155+
};

site/docs/components/highcharts-theme/examples.mdx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ Current issues to be resolved before lab release:
1515

1616
<ul>
1717
<li>
18-
Legend positioning isn't consistent with Figma examples due to Highcharts API limitations - [track issue](https://github.com/jpmorganchase/salt-ds/issues/5548).
18+
Legend positioning isn't consistent with Figma examples due to Highcharts API limitations - [track issue](https://github.com/jpmorganchase/salt-ds/issues/5555).
1919
</li>
2020
<li>
21-
Plot bands aren't currently supported due to v10 accessibility and token issues. If you need to use plot bands, you need to ensure that appropriate color contrast is maintained - [track issue](https://github.com/jpmorganchase/salt-ds/issues/5548 )
21+
Plot bands aren't currently supported due to v10 accessibility and token issues. If you need to use plot bands, you need to ensure that appropriate color contrast is maintained - [track issue](https://github.com/jpmorganchase/salt-ds/issues/5548)
22+
</li>
23+
<li>
24+
Chart titles and X axis titles are misaligned due to Highcharts API limitations - [track issue](https://github.com/jpmorganchase/salt-ds/issues/5770)
2225
</li>
2326
</ul>
2427
</Callout>
@@ -67,6 +70,17 @@ A stacked bar chart is a variation of the bar chart, with the `plotOptions.serie
6770

6871
<LivePreview componentName="highcharts-theme" exampleName="StackedBarChart" />
6972

73+
## Waterfall chart
74+
75+
Use a waterfall chart to show the cumulative effect of sequential positive and negative values. This is ideal for visualizing financial data, showing how an initial value is affected by a series of changes. To ensure the presentation is accessible, fill patterns can be applied to the chart (see [Patterns and Fills](./usage#patterns-and-fills) for details).
76+
77+
<Callout title="Note">
78+
To use the waterfall chart, import the Highcharts `highcharts-more` module and
79+
use it to wrap the `Highcharts` object as shown in the example.
80+
</Callout>
81+
82+
<LivePreview componentName="highcharts-theme" exampleName="WaterfallChart" />
83+
7084
## Bullet chart
7185

7286
Use a bullet chart to show performance against a target across categories. Each category displays a single bar with a marker indicating the target value. To ensure the presentation is accessible, fill patterns can be applied to the chart (see [Patterns and Fills](./usage#patterns-and-fills) for details).

0 commit comments

Comments
 (0)