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

feat(LEMS-2484): add description for sinusoid #2094

Open
wants to merge 35 commits into
base: LEMS-2484-minimally-describe-sinusoid
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9069a68
add description for sinusoid
anakaren-rojas Jan 10, 2025
ef36b07
docs(changeset): adds aria description for sinusoid graph
anakaren-rojas Jan 13, 2025
637652c
remove negative and update strings
anakaren-rojas Jan 13, 2025
18dacc7
lint fix
anakaren-rojas Jan 13, 2025
192c771
Merge branch 'main' into LEMS-2484-aria-description-for-sinusoid
anakaren-rojas Jan 13, 2025
a230434
add aria labels to sinusoid function graph
anakaren-rojas Jan 3, 2025
3c58514
lint fix
anakaren-rojas Jan 3, 2025
6b7c09e
update tests
anakaren-rojas Jan 3, 2025
befefd2
docs(changeset): add aria labels for sinusoid function graphs
anakaren-rojas Jan 3, 2025
42de6d8
remove context and message object
anakaren-rojas Jan 7, 2025
161e9ce
add description for sinusoid
anakaren-rojas Jan 10, 2025
5a9aa0d
docs(changeset): adds aria description for sinusoid graph
anakaren-rojas Jan 13, 2025
5ffa962
remove negative and update strings
anakaren-rojas Jan 13, 2025
60db131
lint fix
anakaren-rojas Jan 13, 2025
4fa84b4
Merge remote-tracking branch 'origin/LEMS-2484-aria-description-for-s…
anakaren-rojas Jan 13, 2025
9cad6b1
add aria labels to sinusoid function graph
anakaren-rojas Jan 3, 2025
2f0de53
lint fix
anakaren-rojas Jan 3, 2025
ed381e4
add description for sinusoid
anakaren-rojas Jan 10, 2025
56f4c12
docs(changeset): adds aria description for sinusoid graph
anakaren-rojas Jan 13, 2025
d8982af
remove negative and update strings
anakaren-rojas Jan 13, 2025
ca3bc82
lint fix
anakaren-rojas Jan 13, 2025
1d15260
remove negative and update strings
anakaren-rojas Jan 13, 2025
1f08919
lint fix
anakaren-rojas Jan 13, 2025
4229859
Merge remote-tracking branch 'origin/LEMS-2484-aria-description-for-s…
anakaren-rojas Jan 13, 2025
b096361
empty commit to kick start actions
anakaren-rojas Jan 13, 2025
e0c9c77
small change to trigger updates
anakaren-rojas Jan 14, 2025
59fef4e
update sinusoid calculations
anakaren-rojas Jan 16, 2025
28f82bd
update calculations for whole graph description
anakaren-rojas Jan 16, 2025
af7ebea
lint fix
anakaren-rojas Jan 16, 2025
a62a75d
WIP on LEMS-2484-minimally-describe-sinusoid
anakaren-rojas Jan 16, 2025
42c7ba2
format all x coords to include pi
anakaren-rojas Jan 16, 2025
b161f0f
Merge branch 'main' into LEMS-2484-aria-description-for-sinusoid
anakaren-rojas Jan 16, 2025
45037e9
format x coord to pi
anakaren-rojas Jan 16, 2025
74d72b5
lint fix
anakaren-rojas Jan 16, 2025
41430e8
Merge branch 'LEMS-2484-minimally-describe-sinusoid' into LEMS-2484-a…
nishasy Jan 21, 2025
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
5 changes: 5 additions & 0 deletions .changeset/mighty-taxis-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": minor
---

adds aria description for sinusoid graph
26 changes: 26 additions & 0 deletions packages/perseus/src/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,21 @@ export type PerseusStrings = {
srSinusoidGraphAriaLabel: string;
srSinusoidExtremumPoint: ({x, y}: {x: string; y: string}) => string;
srSinusoidMidlineIntersection: ({x, y}: {x: string; y: string}) => string;
srSinusoidDescription: ({
minValue,
maxValue,
xStartCoord,
yStartCoord,
xEndCoord,
yEndCoord,
}: {
minValue: string;
maxValue: string;
xStartCoord: string;
yStartCoord: string;
xEndCoord: string;
yEndCoord: string;
}) => string;
// The above strings are used for interactive graph SR descriptions.
};

