@khanacademy/perseus 53.1.0 → 54.1.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 +621 -1948
- 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 +698 -775
- 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 +6 -13
- package/dist/util/graphie.d.ts +1 -1
- package/dist/util.d.ts +0 -5
- 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 -6
- 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, shuffle, random, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, 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) {
|
|
@@ -1901,54 +1939,6 @@ const rWidgetRule = /^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;
|
|
|
1901
1939
|
const rTypeFromWidgetId = /^([a-z-]+) ([0-9]+)$/;
|
|
1902
1940
|
const rWidgetParts = new RegExp(rWidgetRule.source + "$");
|
|
1903
1941
|
const snowman = "\u2603";
|
|
1904
|
-
const seededRNG$1 = function seededRNG(seed) {
|
|
1905
|
-
let randomSeed = seed;
|
|
1906
|
-
return function () {
|
|
1907
|
-
// Robert Jenkins' 32 bit integer hash function.
|
|
1908
|
-
let seed = randomSeed;
|
|
1909
|
-
seed = seed + 0x7ed55d16 + (seed << 12) & 0xffffffff;
|
|
1910
|
-
seed = (seed ^ 0xc761c23c ^ seed >>> 19) & 0xffffffff;
|
|
1911
|
-
seed = seed + 0x165667b1 + (seed << 5) & 0xffffffff;
|
|
1912
|
-
seed = (seed + 0xd3a2646c ^ seed << 9) & 0xffffffff;
|
|
1913
|
-
seed = seed + 0xfd7046c5 + (seed << 3) & 0xffffffff;
|
|
1914
|
-
seed = (seed ^ 0xb55a4f09 ^ seed >>> 16) & 0xffffffff;
|
|
1915
|
-
return (randomSeed = seed & 0xfffffff) / 0x10000000;
|
|
1916
|
-
};
|
|
1917
|
-
};
|
|
1918
|
-
|
|
1919
|
-
// Shuffle an array using a given random seed or function.
|
|
1920
|
-
// If `ensurePermuted` is true, the input and ouput are guaranteed to be
|
|
1921
|
-
// distinct permutations.
|
|
1922
|
-
function shuffle$3(array, randomSeed, ensurePermuted = false) {
|
|
1923
|
-
// Always return a copy of the input array
|
|
1924
|
-
const shuffled = _.clone(array);
|
|
1925
|
-
|
|
1926
|
-
// Handle edge cases (input array is empty or uniform)
|
|
1927
|
-
if (!shuffled.length || _.all(shuffled, function (value) {
|
|
1928
|
-
return _.isEqual(value, shuffled[0]);
|
|
1929
|
-
})) {
|
|
1930
|
-
return shuffled;
|
|
1931
|
-
}
|
|
1932
|
-
let random;
|
|
1933
|
-
if (typeof randomSeed === "function") {
|
|
1934
|
-
random = randomSeed;
|
|
1935
|
-
} else {
|
|
1936
|
-
random = seededRNG$1(randomSeed);
|
|
1937
|
-
}
|
|
1938
|
-
do {
|
|
1939
|
-
// Fischer-Yates shuffle
|
|
1940
|
-
for (let top = shuffled.length; top > 0; top--) {
|
|
1941
|
-
const newEnd = Math.floor(random() * top);
|
|
1942
|
-
const temp = shuffled[newEnd];
|
|
1943
|
-
|
|
1944
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
1945
|
-
shuffled[newEnd] = shuffled[top - 1];
|
|
1946
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
1947
|
-
shuffled[top - 1] = temp;
|
|
1948
|
-
}
|
|
1949
|
-
} while (ensurePermuted && _.isEqual(array, shuffled));
|
|
1950
|
-
return shuffled;
|
|
1951
|
-
}
|
|
1952
1942
|
|
|
1953
1943
|
/**
|
|
1954
1944
|
* TODO(somewhatabstract, FEI-3463):
|
|
@@ -2381,7 +2371,6 @@ const textarea = {
|
|
|
2381
2371
|
* to translate it but don't need the extra dollar signs.
|
|
2382
2372
|
*/
|
|
2383
2373
|
const unescapeMathMode$1 = label => label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
|
|
2384
|
-
const random$1 = seededRNG$1(new Date().getTime() & 0xffffffff);
|
|
2385
2374
|
const Util = {
|
|
2386
2375
|
inputPathsEqual,
|
|
2387
2376
|
nestedMap: nestedMap$2,
|
|
@@ -2389,8 +2378,6 @@ const Util = {
|
|
|
2389
2378
|
rTypeFromWidgetId,
|
|
2390
2379
|
rWidgetParts,
|
|
2391
2380
|
snowman,
|
|
2392
|
-
seededRNG: seededRNG$1,
|
|
2393
|
-
shuffle: shuffle$3,
|
|
2394
2381
|
split,
|
|
2395
2382
|
firstNumericalParse: firstNumericalParse$1,
|
|
2396
2383
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
@@ -2418,8 +2405,7 @@ const Util = {
|
|
|
2418
2405
|
getSvgUrl: getSvgUrl,
|
|
2419
2406
|
getDataUrl: getDataUrl,
|
|
2420
2407
|
textarea,
|
|
2421
|
-
unescapeMathMode: unescapeMathMode$1
|
|
2422
|
-
random: random$1
|
|
2408
|
+
unescapeMathMode: unescapeMathMode$1
|
|
2423
2409
|
};
|
|
2424
2410
|
|
|
2425
2411
|
// TODO(LP-11481): Change the primary API we use for logging in Perseus to use
|
|
@@ -15699,12 +15685,17 @@ class ImageLoader extends React.Component {
|
|
|
15699
15685
|
};
|
|
15700
15686
|
}
|
|
15701
15687
|
const staticUrl = getDependencies().staticUrl;
|
|
15702
|
-
return
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15688
|
+
return (
|
|
15689
|
+
/*#__PURE__*/
|
|
15690
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
15691
|
+
React.createElement("img", _extends({
|
|
15692
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- TODO(LEMS-2871): Address a11y error
|
|
15693
|
+
tabIndex: 0,
|
|
15694
|
+
src: staticUrl(src),
|
|
15695
|
+
onKeyUp: onKeyUp,
|
|
15696
|
+
onKeyDown: onKeyDown
|
|
15697
|
+
}, imgProps))
|
|
15698
|
+
);
|
|
15708
15699
|
};
|
|
15709
15700
|
this.state = {
|
|
15710
15701
|
status: props.src ? Status.LOADING : Status.PENDING
|
|
@@ -16389,16 +16380,20 @@ class Zoomable extends React.Component {
|
|
|
16389
16380
|
opacity: opacity,
|
|
16390
16381
|
WebkitTapHighlightColor: "transparent"
|
|
16391
16382
|
}, transitionStyle);
|
|
16392
|
-
return
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16383
|
+
return (
|
|
16384
|
+
/*#__PURE__*/
|
|
16385
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- TODO(LEMS-2871): Address a11y error
|
|
16386
|
+
React.createElement("span", {
|
|
16387
|
+
onClick: this.handleClick,
|
|
16388
|
+
onClickCapture: this.handleClickIfZoomed,
|
|
16389
|
+
onTouchCancelCapture: this.stopPropagationIfZoomed,
|
|
16390
|
+
onTouchEndCapture: this.stopPropagationIfZoomed,
|
|
16391
|
+
onTouchStartCapture: this.stopPropagationIfZoomed
|
|
16392
|
+
// @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'.
|
|
16393
|
+
,
|
|
16394
|
+
style: style
|
|
16395
|
+
}, this.props.children)
|
|
16396
|
+
);
|
|
16402
16397
|
}
|
|
16403
16398
|
}
|
|
16404
16399
|
Zoomable.defaultProps = {
|
|
@@ -17619,10 +17614,6 @@ const getWidgetExport = name => {
|
|
|
17619
17614
|
var _widgets$name3;
|
|
17620
17615
|
return (_widgets$name3 = widgets[name]) != null ? _widgets$name3 : null;
|
|
17621
17616
|
};
|
|
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
17617
|
const getEditor = name => {
|
|
17627
17618
|
return _.has(editors, name) ? editors[name] : null;
|
|
17628
17619
|
};
|
|
@@ -17759,7 +17750,6 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
17759
17750
|
replaceDeprecatedEditors: replaceDeprecatedEditors,
|
|
17760
17751
|
getWidget: getWidget,
|
|
17761
17752
|
getWidgetExport: getWidgetExport,
|
|
17762
|
-
getPublicWidgetOptionsFunction: getPublicWidgetOptionsFunction,
|
|
17763
17753
|
getEditor: getEditor,
|
|
17764
17754
|
getTransform: getTransform,
|
|
17765
17755
|
getVersion: getVersion,
|
|
@@ -17835,6 +17825,7 @@ class WidgetContainer extends React.Component {
|
|
|
17835
17825
|
"perseus-widget__definition": this.props.type === "definition"
|
|
17836
17826
|
});
|
|
17837
17827
|
const type = this.props.type;
|
|
17828
|
+
const userAgent = navigator.userAgent;
|
|
17838
17829
|
const WidgetType = getWidget(type);
|
|
17839
17830
|
if (WidgetType == null) {
|
|
17840
17831
|
// This is for the good of all people!!
|
|
@@ -17845,6 +17836,12 @@ class WidgetContainer extends React.Component {
|
|
|
17845
17836
|
className: className
|
|
17846
17837
|
});
|
|
17847
17838
|
}
|
|
17839
|
+
let subType = "null";
|
|
17840
|
+
if (type === "interactive-graph") {
|
|
17841
|
+
var _props$graph$type, _props$graph;
|
|
17842
|
+
const props = this.state.widgetProps;
|
|
17843
|
+
subType = (_props$graph$type = (_props$graph = props.graph) == null ? void 0 : _props$graph.type) != null ? _props$graph$type : "null";
|
|
17844
|
+
}
|
|
17848
17845
|
let alignment = this.state.widgetProps.alignment;
|
|
17849
17846
|
if (alignment === "default") {
|
|
17850
17847
|
alignment = CoreWidgetRegistry.getDefaultAlignment(type);
|
|
@@ -17898,12 +17895,26 @@ class WidgetContainer extends React.Component {
|
|
|
17898
17895
|
widget_type: type,
|
|
17899
17896
|
widget_id: this.props.id
|
|
17900
17897
|
},
|
|
17901
|
-
onError:
|
|
17898
|
+
onError: error => {
|
|
17899
|
+
// TODO(LEMS-2826): Remove analytics event in LEMS-2826 in favor of ti below.
|
|
17902
17900
|
analytics.onAnalyticsEvent({
|
|
17903
17901
|
type: "perseus:widget-rendering-error",
|
|
17904
17902
|
payload: {
|
|
17903
|
+
widgetSubType: subType,
|
|
17904
|
+
widgetType: type,
|
|
17905
|
+
widgetId: this.props.id,
|
|
17906
|
+
message: error.message,
|
|
17907
|
+
userAgent: userAgent
|
|
17908
|
+
}
|
|
17909
|
+
});
|
|
17910
|
+
analytics.onAnalyticsEvent({
|
|
17911
|
+
type: "perseus:widget-rendering-error:ti",
|
|
17912
|
+
payload: {
|
|
17913
|
+
widgetSubType: subType,
|
|
17905
17914
|
widgetType: type,
|
|
17906
|
-
widgetId: this.props.id
|
|
17915
|
+
widgetId: this.props.id,
|
|
17916
|
+
message: error.message,
|
|
17917
|
+
userAgent: userAgent
|
|
17907
17918
|
}
|
|
17908
17919
|
});
|
|
17909
17920
|
}
|
|
@@ -20327,7 +20338,6 @@ var NumericInput$1 = {
|
|
|
20327
20338
|
widget: NumericInput,
|
|
20328
20339
|
transform: propsTransform,
|
|
20329
20340
|
isLintable: true,
|
|
20330
|
-
getPublicWidgetOptions: getNumericInputPublicWidgetOptions,
|
|
20331
20341
|
// TODO(LEMS-2656): remove TS suppression
|
|
20332
20342
|
// @ts-expect-error: Type 'Rubric' is not assignable to type 'PerseusNumericInputRubric'
|
|
20333
20343
|
getOneCorrectAnswerFromRubric(rubric) {
|
|
@@ -21132,7 +21142,10 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
21132
21142
|
// using div instead of TooltipContent because
|
|
21133
21143
|
// TooltipContent wouldn't let me overwrite
|
|
21134
21144
|
// user-select and onClick
|
|
21135
|
-
const content =
|
|
21145
|
+
const content =
|
|
21146
|
+
/*#__PURE__*/
|
|
21147
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -- TODO(LEMS-2871): Address a11y error
|
|
21148
|
+
React.createElement("div", {
|
|
21136
21149
|
className: css(styles$x.tooltipLabel),
|
|
21137
21150
|
onClick: this.props.onClick
|
|
21138
21151
|
}, this.props.label);
|
|
@@ -21143,14 +21156,18 @@ class HighlightTooltip extends React.PureComponent {
|
|
|
21143
21156
|
top: `calc(${Math.round(focusRect.top)}px + 0.95em)`,
|
|
21144
21157
|
height: 0
|
|
21145
21158
|
};
|
|
21146
|
-
return
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21159
|
+
return (
|
|
21160
|
+
/*#__PURE__*/
|
|
21161
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
21162
|
+
React.createElement("div", {
|
|
21163
|
+
style: style,
|
|
21164
|
+
onMouseEnter: this.props.onMouseEnter,
|
|
21165
|
+
onMouseLeave: this.props.onMouseLeave
|
|
21166
|
+
}, /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
21167
|
+
content: content,
|
|
21168
|
+
opened: true
|
|
21169
|
+
}, /*#__PURE__*/React.createElement("div", null)))
|
|
21170
|
+
);
|
|
21154
21171
|
}
|
|
21155
21172
|
}
|
|
21156
21173
|
const styles$x = StyleSheet.create({
|
|
@@ -23853,15 +23870,19 @@ const BaseRadio = function BaseRadio({
|
|
|
23853
23870
|
// content somehow? Would changing our choice of key
|
|
23854
23871
|
// somehow break something happening inside a choice's
|
|
23855
23872
|
// child Renderers, by changing when we mount/unmount?
|
|
23856
|
-
return
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
23864
|
-
|
|
23873
|
+
return (
|
|
23874
|
+
/*#__PURE__*/
|
|
23875
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
23876
|
+
React.createElement("li", {
|
|
23877
|
+
key: i,
|
|
23878
|
+
ref: e => listElem = e,
|
|
23879
|
+
className: className,
|
|
23880
|
+
onClick: clickHandler,
|
|
23881
|
+
onTouchStart: labelWrap ? undefined : captureScratchpadTouchStart$1
|
|
23882
|
+
}, /*#__PURE__*/React.createElement(Element, _extends({}, elementProps, {
|
|
23883
|
+
ref: ref
|
|
23884
|
+
})))
|
|
23885
|
+
);
|
|
23865
23886
|
})));
|
|
23866
23887
|
|
|
23867
23888
|
// Allow for horizontal scrolling if content is too wide, which may be
|
|
@@ -24296,11 +24317,6 @@ Radio$1.defaultProps = {
|
|
|
24296
24317
|
showSolutions: "none"
|
|
24297
24318
|
};
|
|
24298
24319
|
|
|
24299
|
-
const {
|
|
24300
|
-
shuffle: shuffle$2,
|
|
24301
|
-
random
|
|
24302
|
-
} = Util;
|
|
24303
|
-
|
|
24304
24320
|
// Transforms the choices for display.
|
|
24305
24321
|
const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
24306
24322
|
const _maybeRandomize = function _maybeRandomize(array) {
|
|
@@ -24311,7 +24327,7 @@ const _choiceTransform = (widgetOptions, strings, problemNum) => {
|
|
|
24311
24327
|
// or if rendered within an article. This results in a predictable
|
|
24312
24328
|
// shuffle order. To avoid this we use a random seed when `problemNum`
|
|
24313
24329
|
// is `undefined`.
|
|
24314
|
-
return widgetOptions.randomize ? shuffle
|
|
24330
|
+
return widgetOptions.randomize ? shuffle(array, randomSeed != null ? randomSeed : 0) : array;
|
|
24315
24331
|
};
|
|
24316
24332
|
const _addNoneOfAbove = function _addNoneOfAbove(choices) {
|
|
24317
24333
|
let noneOfTheAbove = null;
|
|
@@ -24391,8 +24407,7 @@ var Radio = {
|
|
|
24391
24407
|
staticTransform: transform,
|
|
24392
24408
|
version: radioLogic.version,
|
|
24393
24409
|
propUpgrades: radioLogic.widgetOptionsUpgrades,
|
|
24394
|
-
isLintable: true
|
|
24395
|
-
getPublicWidgetOptions: getRadioPublicWidgetOptions
|
|
24410
|
+
isLintable: true
|
|
24396
24411
|
};
|
|
24397
24412
|
|
|
24398
24413
|
/* eslint-disable import/no-named-as-default */
|
|
@@ -24542,8 +24557,7 @@ class Categorizer extends React.Component {
|
|
|
24542
24557
|
const isMobile = this.props.apiOptions.isMobile;
|
|
24543
24558
|
let indexedItems = this.props.items.map((item, n) => [item, n]);
|
|
24544
24559
|
if (this.props.randomizeItems) {
|
|
24545
|
-
|
|
24546
|
-
indexedItems = Util.shuffle(indexedItems, this.props.problemNum);
|
|
24560
|
+
indexedItems = shuffle(indexedItems, this.props.problemNum);
|
|
24547
24561
|
}
|
|
24548
24562
|
const table = /*#__PURE__*/React.createElement("table", {
|
|
24549
24563
|
className: "categorizer-table " + css(styles$n.mobileTable)
|
|
@@ -24569,9 +24583,7 @@ class Categorizer extends React.Component {
|
|
|
24569
24583
|
const uniqueId = self.state.uniqueId + "_" + itemNum;
|
|
24570
24584
|
return /*#__PURE__*/React.createElement("tr", {
|
|
24571
24585
|
key: itemNum
|
|
24572
|
-
}, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(Renderer
|
|
24573
|
-
// @ts-expect-error - TS2322 - Type 'string | number' is not assignable to type 'string | undefined'.
|
|
24574
|
-
, {
|
|
24586
|
+
}, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(Renderer, {
|
|
24575
24587
|
content: item,
|
|
24576
24588
|
linterContext: this.props.linterContext,
|
|
24577
24589
|
strings: this.context.strings
|
|
@@ -24678,8 +24690,7 @@ var Categorizer$1 = {
|
|
|
24678
24690
|
staticTransform: editorProps => {
|
|
24679
24691
|
return _.pick(editorProps, "items", "categories", "values", "randomizeItems");
|
|
24680
24692
|
},
|
|
24681
|
-
isLintable: true
|
|
24682
|
-
getPublicWidgetOptions: getCategorizerPublicWidgetOptions
|
|
24693
|
+
isLintable: true
|
|
24683
24694
|
};
|
|
24684
24695
|
|
|
24685
24696
|
/**
|
|
@@ -24885,8 +24896,7 @@ var CSProgram$1 = {
|
|
|
24885
24896
|
name: "cs-program",
|
|
24886
24897
|
displayName: "CS Program",
|
|
24887
24898
|
widget: CSProgram,
|
|
24888
|
-
hidden: true
|
|
24889
|
-
getPublicWidgetOptions: getCSProgramPublicWidgetOptions
|
|
24899
|
+
hidden: true
|
|
24890
24900
|
};
|
|
24891
24901
|
|
|
24892
24902
|
const getPromptJSON$l = renderProps => {
|
|
@@ -25104,8 +25114,7 @@ var Dropdown$1 = {
|
|
|
25104
25114
|
displayName: "Drop down",
|
|
25105
25115
|
accessible: true,
|
|
25106
25116
|
widget: Dropdown,
|
|
25107
|
-
transform: optionsTransform
|
|
25108
|
-
getPublicWidgetOptions: getDropdownPublicWidgetOptions
|
|
25117
|
+
transform: optionsTransform
|
|
25109
25118
|
};
|
|
25110
25119
|
|
|
25111
25120
|
const getPromptJSON$j = renderProps => {
|
|
@@ -26579,8 +26588,7 @@ var Grapher$1 = {
|
|
|
26579
26588
|
hidden: true,
|
|
26580
26589
|
widget: Grapher,
|
|
26581
26590
|
transform: propTransform$2,
|
|
26582
|
-
staticTransform: staticTransform$4
|
|
26583
|
-
getPublicWidgetOptions: getGrapherPublicWidgetOptions
|
|
26591
|
+
staticTransform: staticTransform$4
|
|
26584
26592
|
};
|
|
26585
26593
|
|
|
26586
26594
|
const getPromptJSON$f = rendererJSON => {
|
|
@@ -26865,12 +26873,16 @@ class Iframe extends React.Component {
|
|
|
26865
26873
|
// that we need. This makes it a bit safer in case some content
|
|
26866
26874
|
// creator "went wild".
|
|
26867
26875
|
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
|
|
26868
|
-
return
|
|
26869
|
-
|
|
26870
|
-
|
|
26871
|
-
|
|
26872
|
-
|
|
26873
|
-
|
|
26876
|
+
return (
|
|
26877
|
+
/*#__PURE__*/
|
|
26878
|
+
// eslint-disable-next-line jsx-a11y/iframe-has-title -- TODO(LEMS-2871): Address a11y error
|
|
26879
|
+
React.createElement("iframe", {
|
|
26880
|
+
sandbox: sandboxProperties,
|
|
26881
|
+
style: style,
|
|
26882
|
+
src: url,
|
|
26883
|
+
allowFullScreen: this.props.allowFullScreen
|
|
26884
|
+
})
|
|
26885
|
+
);
|
|
26874
26886
|
}
|
|
26875
26887
|
}
|
|
26876
26888
|
Iframe.defaultProps = {
|
|
@@ -26885,8 +26897,7 @@ var Iframe$1 = {
|
|
|
26885
26897
|
displayName: "Iframe (deprecated)",
|
|
26886
26898
|
widget: Iframe,
|
|
26887
26899
|
// Let's not expose it to all content creators yet
|
|
26888
|
-
hidden: true
|
|
26889
|
-
getPublicWidgetOptions: getIFramePublicWidgetOptions
|
|
26900
|
+
hidden: true
|
|
26890
26901
|
};
|
|
26891
26902
|
|
|
26892
26903
|
const getPromptJSON$d = renderProps => {
|
|
@@ -26903,7 +26914,7 @@ const getPromptJSON$d = renderProps => {
|
|
|
26903
26914
|
|
|
26904
26915
|
const defaultBoxSize = 400;
|
|
26905
26916
|
const defaultRange = [0, 10];
|
|
26906
|
-
const defaultBackgroundImage$
|
|
26917
|
+
const defaultBackgroundImage$1 = {
|
|
26907
26918
|
url: null,
|
|
26908
26919
|
width: 0,
|
|
26909
26920
|
height: 0
|
|
@@ -27060,7 +27071,7 @@ ImageWidget.defaultProps = {
|
|
|
27060
27071
|
title: "",
|
|
27061
27072
|
range: [defaultRange, defaultRange],
|
|
27062
27073
|
box: [defaultBoxSize, defaultBoxSize],
|
|
27063
|
-
backgroundImage: defaultBackgroundImage$
|
|
27074
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
27064
27075
|
labels: [],
|
|
27065
27076
|
alt: "",
|
|
27066
27077
|
caption: "",
|
|
@@ -27677,307 +27688,6 @@ var Interactive = {
|
|
|
27677
27688
|
hidden: true
|
|
27678
27689
|
};
|
|
27679
27690
|
|
|
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
27691
|
const getPromptJSON$b = (props, userInput) => {
|
|
27982
27692
|
var _props$backgroundImag;
|
|
27983
27693
|
return {
|
|
@@ -28530,13 +28240,18 @@ function escapeIfUnescaped(character) {
|
|
|
28530
28240
|
}
|
|
28531
28241
|
}
|
|
28532
28242
|
|
|
28533
|
-
function AxisLabels(
|
|
28243
|
+
function AxisLabels({
|
|
28244
|
+
i18n
|
|
28245
|
+
}) {
|
|
28534
28246
|
const {
|
|
28535
28247
|
range,
|
|
28536
28248
|
labels,
|
|
28537
28249
|
width,
|
|
28538
28250
|
height
|
|
28539
28251
|
} = useGraphConfig();
|
|
28252
|
+
const {
|
|
28253
|
+
strings
|
|
28254
|
+
} = i18n;
|
|
28540
28255
|
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
28541
28256
|
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
28542
28257
|
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
@@ -28554,6 +28269,7 @@ function AxisLabels() {
|
|
|
28554
28269
|
TeX
|
|
28555
28270
|
} = getDependencies();
|
|
28556
28271
|
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
|
|
28272
|
+
"aria-label": strings.xAxis,
|
|
28557
28273
|
style: {
|
|
28558
28274
|
position: "absolute",
|
|
28559
28275
|
left: x1,
|
|
@@ -28562,6 +28278,7 @@ function AxisLabels() {
|
|
|
28562
28278
|
transform: "translate(7px, -50%)"
|
|
28563
28279
|
}
|
|
28564
28280
|
}, /*#__PURE__*/React__default.createElement(TeX, null, replaceOutsideTeX(xAxisLabelText))), /*#__PURE__*/React__default.createElement("span", {
|
|
28281
|
+
"aria-label": strings.yAxis,
|
|
28565
28282
|
style: {
|
|
28566
28283
|
position: "absolute",
|
|
28567
28284
|
left: x2,
|
|
@@ -29371,7 +29088,6 @@ RangeInput.defaultProps = {
|
|
|
29371
29088
|
var components = /*#__PURE__*/Object.freeze({
|
|
29372
29089
|
__proto__: null,
|
|
29373
29090
|
ButtonGroup: ButtonGroup,
|
|
29374
|
-
Graph: Graph,
|
|
29375
29091
|
Graphie: Graphie,
|
|
29376
29092
|
HUD: HUD,
|
|
29377
29093
|
Icon: Icon,
|
|
@@ -29512,9 +29228,9 @@ const LockedFunction = props => {
|
|
|
29512
29228
|
const {
|
|
29513
29229
|
color,
|
|
29514
29230
|
strokeStyle,
|
|
29515
|
-
directionalAxis
|
|
29516
|
-
domain
|
|
29231
|
+
directionalAxis
|
|
29517
29232
|
} = props;
|
|
29233
|
+
const domain = props.domain ? [Number.isFinite(props.domain[0]) ? props.domain[0] : -Infinity, Number.isFinite(props.domain[1]) ? props.domain[1] : Infinity] : undefined;
|
|
29518
29234
|
const plotProps = {
|
|
29519
29235
|
color: lockedFigureColors[color],
|
|
29520
29236
|
style: strokeStyle,
|
|
@@ -29594,6 +29310,11 @@ function Vector(props) {
|
|
|
29594
29310
|
}
|
|
29595
29311
|
|
|
29596
29312
|
function srFormatNumber(a, locale, maximumFractionDigits) {
|
|
29313
|
+
const piBasedNumber = getPiMultiple(a);
|
|
29314
|
+
if (piBasedNumber) {
|
|
29315
|
+
return piBasedNumber;
|
|
29316
|
+
}
|
|
29317
|
+
|
|
29597
29318
|
// adding zero here converts negative zero to positive zero.
|
|
29598
29319
|
return (0 + a).toLocaleString(locale, {
|
|
29599
29320
|
maximumFractionDigits: maximumFractionDigits != null ? maximumFractionDigits : 3,
|
|
@@ -29601,6 +29322,77 @@ function srFormatNumber(a, locale, maximumFractionDigits) {
|
|
|
29601
29322
|
});
|
|
29602
29323
|
}
|
|
29603
29324
|
|
|
29325
|
+
// Exported for testing
|
|
29326
|
+
function getPiMultiple(a) {
|
|
29327
|
+
// - Save some calculations by checking if this is an integer first.
|
|
29328
|
+
// If a is an integer, it's definitely not a multiple of π.
|
|
29329
|
+
// - 0 should not be presented as a multiple of π.
|
|
29330
|
+
// - If a is greater than 1e12, then it thinks that it's always a
|
|
29331
|
+
// multiple of π even when it's not, due to rounding errors.
|
|
29332
|
+
if (Number.isInteger(a) || a === 0 || a > 1e12) {
|
|
29333
|
+
return null;
|
|
29334
|
+
}
|
|
29335
|
+
|
|
29336
|
+
// Figure out the coefficient before the π.
|
|
29337
|
+
// Example: If a = π/2, then piCoefficient = 0.5
|
|
29338
|
+
// Example: If a = 2π, then piCoefficient = 2
|
|
29339
|
+
const piCoefficient = a / Math.PI;
|
|
29340
|
+
// Truncate the coefficient to account for floating point errors.
|
|
29341
|
+
// π calculations are only accurate up to precision of 1e-12.
|
|
29342
|
+
const truncatedCoefficient = parseFloat(piCoefficient.toFixed(12));
|
|
29343
|
+
|
|
29344
|
+
// If the coefficient is already an integer, then the number
|
|
29345
|
+
// is a multiple of π. Return it here.
|
|
29346
|
+
// Example: If a = 2π, then truncatedCoefficient = 2, so return "2π"
|
|
29347
|
+
if (Number.isInteger(truncatedCoefficient)) {
|
|
29348
|
+
// Return "π" rather than "1π".
|
|
29349
|
+
if (truncatedCoefficient === 1) {
|
|
29350
|
+
return "π";
|
|
29351
|
+
}
|
|
29352
|
+
|
|
29353
|
+
// Return "-π" rather than "-1π".
|
|
29354
|
+
if (truncatedCoefficient === -1) {
|
|
29355
|
+
return "-π";
|
|
29356
|
+
}
|
|
29357
|
+
return truncatedCoefficient + "π";
|
|
29358
|
+
}
|
|
29359
|
+
|
|
29360
|
+
// If the coefficient is not an integer, then we need to
|
|
29361
|
+
// check if it's a multiple of π/2, π/3, π/4, or π/6.
|
|
29362
|
+
// These are π-based values on a unit circle.
|
|
29363
|
+
const acceptableDivisors = [2, 3, 4, 6];
|
|
29364
|
+
|
|
29365
|
+
// Loop through the acceptable divisors and check if the
|
|
29366
|
+
// coefficient is a multiple of (1/divisor).
|
|
29367
|
+
// Example: If a = 5π/6, the coeff is 5/6, which is a multiple of 1/6.
|
|
29368
|
+
// So we return "5π/6".
|
|
29369
|
+
for (const divisor of acceptableDivisors) {
|
|
29370
|
+
// Check if the coefficient is a multiple of (1/divisor) by
|
|
29371
|
+
// multiplying the coefficient by the divisor and checking if
|
|
29372
|
+
// the result is an integer.
|
|
29373
|
+
// Example: If a = 5π/6, then piCoefficient = 5/6. We multiply
|
|
29374
|
+
// by 6 (divisor) to get 5, which is an integer.
|
|
29375
|
+
const coefficientNumerator = parseFloat(
|
|
29376
|
+
// π calculations are only accurate up to precision of 1e-12.
|
|
29377
|
+
(piCoefficient * divisor).toFixed(12));
|
|
29378
|
+
if (Number.isInteger(coefficientNumerator)) {
|
|
29379
|
+
// Handle the case where the coefficient numberator is just 1.
|
|
29380
|
+
// We don't want to write "π/6" as "1π/6"
|
|
29381
|
+
if (coefficientNumerator === 1) {
|
|
29382
|
+
return "π/" + divisor;
|
|
29383
|
+
}
|
|
29384
|
+
|
|
29385
|
+
// Handle the case where the coefficient numberator is just -1.
|
|
29386
|
+
// We don't want to write "π/6" as "-1π/6"
|
|
29387
|
+
if (coefficientNumerator === -1) {
|
|
29388
|
+
return "-π/" + divisor;
|
|
29389
|
+
}
|
|
29390
|
+
return coefficientNumerator + "π/" + divisor;
|
|
29391
|
+
}
|
|
29392
|
+
}
|
|
29393
|
+
return null;
|
|
29394
|
+
}
|
|
29395
|
+
|
|
29604
29396
|
/**
|
|
29605
29397
|
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
29606
29398
|
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
@@ -30756,6 +30548,34 @@ function range(min, max, step = 1) {
|
|
|
30756
30548
|
return result;
|
|
30757
30549
|
}
|
|
30758
30550
|
|
|
30551
|
+
function Hairlines(props) {
|
|
30552
|
+
const {
|
|
30553
|
+
point
|
|
30554
|
+
} = props;
|
|
30555
|
+
const {
|
|
30556
|
+
range
|
|
30557
|
+
} = useGraphConfig();
|
|
30558
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
30559
|
+
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
30560
|
+
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
30561
|
+
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
30562
|
+
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
30563
|
+
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
30564
|
+
return /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
30565
|
+
x1: verticalStartX,
|
|
30566
|
+
y1: y,
|
|
30567
|
+
x2: verticalEndX,
|
|
30568
|
+
y2: y,
|
|
30569
|
+
stroke: color.blue
|
|
30570
|
+
}), /*#__PURE__*/React.createElement("line", {
|
|
30571
|
+
x1: x,
|
|
30572
|
+
y1: horizontalStartY,
|
|
30573
|
+
x2: x,
|
|
30574
|
+
y2: horizontalEndY,
|
|
30575
|
+
stroke: color.blue
|
|
30576
|
+
}));
|
|
30577
|
+
}
|
|
30578
|
+
|
|
30759
30579
|
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
30760
30580
|
// graph.
|
|
30761
30581
|
const hitboxSizePx = 48;
|
|
@@ -30766,7 +30586,6 @@ const hitboxSizePx = 48;
|
|
|
30766
30586
|
const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
30767
30587
|
var _Object$entries$find$, _Object$entries$find;
|
|
30768
30588
|
const {
|
|
30769
|
-
range,
|
|
30770
30589
|
markings,
|
|
30771
30590
|
showTooltips
|
|
30772
30591
|
} = useGraphConfig();
|
|
@@ -30774,6 +30593,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30774
30593
|
point,
|
|
30775
30594
|
color: color$1 = color.blue,
|
|
30776
30595
|
dragging,
|
|
30596
|
+
focused,
|
|
30777
30597
|
cursor,
|
|
30778
30598
|
showFocusRing,
|
|
30779
30599
|
onClick = () => {}
|
|
@@ -30784,25 +30604,7 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30784
30604
|
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
30605
|
const pointClasses = classNames("movable-point", dragging && "movable-point--dragging", showFocusRing && "movable-point--focus");
|
|
30786
30606
|
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
|
-
}));
|
|
30607
|
+
const showHairlines = (dragging || focused) && markings !== "none";
|
|
30806
30608
|
const svgForPoint = /*#__PURE__*/React.createElement("g", {
|
|
30807
30609
|
ref: hitboxRef,
|
|
30808
30610
|
className: pointClasses,
|
|
@@ -30838,7 +30640,9 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
30838
30640
|
},
|
|
30839
30641
|
"data-testid": "movable-point__center"
|
|
30840
30642
|
}));
|
|
30841
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines &&
|
|
30643
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && /*#__PURE__*/React.createElement(Hairlines, {
|
|
30644
|
+
point: point
|
|
30645
|
+
}), showTooltips ? /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
30842
30646
|
autoUpdate: true,
|
|
30843
30647
|
backgroundColor: wbColorName,
|
|
30844
30648
|
content: `(${point[X]}, ${point[Y]})`,
|
|
@@ -30932,6 +30736,7 @@ function useControlPoint(params) {
|
|
|
30932
30736
|
},
|
|
30933
30737
|
point: point,
|
|
30934
30738
|
dragging: dragging,
|
|
30739
|
+
focused: focused,
|
|
30935
30740
|
color: color,
|
|
30936
30741
|
ref: visiblePointRef,
|
|
30937
30742
|
showFocusRing: focused
|
|
@@ -31148,13 +30953,13 @@ const {
|
|
|
31148
30953
|
getClockwiseAngle: getClockwiseAngle$2,
|
|
31149
30954
|
polar: polar$1
|
|
31150
30955
|
} = angles;
|
|
31151
|
-
function renderAngleGraph(state, dispatch) {
|
|
30956
|
+
function renderAngleGraph(state, dispatch, i18n) {
|
|
31152
30957
|
return {
|
|
31153
30958
|
graph: /*#__PURE__*/React.createElement(AngleGraph, {
|
|
31154
30959
|
graphState: state,
|
|
31155
30960
|
dispatch: dispatch
|
|
31156
30961
|
}),
|
|
31157
|
-
interactiveElementsDescription:
|
|
30962
|
+
interactiveElementsDescription: getAngleGraphDescription(state, i18n)
|
|
31158
30963
|
};
|
|
31159
30964
|
}
|
|
31160
30965
|
function AngleGraph(props) {
|
|
@@ -31165,6 +30970,9 @@ function AngleGraph(props) {
|
|
|
31165
30970
|
const {
|
|
31166
30971
|
graphDimensionsInPixels
|
|
31167
30972
|
} = useGraphConfig();
|
|
30973
|
+
const i18n = usePerseusI18n();
|
|
30974
|
+
const id = React.useId();
|
|
30975
|
+
const descriptionId = id + "-description";
|
|
31168
30976
|
const {
|
|
31169
30977
|
coords,
|
|
31170
30978
|
showAngles,
|
|
@@ -31213,76 +31021,106 @@ function AngleGraph(props) {
|
|
|
31213
31021
|
showAngles: showAngles || false // Whether to show the angle or not
|
|
31214
31022
|
};
|
|
31215
31023
|
|
|
31024
|
+
// Aria strings
|
|
31216
31025
|
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]);
|
|
31026
|
+
srAngleGraphAriaLabel,
|
|
31027
|
+
srAngleGraphAriaDescription,
|
|
31028
|
+
srAngleStartingSide,
|
|
31029
|
+
srAngleEndingSide,
|
|
31030
|
+
srAngleVertex
|
|
31031
|
+
} = describeAngleGraph(graphState, i18n);
|
|
31259
31032
|
|
|
31260
31033
|
// Render the lines, angle, and then movable points
|
|
31261
31034
|
return /*#__PURE__*/React.createElement("g", {
|
|
31262
|
-
"aria-label":
|
|
31263
|
-
"aria-describedby":
|
|
31035
|
+
"aria-label": srAngleGraphAriaLabel,
|
|
31036
|
+
"aria-describedby": descriptionId
|
|
31264
31037
|
}, svgLines, /*#__PURE__*/React.createElement(Angle, angleParams), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31265
31038
|
point: coords[1],
|
|
31266
31039
|
sequenceNumber: 1,
|
|
31267
31040
|
constrain: p => p,
|
|
31268
31041
|
onMove: destination => dispatch(actions.angle.movePoint(1, destination)),
|
|
31269
|
-
ariaLabel:
|
|
31042
|
+
ariaLabel: srAngleVertex
|
|
31270
31043
|
}), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31271
31044
|
point: coords[0],
|
|
31272
31045
|
sequenceNumber: 2,
|
|
31273
31046
|
constrain: getAngleSideConstraint(coords[0], coords[1], snapDegrees || 1),
|
|
31274
31047
|
onMove: destination => dispatch(actions.angle.movePoint(0, destination)),
|
|
31275
|
-
ariaLabel:
|
|
31048
|
+
ariaLabel: srAngleEndingSide
|
|
31276
31049
|
}), /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
31277
31050
|
point: coords[2],
|
|
31278
31051
|
sequenceNumber: 3,
|
|
31279
31052
|
constrain: getAngleSideConstraint(coords[2], coords[1], snapDegrees || 1),
|
|
31280
31053
|
onMove: destination => dispatch(actions.angle.movePoint(2, destination)),
|
|
31281
|
-
ariaLabel:
|
|
31054
|
+
ariaLabel: srAngleStartingSide
|
|
31282
31055
|
}), /*#__PURE__*/React.createElement("g", {
|
|
31283
|
-
id:
|
|
31056
|
+
id: descriptionId,
|
|
31284
31057
|
style: a11y.srOnly
|
|
31285
|
-
},
|
|
31058
|
+
}, srAngleGraphAriaDescription));
|
|
31059
|
+
}
|
|
31060
|
+
function getAngleGraphDescription(state, i18n) {
|
|
31061
|
+
const {
|
|
31062
|
+
strings,
|
|
31063
|
+
locale
|
|
31064
|
+
} = i18n;
|
|
31065
|
+
const {
|
|
31066
|
+
coords
|
|
31067
|
+
} = state;
|
|
31068
|
+
return strings.srInteractiveElements({
|
|
31069
|
+
elements: strings.srAngleInteractiveElements({
|
|
31070
|
+
vertexX: srFormatNumber(coords[1][X], locale),
|
|
31071
|
+
vertexY: srFormatNumber(coords[1][Y], locale),
|
|
31072
|
+
startingSideX: srFormatNumber(coords[2][X], locale),
|
|
31073
|
+
startingSideY: srFormatNumber(coords[2][Y], locale),
|
|
31074
|
+
endingSideX: srFormatNumber(coords[0][X], locale),
|
|
31075
|
+
endingSideY: srFormatNumber(coords[0][Y], locale)
|
|
31076
|
+
})
|
|
31077
|
+
});
|
|
31078
|
+
}
|
|
31079
|
+
function describeAngleGraph(state, i18n) {
|
|
31080
|
+
const {
|
|
31081
|
+
strings,
|
|
31082
|
+
locale
|
|
31083
|
+
} = i18n;
|
|
31084
|
+
const {
|
|
31085
|
+
coords,
|
|
31086
|
+
allowReflexAngles,
|
|
31087
|
+
showAngles
|
|
31088
|
+
} = state;
|
|
31089
|
+
const [endingSide, vertex, startingSide] = coords;
|
|
31090
|
+
const angleMeasure = srFormatNumber(getClockwiseAngle$2(coords, allowReflexAngles), locale);
|
|
31091
|
+
const srAngleGraphAriaLabel = strings.srAngleGraphAriaLabel;
|
|
31092
|
+
const srAngleGraphAriaDescription = strings.srAngleGraphAriaDescription({
|
|
31093
|
+
angleMeasure,
|
|
31094
|
+
vertexX: srFormatNumber(vertex[X], locale),
|
|
31095
|
+
vertexY: srFormatNumber(vertex[Y], locale),
|
|
31096
|
+
startingSideX: srFormatNumber(startingSide[X], locale),
|
|
31097
|
+
startingSideY: srFormatNumber(startingSide[Y], locale),
|
|
31098
|
+
endingSideX: srFormatNumber(endingSide[X], locale),
|
|
31099
|
+
endingSideY: srFormatNumber(endingSide[Y], locale)
|
|
31100
|
+
});
|
|
31101
|
+
const srAngleStartingSide = strings.srAngleStartingSide({
|
|
31102
|
+
x: srFormatNumber(startingSide[X], locale),
|
|
31103
|
+
y: srFormatNumber(startingSide[Y], locale)
|
|
31104
|
+
});
|
|
31105
|
+
const srAngleEndingSide = strings.srAngleEndingSide({
|
|
31106
|
+
x: srFormatNumber(endingSide[X], locale),
|
|
31107
|
+
y: srFormatNumber(endingSide[Y], locale)
|
|
31108
|
+
});
|
|
31109
|
+
const srAngleVertex = showAngles ? strings.srAngleVertexWithAngleMeasure({
|
|
31110
|
+
x: srFormatNumber(vertex[X], locale),
|
|
31111
|
+
y: srFormatNumber(vertex[Y], locale),
|
|
31112
|
+
angleMeasure
|
|
31113
|
+
}) : strings.srAngleVertex({
|
|
31114
|
+
x: srFormatNumber(vertex[X], locale),
|
|
31115
|
+
y: srFormatNumber(vertex[Y], locale)
|
|
31116
|
+
});
|
|
31117
|
+
return {
|
|
31118
|
+
srAngleGraphAriaLabel,
|
|
31119
|
+
srAngleGraphAriaDescription,
|
|
31120
|
+
srAngleStartingSide,
|
|
31121
|
+
srAngleEndingSide,
|
|
31122
|
+
srAngleVertex
|
|
31123
|
+
};
|
|
31286
31124
|
}
|
|
31287
31125
|
const positiveX = [1, 0];
|
|
31288
31126
|
const negativeX = [-1, 0];
|
|
@@ -31413,17 +31251,16 @@ function getRadius(graph) {
|
|
|
31413
31251
|
return Math.sqrt(Math.pow(edgeX - centerX, 2) + Math.pow(edgeY - centerY, 2));
|
|
31414
31252
|
}
|
|
31415
31253
|
|
|
31416
|
-
function renderCircleGraph(state, dispatch) {
|
|
31254
|
+
function renderCircleGraph(state, dispatch, i18n) {
|
|
31417
31255
|
return {
|
|
31418
31256
|
graph: /*#__PURE__*/React.createElement(CircleGraph, {
|
|
31419
31257
|
graphState: state,
|
|
31420
31258
|
dispatch: dispatch
|
|
31421
31259
|
}),
|
|
31422
|
-
interactiveElementsDescription:
|
|
31423
|
-
state: state
|
|
31424
|
-
})
|
|
31260
|
+
interactiveElementsDescription: getCircleGraphDescription(state, i18n)
|
|
31425
31261
|
};
|
|
31426
31262
|
}
|
|
31263
|
+
// Exported for testing
|
|
31427
31264
|
function CircleGraph(props) {
|
|
31428
31265
|
const {
|
|
31429
31266
|
dispatch,
|
|
@@ -31516,6 +31353,7 @@ function MovableCircle(props) {
|
|
|
31516
31353
|
snapStep,
|
|
31517
31354
|
disableKeyboardInteraction
|
|
31518
31355
|
} = useGraphConfig();
|
|
31356
|
+
const [focused, setFocused] = React.useState(false);
|
|
31519
31357
|
const draggableRef = useRef(null);
|
|
31520
31358
|
const {
|
|
31521
31359
|
dragging
|
|
@@ -31534,7 +31372,9 @@ function MovableCircle(props) {
|
|
|
31534
31372
|
ref: draggableRef,
|
|
31535
31373
|
role: "button",
|
|
31536
31374
|
tabIndex: disableKeyboardInteraction ? -1 : 0,
|
|
31537
|
-
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}
|
|
31375
|
+
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`,
|
|
31376
|
+
onFocus: () => setFocused(true),
|
|
31377
|
+
onBlur: () => setFocused(false)
|
|
31538
31378
|
}, /*#__PURE__*/React.createElement("ellipse", {
|
|
31539
31379
|
className: "focus-ring",
|
|
31540
31380
|
cx: centerPx[X],
|
|
@@ -31549,19 +31389,29 @@ function MovableCircle(props) {
|
|
|
31549
31389
|
rx: radiiPx[X],
|
|
31550
31390
|
ry: radiiPx[Y]
|
|
31551
31391
|
}), /*#__PURE__*/React.createElement(DragHandle, {
|
|
31552
|
-
center: center
|
|
31392
|
+
center: center,
|
|
31393
|
+
dragging: dragging,
|
|
31394
|
+
focused: focused
|
|
31553
31395
|
}));
|
|
31554
31396
|
}
|
|
31555
31397
|
const dragHandleDimensions = [24, 14];
|
|
31556
31398
|
const dragHandleDotPositions = crossProduct([-4.4, 0, 4.4], [-2.1, 2.1]);
|
|
31557
31399
|
function DragHandle(props) {
|
|
31558
31400
|
const {
|
|
31559
|
-
center
|
|
31401
|
+
center,
|
|
31402
|
+
dragging,
|
|
31403
|
+
focused
|
|
31560
31404
|
} = props;
|
|
31561
|
-
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
31562
31405
|
const [centerPx] = useTransformVectorsToPixels(center);
|
|
31406
|
+
const {
|
|
31407
|
+
markings
|
|
31408
|
+
} = useGraphConfig();
|
|
31409
|
+
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
31563
31410
|
const topLeft = vec.sub(centerPx, vec.scale(dragHandleDimensions, 0.5));
|
|
31564
|
-
|
|
31411
|
+
const showHairlines = (dragging || focused) && markings !== "none";
|
|
31412
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, showHairlines && /*#__PURE__*/React.createElement(Hairlines, {
|
|
31413
|
+
point: center
|
|
31414
|
+
}), /*#__PURE__*/React.createElement("rect", {
|
|
31565
31415
|
className: "movable-circle-handle",
|
|
31566
31416
|
x: topLeft[X],
|
|
31567
31417
|
y: topLeft[Y],
|
|
@@ -31588,13 +31438,7 @@ function crossProduct(as, bs) {
|
|
|
31588
31438
|
}
|
|
31589
31439
|
return result;
|
|
31590
31440
|
}
|
|
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();
|
|
31441
|
+
function getCircleGraphDescription(state, i18n) {
|
|
31598
31442
|
const strings = describeCircleGraph(state, i18n);
|
|
31599
31443
|
return strings.srCircleInteractiveElement;
|
|
31600
31444
|
}
|
|
@@ -31647,15 +31491,13 @@ function describeCircleGraph(state, i18n) {
|
|
|
31647
31491
|
};
|
|
31648
31492
|
}
|
|
31649
31493
|
|
|
31650
|
-
function renderLinearGraph(state, dispatch) {
|
|
31494
|
+
function renderLinearGraph(state, dispatch, i18n) {
|
|
31651
31495
|
return {
|
|
31652
31496
|
graph: /*#__PURE__*/React.createElement(LinearGraph, {
|
|
31653
31497
|
graphState: state,
|
|
31654
31498
|
dispatch: dispatch
|
|
31655
31499
|
}),
|
|
31656
|
-
interactiveElementsDescription:
|
|
31657
|
-
state: state
|
|
31658
|
-
})
|
|
31500
|
+
interactiveElementsDescription: getLinearGraphDescription(state, i18n)
|
|
31659
31501
|
};
|
|
31660
31502
|
}
|
|
31661
31503
|
const LinearGraph = (props, key) => {
|
|
@@ -31720,13 +31562,7 @@ const LinearGraph = (props, key) => {
|
|
|
31720
31562
|
style: a11y.srOnly
|
|
31721
31563
|
}, slopeString));
|
|
31722
31564
|
};
|
|
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();
|
|
31565
|
+
function getLinearGraphDescription(state, i18n) {
|
|
31730
31566
|
const strings = describeLinearGraph(state, i18n);
|
|
31731
31567
|
return strings.srLinearInteractiveElement;
|
|
31732
31568
|
}
|
|
@@ -31770,15 +31606,13 @@ function describeLinearGraph(state, i18n) {
|
|
|
31770
31606
|
};
|
|
31771
31607
|
}
|
|
31772
31608
|
|
|
31773
|
-
function renderLinearSystemGraph(state, dispatch) {
|
|
31609
|
+
function renderLinearSystemGraph(state, dispatch, i18n) {
|
|
31774
31610
|
return {
|
|
31775
31611
|
graph: /*#__PURE__*/React.createElement(LinearSystemGraph, {
|
|
31776
31612
|
graphState: state,
|
|
31777
31613
|
dispatch: dispatch
|
|
31778
31614
|
}),
|
|
31779
|
-
interactiveElementsDescription:
|
|
31780
|
-
state: state
|
|
31781
|
-
})
|
|
31615
|
+
interactiveElementsDescription: getLinearSystemGraphDescription(state, i18n)
|
|
31782
31616
|
};
|
|
31783
31617
|
}
|
|
31784
31618
|
const LinearSystemGraph = props => {
|
|
@@ -31865,18 +31699,9 @@ const LinearSystemGraph = props => {
|
|
|
31865
31699
|
style: a11y.srOnly
|
|
31866
31700
|
}, slopeDescription))));
|
|
31867
31701
|
};
|
|
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
31702
|
|
|
31878
31703
|
// Exported for testing
|
|
31879
|
-
function
|
|
31704
|
+
function getLinearSystemGraphDescription(state, i18n) {
|
|
31880
31705
|
const {
|
|
31881
31706
|
strings,
|
|
31882
31707
|
locale
|
|
@@ -31902,15 +31727,13 @@ function describeLinearSystemGraph(state, i18n) {
|
|
|
31902
31727
|
});
|
|
31903
31728
|
}
|
|
31904
31729
|
|
|
31905
|
-
function renderPointGraph(state, dispatch) {
|
|
31730
|
+
function renderPointGraph(state, dispatch, i18n) {
|
|
31906
31731
|
return {
|
|
31907
31732
|
graph: /*#__PURE__*/React.createElement(PointGraph, {
|
|
31908
31733
|
graphState: state,
|
|
31909
31734
|
dispatch: dispatch
|
|
31910
31735
|
}),
|
|
31911
|
-
interactiveElementsDescription:
|
|
31912
|
-
state: state
|
|
31913
|
-
})
|
|
31736
|
+
interactiveElementsDescription: getPointGraphDescription(state, i18n)
|
|
31914
31737
|
};
|
|
31915
31738
|
}
|
|
31916
31739
|
function PointGraph(props) {
|
|
@@ -31933,7 +31756,9 @@ function PointGraph(props) {
|
|
|
31933
31756
|
var _pointsRef$current$fo;
|
|
31934
31757
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
31935
31758
|
}
|
|
31936
|
-
}, [props.graphState.focusedPointIndex,
|
|
31759
|
+
}, [props.graphState.focusedPointIndex,
|
|
31760
|
+
// Ensure that we re-focus if a point is deleted.
|
|
31761
|
+
props.graphState.coords.length, pointsRef]);
|
|
31937
31762
|
const statefulProps = _extends({}, props, {
|
|
31938
31763
|
graphConfig,
|
|
31939
31764
|
pointsRef,
|
|
@@ -32004,17 +31829,9 @@ function UnlimitedPointGraph(statefulProps) {
|
|
|
32004
31829
|
}
|
|
32005
31830
|
})));
|
|
32006
31831
|
}
|
|
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
31832
|
|
|
32016
31833
|
// Exported for testing
|
|
32017
|
-
function
|
|
31834
|
+
function getPointGraphDescription(state, i18n) {
|
|
32018
31835
|
const {
|
|
32019
31836
|
strings,
|
|
32020
31837
|
locale
|
|
@@ -32101,7 +31918,9 @@ const PolygonGraph = props => {
|
|
|
32101
31918
|
var _pointsRef$current$fo;
|
|
32102
31919
|
(_pointsRef$current$fo = pointsRef.current[focusedIndex]) == null || _pointsRef$current$fo.focus();
|
|
32103
31920
|
}
|
|
32104
|
-
}, [props.graphState.focusedPointIndex,
|
|
31921
|
+
}, [props.graphState.focusedPointIndex,
|
|
31922
|
+
// Ensure that we re-focus if a point is deleted.
|
|
31923
|
+
props.graphState.coords.length, pointsRef]);
|
|
32105
31924
|
|
|
32106
31925
|
// If the unlimited polygon is rendered with 3 or more coordinates
|
|
32107
31926
|
// Close the polygon, but only on first render.
|
|
@@ -32681,15 +32500,13 @@ function describeQuadraticGraph(state, i18n) {
|
|
|
32681
32500
|
};
|
|
32682
32501
|
}
|
|
32683
32502
|
|
|
32684
|
-
function renderRayGraph(state, dispatch) {
|
|
32503
|
+
function renderRayGraph(state, dispatch, i18n) {
|
|
32685
32504
|
return {
|
|
32686
32505
|
graph: /*#__PURE__*/React.createElement(RayGraph, {
|
|
32687
32506
|
graphState: state,
|
|
32688
32507
|
dispatch: dispatch
|
|
32689
32508
|
}),
|
|
32690
|
-
interactiveElementsDescription:
|
|
32691
|
-
state: state
|
|
32692
|
-
})
|
|
32509
|
+
interactiveElementsDescription: getRayGraphDescription(state, i18n)
|
|
32693
32510
|
};
|
|
32694
32511
|
}
|
|
32695
32512
|
const RayGraph = props => {
|
|
@@ -32743,13 +32560,7 @@ const RayGraph = props => {
|
|
|
32743
32560
|
style: a11y.srOnly
|
|
32744
32561
|
}, srRayPoints));
|
|
32745
32562
|
};
|
|
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();
|
|
32563
|
+
function getRayGraphDescription(state, i18n) {
|
|
32753
32564
|
const strings = describeRayGraph(state, i18n);
|
|
32754
32565
|
return strings.srRayInteractiveElement;
|
|
32755
32566
|
}
|
|
@@ -32799,15 +32610,13 @@ function describeRayGraph(state, i18n) {
|
|
|
32799
32610
|
};
|
|
32800
32611
|
}
|
|
32801
32612
|
|
|
32802
|
-
function renderSegmentGraph(state, dispatch) {
|
|
32613
|
+
function renderSegmentGraph(state, dispatch, i18n) {
|
|
32803
32614
|
return {
|
|
32804
32615
|
graph: /*#__PURE__*/React.createElement(SegmentGraph, {
|
|
32805
32616
|
graphState: state,
|
|
32806
32617
|
dispatch: dispatch
|
|
32807
32618
|
}),
|
|
32808
|
-
interactiveElementsDescription:
|
|
32809
|
-
state: state
|
|
32810
|
-
})
|
|
32619
|
+
interactiveElementsDescription: getSegmentGraphDescription(state, i18n)
|
|
32811
32620
|
};
|
|
32812
32621
|
}
|
|
32813
32622
|
const SegmentGraph = ({
|
|
@@ -32899,18 +32708,9 @@ const SegmentGraph = ({
|
|
|
32899
32708
|
function getLengthOfSegment(segment) {
|
|
32900
32709
|
return point.distanceToPoint(...segment);
|
|
32901
32710
|
}
|
|
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
32711
|
|
|
32912
32712
|
// Exported for testing
|
|
32913
|
-
function
|
|
32713
|
+
function getSegmentGraphDescription(state, i18n) {
|
|
32914
32714
|
const {
|
|
32915
32715
|
strings,
|
|
32916
32716
|
locale
|
|
@@ -32927,13 +32727,13 @@ function describeSegmentGraph(state, i18n) {
|
|
|
32927
32727
|
});
|
|
32928
32728
|
}
|
|
32929
32729
|
|
|
32930
|
-
function renderSinusoidGraph(state, dispatch) {
|
|
32730
|
+
function renderSinusoidGraph(state, dispatch, i18n) {
|
|
32931
32731
|
return {
|
|
32932
32732
|
graph: /*#__PURE__*/React.createElement(SinusoidGraph, {
|
|
32933
32733
|
graphState: state,
|
|
32934
32734
|
dispatch: dispatch
|
|
32935
32735
|
}),
|
|
32936
|
-
interactiveElementsDescription:
|
|
32736
|
+
interactiveElementsDescription: getSinusoidDescription(state, i18n)
|
|
32937
32737
|
};
|
|
32938
32738
|
}
|
|
32939
32739
|
function SinusoidGraph(props) {
|
|
@@ -32941,6 +32741,9 @@ function SinusoidGraph(props) {
|
|
|
32941
32741
|
dispatch,
|
|
32942
32742
|
graphState
|
|
32943
32743
|
} = props;
|
|
32744
|
+
const i18n = usePerseusI18n();
|
|
32745
|
+
const id = React.useId();
|
|
32746
|
+
const descriptionId = id + "-description";
|
|
32944
32747
|
|
|
32945
32748
|
// Destructure the coordinates from the graph state
|
|
32946
32749
|
// Note: The order of the coordinates is important:
|
|
@@ -32965,15 +32768,30 @@ function SinusoidGraph(props) {
|
|
|
32965
32768
|
if (coeffs !== undefined) {
|
|
32966
32769
|
coeffRef.current = coeffs;
|
|
32967
32770
|
}
|
|
32968
|
-
|
|
32771
|
+
|
|
32772
|
+
// Aria strings
|
|
32773
|
+
const {
|
|
32774
|
+
srSinusoidGraph,
|
|
32775
|
+
srSinusoidDescription,
|
|
32776
|
+
srSinusoidRootPoint,
|
|
32777
|
+
srSinusoidPeakPoint
|
|
32778
|
+
} = describeSinusoidGraph(graphState, i18n);
|
|
32779
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
32780
|
+
// Outer graph minimal description
|
|
32781
|
+
"aria-label": srSinusoidGraph,
|
|
32782
|
+
"aria-describedby": descriptionId
|
|
32783
|
+
}, /*#__PURE__*/React.createElement(Plot$2.OfX, {
|
|
32969
32784
|
y: x => computeSine(x, coeffRef.current),
|
|
32970
32785
|
color: color.blue
|
|
32971
32786
|
}), coords.map((coord, i) => /*#__PURE__*/React.createElement(MovablePoint$1, {
|
|
32787
|
+
ariaLabel: i === 0 ? srSinusoidRootPoint : srSinusoidPeakPoint,
|
|
32972
32788
|
key: "point-" + i,
|
|
32973
32789
|
point: coord,
|
|
32974
32790
|
sequenceNumber: i + 1,
|
|
32975
32791
|
onMove: destination => dispatch(actions.sinusoid.movePoint(i, destination))
|
|
32976
|
-
}))
|
|
32792
|
+
})), /*#__PURE__*/React.createElement("g", {
|
|
32793
|
+
id: descriptionId
|
|
32794
|
+
}, srSinusoidDescription));
|
|
32977
32795
|
}
|
|
32978
32796
|
|
|
32979
32797
|
// Plot a sinusoid of the form: f(x) = a * sin(b * x - c) + d
|
|
@@ -33011,6 +32829,52 @@ const getSinusoidCoefficients$1 = coords => {
|
|
|
33011
32829
|
verticalOffset
|
|
33012
32830
|
};
|
|
33013
32831
|
};
|
|
32832
|
+
function getSinusoidDescription(state, i18n) {
|
|
32833
|
+
const strings = describeSinusoidGraph(state, i18n);
|
|
32834
|
+
return strings.srSinusoidInteractiveElements;
|
|
32835
|
+
}
|
|
32836
|
+
function describeSinusoidGraph(state, i18n) {
|
|
32837
|
+
const {
|
|
32838
|
+
strings,
|
|
32839
|
+
locale
|
|
32840
|
+
} = i18n;
|
|
32841
|
+
const {
|
|
32842
|
+
coords
|
|
32843
|
+
} = state;
|
|
32844
|
+
const [root, peak] = coords;
|
|
32845
|
+
const diffX = Math.abs(peak[X] - root[X]);
|
|
32846
|
+
const diffY = Math.abs(peak[Y] - root[Y]);
|
|
32847
|
+
const srSinusoidGraph = strings.srSinusoidGraph;
|
|
32848
|
+
const srSinusoidDescription = strings.srSinusoidDescription({
|
|
32849
|
+
minValue: srFormatNumber(root[Y] - diffY, locale),
|
|
32850
|
+
maxValue: srFormatNumber(root[Y] + diffY, locale),
|
|
32851
|
+
cycleStart: srFormatNumber(root[X] - 2 * diffX, locale),
|
|
32852
|
+
cycleEnd: srFormatNumber(root[X] + 2 * diffX, locale)
|
|
32853
|
+
});
|
|
32854
|
+
const srSinusoidRootPoint = strings.srSinusoidRootPoint({
|
|
32855
|
+
x: srFormatNumber(root[X], locale),
|
|
32856
|
+
y: srFormatNumber(root[Y], locale)
|
|
32857
|
+
});
|
|
32858
|
+
const srSinusoidPeakPoint = strings.srSinusoidPeakPoint({
|
|
32859
|
+
x: srFormatNumber(peak[X], locale),
|
|
32860
|
+
y: srFormatNumber(peak[Y], locale)
|
|
32861
|
+
});
|
|
32862
|
+
const srSinusoidInteractiveElements = strings.srInteractiveElements({
|
|
32863
|
+
elements: strings.srSinusoidInteractiveElements({
|
|
32864
|
+
point1X: srFormatNumber(root[X], locale),
|
|
32865
|
+
point1Y: srFormatNumber(root[Y], locale),
|
|
32866
|
+
point2X: srFormatNumber(peak[X], locale),
|
|
32867
|
+
point2Y: srFormatNumber(peak[Y], locale)
|
|
32868
|
+
})
|
|
32869
|
+
});
|
|
32870
|
+
return {
|
|
32871
|
+
srSinusoidGraph,
|
|
32872
|
+
srSinusoidDescription,
|
|
32873
|
+
srSinusoidRootPoint,
|
|
32874
|
+
srSinusoidPeakPoint,
|
|
32875
|
+
srSinusoidInteractiveElements
|
|
32876
|
+
};
|
|
32877
|
+
}
|
|
33014
32878
|
|
|
33015
32879
|
const {
|
|
33016
32880
|
calculateAngleInDegrees,
|
|
@@ -33181,6 +33045,7 @@ const MafsGraph = props => {
|
|
|
33181
33045
|
const descriptionId = `interactive-graph-description-${uniqueId}`;
|
|
33182
33046
|
const interactiveElementsDescriptionId = `interactive-graph-interactive-elements-description-${uniqueId}`;
|
|
33183
33047
|
const unlimitedGraphKeyboardPromptId = `unlimited-graph-keyboard-prompt-${uniqueId}`;
|
|
33048
|
+
const instructionsId = `instructions-${uniqueId}`;
|
|
33184
33049
|
const graphRef = React.useRef(null);
|
|
33185
33050
|
const {
|
|
33186
33051
|
analytics
|
|
@@ -33208,6 +33073,7 @@ const MafsGraph = props => {
|
|
|
33208
33073
|
const interactionPrompt = isUnlimitedGraphState(state) && state.showKeyboardInteractionInvitation;
|
|
33209
33074
|
useOnMountEffect(() => {
|
|
33210
33075
|
analytics.onAnalyticsEvent({
|
|
33076
|
+
// TODO(LEMS-2827): Remove analytics event in LEMS-2827 in favor of ti below.
|
|
33211
33077
|
type: "perseus:interactive-graph-widget:rendered",
|
|
33212
33078
|
payload: {
|
|
33213
33079
|
type,
|
|
@@ -33215,6 +33081,14 @@ const MafsGraph = props => {
|
|
|
33215
33081
|
widgetId: "interactive-graph"
|
|
33216
33082
|
}
|
|
33217
33083
|
});
|
|
33084
|
+
analytics.onAnalyticsEvent({
|
|
33085
|
+
type: "perseus:widget:rendered:ti",
|
|
33086
|
+
payload: {
|
|
33087
|
+
widgetSubType: type,
|
|
33088
|
+
widgetType: "INTERACTIVE_GRAPH",
|
|
33089
|
+
widgetId: "interactive-graph"
|
|
33090
|
+
}
|
|
33091
|
+
});
|
|
33218
33092
|
});
|
|
33219
33093
|
const {
|
|
33220
33094
|
graph,
|
|
@@ -33258,7 +33132,7 @@ const MafsGraph = props => {
|
|
|
33258
33132
|
handleKeyboardEvent(event, state, dispatch);
|
|
33259
33133
|
},
|
|
33260
33134
|
"aria-label": fullGraphAriaLabel,
|
|
33261
|
-
"aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId),
|
|
33135
|
+
"aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && unlimitedGraphKeyboardPromptId, state.type !== "none" && instructionsId),
|
|
33262
33136
|
ref: graphRef,
|
|
33263
33137
|
tabIndex: 0,
|
|
33264
33138
|
onFocus: event => {
|
|
@@ -33275,7 +33149,11 @@ const MafsGraph = props => {
|
|
|
33275
33149
|
id: interactiveElementsDescriptionId,
|
|
33276
33150
|
tabIndex: -1,
|
|
33277
33151
|
className: "mafs-sr-only"
|
|
33278
|
-
}, interactiveElementsDescription), /*#__PURE__*/React.createElement(
|
|
33152
|
+
}, interactiveElementsDescription), state.type !== "none" && /*#__PURE__*/React.createElement(View, {
|
|
33153
|
+
id: instructionsId,
|
|
33154
|
+
tabIndex: -1,
|
|
33155
|
+
className: "mafs-sr-only"
|
|
33156
|
+
}, isUnlimitedGraphState(state) ? strings.srUnlimitedGraphInstructions : strings.srGraphInstructions), /*#__PURE__*/React.createElement(LegacyGrid, {
|
|
33279
33157
|
box: props.box,
|
|
33280
33158
|
backgroundImage: props.backgroundImage
|
|
33281
33159
|
}), /*#__PURE__*/React.createElement(View, {
|
|
@@ -33284,7 +33162,9 @@ const MafsGraph = props => {
|
|
|
33284
33162
|
bottom: 0,
|
|
33285
33163
|
left: 0
|
|
33286
33164
|
}
|
|
33287
|
-
}, (props.markings === "graph" || props.markings === "axes") && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels,
|
|
33165
|
+
}, (props.markings === "graph" || props.markings === "axes") && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels, {
|
|
33166
|
+
i18n: i18n
|
|
33167
|
+
})), /*#__PURE__*/React.createElement(View
|
|
33288
33168
|
// If we have locked figures, we set aria-hidden
|
|
33289
33169
|
// to false so that screen readers can read the
|
|
33290
33170
|
// locked figures. If we don't have any locked
|
|
@@ -33622,25 +33502,25 @@ const renderGraphElements = props => {
|
|
|
33622
33502
|
} = state;
|
|
33623
33503
|
switch (type) {
|
|
33624
33504
|
case "angle":
|
|
33625
|
-
return renderAngleGraph(state, dispatch);
|
|
33505
|
+
return renderAngleGraph(state, dispatch, i18n);
|
|
33626
33506
|
case "segment":
|
|
33627
|
-
return renderSegmentGraph(state, dispatch);
|
|
33507
|
+
return renderSegmentGraph(state, dispatch, i18n);
|
|
33628
33508
|
case "linear-system":
|
|
33629
|
-
return renderLinearSystemGraph(state, dispatch);
|
|
33509
|
+
return renderLinearSystemGraph(state, dispatch, i18n);
|
|
33630
33510
|
case "linear":
|
|
33631
|
-
return renderLinearGraph(state, dispatch);
|
|
33511
|
+
return renderLinearGraph(state, dispatch, i18n);
|
|
33632
33512
|
case "ray":
|
|
33633
|
-
return renderRayGraph(state, dispatch);
|
|
33513
|
+
return renderRayGraph(state, dispatch, i18n);
|
|
33634
33514
|
case "polygon":
|
|
33635
33515
|
return renderPolygonGraph(state, dispatch, i18n, markings);
|
|
33636
33516
|
case "point":
|
|
33637
|
-
return renderPointGraph(state, dispatch);
|
|
33517
|
+
return renderPointGraph(state, dispatch, i18n);
|
|
33638
33518
|
case "circle":
|
|
33639
|
-
return renderCircleGraph(state, dispatch);
|
|
33519
|
+
return renderCircleGraph(state, dispatch, i18n);
|
|
33640
33520
|
case "quadratic":
|
|
33641
33521
|
return renderQuadraticGraph(state, dispatch, i18n);
|
|
33642
33522
|
case "sinusoid":
|
|
33643
|
-
return renderSinusoidGraph(state, dispatch);
|
|
33523
|
+
return renderSinusoidGraph(state, dispatch, i18n);
|
|
33644
33524
|
case "none":
|
|
33645
33525
|
return {
|
|
33646
33526
|
graph: null,
|
|
@@ -34037,13 +33917,13 @@ const {
|
|
|
34037
33917
|
polar
|
|
34038
33918
|
} = angles;
|
|
34039
33919
|
const {
|
|
34040
|
-
angleMeasures
|
|
34041
|
-
ccw
|
|
34042
|
-
lawOfCosines
|
|
33920
|
+
angleMeasures,
|
|
33921
|
+
ccw,
|
|
33922
|
+
lawOfCosines,
|
|
34043
33923
|
magnitude: magnitude$1,
|
|
34044
33924
|
polygonSidesIntersect,
|
|
34045
33925
|
reverseVector,
|
|
34046
|
-
sign
|
|
33926
|
+
sign,
|
|
34047
33927
|
vector: vector$1
|
|
34048
33928
|
} = geometry;
|
|
34049
33929
|
const {
|
|
@@ -34527,7 +34407,7 @@ function doAddPoint(state, action) {
|
|
|
34527
34407
|
return _extends({}, state, {
|
|
34528
34408
|
hasBeenInteractedWith: true,
|
|
34529
34409
|
coords: newCoords,
|
|
34530
|
-
showRemovePointButton:
|
|
34410
|
+
showRemovePointButton: true,
|
|
34531
34411
|
focusedPointIndex: newCoords.length - 1
|
|
34532
34412
|
});
|
|
34533
34413
|
}
|
|
@@ -34535,16 +34415,11 @@ function doRemovePoint(state, action) {
|
|
|
34535
34415
|
if (!isUnlimitedGraphState(state)) {
|
|
34536
34416
|
return state;
|
|
34537
34417
|
}
|
|
34538
|
-
|
|
34539
|
-
if (state.interactionMode === "mouse") {
|
|
34540
|
-
nextFocusedPointIndex = null;
|
|
34541
|
-
} else {
|
|
34542
|
-
nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
|
|
34543
|
-
}
|
|
34418
|
+
const nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
|
|
34544
34419
|
return _extends({}, state, {
|
|
34545
34420
|
coords: state.coords.filter((_, i) => i !== action.index),
|
|
34546
34421
|
focusedPointIndex: nextFocusedPointIndex,
|
|
34547
|
-
showRemovePointButton: false
|
|
34422
|
+
showRemovePointButton: nextFocusedPointIndex !== null ? true : false
|
|
34548
34423
|
});
|
|
34549
34424
|
}
|
|
34550
34425
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
@@ -34568,7 +34443,7 @@ const getChange = (coords, delta, constraintOpts) => {
|
|
|
34568
34443
|
return [dx, dy];
|
|
34569
34444
|
};
|
|
34570
34445
|
// Less than or approximately equal
|
|
34571
|
-
function leq
|
|
34446
|
+
function leq(a, b) {
|
|
34572
34447
|
return a < b || approximateEqual(a, b);
|
|
34573
34448
|
}
|
|
34574
34449
|
function boundAndSnapToGrid(point, {
|
|
@@ -34713,7 +34588,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34713
34588
|
});
|
|
34714
34589
|
|
|
34715
34590
|
// Gets the radian angles between the coords and maps them to degrees
|
|
34716
|
-
const angles = angleMeasures
|
|
34591
|
+
const angles = angleMeasures(coordsCopy).map(angle => angle * 180 / Math.PI);
|
|
34717
34592
|
|
|
34718
34593
|
// Gets the relative index of a point
|
|
34719
34594
|
const rel = j => {
|
|
@@ -34733,7 +34608,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34733
34608
|
|
|
34734
34609
|
// Avoid degenerate triangles
|
|
34735
34610
|
if (innerAngles.some(function (angle) {
|
|
34736
|
-
return leq
|
|
34611
|
+
return leq(angle, 1);
|
|
34737
34612
|
})) {
|
|
34738
34613
|
return startingPoint;
|
|
34739
34614
|
}
|
|
@@ -34747,7 +34622,7 @@ function boundAndSnapToPolygonAngle(destinationPoint, {
|
|
|
34747
34622
|
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
34748
34623
|
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
34749
34624
|
// for is then used in the polar function to determine the new point.
|
|
34750
|
-
const onLeft = sign
|
|
34625
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
34751
34626
|
|
|
34752
34627
|
// Solve for side by using the law of sines
|
|
34753
34628
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
@@ -34794,13 +34669,13 @@ function boundAndSnapToSides(destinationPoint, {
|
|
|
34794
34669
|
});
|
|
34795
34670
|
|
|
34796
34671
|
// Avoid degenerate triangles
|
|
34797
|
-
if (leq
|
|
34672
|
+
if (leq(sides[1] + sides[2], sides[0]) || leq(sides[0] + sides[2], sides[1]) || leq(sides[0] + sides[1], sides[2])) {
|
|
34798
34673
|
return startingPoint;
|
|
34799
34674
|
}
|
|
34800
34675
|
|
|
34801
34676
|
// Solve for angle by using the law of cosines
|
|
34802
34677
|
// Angle at the first vertex of the polygon
|
|
34803
|
-
const innerAngle = lawOfCosines
|
|
34678
|
+
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
34804
34679
|
|
|
34805
34680
|
// Angle at the second vertex of the polygon
|
|
34806
34681
|
const outerAngle = getAngleFromVertex(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
@@ -34811,7 +34686,7 @@ function boundAndSnapToSides(destinationPoint, {
|
|
|
34811
34686
|
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
34812
34687
|
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
34813
34688
|
// for is then used in the polar function to determine the new point.
|
|
34814
|
-
const onLeft = sign
|
|
34689
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
34815
34690
|
|
|
34816
34691
|
// Uses the length of the first side of the polygon (radial coordinate)
|
|
34817
34692
|
// and the angle between the first and second sides of the
|
|
@@ -34946,19 +34821,11 @@ const {
|
|
|
34946
34821
|
getClockwiseAngle
|
|
34947
34822
|
} = angles;
|
|
34948
34823
|
const {
|
|
34949
|
-
angleMeasures,
|
|
34950
|
-
ccw,
|
|
34951
|
-
collinear,
|
|
34952
34824
|
getLineEquation,
|
|
34953
34825
|
getLineIntersection,
|
|
34954
|
-
intersects,
|
|
34955
|
-
lawOfCosines,
|
|
34956
34826
|
magnitude,
|
|
34957
|
-
rotate,
|
|
34958
|
-
sign,
|
|
34959
34827
|
vector
|
|
34960
34828
|
} = geometry;
|
|
34961
|
-
const TRASH_ICON_URI = "https://ka-perseus-graphie.s3.amazonaws.com/b1452c0d79fd0f7ff4c3af9488474a0a0decb361.png";
|
|
34962
34829
|
const defaultBackgroundImage = {
|
|
34963
34830
|
url: null
|
|
34964
34831
|
};
|
|
@@ -34967,31 +34834,9 @@ const UNLIMITED = "unlimited";
|
|
|
34967
34834
|
// Sample background image:
|
|
34968
34835
|
// https://ka-perseus-graphie.s3.amazonaws.com/29c1b0fcd17fe63df0f148fe357044d5d5c7d0bb.png
|
|
34969
34836
|
|
|
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
34837
|
function numSteps(range, step) {
|
|
34985
34838
|
return Math.floor((range[1] - range[0]) / step);
|
|
34986
34839
|
}
|
|
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
34840
|
const makeInvalidTypeError = (functionName, graphType) => {
|
|
34996
34841
|
return new PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, Errors.NotAllowed, {
|
|
34997
34842
|
metadata: {
|
|
@@ -35032,1236 +34877,16 @@ function getQuadraticCoefficients(coords) {
|
|
|
35032
34877
|
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
34878
|
return [a, b, c];
|
|
35034
34879
|
}
|
|
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
34880
|
class InteractiveGraph extends React.Component {
|
|
36252
34881
|
constructor(...args) {
|
|
36253
34882
|
super(...args);
|
|
36254
|
-
this.legacyGraphRef = /*#__PURE__*/React.createRef();
|
|
36255
34883
|
this.mafsRef = /*#__PURE__*/React.createRef();
|
|
36256
34884
|
}
|
|
36257
34885
|
getUserInput() {
|
|
36258
|
-
var _this$mafsRef$current
|
|
34886
|
+
var _this$mafsRef$current;
|
|
36259
34887
|
if ((_this$mafsRef$current = this.mafsRef.current) != null && _this$mafsRef$current.getUserInput) {
|
|
36260
34888
|
return this.mafsRef.current.getUserInput();
|
|
36261
34889
|
}
|
|
36262
|
-
if ((_this$legacyGraphRef$ = this.legacyGraphRef.current) != null && _this$legacyGraphRef$.getUserInput) {
|
|
36263
|
-
return this.legacyGraphRef.current.getUserInput();
|
|
36264
|
-
}
|
|
36265
34890
|
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
36266
34891
|
}
|
|
36267
34892
|
getPromptJSON() {
|
|
@@ -36456,8 +35081,32 @@ class InteractiveGraph extends React.Component {
|
|
|
36456
35081
|
}
|
|
36457
35082
|
static getEquationString(props) {
|
|
36458
35083
|
const type = props.graph.type;
|
|
36459
|
-
|
|
36460
|
-
|
|
35084
|
+
switch (type) {
|
|
35085
|
+
case "none":
|
|
35086
|
+
return InteractiveGraph.getNoneEquationString();
|
|
35087
|
+
case "linear":
|
|
35088
|
+
return InteractiveGraph.getLinearEquationString(props);
|
|
35089
|
+
case "quadratic":
|
|
35090
|
+
return InteractiveGraph.getQuadraticEquationString(props);
|
|
35091
|
+
case "sinusoid":
|
|
35092
|
+
return InteractiveGraph.getSinusoidEquationString(props);
|
|
35093
|
+
case "circle":
|
|
35094
|
+
return InteractiveGraph.getCircleEquationString(props);
|
|
35095
|
+
case "linear-system":
|
|
35096
|
+
return InteractiveGraph.getLinearSystemEquationString(props);
|
|
35097
|
+
case "point":
|
|
35098
|
+
return InteractiveGraph.getPointEquationString(props);
|
|
35099
|
+
case "segment":
|
|
35100
|
+
return InteractiveGraph.getSegmentEquationString(props);
|
|
35101
|
+
case "ray":
|
|
35102
|
+
return InteractiveGraph.getRayEquationString(props);
|
|
35103
|
+
case "polygon":
|
|
35104
|
+
return InteractiveGraph.getPolygonEquationString(props);
|
|
35105
|
+
case "angle":
|
|
35106
|
+
return InteractiveGraph.getAngleEquationString(props);
|
|
35107
|
+
default:
|
|
35108
|
+
throw new UnreachableCaseError(type);
|
|
35109
|
+
}
|
|
36461
35110
|
}
|
|
36462
35111
|
static pointsFromNormalized(props, coordsList, noSnap) {
|
|
36463
35112
|
// @ts-expect-error - TS2322 - Type 'number[][]' is not assignable to type 'readonly Coord[]'.
|
|
@@ -36613,8 +35262,7 @@ var InteractiveGraph$1 = {
|
|
|
36613
35262
|
name: "interactive-graph",
|
|
36614
35263
|
displayName: "Interactive graph (Assessments only)",
|
|
36615
35264
|
widget: InteractiveGraph,
|
|
36616
|
-
staticTransform: staticTransform$3
|
|
36617
|
-
getPublicWidgetOptions: getInteractiveGraphPublicWidgetOptions
|
|
35265
|
+
staticTransform: staticTransform$3
|
|
36618
35266
|
};
|
|
36619
35267
|
|
|
36620
35268
|
// TODO: can we use WB typography?
|
|
@@ -37241,11 +35889,16 @@ class LabelImage extends React.Component {
|
|
|
37241
35889
|
});
|
|
37242
35890
|
}
|
|
37243
35891
|
activateMarker(index, opened) {
|
|
37244
|
-
var _this$props$analytics;
|
|
35892
|
+
var _this$props$analytics, _this$props$analytics2;
|
|
35893
|
+
// TODO(LEMS-2830): Remove analytics event in LEMS-2830 in favor of ti below.
|
|
37245
35894
|
(_this$props$analytics = this.props.analytics) == null || _this$props$analytics.onAnalyticsEvent({
|
|
37246
35895
|
type: "perseus:label-image:marker-interacted-with",
|
|
37247
35896
|
payload: null
|
|
37248
35897
|
});
|
|
35898
|
+
(_this$props$analytics2 = this.props.analytics) == null || _this$props$analytics2.onAnalyticsEvent({
|
|
35899
|
+
type: "perseus:label-image:marker-interacted-with:ti",
|
|
35900
|
+
payload: null
|
|
35901
|
+
});
|
|
37249
35902
|
const {
|
|
37250
35903
|
activeMarkerIndex
|
|
37251
35904
|
} = this.state;
|
|
@@ -37388,11 +36041,16 @@ class LabelImage extends React.Component {
|
|
|
37388
36041
|
})),
|
|
37389
36042
|
multipleSelect: this.props.multipleAnswers,
|
|
37390
36043
|
onChange: selection => {
|
|
37391
|
-
var _this$props$
|
|
37392
|
-
(
|
|
36044
|
+
var _this$props$analytics3, _this$props$analytics4;
|
|
36045
|
+
// TODO(LEMS-2829): Remove analytics event in LEMS-2829 in favor of ti below.
|
|
36046
|
+
(_this$props$analytics3 = this.props.analytics) == null || _this$props$analytics3.onAnalyticsEvent({
|
|
37393
36047
|
type: "perseus:label-image:choiced-interacted-with",
|
|
37394
36048
|
payload: null
|
|
37395
36049
|
});
|
|
36050
|
+
(_this$props$analytics4 = this.props.analytics) == null || _this$props$analytics4.onAnalyticsEvent({
|
|
36051
|
+
type: "perseus:label-image:choiced-interacted-with:ti",
|
|
36052
|
+
payload: null
|
|
36053
|
+
});
|
|
37396
36054
|
this.handleAnswerChoicesChangeForMarker(index, selection);
|
|
37397
36055
|
},
|
|
37398
36056
|
onToggle: opened => this.activateMarker(index, opened)
|
|
@@ -37488,11 +36146,16 @@ class LabelImage extends React.Component {
|
|
|
37488
36146
|
}))), this.renderMarkers()), /*#__PURE__*/React.createElement(HideAnswersToggle, {
|
|
37489
36147
|
areAnswersHidden: this.state.hideAnswers,
|
|
37490
36148
|
onChange: hideAnswers => {
|
|
37491
|
-
var _this$props$
|
|
37492
|
-
(
|
|
36149
|
+
var _this$props$analytics5, _this$props$analytics6;
|
|
36150
|
+
// TODO(LEMS-2831): Remove analytics event in LEMS-2831 in favor of ti below.
|
|
36151
|
+
(_this$props$analytics5 = this.props.analytics) == null || _this$props$analytics5.onAnalyticsEvent({
|
|
37493
36152
|
type: "perseus:label-image:toggle-answers-hidden",
|
|
37494
36153
|
payload: null
|
|
37495
36154
|
});
|
|
36155
|
+
(_this$props$analytics6 = this.props.analytics) == null || _this$props$analytics6.onAnalyticsEvent({
|
|
36156
|
+
type: "perseus:label-image:toggle-answers-hidden:ti",
|
|
36157
|
+
payload: null
|
|
36158
|
+
});
|
|
37496
36159
|
this.setState({
|
|
37497
36160
|
hideAnswers
|
|
37498
36161
|
});
|
|
@@ -37555,8 +36218,7 @@ var LabelImage$1 = {
|
|
|
37555
36218
|
displayName: "Label Image",
|
|
37556
36219
|
widget: LabelImageWithDependencies,
|
|
37557
36220
|
accessible: true,
|
|
37558
|
-
isLintable: true
|
|
37559
|
-
getPublicWidgetOptions: getLabelImagePublicWidgetOptions
|
|
36221
|
+
isLintable: true
|
|
37560
36222
|
};
|
|
37561
36223
|
|
|
37562
36224
|
var ItemState = /*#__PURE__*/function (ItemState) {
|
|
@@ -37811,20 +36473,24 @@ class Draggable extends React.Component {
|
|
|
37811
36473
|
if (this.props.margin != null) {
|
|
37812
36474
|
style.margin = this.props.margin;
|
|
37813
36475
|
}
|
|
37814
|
-
return
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37825
|
-
|
|
37826
|
-
|
|
37827
|
-
|
|
36476
|
+
return (
|
|
36477
|
+
/*#__PURE__*/
|
|
36478
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
36479
|
+
React.createElement("li", {
|
|
36480
|
+
className: className,
|
|
36481
|
+
style: style,
|
|
36482
|
+
onMouseDown: this.onMouseDown,
|
|
36483
|
+
onTouchStart: this.onMouseDown,
|
|
36484
|
+
onTouchMove: this.onMouseMove,
|
|
36485
|
+
onTouchEnd: this.onMouseUp,
|
|
36486
|
+
onTouchCancel: this.onMouseUp
|
|
36487
|
+
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
36488
|
+
content: this.props.content,
|
|
36489
|
+
linterContext: PerseusLinter.pushContextStack(this.props.linterContext, "draggable"),
|
|
36490
|
+
onRender: this.props.onRender,
|
|
36491
|
+
strings: this.context.strings
|
|
36492
|
+
}))
|
|
36493
|
+
);
|
|
37828
36494
|
}
|
|
37829
36495
|
}
|
|
37830
36496
|
Draggable.contextType = PerseusI18nContext;
|
|
@@ -38287,10 +36953,6 @@ const getPromptJSON$9 = (renderProps, userInput) => {
|
|
|
38287
36953
|
};
|
|
38288
36954
|
};
|
|
38289
36955
|
|
|
38290
|
-
const {
|
|
38291
|
-
shuffle: shuffle$1,
|
|
38292
|
-
seededRNG
|
|
38293
|
-
} = Util;
|
|
38294
36956
|
const HACKY_CSS_CLASSNAME = "perseus-widget-matcher";
|
|
38295
36957
|
class Matcher extends React.Component {
|
|
38296
36958
|
constructor(...args) {
|
|
@@ -38382,16 +37044,16 @@ class Matcher extends React.Component {
|
|
|
38382
37044
|
}, "1")));
|
|
38383
37045
|
}
|
|
38384
37046
|
|
|
38385
|
-
|
|
38386
|
-
|
|
38387
|
-
|
|
38388
|
-
|
|
38389
|
-
|
|
38390
|
-
|
|
38391
|
-
|
|
38392
|
-
left
|
|
38393
|
-
|
|
38394
|
-
|
|
37047
|
+
/* TODO(LEMS-2841):
|
|
37048
|
+
Once the getMatcherPublicWidgetOptions function gets connected to the
|
|
37049
|
+
widget, we'll need to update this to the line below to only shuffle
|
|
37050
|
+
on the server.
|
|
37051
|
+
const {left, right} = this.props;
|
|
37052
|
+
*/
|
|
37053
|
+
const {
|
|
37054
|
+
left,
|
|
37055
|
+
right
|
|
37056
|
+
} = shuffleMatcher(this.props);
|
|
38395
37057
|
const showLabels = _.any(this.props.labels);
|
|
38396
37058
|
const constraints = {
|
|
38397
37059
|
height: _.max([this.state.leftHeight, this.state.rightHeight])
|
|
@@ -38894,8 +37556,7 @@ var Matrix$1 = {
|
|
|
38894
37556
|
widget: Matrix,
|
|
38895
37557
|
transform: propTransform$1,
|
|
38896
37558
|
staticTransform: staticTransform$2,
|
|
38897
|
-
isLintable: true
|
|
38898
|
-
getPublicWidgetOptions: getMatrixPublicWidgetOptions
|
|
37559
|
+
isLintable: true
|
|
38899
37560
|
};
|
|
38900
37561
|
|
|
38901
37562
|
const getPromptJSON$7 = () => {
|
|
@@ -40468,8 +39129,7 @@ var NumberLine$1 = {
|
|
|
40468
39129
|
displayName: "Number line",
|
|
40469
39130
|
widget: NumberLine,
|
|
40470
39131
|
transform: numberLineTransform,
|
|
40471
|
-
staticTransform: staticTransform$1
|
|
40472
|
-
getPublicWidgetOptions: getNumberLinePublicWidgetOptions
|
|
39132
|
+
staticTransform: staticTransform$1
|
|
40473
39133
|
};
|
|
40474
39134
|
|
|
40475
39135
|
const getPromptJSON$5 = (renderProps, userInput) => {
|
|
@@ -40637,19 +39297,23 @@ class Card extends React.Component {
|
|
|
40637
39297
|
// Pull out the content to get rendered
|
|
40638
39298
|
const rendererProps = _.pick(this.props, "content");
|
|
40639
39299
|
const onMouseDown = this.props.animating ? $.noop : this.onMouseDown;
|
|
40640
|
-
return
|
|
40641
|
-
|
|
40642
|
-
|
|
40643
|
-
|
|
40644
|
-
|
|
40645
|
-
|
|
40646
|
-
|
|
40647
|
-
|
|
40648
|
-
|
|
40649
|
-
|
|
40650
|
-
|
|
40651
|
-
|
|
40652
|
-
|
|
39300
|
+
return (
|
|
39301
|
+
/*#__PURE__*/
|
|
39302
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO(LEMS-2871): Address a11y error
|
|
39303
|
+
React.createElement("div", {
|
|
39304
|
+
className: "card-wrap",
|
|
39305
|
+
style: style,
|
|
39306
|
+
onMouseDown: onMouseDown,
|
|
39307
|
+
onTouchStart: onMouseDown,
|
|
39308
|
+
onTouchEnd: this.onMouseUp,
|
|
39309
|
+
onTouchCancel: this.onMouseUp
|
|
39310
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
39311
|
+
className: className.join(" ")
|
|
39312
|
+
}, /*#__PURE__*/React.createElement(Renderer, _extends({}, rendererProps, {
|
|
39313
|
+
linterContext: this.props.linterContext,
|
|
39314
|
+
strings: this.context.strings
|
|
39315
|
+
}))))
|
|
39316
|
+
);
|
|
40653
39317
|
}
|
|
40654
39318
|
}
|
|
40655
39319
|
Card.contextType = PerseusI18nContext;
|
|
@@ -41029,8 +39693,7 @@ var Orderer$1 = {
|
|
|
41029
39693
|
displayName: "Orderer",
|
|
41030
39694
|
hidden: true,
|
|
41031
39695
|
widget: Orderer,
|
|
41032
|
-
isLintable: true
|
|
41033
|
-
getPublicWidgetOptions: getOrdererPublicWidgetOptions
|
|
39696
|
+
isLintable: true
|
|
41034
39697
|
};
|
|
41035
39698
|
|
|
41036
39699
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
@@ -42090,8 +40753,7 @@ var Plotter$1 = {
|
|
|
42090
40753
|
displayName: "Plotter",
|
|
42091
40754
|
hidden: true,
|
|
42092
40755
|
widget: Plotter,
|
|
42093
|
-
staticTransform: staticTransform
|
|
42094
|
-
getPublicWidgetOptions: getPlotterPublicWidgetOptions
|
|
40756
|
+
staticTransform: staticTransform
|
|
42095
40757
|
};
|
|
42096
40758
|
|
|
42097
40759
|
const getPromptJSON$2 = () => {
|
|
@@ -42167,9 +40829,6 @@ const getPromptJSON$1 = userInput => {
|
|
|
42167
40829
|
};
|
|
42168
40830
|
};
|
|
42169
40831
|
|
|
42170
|
-
const {
|
|
42171
|
-
shuffle
|
|
42172
|
-
} = Util;
|
|
42173
40832
|
class Sorter extends React.Component {
|
|
42174
40833
|
constructor(...args) {
|
|
42175
40834
|
super(...args);
|
|
@@ -42221,6 +40880,10 @@ class Sorter extends React.Component {
|
|
|
42221
40880
|
return getPromptJSON$1(this.getUserInput());
|
|
42222
40881
|
}
|
|
42223
40882
|
render() {
|
|
40883
|
+
// TODO(LEMS-2841): Remove client-side shuffle once receiving public
|
|
40884
|
+
// options. The correct field will already be shuffled.
|
|
40885
|
+
// Probably easiest to replace "options" with "this.props.correct" when
|
|
40886
|
+
// setting up Sortable below. Or use the assignment to rename for clarity.
|
|
42224
40887
|
const options = shuffle(this.props.correct, this.props.problemNum, /* ensurePermuted */true);
|
|
42225
40888
|
const {
|
|
42226
40889
|
apiOptions
|
|
@@ -42253,8 +40916,7 @@ var Sorter$1 = {
|
|
|
42253
40916
|
name: "sorter",
|
|
42254
40917
|
displayName: "Sorter",
|
|
42255
40918
|
widget: Sorter,
|
|
42256
|
-
isLintable: true
|
|
42257
|
-
getPublicWidgetOptions: getSorterPublicWidgetOptions
|
|
40919
|
+
isLintable: true
|
|
42258
40920
|
};
|
|
42259
40921
|
|
|
42260
40922
|
const {
|
|
@@ -42473,8 +41135,7 @@ var Table$1 = {
|
|
|
42473
41135
|
widget: Table,
|
|
42474
41136
|
transform: propTransform,
|
|
42475
41137
|
hidden: true,
|
|
42476
|
-
isLintable: true
|
|
42477
|
-
getPublicWidgetOptions: getTablePublicWidgetOptions
|
|
41138
|
+
isLintable: true
|
|
42478
41139
|
};
|
|
42479
41140
|
|
|
42480
41141
|
const getPromptJSON = () => {
|
|
@@ -42653,7 +41314,7 @@ const init = function init() {
|
|
|
42653
41314
|
|
|
42654
41315
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42655
41316
|
const libName = "@khanacademy/perseus";
|
|
42656
|
-
const libVersion = "
|
|
41317
|
+
const libVersion = "54.1.0";
|
|
42657
41318
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42658
41319
|
|
|
42659
41320
|
const apiVersion = {
|
|
@@ -44140,6 +42801,18 @@ function getWidgetTypeByWidgetId(WidgetId, widgetMap) {
|
|
|
44140
42801
|
const widget = widgetMap[WidgetId];
|
|
44141
42802
|
return (_widget$type = widget == null ? void 0 : widget.type) != null ? _widget$type : null;
|
|
44142
42803
|
}
|
|
42804
|
+
function getWidgetSubTypeByWidgetId(widgetId, widgetMap) {
|
|
42805
|
+
var _widget$type2, _graph$type;
|
|
42806
|
+
const widget = widgetMap[widgetId];
|
|
42807
|
+
const widgetType = (_widget$type2 = widget == null ? void 0 : widget.type) != null ? _widget$type2 : null;
|
|
42808
|
+
switch (widgetType) {
|
|
42809
|
+
case "interactive-graph":
|
|
42810
|
+
const graph = widget.options.graph;
|
|
42811
|
+
return (_graph$type = graph == null ? void 0 : graph.type) != null ? _graph$type : null;
|
|
42812
|
+
default:
|
|
42813
|
+
return null;
|
|
42814
|
+
}
|
|
42815
|
+
}
|
|
44143
42816
|
|
|
44144
42817
|
/**
|
|
44145
42818
|
* Does the content have a specific type of widget?
|
|
@@ -44932,5 +43605,5 @@ const ScoringUtil = {
|
|
|
44932
43605
|
* Types
|
|
44933
43606
|
*/
|
|
44934
43607
|
|
|
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 };
|
|
43608
|
+
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
43609
|
//# sourceMappingURL=index.js.map
|