@ons/design-system 72.5.0 → 72.6.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 +51 -0
- package/components/chart/_macro.njk +27 -3
- package/components/chart/_macro.spec.js +388 -0
- package/components/chart/annotations-options.js +78 -0
- package/components/chart/bar-chart.js +6 -2
- package/components/chart/chart.js +111 -26
- package/components/chart/column-chart.js +2 -2
- package/components/chart/common-chart-options.js +97 -50
- package/components/chart/example-bar-chart-with-annotations.njk +62 -0
- package/components/chart/example-bar-chart.njk +1 -0
- package/components/chart/example-bar-with-line-chart.njk +64 -0
- package/components/chart/example-clustered-column-chart.njk +3 -1
- package/components/chart/example-column-chart-with-annotations.njk +62 -0
- package/components/chart/example-column-chart.njk +3 -1
- package/components/chart/example-column-with-line-chart.njk +62 -0
- package/components/chart/example-line-chart-with-annotations.njk +235 -0
- package/components/chart/example-line-chart.njk +4 -2
- package/components/chart/example-stacked-column-chart.njk +3 -1
- package/components/chart/line-chart.js +2 -7
- package/components/hero/_hero.scss +31 -0
- package/components/hero/_macro.njk +20 -9
- package/components/hero/_macro.spec.js +94 -0
- package/components/hero/example-hero-grey.njk +8 -0
- package/components/icon/_macro.njk +1 -1
- package/components/pagination/_pagination.scss +7 -1
- package/components/summary/_macro.njk +1 -1
- package/components/summary/_macro.spec.js +6 -0
- package/components/table-of-contents/_macro.njk +40 -0
- package/components/table-of-contents/_macro.spec.js +72 -0
- package/components/table-of-contents/_table-of-contents.scss +11 -0
- package/components/table-of-contents/example-table-of-contents-related-links-with-button.njk +60 -0
- package/css/main.css +1 -1
- package/js/cookies-functions.js +11 -6
- package/js/cookies-functions.spec.js +44 -0
- package/package.json +1 -1
- package/scripts/main.es5.js +1 -1
- package/scripts/main.js +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
.ons-chart {
|
|
2
2
|
margin: 0;
|
|
3
|
+
container-type: inline-size;
|
|
4
|
+
max-width: $grid-max-width;
|
|
3
5
|
|
|
4
6
|
&__download-title {
|
|
5
7
|
@extend .ons-u-pt-l;
|
|
@@ -21,6 +23,55 @@
|
|
|
21
23
|
line-height: 1.2rem;
|
|
22
24
|
color: var(--ons-color-grey-75);
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
&__footnote-number {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
flex-grow: 0;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
min-width: 1.125rem; // 18px
|
|
34
|
+
min-height: 1.125rem; // 18px
|
|
35
|
+
padding: 0.2143em; // 3px;
|
|
36
|
+
aspect-ratio: 1;
|
|
37
|
+
border: 1px solid var(--ons-color-grey-100);
|
|
38
|
+
border-radius: 50%;
|
|
39
|
+
font-size: 0.875rem; // 14px
|
|
40
|
+
line-height: 0;
|
|
41
|
+
background-color: var(--ons-color-white);
|
|
42
|
+
color: var(--ons-color-grey-100);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Override Highcharts styling */
|
|
46
|
+
&__footnote-number span {
|
|
47
|
+
position: static !important;
|
|
48
|
+
transform-origin: 0 0 !important;
|
|
49
|
+
font-size: inherit !important;
|
|
50
|
+
color: inherit !important;
|
|
51
|
+
top: 0 !important;
|
|
52
|
+
left: 0 !important;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&__footnotes {
|
|
56
|
+
list-style: none;
|
|
57
|
+
padding: 0;
|
|
58
|
+
margin: 0 0 1rem;
|
|
59
|
+
|
|
60
|
+
// We need to use a container query here in order to match the responsive rules for Highcharts
|
|
61
|
+
// which is based on the width that the chart renders not the viewport
|
|
62
|
+
// Update the breakpoint value here if the Highcharts responsive rules change
|
|
63
|
+
@container (min-width: 601px) {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&__footnote_item {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: 0.5rem;
|
|
72
|
+
font-size: 0.875rem; // 14px
|
|
73
|
+
color: var(--ons-color-grey-100);
|
|
74
|
+
}
|
|
24
75
|
}
|
|
25
76
|
|
|
26
77
|
// This is a workaround to position the axis title to the left
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
data-highcharts-id="{{ params.id }}"
|
|
24
24
|
{% if params.useStackedLayout %}data-highcharts-use-stacked-layout="{{ params.useStackedLayout }}"{% endif %}
|
|
25
25
|
id="{{ params.id }}"
|
|
26
|
+
{% if params.percentageHeightDesktop and params.chartType != 'bar' %}
|
|
27
|
+
data-highcharts-percentage-height-desktop="{{ params.percentageHeightDesktop }}"
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% if params.percentageHeightMobile and params.chartType != 'bar' %}
|
|
30
|
+
data-highcharts-percentage-height-mobile="{{ params.percentageHeightMobile }}"
|
|
31
|
+
{% endif %}
|
|
26
32
|
>
|
|
27
33
|
{% if params.chartType in supportedChartTypes %}
|
|
28
34
|
<figure class="ons-chart">
|
|
@@ -33,6 +39,18 @@
|
|
|
33
39
|
<p class="ons-u-vh">{{ params.description }}</p>
|
|
34
40
|
{% endif %}
|
|
35
41
|
<div data-highcharts-chart></div>
|
|
42
|
+
{#
|
|
43
|
+
Footnotes for the annotations at mobile
|
|
44
|
+
Hidden from screen readers because the full text will be read out where they appear in the chart
|
|
45
|
+
#}
|
|
46
|
+
<ul class="ons-chart__footnotes" aria-hidden="true">
|
|
47
|
+
{% for annotation in params.annotations %}
|
|
48
|
+
<li class="ons-chart__footnote_item">
|
|
49
|
+
<span class="ons-chart__footnote-number">{{ loop.index }}</span>
|
|
50
|
+
{{ annotation.text }}
|
|
51
|
+
</li>
|
|
52
|
+
{% endfor %}
|
|
53
|
+
</ul>
|
|
36
54
|
{% if params.caption %}
|
|
37
55
|
<figcaption class="ons-chart__caption">{{ params.caption }}</figcaption>
|
|
38
56
|
{% endif %}
|
|
@@ -60,14 +78,15 @@
|
|
|
60
78
|
},
|
|
61
79
|
"dataLabels": {
|
|
62
80
|
"enabled": item.dataLabels if item.dataLabels else false
|
|
63
|
-
}
|
|
81
|
+
},
|
|
82
|
+
"type": item.type if item.type and item.type == 'line' else params.chartType
|
|
64
83
|
})
|
|
65
84
|
%}
|
|
66
85
|
{% endfor %}
|
|
67
86
|
{%
|
|
68
87
|
set config = {
|
|
69
88
|
"legend": {
|
|
70
|
-
"enabled" : params.legend
|
|
89
|
+
"enabled" : params.legend if params.legend else true
|
|
71
90
|
},
|
|
72
91
|
"yAxis": {
|
|
73
92
|
"title": {
|
|
@@ -94,8 +113,13 @@
|
|
|
94
113
|
<!-- Set scripts to pass the config values as json to the javascript -->
|
|
95
114
|
<!-- prettier-ignore-start -->
|
|
96
115
|
<script type="application/json" data-highcharts-config--{{ params.id }}>
|
|
97
|
-
{{ config |
|
|
116
|
+
{{ config | tojson }}
|
|
98
117
|
</script>
|
|
118
|
+
{% if params.annotations %}
|
|
119
|
+
<script type="application/json" data-highcharts-annotations--{{ params.id }}>
|
|
120
|
+
{{ params.annotations | tojson }}
|
|
121
|
+
</script>
|
|
122
|
+
{% endif %}
|
|
99
123
|
<!-- prettier-ignore-end -->
|
|
100
124
|
</div>
|
|
101
125
|
{% endmacro %}
|
|
@@ -8,7 +8,13 @@ import {
|
|
|
8
8
|
EXAMPLE_LINE_CHART_REQUIRED_PARAMS,
|
|
9
9
|
EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS,
|
|
10
10
|
EXAMPLE_BAR_CHART_PARAMS,
|
|
11
|
+
EXAMPLE_BAR_CHART_WITH_PERCENTAGE_HEIGHT_PARAMS,
|
|
11
12
|
EXAMPLE_COLUMN_CHART_PARAMS,
|
|
13
|
+
EXAMPLE_LINE_CHART_WITH_ANNOTATIONS_PARAMS,
|
|
14
|
+
EXAMPLE_BAR_CHART_WITH_ANNOTATIONS_PARAMS,
|
|
15
|
+
EXAMPLE_COLUMN_CHART_WITH_ANNOTATIONS_PARAMS,
|
|
16
|
+
EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
|
|
17
|
+
EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
12
18
|
} from './_test-examples';
|
|
13
19
|
|
|
14
20
|
describe('Macro: Chart', () => {
|
|
@@ -119,6 +125,24 @@ describe('Macro: Chart', () => {
|
|
|
119
125
|
});
|
|
120
126
|
});
|
|
121
127
|
|
|
128
|
+
describe('GIVEN: Params: Percentage Height Desktop', () => {
|
|
129
|
+
describe('WHEN: percentage height desktop is provided', () => {
|
|
130
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS));
|
|
131
|
+
test('THEN: it includes correct percentage height desktop', () => {
|
|
132
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-desktop')).toBe('50');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('GIVEN: Params: Percentage Height Mobile', () => {
|
|
138
|
+
describe('WHEN: percentage height mobile is provided', () => {
|
|
139
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_CONFIG_PARAMS));
|
|
140
|
+
test('THEN: it includes correct percentage height mobile', () => {
|
|
141
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-mobile')).toBe('120');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
122
146
|
describe('GIVEN: Params: Caption', () => {
|
|
123
147
|
describe('WHEN: caption is provided', () => {
|
|
124
148
|
const $ = cheerio.load(
|
|
@@ -229,6 +253,24 @@ describe('Macro: Chart', () => {
|
|
|
229
253
|
});
|
|
230
254
|
});
|
|
231
255
|
|
|
256
|
+
describe('GIVEN: Params: Percentage Height Desktop', () => {
|
|
257
|
+
describe('WHEN: percentage height desktop is provided', () => {
|
|
258
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_CHART_WITH_PERCENTAGE_HEIGHT_PARAMS));
|
|
259
|
+
test('THEN: it does not include percentage height desktop', () => {
|
|
260
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-desktop')).toBe(undefined);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('GIVEN: Params: Percentage Height Mobile', () => {
|
|
266
|
+
describe('WHEN: percentage height mobile is provided', () => {
|
|
267
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_CHART_WITH_PERCENTAGE_HEIGHT_PARAMS));
|
|
268
|
+
test('THEN: it does not include percentage height mobile', () => {
|
|
269
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-mobile')).toBe(undefined);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
232
274
|
describe('GIVEN: Params: Caption', () => {
|
|
233
275
|
describe('WHEN: caption is provided', () => {
|
|
234
276
|
const $ = cheerio.load(
|
|
@@ -358,6 +400,24 @@ describe('Macro: Chart', () => {
|
|
|
358
400
|
});
|
|
359
401
|
});
|
|
360
402
|
|
|
403
|
+
describe('GIVEN: Params: Percentage Height Desktop', () => {
|
|
404
|
+
describe('WHEN: percentage height desktop is provided', () => {
|
|
405
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_CHART_PARAMS));
|
|
406
|
+
test('THEN: it includes correct percentage height desktop', () => {
|
|
407
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-desktop')).toBe('50');
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
describe('GIVEN: Params: Percentage Height Mobile', () => {
|
|
413
|
+
describe('WHEN: percentage height mobile is provided', () => {
|
|
414
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_CHART_PARAMS));
|
|
415
|
+
test('THEN: it includes correct percentage height mobile', () => {
|
|
416
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-percentage-height-mobile')).toBe('120');
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
361
421
|
describe('GIVEN: Params: Caption', () => {
|
|
362
422
|
describe('WHEN: caption is provided', () => {
|
|
363
423
|
const $ = cheerio.load(
|
|
@@ -434,4 +494,332 @@ describe('Macro: Chart', () => {
|
|
|
434
494
|
});
|
|
435
495
|
});
|
|
436
496
|
});
|
|
497
|
+
|
|
498
|
+
describe('FOR: Line chart with annotations', () => {
|
|
499
|
+
describe('GIVEN: Params: Annotations', () => {
|
|
500
|
+
describe('WHEN: annotations params are provided', () => {
|
|
501
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_LINE_CHART_WITH_ANNOTATIONS_PARAMS));
|
|
502
|
+
|
|
503
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
504
|
+
const results = await axe($.html());
|
|
505
|
+
expect(results).toHaveNoViolations();
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
test('THEN: it renders the footnotes', () => {
|
|
509
|
+
expect($('.ons-chart__footnotes').text()).toContain('1');
|
|
510
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test annotation');
|
|
511
|
+
expect($('.ons-chart__footnotes').text()).toContain('2');
|
|
512
|
+
expect($('.ons-chart__footnotes').text()).toContain('Another test annotation');
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
test('THEN: the footnotes are hidden from screen readers', () => {
|
|
516
|
+
expect($('.ons-chart__footnotes').attr('aria-hidden')).toBe('true');
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
test('THEN: it includes the Annotations JSON config', () => {
|
|
520
|
+
const configScript = $(`script[data-highcharts-annotations--line-chart-annotations-123]`).html();
|
|
521
|
+
expect(configScript).toContain('"text":"A test annotation"');
|
|
522
|
+
expect(configScript).toContain('"point":{"x":10,"y":1.3}');
|
|
523
|
+
expect(configScript).toContain('"labelOffsetX":10,"labelOffsetY":-50');
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
describe('FOR: Bar chart with annotations', () => {
|
|
530
|
+
describe('GIVEN: Params: Annotations', () => {
|
|
531
|
+
describe('WHEN: annotations params are provided', () => {
|
|
532
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_CHART_WITH_ANNOTATIONS_PARAMS));
|
|
533
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
534
|
+
const results = await axe($.html());
|
|
535
|
+
expect(results).toHaveNoViolations();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test('THEN: it renders the footnotes', () => {
|
|
539
|
+
expect($('.ons-chart__footnotes').text()).toContain('1');
|
|
540
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test annotation');
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test('THEN: the footnotes are hidden from screen readers', () => {
|
|
544
|
+
expect($('.ons-chart__footnotes').attr('aria-hidden')).toBe('true');
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test('THEN: it includes the Annotations JSON config', () => {
|
|
548
|
+
const configScript = $(`script[data-highcharts-annotations--bar-chart-annotations-123]`).html();
|
|
549
|
+
expect(configScript).toContain('"text":"A test annotation"');
|
|
550
|
+
expect(configScript).toContain('"point":{"x":2,"y":3}');
|
|
551
|
+
expect(configScript).toContain('"labelOffsetX":10,"labelOffsetY":-50');
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
describe('FOR: Column chart with annotations', () => {
|
|
558
|
+
describe('GIVEN: Params: Annotations', () => {
|
|
559
|
+
describe('WHEN: annotations params are provided', () => {
|
|
560
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_CHART_WITH_ANNOTATIONS_PARAMS));
|
|
561
|
+
|
|
562
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
563
|
+
const results = await axe($.html());
|
|
564
|
+
expect(results).toHaveNoViolations();
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
test('THEN: it renders the footnotes', () => {
|
|
568
|
+
expect($('.ons-chart__footnotes').text()).toContain('1');
|
|
569
|
+
expect($('.ons-chart__footnotes').text()).toContain('A test annotation');
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test('THEN: the footnotes are hidden from screen readers', () => {
|
|
573
|
+
expect($('.ons-chart__footnotes').attr('aria-hidden')).toBe('true');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
test('THEN: it includes the Annotations JSON config', () => {
|
|
577
|
+
const configScript = $(`script[data-highcharts-annotations--column-chart-annotations-123]`).html();
|
|
578
|
+
expect(configScript).toContain('"text":"A test annotation"');
|
|
579
|
+
expect(configScript).toContain('"point":{"x":11,"y":31.8}');
|
|
580
|
+
expect(configScript).toContain('"labelOffsetX":10,"labelOffsetY":-50');
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
describe('FOR: Bar Chart with Line', () => {
|
|
587
|
+
describe('GIVEN: Params: required', () => {
|
|
588
|
+
describe('WHEN: required params are provided', () => {
|
|
589
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_WITH_LINE_CHART_PARAMS));
|
|
590
|
+
const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
|
|
591
|
+
|
|
592
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
593
|
+
const results = await axe($.html());
|
|
594
|
+
expect(results).toHaveNoViolations();
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test('THEN: it includes one series of type "bar" and another of type "line"', () => {
|
|
598
|
+
expect(configScript).toContain('"type":"bar"');
|
|
599
|
+
expect(configScript).toContain('"type":"line"');
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
test('THEN: it renders the chart container with correct data attributes', () => {
|
|
603
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-type')).toBe('bar');
|
|
604
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-theme')).toBe('alternate');
|
|
605
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-title')).toBe('Example Bar Chart');
|
|
606
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-id')).toBe('bar-chart-123');
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
test('THEN: it includes the Highcharts JSON config', () => {
|
|
610
|
+
expect(configScript).toContain('"text":"X Axis Title"');
|
|
611
|
+
expect(configScript).toContain('"text":"Y Axis Title"');
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
describe('GIVEN: Params: Legend', () => {
|
|
617
|
+
describe('WHEN: legend is enabled', () => {
|
|
618
|
+
const $ = cheerio.load(renderComponent('chart', { ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS, legend: false }));
|
|
619
|
+
|
|
620
|
+
test('THEN: it renders the legend', () => {
|
|
621
|
+
const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
|
|
622
|
+
expect(configScript).toContain('"enabled":false');
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
describe('GIVEN: Params: Caption', () => {
|
|
628
|
+
describe('WHEN: caption is provided', () => {
|
|
629
|
+
const $ = cheerio.load(
|
|
630
|
+
renderComponent('chart', {
|
|
631
|
+
...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
|
|
632
|
+
caption: 'This is an example caption for the chart.',
|
|
633
|
+
}),
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
test('THEN: it renders the caption when provided', () => {
|
|
637
|
+
expect($('figcaption').text()).toBe('This is an example caption for the chart.');
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
describe('GIVEN: Params: Description', () => {
|
|
643
|
+
describe('WHEN: description is provided', () => {
|
|
644
|
+
const $ = cheerio.load(
|
|
645
|
+
renderComponent('chart', {
|
|
646
|
+
...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
|
|
647
|
+
description: 'An accessible description for screen readers.',
|
|
648
|
+
}),
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
test('THEN: it renders the description for accessibility', () => {
|
|
652
|
+
expect($('.ons-u-vh').text()).toBe('An accessible description for screen readers.');
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
describe('GIVEN: Params: Series: Type', () => {
|
|
658
|
+
describe('WHEN: a series has an invalid type', () => {
|
|
659
|
+
const invalidTypeParams = {
|
|
660
|
+
...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
|
|
661
|
+
series: [
|
|
662
|
+
{ name: 'Invalid Series', data: [5, 15, 25], type: 'scatter' },
|
|
663
|
+
{ name: 'Valid Line Series', data: [10, 20, 30], type: 'line' },
|
|
664
|
+
],
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
const $ = cheerio.load(renderComponent('chart', invalidTypeParams));
|
|
668
|
+
const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
|
|
669
|
+
|
|
670
|
+
test('THEN: it defaults non-line series type to the chartType', () => {
|
|
671
|
+
expect(configScript).not.toContain('"type":"scatter"');
|
|
672
|
+
expect(configScript).toContain('"type":"bar"');
|
|
673
|
+
expect(configScript).toContain('"type":"line"');
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
describe('GIVEN: Params: Download', () => {
|
|
679
|
+
describe('WHEN: download object are provided', () => {
|
|
680
|
+
const $ = cheerio.load(
|
|
681
|
+
renderComponent('chart', {
|
|
682
|
+
...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
|
|
683
|
+
download: {
|
|
684
|
+
title: 'Download Chart Data',
|
|
685
|
+
itemsList: [
|
|
686
|
+
{ text: 'Download as PNG', url: 'https://example.com/chart.png' },
|
|
687
|
+
{ text: 'Download as CSV', url: 'https://example.com/chart.csv' },
|
|
688
|
+
],
|
|
689
|
+
},
|
|
690
|
+
}),
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
test('THEN: it renders the download section correctly', () => {
|
|
694
|
+
expect($('.ons-chart__download-title').text()).toBe('Download Chart Data');
|
|
695
|
+
|
|
696
|
+
const downloadLinks = $('.ons-chart__download-title').next().find('li a');
|
|
697
|
+
expect(downloadLinks.eq(0).text()).toBe('Download as PNG');
|
|
698
|
+
expect(downloadLinks.eq(0).attr('href')).toBe('https://example.com/chart.png');
|
|
699
|
+
expect(downloadLinks.eq(1).text()).toBe('Download as CSV');
|
|
700
|
+
expect(downloadLinks.eq(1).attr('href')).toBe('https://example.com/chart.csv');
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
describe('FOR: Column Chart with Line', () => {
|
|
707
|
+
describe('GIVEN: Params: required', () => {
|
|
708
|
+
describe('WHEN: required params are provided', () => {
|
|
709
|
+
const $ = cheerio.load(renderComponent('chart', EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS));
|
|
710
|
+
const configScript = $(`script[data-highcharts-config--column-chart-123]`).html();
|
|
711
|
+
|
|
712
|
+
test('THEN: it passes jest-axe checks', async () => {
|
|
713
|
+
const results = await axe($.html());
|
|
714
|
+
expect(results).toHaveNoViolations();
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
test('THEN: it includes one series of type "column" and another of type "line"', () => {
|
|
718
|
+
expect(configScript).toContain('"type":"column"');
|
|
719
|
+
expect(configScript).toContain('"type":"line"');
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
test('THEN: it renders the chart container with correct data attributes', () => {
|
|
723
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-type')).toBe('column');
|
|
724
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-theme')).toBe('alternate');
|
|
725
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-title')).toBe('Example Column Chart');
|
|
726
|
+
expect($('[data-highcharts-base-chart]').attr('data-highcharts-id')).toBe('column-chart-123');
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
test('THEN: it includes the Highcharts JSON config', () => {
|
|
730
|
+
expect(configScript).toContain('"text":"X Axis Title"');
|
|
731
|
+
expect(configScript).toContain('"text":"Y Axis Title"');
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
describe('GIVEN: Params: Legend', () => {
|
|
737
|
+
describe('WHEN: legend is enabled', () => {
|
|
738
|
+
const $ = cheerio.load(renderComponent('chart', { ...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS, legend: false }));
|
|
739
|
+
|
|
740
|
+
test('THEN: it renders the legend', () => {
|
|
741
|
+
const configScript = $(`script[data-highcharts-config--column-chart-123]`).html();
|
|
742
|
+
expect(configScript).toContain('"enabled":false');
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
describe('GIVEN: Params: Caption', () => {
|
|
748
|
+
describe('WHEN: caption is provided', () => {
|
|
749
|
+
const $ = cheerio.load(
|
|
750
|
+
renderComponent('chart', {
|
|
751
|
+
...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
752
|
+
caption: 'This is an example caption for the chart.',
|
|
753
|
+
}),
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
test('THEN: it renders the caption when provided', () => {
|
|
757
|
+
expect($('figcaption').text()).toBe('This is an example caption for the chart.');
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
describe('GIVEN: Params: Description', () => {
|
|
763
|
+
describe('WHEN: description is provided', () => {
|
|
764
|
+
const $ = cheerio.load(
|
|
765
|
+
renderComponent('chart', {
|
|
766
|
+
...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
767
|
+
description: 'An accessible description for screen readers.',
|
|
768
|
+
}),
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
test('THEN: it renders the description for accessibility', () => {
|
|
772
|
+
expect($('.ons-u-vh').text()).toBe('An accessible description for screen readers.');
|
|
773
|
+
});
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
describe('GIVEN: Params: Download', () => {
|
|
778
|
+
describe('WHEN: download object is provided', () => {
|
|
779
|
+
const $ = cheerio.load(
|
|
780
|
+
renderComponent('chart', {
|
|
781
|
+
...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
782
|
+
download: {
|
|
783
|
+
title: 'Download Chart Data',
|
|
784
|
+
itemsList: [
|
|
785
|
+
{ text: 'Download as PNG', url: 'https://example.com/chart.png' },
|
|
786
|
+
{ text: 'Download as CSV', url: 'https://example.com/chart.csv' },
|
|
787
|
+
],
|
|
788
|
+
},
|
|
789
|
+
}),
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
test('THEN: it renders the download section correctly', () => {
|
|
793
|
+
expect($('.ons-chart__download-title').text()).toBe('Download Chart Data');
|
|
794
|
+
|
|
795
|
+
const downloadLinks = $('.ons-chart__download-title').next().find('li a');
|
|
796
|
+
expect(downloadLinks.eq(0).text()).toBe('Download as PNG');
|
|
797
|
+
expect(downloadLinks.eq(0).attr('href')).toBe('https://example.com/chart.png');
|
|
798
|
+
expect(downloadLinks.eq(1).text()).toBe('Download as CSV');
|
|
799
|
+
expect(downloadLinks.eq(1).attr('href')).toBe('https://example.com/chart.csv');
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
describe('GIVEN: Params: Series: Type', () => {
|
|
805
|
+
describe('WHEN: a series has an invalid type', () => {
|
|
806
|
+
const invalidTypeParams = {
|
|
807
|
+
...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
|
|
808
|
+
series: [
|
|
809
|
+
{ name: 'Invalid Series', data: [5, 15, 25], type: 'scatter' },
|
|
810
|
+
{ name: 'Valid Line Series', data: [10, 20, 30], type: 'line' },
|
|
811
|
+
],
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
const $ = cheerio.load(renderComponent('chart', invalidTypeParams));
|
|
815
|
+
const configScript = $(`script[data-highcharts-config--column-chart-123]`).html();
|
|
816
|
+
|
|
817
|
+
test('THEN: it defaults non-line series type to the chartType', () => {
|
|
818
|
+
expect(configScript).not.toContain('"type":"scatter"');
|
|
819
|
+
expect(configScript).toContain('"type":"column"');
|
|
820
|
+
expect(configScript).toContain('"type":"line"');
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
});
|
|
824
|
+
});
|
|
437
825
|
});
|
|
@@ -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;
|
|
@@ -76,6 +76,10 @@ class BarChart {
|
|
|
76
76
|
// Get the actual width of the data label
|
|
77
77
|
const labelWidth = point.dataLabel && point.dataLabel.getBBox().width;
|
|
78
78
|
// Move the data labels inside the bar if the bar is wider than the label plus some padding
|
|
79
|
+
if (series.type == 'line') {
|
|
80
|
+
// If we have a bar chart with an extra line, exit early for the line series
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
79
83
|
if (point.shapeArgs.height > labelWidth + 20) {
|
|
80
84
|
point.update(insideOptions, false);
|
|
81
85
|
} else {
|
|
@@ -112,9 +116,9 @@ class BarChart {
|
|
|
112
116
|
|
|
113
117
|
// This updates the height of the vertical axis and overall chart to fit the number of categories
|
|
114
118
|
// Note that the vertical axis on a bar chart is the x axis
|
|
115
|
-
updateBarChartHeight = (config, currentChart, useStackedLayout) => {
|
|
119
|
+
updateBarChartHeight = (config, currentChart, useStackedLayout, numberOfExtraLines) => {
|
|
116
120
|
const numberOfCategories = config.xAxis.categories.length;
|
|
117
|
-
const numberOfSeries = currentChart.series.length; // Get number of bar series
|
|
121
|
+
const numberOfSeries = currentChart.series.length - numberOfExtraLines; // Get number of bar series
|
|
118
122
|
let barHeight = 30; // Height of each individual bar - set in bar-chart-plot-options
|
|
119
123
|
let groupSpacing = 0; // Space we want between category groups, or between series groups for cluster charts
|
|
120
124
|
let categoriesTotalHeight = 0;
|