Skip to content

Commit be68d17

Browse files
authored
feat: add keyboard navigation for select charts (#4481)
Signed-off-by: Gordon Smith <[email protected]>
1 parent 0289b85 commit be68d17

File tree

17 files changed

+809
-297
lines changed

17 files changed

+809
-297
lines changed

packages/chart/index.html

Lines changed: 197 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,43 @@
1616
margin-top: 50px;
1717
}
1818

19-
#placeholder {
19+
.controls {
20+
max-width: 800px;
21+
margin: 20px auto;
22+
padding: 15px;
23+
background-color: #fff;
24+
border-radius: 5px;
25+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
26+
}
27+
28+
.control-group {
29+
margin: 10px 0;
30+
}
31+
32+
.control-group label {
33+
display: flex;
34+
align-items: center;
35+
cursor: pointer;
36+
font-size: 14px;
37+
}
38+
39+
.control-group input[type="checkbox"] {
40+
margin-right: 10px;
41+
cursor: pointer;
42+
width: 18px;
43+
height: 18px;
44+
}
45+
46+
.control-group .description {
47+
margin-left: 28px;
48+
font-size: 12px;
49+
color: #666;
50+
font-style: italic;
51+
}
52+
53+
#placeholder,
54+
#placeholder2,
55+
#placeholder3 {
2056
width: 100%;
2157
height: 500px;
2258
background-color: #fff;
@@ -29,9 +65,56 @@
2965

3066
<body onresize="doResize()">
3167
<h1>ESM Quick Test</h1>
32-
<div id="placeholder"></div>
68+
69+
<div class="controls">
70+
<div class="control-group">
71+
<label>
72+
<input type="checkbox" checked id="tabNavigationToggleScatter">
73+
Enable Tab Navigation for Scatter Chart
74+
</label>
75+
<div class="description">
76+
When enabled, you can use Tab to navigate through points and Space/Enter to select them
77+
</div>
78+
</div>
79+
<div class="control-group">
80+
<label for="scatterVariantSelect" style="cursor: default;">
81+
Scatter Variant
82+
</label>
83+
<select id="scatterVariantSelect" style="margin-left: 0; width: 220px; padding: 4px;">
84+
<option value="points" selected>Points Only</option>
85+
<option value="line">Points + Line</option>
86+
<option value="area">Line + Area Fill</option>
87+
</select>
88+
<div class="description">
89+
Quickly preview how scatter behaves with lines or area fill enabled
90+
</div>
91+
</div>
92+
<div class="control-group">
93+
<label>
94+
<input type="checkbox" checked id="tabNavigationToggle">
95+
Enable Tab Navigation for Column Chart
96+
</label>
97+
<div class="description">
98+
When enabled, you can use Tab to navigate through columns and Space/Enter to select them
99+
</div>
100+
</div>
101+
<div class="control-group">
102+
<label>
103+
<input type="checkbox" checked id="tabNavigationTogglePie">
104+
Enable Tab Navigation for Pie Chart
105+
</label>
106+
<div class="description">
107+
When enabled, you can use Tab to navigate through slices and Space/Enter to select them
108+
</div>
109+
</div>
110+
</div>
111+
112+
<div id="placeholder2" tabindex="0"></div>
113+
<div id="placeholder3" tabindex="0"></div>
114+
<div id="placeholder" tabindex="0"></div>
115+
33116
<script type="module">
34-
import { Area, Column } from "@hpcc-js/chart";
117+
import { Column } from "./src/index.ts";
35118

36119
const simple = {
37120
ND: {
@@ -57,7 +140,7 @@ <h1>ESM Quick Test</h1>
57140
}
58141
};
59142

