diff --git a/.changeset/heavy-deers-whisper.md b/.changeset/heavy-deers-whisper.md new file mode 100644 index 00000000000..f2487ad7640 --- /dev/null +++ b/.changeset/heavy-deers-whisper.md @@ -0,0 +1,7 @@ +--- +"@khanacademy/perseus": minor +"@khanacademy/perseus-core": minor +"@khanacademy/perseus-editor": minor +--- + +Creation of initial types and stubs for Vector graph diff --git a/packages/perseus-core/src/data-schema.ts b/packages/perseus-core/src/data-schema.ts index a5f666fb676..8c998794f12 100644 --- a/packages/perseus-core/src/data-schema.ts +++ b/packages/perseus-core/src/data-schema.ts @@ -1109,7 +1109,8 @@ export type PerseusGraphType = | PerseusGraphTypeSegment | PerseusGraphTypeSinusoid | PerseusGraphTypeExponential - | PerseusGraphTypeTangent; + | PerseusGraphTypeTangent + | PerseusGraphTypeVector; export type PerseusGraphTypeAngle = { type: "angle"; @@ -1263,6 +1264,14 @@ export type PerseusGraphTypeRay = { startCoords?: CollinearTuple; }; +export type PerseusGraphTypeVector = { + type: "vector"; + /** The tail and tip coordinates of the vector: [tail, tip] */ + coords?: CollinearTuple | null; + /** The initial coordinates the graph renders with. */ + startCoords?: CollinearTuple; +}; + type AbsoluteValueGraphCorrect = { type: "absolute-value"; coords: [Coord, Coord]; @@ -1337,6 +1346,11 @@ type RayGraphCorrect = { coords: CollinearTuple; }; +type VectorGraphCorrect = { + type: "vector"; + coords: CollinearTuple; +}; + export type PerseusGraphCorrectType = | AbsoluteValueGraphCorrect | AngleGraphCorrect @@ -1351,7 +1365,8 @@ export type PerseusGraphCorrectType = | SegmentGraphCorrect | SinusoidGraphCorrect | ExponentialGraphCorrect - | TangentGraphCorrect; + | TangentGraphCorrect + | VectorGraphCorrect; /** Options for the label-image widget. Asks learners to label image parts. */ export type PerseusLabelImageWidgetOptions = { diff --git a/packages/perseus-core/src/parse-perseus-json/perseus-parsers/interactive-graph-widget.ts b/packages/perseus-core/src/parse-perseus-json/perseus-parsers/interactive-graph-widget.ts index d5e4a8af017..5cc4b3b2021 100644 --- a/packages/perseus-core/src/parse-perseus-json/perseus-parsers/interactive-graph-widget.ts +++ b/packages/perseus-core/src/parse-perseus-json/perseus-parsers/interactive-graph-widget.ts @@ -137,6 +137,12 @@ const parsePerseusGraphTypeTangent = object({ startCoords: optional(array(pairOfNumbers)), }); +const parsePerseusGraphTypeVector = object({ + type: constant("vector"), + coords: optional(nullable(pair(pairOfNumbers, pairOfNumbers))), + startCoords: optional(pair(pairOfNumbers, pairOfNumbers)), +}); + export const parsePerseusGraphType = discriminatedUnionOn("type") .withBranch("absolute-value", parsePerseusGraphTypeAbsoluteValue) .withBranch("angle", parsePerseusGraphTypeAngle) @@ -151,7 +157,8 @@ export const parsePerseusGraphType = discriminatedUnionOn("type") .withBranch("ray", parsePerseusGraphTypeRay) .withBranch("segment", parsePerseusGraphTypeSegment) .withBranch("sinusoid", parsePerseusGraphTypeSinusoid) - .withBranch("tangent", parsePerseusGraphTypeTangent).parser; + .withBranch("tangent", parsePerseusGraphTypeTangent) + .withBranch("vector", parsePerseusGraphTypeVector).parser; const parseLockedFigureColor = enumeration(...lockedFigureColorNames); diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx index e8e8a9a66c8..e162a121c0a 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx @@ -551,6 +551,9 @@ function mergeGraphs( case "tangent": invariant(b.type === "tangent"); return {...a, ...b}; + case "vector": + invariant(b.type === "vector"); + return {...a, ...b}; default: throw new UnreachableCaseError(a); } diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/start-coords/util.ts b/packages/perseus-editor/src/widgets/interactive-graph-editor/start-coords/util.ts index d5b0f1654b5..d527e9f82f5 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/start-coords/util.ts +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/start-coords/util.ts @@ -247,6 +247,7 @@ export const shouldShowStartCoordsUI = ( case "segment": case "sinusoid": case "absolute-value": + case "vector": return true; default: throw new UnreachableCaseError(graph); diff --git a/packages/perseus/src/widget-ai-utils/interactive-graph/interactive-graph-ai-utils.ts b/packages/perseus/src/widget-ai-utils/interactive-graph/interactive-graph-ai-utils.ts index a808e7033ba..ca8c96861f4 100644 --- a/packages/perseus/src/widget-ai-utils/interactive-graph/interactive-graph-ai-utils.ts +++ b/packages/perseus/src/widget-ai-utils/interactive-graph/interactive-graph-ai-utils.ts @@ -268,6 +268,11 @@ const getGraphOptionsForProps = ( type: props.userInput.type, startCoords: props.userInput.startCoords, }; + case "vector": + return { + type: props.userInput.type, + startCoords: props.userInput.startCoords, + }; default: throw new UnreachableCaseError(type); } @@ -334,6 +339,10 @@ const getUserInput = (userInput: PerseusGraphType): UserInput => { coords: userInput.coords, asymptote: userInput.asymptote, }; + case "vector": + return { + coords: userInput.coords, + }; default: throw new UnreachableCaseError(type); } diff --git a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.tsx b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.tsx index d74e592cbcd..8f49b1b947d 100644 --- a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.tsx @@ -613,6 +613,8 @@ class InteractiveGraph extends React.Component { return InteractiveGraph.getExponentialEquationString(props); case "tangent": return InteractiveGraph.getTangentEquationString(props); + case "vector": + return ""; default: throw new UnreachableCaseError(type); } diff --git a/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx b/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx index 4d22c0a8d8c..dc2744b552a 100644 --- a/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx @@ -777,6 +777,8 @@ const renderGraphElements = (props: { return renderAbsoluteValueGraph(state, dispatch, i18n); case "tangent": return renderTangentGraph(state, dispatch, i18n); + case "vector": + throw new Error("Not implemented"); default: throw new UnreachableCaseError(type); } diff --git a/packages/perseus/src/widgets/interactive-graphs/mafs-state-to-interactive-graph.ts b/packages/perseus/src/widgets/interactive-graphs/mafs-state-to-interactive-graph.ts index f09f78ab33f..95890fd591c 100644 --- a/packages/perseus/src/widgets/interactive-graphs/mafs-state-to-interactive-graph.ts +++ b/packages/perseus/src/widgets/interactive-graphs/mafs-state-to-interactive-graph.ts @@ -110,6 +110,12 @@ export function mafsStateToInteractiveGraph( ...originalGraph, coords: state.coords, }; + case "vector": + invariant(originalGraph.type === "vector"); + return { + ...originalGraph, + coords: state.coords, + }; default: throw new UnreachableCaseError(state); } diff --git a/packages/perseus/src/widgets/interactive-graphs/reducer/initialize-graph-state.ts b/packages/perseus/src/widgets/interactive-graphs/reducer/initialize-graph-state.ts index 5cf40842223..10762fffb8e 100644 --- a/packages/perseus/src/widgets/interactive-graphs/reducer/initialize-graph-state.ts +++ b/packages/perseus/src/widgets/interactive-graphs/reducer/initialize-graph-state.ts @@ -146,6 +146,8 @@ export function initializeGraphState( type: graph.type, coords: getTangentCoords(graph, range, step), }; + case "vector": + throw new Error("Not implemented"); default: throw new UnreachableCaseError(graph); } diff --git a/packages/perseus/src/widgets/interactive-graphs/reducer/interactive-graph-reducer.ts b/packages/perseus/src/widgets/interactive-graphs/reducer/interactive-graph-reducer.ts index 762d2ee14f8..28681dce0b9 100644 --- a/packages/perseus/src/widgets/interactive-graphs/reducer/interactive-graph-reducer.ts +++ b/packages/perseus/src/widgets/interactive-graphs/reducer/interactive-graph-reducer.ts @@ -315,6 +315,7 @@ function doMovePointInFigure( case "absolute-value": case "tangent": case "exponential": + case "vector": throw new Error( `Don't use movePointInFigure for ${state.type} graphs. Use movePoint instead!`, ); diff --git a/packages/perseus/src/widgets/interactive-graphs/types.ts b/packages/perseus/src/widgets/interactive-graphs/types.ts index 3eec034675b..bc92c4bf447 100644 --- a/packages/perseus/src/widgets/interactive-graphs/types.ts +++ b/packages/perseus/src/widgets/interactive-graphs/types.ts @@ -42,7 +42,8 @@ export type InteractiveGraphState = | QuadraticGraphState | SinusoidGraphState | ExponentialGraphState - | TangentGraphState; + | TangentGraphState + | VectorGraphState; export type UnlimitedGraphState = PointGraphState | PolygonGraphState; @@ -90,6 +91,11 @@ export interface RayGraphState extends InteractiveGraphStateCommon { coords: PairOfPoints; } +interface VectorGraphState extends InteractiveGraphStateCommon { + type: "vector"; + coords: PairOfPoints; +} + export interface PolygonGraphState extends InteractiveGraphStateCommon { type: "polygon"; showAngles: boolean;