-
Notifications
You must be signed in to change notification settings - Fork 351
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
Angle Graph bug fixes and refactoring #1666
base: main
Are you sure you want to change the base?
Conversation
@@ -405,6 +405,86 @@ class InteractiveGraphEditor extends React.Component<Props> { | |||
/> | |||
</LabeledRow> | |||
)} | |||
{this.props.correct?.type === "angle" && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds the missing options to the Angle Graph Editor for controlling "showAngles" and "allowReflexAngles"
return ( | ||
<> | ||
{/* Current equation */} | ||
<View style={styles.equationSection}> | ||
<LabelMedium>Starting equation:</LabelMedium> | ||
<BodyMonospace style={styles.equationBody}> | ||
{getAngleEquation(startCoords)} | ||
{getAngleEquation(startCoords, allowReflexAngles)} | ||
</BodyMonospace> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the allowReflexAngles option in order to correctly calculate the angle equation for the start coordinates.
npm Snapshot: PublishedGood news!! We've packaged up the latest commit from this PR (fe0bef1) and published it to npm. You Example: yarn add @khanacademy/perseus@PR1666 If you are working in Khan Academy's webapp, you can run: ./dev/tools/bump_perseus_version.sh -t PR1666 |
Size Change: +785 B (+0.09%) Total Size: 866 kB
ℹ️ View Unchanged
|
@@ -125,6 +125,9 @@ export { | |||
getQuadraticCoords, | |||
getAngleCoords, | |||
} from "./widgets/interactive-graphs/reducer/initialize-graph-state"; | |||
// This export is to support necessary functionality in the perseus-editor package. | |||
// It should be removed if widgets and editors become colocated. | |||
export {getClockwiseAngle} from "./widgets/interactive-graphs/math"; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reviewing kmath and some other possible locations, it seemed best to simply export this. I feel like this is a relatively safe function to export and is using the same approach as the getAngleCoords.
I'm happy to take any feedback on this however!
// This function is deprecated as it has several issues calculating | ||
// correctly when dealing with reflexive angles or the position of point2 | ||
// (LEMS-2202) Remove this function while removing the Legacy Interactive Graph. | ||
findAngleDeprecated: function ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add a comment to LEMS-2202 to mention deleting this function once we strip out the Legacy Graph. First, I need to confirm if interactive.ts
is used anywhere else as it's the only other consumer of this function.
} | ||
const angle = getClockwiseAngle( | ||
coords, | ||
allowReflexAngles, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While there aren't any graphs that currently make use of the reflexive angles, this update in validation logic is necessary to make sure that we can support them properly moving forward.
I think it is safe to update the validator at this time as the Legacy Angle Graph is no longer being shown to users.
@@ -94,10 +95,13 @@ describe("shouldDrawArcOutside", () => { | |||
).toBe(true); | |||
}); | |||
|
|||
// TODO: (third) Move this test to the math package | |||
it("should correctly calculate the angle for the given coordinates", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops missed a TODO, I'll get this updated tomorrow.
// This function calculates the angle between two points and an optional vertex. | ||
// If the vertex is not provided, the angle is measured between the two points. | ||
// This does not account for reflex angles or clockwise position. | ||
export const findAngleFromVertex = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was only one case I could find where we were actually making use of all 3 points for findAngle, which was the polygon graph.
In order to simplify these functions, I've opted to scope this function to only calculate the angle from a single point and the vertex. I have updated the polygon graph to use the new getClockwiseAngle method below, which is able to be shared in several other places.
// This function calculates the clockwise angle between three points, | ||
// and is used to generate the labels and equation strings of the | ||
// current angle for the interactive graph. | ||
export const getClockwiseAngle = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should note that this is also used in the validator now, in order to preemptively solve issues with calculating the angles of reflexive graphs.
? graph.showAngles | ||
: null; | ||
const allowReflexAngles = | ||
graph.type === "angle" ? graph.allowReflexAngles : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These options needed to be added in order to update the graph previews while editing these options in the Content Editor.
4b959d6
to
7e06ffd
Compare
return false; | ||
} | ||
const angle = getClockwiseAngle(coords, allowReflexAngles); | ||
return angle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I generally tried to avoid updating the validation logic, I think this is now necessary in order to properly score reflexive/non-reflexive graphs in the future. This will provide a much more stable and consistent experience for our users.
EXAMPLE
To provide an example of the issue being solved here: Previously, the legacy graph would incorrectly become "reflexive" if you dragged the bottom ray (point2) down, even if reflexive angles were turned off. This has been a long-standing bug with our graphs. As a result, legacy graphs could only be scored correct unidirectionally. Furthermore, there were several issues related to how reflexive angles were calculated and often resulted in negative angles.
In our modern re-implementation, these issues have already been fixed visually. Now, a graph's ability to become reflexive is wholly controlled by the allowReflexAngles
property. As a result, the graph should be scored correctly regardless of the clockwise order of the points. ie. [0,1] [0,0] [1,0] and [1,0][0,0][0,1] both create a 90* angle for a graph where allowReflexAngles=false
.
GeraldRequired Reviewers
Don't want to be involved in this pull request? Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall lgtm - very fun to play with, you did a great job!
Since I'm not as familiar with this feature though, I will leave the approving the those that are 😜
!!this.props.correct?.showAngles | ||
} | ||
onChange={() => { | ||
if (this.props.graph?.type === "angle") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit since this seems to be the pattern in the file:
could the logic for the checkboxes be extracted into their own methods?
handleAngleChange = () => {
const { graph, correct, onChange } = this.props;
if (graph?.type !== "angle") return;
invariant(
correct.type === "angle",
`Expected graph type to be angle, but got ${correct.type}`,
);
onChange({
correct: {
...correct,
showAngles: !correct.showAngles,
},
graph: {
...graph,
showAngles: !graph.showAngles,
},
});
};
// then in the checkbox
<Checkbox
...
onChange={this.handleAngleChange}
/>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooo good callout! They definitely could be separated out, but I think this PR is probably already large and long-lived enough as it is.😅
That sounds like a good clean up ticket for Interactive Graph's backlog however! It seems like this is the existing design pattern in this file, and we should probably update all of the checkbox logic together in order to maintain consistency.
export const getAngleEquation = ( | ||
startCoords: [Coord, Coord, Coord], | ||
allowReflexAngles?: boolean, | ||
) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another nit suggestion: adding the default param vs using an ||
, you can remove the declaration of allowReflex
- allowReflexAngles?: boolean,
+ allowReflexAngles: boolean = false,
....
- const allowReflex = allowReflexAngles || false;
- const angle = getClockwiseAngle(startCoords, allowReflex);
+ const angle = getClockwiseAngle(startCoords, allowReflexAngles);
) => { | ||
const vertex = startCoords[1]; | ||
const allowReflex = allowReflexAngles || false; | ||
const angle = getClockwiseAngle(startCoords, allowReflex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also chaining might be helpful here, although idk how much that would improve readability
- const angle = getClockwiseAngle(startCoords, allowReflex);
- const roundedAngle = angle.toFixed(0);
+ const roundedAngle = getClockwiseAngle(startCoords, allowReflex).toFixed(0);
Summary:
This ticket includes several fixes to the angle graph in terms of the correct calculation of the angle, particularly when dealing with reflexive angles. A short summary of the changes will be listed below:
Video Example:
Screen.Recording.2024-09-26.at.3.44.49.PM.mov
Issue: LEMS-2302
Test plan: