@ons/design-system 72.5.0 → 72.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/components/breadcrumbs/_breadcrumbs.scss +1 -0
  2. package/components/chart/_chart.scss +56 -0
  3. package/components/chart/_macro.njk +43 -5
  4. package/components/chart/_macro.spec.js +420 -0
  5. package/components/chart/annotations-options.js +78 -0
  6. package/components/chart/bar-chart.js +15 -2
  7. package/components/chart/chart.js +119 -27
  8. package/components/chart/column-chart.js +2 -2
  9. package/components/chart/common-chart-options.js +104 -51
  10. package/components/chart/example-bar-chart-with-annotations.njk +62 -0
  11. package/components/chart/example-bar-chart.njk +1 -0
  12. package/components/chart/example-bar-with-line-chart.njk +64 -0
  13. package/components/chart/example-clustered-column-chart.njk +5 -2
  14. package/components/chart/example-column-chart-with-annotations.njk +63 -0
  15. package/components/chart/example-column-chart.njk +5 -2
  16. package/components/chart/example-column-with-line-chart.njk +63 -0
  17. package/components/chart/example-line-chart-with-annotations.njk +235 -0
  18. package/components/chart/example-line-chart.njk +7 -3
  19. package/components/chart/example-stacked-column-chart.njk +3 -1
  20. package/components/chart/line-chart.js +2 -7
  21. package/components/details/details.js +5 -0
  22. package/components/details-panel/_details-panel.scss +107 -0
  23. package/components/details-panel/_macro.njk +41 -0
  24. package/components/details-panel/_macro.spec.js +54 -0
  25. package/components/details-panel/example-details-panel-open.njk +29 -0
  26. package/components/details-panel/example-details-panel.njk +28 -0
  27. package/components/hero/_hero.scss +101 -43
  28. package/components/hero/_macro.njk +21 -10
  29. package/components/hero/_macro.spec.js +94 -0
  30. package/components/hero/example-hero-dark.njk +1 -1
  31. package/components/hero/example-hero-grey.njk +8 -0
  32. package/components/icon/_macro.njk +1 -1
  33. package/components/pagination/_macro.njk +1 -1
  34. package/components/pagination/_pagination.scss +6 -0
  35. package/components/summary/_macro.njk +2 -2
  36. package/components/summary/_macro.spec.js +43 -21
  37. package/components/summary/_summary.scss +5 -1
  38. package/components/summary/example-summary-grouped.njk +0 -12
  39. package/components/table-of-contents/_macro.njk +40 -0
  40. package/components/table-of-contents/_macro.spec.js +72 -0
  41. package/components/table-of-contents/_table-of-contents.scss +11 -0
  42. package/components/table-of-contents/example-table-of-contents-related-links-with-button.njk +60 -0
  43. package/css/main.css +1 -1
  44. package/js/cookies-functions.js +11 -6
  45. package/js/cookies-functions.spec.js +44 -0
  46. package/package.json +1 -1
  47. package/scripts/main.es5.js +1 -1
  48. package/scripts/main.js +1 -1
  49. package/scss/main.scss +1 -0
  50. package/scss/vars/_colors.scss +1 -0