60-
window.__widget = new Column()
143+
window.__column = new Column()
61144
.target("placeholder")
62145
.columns(["Category", "Series-1", "Series-2"])
63146
.data([
@@ -70,14 +153,122 @@ <h1>ESM Quick Test</h1>
70153
])
71154
.tooltipValueFormat(",.0f")
72155
.showValue(true)
73-
.xAxisFocus(true)
156+
.xAxisFocus(false)
157+
.tabNavigation(true)
158+
.render()
159+
;
160+
</script>
161+
162+
<script type="module">
163+
import { Pie } from "./src/index.ts";
164+
165+
window.__pie = new Pie()
166+
.target("placeholder2")
167+
.columns(["Category", "Series-1", "Series-2"])
168+
.data([
169+
["B", 55],
170+
["C", 54],
171+
["D", 80],
172+
["E", 86],
173+
["A", 34],
174+
["F", 144]
175+
])
176+
.tabNavigation(true)
177+
.render()
178+
;
179+
</script>
180+
181+
<script type="module">
182+
import { Scatter } from "./src/index.ts";
183+
184+
window.__scatter = new Scatter()
185+
.target("placeholder3")
186+
.columns(["Category", "Series-1", "Series-2"])
187+
.data([
188+
["A", 15, 25],
189+
["B", 25, 45],
190+
["C", 40, 60],
191+
["D", 55, 75],
192+
["E", 65, 90],
193+
["F", 80, 110]
194+
])
195+
.pointShape("cross")
196+
.pointSize(10)
197+
.showValue(false)
198+
.tabNavigation(true)
74199
.render()
75200
;
76201
</script>
77202
<script>
203+
78204
function doResize() {
79-
window.__widget?.resize()?.render();
205+
window.__column?.resize()?.render();
206+
window.__pie?.resize()?.render();
207+
window.__scatter?.resize()?.render();
80208
}
209+
210+
document.getElementById('tabNavigationToggle').addEventListener('change', function (e) {
211+
window.__column
212+
.tabNavigation(e.target.checked)
213+
.lazyRender()
214+
;
215+
});
216+
217+
document.getElementById('tabNavigationTogglePie').addEventListener('change', function (e) {
218+
window.__pie
219+
.tabNavigation(e.target.checked)
220+
.lazyRender()
221+
;
222+
});
223+
224+
document.getElementById('tabNavigationToggleScatter').addEventListener('change', function (e) {
225+
window.__scatter
226+
.tabNavigation(e.target.checked)
227+
.lazyRender()
228+
;
229+
});
230+
231+
const scatterVariantSelect = document.getElementById('scatterVariantSelect');
232+
233+
function applyScatterVariant(variant) {
234+
if (!window.__scatter) return;
235+
switch (variant) {
236+
case "line":
237+
window.__scatter
238+
.interpolate("linear")
239+
.interpolateFill(false)
240+
.showValue(false)
241+
;
242+
break;
243+
case "area":
244+
window.__scatter
245+
.interpolate("linear")
246+
.interpolateFill(true)
247+
.interpolateFillOpacity(0.35)
248+
.showValue(false)
249+
;
250+
break;
251+
case "points":
252+
default:
253+
window.__scatter
254+
.interpolate("")
255+
.interpolateFill(false)
256+
.pointShape("cross")
257+
.pointSize(10)
258+
.showValue(false)
259+
;
260+
break;
261+
}
262+
window.__scatter.lazyRender();
263+
}
264+
265+
scatterVariantSelect.addEventListener('change', function (e) {
266+
applyScatterVariant(e.target.value);
267+
});
268+
269+
applyScatterVariant(scatterVariantSelect.value);
270+
271+
81272
</script>
82273
</body>
83274

packages/chart/src/Column.css

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
11
.chart_Column .columnRect {
2-
fill: steelblue;
3-
cursor: pointer;
2+
fill: steelblue;
3+
cursor: pointer;
44
}
55

66
.chart_Column .data.axis path {
7-
display: none;
7+
display: none;
88
}
99

1010
.chart_Column .columnRect {
1111
stroke: transparent;
12-
border-width: 1.5px;
12+
border-width: 2px;
1313
}
1414

15-
.chart_Column .columnRect.selected {
16-
stroke: red;
15+
.chart_Column .dataCell.selected .columnRect {
16+
stroke: #dc3545 !important;
17+
stroke-width: 3px !important;
18+
paint-order: fill stroke !important;
19+
transition: all 0.2s ease;
1720
}
21+
22+
.chart_Column .dataCell:hover .columnRect {
23+
stroke: rgba(108, 117, 125, 0.6);
24+
stroke-width: 2px;
25+
filter: brightness(1.05);
26+
}
27+
28+
.chart_Column .dataCell:focus .columnRect {
29+
stroke: #007bff !important;
30+
stroke-width: 3px !important;
31+
paint-order: fill stroke !important;
32+
transition: all 0.2s ease;
33+
}
34+
35+
.chart_Column .dataCell.selected:focus .columnRect {
36+
stroke: #6f42c1 !important;
37+
}
38+
39+
.chart_Column .dataCell:focus-visible {
40+
outline: none;
41+
}
42+
43+
.chart_Column .dataCell:active {
44+
outline: none !important;
45+
}

0 commit comments

Comments
 (0)