@ons/design-system 72.9.2 → 72.10.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.
- package/components/chart/_chart.scss +74 -1
- package/components/chart/_macro.njk +64 -5
- package/components/chart/_macro.spec.js +405 -0
- package/components/chart/bar-chart.js +2 -2
- package/components/chart/boxplot.js +37 -0
- package/components/chart/chart-constants.js +13 -0
- package/components/chart/chart.js +86 -46
- package/components/chart/columnrange-chart.js +94 -0
- package/components/chart/common-chart-options.js +28 -15
- package/components/chart/example-bar-chart-with-annotations.njk +1 -1
- package/components/chart/example-bar-chart-with-point-range-and-reference-line-annotations.njk +95 -0
- package/components/chart/example-bar-with-confidence-levels.njk +71 -0
- package/components/chart/example-clustered-column-chart.njk +1 -3
- package/components/chart/example-column-chart-with-annotations.njk +1 -1
- package/components/chart/example-column-chart-with-range-annotations.njk +64 -0
- package/components/chart/example-column-chart-with-reference-line-annotations.njk +64 -0
- package/components/chart/example-column-with-confidence-levels.njk +61 -0
- package/components/chart/example-line-chart-with-annotations.njk +3 -3
- package/components/chart/example-line-chart-with-markers.njk +1 -1
- package/components/chart/example-line-chart-with-range-annotations-inside.njk +238 -0
- package/components/chart/example-line-chart-with-range-annotations-outside-left-right.njk +240 -0
- package/components/chart/example-line-chart-with-range-annotations-outside-top-bottom.njk +239 -0
- package/components/chart/example-line-chart-with-reference-line-annotations.njk +236 -0
- package/components/chart/example-scatter-chart.njk +1 -1
- package/components/chart/range-annotations-options.js +216 -0
- package/components/chart/reference-line-annotations-options.js +93 -0
- package/components/chart/scatter-chart.js +15 -0
- package/components/chart/specific-chart-options.js +1 -1
- package/components/chart/utilities.js +96 -0
- package/css/main.css +1 -1
- package/package.json +1 -1
- package/scripts/main.es5.js +1 -1
- package/scripts/main.js +1 -1
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
&__footnote-number {
|
|
28
|
-
|
|
28
|
+
// !important is necessary for some range annotation labels at mobile, otherwise
|
|
29
|
+
// the inline-styled block display takes precedence. This inline style is only
|
|
30
|
+
// applied in some cases - it seems to happen when the shaded area is narrower than the label width.
|
|
31
|
+
display: flex !important;
|
|
29
32
|
flex-shrink: 0;
|
|
30
33
|
flex-grow: 0;
|
|
31
34
|
align-items: center;
|
|
@@ -72,6 +75,39 @@
|
|
|
72
75
|
font-size: 0.875rem; // 14px
|
|
73
76
|
color: var(--ons-color-grey-100);
|
|
74
77
|
}
|
|
78
|
+
|
|
79
|
+
&__boxplot-legend {
|
|
80
|
+
display: flex;
|
|
81
|
+
gap: 2rem;
|
|
82
|
+
font-size: 0.875rem; // 14px
|
|
83
|
+
padding-left: 1rem;
|
|
84
|
+
align-items: center;
|
|
85
|
+
|
|
86
|
+
&-item {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 0.5rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&-item {
|
|
93
|
+
&--uncertainty {
|
|
94
|
+
width: 12px;
|
|
95
|
+
height: 12px;
|
|
96
|
+
background-color: rgb(32 96 149 / 65%);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&--estimate {
|
|
100
|
+
width: 20px;
|
|
101
|
+
height: 3px;
|
|
102
|
+
border-radius: 2px;
|
|
103
|
+
background-color: #003c57;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&-label {
|
|
108
|
+
font-size: inherit;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
75
111
|
}
|
|
76
112
|
|
|
77
113
|
// This is a workaround to position the axis title to the left
|
|
@@ -88,3 +124,40 @@
|
|
|
88
124
|
.highcharts-a11y-proxy-group-legend button {
|
|
89
125
|
cursor: auto !important;
|
|
90
126
|
}
|
|
127
|
+
|
|
128
|
+
.ons-chart__range-annotation-label {
|
|
129
|
+
&--x {
|
|
130
|
+
padding: 0 1.25rem;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&--outside {
|
|
134
|
+
padding: 0;
|
|
135
|
+
overflow: visible !important;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&--right {
|
|
139
|
+
text-align: left !important;
|
|
140
|
+
padding-left: 0.3125rem;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&--left {
|
|
144
|
+
text-align: right !important;
|
|
145
|
+
padding-right: 0.3125rem;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&--top {
|
|
149
|
+
text-align: center !important;
|
|
150
|
+
padding-bottom: 0.3125rem;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
&--bottom {
|
|
154
|
+
text-align: center !important;
|
|
155
|
+
padding-top: 0.3125rem;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ons-chart__connector-line {
|
|
160
|
+
position: absolute;
|
|
161
|
+
border-top: 1px solid var(--ons-color-grey-100);
|
|
162
|
+
border-left: 1px solid var(--ons-color-grey-100);
|
|
163
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{% from "components/list/_macro.njk" import onsList %}
|
|
2
2
|
|
|
3
3
|
{% macro onsChart(params) %}
|
|
4
|
-
{% set supportedChartTypes = ['line', 'bar', 'column', 'scatter', 'area'] %}
|
|
5
|
-
{% set supportedChartTypesWithLine = ['column'] %}
|
|
4
|
+
{% set supportedChartTypes = ['line', 'bar', 'column', 'scatter', 'area', 'columnrange', 'boxplot'] %}
|
|
5
|
+
{% set supportedChartTypesWithLine = ['column', 'columnrange'] %}
|
|
6
|
+
{% set supportedChartTypesWithScatter = ['columnrange'] %}
|
|
6
7
|
|
|
7
8
|
{% if params.headingLevel and params.headingLevel >= 1 and params.headingLevel <= 4 %}
|
|
8
9
|
{% set headingLevel = params.headingLevel %}
|
|
@@ -15,7 +16,6 @@
|
|
|
15
16
|
{% set closingSubtitleTag = "</h" ~ (headingLevel + 1) ~ ">" %}
|
|
16
17
|
{% set openingDownloadTitleTag = "<h" ~ (headingLevel + 2) %}
|
|
17
18
|
{% set closingDownloadTitleTag = "</h" ~ (headingLevel + 2) ~ ">" %}
|
|
18
|
-
|
|
19
19
|
<div
|
|
20
20
|
data-highcharts-base-chart
|
|
21
21
|
data-highcharts-type="{{ params.chartType }}"
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
{% if params.yAxis.tickIntervalDesktop %}
|
|
42
42
|
data-highcharts-y-axis-tick-interval-desktop="{{ params.yAxis.tickIntervalDesktop }}"
|
|
43
43
|
{% endif %}
|
|
44
|
+
{% if params.estimateLineLabel %}
|
|
45
|
+
data-highcharts-estimate-line-label="{{ params.estimateLineLabel }}"
|
|
46
|
+
{% endif %}
|
|
47
|
+
{% if params.uncertaintyRangeLabel %}
|
|
48
|
+
data-highcharts-uncertainty-range-label="{{ params.uncertaintyRangeLabel }}"
|
|
49
|
+
{% endif %}
|
|
44
50
|
>
|
|
45
51
|
<figure class="ons-chart">
|
|
46
52
|
{{ openingTitleTag | safe }} class="ons-chart__title">{{ params.title }}{{ closingTitleTag | safe }}
|
|
@@ -49,6 +55,22 @@
|
|
|
49
55
|
{% if params.description %}
|
|
50
56
|
<p class="ons-u-vh">{{ params.description }}</p>
|
|
51
57
|
{% endif %}
|
|
58
|
+
{% if params.chartType == 'boxplot' and (params.estimateLineLabel or params.uncertaintyRangeLabel) and params.legend == true %}
|
|
59
|
+
<div class="ons-chart__boxplot-legend">
|
|
60
|
+
{% if params.uncertaintyRangeLabel %}
|
|
61
|
+
<div class="ons-chart__boxplot-legend-item">
|
|
62
|
+
<span class="ons-chart__boxplot-legend-item ons-chart__boxplot-legend-item--uncertainty"></span>
|
|
63
|
+
<span class="ons-chart__boxplot-legend-label">{{ params.uncertaintyRangeLabel }}</span>
|
|
64
|
+
</div>
|
|
65
|
+
{% endif %}
|
|
66
|
+
{% if params.estimateLineLabel %}
|
|
67
|
+
<div class="ons-chart__boxplot-legend-item">
|
|
68
|
+
<span class="ons-chart__boxplot-legend-item ons-chart__boxplot-legend-item--estimate"></span>
|
|
69
|
+
<span class="ons-chart__boxplot-legend-label">{{ params.estimateLineLabel }}</span>
|
|
70
|
+
</div>
|
|
71
|
+
{% endif %}
|
|
72
|
+
</div>
|
|
73
|
+
{% endif %}
|
|
52
74
|
{% if params.chartType in supportedChartTypes %}
|
|
53
75
|
<div data-highcharts-chart></div>
|
|
54
76
|
{% else %}
|
|
@@ -65,6 +87,20 @@
|
|
|
65
87
|
{{ annotation.text }}
|
|
66
88
|
</li>
|
|
67
89
|
{% endfor %}
|
|
90
|
+
{% for rangeAnnotation in params.rangeAnnotations %}
|
|
91
|
+
<li class="ons-chart__footnote_item">
|
|
92
|
+
<span class="ons-chart__footnote-number">{{ loop.index + params.annotations | length }}</span>
|
|
93
|
+
{{ rangeAnnotation.text }}
|
|
94
|
+
</li>
|
|
95
|
+
{% endfor %}
|
|
96
|
+
{% for referenceLineAnnotation in params.referenceLineAnnotations %}
|
|
97
|
+
<li class="ons-chart__footnote_item">
|
|
98
|
+
<span class="ons-chart__footnote-number"
|
|
99
|
+
>{{ loop.index + params.annotations | length + params.rangeAnnotations | length }}</span
|
|
100
|
+
>
|
|
101
|
+
{{ referenceLineAnnotation.text }}
|
|
102
|
+
</li>
|
|
103
|
+
{% endfor %}
|
|
68
104
|
</ul>
|
|
69
105
|
{% if params.caption %}
|
|
70
106
|
<figcaption class="ons-chart__caption">{{ params.caption }}</figcaption>
|
|
@@ -95,16 +131,29 @@
|
|
|
95
131
|
"enabled": item.dataLabels if item.dataLabels else false
|
|
96
132
|
},
|
|
97
133
|
"connectNulls": item.connectNulls if item.connectNulls else false,
|
|
98
|
-
"type": item.type if item.type and item.type == 'line' and params.chartType in supportedChartTypesWithLine else params.chartType
|
|
134
|
+
"type": item.type if item.type and (item.type == 'line' and params.chartType in supportedChartTypesWithLine) or (item.type == 'scatter' and params.chartType in supportedChartTypesWithScatter) else params.chartType
|
|
99
135
|
}
|
|
100
136
|
%}
|
|
101
137
|
{# Use `set` tag to avoid printing the return value of extend #}
|
|
102
138
|
{% set _ = extend(series, seriesItem) %}
|
|
103
139
|
{% endfor %}
|
|
140
|
+
{# Set the legend value to true by default #}
|
|
141
|
+
{% set legendValue = true %}
|
|
142
|
+
{% if params.legend is defined %}
|
|
143
|
+
{# if a legend parameter has been provided, check that it is a boolean #}
|
|
144
|
+
{% if params.legend == true or params.legend == false %}
|
|
145
|
+
{# legend value is a boolean - use the value passed in #}
|
|
146
|
+
{% set legendValue = params.legend %}
|
|
147
|
+
{% endif %}
|
|
148
|
+
{% endif %}
|
|
104
149
|
{%
|
|
105
150
|
set config = {
|
|
151
|
+
"chart": {
|
|
152
|
+
"type": params.chartType,
|
|
153
|
+
"inverted": params.isChartInverted if params.isChartInverted == true else false
|
|
154
|
+
},
|
|
106
155
|
"legend": {
|
|
107
|
-
"enabled" :
|
|
156
|
+
"enabled" : legendValue
|
|
108
157
|
},
|
|
109
158
|
"yAxis": {
|
|
110
159
|
"title": {
|
|
@@ -139,6 +188,16 @@
|
|
|
139
188
|
{{ params.annotations | tojson }}
|
|
140
189
|
</script>
|
|
141
190
|
{% endif %}
|
|
191
|
+
{% if params.rangeAnnotations %}
|
|
192
|
+
<script type="application/json" data-highcharts-range-annotations--{{ params.id }}>
|
|
193
|
+
{{ params.rangeAnnotations | tojson }}
|
|
194
|
+
</script>
|
|
195
|
+
{% endif %}
|
|
196
|
+
{% if params.referenceLineAnnotations %}
|
|
197
|
+
<script type="application/json" data-highcharts-reference-line-annotations--{{ params.id }}>
|
|
198
|
+
{{ params.referenceLineAnnotations | tojson }}
|
|
199
|
+
</script>
|
|
200
|
+
{% endif %}
|
|
142
201
|
<!-- prettier-ignore-end -->
|
|
143
202
|
</div>
|
|
144
203
|
{% endmacro %}
|
|
@@ -7,6 +7,7 @@ import { renderComponent } from '../../tests/helpers/rendering';
|
|
|
7
7
|
import {
|
|
8
8
|
EXAMPLE_LINE_CHART_REQUIRED_PARAMS,
|
|
9
9
|
EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS,
|
|
10
|
+
EXAMPLE_LINE_CHART_WITH_LEGEND_UNSET_PARAMS,
|
|
10
11
|
EXAMPLE_BAR_CHART_PARAMS,
|
|
11
12
|
EXAMPLE_BAR_CHART_WITH_PERCENTAGE_HEIGHT_PARAMS,
|
|
12
13
|
EXAMPLE_COLUMN_CHART_PARAMS,
|
|
@@ -16,7 +17,14 @@ import {
|
|
|
16
17
|
EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
17
18
|
EXAMPLE_SCATTER_CHART_PARAMS,
|
|
18
19
|
EXAMPLE_AREA_CHART_PARAMS,
|
|
20
|
+
EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
21
|
+
EXAMPLE_COLUMN_RANGE_CHART_PARAMS,
|
|
19
22
|
EXAMPLE_INVALID_CHART_PARAMS,
|
|
23
|
+
EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_ON_X_AXIS_PARAMS,
|
|
24
|
+
EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_ON_Y_AXIS_WITH_LABEL_WIDTH_PARAMS,
|
|
25
|
+
EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_WITH_LABEL_INSIDE_PARAMS,
|
|
26
|
+
EXAMPLE_LINE_CHART_WITH_REFERENCE_LINE_ANNOTATIONS_PARAMS,
|
|
27
|
+
EXAMPLE_LINE_CHART_WITH_MIXED_ANNOTATION_TYPES_PARAMS,
|
|
20
28
|
} from './_test-examples';
|
|
21
29
|
|
|
22
30
|
describe('Macro: Chart', () => {
|
|
@@ -240,6 +248,55 @@ describe('Macro: Chart', () => {
|
|
|
240
248
|
});
|
|
241
249
|
});
|
|
242
250
|
});
|
|
251
|
+
|
|
252
|
+
describe('GIVEN: Params: Legend', () => {
|
|
253
|
+
describe('WHEN: legend parameter is provided and set to true', () => {
|
|
254
|
+
const $ = cheerio.load(
|
|
255
|
+
renderComponent('chart', {
|
|
256
|
+
...EXAMPLE_LINE_CHART_WITH_LEGEND_UNSET_PARAMS,
|
|
257
|
+
legend: true,
|
|
258
|
+
}),
|
|
259
|
+
);
|
|
260
|
+
test('THEN: it renders the legend', () => {
|
|
261
|
+
const configScript = $(`script[data-highcharts-config--line-chart-legend-tests-123]`).html();
|
|
262
|
+
expect(configScript).toContain('"legend":{"enabled":true}');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe('WHEN: legend parameter is provided and set to false', () => {
|
|
267
|
+
const $ = cheerio.load(
|
|
268
|
+
renderComponent('chart', {
|
|
269
|
+
...EXAMPLE_LINE_CHART_WITH_LEGEND_UNSET_PARAMS,
|
|
270
|
+
legend: false,
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
test('THEN: it does not render the legend', () => {
|
|
274
|
+
const configScript = $(`script[data-highcharts-config--line-chart-legend-tests-123]`).html();
|
|
275
|
+
expect(configScript).toContain('"legend":{"enabled":false}');
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe('WHEN: legend parameter is not provided', () => {
|
|
280
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_LEGEND_UNSET_PARAMS));
|
|
281
|
+
test('THEN: it renders the legend', () => {
|
|
282
|
+
const configScript = $(`script[data-highcharts-config--line-chart-legend-tests-123]`).html();
|
|
283
|
+
expect(configScript).toContain('"legend":{"enabled":true}');
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('WHEN: legend parameter is provided but is not a boolean', () => {
|
|
288
|
+
const $ = cheerio.load(
|
|
289
|
+
renderComponent('chart', {
|
|
290
|
+
...EXAMPLE_LINE_CHART_WITH_LEGEND_UNSET_PARAMS,
|
|
291
|
+
legend: 'false',
|
|
292
|
+
}),
|
|
293
|
+
);
|
|
294
|
+
test('THEN: it renders the legend', () => {
|
|
295
|
+
const configScript = $(`script[data-highcharts-config--line-chart-legend-tests-123]`).html();
|
|
296
|
+
expect(configScript).toContain('"legend":{"enabled":true}');
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
});
|
|
243
300
|
});
|
|
244
301
|
|
|
245
302
|
describe('FOR: Bar Chart', () => {
|
|
@@ -879,6 +936,236 @@ describe('Macro: Chart', () => {
|
|
|
879
936
|
});
|
|
880
937
|
});
|
|
881
938
|
|
|
939
|
+
describe('FOR: Boxplot Chart', () => {
|
|
940
|
+
describe('GIVEN: Params: required', () => {
|
|
941
|
+
describe('WHEN: required params are provided', () => {
|
|
942
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BOXPLOT_CHART_PARAMS));
|
|
943
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
944
|
+
|
|
945
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
946
|
+
const results = await axe($.html());
|
|
947
|
+
expect(results).toHaveNoViolations();
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
test('THEN: it includes at least one boxplot series', () => {
|
|
951
|
+
expect(configScript).toContain('"type":"boxplot"');
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
test('THEN: it renders the chart container with correct data attributes', () => {
|
|
955
|
+
const chartContainer = $('[data-highcharts-base-chart]');
|
|
956
|
+
expect(chartContainer.attr('data-highcharts-type')).toBe('boxplot');
|
|
957
|
+
expect(chartContainer.attr('data-highcharts-theme')).toBe('primary');
|
|
958
|
+
expect(chartContainer.attr('data-highcharts-title')).toBe('Example Boxplot Chart');
|
|
959
|
+
expect(chartContainer.attr('data-highcharts-id')).toBe('uuid');
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
test('THEN: it includes the Highcharts JSON config', () => {
|
|
963
|
+
expect(configScript).toContain('"text":"Years"');
|
|
964
|
+
expect(configScript).toContain('"text":"Percentage of GDP"');
|
|
965
|
+
});
|
|
966
|
+
});
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
describe('GIVEN: Params: Legend', () => {
|
|
970
|
+
describe('WHEN: both labels are provided and legend is enabled', () => {
|
|
971
|
+
const $ = cheerio.load(
|
|
972
|
+
renderComponent('chart', {
|
|
973
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
974
|
+
estimateLineLabel: 'Estimated value',
|
|
975
|
+
uncertaintyRangeLabel: '95% Confidence Interval',
|
|
976
|
+
legend: true,
|
|
977
|
+
}),
|
|
978
|
+
);
|
|
979
|
+
|
|
980
|
+
test('THEN: it renders the boxplot legend container', () => {
|
|
981
|
+
const legendContainer = $('.ons-chart__boxplot-legend');
|
|
982
|
+
expect(legendContainer.length).toBe(1);
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
test('THEN: it includes the estimate line legend item', () => {
|
|
986
|
+
const estimateLabel = $('.ons-chart__boxplot-legend-label').filter((_, el) => $(el).text().includes('Estimated value'));
|
|
987
|
+
expect(estimateLabel.length).toBe(1);
|
|
988
|
+
|
|
989
|
+
const estimateSwatch = $('.ons-chart__boxplot-legend-item--estimate');
|
|
990
|
+
expect(estimateSwatch.length).toBe(1);
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
test('THEN: it includes the uncertainty range legend item', () => {
|
|
994
|
+
const uncertaintyLabel = $('.ons-chart__boxplot-legend-label').filter((_, el) =>
|
|
995
|
+
$(el).text().includes('95% Confidence Interval'),
|
|
996
|
+
);
|
|
997
|
+
expect(uncertaintyLabel.length).toBe(1);
|
|
998
|
+
|
|
999
|
+
const uncertaintySwatch = $('.ons-chart__boxplot-legend-item--uncertainty');
|
|
1000
|
+
expect(uncertaintySwatch.length).toBe(1);
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
describe('WHEN: only estimateLineLabel is provided', () => {
|
|
1005
|
+
const $ = cheerio.load(
|
|
1006
|
+
renderComponent('chart', {
|
|
1007
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
1008
|
+
estimateLineLabel: 'Estimated only',
|
|
1009
|
+
legend: true,
|
|
1010
|
+
}),
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
test('THEN: it renders only the estimate legend item', () => {
|
|
1014
|
+
expect($('.ons-chart__boxplot-legend-item--estimate').length).toBe(1);
|
|
1015
|
+
expect($('.ons-chart__boxplot-legend-item--uncertainty').length).toBe(0);
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
describe('WHEN: only uncertaintyRangeLabel is provided', () => {
|
|
1019
|
+
const $ = cheerio.load(
|
|
1020
|
+
renderComponent('chart', {
|
|
1021
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
1022
|
+
uncertaintyRangeLabel: 'Uncertainty only',
|
|
1023
|
+
legend: true,
|
|
1024
|
+
}),
|
|
1025
|
+
);
|
|
1026
|
+
test('THEN: it renders only the uncertainty legend item', () => {
|
|
1027
|
+
expect($('.ons-chart__boxplot-legend-item--estimate').length).toBe(0);
|
|
1028
|
+
expect($('.ons-chart__boxplot-legend-item--uncertainty').length).toBe(1);
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
describe('WHEN: estimate and uncertainty labels are provided but legend is false', () => {
|
|
1032
|
+
const $ = cheerio.load(
|
|
1033
|
+
renderComponent('chart', {
|
|
1034
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
1035
|
+
estimateLineLabel: 'Estimated value',
|
|
1036
|
+
uncertaintyRangeLabel: '95% Confidence Interval',
|
|
1037
|
+
legend: false,
|
|
1038
|
+
}),
|
|
1039
|
+
);
|
|
1040
|
+
|
|
1041
|
+
test('THEN: it does NOT render the boxplot legend container', () => {
|
|
1042
|
+
expect($('.ons-chart__boxplot-legend').length).toBe(0);
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
test('THEN: it does NOT render any custom legend items', () => {
|
|
1046
|
+
expect($('.ons-chart__boxplot-legend-item--estimate').length).toBe(0);
|
|
1047
|
+
expect($('.ons-chart__boxplot-legend-item--uncertainty').length).toBe(0);
|
|
1048
|
+
});
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
describe('GIVEN: Params: Description', () => {
|
|
1053
|
+
describe('WHEN: description is provided', () => {
|
|
1054
|
+
const accessibleDescription = 'An accessible description for screen readers.';
|
|
1055
|
+
const $ = cheerio.load(
|
|
1056
|
+
renderComponent('chart', {
|
|
1057
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
1058
|
+
description: accessibleDescription,
|
|
1059
|
+
}),
|
|
1060
|
+
);
|
|
1061
|
+
|
|
1062
|
+
test('THEN: it renders the description for accessibility', () => {
|
|
1063
|
+
expect($('.ons-u-vh').text()).toBe(accessibleDescription);
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
describe('GIVEN: Params: Estimate Line and Uncertainty Range Labels', () => {
|
|
1069
|
+
describe('WHEN: both labels are provided', () => {
|
|
1070
|
+
const $ = cheerio.load(
|
|
1071
|
+
renderComponent('chart', {
|
|
1072
|
+
...EXAMPLE_BOXPLOT_CHART_PARAMS,
|
|
1073
|
+
estimateLineLabel: 'Estimated value',
|
|
1074
|
+
uncertaintyRangeLabel: '95% Confidence Interval',
|
|
1075
|
+
}),
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
test('THEN: it sets the estimate line label as a data attribute', () => {
|
|
1079
|
+
const baseChart = $('[data-highcharts-base-chart]');
|
|
1080
|
+
expect(baseChart.attr('data-highcharts-estimate-line-label')).toBe('Estimated value');
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
test('THEN: it sets the uncertainty range label as a data attribute', () => {
|
|
1084
|
+
const baseChart = $('[data-highcharts-base-chart]');
|
|
1085
|
+
expect(baseChart.attr('data-highcharts-uncertainty-range-label')).toBe('95% Confidence Interval');
|
|
1086
|
+
});
|
|
1087
|
+
});
|
|
1088
|
+
});
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
describe('FOR: Column Range Chart', () => {
|
|
1092
|
+
describe('GIVEN: Params: Required', () => {
|
|
1093
|
+
describe('WHEN: required params are provided', () => {
|
|
1094
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_RANGE_CHART_PARAMS));
|
|
1095
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
1096
|
+
|
|
1097
|
+
test('THEN: it passes jest-axe accessibility checks', async () => {
|
|
1098
|
+
const results = await axe($.html());
|
|
1099
|
+
expect(results).toHaveNoViolations();
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
test('THEN: it renders with correct chart metadata attributes', () => {
|
|
1103
|
+
const baseChart = $('[data-highcharts-base-chart]');
|
|
1104
|
+
expect(baseChart.attr('data-highcharts-type')).toBe('columnrange');
|
|
1105
|
+
expect(baseChart.attr('data-highcharts-theme')).toBe('primary');
|
|
1106
|
+
expect(baseChart.attr('data-highcharts-title')).toBe(
|
|
1107
|
+
'Food stores showed a strong rise on the month, while non-food stores fell',
|
|
1108
|
+
);
|
|
1109
|
+
expect(baseChart.attr('data-highcharts-id')).toBe('uuid');
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
test('THEN: it includes columnrange and scatter series types', () => {
|
|
1113
|
+
expect(configScript).toContain('"type":"columnrange"');
|
|
1114
|
+
expect(configScript).toContain('"type":"scatter"');
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
describe('GIVEN: Params: isChartInverted', () => {
|
|
1118
|
+
describe('WHEN: isChartInverted parameter is provided and set to true', () => {
|
|
1119
|
+
const $ = cheerio.load(
|
|
1120
|
+
renderComponent('chart', {
|
|
1121
|
+
...EXAMPLE_COLUMN_RANGE_CHART_PARAMS,
|
|
1122
|
+
isChartInverted: true,
|
|
1123
|
+
}),
|
|
1124
|
+
);
|
|
1125
|
+
test('THEN: it sets isChartInverted to true', () => {
|
|
1126
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
1127
|
+
expect(configScript).toContain('"chart":{"type":"columnrange","inverted":true}');
|
|
1128
|
+
});
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
describe('WHEN: isChartInverted parameter is provided and set to false', () => {
|
|
1132
|
+
const $ = cheerio.load(
|
|
1133
|
+
renderComponent('chart', {
|
|
1134
|
+
...EXAMPLE_COLUMN_RANGE_CHART_PARAMS,
|
|
1135
|
+
isChartInverted: false,
|
|
1136
|
+
}),
|
|
1137
|
+
);
|
|
1138
|
+
test('THEN: it sets isChartInverted to false', () => {
|
|
1139
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
1140
|
+
expect(configScript).toContain('"chart":{"type":"columnrange","inverted":false}');
|
|
1141
|
+
});
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
describe('WHEN: isChartInverted parameter is not provided', () => {
|
|
1145
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_RANGE_CHART_PARAMS));
|
|
1146
|
+
test('THEN: it sets isChartInverted to false', () => {
|
|
1147
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
1148
|
+
expect(configScript).toContain('"chart":{"type":"columnrange","inverted":false}');
|
|
1149
|
+
});
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
describe('WHEN: isChartInverted parameter is provided but is not a boolean', () => {
|
|
1153
|
+
const $ = cheerio.load(
|
|
1154
|
+
renderComponent('chart', {
|
|
1155
|
+
...EXAMPLE_COLUMN_RANGE_CHART_PARAMS,
|
|
1156
|
+
isChartInverted: 'false',
|
|
1157
|
+
}),
|
|
1158
|
+
);
|
|
1159
|
+
test('THEN: it sets isChartInverted to false', () => {
|
|
1160
|
+
const configScript = $(`script[data-highcharts-config--uuid]`).html();
|
|
1161
|
+
expect(configScript).toContain('"chart":{"type":"columnrange","inverted":false}');
|
|
1162
|
+
});
|
|
1163
|
+
});
|
|
1164
|
+
});
|
|
1165
|
+
});
|
|
1166
|
+
});
|
|
1167
|
+
});
|
|
1168
|
+
|
|
882
1169
|
describe('FOR: Invalid Chart', () => {
|
|
883
1170
|
describe('GIVEN: Invalid chart type', () => {
|
|
884
1171
|
describe('WHEN: an invalid chart type is provided', () => {
|
|
@@ -919,4 +1206,122 @@ describe('Macro: Chart', () => {
|
|
|
919
1206
|
});
|
|
920
1207
|
});
|
|
921
1208
|
});
|
|
1209
|
+
|
|
1210
|
+
describe('FOR: Line chart with range annotation on the x axis', () => {
|
|
1211
|
+
describe('GIVEN: Params: Range annotations', () => {
|
|
1212
|
+
describe('WHEN: range annotations params are provided', () => {
|
|
1213
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_ON_X_AXIS_PARAMS));
|
|
1214
|
+
|
|
1215
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
1216
|
+
const results = await axe($.html());
|
|
1217
|
+
expect(results).toHaveNoViolations();
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
test('THEN: it includes the range annotations JSON config', () => {
|
|
1221
|
+
const configScript = $(`script[data-highcharts-range-annotations--line-chart-range-annotations-x-axis-123]`).html();
|
|
1222
|
+
expect(configScript).toContain('"text":"A test x axis range annotation"');
|
|
1223
|
+
expect(configScript).toContain('"range":{"axisValue1":10,"axisValue2":15}');
|
|
1224
|
+
expect(configScript).toContain('"axis":"x"');
|
|
1225
|
+
expect(configScript).toContain('"labelOffsetX":150');
|
|
1226
|
+
expect(configScript).toContain('"labelOffsetY":0');
|
|
1227
|
+
});
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
describe('FOR: Line chart with range annotation on the y axis with label width', () => {
|
|
1233
|
+
describe('GIVEN: Params: Range annotations', () => {
|
|
1234
|
+
describe('WHEN: range annotations params are provided', () => {
|
|
1235
|
+
const $ = cheerio.load(
|
|
1236
|
+
renderComponent('chart', EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_ON_Y_AXIS_WITH_LABEL_WIDTH_PARAMS),
|
|
1237
|
+
);
|
|
1238
|
+
|
|
1239
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
1240
|
+
const results = await axe($.html());
|
|
1241
|
+
expect(results).toHaveNoViolations();
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
test('THEN: it includes the range annotations JSON config', () => {
|
|
1245
|
+
const configScript = $(`script[data-highcharts-range-annotations--line-chart-range-annotations-y-axis-123]`).html();
|
|
1246
|
+
expect(configScript).toContain('"text":"A test y axis range annotation with a label width of 250px"');
|
|
1247
|
+
expect(configScript).toContain('"axis":"y"');
|
|
1248
|
+
expect(configScript).toContain('"labelWidth":250');
|
|
1249
|
+
});
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
describe('FOR: Line chart with range annotation with the label inside', () => {
|
|
1255
|
+
describe('GIVEN: Params: Range annotations', () => {
|
|
1256
|
+
describe('WHEN: range annotations params are provided', () => {
|
|
1257
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_RANGE_ANNOTATION_WITH_LABEL_INSIDE_PARAMS));
|
|
1258
|
+
|
|
1259
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
1260
|
+
const results = await axe($.html());
|
|
1261
|
+
expect(results).toHaveNoViolations();
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
test('THEN: it includes the range annotations JSON config', () => {
|
|
1265
|
+
const configScript = $(
|
|
1266
|
+
`script[data-highcharts-range-annotations--line-chart-range-annotations-label-inside-123]`,
|
|
1267
|
+
).html();
|
|
1268
|
+
expect(configScript).toContain('"text":"A test y axis range annotation with the label inside"');
|
|
1269
|
+
expect(configScript).toContain('"axis":"y"');
|
|
1270
|
+
expect(configScript).toContain('"labelInside":true');
|
|
1271
|
+
});
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
describe('FOR: Line chart with reference line annotations', () => {
|
|
1277
|
+
describe('GIVEN: Params: Reference line annotations', () => {
|
|
1278
|
+
describe('WHEN: reference line annotations params are provided', () => {
|
|
1279
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_REFERENCE_LINE_ANNOTATIONS_PARAMS));
|
|
1280
|
+
|
|
1281
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
1282
|
+
const results = await axe($.html());
|
|
1283
|
+
expect(results).toHaveNoViolations();
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
test('THEN: it includes the reference line annotations JSON config', () => {
|
|
1287
|
+
const configScript = $(
|
|
1288
|
+
`script[data-highcharts-reference-line-annotations--line-chart-reference-line-annotations-123]`,
|
|
1289
|
+
).html();
|
|
1290
|
+
expect(configScript).toContain('"text":"A test x axis reference line annotation"');
|
|
1291
|
+
expect(configScript).toContain('"value":34');
|
|
1292
|
+
expect(configScript).toContain('"axis":"x"');
|
|
1293
|
+
expect(configScript).toContain('"text":"A test y axis reference line annotation"');
|
|
1294
|
+
expect(configScript).toContain('"value":12');
|
|
1295
|
+
expect(configScript).toContain('"axis":"y"');
|
|
1296
|
+
expect(configScript).toContain('"labelWidth":100');
|
|
1297
|
+
});
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
describe('FOR: Line chart with mixed annotation types', () => {
|
|
1303
|
+
describe('GIVEN: Params: Mixed annotations', () => {
|
|
1304
|
+
describe('WHEN: mixed annotations params are provided', () => {
|
|
1305
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_MIXED_ANNOTATION_TYPES_PARAMS));
|
|
1306
|
+
|
|
1307
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
1308
|
+
const results = await axe($.html());
|
|
1309
|
+
expect(results).toHaveNoViolations();
|
|
1310
|
+
});
|
|
1311
|
+
|
|
1312
|
+
test('THEN: it renders the footnotes sequentially', () => {
|
|
1313
|
+
expect($('.ons-chart__footnotes').text()).toContain('1');
|
|
1314
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test point annotation');
|
|
1315
|
+
expect($('.ons-chart__footnotes').text()).toContain('2');
|
|
1316
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test x axis range annotation');
|
|
1317
|
+
expect($('.ons-chart__footnotes').text()).toContain('3');
|
|
1318
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test y axis range annotation with the label inside');
|
|
1319
|
+
expect($('.ons-chart__footnotes').text()).toContain('4');
|
|
1320
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test x axis reference line annotation');
|
|
1321
|
+
expect($('.ons-chart__footnotes').text()).toContain('5');
|
|
1322
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test y axis reference line annotation');
|
|
1323
|
+
});
|
|
1324
|
+
});
|
|
1325
|
+
});
|
|
1326
|
+
});
|
|
922
1327
|
});
|
|
@@ -85,8 +85,8 @@ class BarChart {
|
|
|
85
85
|
// Get the actual width of the data label
|
|
86
86
|
const labelWidth = point.dataLabel && point.dataLabel.getBBox().width;
|
|
87
87
|
// Move the data labels inside the bar if the bar is wider than the label plus some padding
|
|
88
|
-
if (series.type == '
|
|
89
|
-
// If we have a bar chart with
|
|
88
|
+
if (series.type == 'scatter') {
|
|
89
|
+
// If we have a bar chart with confidence levels, exit early for the scatter series
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
if (point.shapeArgs.height > labelWidth + 20) {
|