@@ -0,0 +1,78 @@
1
+ import ChartConstants from './chart-constants';
2
+
3
+ class AnnotationsOptions {
4
+ constructor(annotations) {
5
+ this.constants = ChartConstants.constants();
6
+ this.annotations = annotations;
7
+ }
8
+
9
+ getAnnotationsOptionsDesktop = () => {
10
+ let annotations = [
11
+ {
12
+ labels: [],
13
+ labelOptions: {
14
+ shape: 'connector',
15
+ borderColor: this.constants.labelColor,
16
+ padding: 3,
17
+ style: {
18
+ color: this.constants.labelColor,
19
+ fontSize: this.constants.desktopFontSize,
20
+ width: 150,
21
+ textAlign: 'left',
22
+ },
23
+ },
24
+ draggable: '',
25
+ },
26
+ ];
27
+ this.annotations.forEach((annotation) => {
28
+ annotations[0].labels.push({
29
+ point: {
30
+ x: annotation.point.x,
31
+ y: annotation.point.y,
32
+ xAxis: 0,
33
+ yAxis: 0,
34
+ },
35
+ text: annotation.text,
36
+ x: annotation.labelOffsetX,
37
+ y: annotation.labelOffsetY,
38
+ });
39
+ });
40
+ return annotations;
41
+ };
42
+
43
+ getAnnotationsOptionsMobile = () => {
44
+ let annotations = [
45
+ {
46
+ labels: [],
47
+ labelOptions: {
48
+ backgroundColor: 'transparent',
49
+ borderColor: 'transparent',
50
+ // We use css styling for the rounded number annotation at mobile
51
+ useHTML: true,
52
+ className: 'ons-chart__footnote-number',
53
+ },
54
+ draggable: '',
55
+ },
56
+ ];
57
+ this.annotations.forEach((annotation, index) => {
58
+ annotations[0].labels.push({
59
+ point: {
60
+ x: annotation.point.x,
61
+ y: annotation.point.y,
62
+ xAxis: 0,
63
+ yAxis: 0,
64
+ },
65
+ text: index + 1,
66
+ x: 0,
67
+ y: 0,
68
+ // Ensures the full label is read out by screen readers
69
+ accessibility: {
70
+ description: annotation.text,
71
+ },
72
+ });
73
+ });
74
+ return annotations;
75
+ };
76
+ }
77
+
78
+ export default AnnotationsOptions;
@@ -40,6 +40,7 @@ class BarChart {
40
40
  style: {
41
41
  color: this.constants.categoryLabelColor,
42
42
  },
43
+ useHTML: false,
43
44
  },
44
45
  // remove the tick marks for bar charts
45
46
  tickWidth: 0,
@@ -48,6 +49,14 @@ class BarChart {
48
49
  title: { align: 'high', textAlign: 'middle', reserveSpace: false, rotation: 0, y: -25, useHTML: true },
49
50
  },
