@khanacademy/perseus 53.1.0 → 54.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/highlighting/types.d.ts +2 -1
- package/dist/components.d.ts +0 -1
- package/dist/es/index.js +603 -1867
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +61 -10
- package/dist/es/strings.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +678 -691
- package/dist/index.js.map +1 -1
- package/dist/interactive2/movable.d.ts +2 -1
- package/dist/strings.d.ts +57 -6
- package/dist/strings.js +139 -67
- package/dist/strings.js.map +1 -1
- package/dist/types.d.ts +3 -12
- package/dist/util/graphie.d.ts +1 -1
- package/dist/widget-ai-utils/radio/radio-ai-utils.d.ts +2 -1
- package/dist/widget-type-utils.d.ts +1 -0
- package/dist/widgets/categorizer/categorizer.d.ts +1 -2
- package/dist/widgets/cs-program/cs-program.d.ts +0 -2
- package/dist/widgets/dropdown/dropdown.d.ts +0 -2
- package/dist/widgets/expression/expression.d.ts +3 -4
- package/dist/widgets/grapher/grapher.d.ts +0 -2
- package/dist/widgets/iframe/iframe.d.ts +1 -2
- package/dist/widgets/interactive-graph.d.ts +2 -87
- package/dist/widgets/interactive-graphs/backgrounds/axis-labels.d.ts +4 -1
- package/dist/widgets/interactive-graphs/graphs/angle.d.ts +2 -1
- package/dist/widgets/interactive-graphs/graphs/circle.d.ts +6 -2
- package/dist/widgets/interactive-graphs/graphs/components/hairlines.d.ts +7 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point-view.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/components/svg-line.d.ts +2 -1
- package/dist/widgets/interactive-graphs/graphs/linear-system.d.ts +2 -2
- package/dist/widgets/interactive-graphs/graphs/linear.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/point.d.ts +3 -2
- package/dist/widgets/interactive-graphs/graphs/ray.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/screenreader-text.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/segment.d.ts +2 -2
- package/dist/widgets/interactive-graphs/graphs/sinusoid.d.ts +2 -1
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +0 -3
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +1 -2
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +3 -3
- package/dist/widgets/label-image/label-image.d.ts +1 -3
- package/dist/widgets/matrix/matrix.d.ts +1 -2
- package/dist/widgets/number-line/number-line.d.ts +0 -2
- package/dist/widgets/numeric-input/numeric-input.d.ts +0 -2
- package/dist/widgets/orderer/orderer.d.ts +0 -2
- package/dist/widgets/plotter/plotter.d.ts +0 -2
- package/dist/widgets/radio/radio.d.ts +1 -2
- package/dist/widgets/sorter/sorter.d.ts +1 -2
- package/dist/widgets/table/table.d.ts +0 -2
- package/dist/widgets.d.ts +1 -2
- package/package.json +10 -10
- package/dist/components/graph.d.ts +0 -61
package/dist/es/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as KAS from '@khanacademy/kas';
|
|
2
2
|
import { MathInputI18nContext, CursorContext, getKeyTranslator, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
|
|
3
|
-
import { PerseusError, Errors, expressionLogic,
|
|
3
|
+
import { PerseusError, Errors, expressionLogic, getDecimalSeparator, approximateDeepEqual, pluck, CoreWidgetRegistry, getUpgradedWidgetOptions, mapObject, passageRefLogic, radioLogic, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, getMatrixSize, measurerLogic, addLibraryVersionToPerseusDebug, upgradeWidgetInfoToLatestVersion, getWidgetIdsFromContentByType } from '@khanacademy/perseus-core';
|
|
4
4
|
export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
|
|
5
5
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
6
6
|
import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
|
|
@@ -33,7 +33,6 @@ import Banner from '@khanacademy/wonder-blocks-banner';
|
|
|
33
33
|
import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-blocks-dropdown';
|
|
34
34
|
import caretDown from '@phosphor-icons/core/regular/caret-down.svg';
|
|
35
35
|
import caretUp from '@phosphor-icons/core/regular/caret-up.svg';
|
|
36
|
-
import debounce$2 from 'lodash.debounce';
|
|
37
36
|
import { vec, Coordinates, Ellipse, Plot as Plot$2, Line as Line$4, Point as Point$2, Polygon, Text as Text$1, useTransformContext, Polyline, Mafs } from 'mafs';
|
|
38
37
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
39
38
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
@@ -240,6 +239,10 @@ const mockStrings = {
|
|
|
240
239
|
simulationLocaleWarning: "Sorry, this simulation isn't available in your language.",
|
|
241
240
|
selectAnAnswer: "Select an answer",
|
|
242
241
|
// The following strings are used for interactive graph SR descriptions.
|
|
242
|
+
srGraphInstructions: "Use the Tab key to move through the interactive elements in the graph. When an interactive element has focus, use the Arrow keys to move it.",
|
|
243
|
+
srUnlimitedGraphInstructions: "Press Shift + Enter to interact with the graph. Use the Tab key to move through the interactive elements in the graph and access the graph Action Bar. When an interactive element has focus, use the Arrow keys to move it or use the Delete key to remove it from the graph. Use the buttons in the Action Bar to add or adjust elements within the graph.",
|
|
244
|
+
xAxis: "X-axis",
|
|
245
|
+
yAxis: "Y-axis",
|
|
243
246
|
graphKeyboardPrompt: "Press Shift + Enter to interact with the graph",
|
|
244
247
|
addPoint: "Add Point",
|
|
245
248
|
removePoint: "Remove Point",
|
|
@@ -304,17 +307,23 @@ const mockStrings = {
|
|
|
304
307
|
point2X,
|
|
305
308
|
point2Y
|
|
306
309
|
}) => `Line from ${point1X} comma ${point1Y} to ${point2X} comma ${point2Y}.`,
|
|
307
|
-
|
|
308
|
-
point,
|
|
309
|
-
side,
|
|
310
|
+
srAngleStartingSide: ({
|
|
310
311
|
x,
|
|
311
312
|
y
|
|
312
|
-
}) => `Point
|
|
313
|
-
|
|
313
|
+
}) => `Point 3, starting side at ${x} comma ${y}.`,
|
|
314
|
+
srAngleEndingSide: ({
|
|
315
|
+
x,
|
|
316
|
+
y
|
|
317
|
+
}) => `Point 2, ending side at ${x} comma ${y}.`,
|
|
318
|
+
srAngleVertex: ({
|
|
319
|
+
x,
|
|
320
|
+
y
|
|
321
|
+
}) => `Point 1, vertex at ${x} comma ${y}.`,
|
|
322
|
+
srAngleVertexWithAngleMeasure: ({
|
|
314
323
|
x,
|
|
315
324
|
y,
|
|
316
325
|
angleMeasure
|
|
317
|
-
}) => `Point
|
|
326
|
+
}) => `Point 1, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees.`,
|
|
318
327
|
srAngleGraphAriaLabel: "An angle on a coordinate plane.",
|
|
319
328
|
srAngleGraphAriaDescription: ({
|
|
320
329
|
angleMeasure,
|
|
@@ -325,6 +334,14 @@ const mockStrings = {
|
|
|
325
334
|
endingSideX,
|
|
326
335
|
endingSideY
|
|
327
336
|
}) => `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`,
|
|
337
|
+
srAngleInteractiveElements: ({
|
|
338
|
+
vertexX,
|
|
339
|
+
vertexY,
|
|
340
|
+
startingSideX,
|
|
341
|
+
startingSideY,
|
|
342
|
+
endingSideX,
|
|
343
|
+
endingSideY
|
|
344
|
+
}) => `An angle formed by 3 points. The vertex is at ${vertexX} comma ${vertexY}. The starting side point is at ${startingSideX} comma ${startingSideY}. The ending side point is at ${endingSideX} comma ${endingSideY}.`,
|
|
328
345
|
srSingleSegmentGraphAriaLabel: "A line segment on a coordinate plane.",
|
|
329
346
|
srMultipleSegmentGraphAriaLabel: ({
|
|
330
347
|
countOfSegments
|
|
@@ -462,7 +479,28 @@ const mockStrings = {
|
|
|
462
479
|
pointNum,
|
|
463
480
|
length
|
|
464
481
|
}) => `A line segment, length approximately equal to ${length} units, connects to point ${pointNum}.`,
|
|
465
|
-
srUnlimitedPolygonEmpty: "An empty coordinate plane."
|
|
482
|
+
srUnlimitedPolygonEmpty: "An empty coordinate plane.",
|
|
483
|
+
srSinusoidGraph: "A sinusoid function on a coordinate plane.",
|
|
484
|
+
srSinusoidRootPoint: ({
|
|
485
|
+
x,
|
|
486
|
+
y
|
|
487
|
+
}) => `Midline intersection at ${x} comma ${y}.`,
|
|
488
|
+
srSinusoidPeakPoint: ({
|
|
489
|
+
x,
|
|
490
|
+
y
|
|
491
|
+
}) => `Extremum point at ${x} comma ${y}.`,
|
|
492
|
+
srSinusoidDescription: ({
|
|
493
|
+
minValue,
|
|
494
|
+
maxValue,
|
|
495
|
+
cycleStart,
|
|
496
|
+
cycleEnd
|
|
497
|
+
}) => `The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${cycleStart} to ${cycleEnd}.`,
|
|
498
|
+
srSinusoidInteractiveElements: ({
|
|
499
|
+
point1X,
|
|
500
|
+
point1Y,
|
|
501
|
+
point2X,
|
|
502
|
+
point2Y
|
|
503
|
+
}) => `Sinusoid graph with midline intersection point at ${point1X} comma ${point1Y} and extremum point at ${point2X} comma ${point2Y}.`
|
|
466
504
|
// The above strings are used for interactive graph SR descriptions.
|
|
467
505
|
};
|
|
468
506
|
|
|
@@ -1394,6 +1432,7 @@ const ApiOptions = {
|
|
|
1394
1432
|
},
|
|
1395
1433
|
baseElements: {
|
|
1396
1434
|
Link: props => {
|
|
1435
|
+
// eslint-disable-next-line jsx-a11y/anchor-has-content -- TODO(LEMS-2871): Address a11y error
|
|
1397
1436
|
return /*#__PURE__*/React.createElement("a", props);
|
|
1398
1437
|
}
|
|
1399
1438
|
},
|
|
@@ -1797,7 +1836,6 @@ var Expression$1 = {
|
|
|
1797
1836
|
propUpgrades: expressionLogic.widgetOptionsUpgrades,
|
|
1798
1837
|
// For use by the editor
|
|
1799
1838
|
isLintable: true,
|
|
1800
|
-
getPublicWidgetOptions: getExpressionPublicWidgetOptions,
|
|
1801
1839
|
// TODO(LEMS-2656): remove TS suppression
|
|
1802
1840
|
// @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusExpressionRubric'.
|
|
1803
1841
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
@@ -15699,12 +15737,17 @@ class ImageLoader extends React.Component {
|
|
|
15699
15737
|
};
|
|
15700
15738
|
}
|
|
15701
15739
|
const staticUrl = getDependencies().staticUrl;
|
|
15702
|
-
return
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15740
|
+
return (
|
|
15741
|
+
/*#__PURE__*/
|
|
15742
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
15743
|
+
React.createElement("img", _extends({
|
|
15744
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
|
|
15745
|
+
tabIndex: 0,
|
|
15746
|
+
src: staticUrl(src),
|
|
15747
|
+
onKeyUp: onKeyUp,
|
|
15748
|
+
onKeyDown: onKeyDown
|
|
15749
|
+
}, imgProps))
|
|
15750
|
+
);
|
|
15708
15751
|
};
|
|
15709
15752
|
this.state = {
|
|
15710
15753
|
status: props.src ? Status.LOADING : Status.PENDING
|
|
@@ -16389,16 +16432,20 @@ class Zoomable extends React.Component {
|
|
|
16389
16432
|
opacity: opacity,
|
|
16390
16433
|
WebkitTapHighlightColor: "transparent"
|
|
16391
16434
|
}, transitionStyle);
|
|
16392
|
-
return
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16435
|
+
return (
|
|
16436
|
+
/*#__PURE__*/
|
|
16437
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- TODO(LEMS-2871): Address a11y error
|
|
16438
|
+
React.createElement("span", {
|
|
16439
|
+
onClick: this.handleClick,
|
|
16440
|
+
onClickCapture: this.handleClickIfZoomed,
|
|
16441
|
+
onTouchCancelCapture: this.stopPropagationIfZoomed,
|
|
16442
|
+
onTouchEndCapture: this.stopPropagationIfZoomed,
|
|
16443
|
+
onTouchStartCapture: this.stopPropagationIfZoomed
|
|
16444
|
+
// @ts-expect-error - TS2322 - Type '{ readonly transitionProperty: string; readonly transitionDuration: string; readonly transitionTimingFunction: string; readonly display: "block"; readonly width: "100%"; readonly height: number | ... 1 more ... | undefined; readonly transform: string; readonly transformOrigin: "0 0"; readonly opacity: 0 | 1; readonl...' is not assignable to type 'CSSProperties | undefined'.
|
|
16445
|
+
,
|
|
16446
|
+
style: style
|
|
16447
|
+
}, this.props.children)
|
|
16448
|
+
);
|
|
16402
16449
|
}
|
|
16403
16450
|
}
|
|
16404
16451
|
Zoomable.defaultProps = {
|
|
@@ -17619,10 +17666,6 @@ const getWidgetExport = name => {
|
|
|
17619
17666
|
var _widgets$name3;
|
|
17620
17667
|
return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
|
|
17621
17668
|
};
|
|
17622
|
-
const getPublicWidgetOptionsFunction = name => {
|
|
17623
|
-
var _widgets$name$getPubl, _widgets$name4;
|
|
17624
|
-
return (_widgets$name$getPubl = (_widgets$name4 = widgets[name]) == null ? void 0 : _widgets$name4.getPublicWidgetOptions) != null ? _widgets$name$getPubl : i => i;
|
|
17625
|
-
};
|
|
17626
17669
|
const getEditor = name => {
|
|
17627
17670
|
return _.has(editors, name) ? editors[name] : null;
|
|
17628
17671
|
};
|
|
@@ -17759,7 +17802,6 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
17759
17802
|
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
17760
17803
|
getWidget: getWidget,
|
|
17761
17804
|
getWidgetExport: getWidgetExport,
|
|
17762
|
-
getPublicWidgetOptionsFunction: getPublicWidgetOptionsFunction,
|
|
17763
17805
|
getEditor: getEditor,
|
|
17764
17806
|
getTransform: getTransform,
|
|
17765
17807
|
getVersion: getVersion,
|
|
@@ -17835,6 +17877,7 @@ class WidgetContainer extends React.Component {
|
|
|
17835
17877
|
"perseus-widget__definition": this.props.type === "definition"
|
|
17836
17878
|
});
|
|
17837
17879
|
const type = this.props.type;
|
|
17880
|
+
const userAgent = navigator.userAgent;
|
|
17838
17881
|
const WidgetType = getWidget(type);
|
|
17839
17882
|
if (WidgetType == null) {
|
|
17840
17883
|
// This is for the good of all people!!
|
|
@@ -17845,6 +17888,12 @@ class WidgetContainer extends React.Component {
|
|
|
17845
17888
|
className: className
|
|
17846
17889
|
});
|
|
17847
17890
|
}
|
|
17891
|
+
let subType = "null";
|
|
17892
|
+
if (type === "interactive-graph") {
|
|
17893
|
+
var _props$graph$type, _props$graph;
|
|
17894
|
+
const props = this.state.widgetProps;
|
|
17895
|
+
subType = (_props$graph$type = (_props$graph = props.graph) == null ? void 0 : _props$graph.type) != null ? _props$graph$type : "null";
|
|
17896
|
+
}
|
|
17848
17897
|
let alignment = this.state.widgetProps.alignment;
|
|
17849
17898
|
if (alignment === "default") {
|
|
17850
17899
|
alignment = CoreWidgetRegistry.getDefaultAlignment(type);
|
|
@@ -17898,12 +17947,26 @@ class WidgetContainer extends React.Component {
|
|
|
17898
17947
|
widget_type: type,
|
|
17899
17948
|
widget_id: this.props.id
|
|
17900
17949
|
},
|
|
17901
|
-
onError:
|
|
17950
|
+
onError: error => {
|
|
17951
|
+
// TODO(LEMS-2826): Remove analytics event in LEMS-2826 in favor of ti below.
|
|
17902
17952
|
analytics.onAnalyticsEvent({
|
|
17903
17953
|
type: "perseus:widget-rendering-error",
|
|
17904
17954
|
payload: {
|
|
17955
|
+
widgetSubType: subType,
|
|
17956
|
+
widgetType: type,
|
|
17957
|
+
widgetId: this.props.id,
|
|
17958
|
+
message: error.message,
|
|
17959
|
+
userAgent: userAgent
|
|
17960
|
+
}
|
|
17961
|
+
});
|
|
17962
|
+
analytics.onAnalyticsEvent({
|
|
17963
|
+
type: "perseus:widget-rendering-error:ti",
|
|
17964
|
+
payload: {
|
|
17965
|
+
widgetSubType: subType,
|
|
17905
17966
|
widgetType: type,
|
|
17906
|
-
widgetId: this.props.id
|
|
17967
|
+
widgetId: this.props.id,
|
|
17968
|
+
message: error.message,
|
|
17969
|
+
userAgent: userAgent
|
|
17907
17970
|
}
|
|
17908
17971
|
});
|
|
17909
17972
|
}
|
|
@@ -20327,7 +20390,6 @@ var NumericInput$1 = {
|
|
|
20327
20390
|
widget: NumericInput,
|
|
20328
20391
|
transform: propsTransform,
|
|
20329
20392
|
isLintable: true,
|
|
20330
|
-
getPublicWidgetOptions: getNumericInputPublicWidgetOptions,
|
|
20331
20393
|
// TODO(LEMS-2656): remove TS suppression
|
|
20332
20394
|
// @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusNumericInputRubric'
|
|
20333
20395
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
@@ -21132,7 +21194,10 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
21132
21194
|
// using div instead of TooltipContent because
|
|
21133
21195
|
// TooltipContent wouldn't let me overwrite
|
|
21134
21196
|
// user-select and onClick
|
|
21135
|
-
const content =
|
|
21197
|
+
const content =
|
|
21198
|
+
/*#__PURE__*/
|
|
21199
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- TODO(LEMS-2871): Address a11y error
|
|
21200
|
+
React.createElement("div", {
|
|
21136
21201
|
className: css(styles$x.tooltipLabel),
|
|
21137
21202
|
onClick: this.props.onClick
|
|
21138
21203
|
}, this.props.label);
|
|
@@ -21143,14 +21208,18 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
21143
21208
|
top: `calc(${Math.round(focusRect.top)}px + 0.95em)`,
|
|
21144
21209
|
height: 0
|
|
21145
21210
|
};
|
|
21146
|
-
return
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21211
|
+
return (
|
|
21212
|
+
/*#__PURE__*/
|
|
21213
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
21214
|
+
React.createElement("div", {
|
|
21215
|
+
style: style,
|
|
21216
|
+
onMouseEnter: this.props.onMouseEnter,
|
|
21217
|
+
onMouseLeave: this.props.onMouseLeave
|
|
21218
|
+
}, /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
21219
|
+
content: content,
|
|
21220
|
+
opened: true
|
|
21221
|
+
}, /*#__PURE__*/React.createElement("div", null)))
|
|
21222
|
+
);
|
|
21154
21223
|
}
|
|
21155
21224
|
}
|
|
21156
21225
|
const styles$x = StyleSheet.create({
|
|
@@ -23853,15 +23922,19 @@ const BaseRadio = function BaseRadio({
|
|
|
23853
23922
|
// content somehow? Would changing our choice of key
|
|
23854
23923
|
// somehow break something happening inside a choice's
|
|
23855
23924
|
// child Renderers, by changing when we mount/unmount?
|
|
23856
|
-
return
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
23864
|
-
|
|
23925
|
+
return (
|
|
23926
|
+
/*#__PURE__*/
|
|
23927
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
23928
|
+
React.createElement("li", {
|
|
23929
|
+
key: i,
|
|
23930
|
+
ref: e => listElem = e,
|
|
23931
|
+
className: className,
|
|
23932
|
+
onClick: clickHandler,
|
|
23933
|
+
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
23934
|
+
}, /*#__PURE__*/React.createElement(Element, _extends({}, elementProps, {
|
|
23935
|
+
ref: ref
|
|
23936
|
+
})))
|
|
23937
|
+
);
|
|
23865
23938
|
})));
|
|
23866
23939
|
|
|
23867
23940
|
// Allow for horizontal scrolling if content is too wide, which may be
|
|
@@ -24391,8 +24464,7 @@ var Radio = {
|
|
|
24391
24464
|
staticTransform: transform,
|
|
24392
24465
|
version: radioLogic.version,
|
|
24393
24466
|
propUpgrades: radioLogic.widgetOptionsUpgrades,
|
|
24394
|
-
isLintable: true
|
|
24395
|
-
getPublicWidgetOptions: getRadioPublicWidgetOptions
|
|
24467
|
+
isLintable: true
|
|
24396
24468
|
};
|
|
24397
24469
|
|
|
24398
24470
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -24678,8 +24750,7 @@ var Categorizer$1 = {
|
|
|
24678
24750
|
staticTransform: editorProps => {
|
|
24679
24751
|
return _.pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
24680
24752
|
},
|
|
24681
|
-
isLintable: true
|
|
24682
|
-
getPublicWidgetOptions: getCategorizerPublicWidgetOptions
|
|
24753
|
+
isLintable: true
|
|
24683
24754
|
};
|
|
24684
24755
|
|
|
24685
24756
|
/**
|
|
@@ -24885,8 +24956,7 @@ var CSProgram$1 = {
|
|
|
24885
24956
|
name: "cs-program",
|
|
24886
24957
|
displayName: "CS Program",
|
|
24887
24958
|
widget: CSProgram,
|
|
24888
|
-
hidden: true
|
|
24889
|
-
getPublicWidgetOptions: getCSProgramPublicWidgetOptions
|
|
24959
|
+
hidden: true
|
|
24890
24960
|
};
|
|
24891
24961
|
|
|
24892
24962
|
const getPromptJSON$l = renderProps => {
|
|
@@ -25104,8 +25174,7 @@ var Dropdown$1 = {
|
|
|
25104
25174
|
displayName: "Drop down",
|
|
25105
25175
|
accessible: true,
|
|
25106
25176
|
widget: Dropdown,
|
|
25107
|
-
transform: optionsTransform
|
|
25108
|
-
getPublicWidgetOptions: getDropdownPublicWidgetOptions
|
|
25177
|
+
transform: optionsTransform
|
|
25109
25178
|
};
|
|
25110
25179
|
|
|
25111
25180
|
const getPromptJSON$j = renderProps => {
|
|
@@ -26579,8 +26648,7 @@ var Grapher$1 = {
|
|
|
26579
26648
|
hidden: true,
|
|
26580
26649
|
widget: Grapher,
|
|
26581
26650
|
transform: propTransform$2,
|
|
26582
|
-
staticTransform: staticTransform$4
|
|
26583
|
-
getPublicWidgetOptions: getGrapherPublicWidgetOptions
|
|
26651
|
+
staticTransform: staticTransform$4
|
|
26584
26652
|
};
|
|
26585
26653
|
|
|
26586
26654
|
const getPromptJSON$f = rendererJSON => {
|
|
@@ -26865,12 +26933,16 @@ class Iframe extends React.Component {
|
|
|
26865
26933
|
// that we need. This makes it a bit safer in case some content
|
|
26866
26934
|
// creator "went wild".
|
|
26867
26935
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
26868
|
-
return
|
|
26869
|
-
|
|
26870
|
-
|
|
26871
|
-
|
|
26872
|
-
|
|
26873
|
-
|
|
26936
|
+
return (
|
|
26937
|
+
/*#__PURE__*/
|
|
26938
|
+
// eslint-disable-next-line jsx-a11y/iframe-has-title -- TODO(LEMS-2871): Address a11y error
|
|
26939
|
+
React.createElement("iframe", {
|
|
26940
|
+
sandbox: sandboxProperties,
|
|
26941
|
+
style: style,
|
|
26942
|
+
src: url,
|
|
26943
|
+
allowFullScreen: this.props.allowFullScreen
|
|
26944
|
+
})
|
|
26945
|
+
);
|
|
26874
26946
|
}
|
|
26875
26947
|
}
|
|
26876
26948
|
Iframe.defaultProps = {
|
|
@@ -26885,8 +26957,7 @@ var Iframe$1 = {
|
|
|
26885
26957
|
displayName: "Iframe (deprecated)",
|
|
26886
26958
|
widget: Iframe,
|
|
26887
26959
|
// Let's not expose it to all content creators yet
|
|
26888
|
-
hidden: true
|
|
26889
|
-
getPublicWidgetOptions: getIFramePublicWidgetOptions
|
|
26960
|
+
hidden: true
|
|
26890
26961
|
};
|
|
26891
26962
|
|
|
26892
26963
|
const getPromptJSON$d = renderProps => {
|
|
@@ -26903,7 +26974,7 @@ const getPromptJSON$d = renderProps => {
|
|
|
26903
26974
|
|
|
26904
26975
|
const defaultBoxSize = 400;
|
|
26905
26976
|
const defaultRange = [0, 10];
|
|
26906
|
-
const defaultBackgroundImage$
|
|
26977
|
+
const defaultBackgroundImage$1 = {
|
|
26907
26978
|
url: null,
|
|
26908
26979
|
width: 0,
|
|
26909
26980
|
height: 0
|
|
@@ -27060,7 +27131,7 @@ ImageWidget.defaultProps = {
|
|
|
27060
27131
|
title: "",
|
|
27061
27132
|
range: [defaultRange, defaultRange],
|
|
27062
27133
|
box: [defaultBoxSize, defaultBoxSize],
|
|
27063
|
-
backgroundImage: defaultBackgroundImage$
|
|
27134
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
27064
27135
|
labels: [],
|
|
27065
27136
|
alt: "",
|
|
27066
27137
|
caption: "",
|
|
@@ -27677,307 +27748,6 @@ var Interactive = {
|
|
|
27677
27748
|
hidden: true
|
|
27678
27749
|
};
|
|
27679
27750
|
|
|
27680
|
-
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
27681
|
-
const defaultBackgroundImage$1 = {
|
|
27682
|
-
url: null
|
|
27683
|
-
};
|
|
27684
|
-
|
|
27685
|
-
/* Style objects */
|
|
27686
|
-
const defaultInstructionsStyle = {
|
|
27687
|
-
fontStyle: "italic",
|
|
27688
|
-
fontWeight: "bold",
|
|
27689
|
-
fontSize: "32px",
|
|
27690
|
-
width: "100%",
|
|
27691
|
-
height: "100%",
|
|
27692
|
-
textAlign: "center",
|
|
27693
|
-
backgroundColor: "white",
|
|
27694
|
-
position: "absolute",
|
|
27695
|
-
zIndex: 1,
|
|
27696
|
-
transition: "opacity .25s ease-in-out"
|
|
27697
|
-
};
|
|
27698
|
-
const instructionsTextStyle = {
|
|
27699
|
-
position: "relative",
|
|
27700
|
-
top: "25%"
|
|
27701
|
-
};
|
|
27702
|
-
function numSteps$1(range, step) {
|
|
27703
|
-
return Math.floor((range[1] - range[0]) / step);
|
|
27704
|
-
}
|
|
27705
|
-
class Graph extends React.Component {
|
|
27706
|
-
constructor(...args) {
|
|
27707
|
-
super(...args);
|
|
27708
|
-
this.graphieDivRef = /*#__PURE__*/React.createRef();
|
|
27709
|
-
this.protractor = void 0;
|
|
27710
|
-
this.ruler = void 0;
|
|
27711
|
-
this._graphie = void 0;
|
|
27712
|
-
// @ts-expect-error - TS2564 - Property '_hasSetupGraphieThisUpdate' has no initializer and is not definitely assigned in the constructor.
|
|
27713
|
-
this._hasSetupGraphieThisUpdate = void 0;
|
|
27714
|
-
// @ts-expect-error - TS2564 - Property '_shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
27715
|
-
this._shouldSetupGraphie = void 0;
|
|
27716
|
-
/* Reset the graphie canvas to its initial state
|
|
27717
|
-
*
|
|
27718
|
-
* Use when re-rendering the parent component and you need a blank
|
|
27719
|
-
* graphie.
|
|
27720
|
-
*/
|
|
27721
|
-
this.reset = () => {
|
|
27722
|
-
this._setupGraphie(false);
|
|
27723
|
-
};
|
|
27724
|
-
this.graphie = () => {
|
|
27725
|
-
return this._graphie;
|
|
27726
|
-
};
|
|
27727
|
-
this.pointsFromNormalized = (coordsList, noSnap) => {
|
|
27728
|
-
const self = this;
|
|
27729
|
-
return _.map(coordsList, function (coords) {
|
|
27730
|
-
return _.map(coords, function (coord, i) {
|
|
27731
|
-
const range = self.props.range[i];
|
|
27732
|
-
if (noSnap) {
|
|
27733
|
-
return range[0] + (range[1] - range[0]) * coord;
|
|
27734
|
-
}
|
|
27735
|
-
const step = self.props.step[i];
|
|
27736
|
-
const nSteps = numSteps$1(range, step);
|
|
27737
|
-
const tick = Math.round(coord * nSteps);
|
|
27738
|
-
return range[0] + step * tick;
|
|
27739
|
-
});
|
|
27740
|
-
});
|
|
27741
|
-
};
|
|
27742
|
-
this._setupGraphie = initialMount => {
|
|
27743
|
-
// Only setupGraphie once per componentDidUpdate().
|
|
27744
|
-
// This prevents this component from rendering graphie
|
|
27745
|
-
// and then immediately re-render graphie because its
|
|
27746
|
-
// parent component asked it to. This will happen when
|
|
27747
|
-
// props on the parent and props on this component both
|
|
27748
|
-
// require graphie to be re-rendered.
|
|
27749
|
-
if (this._hasSetupGraphieThisUpdate) {
|
|
27750
|
-
return;
|
|
27751
|
-
}
|
|
27752
|
-
const graphieDiv = this.graphieDivRef.current;
|
|
27753
|
-
// @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'empty' does not exist on type 'JQueryStatic'.
|
|
27754
|
-
$(graphieDiv).empty();
|
|
27755
|
-
|
|
27756
|
-
// Content creators may need to explicitly add the dollar signs so the
|
|
27757
|
-
// strings are picked up by our translation tools. However, these math
|
|
27758
|
-
// annotations are redundant because we already render all graph labels
|
|
27759
|
-
// in math mode. For example, a label value of `$\text{Dollars}$` will
|
|
27760
|
-
// be translatable, but we only want to pass the string
|
|
27761
|
-
// `\text{Dollars}` to the Graph widget.
|
|
27762
|
-
const labels = this.props.labels.map(label => Util.unescapeMathMode(label));
|
|
27763
|
-
const range = this.props.range;
|
|
27764
|
-
// @ts-expect-error - TS2345: Argument of type 'Element | Text | null' is not assignable to parameter of type 'HTMLElement'.
|
|
27765
|
-
const graphie = this._graphie = GraphUtils.createGraphie(graphieDiv);
|
|
27766
|
-
const gridConfig = this._getGridConfig();
|
|
27767
|
-
// @ts-expect-error - TS2339: Property 'snap' does not exist on type 'Graphie'.
|
|
27768
|
-
graphie.snap = this.props.snapStep;
|
|
27769
|
-
if (this.props.markings === "graph") {
|
|
27770
|
-
graphie.graphInit({
|
|
27771
|
-
range: range,
|
|
27772
|
-
scale: vector$3.map(gridConfig, g => g.scale),
|
|
27773
|
-
axisArrows: "<->",
|
|
27774
|
-
labelFormat: function (s) {
|
|
27775
|
-
return "\\small{" + s + "}";
|
|
27776
|
-
},
|
|
27777
|
-
gridStep: this.props.gridStep,
|
|
27778
|
-
tickStep: vector$3.map(gridConfig, g => g.tickStep),
|
|
27779
|
-
labelStep: 1,
|
|
27780
|
-
unityLabels: vector$3.map(gridConfig, g => g.unityLabel),
|
|
27781
|
-
isMobile: this.props.isMobile
|
|
27782
|
-
});
|
|
27783
|
-
graphie.label([0, range[1][1]], labels[1], this.props.isMobile ? "below right" : "above");
|
|
27784
|
-
graphie.label([range[0][1], 0], labels[0], this.props.isMobile ? "above left" : "right");
|
|
27785
|
-
} else if (this.props.markings === "grid") {
|
|
27786
|
-
graphie.graphInit({
|
|
27787
|
-
range: range,
|
|
27788
|
-
scale: vector$3.map(gridConfig, g => g.scale),
|
|
27789
|
-
gridStep: this.props.gridStep,
|
|
27790
|
-
axes: false,
|
|
27791
|
-
ticks: false,
|
|
27792
|
-
labels: false,
|
|
27793
|
-
isMobile: this.props.isMobile
|
|
27794
|
-
});
|
|
27795
|
-
} else if (this.props.markings === "none") {
|
|
27796
|
-
graphie.init({
|
|
27797
|
-
range: range,
|
|
27798
|
-
scale: vector$3.map(gridConfig, g => g.scale),
|
|
27799
|
-
isMobile: this.props.isMobile
|
|
27800
|
-
});
|
|
27801
|
-
}
|
|
27802
|
-
|
|
27803
|
-
// Add instructions just before mouse layer
|
|
27804
|
-
const visible = 0.5;
|
|
27805
|
-
const invisible = 0.0;
|
|
27806
|
-
let $instructionsWrapper;
|
|
27807
|
-
if (this.props.instructions) {
|
|
27808
|
-
$instructionsWrapper = $("<div/>");
|
|
27809
|
-
_.each(defaultInstructionsStyle, function (value, key) {
|
|
27810
|
-
$instructionsWrapper.css(key, value);
|
|
27811
|
-
});
|
|
27812
|
-
$instructionsWrapper.css("opacity", visible);
|
|
27813
|
-
const $instructions = $("<span/>", {
|
|
27814
|
-
text: this.props.instructions
|
|
27815
|
-
});
|
|
27816
|
-
_.each(instructionsTextStyle, function (value, key) {
|
|
27817
|
-
$instructions.css(key, value);
|
|
27818
|
-
});
|
|
27819
|
-
$instructionsWrapper.append($instructions);
|
|
27820
|
-
// @ts-expect-error - TS2769 - No overload matches this call. | TS2339 - Property 'append' does not exist on type 'JQueryStatic'.
|
|
27821
|
-
$(graphieDiv).append($instructionsWrapper);
|
|
27822
|
-
} else {
|
|
27823
|
-
$instructionsWrapper = undefined;
|
|
27824
|
-
}
|
|
27825
|
-
|
|
27826
|
-
// Add some handlers for instructions text (if necessary)
|
|
27827
|
-
const onMouseDown = $instructionsWrapper || this.props.onMouseDown ? _.bind(function (coord) {
|
|
27828
|
-
if ($instructionsWrapper) {
|
|
27829
|
-
$instructionsWrapper.remove();
|
|
27830
|
-
$instructionsWrapper = null;
|
|
27831
|
-
}
|
|
27832
|
-
// eslint-disable-next-line @babel/no-invalid-this
|
|
27833
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
27834
|
-
// eslint-disable-next-line @babel/no-invalid-this
|
|
27835
|
-
this.props.onMouseDown(coord);
|
|
27836
|
-
}, this) : undefined;
|
|
27837
|
-
const onMouseOver = $instructionsWrapper ? function () {
|
|
27838
|
-
var _$instructionsWrapper;
|
|
27839
|
-
(_$instructionsWrapper = $instructionsWrapper) == null || _$instructionsWrapper.css("opacity", invisible);
|
|
27840
|
-
} : undefined;
|
|
27841
|
-
const onMouseOut = $instructionsWrapper ? function () {
|
|
27842
|
-
var _$instructionsWrapper2;
|
|
27843
|
-
(_$instructionsWrapper2 = $instructionsWrapper) == null || _$instructionsWrapper2.css("opacity", visible);
|
|
27844
|
-
} : undefined;
|
|
27845
|
-
/* eslint-enable indent */
|
|
27846
|
-
|
|
27847
|
-
graphie.addMouseLayer({
|
|
27848
|
-
onClick: this.props.onClick,
|
|
27849
|
-
onMouseDown: onMouseDown,
|
|
27850
|
-
onMouseOver: onMouseOver,
|
|
27851
|
-
onMouseOut: onMouseOut,
|
|
27852
|
-
onMouseMove: this.props.onMouseMove,
|
|
27853
|
-
allowScratchpad: true,
|
|
27854
|
-
setDrawingAreaAvailable: this.props.setDrawingAreaAvailable
|
|
27855
|
-
});
|
|
27856
|
-
this._updateProtractor();
|
|
27857
|
-
this._updateRuler();
|
|
27858
|
-
|
|
27859
|
-
// We set this flag before jumping into our callback
|
|
27860
|
-
// to avoid recursing if our callback calls reset() itself
|
|
27861
|
-
this._hasSetupGraphieThisUpdate = true;
|
|
27862
|
-
if (!initialMount && this.props.onGraphieUpdated) {
|
|
27863
|
-
// Calling a parent callback in componentDidMount is bad and
|
|
27864
|
-
// results in hard-to-reason-about lifecycle problems (esp. with
|
|
27865
|
-
// refs), so we do it only on update and rely on the parent to
|
|
27866
|
-
// query for the graphie object on initial mount
|
|
27867
|
-
this.props.onGraphieUpdated(graphie);
|
|
27868
|
-
}
|
|
27869
|
-
};
|
|
27870
|
-
this._getGridConfig = () => {
|
|
27871
|
-
return vector$3.map(this.props.step, (step, i) => Util.gridDimensionConfig(step, this.props.range[i], this.props.box[i], this.props.gridStep[i]));
|
|
27872
|
-
};
|
|
27873
|
-
this._updateProtractor = () => {
|
|
27874
|
-
if (this.protractor) {
|
|
27875
|
-
this.protractor.remove();
|
|
27876
|
-
}
|
|
27877
|
-
if (this.props.showProtractor) {
|
|
27878
|
-
// @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
|
|
27879
|
-
const coord = this.pointsFromNormalized([[0.5, 0.05]])[0];
|
|
27880
|
-
this.protractor = this._graphie.protractor(coord);
|
|
27881
|
-
}
|
|
27882
|
-
};
|
|
27883
|
-
this._updateRuler = () => {
|
|
27884
|
-
if (this.ruler) {
|
|
27885
|
-
this.ruler.remove();
|
|
27886
|
-
}
|
|
27887
|
-
if (this.props.showRuler) {
|
|
27888
|
-
// @ts-expect-error - TS2554 - Expected 2 arguments, but got 1.
|
|
27889
|
-
const coord = this.pointsFromNormalized([[0.5, 0.25]])[0];
|
|
27890
|
-
const extent = this._graphie.range[0][1] - this._graphie.range[0][0];
|
|
27891
|
-
this.ruler = this._graphie.ruler({
|
|
27892
|
-
center: coord,
|
|
27893
|
-
label: this.props.rulerLabel,
|
|
27894
|
-
pixelsPerUnit: this._graphie.scale[0],
|
|
27895
|
-
ticksPerUnit: this.props.rulerTicks,
|
|
27896
|
-
units: Math.round(0.8 * extent)
|
|
27897
|
-
});
|
|
27898
|
-
}
|
|
27899
|
-
};
|
|
27900
|
-
this.toJSON = () => {
|
|
27901
|
-
return _.pick(this.props, "range", "step", "markings", "labels", "backgroundImage", "showProtractor", "showRuler", "rulerLabel", "rulerTicks", "gridStep", "snapStep");
|
|
27902
|
-
};
|
|
27903
|
-
}
|
|
27904
|
-
componentDidMount() {
|
|
27905
|
-
this._setupGraphie(true);
|
|
27906
|
-
}
|
|
27907
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
27908
|
-
const potentialChanges = ["labels", "range", "step", "markings", "showProtractor", "showRuler", "rulerLabel", "rulerTicks", "gridStep", "snapStep"];
|
|
27909
|
-
const self = this;
|
|
27910
|
-
_.each(potentialChanges, function (prop) {
|
|
27911
|
-
if (!_.isEqual(self.props[prop], nextProps[prop])) {
|
|
27912
|
-
self._shouldSetupGraphie = true;
|
|
27913
|
-
}
|
|
27914
|
-
});
|
|
27915
|
-
}
|
|
27916
|
-
componentDidUpdate() {
|
|
27917
|
-
// Only setupGraphie once per componentDidUpdate().
|
|
27918
|
-
// See explanation in setupGraphie().
|
|
27919
|
-
this._hasSetupGraphieThisUpdate = false;
|
|
27920
|
-
if (this._shouldSetupGraphie) {
|
|
27921
|
-
this._setupGraphie(false);
|
|
27922
|
-
this._shouldSetupGraphie = false;
|
|
27923
|
-
}
|
|
27924
|
-
}
|
|
27925
|
-
render() {
|
|
27926
|
-
let image;
|
|
27927
|
-
const imageData = this.props.backgroundImage;
|
|
27928
|
-
if (imageData.url) {
|
|
27929
|
-
const scale = this.props.box[0] / interactiveSizes$1.defaultBoxSize;
|
|
27930
|
-
image = /*#__PURE__*/React.createElement(context$1.Consumer, null, ({
|
|
27931
|
-
setAssetStatus
|
|
27932
|
-
}) => /*#__PURE__*/React.createElement(SvgImage
|
|
27933
|
-
// @ts-expect-error - TS2741 - Property 'alt' is missing in type '{ src: any; width: any; height: any; scale: number; responsive: false; }' but required in type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "children" | "height" | "width" | "title" | "alt" | "trackInteraction" | "preloader" | "allowFullBleed" | "extraGraphie" | "overrideAriaHidden">'.
|
|
27934
|
-
, {
|
|
27935
|
-
src: imageData.url,
|
|
27936
|
-
width: imageData.width,
|
|
27937
|
-
height: imageData.height,
|
|
27938
|
-
scale: scale,
|
|
27939
|
-
responsive: false,
|
|
27940
|
-
setAssetStatus: setAssetStatus
|
|
27941
|
-
}));
|
|
27942
|
-
} else {
|
|
27943
|
-
image = null;
|
|
27944
|
-
}
|
|
27945
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
27946
|
-
className: "graphie-container blank-background",
|
|
27947
|
-
style: {
|
|
27948
|
-
width: this.props.box[0],
|
|
27949
|
-
height: this.props.box[1]
|
|
27950
|
-
}
|
|
27951
|
-
// @ts-expect-error - TS2339 - Property 'onMouseOut' does not exist on type 'Graph'.
|
|
27952
|
-
,
|
|
27953
|
-
onMouseOut: this.onMouseOut
|
|
27954
|
-
// @ts-expect-error - TS2339 - Property 'onMouseOver' does not exist on type 'Graph'.
|
|
27955
|
-
,
|
|
27956
|
-
onMouseOver: this.onMouseOver
|
|
27957
|
-
// @ts-expect-error - TS2339 - Property 'onClick' does not exist on type 'Graph'.
|
|
27958
|
-
,
|
|
27959
|
-
onClick: this.onClick
|
|
27960
|
-
}, image, /*#__PURE__*/React.createElement("div", {
|
|
27961
|
-
className: "graphie",
|
|
27962
|
-
ref: this.graphieDivRef
|
|
27963
|
-
}));
|
|
27964
|
-
}
|
|
27965
|
-
}
|
|
27966
|
-
Graph.defaultProps = {
|
|
27967
|
-
labels: ["x", "y"],
|
|
27968
|
-
range: [[-10, 10], [-10, 10]],
|
|
27969
|
-
step: [1, 1],
|
|
27970
|
-
gridStep: [1, 1],
|
|
27971
|
-
snapStep: [0.5, 0.5],
|
|
27972
|
-
markings: "graph",
|
|
27973
|
-
backgroundImage: defaultBackgroundImage$1,
|
|
27974
|
-
showProtractor: false,
|
|
27975
|
-
showRuler: false,
|
|
27976
|
-
rulerLabel: "",
|
|
27977
|
-
rulerTicks: 10,
|
|
27978
|
-
isMobile: false
|
|
27979
|
-
};
|
|
27980
|
-
|
|
27981
27751
|
const getPromptJSON$b = (props, userInput) => {
|
|
27982
27752
|
var _props$backgroundImag;
|
|
27983
27753
|
return {
|
|
@@ -28530,13 +28300,18 @@ function escapeIfUnescaped(character) {
|
|
|
28530
28300
|
}
|
|
28531
28301
|
}
|
|
28532
28302
|
|
|
28533
|
-
function AxisLabels(
|
|
28303
|
+
function AxisLabels({
|
|
28304
|
+
i18n
|
|
28305
|
+
}) {
|
|
28534
28306
|
const {
|
|
28535
28307
|
range,
|
|
28536
28308
|
labels,
|
|
28537
28309
|
width,
|
|
28538
28310
|
height
|
|
28539
28311
|
} = useGraphConfig();
|
|
28312
|
+
const {
|
|
28313
|
+
strings
|
|
28314
|
+
} = i18n;
|
|
28540
28315
|
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
28541
28316
|
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
28542
28317
|
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
@@ -28554,6 +28329,7 @@ function AxisLabels() {
|
|
|
28554
28329
|
TeX
|
|
28555
28330
|
} = getDependencies();
|
|
28556
28331
|
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
|
|
28332
|
+
"aria-label": strings.xAxis,
|
|
28557
28333
|
style: {
|
|
28558
28334
|
position: "absolute",
|
|
28559
28335
|
left: x1,
|
|
@@ -28562,6 +28338,7 @@ function AxisLabels() {
|
|
|
28562
28338
|
transform: "translate(7px, -50%)"
|
|
28563
28339
|
}
|
|
28564
28340
|
}, /*#__PURE__*/React__default.createElement(TeX, null, replaceOutsideTeX(xAxisLabelText))), /*#__PURE__*/React__default.createElement("span", {
|
|
28341
|
+
"aria-label": strings.yAxis,
|
|
28565
28342
|
style: {
|
|
28566
28343
|
position: "absolute",
|
|
28567
28344
|
left: x2,
|
|
@@ -29371,7 +29148,6 @@ RangeInput.defaultProps = {
|
|
|
29371
29148
|
var components = /*#__PURE__*/Object.freeze({
|
|
29372
29149
|
__proto__: null,
|
|
29373
29150
|
ButtonGroup: ButtonGroup,
|
|
29374
|
-
Graph: Graph,
|
|
29375
29151
|
Graphie: Graphie,
|
|
29376
29152
|
HUD: HUD,
|
|
29377
29153
|
Icon: Icon,
|
|
@@ -29512,9 +29288,9 @@ const LockedFunction = props => {
|
|
|
29512
29288
|
const {
|
|
29513
29289
|
color,
|
|
29514
29290
|
strokeStyle,
|
|
29515
|
-
directionalAxis
|
|
29516
|
-
domain
|
|
29291
|
+
directionalAxis
|
|
29517
29292
|
} = props;
|
|
29293
|
+
const domain = props.domain ? [Number.isFinite(props.domain[0]) ? props.domain[0] : -Infinity, Number.isFinite(props.domain[1]) ? props.domain[1] : Infinity] : undefined;
|
|
29518
29294
|
const plotProps = {
|
|
29519
29295
|
color: lockedFigureColors[color],
|
|
29520
29296
|
style: strokeStyle,
|
|
@@ -29594,6 +29370,11 @@ function Vector(props) {
|
|
|
29594
29370
|
}
|
|
29595
29371
|
|
|
29596
29372
|
function srFormatNumber(a, locale, maximumFractionDigits) {
|
|
29373
|
+
const piBasedNumber = getPiMultiple(a);
|
|
29374
|
+
if (piBasedNumber) {
|
|
29375
|
+
return piBasedNumber;
|
|
29376
|
+
}
|
|
29377
|
+
|
|
29597
29378
|
// adding zero here converts negative zero to positive zero.
|
|
29598
29379
|
return (0 + a).toLocaleString(locale, {
|
|
29599
29380
|
maximumFractionDigits: maximumFractionDigits != null ? maximumFractionDigits : 3,
|
|
@@ -29601,6 +29382,77 @@ function srFormatNumber(a, locale, maximumFractionDigits) {
|
|
|
29601
29382
|
});
|
|
29602
29383
|
}
|
|
29603
29384
|
|
|
29385
|
+
// Exported for testing
|
|
29386
|
+
function getPiMultiple(a) {
|
|
29387
|
+
// - Save some calculations by checking if this is an integer first.
|
|
29388
|
+
// If a is an integer, it's definitely not a multiple of π.
|
|
29389
|
+
// - 0 should not be presented as a multiple of π.
|
|
29390
|
+
// - If a is greater than 1e12, then it thinks that it's always a
|
|
29391
|
+
// multiple of π even when it's not, due to rounding errors.
|
|
29392
|
+
if (Number.isInteger(a) || a === 0 || a > 1e12) {
|
|
29393
|
+
return null;
|
|
29394
|
+
}
|
|
29395
|
+
|
|
29396
|
+
// Figure out the coefficient before the π.
|
|
29397
|
+
// Example: If a = π/2, then piCoefficient = 0.5
|
|
29398
|
+
// Example: If a = 2π, then piCoefficient = 2
|
|
29399
|
+
const piCoefficient = a / Math.PI;
|
|
29400
|
+
// Truncate the coefficient to account for floating point errors.
|
|
29401
|
+
// π calculations are only accurate up to precision of 1e-12.
|
|
29402
|
+
const truncatedCoefficient = parseFloat(piCoefficient.toFixed(12));
|
|
29403
|
+
|
|
29404
|
+
// If the coefficient is already an integer, then the number
|
|
29405
|
+
// is a multiple of π. Return it here.
|
|
29406
|
+
// Example: If a = 2π, then truncatedCoefficient = 2, so return "2π"
|
|
29407
|
+
if (Number.isInteger(truncatedCoefficient)) {
|
|
29408
|
+
// Return "π" rather than "1π".
|
|
29409
|
+
if (truncatedCoefficient === 1) {
|
|
29410
|
+
return "π";
|
|
29411
|
+
}
|
|
29412
|
+
|
|
29413
|
+
// Return "-π" rather than "-1π".
|
|
29414
|
+
if (truncatedCoefficient === -1) {
|
|
29415
|
+
return "-π";
|
|
29416
|
+
}
|
|
29417
|
+
return truncatedCoefficient + "π";
|
|
29418
|
+
}
|
|
29419
|
+
|
|
29420
|
+
// If the coefficient is not an integer, then we need to
|
|
29421
|
+
// check if it's a multiple of π/2, π/3, π/4, or π/6.
|
|
29422
|
+
// These are π-based values on a unit circle.
|
|
29423
|
+
const acceptableDivisors = [2, 3, 4, 6];
|
|
29424
|
+
|
|
29425
|
+
// Loop through the acceptable divisors and check if the
|
|
29426
|
+
// coefficient is a multiple of (1/divisor).
|
|
29427
|
+
// Example: If a = 5π/6, the coeff is 5/6, which is a multiple of 1/6.
|
|
29428
|
+
// So we return "5π/6".
|
|
29429
|
+
for (const divisor of acceptableDivisors) {
|
|
29430
|
+
// Check if the coefficient is a multiple of (1/divisor) by
|
|
29431
|
+
// multiplying the coefficient by the divisor and checking if
|
|
29432
|
+
// the result is an integer.
|
|
29433
|
+
// Example: If a = 5π/6, then piCoefficient = 5/6. We multiply
|
|
29434
|
+
// by 6 (divisor) to get 5, which is an integer.
|
|
29435
|
+
const coefficientNumerator = parseFloat(
|
|
29436
|
+
// π calculations are only accurate up to precision of 1e-12.
|
|
29437
|
+
(piCoefficient * divisor).toFixed(12));
|
|
29438
|
+
if (Number.isInteger(coefficientNumerator)) {
|
|
29439
|
+
// Handle the case where the coefficient numberator is just 1.
|
|
29440
|
+
// We don't want to write "π/6" as "1π/6"
|
|
29441
|
+
if (coefficientNumerator === 1) {
|
|
29442
|
+
return "π/" + divisor;
|
|
29443
|
+
}
|
|
29444
|
+
|
|
29445
|
+
// Handle the case where the coefficient numberator is just -1.
|
|
29446
|
+
// We don't want to write "π/6" as "-1π/6"
|
|
29447
|
+
if (coefficientNumerator === -1) {
|
|
29448
|
+
return "-π/" + divisor;
|
|
29449
|
+
}
|
|
29450
|
+
return coefficientNumerator + "π/" + divisor;
|
|
29451
|
+
}
|
|
29452
|
+
}
|
|
29453
|
+
return null;
|
|
29454
|
+
}
|
|
29455
|
+
|
|
29604
29456
|
/**
|
|
29605
29457
|
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
29606
29458
|
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
@@ -30756,6 +30608,34 @@ function range(min, max, step = 1) {
|
|
|
30756
30608
|
return result;
|
|
30757
30609
|
}
|
|
30758
30610
|
|
|
30611
|
+
function Hairlines(props) {
|
|
30612
|
+
const {
|
|
30613
|
+
point
|
|
30614
|
+
} = props;
|
|
30615
|
+
const {
|
|
30616
|
+
range
|
|
30617
|
+
} = useGraphConfig();
|
|
30618
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
30619
|
+
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
30620
|
+
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
30621
|
+
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
30622
|
+
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
30623
|
+
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
30624
|
+
return /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
30625
|
+
x1: verticalStartX,
|
|
30626
|
+
y1: y,
|
|
30627
|
+
x2: verticalEndX,
|
|
30628
|
+
y2: y,
|
|
30629
|
+
stroke: color.blue
|
|
30630
|
+
}), /*#__PURE__*/React.createElement("line", {
|
|
30631
|
+
x1: x,
|
|
30632
|
+
y1: horizontalStartY,
|
|
30633
|
+
x2: x,
|
|
30634
|
+
y2: horizontalEndY,
|
|
30635
|
+
stroke: color.blue
|
|
30636
|
+
}));
|
|
30637
|
+
}
|
|
30638
|
+
|
|
30759
30639
|
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
30760
30640
|
// graph.
|
|
30761
30641
|
const hitboxSizePx = 48;
|
|
@@ -30766,7 +30646,6 @@ const hitboxSizePx = 48;
|
|
|
30766
30646
|
const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
30767
30647
|
var _Object$entries$find$, _Object$entries$find;
|
|
30768
30648
|
const {
|
|
30769
|
-
range,
|
|
30770
30649
|
markings,
|
|
30771
30650
|
showTooltips
|
|
30772
30651
|
} = useGraphConfig();
|
|
@@ -30774,6 +30653,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30774
30653
|
point,
|
|
30775
30654
|
color: color$1 = color.blue,
|
|
30776
30655
|
dragging,
|
|
30656
|
+
focused,
|
|
30777
30657
|
cursor,
|
|
30778
30658
|
showFocusRing,
|
|
30779
30659
|
onClick = () => {}
|
|
@@ -30784,25 +30664,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30784
30664
|
const wbColorName = (_Object$entries$find$ = (_Object$entries$find = Object.entries(color).find(([_, value]) => value === color$1)) == null ? void 0 : _Object$entries$find[0]) != null ? _Object$entries$find$ : "blue";
|
|
30785
30665
|
const pointClasses = classNames("movable-point", dragging && "movable-point--dragging", showFocusRing && "movable-point--focus");
|
|
30786
30666
|
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
30787
|
-
const
|
|
30788
|
-
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
30789
|
-
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
30790
|
-
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
30791
|
-
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
30792
|
-
const showHairlines = dragging && markings !== "none";
|
|
30793
|
-
const hairlines = /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
30794
|
-
x1: verticalStartX,
|
|
30795
|
-
y1: y,
|
|
30796
|
-
x2: verticalEndX,
|
|
30797
|
-
y2: y,
|
|
30798
|
-
stroke: color$1
|
|
30799
|
-
}), /*#__PURE__*/React.createElement("line", {
|
|
30800
|
-
x1: x,
|
|
30801
|
-
y1: horizontalStartY,
|
|
30802
|
-
x2: x,
|
|
30803
|
-
y2: horizontalEndY,
|
|
30804
|
-
stroke: color$1
|
|
30805
|
-
}));
|
|
30667
|
+
const showHairlines = (dragging || focused) && markings !== "none";
|
|
30806
30668
|
const svgForPoint = /*#__PURE__*/React.createElement("g", {
|
|
30807
30669
|
ref: hitboxRef,
|
|
30808
30670
|
className: pointClasses,
|
|
@@ -30838,7 +30700,9 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30838
30700
|
},
|
|
30839
30701
|
"data-testid": "movable-point__center"
|
|
30840
30702
|
}));
|
|
30841
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines &&
|
|
30703
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && /*#__PURE__*/React.createElement(Hairlines, {
|
|
30704
|
+
point: point
|
|
30705
|
+
}), showTooltips ? /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
30842
30706
|
autoUpdate: true,
|
|
30843
30707
|
backgroundColor: wbColorName,
|
|
30844
30708
|
content: `(${point[X]}, ${point[Y]})`,
|
|
@@ -30932,6 +30796,7 @@ function useControlPoint(params) {
|
|
|
30932
30796
|
},
|
|
30933
30797
|
point: point,
|
|
30934
30798
|
dragging: dragging,
|
|
30799
|
+
focused: focused,
|
|
30935
30800
|
color: color,
|
|
30936
30801
|
ref: visiblePointRef,
|
|
30937
30802
|
showFocusRing: focused
|
|
@@ -31148,13 +31013,13 @@ const {
|
|
|
31148
31013
|
getClockwiseAngle: getClockwiseAngle$2,
|
|
31149
31014
|
polar: polar$1
|
|
31150
31015
|
} = angles;
|
|
31151
|
-
function renderAngleGraph(state, dispatch) {
|
|
31016
|
+
function renderAngleGraph(state, dispatch, i18n) {
|
|
31152
31017
|
return {
|
|
31153
31018
|
graph: /*#__PURE__*/React.createElement(AngleGraph, {
|
|
31154
31019
|
graphState: state,
|
|
31155
31020
|
dispatch: dispatch
|
|
31156
31021
|
}),
|
|
31157
|
-
interactiveElementsDescription:
|
|
31022
|
+
interactiveElementsDescription: getAngleGraphDescription(state, i18n)
|
|
31158
31023
|
};
|
|
31159
31024
|
}
|
|
31160
31025
|
function AngleGraph(props) {
|
|
@@ -31165,6 +31030,9 @@ function AngleGraph(props) {
|
|
|
31165
31030
|
const {
|
|
31166
31031
|
graphDimensionsInPixels
|
|
31167
31032
|
} = useGraphConfig();
|
|
31033
|
+
const i18n = usePerseusI18n();
|
|
31034
|
+
const id = React.useId();
|
|
31035
|
+
const descriptionId = id + "-description";
|
|
31168
31036
|
const {
|
|
31169
31037
|
coords,
|
|
31170
31038
|
showAngles,
|
|
@@ -31213,76 +31081,106 @@ function AngleGraph(props) {
|
|
|
31213
31081
|
showAngles: showAngles || false // Whether to show the angle or not
|
|
31214
31082
|
};
|
|
31215
31083
|
|
|
31084
|
+
// Aria strings
|
|
31216
31085
|
const {
|
|
31217
|
-
|
|
31218
|
-
|
|
31219
|
-
|
|
31220
|
-
|
|
31221
|
-
|
|
31222
|
-
|
|
31223
|
-
angleMeasure,
|
|
31224
|
-
vertexX: srFormatNumber(coords[1][X], locale),
|
|
31225
|
-
vertexY: srFormatNumber(coords[1][Y], locale),
|
|
31226
|
-
startingSideX: srFormatNumber(coords[2][X], locale),
|
|
31227
|
-
startingSideY: srFormatNumber(coords[2][Y], locale),
|
|
31228
|
-
endingSideX: srFormatNumber(coords[0][X], locale),
|
|
31229
|
-
endingSideY: srFormatNumber(coords[0][Y], locale)
|
|
31230
|
-
});
|
|
31231
|
-
const formatCoordinates = (x, y) => ({
|
|
31232
|
-
x: srFormatNumber(x, locale),
|
|
31233
|
-
y: srFormatNumber(y, locale)
|
|
31234
|
-
});
|
|
31235
|
-
const formatSideAriaLabel = (side, newPoint) => {
|
|
31236
|
-
const formattedCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
|
|
31237
|
-
const label = side === "terminal" ? strings.srAngleSideAtCoordinates(_extends({
|
|
31238
|
-
point: 1,
|
|
31239
|
-
side: "terminal side"
|
|
31240
|
-
}, formattedCoordinates)) : strings.srAngleSideAtCoordinates(_extends({
|
|
31241
|
-
point: 3,
|
|
31242
|
-
side: "initial side"
|
|
31243
|
-
}, formattedCoordinates));
|
|
31244
|
-
return label;
|
|
31245
|
-
};
|
|
31246
|
-
const formatVertexAriaLabel = newPoint => {
|
|
31247
|
-
const formattedVertexCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
|
|
31248
|
-
const label = showAngles ? strings.srAngleVertexAtCoordinatesWithAngleMeasure(_extends({}, formattedVertexCoordinates, {
|
|
31249
|
-
angleMeasure: angleMeasure
|
|
31250
|
-
})) : strings.srAngleSideAtCoordinates(_extends({
|
|
31251
|
-
point: 2,
|
|
31252
|
-
side: "vertex"
|
|
31253
|
-
}, formattedVertexCoordinates));
|
|
31254
|
-
return label;
|
|
31255
|
-
};
|
|
31256
|
-
const initialSideAriaLabel = formatSideAriaLabel("initial", coords[2]);
|
|
31257
|
-
const terminalSideAriaLabel = formatSideAriaLabel("terminal", coords[0]);
|
|
31258
|
-
const vertexAriaLabel = formatVertexAriaLabel(coords[1]);
|
|
31086
|
+
srAngleGraphAriaLabel,
|
|
31087
|
+
srAngleGraphAriaDescription,
|
|
31088
|
+
srAngleStartingSide,
|
|
31089
|
+
srAngleEndingSide,
|
|
31090
|
+
srAngleVertex
|
|
31091
|
+
} = describeAngleGraph(graphState, i18n);
|
|
31259
31092
|
|
|
31260
31093
|
// Render the lines, angle, and then movable points
|
|
31261
31094
|
return /*#__PURE__*/React.createElement("g", {
|
|
31262
|
-
"aria-label":
|
|
31263
|
-
"aria-describedby":
|
|
31095
|
+
"aria-label": srAngleGraphAriaLabel,
|
|
31096
|
+
"aria-describedby": descriptionId
|
|
31264
31097
|
}, svgLines, /*#__PURE__*/React.createElement(Angle, angleParams), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31265
31098
|
point: coords[1],
|
|
31266
31099
|
sequenceNumber: 1,
|
|
31267
31100
|
constrain: p => p,
|
|
31268
31101
|
onMove: destination => dispatch(actions.angle.movePoint(1, destination)),
|
|
31269
|
-
ariaLabel:
|
|
31102
|
+
ariaLabel: srAngleVertex
|
|
31270
31103
|
}), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31271
31104
|
point: coords[0],
|
|
31272
31105
|
sequenceNumber: 2,
|
|
31273
31106
|
constrain: getAngleSideConstraint(coords[0], coords[1], snapDegrees || 1),
|
|
31274
31107
|
onMove: destination => dispatch(actions.angle.movePoint(0, destination)),
|
|
31275
|
-
ariaLabel:
|
|
31108
|
+
ariaLabel: srAngleEndingSide
|
|
31276
31109
|
}), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31277
31110
|
point: coords[2],
|
|
31278
31111
|
sequenceNumber: 3,
|
|
31279
31112
|
constrain: getAngleSideConstraint(coords[2], coords[1], snapDegrees || 1),
|
|
31280
31113
|
onMove: destination => dispatch(actions.angle.movePoint(2, destination)),
|
|
31281
|
-
ariaLabel:
|
|
31114
|
+
ariaLabel: srAngleStartingSide
|
|
31282
31115
|
}), /*#__PURE__*/React.createElement("g", {
|
|
31283
|
-
id:
|
|
31116
|
+
id: descriptionId,
|
|
31284
31117
|
style: a11y.srOnly
|
|
31285
|
-
},
|
|
31118
|
+
}, srAngleGraphAriaDescription));
|
|
31119
|
+
}
|
|
31120
|
+
function getAngleGraphDescription(state, i18n) {
|
|
31121
|
+
const {
|
|
31122
|
+
strings,
|
|
31123
|
+
locale
|
|
31124
|
+
} = i18n;
|
|
31125
|
+
const {
|
|
31126
|
+
coords
|
|
31127
|
+
} = state;
|
|
31128
|
+
return strings.srInteractiveElements({
|
|
31129
|
+
elements: strings.srAngleInteractiveElements({
|
|
31130
|
+
vertexX: srFormatNumber(coords[1][X], locale),
|
|
31131
|
+
vertexY: srFormatNumber(coords[1][Y], locale),
|
|
31132
|
+
startingSideX: srFormatNumber(coords[2][X], locale),
|
|
31133
|
+
startingSideY: srFormatNumber(coords[2][Y], locale),
|
|
31134
|
+
endingSideX: srFormatNumber(coords[0][X], locale),
|
|
31135
|
+
endingSideY: srFormatNumber(coords[0][Y], locale)
|
|
31136
|
+
})
|
|
31137
|
+
});
|
|
31138
|
+
}
|
|
31139
|
+
function describeAngleGraph(state, i18n) {
|
|
31140
|
+
const {
|
|
31141
|
+
strings,
|
|
31142
|
+
locale
|
|
31143
|
+
} = i18n;
|
|
31144
|
+
const {
|
|
31145
|
+
coords,
|
|
31146
|
+
allowReflexAngles,
|
|
31147
|
+
showAngles
|
|
31148
|
+
} = state;
|
|
31149
|
+
const [endingSide, vertex, startingSide] = coords;
|
|
31150
|
+
const angleMeasure = srFormatNumber(getClockwiseAngle$2(coords, allowReflexAngles), locale);
|
|
31151
|
+
const srAngleGraphAriaLabel = strings.srAngleGraphAriaLabel;
|
|
31152
|
+
const srAngleGraphAriaDescription = strings.srAngleGraphAriaDescription({
|
|
31153
|
+
angleMeasure,
|
|
31154
|
+
vertexX: srFormatNumber(vertex[X], locale),
|
|
31155
|
+
vertexY: srFormatNumber(vertex[Y], locale),
|
|
31156
|
+
startingSideX: srFormatNumber(startingSide[X], locale),
|
|
31157
|
+
startingSideY: srFormatNumber(startingSide[Y], locale),
|
|
31158
|
+
endingSideX: srFormatNumber(endingSide[X], locale),
|
|
31159
|
+
endingSideY: srFormatNumber(endingSide[Y], locale)
|
|
31160
|
+
});
|
|
31161
|
+
const srAngleStartingSide = strings.srAngleStartingSide({
|
|
31162
|
+
x: srFormatNumber(startingSide[X], locale),
|
|
31163
|
+
y: srFormatNumber(startingSide[Y], locale)
|
|
31164
|
+
});
|
|
31165
|
+
const srAngleEndingSide = strings.srAngleEndingSide({
|
|
31166
|
+
x: srFormatNumber(endingSide[X], locale),
|
|
31167
|
+
y: srFormatNumber(endingSide[Y], locale)
|
|
31168
|
+
});
|
|
31169
|
+
const srAngleVertex = showAngles ? strings.srAngleVertexWithAngleMeasure({
|
|
31170
|
+
x: srFormatNumber(vertex[X], locale),
|
|
31171
|
+
y: srFormatNumber(vertex[Y], locale),
|
|
31172
|
+
angleMeasure
|
|
31173
|
+
}) : strings.srAngleVertex({
|
|
31174
|
+
x: srFormatNumber(vertex[X], locale),
|
|
31175
|
+
y: srFormatNumber(vertex[Y], locale)
|
|
31176
|
+
});
|
|
31177
|
+
return {
|
|
31178
|
+
srAngleGraphAriaLabel,
|
|
31179
|
+
srAngleGraphAriaDescription,
|
|
31180
|
+
srAngleStartingSide,
|
|
31181
|
+
srAngleEndingSide,
|
|
31182
|
+
srAngleVertex
|
|
31183
|
+
};
|
|
31286
31184
|
}
|
|
31287
31185
|
const positiveX = [1, 0];
|
|
31288
31186
|
const negativeX = [-1, 0];
|
|
@@ -31413,17 +31311,16 @@ function getRadius(graph) {
|
|
|
31413
31311
|
return Math.sqrt(Math.pow(edgeX - centerX, 2) + Math.pow(edgeY - centerY, 2));
|
|
31414
31312
|
}
|
|
31415
31313
|
|
|
31416
|
-
function renderCircleGraph(state, dispatch) {
|
|
31314
|
+
function renderCircleGraph(state, dispatch, i18n) {
|
|
31417
31315
|
return {
|
|
31418
31316
|
graph: /*#__PURE__*/React.createElement(CircleGraph, {
|
|
31419
31317
|
graphState: state,
|
|
31420
31318
|
dispatch: dispatch
|
|
31421
31319
|
}),
|
|
31422
|
-
interactiveElementsDescription:
|
|
31423
|
-
state: state
|
|
31424
|
-
})
|
|
31320
|
+
interactiveElementsDescription: getCircleGraphDescription(state, i18n)
|
|
31425
31321
|
};
|
|
31426
31322
|
}
|
|
31323
|
+
// Exported for testing
|
|
31427
31324
|
function CircleGraph(props) {
|
|
31428
31325
|
const {
|
|
31429
31326
|
dispatch,
|
|
@@ -31516,6 +31413,7 @@ function MovableCircle(props) {
|
|
|
31516
31413
|
snapStep,
|
|
31517
31414
|
disableKeyboardInteraction
|
|
31518
31415
|
} = useGraphConfig();
|
|
31416
|
+
const [focused, setFocused] = React.useState(false);
|
|
31519
31417
|
const draggableRef = useRef(null);
|
|
31520
31418
|
const {
|
|
31521
31419
|
dragging
|
|
@@ -31534,7 +31432,9 @@ function MovableCircle(props) {
|
|
|
31534
31432
|
ref: draggableRef,
|
|
31535
31433
|
role: "button",
|
|
31536
31434
|
tabIndex: disableKeyboardInteraction ? -1 : 0,
|
|
31537
|
-
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}
|
|
31435
|
+
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`,
|
|
31436
|
+
onFocus: () => setFocused(true),
|
|
31437
|
+
onBlur: () => setFocused(false)
|
|
31538
31438
|
}, /*#__PURE__*/React.createElement("ellipse", {
|
|
31539
31439
|
className: "focus-ring",
|
|
31540
31440
|
cx: centerPx[X],
|
|
@@ -31549,19 +31449,29 @@ function MovableCircle(props) {
|
|
|
31549
31449
|
rx: radiiPx[X],
|
|
31550
31450
|
ry: radiiPx[Y]
|
|
31551
31451
|
}), /*#__PURE__*/React.createElement(DragHandle, {
|
|
31552
|
-
center: center
|
|
31452
|
+
center: center,
|
|
31453
|
+
dragging: dragging,
|
|
31454
|
+
focused: focused
|
|
31553
31455
|
}));
|
|
31554
31456
|
}
|
|
31555
31457
|
const dragHandleDimensions = [24, 14];
|
|
31556
31458
|
const dragHandleDotPositions = crossProduct([-4.4, 0, 4.4], [-2.1, 2.1]);
|
|
31557
31459
|
function DragHandle(props) {
|
|
31558
31460
|
const {
|
|
31559
|
-
center
|
|
31461
|
+
center,
|
|
31462
|
+
dragging,
|
|
31463
|
+
focused
|
|
31560
31464
|
} = props;
|
|
31561
|
-
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
31562
31465
|
const [centerPx] = useTransformVectorsToPixels(center);
|
|
31466
|
+
const {
|
|
31467
|
+
markings
|
|
31468
|
+
} = useGraphConfig();
|
|
31469
|
+
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
31563
31470
|
const topLeft = vec.sub(centerPx, vec.scale(dragHandleDimensions, 0.5));
|
|
31564
|
-
|
|
31471
|
+
const showHairlines = (dragging || focused) && markings !== "none";
|
|
31472
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && /*#__PURE__*/React.createElement(Hairlines, {
|
|
31473
|
+
point: center
|
|
31474
|
+
}), /*#__PURE__*/React.createElement("rect", {
|
|
31565
31475
|
className: "movable-circle-handle",
|
|
31566
31476
|
x: topLeft[X],
|
|
31567
31477
|
y: topLeft[Y],
|
|
@@ -31588,13 +31498,7 @@ function crossProduct(as, bs) {
|
|
|
31588
31498
|
}
|
|
31589
31499
|
return result;
|
|
31590
31500
|
}
|
|
31591
|
-
function
|
|
31592
|
-
state
|
|
31593
|
-
}) {
|
|
31594
|
-
// The reason that CircleGraphDescription is a component (rather than a
|
|
31595
|
-
// function that returns a string) is because it needs to use a
|
|
31596
|
-
// hook: `usePerseusI18n`.
|
|
31597
|
-
const i18n = usePerseusI18n();
|
|
31501
|
+
function getCircleGraphDescription(state, i18n) {
|
|
31598
31502
|
const strings = describeCircleGraph(state, i18n);
|
|
31599
31503
|
return strings.srCircleInteractiveElement;
|
|
31600
31504
|
}
|
|
@@ -31647,15 +31551,13 @@ function describeCircleGraph(state, i18n) {
|
|
|
31647
31551
|
};
|
|
31648
31552
|
}
|
|
31649
31553
|
|
|
31650
|
-
function renderLinearGraph(state, dispatch) {
|
|
31554
|
+
function renderLinearGraph(state, dispatch, i18n) {
|
|
31651
31555
|
return {
|
|
31652
31556
|
graph: /*#__PURE__*/React.createElement(LinearGraph, {
|
|
31653
31557
|
graphState: state,
|
|
31654
31558
|
dispatch: dispatch
|
|
31655
31559
|
}),
|
|
31656
|
-
interactiveElementsDescription:
|
|
31657
|
-
state: state
|
|
31658
|
-
})
|
|
31560
|
+
interactiveElementsDescription: getLinearGraphDescription(state, i18n)
|
|
31659
31561
|
};
|
|
31660
31562
|
}
|
|
31661
31563
|
const LinearGraph = (props, key) => {
|
|
@@ -31720,13 +31622,7 @@ const LinearGraph = (props, key) => {
|
|
|
31720
31622
|
style: a11y.srOnly
|
|
31721
31623
|
}, slopeString));
|
|
31722
31624
|
};
|
|
31723
|
-
function
|
|
31724
|
-
state
|
|
31725
|
-
}) {
|
|
31726
|
-
// The reason that LinearGraphDescription is a component (rather than a
|
|
31727
|
-
// function that returns a string) is because it needs to use a
|
|
31728
|
-
// hook: `usePerseusI18n`.
|
|
31729
|
-
const i18n = usePerseusI18n();
|
|
31625
|
+
function getLinearGraphDescription(state, i18n) {
|
|
31730
31626
|
const strings = describeLinearGraph(state, i18n);
|
|
31731
31627
|
return strings.srLinearInteractiveElement;
|
|
31732
31628
|
}
|
|
@@ -31770,15 +31666,13 @@ function describeLinearGraph(state, i18n) {
|
|
|
31770
31666
|
};
|
|
31771
31667
|
}
|
|
31772
31668
|
|
|
31773
|
-
function renderLinearSystemGraph(state, dispatch) {
|
|
31669
|
+
function renderLinearSystemGraph(state, dispatch, i18n) {
|
|
31774
31670
|
return {
|
|
31775
31671
|
graph: /*#__PURE__*/React.createElement(LinearSystemGraph, {
|
|
31776
31672
|
graphState: state,
|
|
31777
31673
|
dispatch: dispatch
|
|
31778
31674
|
}),
|
|
31779
|
-
interactiveElementsDescription:
|
|
31780
|
-
state: state
|
|
31781
|
-
})
|
|
31675
|
+
interactiveElementsDescription: getLinearSystemGraphDescription(state, i18n)
|
|
31782
31676
|
};
|
|
31783
31677
|
}
|
|
31784
31678
|
const LinearSystemGraph = props => {
|
|
@@ -31865,18 +31759,9 @@ const LinearSystemGraph = props => {
|
|
|
31865
31759
|
style: a11y.srOnly
|
|
31866
31760
|
}, slopeDescription))));
|
|
31867
31761
|
};
|
|
31868
|
-
function LinearSystemGraphDescription({
|
|
31869
|
-
state
|
|
31870
|
-
}) {
|
|
31871
|
-
// The reason that LinearSystemGraphDescription is a component (rather
|
|
31872
|
-
// than a function that returns a string) is because it needs to use a
|
|
31873
|
-
// hook: `usePerseusI18n`.
|
|
31874
|
-
const i18n = usePerseusI18n();
|
|
31875
|
-
return describeLinearSystemGraph(state, i18n);
|
|
31876
|
-
}
|
|
31877
31762
|
|
|
31878
31763
|
// Exported for testing
|
|
31879
|
-
function
|
|
31764
|
+
function getLinearSystemGraphDescription(state, i18n) {
|
|
31880
31765
|
const {
|
|
31881
31766
|
strings,
|
|
31882
31767
|
locale
|
|
@@ -31902,15 +31787,13 @@ function describeLinearSystemGraph(state, i18n) {
|
|
|
31902
31787
|
});
|
|
31903
31788
|
}
|
|
31904
31789
|
|
|
31905
|
-
function renderPointGraph(state, dispatch) {
|
|
31790
|
+
function renderPointGraph(state, dispatch, i18n) {
|
|
31906
31791
|
return {
|
|
31907
31792
|
graph: /*#__PURE__*/React.createElement(PointGraph, {
|
|
31908
31793
|
graphState: state,
|
|
31909
31794
|
dispatch: dispatch
|
|
31910
31795
|
}),
|
|
31911
|
-
interactiveElementsDescription:
|
|
31912
|
-
state: state
|
|
31913
|
-
})
|
|
31796
|
+
interactiveElementsDescription: getPointGraphDescription(state, i18n)
|
|
31914
31797
|
};
|
|
31915
31798
|
}
|
|
31916
31799
|
function PointGraph(props) {
|
|
@@ -31933,7 +31816,9 @@ function PointGraph(props) {
|
|
|
31933
31816
|
var _pointsRef$current$fo;
|
|
31934
31817
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
31935
31818
|
}
|
|
31936
|
-
}, [props.graphState.focusedPointIndex,
|
|
31819
|
+
}, [props.graphState.focusedPointIndex,
|
|
31820
|
+
// Ensure that we re-focus if a point is deleted.
|
|
31821
|
+
props.graphState.coords.length, pointsRef]);
|
|
31937
31822
|
const statefulProps = _extends({}, props, {
|
|
31938
31823
|
graphConfig,
|
|
31939
31824
|
pointsRef,
|
|
@@ -32004,17 +31889,9 @@ function UnlimitedPointGraph(statefulProps) {
|
|
|
32004
31889
|
}
|
|
32005
31890
|
})));
|
|
32006
31891
|
}
|
|
32007
|
-
function PointGraphDescription({
|
|
32008
|
-
state
|
|
32009
|
-
}) {
|
|
32010
|
-
// PointGraphDescription needs to `usePerseusI18n`, so it has to be a
|
|
32011
|
-
// component rather than a function that simply returns a string.
|
|
32012
|
-
const i18n = usePerseusI18n();
|
|
32013
|
-
return describePointGraph(state, i18n);
|
|
32014
|
-
}
|
|
32015
31892
|
|
|
32016
31893
|
// Exported for testing
|
|
32017
|
-
function
|
|
31894
|
+
function getPointGraphDescription(state, i18n) {
|
|
32018
31895
|
const {
|
|
32019
31896
|
strings,
|
|
32020
31897
|
locale
|
|
@@ -32101,7 +31978,9 @@ const PolygonGraph = props => {
|
|
|
32101
31978
|
var _pointsRef$current$fo;
|
|
32102
31979
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
32103
31980
|
}
|
|
32104
|
-
}, [props.graphState.focusedPointIndex,
|
|
31981
|
+
}, [props.graphState.focusedPointIndex,
|
|
31982
|
+
// Ensure that we re-focus if a point is deleted.
|
|
31983
|
+
props.graphState.coords.length, pointsRef]);
|
|
32105
31984
|
|
|
32106
31985
|
// If the unlimited polygon is rendered with 3 or more coordinates
|
|
32107
31986
|
// Close the polygon, but only on first render.
|
|
@@ -32681,15 +32560,13 @@ function describeQuadraticGraph(state, i18n) {
|
|
|
32681
32560
|
};
|
|
32682
32561
|
}
|
|
32683
32562
|
|
|
32684
|
-
function renderRayGraph(state, dispatch) {
|
|
32563
|
+
function renderRayGraph(state, dispatch, i18n) {
|
|
32685
32564
|
return {
|
|
32686
32565
|
graph: /*#__PURE__*/React.createElement(RayGraph, {
|
|
32687
32566
|
graphState: state,
|
|
32688
32567
|
dispatch: dispatch
|
|
32689
32568
|
}),
|
|
32690
|
-
interactiveElementsDescription:
|
|
32691
|
-
state: state
|
|
32692
|
-
})
|
|
32569
|
+
interactiveElementsDescription: getRayGraphDescription(state, i18n)
|
|
32693
32570
|
};
|
|
32694
32571
|
}
|
|
32695
32572
|
const RayGraph = props => {
|
|
@@ -32743,13 +32620,7 @@ const RayGraph = props => {
|
|
|
32743
32620
|
style: a11y.srOnly
|
|
32744
32621
|
}, srRayPoints));
|
|
32745
32622
|
};
|
|
32746
|
-
function
|
|
32747
|
-
state
|
|
32748
|
-
}) {
|
|
32749
|
-
// The reason that RayGraphDescription is a component (rather than a
|
|
32750
|
-
// function that returns a string) is because it needs to use a
|
|
32751
|
-
// hook: `usePerseusI18n`.
|
|
32752
|
-
const i18n = usePerseusI18n();
|
|
32623
|
+
function getRayGraphDescription(state, i18n) {
|
|
32753
32624
|
const strings = describeRayGraph(state, i18n);
|
|
32754
32625
|
return strings.srRayInteractiveElement;
|
|
32755
32626
|
}
|
|
@@ -32799,15 +32670,13 @@ function describeRayGraph(state, i18n) {
|
|
|
32799
32670
|
};
|
|
32800
32671
|
}
|
|
32801
32672
|
|
|
32802
|
-
function renderSegmentGraph(state, dispatch) {
|
|
32673
|
+
function renderSegmentGraph(state, dispatch, i18n) {
|
|
32803
32674
|
return {
|
|
32804
32675
|
graph: /*#__PURE__*/React.createElement(SegmentGraph, {
|
|
32805
32676
|
graphState: state,
|
|
32806
32677
|
dispatch: dispatch
|
|
32807
32678
|
}),
|
|
32808
|
-
interactiveElementsDescription:
|
|
32809
|
-
state: state
|
|
32810
|
-
})
|
|
32679
|
+
interactiveElementsDescription: getSegmentGraphDescription(state, i18n)
|
|
32811
32680
|
};
|
|
32812
32681
|
}
|
|
32813
32682
|
const SegmentGraph = ({
|
|
@@ -32899,18 +32768,9 @@ const SegmentGraph = ({
|
|
|
32899
32768
|
function getLengthOfSegment(segment) {
|
|
32900
32769
|
return point.distanceToPoint(...segment);
|
|
32901
32770
|
}
|
|
32902
|
-
function SegmentGraphDescription({
|
|
32903
|
-
state
|
|
32904
|
-
}) {
|
|
32905
|
-
// The reason that SegmentGraphDescription is a component (rather than a
|
|
32906
|
-
// function that returns a string) is because it needs to use a
|
|
32907
|
-
// hook: `usePerseusI18n`.
|
|
32908
|
-
const i18n = usePerseusI18n();
|
|
32909
|
-
return describeSegmentGraph(state, i18n);
|
|
32910
|
-
}
|
|
32911
32771
|
|
|
32912
32772
|
// Exported for testing
|
|
32913
|
-
function
|
|
32773
|
+
function getSegmentGraphDescription(state, i18n) {
|
|
32914
32774
|
const {
|
|
32915
32775
|
strings,
|
|
32916
32776
|
locale
|
|
@@ -32927,13 +32787,13 @@ function describeSegmentGraph(state, i18n) {
|
|
|
32927
32787
|
});
|
|
32928
32788
|
}
|
|
32929
32789
|
|
|
32930
|
-
function renderSinusoidGraph(state, dispatch) {
|
|
32790
|
+
function renderSinusoidGraph(state, dispatch, i18n) {
|
|
32931
32791
|
return {
|
|
32932
32792
|
graph: /*#__PURE__*/React.createElement(SinusoidGraph, {
|
|
32933
32793
|
graphState: state,
|
|
32934
32794
|
dispatch: dispatch
|
|
32935
32795
|
}),
|
|
32936
|
-
interactiveElementsDescription:
|
|
32796
|
+
interactiveElementsDescription: getSinusoidDescription(state, i18n)
|
|
32937
32797
|
};
|
|
32938
32798
|
}
|
|
32939
32799
|
function SinusoidGraph(props) {
|
|
@@ -32941,6 +32801,9 @@ function SinusoidGraph(props) {
|
|
|
32941
32801
|
dispatch,
|
|
32942
32802
|
graphState
|
|
32943
32803
|
} = props;
|
|
32804
|
+
const i18n = usePerseusI18n();
|
|
32805
|
+
const id = React.useId();
|
|
32806
|
+
const descriptionId = id + "-description";
|
|
32944
32807
|
|
|
32945
32808
|
// Destructure the coordinates from the graph state
|
|
32946
32809
|
// Note: The order of the coordinates is important:
|
|
@@ -32965,15 +32828,30 @@ function SinusoidGraph(props) {
|
|
|
32965
32828
|
if (coeffs !== undefined) {
|
|
32966
32829
|
coeffRef.current = coeffs;
|
|
32967
32830
|
}
|
|
32968
|
-
|
|
32831
|
+
|
|
32832
|
+
// Aria strings
|
|
32833
|
+
const {
|
|
32834
|
+
srSinusoidGraph,
|
|
32835
|
+
srSinusoidDescription,
|
|
32836
|
+
srSinusoidRootPoint,
|
|
32837
|
+
srSinusoidPeakPoint
|
|
32838
|
+
} = describeSinusoidGraph(graphState, i18n);
|
|
32839
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
32840
|
+
// Outer graph minimal description
|
|
32841
|
+
"aria-label": srSinusoidGraph,
|
|
32842
|
+
"aria-describedby": descriptionId
|
|
32843
|
+
}, /*#__PURE__*/React.createElement(Plot$2.OfX, {
|
|
32969
32844
|
y: x => computeSine(x, coeffRef.current),
|
|
32970
32845
|
color: color.blue
|
|
32971
32846
|
}), coords.map((coord, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
32847
|
+
ariaLabel: i === 0 ? srSinusoidRootPoint : srSinusoidPeakPoint,
|
|
32972
32848
|
key: "point-" + i,
|
|
32973
32849
|
point: coord,
|
|
32974
32850
|
sequenceNumber: i + 1,
|
|
32975
32851
|
onMove: destination => dispatch(actions.sinusoid.movePoint(i, destination))
|
|
32976
|
-
}))
|
|
32852
|
+
})), /*#__PURE__*/React.createElement("g", {
|
|
32853
|
+
id: descriptionId
|
|
32854
|
+
}, srSinusoidDescription));
|
|
32977
32855
|
}
|
|
32978
32856
|
|
|
32979
32857
|
// Plot a sinusoid of the form: f(x) = a * sin(b * x - c) + d
|
|
@@ -33011,6 +32889,52 @@ const getSinusoidCoefficients$1 = coords => {
|
|
|
33011
32889
|
verticalOffset
|
|
33012
32890
|
};
|
|
33013
32891
|
};
|
|
32892
|
+
function getSinusoidDescription(state, i18n) {
|
|
32893
|
+
const strings = describeSinusoidGraph(state, i18n);
|
|
32894
|
+
return strings.srSinusoidInteractiveElements;
|
|
32895
|
+
}
|
|
32896
|
+
function describeSinusoidGraph(state, i18n) {
|
|
32897
|
+
const {
|
|
32898
|
+
strings,
|
|
32899
|
+
locale
|
|
32900
|
+
} = i18n;
|
|
32901
|
+
const {
|
|
32902
|
+
coords
|
|
32903
|
+
} = state;
|
|
32904
|
+
const [root, peak] = coords;
|
|
32905
|
+
const diffX = Math.abs(peak[X] - root[X]);
|
|
32906
|
+
const diffY = Math.abs(peak[Y] - root[Y]);
|
|
32907
|
+
const srSinusoidGraph = strings.srSinusoidGraph;
|
|
32908
|
+
const srSinusoidDescription = strings.srSinusoidDescription({
|
|
32909
|
+
minValue: srFormatNumber(root[Y] - diffY, locale),
|
|
32910
|
+
maxValue: srFormatNumber(root[Y] + diffY, locale),
|
|
32911
|
+
cycleStart: srFormatNumber(root[X] - 2 * diffX, locale),
|
|
32912
|
+
cycleEnd: srFormatNumber(root[X] + 2 * diffX, locale)
|
|
32913
|
+
});
|
|
32914
|
+
const srSinusoidRootPoint = strings.srSinusoidRootPoint({
|
|
32915
|
+
x: srFormatNumber(root[X], locale),
|
|
32916
|
+
y: srFormatNumber(root[Y], locale)
|
|
32917
|
+
});
|
|
32918
|
+
const srSinusoidPeakPoint = strings.srSinusoidPeakPoint({
|
|
32919
|
+
x: srFormatNumber(peak[X], locale),
|
|
32920
|
+
y: srFormatNumber(peak[Y], locale)
|
|
32921
|
+
});
|
|
32922
|
+
const srSinusoidInteractiveElements = strings.srInteractiveElements({
|
|
32923
|
+
elements: strings.srSinusoidInteractiveElements({
|
|
32924
|
+
point1X: srFormatNumber(root[X], locale),
|
|
32925
|
+
point1Y: srFormatNumber(root[Y], locale),
|
|
32926
|
+
point2X: srFormatNumber(peak[X], locale),
|
|
32927
|
+
point2Y: srFormatNumber(peak[Y], locale)
|
|
32928
|
+
})
|
|
32929
|
+
});
|
|
32930
|
+
return {
|
|
32931
|
+
srSinusoidGraph,
|
|
32932
|
+
srSinusoidDescription,
|
|
32933
|
+
srSinusoidRootPoint,
|
|
32934
|
+
srSinusoidPeakPoint,
|
|
32935
|
+
srSinusoidInteractiveElements
|
|
32936
|
+
};
|
|
32937
|
+
}
|
|
33014
32938
|
|
|
33015
32939
|
const {
|
|
33016
32940
|
calculateAngleInDegrees,
|
|
@@ -33181,6 +33105,7 @@ const MafsGraph = props => {
|
|
|
33181
33105
|
const descriptionId = `interactive-graph-description-${uniqueId}`;
|
|
33182
33106
|
const interactiveElementsDescriptionId = `interactive-graph-interactive-elements-description-${uniqueId}`;
|
|
33183
33107
|
const unlimitedGraphKeyboardPromptId = `unlimited-graph-keyboard-prompt-${uniqueId}`;
|
|
33108
|
+
const instructionsId = `instructions-${uniqueId}`;
|
|
33184
33109
|
const graphRef = React.useRef(null);
|
|
33185
33110
|
const {
|
|
33186
33111
|
analytics
|
|
@@ -33208,6 +33133,7 @@ const MafsGraph = props => {
|
|
|
33208
33133
|
const interactionPrompt = isUnlimitedGraphState(state) && state.showKeyboardInteractionInvitation;
|
|
33209
33134
|
useOnMountEffect(() => {
|
|
33210
33135
|
analytics.onAnalyticsEvent({
|
|
33136
|
+
// TODO(LEMS-2827): Remove analytics event in LEMS-2827 in favor of ti below.
|
|
33211
33137
|
type: "perseus:interactive-graph-widget:rendered",
|
|
33212
33138
|
payload: {
|
|
33213
33139
|
type,
|
|
@@ -33215,6 +33141,14 @@ const MafsGraph = props => {
|
|
|
33215
33141
|
widgetId: "interactive-graph"
|
|
33216
33142
|
}
|
|
33217
33143
|
});
|
|
33144
|
+
analytics.onAnalyticsEvent({
|
|
33145
|
+
type: "perseus:widget:rendered:ti",
|
|
33146
|
+
payload: {
|
|
33147
|
+
widgetSubType: type,
|
|
33148
|
+
widgetType: "INTERACTIVE_GRAPH",
|
|
33149
|
+
widgetId: "interactive-graph"
|
|
33150
|
+
}
|
|
33151
|
+
});
|
|
33218
33152
|
});
|
|
33219
33153
|
const {
|
|
33220
33154
|
graph,
|
|
@@ -33258,7 +33192,7 @@ const MafsGraph = props => {
|
|
|
33258
33192
|
handleKeyboardEvent(event, state, dispatch);
|
|
33259
33193
|
},
|
|
33260
33194
|
"aria-label": fullGraphAriaLabel,
|
|
33261
|
-
"aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId),
|
|
33195
|
+
"aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && instructionsId),
|
|
33262
33196
|
ref: graphRef,
|
|
33263
33197
|
tabIndex: 0,
|
|
33264
33198
|
onFocus: event => {
|
|
@@ -33275,7 +33209,11 @@ const MafsGraph = props => {
|
|
|
33275
33209
|
id: interactiveElementsDescriptionId,
|
|
33276
33210
|
tabIndex: -1,
|
|
33277
33211
|
className: "mafs-sr-only"
|
|
33278
|
-
}, interactiveElementsDescription), /*#__PURE__*/React.createElement(
|
|
33212
|
+
}, interactiveElementsDescription), state.type !== "none" && /*#__PURE__*/React.createElement(View, {
|
|
33213
|
+
id: instructionsId,
|
|
33214
|
+
tabIndex: -1,
|
|
33215
|
+
className: "mafs-sr-only"
|
|
33216
|
+
}, isUnlimitedGraphState(state) ? strings.srUnlimitedGraphInstructions : strings.srGraphInstructions), /*#__PURE__*/React.createElement(LegacyGrid, {
|
|
33279
33217
|
box: props.box,
|
|
33280
33218
|
backgroundImage: props.backgroundImage
|
|
33281
33219
|
}), /*#__PURE__*/React.createElement(View, {
|
|
@@ -33284,7 +33222,9 @@ const MafsGraph = props => {
|
|
|
33284
33222
|
bottom: 0,
|
|
33285
33223
|
left: 0
|
|
33286
33224
|
}
|
|
33287
|
-
}, (props.markings === "graph" || props.markings === "axes") && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels,
|
|
33225
|
+
}, (props.markings === "graph" || props.markings === "axes") && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels, {
|
|
33226
|
+
i18n: i18n
|
|
33227
|
+
})), /*#__PURE__*/React.createElement(View
|
|
33288
33228
|
// If we have locked figures, we set aria-hidden
|
|
33289
33229
|
// to false so that screen readers can read the
|
|
33290
33230
|
// locked figures. If we don't have any locked
|
|
@@ -33622,25 +33562,25 @@ const renderGraphElements = props => {
|
|
|
33622
33562
|
} = state;
|
|
33623
33563
|
switch (type) {
|
|
33624
33564
|
case "angle":
|
|
33625
|
-
return renderAngleGraph(state, dispatch);
|
|
33565
|
+
return renderAngleGraph(state, dispatch, i18n);
|
|
33626
33566
|
case "segment":
|
|
33627
|
-
return renderSegmentGraph(state, dispatch);
|
|
33567
|
+
return renderSegmentGraph(state, dispatch, i18n);
|
|
33628
33568
|
case "linear-system":
|
|
33629
|
-
return renderLinearSystemGraph(state, dispatch);
|
|
33569
|
+
return renderLinearSystemGraph(state, dispatch, i18n);
|
|
33630
33570
|
case "linear":
|
|
33631
|
-
return renderLinearGraph(state, dispatch);
|
|
33571
|
+
return renderLinearGraph(state, dispatch, i18n);
|
|
33632
33572
|
case "ray":
|
|
33633
|
-
return renderRayGraph(state, dispatch);
|
|
33573
|
+
return renderRayGraph(state, dispatch, i18n);
|
|
33634
33574
|
case "polygon":
|
|
33635
33575
|
return renderPolygonGraph(state, dispatch, i18n, markings);
|
|
33636
33576
|
case "point":
|
|
33637
|
-
return renderPointGraph(state, dispatch);
|
|
33577
|
+
return renderPointGraph(state, dispatch, i18n);
|
|
33638
33578
|
case "circle":
|
|
33639
|
-
return renderCircleGraph(state, dispatch);
|
|
33579
|
+
return renderCircleGraph(state, dispatch, i18n);
|
|
33640
33580
|
case "quadratic":
|
|
33641
33581
|
return renderQuadraticGraph(state, dispatch, i18n);
|
|
33642
33582
|
case "sinusoid":
|
|
33643
|
-
return renderSinusoidGraph(state, dispatch);
|
|
33583
|
+
return renderSinusoidGraph(state, dispatch, i18n);
|
|
33644
33584
|
case "none":
|
|
33645
33585
|
return {
|
|
33646
33586
|
graph: null,
|
|
@@ -34037,13 +33977,13 @@ const {
|
|
|
34037
33977
|
polar
|
|
34038
33978
|
} = angles;
|
|
34039
33979
|
const {
|
|
34040
|
-
angleMeasures
|
|
34041
|
-
ccw
|
|
34042
|
-
lawOfCosines
|
|
33980
|
+
angleMeasures,
|
|
33981
|
+
ccw,
|
|
33982
|
+
lawOfCosines,
|
|
34043
33983
|
magnitude: magnitude$1,
|
|
34044
33984
|
polygonSidesIntersect,
|
|
34045
33985
|
reverseVector,
|
|
34046
|
-
sign
|
|
33986
|
+
sign,
|
|
34047
33987
|
vector: vector$1
|
|
34048
33988
|
} = geometry;
|
|
34049
33989
|
const {
|
|
@@ -34527,7 +34467,7 @@ function doAddPoint(state, action) {
|
|
|
34527
34467
|
return _extends({}, state, {
|
|
34528
34468
|
hasBeenInteractedWith: true,
|
|
34529
34469
|
coords: newCoords,
|
|
34530
|
-
showRemovePointButton:
|
|
34470
|
+
showRemovePointButton: true,
|
|
34531
34471
|
focusedPointIndex: newCoords.length - 1
|
|
34532
34472
|
});
|
|
34533
34473
|
}
|
|
@@ -34535,16 +34475,11 @@ function doRemovePoint(state, action) {
|
|
|
34535
34475
|
if (!isUnlimitedGraphState(state)) {
|
|
34536
34476
|
return state;
|
|
34537
34477
|
}
|
|
34538
|
-
|
|
34539
|
-
if (state.interactionMode === "mouse") {
|
|
34540
|
-
nextFocusedPointIndex = null;
|
|
34541
|
-
} else {
|
|
34542
|
-
nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
|
|
34543
|
-
}
|
|
34478
|
+
const nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
|
|
34544
34479
|
return _extends({}, state, {
|
|
34545
34480
|
coords: state.coords.filter((_, i) => i !== action.index),
|
|
34546
34481
|
focusedPointIndex: nextFocusedPointIndex,
|
|
34547
|
-
showRemovePointButton: false
|
|
34482
|
+
showRemovePointButton: nextFocusedPointIndex !== null ? true : false
|
|
34548
34483
|
});
|
|
34549
34484
|
}
|
|
34550
34485
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
@@ -34568,7 +34503,7 @@ const getChange = (coords, delta, constraintOpts) => {
|
|
|
34568
34503
|
return [dx, dy];
|
|
34569
34504
|
};
|
|
34570
34505
|
// Less than or approximately equal
|
|
34571
|
-
function leq
|
|
34506
|
+
function leq(a, b) {
|
|
34572
34507
|
return a < b || approximateEqual(a, b);
|
|
34573
34508
|
}
|
|
34574
34509
|
function boundAndSnapToGrid(point, {
|
|
@@ -34713,7 +34648,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34713
34648
|
});
|
|
34714
34649
|
|
|
34715
34650
|
// Gets the radian angles between the coords and maps them to degrees
|
|
34716
|
-
const angles = angleMeasures
|
|
34651
|
+
const angles = angleMeasures(coordsCopy).map(angle => angle * 180 / Math.PI);
|
|
34717
34652
|
|
|
34718
34653
|
// Gets the relative index of a point
|
|
34719
34654
|
const rel = j => {
|
|
@@ -34733,7 +34668,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34733
34668
|
|
|
34734
34669
|
// Avoid degenerate triangles
|
|
34735
34670
|
if (innerAngles.some(function (angle) {
|
|
34736
|
-
return leq
|
|
34671
|
+
return leq(angle, 1);
|
|
34737
34672
|
})) {
|
|
34738
34673
|
return startingPoint;
|
|
34739
34674
|
}
|
|
@@ -34747,7 +34682,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34747
34682
|
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
34748
34683
|
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
34749
34684
|
// for is then used in the polar function to determine the new point.
|
|
34750
|
-
const onLeft = sign
|
|
34685
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
34751
34686
|
|
|
34752
34687
|
// Solve for side by using the law of sines
|
|
34753
34688
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
@@ -34794,13 +34729,13 @@ function boundAndSnapToSides(destinationPoint, {
|
|
|
34794
34729
|
});
|
|
34795
34730
|
|
|
34796
34731
|
// Avoid degenerate triangles
|
|
34797
|
-
if (leq
|
|
34732
|
+
if (leq(sides[1] + sides[2], sides[0]) || leq(sides[0] + sides[2], sides[1]) || leq(sides[0] + sides[1], sides[2])) {
|
|
34798
34733
|
return startingPoint;
|
|
34799
34734
|
}
|
|
34800
34735
|
|
|
34801
34736
|
// Solve for angle by using the law of cosines
|
|
34802
34737
|
// Angle at the first vertex of the polygon
|
|
34803
|
-
const innerAngle = lawOfCosines
|
|
34738
|
+
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
34804
34739
|
|
|
34805
34740
|
// Angle at the second vertex of the polygon
|
|
34806
34741
|
const outerAngle = getAngleFromVertex(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
@@ -34811,7 +34746,7 @@ function boundAndSnapToSides(destinationPoint, {
|
|
|
34811
34746
|
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
34812
34747
|
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
34813
34748
|
// for is then used in the polar function to determine the new point.
|
|
34814
|
-
const onLeft = sign
|
|
34749
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
34815
34750
|
|
|
34816
34751
|
// Uses the length of the first side of the polygon (radial coordinate)
|
|
34817
34752
|
// and the angle between the first and second sides of the
|
|
@@ -34946,19 +34881,11 @@ const {
|
|
|
34946
34881
|
getClockwiseAngle
|
|
34947
34882
|
} = angles;
|
|
34948
34883
|
const {
|
|
34949
|
-
angleMeasures,
|
|
34950
|
-
ccw,
|
|
34951
|
-
collinear,
|
|
34952
34884
|
getLineEquation,
|
|
34953
34885
|
getLineIntersection,
|
|
34954
|
-
intersects,
|
|
34955
|
-
lawOfCosines,
|
|
34956
34886
|
magnitude,
|
|
34957
|
-
rotate,
|
|
34958
|
-
sign,
|
|
34959
34887
|
vector
|
|
34960
34888
|
} = geometry;
|
|
34961
|
-
const TRASH_ICON_URI = "https://ka-perseus-graphie.s3.amazonaws.com/b1452c0d79fd0f7ff4c3af9488474a0a0decb361.png";
|
|
34962
34889
|
const defaultBackgroundImage = {
|
|
34963
34890
|
url: null
|
|
34964
34891
|
};
|
|
@@ -34967,31 +34894,9 @@ const UNLIMITED = "unlimited";
|
|
|
34967
34894
|
// Sample background image:
|
|
34968
34895
|
// https://ka-perseus-graphie.s3.amazonaws.com/29c1b0fcd17fe63df0f148fe357044d5d5c7d0bb.png
|
|
34969
34896
|
|
|
34970
|
-
// default to defaultValue if actual is null or undefined
|
|
34971
|
-
function defaultVal(actual, defaultValue) {
|
|
34972
|
-
return actual == null ? defaultValue : actual;
|
|
34973
|
-
}
|
|
34974
|
-
|
|
34975
|
-
// Less than or approximately equal
|
|
34976
|
-
function leq(a, b) {
|
|
34977
|
-
return a < b || approximateEqual(a, b);
|
|
34978
|
-
}
|
|
34979
|
-
function capitalize(str) {
|
|
34980
|
-
return str.replace(/(?:^|-)(.)/g, function (match, letter) {
|
|
34981
|
-
return letter.toUpperCase();
|
|
34982
|
-
});
|
|
34983
|
-
}
|
|
34984
34897
|
function numSteps(range, step) {
|
|
34985
34898
|
return Math.floor((range[1] - range[0]) / step);
|
|
34986
34899
|
}
|
|
34987
|
-
const _getShouldShowInstructions = props => {
|
|
34988
|
-
return _isClickToAddPoints(props) && (
|
|
34989
|
-
// @ts-expect-error - TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'. | TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'.
|
|
34990
|
-
props.graph.coords == null || props.graph.coords.length === 0);
|
|
34991
|
-
};
|
|
34992
|
-
const _isClickToAddPoints = props => {
|
|
34993
|
-
return props.graph.type === "point" && props.graph.numPoints === UNLIMITED || props.graph.type === "polygon" && props.graph.numSides === UNLIMITED;
|
|
34994
|
-
};
|
|
34995
34900
|
const makeInvalidTypeError = (functionName, graphType) => {
|
|
34996
34901
|
return new PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, Errors.NotAllowed, {
|
|
34997
34902
|
metadata: {
|
|
@@ -35032,1236 +34937,16 @@ function getQuadraticCoefficients(coords) {
|
|
|
35032
34937
|
const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
|
|
35033
34938
|
return [a, b, c];
|
|
35034
34939
|
}
|
|
35035
|
-
|
|
35036
|
-
// (LEMS-2190): Move the Mafs Angle Graph coordinate reversal logic in interactive-graph-state.ts
|
|
35037
|
-
// to this file when we remove the legacy graph. This logic allows us to support bi-directional angles
|
|
35038
|
-
// for the new (non-reflexive) Mafs graphs, while maintaining the same scoring behaviour as the legacy graph.
|
|
35039
|
-
// Once the legacy graph is removed, we should move this logic directly into the validate function below.
|
|
35040
|
-
class LegacyInteractiveGraph extends React.Component {
|
|
35041
|
-
constructor(...args) {
|
|
35042
|
-
super(...args);
|
|
35043
|
-
this.angle = void 0;
|
|
35044
|
-
this.circle = void 0;
|
|
35045
|
-
this.graphie = void 0;
|
|
35046
|
-
this.horizHairline = void 0;
|
|
35047
|
-
this.line = void 0;
|
|
35048
|
-
this.lines = void 0;
|
|
35049
|
-
this.parabola = void 0;
|
|
35050
|
-
this.pointA = void 0;
|
|
35051
|
-
this.pointB = void 0;
|
|
35052
|
-
this.pointC = void 0;
|
|
35053
|
-
// @ts-expect-error - TS2564 - Property 'points' has no initializer and is not definitely assigned in the constructor.
|
|
35054
|
-
this.points = void 0;
|
|
35055
|
-
this.polygon = void 0;
|
|
35056
|
-
// @ts-expect-error - TS2564 - Property 'shouldResetGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
35057
|
-
this.shouldResetGraphie = void 0;
|
|
35058
|
-
this.sinusoid = void 0;
|
|
35059
|
-
this.trashCan = void 0;
|
|
35060
|
-
this.vertHairline = void 0;
|
|
35061
|
-
this.state = {
|
|
35062
|
-
shouldShowInstructions: _getShouldShowInstructions(this.props)
|
|
35063
|
-
};
|
|
35064
|
-
this._getShouldShowInstructions = props => {
|
|
35065
|
-
props = props || this.props;
|
|
35066
|
-
return this.isClickToAddPoints(props) && (
|
|
35067
|
-
// @ts-expect-error - TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'. | TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'.
|
|
35068
|
-
props.graph.coords == null || props.graph.coords.length === 0);
|
|
35069
|
-
};
|
|
35070
|
-
this.setGraphie = newGraphie => {
|
|
35071
|
-
this.graphie = newGraphie;
|
|
35072
|
-
this.setupGraphie();
|
|
35073
|
-
};
|
|
35074
|
-
this.handleAddPointsMouseDown = coord => {
|
|
35075
|
-
// This function should only be called when this.isClickToAddPoints()
|
|
35076
|
-
// is true
|
|
35077
|
-
if (!this.isClickToAddPoints()) {
|
|
35078
|
-
throw new PerseusError("handleAddPointsClick should not be registered" + "when isClickToAddPoints() is false", Errors.NotAllowed);
|
|
35079
|
-
}
|
|
35080
|
-
if (!this.isCoordInTrash(coord)) {
|
|
35081
|
-
let point;
|
|
35082
|
-
if (this.props.graph.type === "point") {
|
|
35083
|
-
point = this.createPointForPointsType(coord, this.points.length);
|
|
35084
|
-
if (!point.constrain()) {
|
|
35085
|
-
point.remove();
|
|
35086
|
-
return;
|
|
35087
|
-
}
|
|
35088
|
-
this.points.push(point);
|
|
35089
|
-
|
|
35090
|
-
// interactive2 allows us to grab the point
|
|
35091
|
-
const idx = this.points.length - 1;
|
|
35092
|
-
this.points[idx].grab(coord);
|
|
35093
|
-
this.updateCoordsFromPoints();
|
|
35094
|
-
} else if (this.props.graph.type === "polygon") {
|
|
35095
|
-
var _this$polygon;
|
|
35096
|
-
if ((_this$polygon = this.polygon) != null && _this$polygon.closed()) {
|
|
35097
|
-
return;
|
|
35098
|
-
}
|
|
35099
|
-
point = this.createPointForPolygonType(coord, this.points.length);
|
|
35100
|
-
this.points.push(point);
|
|
35101
|
-
const idx = this.points.length - 1;
|
|
35102
|
-
this.points[idx].grab(coord);
|
|
35103
|
-
|
|
35104
|
-
// We don't call updateCoordsFromPoints for
|
|
35105
|
-
// polygons, since the polygon won't be
|
|
35106
|
-
// closed yet.
|
|
35107
|
-
this.updatePolygon();
|
|
35108
|
-
}
|
|
35109
|
-
this.setState({
|
|
35110
|
-
shouldShowInstructions: false
|
|
35111
|
-
});
|
|
35112
|
-
}
|
|
35113
|
-
};
|
|
35114
|
-
this.resetGraphie = () => {
|
|
35115
|
-
var _this$refs$graph;
|
|
35116
|
-
this.shouldResetGraphie = false;
|
|
35117
|
-
this.parabola = null;
|
|
35118
|
-
this.sinusoid = null;
|
|
35119
|
-
// eslint-disable-next-line react/no-string-refs
|
|
35120
|
-
// @ts-expect-error - TS2339 - Property 'reset' does not exist on type 'ReactInstance'.
|
|
35121
|
-
(_this$refs$graph = this.refs.graph) == null || _this$refs$graph.reset();
|
|
35122
|
-
};
|
|
35123
|
-
this.setupGraphie = () => {
|
|
35124
|
-
this.setTrashCanVisibility(0);
|
|
35125
|
-
if (this.isClickToAddPoints()) {
|
|
35126
|
-
this.setTrashCanVisibility(0.5);
|
|
35127
|
-
}
|
|
35128
|
-
if (this.props.apiOptions.isMobile) {
|
|
35129
|
-
var _this$horizHairline, _this$vertHairline;
|
|
35130
|
-
this.horizHairline = new WrappedLine(this.graphie, [0, 0], [0, 0], {
|
|
35131
|
-
normalStyle: {
|
|
35132
|
-
strokeWidth: 1
|
|
35133
|
-
}
|
|
35134
|
-
});
|
|
35135
|
-
this.horizHairline.attr({
|
|
35136
|
-
stroke: KhanColors.INTERACTIVE
|
|
35137
|
-
});
|
|
35138
|
-
(_this$horizHairline = this.horizHairline) == null || _this$horizHairline.hide();
|
|
35139
|
-
this.vertHairline = new WrappedLine(this.graphie, [0, 0], [0, 0], {
|
|
35140
|
-
normalStyle: {
|
|
35141
|
-
strokeWidth: 1
|
|
35142
|
-
}
|
|
35143
|
-
});
|
|
35144
|
-
this.vertHairline.attr({
|
|
35145
|
-
stroke: KhanColors.INTERACTIVE
|
|
35146
|
-
});
|
|
35147
|
-
(_this$vertHairline = this.vertHairline) == null || _this$vertHairline.hide();
|
|
35148
|
-
}
|
|
35149
|
-
const type = this.props.graph.type;
|
|
35150
|
-
this["add" + capitalize(type) + "Controls"]();
|
|
35151
|
-
};
|
|
35152
|
-
this.showHairlines = point => {
|
|
35153
|
-
if (this.props.apiOptions.isMobile && this.props.markings !== "none") {
|
|
35154
|
-
var _this$horizHairline2, _this$horizHairline3, _this$vertHairline2, _this$vertHairline3;
|
|
35155
|
-
// Hairlines are already initialized when the graph is loaded, so
|
|
35156
|
-
// here we just move them to the updated location and make them
|
|
35157
|
-
// visible.
|
|
35158
|
-
(_this$horizHairline2 = this.horizHairline) == null || _this$horizHairline2.moveTo([this.props.range[0][0], point[1]], [this.props.range[0][1], point[1]]);
|
|
35159
|
-
(_this$horizHairline3 = this.horizHairline) == null || _this$horizHairline3.show();
|
|
35160
|
-
(_this$vertHairline2 = this.vertHairline) == null || _this$vertHairline2.moveTo([point[0], this.props.range[1][0]], [point[0], this.props.range[1][1]]);
|
|
35161
|
-
(_this$vertHairline3 = this.vertHairline) == null || _this$vertHairline3.show();
|
|
35162
|
-
}
|
|
35163
|
-
};
|
|
35164
|
-
this.hideHairlines = () => {
|
|
35165
|
-
if (this.props.apiOptions.isMobile) {
|
|
35166
|
-
var _this$horizHairline4, _this$vertHairline4;
|
|
35167
|
-
(_this$horizHairline4 = this.horizHairline) == null || _this$horizHairline4.hide();
|
|
35168
|
-
(_this$vertHairline4 = this.vertHairline) == null || _this$vertHairline4.hide();
|
|
35169
|
-
}
|
|
35170
|
-
};
|
|
35171
|
-
this.setTrashCanVisibility = opacity => {
|
|
35172
|
-
const graphie = this.graphie;
|
|
35173
|
-
if (number.equal(opacity, 0)) {
|
|
35174
|
-
if (this.trashCan) {
|
|
35175
|
-
this.trashCan.remove();
|
|
35176
|
-
this.trashCan = null;
|
|
35177
|
-
}
|
|
35178
|
-
} else if (!this.props.apiOptions.isMobile) {
|
|
35179
|
-
var _this$trashCan;
|
|
35180
|
-
// Only if trash tooltips are not being used, we initialize the old
|
|
35181
|
-
// trash can area.
|
|
35182
|
-
if (!this.trashCan) {
|
|
35183
|
-
var _graphie$raphael;
|
|
35184
|
-
this.trashCan = graphie == null || (_graphie$raphael = graphie.raphael) == null ? void 0 : _graphie$raphael.image(TRASH_ICON_URI, graphie.xpixels - 40, graphie.ypixels - 40, 40, 40);
|
|
35185
|
-
}
|
|
35186
|
-
(_this$trashCan = this.trashCan) == null || _this$trashCan.attr({
|
|
35187
|
-
opacity: opacity
|
|
35188
|
-
});
|
|
35189
|
-
}
|
|
35190
|
-
};
|
|
35191
|
-
this.isClickToAddPoints = props => {
|
|
35192
|
-
props = props || this.props;
|
|
35193
|
-
return _isClickToAddPoints(props);
|
|
35194
|
-
};
|
|
35195
|
-
this._lineStroke = () => {
|
|
35196
|
-
// This should probably use: this.props.apiOptions.isMobile
|
|
35197
|
-
// @ts-expect-error - TS2339 - Property 'isMobile' does not exist on type 'Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
|
|
35198
|
-
return this.props.isMobile ? {
|
|
35199
|
-
"stroke-width": 3
|
|
35200
|
-
} : {};
|
|
35201
|
-
};
|
|
35202
|
-
this.addLine = type => {
|
|
35203
|
-
const self = this;
|
|
35204
|
-
const graphie = self.graphie;
|
|
35205
|
-
const coords = InteractiveGraph.getLineCoords(self.props.graph, self.props);
|
|
35206
|
-
const points = self.points = _.map(coords, coord => {
|
|
35207
|
-
return Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35208
|
-
coord: coord,
|
|
35209
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap()],
|
|
35210
|
-
onMove: () => {
|
|
35211
|
-
const graph = _.extend({}, self.props.graph, {
|
|
35212
|
-
coords: _.invoke(points, "coord")
|
|
35213
|
-
});
|
|
35214
|
-
self.onChange({
|
|
35215
|
-
graph: graph
|
|
35216
|
-
});
|
|
35217
|
-
}
|
|
35218
|
-
});
|
|
35219
|
-
});
|
|
35220
|
-
const lineConfig = {
|
|
35221
|
-
points: points,
|
|
35222
|
-
static: true,
|
|
35223
|
-
normalStyle: _extends({
|
|
35224
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.INTERACTIVE
|
|
35225
|
-
}, this._lineStroke())
|
|
35226
|
-
};
|
|
35227
|
-
if (type === "line") {
|
|
35228
|
-
// @ts-expect-error - TS2339 - Property 'extendLine' does not exist on type '{ readonly points: any[]; readonly static: true; readonly normalStyle: { readonly "stroke-width"?: number | undefined; readonly stroke: "#71B307" | "#63D9EA"; }; }'.
|
|
35229
|
-
lineConfig.extendLine = true;
|
|
35230
|
-
} else if (type === "ray") {
|
|
35231
|
-
// @ts-expect-error - TS2339 - Property 'extendRay' does not exist on type '{ readonly points: any[]; readonly static: true; readonly normalStyle: { readonly "stroke-width"?: number | undefined; readonly stroke: "#71B307" | "#63D9EA"; }; }'.
|
|
35232
|
-
lineConfig.extendRay = true;
|
|
35233
|
-
}
|
|
35234
|
-
self.line = Interactive2.addMovableLine(graphie, lineConfig);
|
|
35235
|
-
|
|
35236
|
-
// A and B can't be in the same place
|
|
35237
|
-
points[0].listen("constraints", "isLine", coord => {
|
|
35238
|
-
return !point.equal(coord, points[1].coord());
|
|
35239
|
-
});
|
|
35240
|
-
points[1].listen("constraints", "isLine", coord => {
|
|
35241
|
-
return !point.equal(coord, points[0].coord());
|
|
35242
|
-
});
|
|
35243
|
-
};
|
|
35244
|
-
this.removeLine = () => {
|
|
35245
|
-
var _this$line;
|
|
35246
|
-
_.invoke(this.points, "remove");
|
|
35247
|
-
(_this$line = this.line) == null || _this$line.remove();
|
|
35248
|
-
};
|
|
35249
|
-
this.addNoneControls = () => {};
|
|
35250
|
-
this.removeNoneControls = () => {};
|
|
35251
|
-
this.addLinearControls = () => {
|
|
35252
|
-
this.addLine("line");
|
|
35253
|
-
};
|
|
35254
|
-
this.removeLinearControls = () => {
|
|
35255
|
-
this.removeLine();
|
|
35256
|
-
};
|
|
35257
|
-
this.addQuadraticControls = () => {
|
|
35258
|
-
if (this.props.graph.type !== "quadratic") {
|
|
35259
|
-
throw makeInvalidTypeError("addQuadraticControls", "quadratic");
|
|
35260
|
-
}
|
|
35261
|
-
let coords = this.props.graph.coords;
|
|
35262
|
-
if (!coords) {
|
|
35263
|
-
coords = InteractiveGraph.defaultQuadraticCoords(this.props);
|
|
35264
|
-
}
|
|
35265
|
-
const onMoveHandler = () => {
|
|
35266
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35267
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2531 - Object is possibly 'null'. | TS2531 - Object is possibly 'null'.
|
|
35268
|
-
coords: [pointA.coord(), pointB.coord(), pointC.coord()]
|
|
35269
|
-
});
|
|
35270
|
-
this.onChange({
|
|
35271
|
-
graph
|
|
35272
|
-
});
|
|
35273
|
-
this.updateQuadratic();
|
|
35274
|
-
};
|
|
35275
|
-
|
|
35276
|
-
// NOTE(jeresig): This code attempts to access the variable while it's
|
|
35277
|
-
// still being defined, it should be refactored! The callbacks appear
|
|
35278
|
-
// to be executed synchronously, which causes this issue.
|
|
35279
|
-
let pointA = null;
|
|
35280
|
-
pointA = this.pointA = Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35281
|
-
coord: coords[0],
|
|
35282
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35283
|
-
return !pointA ||
|
|
35284
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35285
|
-
coord[0] !== pointB.coord()[0] &&
|
|
35286
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35287
|
-
coord[0] !== pointC.coord()[0];
|
|
35288
|
-
}],
|
|
35289
|
-
onMove: onMoveHandler
|
|
35290
|
-
});
|
|
35291
|
-
|
|
35292
|
-
// NOTE(jeresig): This code attempts to access the variable while it's
|
|
35293
|
-
// still being defined, it should be refactored! The callbacks appear
|
|
35294
|
-
// to be executed synchronously, which causes this issue.
|
|
35295
|
-
let pointB = null;
|
|
35296
|
-
pointB = this.pointB = Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35297
|
-
coord: coords[1],
|
|
35298
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35299
|
-
return !pointB ||
|
|
35300
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35301
|
-
coord[0] !== pointA.coord()[0] &&
|
|
35302
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35303
|
-
coord[0] !== pointC.coord()[0];
|
|
35304
|
-
}],
|
|
35305
|
-
onMove: onMoveHandler
|
|
35306
|
-
});
|
|
35307
|
-
|
|
35308
|
-
// NOTE(jeresig): This code attempts to access the variable while it's
|
|
35309
|
-
// still being defined, it should be refactored! The callbacks appear
|
|
35310
|
-
// to be executed synchronously, which causes this issue.
|
|
35311
|
-
let pointC = null;
|
|
35312
|
-
pointC = this.pointC = Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35313
|
-
coord: coords[2],
|
|
35314
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35315
|
-
return !pointC ||
|
|
35316
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35317
|
-
coord[0] !== pointA.coord()[0] &&
|
|
35318
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35319
|
-
coord[0] !== pointB.coord()[0];
|
|
35320
|
-
}],
|
|
35321
|
-
onMove: onMoveHandler
|
|
35322
|
-
});
|
|
35323
|
-
this.updateQuadratic();
|
|
35324
|
-
};
|
|
35325
|
-
this.updateQuadratic = () => {
|
|
35326
|
-
const coeffs = InteractiveGraph.getCurrentQuadraticCoefficients(this.props);
|
|
35327
|
-
if (!coeffs) {
|
|
35328
|
-
return;
|
|
35329
|
-
}
|
|
35330
|
-
|
|
35331
|
-
// Extract coefficients the parabola
|
|
35332
|
-
const a = coeffs[0];
|
|
35333
|
-
const b = coeffs[1];
|
|
35334
|
-
const c = coeffs[2];
|
|
35335
|
-
|
|
35336
|
-
// Plot and style
|
|
35337
|
-
if (this.parabola) {
|
|
35338
|
-
var _this$graphie, _this$parabola;
|
|
35339
|
-
const path = (_this$graphie = this.graphie) == null ? void 0 : _this$graphie.svgParabolaPath(a, b, c);
|
|
35340
|
-
(_this$parabola = this.parabola) == null || _this$parabola.attr({
|
|
35341
|
-
path: path
|
|
35342
|
-
});
|
|
35343
|
-
} else {
|
|
35344
|
-
var _this$graphie2, _this$parabola2, _this$parabola3;
|
|
35345
|
-
this.parabola = (_this$graphie2 = this.graphie) == null ? void 0 : _this$graphie2.parabola(a, b, c);
|
|
35346
|
-
(_this$parabola2 = this.parabola) == null || _this$parabola2.attr(_extends({
|
|
35347
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.DYNAMIC
|
|
35348
|
-
}, this._lineStroke()));
|
|
35349
|
-
(_this$parabola3 = this.parabola) == null || _this$parabola3.toBack();
|
|
35350
|
-
}
|
|
35351
|
-
};
|
|
35352
|
-
this.removeQuadraticControls = () => {
|
|
35353
|
-
var _this$pointA, _this$pointB, _this$pointC;
|
|
35354
|
-
(_this$pointA = this.pointA) == null || _this$pointA.remove();
|
|
35355
|
-
(_this$pointB = this.pointB) == null || _this$pointB.remove();
|
|
35356
|
-
(_this$pointC = this.pointC) == null || _this$pointC.remove();
|
|
35357
|
-
if (this.parabola) {
|
|
35358
|
-
this.parabola.remove();
|
|
35359
|
-
this.parabola = null;
|
|
35360
|
-
}
|
|
35361
|
-
};
|
|
35362
|
-
this.addSinusoidControls = () => {
|
|
35363
|
-
if (this.props.graph.type !== "sinusoid") {
|
|
35364
|
-
throw makeInvalidTypeError("addSinusoidControls", "sinusoid");
|
|
35365
|
-
}
|
|
35366
|
-
let coords = this.props.graph.coords;
|
|
35367
|
-
if (!coords) {
|
|
35368
|
-
coords = InteractiveGraph.defaultSinusoidCoords(this.props);
|
|
35369
|
-
}
|
|
35370
|
-
const onMoveHandler = () => {
|
|
35371
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35372
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35373
|
-
coords: [pointA.coord(), pointB.coord()]
|
|
35374
|
-
});
|
|
35375
|
-
this.onChange({
|
|
35376
|
-
graph: graph
|
|
35377
|
-
});
|
|
35378
|
-
this.updateSinusoid();
|
|
35379
|
-
};
|
|
35380
|
-
|
|
35381
|
-
// NOTE(jeresig): This code attempts to access the variable while it's
|
|
35382
|
-
// still being defined, it should be refactored! The callbacks appear
|
|
35383
|
-
// to be executed synchronously, which causes this issue.
|
|
35384
|
-
let pointA = null;
|
|
35385
|
-
pointA = this.pointA = Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35386
|
-
coord: coords[0],
|
|
35387
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35388
|
-
return !pointA || coord[0] !== pointB.coord()[0];
|
|
35389
|
-
}],
|
|
35390
|
-
onMove: onMoveHandler
|
|
35391
|
-
});
|
|
35392
|
-
const pointB = this.pointB = Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35393
|
-
coord: coords[1],
|
|
35394
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35395
|
-
// @ts-expect-error - TS2339 - Property 'coord' does not exist on type 'never'.
|
|
35396
|
-
return !pointA || coord[0] !== pointA.coord()[0];
|
|
35397
|
-
}],
|
|
35398
|
-
onMove: onMoveHandler
|
|
35399
|
-
});
|
|
35400
|
-
this.updateSinusoid();
|
|
35401
|
-
};
|
|
35402
|
-
this.updateSinusoid = () => {
|
|
35403
|
-
const coeffs = InteractiveGraph.getCurrentSinusoidCoefficients(this.props);
|
|
35404
|
-
if (!coeffs) {
|
|
35405
|
-
return;
|
|
35406
|
-
}
|
|
35407
|
-
const a = coeffs[0];
|
|
35408
|
-
const b = coeffs[1];
|
|
35409
|
-
const c = coeffs[2];
|
|
35410
|
-
const d = coeffs[3];
|
|
35411
|
-
|
|
35412
|
-
// Plot and style
|
|
35413
|
-
if (this.sinusoid) {
|
|
35414
|
-
var _this$graphie3, _this$sinusoid;
|
|
35415
|
-
const path = (_this$graphie3 = this.graphie) == null ? void 0 : _this$graphie3.svgSinusoidPath(a, b, c, d);
|
|
35416
|
-
(_this$sinusoid = this.sinusoid) == null || _this$sinusoid.attr({
|
|
35417
|
-
path: path
|
|
35418
|
-
});
|
|
35419
|
-
} else {
|
|
35420
|
-
var _this$graphie4, _this$sinusoid2, _this$sinusoid3;
|
|
35421
|
-
this.sinusoid = (_this$graphie4 = this.graphie) == null ? void 0 : _this$graphie4.sinusoid(a, b, c, d);
|
|
35422
|
-
(_this$sinusoid2 = this.sinusoid) == null || _this$sinusoid2.attr(_extends({
|
|
35423
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.DYNAMIC
|
|
35424
|
-
}, this._lineStroke()));
|
|
35425
|
-
(_this$sinusoid3 = this.sinusoid) == null || _this$sinusoid3.toBack();
|
|
35426
|
-
}
|
|
35427
|
-
};
|
|
35428
|
-
this.removeSinusoidControls = () => {
|
|
35429
|
-
var _this$pointA2, _this$pointB2;
|
|
35430
|
-
(_this$pointA2 = this.pointA) == null || _this$pointA2.remove();
|
|
35431
|
-
(_this$pointB2 = this.pointB) == null || _this$pointB2.remove();
|
|
35432
|
-
if (this.sinusoid) {
|
|
35433
|
-
this.sinusoid.remove();
|
|
35434
|
-
this.sinusoid = null;
|
|
35435
|
-
}
|
|
35436
|
-
};
|
|
35437
|
-
this.addCircleControls = () => {
|
|
35438
|
-
const graphie = this.graphie;
|
|
35439
|
-
const minSnap = _.min(graphie.snap);
|
|
35440
|
-
const circle = this.circle = graphie == null ? void 0 : graphie.addCircleGraph({
|
|
35441
|
-
// @ts-expect-error - TS2339 - Property 'center' does not exist on type 'PerseusGraphType'.
|
|
35442
|
-
center: this.props.graph.center || [0, 0],
|
|
35443
|
-
// @ts-expect-error - TS2339 - Property 'radius' does not exist on type 'PerseusGraphType'.
|
|
35444
|
-
radius: this.props.graph.radius || _.min(this.props.step),
|
|
35445
|
-
snapX: graphie.snap[0],
|
|
35446
|
-
snapY: graphie.snap[1],
|
|
35447
|
-
minRadius: minSnap,
|
|
35448
|
-
snapRadius: minSnap
|
|
35449
|
-
});
|
|
35450
|
-
$(circle).on("move", () => {
|
|
35451
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35452
|
-
center: circle.center,
|
|
35453
|
-
radius: circle.radius
|
|
35454
|
-
});
|
|
35455
|
-
this.onChange({
|
|
35456
|
-
graph: graph
|
|
35457
|
-
});
|
|
35458
|
-
});
|
|
35459
|
-
};
|
|
35460
|
-
this.removeCircleControls = () => {
|
|
35461
|
-
var _this$circle;
|
|
35462
|
-
(_this$circle = this.circle) == null || _this$circle.remove();
|
|
35463
|
-
};
|
|
35464
|
-
this.addLinearSystemControls = () => {
|
|
35465
|
-
const graphie = this.graphie;
|
|
35466
|
-
const coords = InteractiveGraph.getLinearSystemCoords(this.props.graph, this.props);
|
|
35467
|
-
const segmentColors = [KhanColors.INTERACTIVE, KhanColors.GREEN];
|
|
35468
|
-
const points = this.points = _.map(coords, (segmentCoords, segmentIndex) => {
|
|
35469
|
-
// NOTE(jeresig): This code attempts to access the variable
|
|
35470
|
-
// while it's still being defined, it should be refactored!
|
|
35471
|
-
// The callbacks appear to be executed synchronously, which
|
|
35472
|
-
// causes this issue.
|
|
35473
|
-
const segmentPoints = [];
|
|
35474
|
-
for (let i = 0; i < segmentCoords.length; i += 1) {
|
|
35475
|
-
const coord = segmentCoords[i];
|
|
35476
|
-
segmentPoints.push(Interactive2.addMaybeMobileMovablePoint(this, {
|
|
35477
|
-
coord: coord,
|
|
35478
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35479
|
-
const otherSegment = segmentPoints[1 - i];
|
|
35480
|
-
if (!otherSegment) {
|
|
35481
|
-
// segment hasn't been defined yet
|
|
35482
|
-
// because we're still creating them
|
|
35483
|
-
return;
|
|
35484
|
-
}
|
|
35485
|
-
return !point.equal(coord, otherSegment.coord());
|
|
35486
|
-
}],
|
|
35487
|
-
onMove: () => {
|
|
35488
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35489
|
-
coords: _.map(this.points, segment => _.invoke(segment, "coord"))
|
|
35490
|
-
});
|
|
35491
|
-
this.onChange({
|
|
35492
|
-
graph: graph
|
|
35493
|
-
});
|
|
35494
|
-
},
|
|
35495
|
-
normalStyle: {
|
|
35496
|
-
fill: segmentColors[segmentIndex]
|
|
35497
|
-
},
|
|
35498
|
-
highlightStyle: {
|
|
35499
|
-
fill: segmentColors[segmentIndex]
|
|
35500
|
-
}
|
|
35501
|
-
}));
|
|
35502
|
-
}
|
|
35503
|
-
return segmentPoints;
|
|
35504
|
-
});
|
|
35505
|
-
this.lines = _.map(points, (segmentPoints, segmentIndex) => {
|
|
35506
|
-
return Interactive2.addMovableLine(graphie, {
|
|
35507
|
-
points: segmentPoints,
|
|
35508
|
-
static: true,
|
|
35509
|
-
extendLine: true,
|
|
35510
|
-
normalStyle: {
|
|
35511
|
-
stroke: segmentColors[segmentIndex]
|
|
35512
|
-
}
|
|
35513
|
-
});
|
|
35514
|
-
});
|
|
35515
|
-
};
|
|
35516
|
-
this.removeLinearSystemControls = () => {
|
|
35517
|
-
// @ts-expect-error - TS2345 - Argument of type 'readonly (readonly Coord[])[] | null | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
35518
|
-
_.invoke(this.lines, "remove");
|
|
35519
|
-
_.map(this.points, segment => _.invoke(segment, "remove"));
|
|
35520
|
-
};
|
|
35521
|
-
this.isCoordInTrash = coord => {
|
|
35522
|
-
if (this.props.apiOptions.isMobile) {
|
|
35523
|
-
return false;
|
|
35524
|
-
}
|
|
35525
|
-
const graphie = this.graphie;
|
|
35526
|
-
const screenPoint = graphie == null ? void 0 : graphie.scalePoint(coord);
|
|
35527
|
-
return screenPoint[0] >= graphie.xpixels - 40 && screenPoint[1] >= graphie.ypixels - 40;
|
|
35528
|
-
};
|
|
35529
|
-
this.createPointForPointsType = (coord, i) => {
|
|
35530
|
-
const self = this;
|
|
35531
|
-
const remove = () => {
|
|
35532
|
-
self.points = _.filter(self.points, function (pt) {
|
|
35533
|
-
return pt !== point$1;
|
|
35534
|
-
});
|
|
35535
|
-
// update the correct answer box
|
|
35536
|
-
self.updateCoordsFromPoints();
|
|
35537
|
-
|
|
35538
|
-
// remove this movablePoint from graphie.
|
|
35539
|
-
// we wait to do this until we're not inside of
|
|
35540
|
-
// said point's onMoveEnd method so its state is
|
|
35541
|
-
// consistent throughout this method call
|
|
35542
|
-
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
35543
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
35544
|
-
setTimeout(point$1.remove.bind(point$1), 0); // eslint-disable-line no-restricted-syntax
|
|
35545
|
-
};
|
|
35546
|
-
|
|
35547
|
-
// NOTE(jeresig): This code attempts to access the variable while it's
|
|
35548
|
-
// still being defined, it should be refactored! The callbacks appear
|
|
35549
|
-
// to be executed synchronously, which causes this issue.
|
|
35550
|
-
let point$1 = null;
|
|
35551
|
-
point$1 = Interactive2.addMaybeMobileMovablePoint(this, _extends({
|
|
35552
|
-
coord: coord,
|
|
35553
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), function (coord) {
|
|
35554
|
-
// TODO(jack): There ought to be a
|
|
35555
|
-
// MovablePoint.constraints.avoid
|
|
35556
|
-
// default that lets you do things like this
|
|
35557
|
-
return _.all(self.points, function (pt) {
|
|
35558
|
-
return point$1 === pt || !point.equal(coord, pt.coord());
|
|
35559
|
-
});
|
|
35560
|
-
}],
|
|
35561
|
-
onMoveStart: function () {
|
|
35562
|
-
if (self.isClickToAddPoints()) {
|
|
35563
|
-
self.setTrashCanVisibility(1);
|
|
35564
|
-
}
|
|
35565
|
-
},
|
|
35566
|
-
onMove: self.updateCoordsFromPoints,
|
|
35567
|
-
onMoveEnd: function (coord) {
|
|
35568
|
-
if (self.isClickToAddPoints()) {
|
|
35569
|
-
if (self.isCoordInTrash(coord)) {
|
|
35570
|
-
remove();
|
|
35571
|
-
}
|
|
35572
|
-
// In case we mouseup'd off the graphie and that
|
|
35573
|
-
// stopped the move (in which case, we might not
|
|
35574
|
-
// be in isCoordInTrash()
|
|
35575
|
-
self.setTrashCanVisibility(0.5);
|
|
35576
|
-
}
|
|
35577
|
-
}
|
|
35578
|
-
}, this.props.apiOptions.isMobile && self.isClickToAddPoints() ? {
|
|
35579
|
-
onRemove: remove
|
|
35580
|
-
} : {}));
|
|
35581
|
-
return point$1;
|
|
35582
|
-
};
|
|
35583
|
-
this.removePoint = point => {
|
|
35584
|
-
let index = null;
|
|
35585
|
-
this.points = _.filter(this.points, function (pt, i) {
|
|
35586
|
-
if (pt === point) {
|
|
35587
|
-
// @ts-expect-error - TS2322 - Type 'number' is not assignable to type 'null'.
|
|
35588
|
-
index = i;
|
|
35589
|
-
return false;
|
|
35590
|
-
}
|
|
35591
|
-
return true;
|
|
35592
|
-
});
|
|
35593
|
-
return index;
|
|
35594
|
-
};
|
|
35595
|
-
this.createPointForPolygonType = (coord, i) => {
|
|
35596
|
-
if (this.props.graph.type !== "polygon") {
|
|
35597
|
-
throw makeInvalidTypeError("createPointForPolygonType", "polygon");
|
|
35598
|
-
}
|
|
35599
|
-
|
|
35600
|
-
// TODO(alex): check against "grid" instead, use constants
|
|
35601
|
-
const snapToGrid = !_.contains(["angles", "sides"], this.props.graph.snapTo);
|
|
35602
|
-
|
|
35603
|
-
// Index relative to current point -> absolute index
|
|
35604
|
-
// NOTE: This does not work when isClickToAddPoints() == true,
|
|
35605
|
-
// as `i` can be changed by dragging a point to the trash
|
|
35606
|
-
// Currently this function is only called when !isClickToAddPoints()
|
|
35607
|
-
const rel = j => {
|
|
35608
|
-
return (i + j + this.points.length) % this.points.length;
|
|
35609
|
-
};
|
|
35610
|
-
const remove = () => {
|
|
35611
|
-
var _this$polygon2;
|
|
35612
|
-
// remove this point from points
|
|
35613
|
-
const index = this.removePoint(point$1);
|
|
35614
|
-
if ((_this$polygon2 = this.polygon) != null && _this$polygon2.closed()) {
|
|
35615
|
-
var _this$polygon3;
|
|
35616
|
-
// We should be checking if this.points is defined before rotating them.
|
|
35617
|
-
// @ts-expect-error - TS4104 - The type 'readonly any[]' is 'readonly' and cannot be assigned to the mutable type 'any[]'. | TS2345 - Argument of type 'number | null | undefined' is not assignable to parameter of type 'number | undefined'.
|
|
35618
|
-
this.points = rotate(this.points, index);
|
|
35619
|
-
(_this$polygon3 = this.polygon) == null || _this$polygon3.update({
|
|
35620
|
-
closed: false
|
|
35621
|
-
});
|
|
35622
|
-
}
|
|
35623
|
-
this.updatePolygon();
|
|
35624
|
-
// the polygon is now unclosed, so we need to
|
|
35625
|
-
// remove any points props
|
|
35626
|
-
this.clearCoords();
|
|
35627
|
-
|
|
35628
|
-
// remove this movablePoint from graphie.
|
|
35629
|
-
// wait to do this until we're not inside of
|
|
35630
|
-
// said point's onMoveEnd method so state is
|
|
35631
|
-
// consistent throughout the method call
|
|
35632
|
-
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
35633
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
35634
|
-
setTimeout(point$1.remove.bind(point$1), 0);
|
|
35635
|
-
};
|
|
35636
|
-
const setInitialMove = debounce$2((point, bool) => {
|
|
35637
|
-
point.state.isInitialMove = bool;
|
|
35638
|
-
}, 1000);
|
|
35639
|
-
const onMoveEndHandler = coord => {
|
|
35640
|
-
// If the user clicked and dragged a point over endpoint,
|
|
35641
|
-
// join the them
|
|
35642
|
-
const overlappedPoints = this.points.length > 1 && (point$1 === this.points[0] && point.equal(coord, _.last(this.points).coord()) || point$1 === _.last(this.points) && point.equal(coord, this.points[0].coord()));
|
|
35643
|
-
if (this.isClickToAddPoints()) {
|
|
35644
|
-
if (this.isCoordInTrash(coord)) {
|
|
35645
|
-
remove();
|
|
35646
|
-
} else if (overlappedPoints) {
|
|
35647
|
-
const pointToRemove = this.points.pop();
|
|
35648
|
-
if (this.points.length > 2) {
|
|
35649
|
-
var _this$polygon4;
|
|
35650
|
-
(_this$polygon4 = this.polygon) == null || _this$polygon4.update({
|
|
35651
|
-
closed: true
|
|
35652
|
-
});
|
|
35653
|
-
this.updateCoordsFromPoints();
|
|
35654
|
-
} else {
|
|
35655
|
-
var _this$polygon5;
|
|
35656
|
-
(_this$polygon5 = this.polygon) == null || _this$polygon5.update({
|
|
35657
|
-
closed: false
|
|
35658
|
-
});
|
|
35659
|
-
this.clearCoords();
|
|
35660
|
-
}
|
|
35661
|
-
this.updatePolygon();
|
|
35662
|
-
// remove this movablePoint from graphie.
|
|
35663
|
-
// wait to do this until we're not inside of
|
|
35664
|
-
// said point's onMoveEnd method so state is
|
|
35665
|
-
// consistent throughout the method call
|
|
35666
|
-
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
35667
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
35668
|
-
setTimeout(pointToRemove.remove.bind(pointToRemove), 0);
|
|
35669
|
-
} else {
|
|
35670
|
-
// If the user clicked and dragged a point over any other
|
|
35671
|
-
// existing point, fix shape
|
|
35672
|
-
const shouldRemove = _.any(this.points, function (pt) {
|
|
35673
|
-
return pt !== point$1 && point.equal(pt.coord(), coord);
|
|
35674
|
-
});
|
|
35675
|
-
if (shouldRemove) {
|
|
35676
|
-
var _this$polygon7;
|
|
35677
|
-
this.removePoint(point$1);
|
|
35678
|
-
if (this.points.length < 3) {
|
|
35679
|
-
var _this$polygon6;
|
|
35680
|
-
(_this$polygon6 = this.polygon) == null || _this$polygon6.update({
|
|
35681
|
-
closed: false
|
|
35682
|
-
});
|
|
35683
|
-
this.clearCoords();
|
|
35684
|
-
} else if ((_this$polygon7 = this.polygon) != null && _this$polygon7.closed()) {
|
|
35685
|
-
this.updateCoordsFromPoints();
|
|
35686
|
-
}
|
|
35687
|
-
this.updatePolygon();
|
|
35688
|
-
// remove this movablePoint from graphie.
|
|
35689
|
-
// wait to do this until we're not inside
|
|
35690
|
-
// said point's onMoveEnd method so state
|
|
35691
|
-
// is consistent throughout the method call
|
|
35692
|
-
// TODO(jeff, CP-3128): Use Wonder Blocks Timing API.
|
|
35693
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
35694
|
-
setTimeout(point$1.remove.bind(point$1), 0);
|
|
35695
|
-
} else {
|
|
35696
|
-
var _this$polygon8;
|
|
35697
|
-
// If this was
|
|
35698
|
-
// * a click on the first or last point
|
|
35699
|
-
// * and not a deletion
|
|
35700
|
-
// * and not a drag,
|
|
35701
|
-
// * and not a creation of a new point
|
|
35702
|
-
// (see !point.state.isInitialMove, below),
|
|
35703
|
-
// * and our polygon is not closed,
|
|
35704
|
-
// * and we can close it (we need at least the same
|
|
35705
|
-
// number of points as coordinates asked for in the
|
|
35706
|
-
// question),
|
|
35707
|
-
// then close it
|
|
35708
|
-
const isFirstOrLastPoint = point$1 === _.head(this.points) || point$1 === _.last(this.points);
|
|
35709
|
-
const pointNotMoved = !point$1.hasMoved();
|
|
35710
|
-
// NOTE (jsatk): Currently different on mobile versus
|
|
35711
|
-
// destkop
|
|
35712
|
-
const notANewPoint = !point$1.state.isInitialMove;
|
|
35713
|
-
const polygonNotClosed = !((_this$polygon8 = this.polygon) != null && _this$polygon8.closed());
|
|
35714
|
-
const allPointsPlotted = this.points.length > 2;
|
|
35715
|
-
const canCloseUnclosedPolygon = isFirstOrLastPoint && pointNotMoved && notANewPoint && polygonNotClosed && allPointsPlotted;
|
|
35716
|
-
if (canCloseUnclosedPolygon) {
|
|
35717
|
-
var _this$polygon9;
|
|
35718
|
-
(_this$polygon9 = this.polygon) == null || _this$polygon9.update({
|
|
35719
|
-
closed: true
|
|
35720
|
-
});
|
|
35721
|
-
this.updatePolygon();
|
|
35722
|
-
|
|
35723
|
-
// We finally have a closed polygon, so save our
|
|
35724
|
-
// points to props
|
|
35725
|
-
this.updateCoordsFromPoints();
|
|
35726
|
-
}
|
|
35727
|
-
}
|
|
35728
|
-
}
|
|
35729
|
-
|
|
35730
|
-
// In case we mouseup'd off the graphie and that
|
|
35731
|
-
// stopped the move
|
|
35732
|
-
this.setTrashCanVisibility(0.5);
|
|
35733
|
-
}
|
|
35734
|
-
setInitialMove(point$1, false);
|
|
35735
|
-
};
|
|
35736
|
-
const graphConstraint = coord => {
|
|
35737
|
-
// These constraints are all relative to the other points, so if
|
|
35738
|
-
// we're creating the initial points and haven't added any others
|
|
35739
|
-
// to the graph, we can't enforce them.
|
|
35740
|
-
if (this.points == null || this.points.length === 0) {
|
|
35741
|
-
return true;
|
|
35742
|
-
}
|
|
35743
|
-
const coords = _.invoke(this.points, "coord");
|
|
35744
|
-
coords[i] = coord;
|
|
35745
|
-
|
|
35746
|
-
// Check for invalid positioning, but only if we aren't adding
|
|
35747
|
-
// points one click at a time, since those added points could
|
|
35748
|
-
// have already violated these constraints
|
|
35749
|
-
if (!this.isClickToAddPoints()) {
|
|
35750
|
-
// Polygons can't have consecutive collinear points
|
|
35751
|
-
if (collinear(coords[rel(-2)], coords[rel(-1)], coords[i]) || collinear(coords[rel(-1)], coords[i], coords[rel(1)]) || collinear(coords[i], coords[rel(1)], coords[rel(2)])) {
|
|
35752
|
-
return false;
|
|
35753
|
-
}
|
|
35754
|
-
const segments = _.zip(coords, rotate(coords));
|
|
35755
|
-
if (this.points.length > 3) {
|
|
35756
|
-
// Constrain to simple (non self-intersecting) polygon by
|
|
35757
|
-
// testing whether adjacent segments intersect any others
|
|
35758
|
-
for (let j = -1; j <= 0; j++) {
|
|
35759
|
-
const segment = segments[rel(j)];
|
|
35760
|
-
const others = _.without(segments, segment, segments[rel(j - 1)], segments[rel(j + 1)]);
|
|
35761
|
-
for (let k = 0; k < others.length; k++) {
|
|
35762
|
-
const other = others[k];
|
|
35763
|
-
// @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Line'.
|
|
35764
|
-
if (intersects(segment, other)) {
|
|
35765
|
-
return false;
|
|
35766
|
-
}
|
|
35767
|
-
}
|
|
35768
|
-
}
|
|
35769
|
-
}
|
|
35770
|
-
}
|
|
35771
|
-
if (
|
|
35772
|
-
// @ts-expect-error - TS2339 - Property 'snapTo' does not exist on type 'PerseusGraphType'.
|
|
35773
|
-
this.props.graph.snapTo === "angles" && this.points.length > 2) {
|
|
35774
|
-
var _this$graphie5;
|
|
35775
|
-
// Snap to whole degree interior angles
|
|
35776
|
-
|
|
35777
|
-
const angles = _.map(angleMeasures(coords), function (rad) {
|
|
35778
|
-
return rad * 180 / Math.PI;
|
|
35779
|
-
});
|
|
35780
|
-
_.each([-1, 1], function (j) {
|
|
35781
|
-
angles[rel(j)] = Math.round(angles[rel(j)]);
|
|
35782
|
-
});
|
|
35783
|
-
const getAngle = function getAngle(a, vertex, b) {
|
|
35784
|
-
const angle = GraphUtils.findAngleDeprecated(coords[rel(a)], coords[rel(b)], coords[rel(vertex)]);
|
|
35785
|
-
return (angle + 360) % 360;
|
|
35786
|
-
};
|
|
35787
|
-
const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
|
|
35788
|
-
innerAngles[2] = 180 - (innerAngles[0] + innerAngles[1]);
|
|
35789
|
-
|
|
35790
|
-
// Avoid degenerate triangles
|
|
35791
|
-
if (_.any(innerAngles, function (angle) {
|
|
35792
|
-
return leq(angle, 1);
|
|
35793
|
-
})) {
|
|
35794
|
-
return false;
|
|
35795
|
-
}
|
|
35796
|
-
const knownSide = magnitude(
|
|
35797
|
-
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'.
|
|
35798
|
-
vector(coords[rel(-1)], coords[rel(1)]));
|
|
35799
|
-
const onLeft = sign(ccw(coords[rel(-1)], coords[rel(1)], coords[i])) === 1;
|
|
35800
|
-
|
|
35801
|
-
// Solve for side by using the law of sines
|
|
35802
|
-
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
35803
|
-
const outerAngle = GraphUtils.findAngleDeprecated(coords[rel(1)], coords[rel(-1)]);
|
|
35804
|
-
const offset = polar$2(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
35805
|
-
return (_this$graphie5 = this.graphie) == null ? void 0 : _this$graphie5.addPoints(coords[rel(-1)], offset);
|
|
35806
|
-
}
|
|
35807
|
-
// @ts-expect-error - TS2339 - Property 'snapTo' does not exist on type 'PerseusGraphType'.
|
|
35808
|
-
if (this.props.graph.snapTo === "sides" && this.points.length > 1) {
|
|
35809
|
-
var _this$graphie6;
|
|
35810
|
-
// Snap to whole unit side measures
|
|
35811
|
-
|
|
35812
|
-
const sides = _.map([[coords[rel(-1)], coords[i]], [coords[i], coords[rel(1)]], [coords[rel(-1)], coords[rel(1)]]], function (coords) {
|
|
35813
|
-
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
35814
|
-
return magnitude(vector(...coords));
|
|
35815
|
-
});
|
|
35816
|
-
_.each([0, 1], function (j) {
|
|
35817
|
-
sides[j] = Math.round(sides[j]);
|
|
35818
|
-
});
|
|
35819
|
-
|
|
35820
|
-
// Avoid degenerate triangles
|
|
35821
|
-
if (leq(sides[1] + sides[2], sides[0]) || leq(sides[0] + sides[2], sides[1]) || leq(sides[0] + sides[1], sides[2])) {
|
|
35822
|
-
return false;
|
|
35823
|
-
}
|
|
35824
|
-
|
|
35825
|
-
// Solve for angle by using the law of cosines
|
|
35826
|
-
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
35827
|
-
const outerAngle = GraphUtils.findAngleDeprecated(coords[rel(1)], coords[rel(-1)]);
|
|
35828
|
-
const onLeft = sign(ccw(coords[rel(-1)], coords[rel(1)], coords[i])) === 1;
|
|
35829
|
-
const offset = polar$2(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
|
|
35830
|
-
return (_this$graphie6 = this.graphie) == null ? void 0 : _this$graphie6.addPoints(coords[rel(-1)], offset);
|
|
35831
|
-
}
|
|
35832
|
-
// Snap to grid (already done)
|
|
35833
|
-
return true;
|
|
35834
|
-
};
|
|
35835
|
-
const point$1 = Interactive2.addMaybeMobileMovablePoint(this, _extends({
|
|
35836
|
-
coord: coord,
|
|
35837
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), snapToGrid ? Interactive2.MovablePoint.constraints.snap() : null, graphConstraint],
|
|
35838
|
-
onMoveStart: () => {
|
|
35839
|
-
if (this.isClickToAddPoints()) {
|
|
35840
|
-
this.setTrashCanVisibility(1);
|
|
35841
|
-
}
|
|
35842
|
-
},
|
|
35843
|
-
onMove: () => {
|
|
35844
|
-
var _this$polygon10;
|
|
35845
|
-
if ((_this$polygon10 = this.polygon) != null && _this$polygon10.closed()) {
|
|
35846
|
-
this.updateCoordsFromPoints();
|
|
35847
|
-
}
|
|
35848
|
-
},
|
|
35849
|
-
onMoveEnd: onMoveEndHandler
|
|
35850
|
-
}, this.props.apiOptions.isMobile && this.isClickToAddPoints() ? {
|
|
35851
|
-
onRemove: remove
|
|
35852
|
-
} : {}));
|
|
35853
|
-
point$1.state.isInitialMove = true;
|
|
35854
|
-
return point$1;
|
|
35855
|
-
};
|
|
35856
|
-
this.updateCoordsFromPoints = () => {
|
|
35857
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35858
|
-
// Handle old movable points with .coord, or
|
|
35859
|
-
// Interactive2.MovablePoint's with .coord()
|
|
35860
|
-
coords: _.map(this.points, function (point) {
|
|
35861
|
-
return _.result(point, "coord");
|
|
35862
|
-
})
|
|
35863
|
-
});
|
|
35864
|
-
this.onChange({
|
|
35865
|
-
graph: graph
|
|
35866
|
-
});
|
|
35867
|
-
};
|
|
35868
|
-
this.clearCoords = () => {
|
|
35869
|
-
const graph = _.extend({}, this.props.graph, {
|
|
35870
|
-
coords: null
|
|
35871
|
-
});
|
|
35872
|
-
this.onChange({
|
|
35873
|
-
graph: graph
|
|
35874
|
-
});
|
|
35875
|
-
};
|
|
35876
|
-
this.onChange = data => {
|
|
35877
|
-
this.props.onChange(data);
|
|
35878
|
-
this.props.trackInteraction();
|
|
35879
|
-
};
|
|
35880
|
-
this.addPointControls = () => {
|
|
35881
|
-
if (this.props.graph.type !== "point") {
|
|
35882
|
-
throw makeInvalidTypeError("addPointControls", "point");
|
|
35883
|
-
}
|
|
35884
|
-
const coords = InteractiveGraph.getPointCoords(this.props.graph, this.props);
|
|
35885
|
-
// Clear out our old points so that newly added points don't
|
|
35886
|
-
// "collide" with them and reposition when being added
|
|
35887
|
-
// Without this, when added, each point checks whether it is on top
|
|
35888
|
-
// of a point in this.points, which (a) shouldn't matter since
|
|
35889
|
-
// we're clearing out this.points anyways, and (b) can cause problems
|
|
35890
|
-
// if each of this.points is a MovablePoint instead of an
|
|
35891
|
-
// Interactive2.MovablePoint, since one has a .coord and the other
|
|
35892
|
-
// has .coord()
|
|
35893
|
-
// TODO(jack): Figure out a better way to do this
|
|
35894
|
-
this.points = [];
|
|
35895
|
-
this.points = _.map(coords, this.createPointForPointsType, this);
|
|
35896
|
-
};
|
|
35897
|
-
this.removePointControls = () => {
|
|
35898
|
-
_.invoke(this.points, "remove");
|
|
35899
|
-
};
|
|
35900
|
-
this.addSegmentControls = () => {
|
|
35901
|
-
if (this.props.graph.type !== "segment") {
|
|
35902
|
-
throw makeInvalidTypeError("addSegmentControls", "segment");
|
|
35903
|
-
}
|
|
35904
|
-
const self = this;
|
|
35905
|
-
const graphie = this.graphie;
|
|
35906
|
-
const coords = InteractiveGraph.getSegmentCoords(this.props.graph, this.props);
|
|
35907
|
-
const createPoint = options => Interactive2.addMaybeMobileMovablePoint(this, options);
|
|
35908
|
-
this.points = [];
|
|
35909
|
-
this.lines = _.map(coords, function (segment, i) {
|
|
35910
|
-
const updateCoordProps = function updateCoordProps() {
|
|
35911
|
-
const graph = _.extend({}, self.props.graph, {
|
|
35912
|
-
// @ts-expect-error - TS2345 - Argument of type 'readonly (readonly Coord[])[] | null | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
35913
|
-
coords: _.invoke(self.lines, "coords")
|
|
35914
|
-
});
|
|
35915
|
-
self.onChange({
|
|
35916
|
-
graph: graph
|
|
35917
|
-
});
|
|
35918
|
-
};
|
|
35919
|
-
|
|
35920
|
-
// NOTE(jeresig): This code attempts to access the variable
|
|
35921
|
-
// while it's still being defined, it should be refactored!
|
|
35922
|
-
// The callbacks appear to be executed synchronously, which
|
|
35923
|
-
// causes this issue.
|
|
35924
|
-
const points = [];
|
|
35925
|
-
for (let _i = 0; _i < segment.length; _i += 1) {
|
|
35926
|
-
const coord = segment[_i];
|
|
35927
|
-
points.push(createPoint({
|
|
35928
|
-
coord: coord,
|
|
35929
|
-
constraints: [Interactive2.MovablePoint.constraints.bound(), Interactive2.MovablePoint.constraints.snap(), coord => {
|
|
35930
|
-
const otherPoint = points[1 - _i];
|
|
35931
|
-
if (!otherPoint) {
|
|
35932
|
-
// point hasn't been defined yet
|
|
35933
|
-
// because we're still creating them
|
|
35934
|
-
// We return false as the points aren't
|
|
35935
|
-
// going to be in the same position at
|
|
35936
|
-
// this point.
|
|
35937
|
-
return false;
|
|
35938
|
-
}
|
|
35939
|
-
return !point.equal(coord, otherPoint.coord());
|
|
35940
|
-
}],
|
|
35941
|
-
onMove: updateCoordProps
|
|
35942
|
-
}));
|
|
35943
|
-
}
|
|
35944
|
-
self.points = self.points.concat(points);
|
|
35945
|
-
const line = Interactive2.addMovableLine(graphie, {
|
|
35946
|
-
points: points,
|
|
35947
|
-
static: false,
|
|
35948
|
-
constraints: [
|
|
35949
|
-
// @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
35950
|
-
Interactive2.MovableLine.constraints.bound(),
|
|
35951
|
-
// @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
35952
|
-
Interactive2.MovableLine.constraints.snap()],
|
|
35953
|
-
onMove: [
|
|
35954
|
-
// @ts-expect-error - TS2339 - Property 'onMove' does not exist on type '(graphie: any, movable: any, options: any) => void'.
|
|
35955
|
-
Interactive2.MovableLine.onMove.updatePoints, updateCoordProps],
|
|
35956
|
-
normalStyle: _extends({
|
|
35957
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
35958
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.INTERACTIVE
|
|
35959
|
-
}, this._lineStroke()),
|
|
35960
|
-
highlightStyle: _extends({
|
|
35961
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
35962
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.INTERACTING
|
|
35963
|
-
}, this._lineStroke())
|
|
35964
|
-
});
|
|
35965
|
-
_.invoke(points, "toFront");
|
|
35966
|
-
return line;
|
|
35967
|
-
}, this);
|
|
35968
|
-
};
|
|
35969
|
-
this.removeSegmentControls = () => {
|
|
35970
|
-
_.invoke(this.points, "remove");
|
|
35971
|
-
// @ts-expect-error - TS2345 - Argument of type 'readonly (readonly Coord[])[] | null | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
35972
|
-
_.invoke(this.lines, "remove");
|
|
35973
|
-
};
|
|
35974
|
-
this.addRayControls = () => {
|
|
35975
|
-
this.addLine("ray");
|
|
35976
|
-
};
|
|
35977
|
-
this.removeRayControls = () => {
|
|
35978
|
-
this.removeLine();
|
|
35979
|
-
};
|
|
35980
|
-
this.addPolygonControls = () => {
|
|
35981
|
-
this.polygon = null;
|
|
35982
|
-
const coords = InteractiveGraph.getPolygonCoords(this.props.graph, this.props);
|
|
35983
|
-
// Clear out our old points so that newly added points don't
|
|
35984
|
-
// "collide", as in `addPointControls`
|
|
35985
|
-
this.points = [];
|
|
35986
|
-
this.points = _.map(coords, this.createPointForPolygonType, this);
|
|
35987
|
-
this.updatePolygon();
|
|
35988
|
-
};
|
|
35989
|
-
this.updatePolygon = () => {
|
|
35990
|
-
if (this.props.graph.type !== "polygon") {
|
|
35991
|
-
throw makeInvalidTypeError("updatePolygon", "polygon");
|
|
35992
|
-
}
|
|
35993
|
-
let closed;
|
|
35994
|
-
if (this.polygon) {
|
|
35995
|
-
closed = this.polygon.closed();
|
|
35996
|
-
} else if (this.points.length >= 3) {
|
|
35997
|
-
closed = true;
|
|
35998
|
-
} else {
|
|
35999
|
-
// There will only be fewer than 3 points in click-to-add-vertices
|
|
36000
|
-
// mode, so we don't need to explicitly check for that here.
|
|
36001
|
-
closed = false;
|
|
36002
|
-
}
|
|
36003
|
-
const graphie = this.graphie;
|
|
36004
|
-
const n = this.points.length;
|
|
36005
|
-
|
|
36006
|
-
// TODO(alex): check against "grid" instead, use constants
|
|
36007
|
-
const snapToGrid = !_.contains(["angles", "sides"], this.props.graph.snapTo);
|
|
36008
|
-
const angleLabels = _.times(n, function (i) {
|
|
36009
|
-
if (
|
|
36010
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36011
|
-
!this.props.graph.showAngles || !closed && (i === 0 || i === n - 1)) {
|
|
36012
|
-
return "";
|
|
36013
|
-
}
|
|
36014
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36015
|
-
if (this.props.graph.snapTo === "angles") {
|
|
36016
|
-
return "$deg0";
|
|
36017
|
-
}
|
|
36018
|
-
return "$deg1";
|
|
36019
|
-
}, this);
|
|
36020
|
-
const showRightAngleMarkers = _.times(n, function (i) {
|
|
36021
|
-
return closed || i !== 0 && i !== n - 1;
|
|
36022
|
-
}, this);
|
|
36023
|
-
const numArcs = _.times(n, function (i) {
|
|
36024
|
-
if (
|
|
36025
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36026
|
-
this.props.graph.showAngles && (closed || i !== 0 && i !== n - 1)) {
|
|
36027
|
-
return 1;
|
|
36028
|
-
}
|
|
36029
|
-
return 0;
|
|
36030
|
-
}, this);
|
|
36031
|
-
const sideLabels = _.times(n, function (i) {
|
|
36032
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36033
|
-
if (!this.props.graph.showSides || !closed && i === n - 1) {
|
|
36034
|
-
return "";
|
|
36035
|
-
}
|
|
36036
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36037
|
-
if (this.props.graph.snapTo === "sides") {
|
|
36038
|
-
return "$len0";
|
|
36039
|
-
}
|
|
36040
|
-
return "$len1";
|
|
36041
|
-
}, this);
|
|
36042
|
-
if (this.polygon == null) {
|
|
36043
|
-
const self = this;
|
|
36044
|
-
self.polygon = Interactive2.addMovablePolygon(graphie, {
|
|
36045
|
-
constraints: [
|
|
36046
|
-
// @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => undefined'.
|
|
36047
|
-
Interactive2.MovablePolygon.constraints.bound(), snapToGrid ?
|
|
36048
|
-
// @ts-expect-error - TS2339 - Property 'constraints' does not exist on type '(graphie: any, movable: any, options: any) => undefined'.
|
|
36049
|
-
Interactive2.MovablePolygon.constraints.snap() : null],
|
|
36050
|
-
closed: closed,
|
|
36051
|
-
points: self.points,
|
|
36052
|
-
angleLabels: angleLabels,
|
|
36053
|
-
showRightAngleMarkers: showRightAngleMarkers,
|
|
36054
|
-
numArcs: numArcs,
|
|
36055
|
-
sideLabels: sideLabels,
|
|
36056
|
-
onMove: [
|
|
36057
|
-
// @ts-expect-error - TS2339 - Property 'onMove' does not exist on type '(graphie: any, movable: any, options: any) => undefined'.
|
|
36058
|
-
Interactive2.MovablePolygon.onMove.updatePoints, function () {
|
|
36059
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
36060
|
-
if (this.closed()) {
|
|
36061
|
-
self.updateCoordsFromPoints();
|
|
36062
|
-
}
|
|
36063
|
-
}],
|
|
36064
|
-
normalStyle: _extends({
|
|
36065
|
-
stroke: this.props.apiOptions.isMobile ? KhanColors.BLUE_C : KhanColors.INTERACTIVE
|
|
36066
|
-
}, this._lineStroke())
|
|
36067
|
-
});
|
|
36068
|
-
} else {
|
|
36069
|
-
// We only need to pass in the properties that might've changed
|
|
36070
|
-
this.polygon.update({
|
|
36071
|
-
closed: closed,
|
|
36072
|
-
points: this.points,
|
|
36073
|
-
angleLabels: angleLabels,
|
|
36074
|
-
showRightAngleMarkers: showRightAngleMarkers,
|
|
36075
|
-
numArcs: numArcs,
|
|
36076
|
-
sideLabels: sideLabels
|
|
36077
|
-
});
|
|
36078
|
-
}
|
|
36079
|
-
};
|
|
36080
|
-
this.removePolygonControls = () => {
|
|
36081
|
-
var _this$polygon11;
|
|
36082
|
-
_.invoke(this.points, "remove");
|
|
36083
|
-
(_this$polygon11 = this.polygon) == null || _this$polygon11.remove();
|
|
36084
|
-
};
|
|
36085
|
-
this.addAngleControls = () => {
|
|
36086
|
-
if (this.props.graph.type !== "angle") {
|
|
36087
|
-
throw makeInvalidTypeError("addAngleControls", "angle");
|
|
36088
|
-
}
|
|
36089
|
-
const graph = this.props.graph;
|
|
36090
|
-
const graphie = this.graphie;
|
|
36091
|
-
const coords = InteractiveGraph.getAngleCoords(this.props.graph, this.props);
|
|
36092
|
-
|
|
36093
|
-
// The vertex snaps to the grid, but the rays don't...
|
|
36094
|
-
this.points = coords.map(function (coord, i) {
|
|
36095
|
-
return graphie == null ? void 0 : graphie.addMovablePoint(_.extend({
|
|
36096
|
-
coord: coord,
|
|
36097
|
-
normalStyle: {
|
|
36098
|
-
stroke: KhanColors.INTERACTIVE,
|
|
36099
|
-
fill: KhanColors.INTERACTIVE
|
|
36100
|
-
}
|
|
36101
|
-
}, i === 1 ? {
|
|
36102
|
-
snapX: graphie.snap[0],
|
|
36103
|
-
snapY: graphie.snap[1]
|
|
36104
|
-
} : {}));
|
|
36105
|
-
});
|
|
36106
|
-
|
|
36107
|
-
// ...they snap to whole-degree angles from the vertex.
|
|
36108
|
-
this.angle = graphie == null ? void 0 : graphie.addMovableAngle({
|
|
36109
|
-
points: this.points,
|
|
36110
|
-
snapDegrees: graph.snapDegrees || 1,
|
|
36111
|
-
snapOffsetDeg: graph.angleOffsetDeg || 0,
|
|
36112
|
-
angleLabel: graph.showAngles ? "$deg0" : "",
|
|
36113
|
-
pushOut: 2,
|
|
36114
|
-
allowReflex: defaultVal(graph.allowReflexAngles, true)
|
|
36115
|
-
});
|
|
36116
|
-
$(this.angle).on("move", () => {
|
|
36117
|
-
var _this$angle;
|
|
36118
|
-
this.onChange({
|
|
36119
|
-
graph: _extends({}, graph, {
|
|
36120
|
-
coords: (_this$angle = this.angle) == null ? void 0 : _this$angle.getClockwiseCoords()
|
|
36121
|
-
})
|
|
36122
|
-
});
|
|
36123
|
-
});
|
|
36124
|
-
};
|
|
36125
|
-
this.removeAngleControls = () => {
|
|
36126
|
-
var _this$angle2;
|
|
36127
|
-
_.invoke(this.points, "remove");
|
|
36128
|
-
(_this$angle2 = this.angle) == null || _this$angle2.remove();
|
|
36129
|
-
};
|
|
36130
|
-
this.toggleShowSides = () => {
|
|
36131
|
-
if (this.props.graph.type !== "polygon") {
|
|
36132
|
-
throw makeInvalidTypeError("toggleShowSides", "polygon");
|
|
36133
|
-
}
|
|
36134
|
-
const graph = _.extend({}, this.props.graph, {
|
|
36135
|
-
showSides: !this.props.graph.showSides
|
|
36136
|
-
});
|
|
36137
|
-
this.onChange({
|
|
36138
|
-
graph: graph
|
|
36139
|
-
});
|
|
36140
|
-
};
|
|
36141
|
-
this.focus = $.noop;
|
|
36142
|
-
}
|
|
36143
|
-
componentDidMount() {
|
|
36144
|
-
if (this.refs.graph) {
|
|
36145
|
-
// eslint-disable-next-line react/no-string-refs
|
|
36146
|
-
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
|
|
36147
|
-
this.setGraphie(this.refs.graph.graphie());
|
|
36148
|
-
}
|
|
36149
|
-
}
|
|
36150
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
36151
|
-
var _this$props$backgroun, _nextProps$background;
|
|
36152
|
-
if (this.isClickToAddPoints() !== this.isClickToAddPoints(nextProps)) {
|
|
36153
|
-
this.shouldResetGraphie = true;
|
|
36154
|
-
this.setState({
|
|
36155
|
-
shouldShowInstructions: _getShouldShowInstructions(nextProps)
|
|
36156
|
-
});
|
|
36157
|
-
}
|
|
36158
|
-
if (((_this$props$backgroun = this.props.backgroundImage) == null ? void 0 : _this$props$backgroun.url) !== ((_nextProps$background = nextProps.backgroundImage) == null ? void 0 : _nextProps$background.url) || this.props.backgroundImage !== nextProps.backgroundImage || this.props.containerSizeClass !== nextProps.containerSizeClass) {
|
|
36159
|
-
this.shouldResetGraphie = true;
|
|
36160
|
-
}
|
|
36161
|
-
}
|
|
36162
|
-
componentDidUpdate(prevProps, prevState) {
|
|
36163
|
-
// TODO(jeremy): This feels underspecified. For example, if the props
|
|
36164
|
-
// change the coords of a segment graph, but not the numSegments, we'd
|
|
36165
|
-
// not count that as an update.
|
|
36166
|
-
const oldType = prevProps.graph.type;
|
|
36167
|
-
const newType = this.props.graph.type;
|
|
36168
|
-
if (oldType !== newType || prevProps.graph.type === "angle" && this.props.graph.type === "angle" && this.areAngleGraphsEqual(prevProps.graph, this.props.graph) || prevProps.graph.type === "point" && this.props.graph.type === "point" && this.arePointGraphsEqual(prevProps.graph, this.props.graph) || prevProps.graph.type === "polygon" && this.props.graph.type === "polygon" && this.arePolygonGraphsEqual(prevProps.graph, this.props.graph) || prevProps.graph.type === "segment" && this.props.graph.type === "segment" && this.areSegmentGraphsEqual(prevProps.graph, this.props.graph)) {
|
|
36169
|
-
this["remove" + capitalize(oldType) + "Controls"]();
|
|
36170
|
-
this["add" + capitalize(newType) + "Controls"]();
|
|
36171
|
-
}
|
|
36172
|
-
if (this.shouldResetGraphie) {
|
|
36173
|
-
this.resetGraphie();
|
|
36174
|
-
}
|
|
36175
|
-
}
|
|
36176
|
-
areAngleGraphsEqual(prevGraph, currentGraph) {
|
|
36177
|
-
return prevGraph.allowReflexAngles !== currentGraph.allowReflexAngles || prevGraph.angleOffsetDeg !== currentGraph.angleOffsetDeg || prevGraph.snapDegrees !== currentGraph.snapDegrees;
|
|
36178
|
-
}
|
|
36179
|
-
arePointGraphsEqual(prevGraph, currentGraph) {
|
|
36180
|
-
return prevGraph.numPoints !== currentGraph.numPoints;
|
|
36181
|
-
}
|
|
36182
|
-
arePolygonGraphsEqual(prevGraph, currentGraph) {
|
|
36183
|
-
return prevGraph.numSides !== currentGraph.numSides || prevGraph.showAngles !== currentGraph.showAngles || prevGraph.showSides !== currentGraph.showSides || prevGraph.snapTo !== currentGraph.snapTo;
|
|
36184
|
-
}
|
|
36185
|
-
areSegmentGraphsEqual(prevGraph, currentGraph) {
|
|
36186
|
-
return prevGraph.numSegments !== currentGraph.numSegments;
|
|
36187
|
-
}
|
|
36188
|
-
getUserInput() {
|
|
36189
|
-
return InteractiveGraph.getUserInputFromProps(this.props);
|
|
36190
|
-
}
|
|
36191
|
-
render() {
|
|
36192
|
-
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
36193
|
-
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
36194
|
-
const snapStep = this.props.snapStep || Util.snapStepFromGridStep(gridStep);
|
|
36195
|
-
let instructions;
|
|
36196
|
-
// isClickToAddPoints() only applies to points and polygons
|
|
36197
|
-
if (this.isClickToAddPoints() && this.state.shouldShowInstructions) {
|
|
36198
|
-
if (this.props.graph.type === "point") {
|
|
36199
|
-
instructions = this.context.strings.addPoints;
|
|
36200
|
-
} else if (this.props.graph.type === "polygon") {
|
|
36201
|
-
instructions = this.context.strings.addVertices;
|
|
36202
|
-
}
|
|
36203
|
-
} else {
|
|
36204
|
-
instructions = undefined;
|
|
36205
|
-
}
|
|
36206
|
-
let onMouseDown;
|
|
36207
|
-
if (this.isClickToAddPoints()) {
|
|
36208
|
-
onMouseDown = this.handleAddPointsMouseDown;
|
|
36209
|
-
}
|
|
36210
|
-
const isMobile = this.props.apiOptions.isMobile;
|
|
36211
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
36212
|
-
className: "perseus-widget " + "perseus-widget-interactive-graph",
|
|
36213
|
-
style: {
|
|
36214
|
-
width: box[0],
|
|
36215
|
-
height: box[1]
|
|
36216
|
-
}
|
|
36217
|
-
}, /*#__PURE__*/React.createElement(Graph, {
|
|
36218
|
-
instructions: instructions
|
|
36219
|
-
// eslint-disable-next-line react/no-string-refs
|
|
36220
|
-
,
|
|
36221
|
-
ref: "graph",
|
|
36222
|
-
box: box,
|
|
36223
|
-
labels: this.props.labels,
|
|
36224
|
-
range: this.props.range,
|
|
36225
|
-
step: isMobile ? Util.constrainedTickStepsFromTickSteps(this.props.step, this.props.range) : this.props.step,
|
|
36226
|
-
gridStep: gridStep,
|
|
36227
|
-
snapStep: snapStep,
|
|
36228
|
-
markings: this.props.markings,
|
|
36229
|
-
backgroundImage: this.props.backgroundImage,
|
|
36230
|
-
showProtractor: this.props.showProtractor,
|
|
36231
|
-
onMouseDown: onMouseDown,
|
|
36232
|
-
onGraphieUpdated: this.setGraphie,
|
|
36233
|
-
setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable,
|
|
36234
|
-
isMobile: isMobile
|
|
36235
|
-
}));
|
|
36236
|
-
}
|
|
36237
|
-
}
|
|
36238
|
-
LegacyInteractiveGraph.contextType = PerseusI18nContext;
|
|
36239
|
-
LegacyInteractiveGraph.defaultProps = {
|
|
36240
|
-
labels: ["x", "y"],
|
|
36241
|
-
range: [[-10, 10], [-10, 10]],
|
|
36242
|
-
step: [1, 1],
|
|
36243
|
-
backgroundImage: defaultBackgroundImage,
|
|
36244
|
-
markings: "graph",
|
|
36245
|
-
showTooltips: false,
|
|
36246
|
-
showProtractor: false,
|
|
36247
|
-
graph: {
|
|
36248
|
-
type: "linear"
|
|
36249
|
-
}
|
|
36250
|
-
};
|
|
36251
34940
|
class InteractiveGraph extends React.Component {
|
|
36252
34941
|
constructor(...args) {
|
|
36253
34942
|
super(...args);
|
|
36254
|
-
this.legacyGraphRef = /*#__PURE__*/React.createRef();
|
|
36255
34943
|
this.mafsRef = /*#__PURE__*/React.createRef();
|
|
36256
34944
|
}
|
|
36257
34945
|
getUserInput() {
|
|
36258
|
-
var _this$mafsRef$current
|
|
34946
|
+
var _this$mafsRef$current;
|
|
36259
34947
|
if ((_this$mafsRef$current = this.mafsRef.current) != null && _this$mafsRef$current.getUserInput) {
|
|
36260
34948
|
return this.mafsRef.current.getUserInput();
|
|
36261
34949
|
}
|
|
36262
|
-
if ((_this$legacyGraphRef$ = this.legacyGraphRef.current) != null && _this$legacyGraphRef$.getUserInput) {
|
|
36263
|
-
return this.legacyGraphRef.current.getUserInput();
|
|
36264
|
-
}
|
|
36265
34950
|
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
36266
34951
|
}
|
|
36267
34952
|
getPromptJSON() {
|
|
@@ -36456,8 +35141,32 @@ class InteractiveGraph extends React.Component {
|
|
|
36456
35141
|
}
|
|
36457
35142
|
static getEquationString(props) {
|
|
36458
35143
|
const type = props.graph.type;
|
|
36459
|
-
|
|
36460
|
-
|
|
35144
|
+
switch (type) {
|
|
35145
|
+
case "none":
|
|
35146
|
+
return InteractiveGraph.getNoneEquationString();
|
|
35147
|
+
case "linear":
|
|
35148
|
+
return InteractiveGraph.getLinearEquationString(props);
|
|
35149
|
+
case "quadratic":
|
|
35150
|
+
return InteractiveGraph.getQuadraticEquationString(props);
|
|
35151
|
+
case "sinusoid":
|
|
35152
|
+
return InteractiveGraph.getSinusoidEquationString(props);
|
|
35153
|
+
case "circle":
|
|
35154
|
+
return InteractiveGraph.getCircleEquationString(props);
|
|
35155
|
+
case "linear-system":
|
|
35156
|
+
return InteractiveGraph.getLinearSystemEquationString(props);
|
|
35157
|
+
case "point":
|
|
35158
|
+
return InteractiveGraph.getPointEquationString(props);
|
|
35159
|
+
case "segment":
|
|
35160
|
+
return InteractiveGraph.getSegmentEquationString(props);
|
|
35161
|
+
case "ray":
|
|
35162
|
+
return InteractiveGraph.getRayEquationString(props);
|
|
35163
|
+
case "polygon":
|
|
35164
|
+
return InteractiveGraph.getPolygonEquationString(props);
|
|
35165
|
+
case "angle":
|
|
35166
|
+
return InteractiveGraph.getAngleEquationString(props);
|
|
35167
|
+
default:
|
|
35168
|
+
throw new UnreachableCaseError(type);
|
|
35169
|
+
}
|
|
36461
35170
|
}
|
|
36462
35171
|
static pointsFromNormalized(props, coordsList, noSnap) {
|
|
36463
35172
|
// @ts-expect-error - TS2322 - Type 'number[][]' is not assignable to type 'readonly Coord[]'.
|
|
@@ -36613,8 +35322,7 @@ var InteractiveGraph$1 = {
|
|
|
36613
35322
|
name: "interactive-graph",
|
|
36614
35323
|
displayName: "Interactive graph (Assessments only)",
|
|
36615
35324
|
widget: InteractiveGraph,
|
|
36616
|
-
staticTransform: staticTransform$3
|
|
36617
|
-
getPublicWidgetOptions: getInteractiveGraphPublicWidgetOptions
|
|
35325
|
+
staticTransform: staticTransform$3
|
|
36618
35326
|
};
|
|
36619
35327
|
|
|
36620
35328
|
// TODO: can we use WB typography?
|
|
@@ -37241,11 +35949,16 @@ class LabelImage extends React.Component {
|
|
|
37241
35949
|
});
|
|
37242
35950
|
}
|
|
37243
35951
|
activateMarker(index, opened) {
|
|
37244
|
-
var _this$props$analytics;
|
|
35952
|
+
var _this$props$analytics, _this$props$analytics2;
|
|
35953
|
+
// TODO(LEMS-2830): Remove analytics event in LEMS-2830 in favor of ti below.
|
|
37245
35954
|
(_this$props$analytics = this.props.analytics) == null || _this$props$analytics.onAnalyticsEvent({
|
|
37246
35955
|
type: "perseus:label-image:marker-interacted-with",
|
|
37247
35956
|
payload: null
|
|
37248
35957
|
});
|
|
35958
|
+
(_this$props$analytics2 = this.props.analytics) == null || _this$props$analytics2.onAnalyticsEvent({
|
|
35959
|
+
type: "perseus:label-image:marker-interacted-with:ti",
|
|
35960
|
+
payload: null
|
|
35961
|
+
});
|
|
37249
35962
|
const {
|
|
37250
35963
|
activeMarkerIndex
|
|
37251
35964
|
} = this.state;
|
|
@@ -37388,11 +36101,16 @@ class LabelImage extends React.Component {
|
|
|
37388
36101
|
})),
|
|
37389
36102
|
multipleSelect: this.props.multipleAnswers,
|
|
37390
36103
|
onChange: selection => {
|
|
37391
|
-
var _this$props$
|
|
37392
|
-
(
|
|
36104
|
+
var _this$props$analytics3, _this$props$analytics4;
|
|
36105
|
+
// TODO(LEMS-2829): Remove analytics event in LEMS-2829 in favor of ti below.
|
|
36106
|
+
(_this$props$analytics3 = this.props.analytics) == null || _this$props$analytics3.onAnalyticsEvent({
|
|
37393
36107
|
type: "perseus:label-image:choiced-interacted-with",
|
|
37394
36108
|
payload: null
|
|
37395
36109
|
});
|
|
36110
|
+
(_this$props$analytics4 = this.props.analytics) == null || _this$props$analytics4.onAnalyticsEvent({
|
|
36111
|
+
type: "perseus:label-image:choiced-interacted-with:ti",
|
|
36112
|
+
payload: null
|
|
36113
|
+
});
|
|
37396
36114
|
this.handleAnswerChoicesChangeForMarker(index, selection);
|
|
37397
36115
|
},
|
|
37398
36116
|
onToggle: opened => this.activateMarker(index, opened)
|
|
@@ -37488,11 +36206,16 @@ class LabelImage extends React.Component {
|
|
|
37488
36206
|
}))), this.renderMarkers()), /*#__PURE__*/React.createElement(HideAnswersToggle, {
|
|
37489
36207
|
areAnswersHidden: this.state.hideAnswers,
|
|
37490
36208
|
onChange: hideAnswers => {
|
|
37491
|
-
var _this$props$
|
|
37492
|
-
(
|
|
36209
|
+
var _this$props$analytics5, _this$props$analytics6;
|
|
36210
|
+
// TODO(LEMS-2831): Remove analytics event in LEMS-2831 in favor of ti below.
|
|
36211
|
+
(_this$props$analytics5 = this.props.analytics) == null || _this$props$analytics5.onAnalyticsEvent({
|
|
37493
36212
|
type: "perseus:label-image:toggle-answers-hidden",
|
|
37494
36213
|
payload: null
|
|
37495
36214
|
});
|
|
36215
|
+
(_this$props$analytics6 = this.props.analytics) == null || _this$props$analytics6.onAnalyticsEvent({
|
|
36216
|
+
type: "perseus:label-image:toggle-answers-hidden:ti",
|
|
36217
|
+
payload: null
|
|
36218
|
+
});
|
|
37496
36219
|
this.setState({
|
|
37497
36220
|
hideAnswers
|
|
37498
36221
|
});
|
|
@@ -37555,8 +36278,7 @@ var LabelImage$1 = {
|
|
|
37555
36278
|
displayName: "Label Image",
|
|
37556
36279
|
widget: LabelImageWithDependencies,
|
|
37557
36280
|
accessible: true,
|
|
37558
|
-
isLintable: true
|
|
37559
|
-
getPublicWidgetOptions: getLabelImagePublicWidgetOptions
|
|
36281
|
+
isLintable: true
|
|
37560
36282
|
};
|
|
37561
36283
|
|
|
37562
36284
|
var ItemState = /*#__PURE__*/function (ItemState) {
|
|
@@ -37811,20 +36533,24 @@ class Draggable extends React.Component {
|
|
|
37811
36533
|
if (this.props.margin != null) {
|
|
37812
36534
|
style.margin = this.props.margin;
|
|
37813
36535
|
}
|
|
37814
|
-
return
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37827
|
-
|
|
36536
|
+
return (
|
|
36537
|
+
/*#__PURE__*/
|
|
36538
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
36539
|
+
React.createElement("li", {
|
|
36540
|
+
className: className,
|
|
36541
|
+
style: style,
|
|
36542
|
+
onMouseDown: this.onMouseDown,
|
|
36543
|
+
onTouchStart: this.onMouseDown,
|
|
36544
|
+
onTouchMove: this.onMouseMove,
|
|
36545
|
+
onTouchEnd: this.onMouseUp,
|
|
36546
|
+
onTouchCancel: this.onMouseUp
|
|
36547
|
+
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
36548
|
+
content: this.props.content,
|
|
36549
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "draggable"),
|
|
36550
|
+
onRender: this.props.onRender,
|
|
36551
|
+
strings: this.context.strings
|
|
36552
|
+
}))
|
|
36553
|
+
);
|
|
37828
36554
|
}
|
|
37829
36555
|
}
|
|
37830
36556
|
Draggable.contextType = PerseusI18nContext;
|
|
@@ -38894,8 +37620,7 @@ var Matrix$1 = {
|
|
|
38894
37620
|
widget: Matrix,
|
|
38895
37621
|
transform: propTransform$1,
|
|
38896
37622
|
staticTransform: staticTransform$2,
|
|
38897
|
-
isLintable: true
|
|
38898
|
-
getPublicWidgetOptions: getMatrixPublicWidgetOptions
|
|
37623
|
+
isLintable: true
|
|
38899
37624
|
};
|
|
38900
37625
|
|
|
38901
37626
|
const getPromptJSON$7 = () => {
|
|
@@ -40468,8 +39193,7 @@ var NumberLine$1 = {
|
|
|
40468
39193
|
displayName: "Number line",
|
|
40469
39194
|
widget: NumberLine,
|
|
40470
39195
|
transform: numberLineTransform,
|
|
40471
|
-
staticTransform: staticTransform$1
|
|
40472
|
-
getPublicWidgetOptions: getNumberLinePublicWidgetOptions
|
|
39196
|
+
staticTransform: staticTransform$1
|
|
40473
39197
|
};
|
|
40474
39198
|
|
|
40475
39199
|
const getPromptJSON$5 = (renderProps, userInput) => {
|
|
@@ -40637,19 +39361,23 @@ class Card extends React.Component {
|
|
|
40637
39361
|
// Pull out the content to get rendered
|
|
40638
39362
|
const rendererProps = _.pick(this.props, "content");
|
|
40639
39363
|
const onMouseDown = this.props.animating ? $.noop : this.onMouseDown;
|
|
40640
|
-
return
|
|
40641
|
-
|
|
40642
|
-
|
|
40643
|
-
|
|
40644
|
-
|
|
40645
|
-
|
|
40646
|
-
|
|
40647
|
-
|
|
40648
|
-
|
|
40649
|
-
|
|
40650
|
-
|
|
40651
|
-
|
|
40652
|
-
|
|
39364
|
+
return (
|
|
39365
|
+
/*#__PURE__*/
|
|
39366
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
39367
|
+
React.createElement("div", {
|
|
39368
|
+
className: "card-wrap",
|
|
39369
|
+
style: style,
|
|
39370
|
+
onMouseDown: onMouseDown,
|
|
39371
|
+
onTouchStart: onMouseDown,
|
|
39372
|
+
onTouchEnd: this.onMouseUp,
|
|
39373
|
+
onTouchCancel: this.onMouseUp
|
|
39374
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
39375
|
+
className: className.join(" ")
|
|
39376
|
+
}, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
|
|
39377
|
+
linterContext: this.props.linterContext,
|
|
39378
|
+
strings: this.context.strings
|
|
39379
|
+
}))))
|
|
39380
|
+
);
|
|
40653
39381
|
}
|
|
40654
39382
|
}
|
|
40655
39383
|
Card.contextType = PerseusI18nContext;
|
|
@@ -41029,8 +39757,7 @@ var Orderer$1 = {
|
|
|
41029
39757
|
displayName: "Orderer",
|
|
41030
39758
|
hidden: true,
|
|
41031
39759
|
widget: Orderer,
|
|
41032
|
-
isLintable: true
|
|
41033
|
-
getPublicWidgetOptions: getOrdererPublicWidgetOptions
|
|
39760
|
+
isLintable: true
|
|
41034
39761
|
};
|
|
41035
39762
|
|
|
41036
39763
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -42090,8 +40817,7 @@ var Plotter$1 = {
|
|
|
42090
40817
|
displayName: "Plotter",
|
|
42091
40818
|
hidden: true,
|
|
42092
40819
|
widget: Plotter,
|
|
42093
|
-
staticTransform: staticTransform
|
|
42094
|
-
getPublicWidgetOptions: getPlotterPublicWidgetOptions
|
|
40820
|
+
staticTransform: staticTransform
|
|
42095
40821
|
};
|
|
42096
40822
|
|
|
42097
40823
|
const getPromptJSON$2 = () => {
|
|
@@ -42253,8 +40979,7 @@ var Sorter$1 = {
|
|
|
42253
40979
|
name: "sorter",
|
|
42254
40980
|
displayName: "Sorter",
|
|
42255
40981
|
widget: Sorter,
|
|
42256
|
-
isLintable: true
|
|
42257
|
-
getPublicWidgetOptions: getSorterPublicWidgetOptions
|
|
40982
|
+
isLintable: true
|
|
42258
40983
|
};
|
|
42259
40984
|
|
|
42260
40985
|
const {
|
|
@@ -42473,8 +41198,7 @@ var Table$1 = {
|
|
|
42473
41198
|
widget: Table,
|
|
42474
41199
|
transform: propTransform,
|
|
42475
41200
|
hidden: true,
|
|
42476
|
-
isLintable: true
|
|
42477
|
-
getPublicWidgetOptions: getTablePublicWidgetOptions
|
|
41201
|
+
isLintable: true
|
|
42478
41202
|
};
|
|
42479
41203
|
|
|
42480
41204
|
const getPromptJSON = () => {
|
|
@@ -42653,7 +41377,7 @@ const init = function init() {
|
|
|
42653
41377
|
|
|
42654
41378
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42655
41379
|
const libName = "@khanacademy/perseus";
|
|
42656
|
-
const libVersion = "
|
|
41380
|
+
const libVersion = "54.0.0";
|
|
42657
41381
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42658
41382
|
|
|
42659
41383
|
const apiVersion = {
|
|
@@ -44140,6 +42864,18 @@ function getWidgetTypeByWidgetId(WidgetId, widgetMap) {
|
|
|
44140
42864
|
const widget = widgetMap[WidgetId];
|
|
44141
42865
|
return (_widget$type = widget == null ? void 0 : widget.type) != null ? _widget$type : null;
|
|
44142
42866
|
}
|
|
42867
|
+
function getWidgetSubTypeByWidgetId(widgetId, widgetMap) {
|
|
42868
|
+
var _widget$type2, _graph$type;
|
|
42869
|
+
const widget = widgetMap[widgetId];
|
|
42870
|
+
const widgetType = (_widget$type2 = widget == null ? void 0 : widget.type) != null ? _widget$type2 : null;
|
|
42871
|
+
switch (widgetType) {
|
|
42872
|
+
case "interactive-graph":
|
|
42873
|
+
const graph = widget.options.graph;
|
|
42874
|
+
return (_graph$type = graph == null ? void 0 : graph.type) != null ? _graph$type : null;
|
|
42875
|
+
default:
|
|
42876
|
+
return null;
|
|
42877
|
+
}
|
|
42878
|
+
}
|
|
44143
42879
|
|
|
44144
42880
|
/**
|
|
44145
42881
|
* Does the content have a specific type of widget?
|
|
@@ -44932,5 +43668,5 @@ const ScoringUtil = {
|
|
|
44932
43668
|
* Types
|
|
44933
43669
|
*/
|
|
44934
43670
|
|
|
44935
|
-
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, mediaQueries, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
43671
|
+
export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, Expression, GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, JiptParagraphs, KhanColors, context as LoadingContext, Log, Matrix$1 as MatrixWidget, NumericInput$1 as NumericInput, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, Radio, Renderer, ScoringUtil, ref as ServerItemRenderer, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, widgets$1 as Widgets, apiVersion, bodyXsmallBold, components, containerSizeClass, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getInteractiveBoxFromSizeClass, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetSubTypeByWidgetId, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, iconChevronDown, iconTrash, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, ItemVersion as itemVersion, libVersion, makeSafeUrl, mathOnlyParser, mediaQueries, parseDataFromJSONP, preprocessTex, registerAllWidgetsForTesting, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
44936
43672
|
//# sourceMappingURL=index.js.map
|