Expand Down Expand Up @@ -543,6 +558,8 @@ export const strings = {
srSinusoidGraphAriaLabel: "A sinusoid function on a coordinate plane.",
srSinusoidExtremumPoint: "Extremum Point at %(x)s comma %(y)s.",
srSinusoidMidlineIntersection: "Midline Intersection at %(x)s comma %(y)s.",
srSinusoidDescription:
"The graph shows a wave with a minimum value of %(minValue)s and a maximum value of %(maxValue)s. The wave completes a full cycle from %(xStartCoord)s comma %(yStartCoord)s to %(xEndCoord)s comma %(yEndCoord)s.",
// The above strings are used for interactive graph SR descriptions.
} satisfies {
[key in keyof PerseusStrings]:
Expand Down Expand Up @@ -781,6 +798,15 @@ export const mockStrings: PerseusStrings = {
srSinusoidExtremumPoint: ({x, y}) => `Extremum Point at ${x} comma ${y}.`,
srSinusoidMidlineIntersection: ({x, y}) =>
`Midline Intersection at ${x} comma ${y}.`,
srSinusoidDescription: ({
minValue,
maxValue,
xStartCoord,
yStartCoord,
xEndCoord,
yEndCoord,
}) =>
`The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${xStartCoord} comma ${yStartCoord} to ${xEndCoord} comma ${yEndCoord}.`,
// The above strings are used for interactive graph SR descriptions.
};

Expand Down
104 changes: 95 additions & 9 deletions packages/perseus/src/widgets/interactive-graphs/graphs/sinusoid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function SinusoidGraph(props: SinusoidGraphProps) {
}

const {strings, locale} = usePerseusI18n();
const uniqueId = React.useId();

function getMoveablePointAriaLabel(
index: number,
Expand All @@ -64,14 +65,7 @@ function SinusoidGraph(props: SinusoidGraphProps) {
const x = coordinate[0];
const y = coordinate[1];

const convertedXCoordinate =
x === 0
? `0`
: x % 2 === 0
? `${x / 2} pi`
: x % 1 === 0
? `${x}/2 pi`
: `${x * 2}/4 pi`;
const convertedXCoordinate = formatXCoordsToPi(x);

const coordsObj = {
x: convertedXCoordinate,
Expand All @@ -83,8 +77,39 @@ function SinusoidGraph(props: SinusoidGraphProps) {
: strings.srSinusoidMidlineIntersection(coordsObj);
}

function getWholeGraphDescription(): string {
const minMaxYVals = calculateMinAndMaxYValues(
coeffRef.current.amplitude,
coeffRef.current.verticalOffset,
);

// coords[1] is associated to the extremum point
const startEndCoords = calculateFullCycleStartAndEndCoords(
minMaxYVals[0],
coords[1],
coeffRef.current.angularFrequency,
locale,
);

const startCoords = startEndCoords[0];
const endCoords = startEndCoords[1];

const descriptionObj = {
minValue: srFormatNumber(minMaxYVals[0], locale),
maxValue: srFormatNumber(minMaxYVals[1], locale),
xStartCoord: startCoords[0],
yStartCoord: startCoords[1],
xEndCoord: endCoords[0],
yEndCoord: endCoords[1],
};
return strings.srSinusoidDescription(descriptionObj);
}

return (
<g aria-label={strings.srSinusoidGraphAriaLabel}>
<g
aria-label={strings.srSinusoidGraphAriaLabel}
aria-describedby={`sinusoid-description-${uniqueId}`}
>
<Plot.OfX
y={(x) => computeSine(x, coeffRef.current)}
color={color.blue}
Expand All @@ -100,6 +125,9 @@ function SinusoidGraph(props: SinusoidGraphProps) {
}
/>
))}
<g id={`sinusoid-description-${uniqueId}`}>
{getWholeGraphDescription()}
</g>
</g>
);
}
Expand Down Expand Up @@ -140,3 +168,61 @@ export const getSinusoidCoefficients = (

return {amplitude, angularFrequency, phase, verticalOffset};
};

/**
* Sine and cosine oscillate between [-1, 1], which is scaled by the graph's amplitude [-A, A] and shifted by the vertical offset [-A+D, A+D]
* @param amplitude Distance from the center to either extreme
* @param verticalOffset aka vertical shift - moves the range up or down
* @returns array [minYVal, maxYVal]
*/
export function calculateMinAndMaxYValues(
amplitude: number,
verticalOffset: number,
) {
const absAmp = Math.abs(amplitude);
return [-absAmp + verticalOffset, absAmp + verticalOffset];
}

/**
* Calculates the start and end coordinates for a full cycle of a sinusoid wave by adding or subtracting the period of the graph
* from the extremum point. If the extremum point provided is the max, subtract the period, if the extremum point is the min, add the period
* @param minVal Y coordinate associated to the minimum value on the graph
* @param coords Extremum coordinates for the graph
* @param angularFrequency Determines how stretched or compressed the graph is
* @returns string matrix of start and end coordinates for the full cycle
*/
export function calculateFullCycleStartAndEndCoords(
minVal: number,
coords: vec.Vector2,
angularFrequency: number,
locale: string,
) {
const [x, y] = coords;
const formattedCoords = [formatXCoordsToPi(x), srFormatNumber(y, locale)];
const period = (2 * Math.PI) / Math.abs(angularFrequency);
const isMinVal = y === minVal;
const adjustedX = isMinVal ? x + period : x - period;
const formattedXValue = formatXCoordsToPi(adjustedX);

const startValCoords = isMinVal
? formattedCoords
: [formattedXValue, srFormatNumber(y, locale)];
const endValCoords = isMinVal
? [formattedXValue, srFormatNumber(y, locale)]
: formattedCoords;

return [startValCoords, endValCoords];
}

export function formatXCoordsToPi(x: number) {
if (x === 0) {
return `0`;
}
if (x % 2 === 0) {
return `${x / 2} pi`;
}
if (x % 1 === 0) {
return `${x}/2 pi`;
}
return `${x * 2}/4 pi`;
}
Loading