50
51
  yAxis: {
52
+ labels: {
53
+ rotation: 0,
54
+ useHTML: true,
55
+ style: {
56
+ whiteSpace: 'nowrap',
57
+ color: this.constants.categoryLabelColor,
58
+ },
59
+ },
51
60
  title: {
52
61
  // Override the y Axis title settings for bar charts where the y axis is horizontal
53
62
  textAlign: 'right',
@@ -76,6 +85,10 @@ class BarChart {
76
85
  // Get the actual width of the data label
77
86
  const labelWidth = point.dataLabel && point.dataLabel.getBBox().width;
78
87
  // Move the data labels inside the bar if the bar is wider than the label plus some padding
88
+ if (series.type == 'line') {
89
+ // If we have a bar chart with an extra line, exit early for the line series
90
+ return;
91
+ }
79
92
  if (point.shapeArgs.height > labelWidth + 20) {
80
93
  point.update(insideOptions, false);
81
94
  } else {
@@ -112,9 +125,9 @@ class BarChart {
112
125
 
113
126
  // This updates the height of the vertical axis and overall chart to fit the number of categories
114
127
  // Note that the vertical axis on a bar chart is the x axis
115
- updateBarChartHeight = (config, currentChart, useStackedLayout) => {
128
+ updateBarChartHeight = (config, currentChart, useStackedLayout, numberOfExtraLines) => {
116
129
  const numberOfCategories = config.xAxis.categories.length;
117
- const numberOfSeries = currentChart.series.length; // Get number of bar series
130
+ const numberOfSeries = currentChart.series.length - numberOfExtraLines; // Get number of bar series
118
131
  let barHeight = 30; // Height of each individual bar - set in bar-chart-plot-options
119
132
  let groupSpacing = 0; // Space we want between category groups, or between series groups for cluster charts
120
133
  let categoriesTotalHeight = 0;
@@ -1,10 +1,13 @@
1
+ import Highcharts from 'highcharts';
2
+ import 'highcharts/modules/accessibility';
3
+ import 'highcharts/modules/annotations';
4
+
1
5
  import CommonChartOptions from './common-chart-options';
2
6
  import SpecificChartOptions from './specific-chart-options';
3
7
  import LineChart from './line-chart';
4
8
  import BarChart from './bar-chart';
5
9
  import ColumnChart from './column-chart';
6
- import Highcharts from 'highcharts';
7
- import 'highcharts/modules/accessibility';
10
+ import AnnotationsOptions from './annotations-options';
8
11
 
9
12
  class HighchartsBaseChart {
10
13
  static selector() {
@@ -16,27 +19,42 @@ class HighchartsBaseChart {
16
19
  this.chartType = this.node.dataset.highchartsType;
17
20
  this.theme = this.node.dataset.highchartsTheme;
18
21
  const chartNode = this.node.querySelector('[data-highcharts-chart]');
19
-
20
22
  this.id = this.node.dataset.highchartsId;
21
23
  this.useStackedLayout = this.node.hasAttribute('data-highcharts-use-stacked-layout');
22
24
  this.config = JSON.parse(this.node.querySelector(`[data-highcharts-config--${this.id}]`).textContent);
23
-
24
- this.commonChartOptions = new CommonChartOptions();
25
+ if (this.node.querySelector(`[data-highcharts-annotations--${this.id}]`)) {
26
+ const annotations = JSON.parse(this.node.querySelector(`[data-highcharts-annotations--${this.id}]`).textContent);
27
+ this.annotationsOptions = new AnnotationsOptions(annotations);
28
+ }
29
+ this.percentageHeightDesktop = this.node.dataset.highchartsPercentageHeightDesktop;
30
+ this.percentageHeightMobile = this.node.dataset.highchartsPercentageHeightMobile;
31
+ this.xAxisTickIntervalMobile = parseInt(this.node.dataset.highchartsXAxisTickIntervalMobile);
32
+ this.xAxisTickIntervalDesktop = parseInt(this.node.dataset.highchartsXAxisTickIntervalDesktop);
33
+ this.yAxisTickIntervalMobile = parseInt(this.node.dataset.highchartsYAxisTickIntervalMobile);
34
+ this.yAxisTickIntervalDesktop = parseInt(this.node.dataset.highchartsYAxisTickIntervalDesktop);
35
+ this.commonChartOptions = new CommonChartOptions(this.xAxisTickIntervalDesktop, this.yAxisTickIntervalDesktop);
25
36
  this.specificChartOptions = new SpecificChartOptions(this.theme, this.chartType, this.config);
26
37
  this.lineChart = new LineChart();
27
38
  this.barChart = new BarChart();
28
39
  this.columnChart = new ColumnChart();
40
+ this.extraLines = this.checkForExtraLines();
29
41
  if (window.isCommonChartOptionsDefined === undefined) {
30
42
  this.setCommonChartOptions();
31
43
  window.isCommonChartOptionsDefined = true;
32
44
  }
33
45
  this.hideDataLabels = this.checkHideDataLabels();
34
46
  this.setSpecificChartOptions();
47
+ this.setResponsiveOptions();
35
48
  this.setLoadEvent();
36
49
  this.setWindowResizeEvent();
37
50
  this.chart = Highcharts.chart(chartNode, this.config);
38
51
  }
39
52
 
53
+ // Check for the number of extra line series in the config
54
+ checkForExtraLines = () => {
55
+ return this.chartType === 'line' ? 0 : this.config.series.filter((series) => series.type === 'line').length;
56
+ };
57
+
40
58
  // Set up the global Highcharts options which are used for all charts
41
59
  setCommonChartOptions = () => {
42
60
  const chartOptions = this.commonChartOptions.getOptions();
@@ -99,6 +117,19 @@ class HighchartsBaseChart {
99
117
  // Merge the column chart options with the existing config
100
118
  this.config = this.mergeConfigs(this.config, columnChartOptions);
101
119
  }
120
+
121
+ if (this.extraLines > 0) {
122
+ this.config = this.mergeConfigs(this.config, this.lineChart.getLineChartOptions());
123
+ if (this.chartType === 'column') {
124
+ this.config = this.mergeConfigs(this.config, columnChartOptions);
125
+ }
126
+ if (this.chartType === 'bar') {
127
+ this.config = this.mergeConfigs(this.config, barChartOptions);
128
+ }
129
+ }
130
+
131
+ // Disable the legend for single series charts
132
+ this.commonChartOptions.disableLegendForSingleSeries(this.config);
102
133
  };
103
134
 
104
135
  // Check if the data labels should be hidden
@@ -107,50 +138,111 @@ class HighchartsBaseChart {
107
138
  return (this.chartType === 'bar' && this.config.series.length > 2) || this.useStackedLayout === true;
108
139
  };
109
140
 
141
+ // Adjust font size and annotations for smaller width of chart
142
+ // Note this is not the same as the viewport width
143
+ // All responsive rules should be defined here to avoid overriding existing rules
144
+ setResponsiveOptions = () => {
145
+ const mobileCommonChartOptions = this.commonChartOptions.getMobileOptions(
146
+ this.xAxisTickIntervalMobile,
147
+ this.yAxisTickIntervalMobile,
148
+ );
149
+ if (!this.config.responsive) {
150
+ this.config.responsive = {};
151
+ }
152
+ // If these conditions change, the styling for the footnotes container query in _chart.scss needs to be updated
153
+ let rules = [
154
+ {
155
+ condition: {
156
+ maxWidth: 400,
157
+ },
158
+ chartOptions: {
159
+ ...mobileCommonChartOptions,
160
+ },
161
+ },
162
+ // We are using a slightly wider breakpoint for annotations
163
+ // to try and reduce the likelihood of them being automatically
164
+ // hidden by Highcharts
165
+ {
166
+ condition: {
167
+ maxWidth: 600,
168
+ },
169
+ chartOptions: {
170
+ annotations: this.annotationsOptions ? this.annotationsOptions.getAnnotationsOptionsMobile() : undefined,
171
+ },
172
+ },
173
+ {
174
+ condition: {
175
+ minWidth: 601,
176
+ },
177
+ chartOptions: {
178
+ annotations: this.annotationsOptions ? this.annotationsOptions.getAnnotationsOptionsDesktop() : undefined,
179
+ },
180
+ },
181
+ ];
182
+ this.config.responsive.rules = rules;
183
+ };
184
+
110
185
  // Create the load event for various chart types
186
+ // All load events should be defined here to avoid overriding existing events
111
187
  setLoadEvent = () => {
112
188
  if (!this.config.chart.events) {
113
189
  this.config.chart.events = {};
114
190
  }
115
191
  this.config.chart.events.load = (event) => {
116
192
  const currentChart = event.target;
117
- // Disable the legend for single series charts
118
- this.commonChartOptions.disableLegendForSingleSeries(currentChart);
119
193
  if (this.chartType === 'line') {
120
- this.lineChart.updateLastPointMarker(currentChart);
121
- this.commonChartOptions.hideDataLabels(currentChart);
194
+ this.lineChart.updateLastPointMarker(currentChart.series);
195
+ this.commonChartOptions.hideDataLabels(currentChart.series);
122
196
  }
123
197
  if (this.chartType === 'bar') {
124
- this.barChart.updateBarChartHeight(this.config, currentChart, this.useStackedLayout);
198
+ this.barChart.updateBarChartHeight(this.config, currentChart, this.useStackedLayout, this.extraLines);
125
199
  if (!this.hideDataLabels) {
126
200
  this.barChart.postLoadDataLabels(currentChart);
127
201
  } else {
128
- this.commonChartOptions.hideDataLabels(currentChart);
202
+ this.commonChartOptions.hideDataLabels(currentChart.series);
129
203
  }
130
204
  }
131
205
  if (this.chartType === 'column') {
132
- this.columnChart.updatePointPadding(this.config, currentChart, this.useStackedLayout);
133
- this.commonChartOptions.hideDataLabels(currentChart);
206
+ this.columnChart.updatePointPadding(this.config, currentChart, this.useStackedLayout, this.extraLines);
207
+ this.commonChartOptions.hideDataLabels(currentChart.series);
208
+ }
209
+ if (this.chartType != 'bar') {
210
+ this.commonChartOptions.adjustChartHeight(currentChart, this.percentageHeightDesktop, this.percentageHeightMobile);
134
211
  }
212
+
213
+ // If the chart has an extra line or lines, hide the data labels for
214
+ // that series, update the last point marker
215
+ if (this.extraLines > 0) {
216
+ currentChart.series.forEach((series) => {
217
+ if (series.type === 'line') {
218
+ this.lineChart.updateLastPointMarker([series]);
219
+ this.commonChartOptions.hideDataLabels([series]);
220
+ }
221
+ });
222
+ }
223
+ // Update the legend items for all charts
224
+ this.commonChartOptions.updateLegendSymbols(currentChart);
135
225
  currentChart.redraw(false);
136
226
  };
137
227
  };
138
228
 
139
- // Set resize events - throttled to 100ms
229
+ // Set resize events - throttled to 50ms
230
+ // All resize events should be defined here to avoid overriding existing events
140
231
  setWindowResizeEvent = () => {
141
- if (this.chartType === 'column' || this.chartType === 'bar') {
142
- window.addEventListener('resize', () => {
143
- clearTimeout(this.resizeTimeout);
144
- this.resizeTimeout = setTimeout(() => {
145
- // Get the current rendered chart instance
146
- const currentChart = Highcharts.charts.find((chart) => chart && chart.container === this.chart.container);
147
- // Update the data labels when the window is resized
148
- if (this.chartType === 'bar' && !this.hideDataLabels) {
149
- this.barChart.postLoadDataLabels(currentChart);
150
- }
151
- }, 100);
152
- });
153
- }
232
+ window.addEventListener('resize', () => {
233
+ clearTimeout(this.resizeTimeout);
234
+ this.resizeTimeout = setTimeout(() => {
235
+ // Get the current rendered chart instance
236
+ const currentChart = Highcharts.charts.find((chart) => chart && chart.container === this.chart.container);
237
+ // Update the data labels when the window is resized
238
+ if (this.chartType === 'bar' && !this.hideDataLabels) {
239
+ this.barChart.postLoadDataLabels(currentChart);
240
+ }
241
+ if (this.chartType != 'bar') {
242
+ this.commonChartOptions.adjustChartHeight(currentChart, this.percentageHeightDesktop, this.percentageHeightMobile);
243
+ }
244
+ }, 50);
245
+ });
154
246
  };
155
247
  }
156
248
 
@@ -18,9 +18,9 @@ class ColumnChart {
18
18
  // Set the point padding between each bar to be 3% (an overall gap of 6%)
19
19
  // For charts with fewer than 5 categories, we use a wider point padding of 4% (8% gap between bars)
20
20
  // For cluster charts we use 0 for the point padding and a group padding of 4% (8% gap between bars)
21
- updatePointPadding = (config, currentChart, stackedLayout) => {
21
+ updatePointPadding = (config, currentChart, stackedLayout, numberOfExtraLines) => {
22
22
  const numberOfCategories = config.xAxis.categories.length;
23
- const numberOfSeries = currentChart.series.length; // Get number of bar series
23
+ const numberOfSeries = currentChart.series.length - numberOfExtraLines; // Get number of column series
24
24
  let pointPadding = 0;
25
25
  let groupPadding = 0;
26
26
  // non-clustered charts or stacked charts
@@ -2,7 +2,7 @@ import ChartConstants from './chart-constants';
2
2
 
3
3
  // Options that are common to all chart types - these are set once in the Highcharts.setOptions() method
4
4
  class CommonChartOptions {
5
- constructor() {
5
+ constructor(xAxisTickInterval, yAxisTickInterval) {
6
6
  this.constants = ChartConstants.constants();
7
7
 
8
8
  this.options = {
@@ -17,10 +17,15 @@ class CommonChartOptions {
17
17
  align: 'left',
18
18
  verticalAlign: 'top',
19
19
  layout: 'horizontal',
20
- // Symbol width and height in the legend. May be overridden for individual chart types
21
- symbolWidth: 12,
22
- symbolHeight: 12,
20
+ // Symbol width and height are set in a postLoad event, depending on the series type
21
+ // Default to the line width to ensure there is enough space for the overall legend item for line symbols
22
+ symbolWidth: 20,
23
23
  margin: 50,
24
+ navigation: {
25
+ // ensures that when the legend is long, there is no pagination or scrollbar
26
+ enabled: false,
27
+ },
28
+ itemDistance: 30,
24
29
  itemHoverStyle: {
25
30
  color: this.constants.labelColor, // Prevents the text from changing color on hover
26
31
  },
@@ -91,9 +96,12 @@ class CommonChartOptions {
91
96
  tickWidth: 1,
92
97
  tickLength: 6,
93
98
  tickColor: this.constants.gridLineColor,
99
+ tickInterval: yAxisTickInterval,
94
100
  },
95
101
  xAxis: {
96
102
  labels: {
103
+ useHTML: true,
104
+ rotation: 0,
97
105
  style: {
98
106
  color: this.constants.axisLabelColor,
99
107
  fontSize: this.constants.desktopFontSize,
@@ -112,6 +120,7 @@ class CommonChartOptions {
112
120
  tickWidth: 1,
113
121
  tickLength: 6,
114
122
  tickColor: this.constants.gridLineColor,
123
+ tickInterval: xAxisTickInterval,
115
124
  },
116
125
  plotOptions: {
117
126
  series: {
@@ -131,55 +140,49 @@ class CommonChartOptions {
131
140
  },
132
141
  },
133
142
  },
134
- // Adjust font size for smaller width of chart
135
- // Note this is not the same as the viewport width
136
- responsive: {
137
- rules: [
138
- {
139
- condition: {
140
- maxWidth: 400,
141
- },
142
- chartOptions: {
143
- legend: {
144
- itemStyle: {
145
- fontSize: this.constants.mobileFontSize,
146
- },
147
- },
148
- xAxis: {
149
- labels: {
150
- style: {
151
- fontSize: this.constants.mobileFontSize,
152
- },
153
- },
154
- title: {
155
- style: {
156
- fontSize: this.constants.mobileFontSize,
157
- },
158
- },
159
- },
160
- yAxis: {
161
- labels: {
162
- style: {
163
- fontSize: this.constants.mobileFontSize,
164
- },
165
- },
166
- title: {
167
- style: {
168
- fontSize: this.constants.mobileFontSize,
169
- },
170
- },
171
- },
172
- },
173
- },
174
- ],
175
- },
176
143
  };
177
144
  }
178
145
 
179
146
  getOptions = () => this.options;
180
147
 
181
- hideDataLabels = (currentChart) => {
182
- currentChart.series.forEach((series) => {
148
+ getMobileOptions = (xAxisTickInterval, yAxisTickInterval) => {
149
+ return {
150
+ legend: {
151
+ itemStyle: {
152
+ fontSize: this.constants.mobileFontSize,
153
+ },
154
+ },
155
+ xAxis: {
156
+ labels: {
157
+ style: {
158
+ fontSize: this.constants.mobileFontSize,
159
+ },
160
+ },
161
+ title: {
162
+ style: {
163
+ fontSize: this.constants.mobileFontSize,
164
+ },
165
+ },
166
+ tickInterval: xAxisTickInterval,
167
+ },
168
+ yAxis: {
169
+ labels: {
170
+ style: {
171
+ fontSize: this.constants.mobileFontSize,
172
+ },
173
+ },
174
+ title: {
175
+ style: {
176
+ fontSize: this.constants.mobileFontSize,
177
+ },
178
+ },
179
+ tickInterval: yAxisTickInterval,
180
+ },
181
+ };
182
+ };
183
+
184
+ hideDataLabels = (series) => {
185
+ series.forEach((series) => {
183
186
  series.update({
184
187
  dataLabels: {
185
188
  enabled: false,
@@ -188,13 +191,63 @@ class CommonChartOptions {
188
191
  });
189
192
  };
190
193
 
191
- disableLegendForSingleSeries = (currentChart) => {
192
- if (currentChart.series.length === 1) {
193
- currentChart.legend.update({
194
+ disableLegendForSingleSeries = (config) => {
195
+ if (config.series.length === 1) {
196
+ config.legend = {
194
197
  enabled: false,
198
+ };
199
+ config.chart.marginTop = 50;
200
+ }
201
+ };
202
+
203
+ updateLegendSymbols = (chart) => {
204
+ if (chart.legend.options.enabled) {
205
+ chart.legend.allItems.forEach((item) => {
206
+ const { legendItem, userOptions } = item;
207
+ const seriesType = userOptions?.type;
208
+ // symbol is defined for bar / column series, and line is defined for line series
209
+ // if symbol is defined for a line series, it is the marker symbol
210
+ const { label, symbol } = legendItem || {};
211
+
212
+ if (seriesType === 'line') {
213
+ symbol?.attr({
214
+ x: 16, // Position the marker to the right of the line
215
+ });
216
+
217
+ label?.attr({
218
+ x: 30, // Adjust label position to account for longer line
219
+ });
220
+ } else {
221
+ // Set the symbol size for bar / column series
222
+ symbol.attr({
223
+ width: 12,
224
+ height: 12,
225
+ y: 8,
226
+ });
227
+ }
195
228
  });
196
229
  }
197
230
  };
231
+
232
+ adjustChartHeight = (currentChart, percentageHeightDesktop, percentageHeightMobile) => {
233
+ // get height and width of the plot area
234
+ const plotHeight = currentChart.plotHeight;
235
+ const plotWidth = currentChart.plotWidth;
236
+ // calculate the new plot height based on the percentage height
237
+ // default to the current height
238
+ let newPlotHeight = plotHeight;
239
+ if (plotWidth > 400) {
240
+ newPlotHeight = plotWidth * (percentageHeightDesktop / 100);
241
+ } else {
242
+ newPlotHeight = plotWidth * (percentageHeightMobile / 100);
243
+ }
244
+ const totalHeight = currentChart.plotTop + newPlotHeight + currentChart.marginBottom;
245
+
246
+ // set the new size of the chart
247
+ if (totalHeight !== currentChart.chartHeight) {
248
+ currentChart.setSize(null, totalHeight, false);
249
+ }
250
+ };
198
251
  }
199
252
 
200
253
  export default CommonChartOptions;
@@ -0,0 +1,62 @@
1
+ {% from "components/chart/_macro.njk" import onsChart %}
2
+
3
+ {{
4
+ onsChart({
5
+ "chartType": "bar",
6
+ "description": "Volume sales, seasonally adjusted, Great Britain, January 2022 to January 2025",
7
+ "theme": "primary",
8
+ "title": "Food stores showed a strong rise on the month, while non-food stores fell",
9
+ "subtitle": "Figure 6: Upward contribution from housing and household services (including energy) saw the annual CPIH inflation rate rise",
10
+ "id": "uuid",
11
+ "caption": "Source: Monthly Business Survey, Retail Sales Inquiry from the Office for National Statistics",
12
+ "download": {
13
+ 'title': 'Download Figure 1 data',
14
+ 'itemsList': [
15
+ {
16
+ "text": "Excel spreadsheet (XLSX format, 18KB)",
17
+ "url": "#"
18
+ },
19
+ {
20
+ "text": "Simple text file (CSV format, 25KB)",
21
+ "url": "#"
22
+ },
23
+ {
24
+ "text": "Image (PNG format, 25KB)",
25
+ "url": "#"
26
+ }
27
+ ]
28
+ },
29
+ "xAxis": {
30
+ "categories": [
31
+ "All retailing",
32
+ "All retailing excluding Automotive fuel",
33
+ "Food stores",
34
+ "Department stores",
35
+ "Other non-food stores",
36
+ "Textile clothing \u0026 footwear stores",
37
+ "Household goods stores",
38
+ "Non-store retailing",
39
+ "Automotive fuel"
40
+ ],
41
+ "type": "linear"
42
+ },
43
+ "yAxis": {
44
+ "title": "Percent (%)"
45
+ },
46
+ "series": [
47
+ {
48
+ "data": [1.7, 2.1, 5.6, 0, -0.6, -2.7, -1.7, 2.4, -1.2],
49
+ "dataLabels": true,
50
+ "name": "Jan-25"
51
+ }
52
+ ],
53
+ "annotations": [
54
+ {
55
+ "text": "A test annotation",
56
+ "point": {"x": 2, "y": 3},
57
+ "labelOffsetX": 40,
58
+ "labelOffsetY": -30
59
+ }
60
+ ]
61
+ })
62
+ }}
@@ -38,6 +38,7 @@
38
38
  "Non-store retailing",
39
39
  "Automotive fuel"
40
40
  ],
41
+ "title": "Retailing",
41
42
  "type": "linear"
42
43
  },
43
44
  "yAxis": {