Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

119 batuhan tli 01f accessibilitytab into graph tab order aria labels for all buttons #121

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 91 additions & 27 deletions frontend/src/pages/DashboardPage/ChartComponenet/ChartComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
const chartRef = useRef(null);
const myChartRef = useRef(null);
const [hoveredIndex, setHoveredIndex] = useState(null);
const [accuracyData, setAccuracyData] = useState([]);
const [lastTabIndex, setLastTabIndex] = useState(20);

useEffect(() => {
if (!chartData) return;

console.log("Rendering chart with data:", chartData);

// Step 1: Identify unique feature1 values and assign colors dynamically
const uniqueFeature1Groups = Array.from(
new Set(chartData.map((item) => item.feature1))
);
Expand All @@ -27,39 +28,38 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
return acc;
}, {});

// Step 2: Sort and prepare data for the chart
const sortedChartData = [...chartData].sort((a, b) =>
a.feature1.localeCompare(b.feature1)
);

const labels = sortedChartData.map((item) => item.feature2); // Only feature2 labels
const labels = sortedChartData.map((item) => item.feature2);

const accuracyData = sortedChartData.map((item) => ({
label: item.feature2, // Use only feature2 as label
const newAccuracyData = sortedChartData.map((item) => ({
label: item.feature2,
accuracy: item.accuracy,
falsePositive: item.falsepositive,
falseNegative: item.falsenegative,
color: feature1Colors[item.feature1] || "rgba(200, 200, 200, 0.7)", // Default gray if missing
color: feature1Colors[item.feature1] || "rgba(200, 200, 200, 0.7)",
}));

// Configure datasets with accuracy data and colors by group
setAccuracyData(newAccuracyData);

const datasets = [
{
label: "Accuracy",
data: accuracyData.map((d) => ({ x: d.label, y: d.accuracy })),
backgroundColor: accuracyData.map((d) => d.color), // Bars are filled with the color for each feature1 group
borderColor: accuracyData.map(
(d) => (d.accuracy > sliderValue ? "rgba(255, 0, 0, 1)" : d.color) // Red border if above threshold, else use the same color as fill
data: newAccuracyData.map((d) => ({ x: d.label, y: d.accuracy })),
backgroundColor: newAccuracyData.map((d) => d.color),
borderColor: newAccuracyData.map(
(d) => (d.accuracy > sliderValue ? "rgba(255, 0, 0, 1)" : d.color)
),
borderWidth: accuracyData.map(
(d) => (d.accuracy > sliderValue ? 3 : 1) // Increased border width if above threshold, else default
borderWidth: newAccuracyData.map(
(d) => (d.accuracy > sliderValue ? 3 : 1)
),
borderCapStyle: "round",
borderJoinStyle: "round",
},
];

// Threshold line
const lineData = {
label: "Threshold",
data: labels.map((label) => ({ x: label, y: sliderValue })),
Expand Down Expand Up @@ -100,14 +100,14 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
},
title: {
color: "rgba(255, 255, 255, 1)",
display: true, // Display the x-axis title
text: 'Demographics', // Set the x-axis label
display: true,
text: 'Demographics',
font: {
size: 16, // Font size for the title
weight: 'bold', // Make the title bold
size: 16,
weight: 'bold',
},
padding: {
top: 8, // Space above the title
top: 8,
},
},
},
Expand All @@ -125,15 +125,15 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
color: "rgba(255, 255, 255, 0.4)",
},
title: {
display: true, // Display the y-axis title
text: 'Bias', // Set the y-axis label
display: true,
text: 'Bias',
color: "rgba(255, 255, 255, 1)",
font: {
size: 16, // Font size for the title
weight: 'bold', // Make the title bold
size: 16,
weight: 'bold',
},
padding: {
bottom: 8, // Space below the title
bottom: 8,
},
},
},
Expand All @@ -155,9 +155,10 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
},
},
tooltip: {
enabled: true,
callbacks: {
label: (tooltipItem) => {
const item = accuracyData[tooltipItem.dataIndex];
const item = newAccuracyData[tooltipItem.dataIndex];
return [
`Bias: ${item.accuracy}`,
`False Positive: ${item.falsePositive}`,
Expand Down Expand Up @@ -199,7 +200,70 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {
},
],
});
}, [chartData, sliderValue]); // Removed hoveredIndex dependency
}, [chartData, sliderValue]);

useEffect(() => {
const handleKeyDown = (event) => {
console.log("current acitve:", document.activeElement.tabIndex)
if (document.activeElement.tabIndex != 19) {
return;
}

if (event.key === 'Tab') {
event.preventDefault(); // Prevent default tab behavior during chart navigation

const nextIndex = hoveredIndex === null
? 0
: (hoveredIndex + 1);

if (nextIndex < accuracyData.length) {
setHoveredIndex(nextIndex);
if (myChartRef.current) {
const chart = myChartRef.current;
// const activeElement = chart.getDatasetMeta(0).data[nextIndex];
chart.setActiveElements([{ datasetIndex: 0, index: nextIndex }]);
chart.update();

chart.tooltip.setActiveElements([{ datasetIndex: 0, index: nextIndex }]);
chart.tooltip.update();
chart.draw();
}
} else {
// After the last accuracy item, allow normal tab flow
event.stopImmediatePropagation(); // Stop custom tabbing, allow native behavior

// Focus on the next focusable element (like buttons or other controls)
if (lastTabIndex == 19) {
setHoveredIndex(nextIndex);
if (myChartRef.current) {
const chart = myChartRef.current;
chart.setActiveElements([{ datasetIndex: 0, index: nextIndex }]);
chart.update();

chart.tooltip.setActiveElements([{ datasetIndex: 0, index: nextIndex }]);
chart.tooltip.update();
chart.draw();
}
}

const qs = `[tabindex="${lastTabIndex}"]`
const nextFocusableElement = document.querySelector(qs);
if (nextFocusableElement) {
nextFocusableElement.focus(); // Move focus to the element with tabindex="1"
setLastTabIndex(lti => lti + 1);
}
}
}
};

window.addEventListener('keydown', handleKeyDown);

return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [hoveredIndex, accuracyData.length, lastTabIndex]);



useImperativeHandle(ref, () => ({
downloadChart() {
Expand All @@ -212,7 +276,7 @@ const ChartComponent = forwardRef(({ chartData, sliderValue }, ref) => {

return (
<div className="chart-container">
<canvas ref={chartRef} />
<canvas ref={chartRef}/>
</div>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ const ControlButtons = ({ onDownload }) => {
</button>
<button
onClick={onDownload}
tabIndex={15}
tabIndex={3}
>
Download Graph
</button>
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/pages/DashboardPage/Dashboard/Dashboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ html {
justify-content: center;
}

.info-button:focus {
outline: none;
border-color: white;
border: 6px solid white;
}

.select-options1 {
display: flex;
flex-direction: column;
Expand Down
38 changes: 19 additions & 19 deletions frontend/src/pages/DashboardPage/Dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,11 @@ const Dashboard = () => {
<TourGuide runTour={runTour}/>

<div className="chart-container-container">
<div className="timeframe-buttons">
<div className="timeframe-buttons" >
<TimeButtons
handleTimeframeChange={handleTimeframeChange}
timeframe={timeframe}
lastTabIndex={15}
/>
</div>
{loading && (
Expand All @@ -495,32 +496,31 @@ const Dashboard = () => {
<div className={loading ? "hidden" : ""}>
<Slider graphData={graphData} maxValue={maxValue}/>
</div>
<DemographicsSelector
demographics={demographics}
selectedDemographic={selectedDemographic}
handleDemographicChange={handleDemographicChange}
selectedValues={selectedValues}
handleValueChange={handleValueChange}
demographicValues={demographicValues}
selectedSecondValues={selectedSecondValues}
secondSelectedDemographic={secondSelectedDemographic}
handleSecondDemographicChange={handleSecondDemographicChange}
secondDemographicValues={secondDemographicValues}
handleGenerate={handleGenerate}
tabIndex={4}
/>

<DemographicsSelector
demographics={demographics}
selectedDemographic={selectedDemographic}
handleDemographicChange={handleDemographicChange}
selectedValues={selectedValues}
handleValueChange={handleValueChange}
demographicValues={demographicValues}
selectedSecondValues={selectedSecondValues}
secondSelectedDemographic={secondSelectedDemographic}
handleSecondDemographicChange={handleSecondDemographicChange}
secondDemographicValues={secondDemographicValues}
handleGenerate={handleGenerate}
/>

<button className="info-button" onClick={openModal}>
<button className="info-button" onClick={openModal} tabIndex={23}>
?
</button>
{isModalOpen && <Modal closeModal={closeModal}/>}

</div>
<div className="upload-buttons">
<div className="upload-buttons" tabIndex={-1}>
<ControlButtons onDownload={handleDownload}/>
</div>

<div className="chatbot-div">
<div className="chatbot-div" tabIndex={22}>
<button
id="chatbot-button"
aria-label="Open Chatbot"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const DemographicsSelector = ({
handleSecondDemographicChange,
secondDemographicValues,
handleGenerate,
tabIndex,
}) => {
return (
<div className="select-demographics-2">
Expand All @@ -25,7 +26,7 @@ const DemographicsSelector = ({
<select
onChange={handleDemographicChange}
value={selectedDemographic}
tabIndex={3}
tabIndex={tabIndex}
>
<option value="">Select</option>
{demographics.map((demo, index) => (
Expand All @@ -45,7 +46,7 @@ const DemographicsSelector = ({
key={idx}
onChange={(event) => handleValueChange(event, idx)}
value={selectedValues[idx] || ""}
tabIndex={idx + 2}
tabIndex={tabIndex + 1 + idx}
>
<option value="">Select</option>
{demographicValues
Expand All @@ -69,7 +70,7 @@ const DemographicsSelector = ({
id="second-demographic-select"
onChange={handleSecondDemographicChange}
value={secondSelectedDemographic}
tabIndex={6}
tabIndex={tabIndex + 5 + 1}
>
<option value="">Select</option>
{demographics
Expand All @@ -93,7 +94,7 @@ const DemographicsSelector = ({
handleValueChange(event, idx, true)
}
value={selectedSecondValues[idx] || ""}
tabIndex={idx + 6}
tabIndex={tabIndex + 5 + 1 + 1 + idx}
>
<label htmlFor={`second-value-select-${idx}`}>
Select Value {idx + 1}
Expand All @@ -114,7 +115,7 @@ const DemographicsSelector = ({
)}
</div>
{selectedDemographic && <div className="generate-btn-container">
<button className="generate-button" onClick={handleGenerate} tabIndex={15}>
<button className="generate-button" onClick={handleGenerate} tabIndex={20}>
Generate
</button>
</div>}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/pages/DashboardPage/QRCodeShare/QRCodeShare.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
border: 2px solid #009999;
}

.share-button:focus {
outline: none;
border-color: white;
border: 6px solid white;
}

.share-button:active {
transform: scale(0.95); /* Press effect */
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/pages/DashboardPage/QRCodeShare/QRCodeShare.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ const QRCodeShare = ({
<button
className="share-button"
onClick={handleShare}
tabIndex={12}>
tabIndex={21}
>
<svg
className="icon-share"
xmlns="http://www.w3.org/2000/svg"
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/pages/DashboardPage/Slider/Slider.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
width: 100%; /* Full width */
height: 10px; /* Track height */
border-radius: 5px; /* Rounded track */
outline: none; /* Remove focus outline */
cursor: pointer;
background: linear-gradient(to right, yellow 50%, white 50%); /* Initial gradient */
transition: background 0.2s ease; /* Smooth color change */
}

.slider-input::-webkit-slider-thumb {
Expand Down
Loading