@khanacademy/perseus 18.0.0 → 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/es/index.css +0 -24
- package/dist/es/index.js +83 -2497
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +0 -24
- package/dist/index.d.ts +0 -1
- package/dist/index.js +81 -2497
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +2 -109
- package/dist/strings.js +0 -29
- package/dist/types.d.ts +0 -4
- package/dist/widgets/expression.d.ts +2 -2
- package/dist/widgets.d.ts +1 -1
- package/package.json +8 -8
- package/src/__tests__/widgets.test.ts +0 -1
- package/src/extra-widgets.ts +0 -2
- package/src/index.ts +0 -1
- package/src/perseus-types.ts +1 -154
- package/src/styles/perseus-renderer.less +0 -1
- package/src/types.ts +0 -5
- package/src/util/register-all-widgets-for-testing.ts +1 -3
- package/src/widgets/__tests__/renderQuestion.tsx +11 -3
- package/src/widgets/label-image/answer-pill.tsx +6 -1
- package/src/widgets.ts +1 -9
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/widgets/transformer.d.ts +0 -94
- package/src/styles/widgets/transformer.less +0 -29
- package/src/widgets/__stories__/transformer.stories.tsx +0 -14
- package/src/widgets/__testdata__/transformer.testdata.ts +0 -107
- package/src/widgets/transformer.tsx +0 -2936
package/dist/index.js
CHANGED
|
@@ -2776,7 +2776,7 @@ function gridDimensionConfig(absTickStep, extent, dimensionConstraint, gridStep)
|
|
|
2776
2776
|
*
|
|
2777
2777
|
* TODO(somewhatabstract, FEI-3464): Consolidate query string parsing functions.
|
|
2778
2778
|
*/
|
|
2779
|
-
function getGridStep
|
|
2779
|
+
function getGridStep(range, step, boxSize) {
|
|
2780
2780
|
// @ts-expect-error - TS2322 - Type '(number | null | undefined)[]' is not assignable to type 'Coordinates'.
|
|
2781
2781
|
return ___default["default"](2).times(function (i) {
|
|
2782
2782
|
const scale = scaleFromExtent(range[i], boxSize);
|
|
@@ -2958,13 +2958,13 @@ function eq$2(x, y) {
|
|
|
2958
2958
|
* Deep approximate equality on primitives, numbers, arrays, and objects.
|
|
2959
2959
|
* Recursive.
|
|
2960
2960
|
*/
|
|
2961
|
-
function deepEq$
|
|
2961
|
+
function deepEq$5(x, y) {
|
|
2962
2962
|
if (Array.isArray(x) && Array.isArray(y)) {
|
|
2963
2963
|
if (x.length !== y.length) {
|
|
2964
2964
|
return false;
|
|
2965
2965
|
}
|
|
2966
2966
|
for (let i = 0; i < x.length; i++) {
|
|
2967
|
-
if (!deepEq$
|
|
2967
|
+
if (!deepEq$5(x[i], y[i])) {
|
|
2968
2968
|
return false;
|
|
2969
2969
|
}
|
|
2970
2970
|
}
|
|
@@ -2982,10 +2982,10 @@ function deepEq$6(x, y) {
|
|
|
2982
2982
|
if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
|
|
2983
2983
|
return x === y || ___default["default"].all(x, function (v, k) {
|
|
2984
2984
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
2985
|
-
return deepEq$
|
|
2985
|
+
return deepEq$5(y[k], v);
|
|
2986
2986
|
}) && ___default["default"].all(y, function (v, k) {
|
|
2987
2987
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
2988
|
-
return deepEq$
|
|
2988
|
+
return deepEq$5(x[k], v);
|
|
2989
2989
|
});
|
|
2990
2990
|
}
|
|
2991
2991
|
if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
|
|
@@ -3185,7 +3185,7 @@ const supportsPassiveEvents = () => {
|
|
|
3185
3185
|
* Pass this function as the touchstart for an element to
|
|
3186
3186
|
* avoid sending the touch to the mobile scratchpad
|
|
3187
3187
|
*/
|
|
3188
|
-
function captureScratchpadTouchStart$
|
|
3188
|
+
function captureScratchpadTouchStart$3(e) {
|
|
3189
3189
|
e.stopPropagation();
|
|
3190
3190
|
}
|
|
3191
3191
|
function getImageSize(url, callback) {
|
|
@@ -3273,7 +3273,7 @@ const Util = {
|
|
|
3273
3273
|
firstNumericalParse: firstNumericalParse$1,
|
|
3274
3274
|
stringArrayOfSize: stringArrayOfSize$1,
|
|
3275
3275
|
gridDimensionConfig,
|
|
3276
|
-
getGridStep
|
|
3276
|
+
getGridStep,
|
|
3277
3277
|
snapStepFromGridStep,
|
|
3278
3278
|
scaleFromExtent,
|
|
3279
3279
|
tickStepFromExtent,
|
|
@@ -3282,7 +3282,7 @@ const Util = {
|
|
|
3282
3282
|
constrainedTickStepsFromTickSteps,
|
|
3283
3283
|
DeprecationMixin: DeprecationMixin$1,
|
|
3284
3284
|
eq: eq$2,
|
|
3285
|
-
deepEq: deepEq$
|
|
3285
|
+
deepEq: deepEq$5,
|
|
3286
3286
|
parseQueryString,
|
|
3287
3287
|
updateQueryString: updateQueryString$2,
|
|
3288
3288
|
strongEncodeURIComponent,
|
|
@@ -3292,7 +3292,7 @@ const Util = {
|
|
|
3292
3292
|
resetTouchHandlers,
|
|
3293
3293
|
extractPointerLocation,
|
|
3294
3294
|
supportsPassiveEvents,
|
|
3295
|
-
captureScratchpadTouchStart: captureScratchpadTouchStart$
|
|
3295
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$3,
|
|
3296
3296
|
getImageSize,
|
|
3297
3297
|
getImageSizeModern: getImageSizeModern,
|
|
3298
3298
|
getRealImageUrl: getRealImageUrl,
|
|
@@ -13479,7 +13479,7 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
13479
13479
|
|
|
13480
13480
|
/* eslint-disable @babel/no-invalid-this */
|
|
13481
13481
|
const nestedMap$1 = Util.nestedMap;
|
|
13482
|
-
const deepEq$
|
|
13482
|
+
const deepEq$4 = Util.deepEq;
|
|
13483
13483
|
|
|
13484
13484
|
/**
|
|
13485
13485
|
* A base class for all Graphie Movables
|
|
@@ -13576,7 +13576,7 @@ const createSimpleClass = function (addFunction) {
|
|
|
13576
13576
|
this._prevProps = this.props;
|
|
13577
13577
|
},
|
|
13578
13578
|
modify: function (graphie) {
|
|
13579
|
-
if (!deepEq$
|
|
13579
|
+
if (!deepEq$4(this.props, this._prevProps)) {
|
|
13580
13580
|
this.remove();
|
|
13581
13581
|
this.add(graphie);
|
|
13582
13582
|
this._prevProps = this.props;
|
|
@@ -13621,7 +13621,7 @@ var GraphieClasses = {
|
|
|
13621
13621
|
* take appropriate action in onMoveStart, onMove, onMoveEnd
|
|
13622
13622
|
*/
|
|
13623
13623
|
const normalizeOptions$3 = InteractiveUtil.normalizeOptions;
|
|
13624
|
-
const assert$
|
|
13624
|
+
const assert$8 = InteractiveUtil.assert;
|
|
13625
13625
|
|
|
13626
13626
|
// state parameters that should be converted into an array of
|
|
13627
13627
|
// functions
|
|
@@ -13692,7 +13692,7 @@ ___default["default"].extend(Movable.prototype, {
|
|
|
13692
13692
|
* Simulates a mouse grab event on the movable object.
|
|
13693
13693
|
*/
|
|
13694
13694
|
grab: function (coord) {
|
|
13695
|
-
assert$
|
|
13695
|
+
assert$8(kmath.point.is(coord));
|
|
13696
13696
|
const self = this;
|
|
13697
13697
|
const graphie = self.graphie;
|
|
13698
13698
|
const state = self.state;
|
|
@@ -14158,7 +14158,7 @@ var MovableLineOptions = {
|
|
|
14158
14158
|
/**
|
|
14159
14159
|
* MovableLine
|
|
14160
14160
|
*/
|
|
14161
|
-
const assert$
|
|
14161
|
+
const assert$7 = InteractiveUtil.assert;
|
|
14162
14162
|
const normalizeOptions$2 = InteractiveUtil.normalizeOptions;
|
|
14163
14163
|
const FUNCTION_ARRAY_OPTIONS$2 = ["add", "draw", "remove", "onMoveStart", "constraints", "onMove", "onMoveEnd"];
|
|
14164
14164
|
|
|
@@ -14184,8 +14184,8 @@ const DEFAULT_STATE$2 = {
|
|
|
14184
14184
|
mouseTarget: null
|
|
14185
14185
|
};
|
|
14186
14186
|
const MovableLine$4 = function (graphie, movable, options) {
|
|
14187
|
-
assert$
|
|
14188
|
-
assert$
|
|
14187
|
+
assert$7(graphie != null);
|
|
14188
|
+
assert$7(options != null);
|
|
14189
14189
|
|
|
14190
14190
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
14191
14191
|
___default["default"].extend(this, {
|
|
@@ -14742,7 +14742,7 @@ var MovablePointOptions = {
|
|
|
14742
14742
|
}
|
|
14743
14743
|
};
|
|
14744
14744
|
|
|
14745
|
-
const assert$
|
|
14745
|
+
const assert$6 = InteractiveUtil.assert;
|
|
14746
14746
|
const normalizeOptions$1 = InteractiveUtil.normalizeOptions;
|
|
14747
14747
|
const {
|
|
14748
14748
|
processMath
|
|
@@ -14878,7 +14878,7 @@ ___default["default"].extend(MovablePoint$5.prototype, {
|
|
|
14878
14878
|
const self = this;
|
|
14879
14879
|
const graphie = self.graphie;
|
|
14880
14880
|
const state = ___default["default"].extend(self.state, normalizeOptions$1(FUNCTION_ARRAY_OPTIONS$1, options));
|
|
14881
|
-
assert$
|
|
14881
|
+
assert$6(kmath.point.is(state.coord));
|
|
14882
14882
|
|
|
14883
14883
|
// Default things inside the state.normalStyle object, because
|
|
14884
14884
|
// _.extend is not deep.
|
|
@@ -15080,12 +15080,12 @@ ___default["default"].extend(MovablePoint$5.prototype, {
|
|
|
15080
15080
|
return result !== false;
|
|
15081
15081
|
},
|
|
15082
15082
|
setCoord: function (coord) {
|
|
15083
|
-
assert$
|
|
15083
|
+
assert$6(kmath.point.is(coord, 2));
|
|
15084
15084
|
this.state.coord = ___default["default"].clone(coord);
|
|
15085
15085
|
this.draw();
|
|
15086
15086
|
},
|
|
15087
15087
|
setCoordConstrained: function (coord) {
|
|
15088
|
-
assert$
|
|
15088
|
+
assert$6(kmath.point.is(coord, 2));
|
|
15089
15089
|
const result = this._applyConstraints(coord, this.coord());
|
|
15090
15090
|
if (result !== false) {
|
|
15091
15091
|
this.state.coord = ___default["default"].clone(result);
|
|
@@ -15481,7 +15481,7 @@ var MovablePolygonOptions = {
|
|
|
15481
15481
|
* Creates and adds a polygon to the graph that can be dragged around.
|
|
15482
15482
|
* It allows constraints on its movement and draws when moves happen.
|
|
15483
15483
|
*/
|
|
15484
|
-
const assert$
|
|
15484
|
+
const assert$5 = InteractiveUtil.assert;
|
|
15485
15485
|
const normalizeOptions = InteractiveUtil.normalizeOptions;
|
|
15486
15486
|
|
|
15487
15487
|
// State parameters that should be converted into an array of
|
|
@@ -15520,8 +15520,8 @@ const DEFAULT_STATE = {
|
|
|
15520
15520
|
mouseTarget: null
|
|
15521
15521
|
};
|
|
15522
15522
|
const MovablePolygon = function (graphie, movable, options) {
|
|
15523
|
-
assert$
|
|
15524
|
-
assert$
|
|
15523
|
+
assert$5(graphie != null);
|
|
15524
|
+
assert$5(options != null);
|
|
15525
15525
|
|
|
15526
15526
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
15527
15527
|
___default["default"].extend(this, {
|
|
@@ -16039,11 +16039,11 @@ var Movables = {
|
|
|
16039
16039
|
const GraphieMovable = GraphieClasses.GraphieMovable;
|
|
16040
16040
|
const createGraphie = GraphUtils.createGraphie;
|
|
16041
16041
|
const {
|
|
16042
|
-
deepEq: deepEq$
|
|
16042
|
+
deepEq: deepEq$3,
|
|
16043
16043
|
nestedMap
|
|
16044
16044
|
} = Util;
|
|
16045
16045
|
const {
|
|
16046
|
-
assert: assert$
|
|
16046
|
+
assert: assert$4
|
|
16047
16047
|
} = InteractiveUtil;
|
|
16048
16048
|
class Graphie extends React__namespace.Component {
|
|
16049
16049
|
graphieDivRef = /*#__PURE__*/React__namespace.createRef();
|
|
@@ -16074,7 +16074,7 @@ class Graphie extends React__namespace.Component {
|
|
|
16074
16074
|
if (this.props.setup !== prevProps.setup) {
|
|
16075
16075
|
Log.error("<Graphie> was given a new setup function. " + "This is a bad idea; please refactor your code to give " + "the same setup function reference to <Graphie> on " + "every render.", Errors.Internal);
|
|
16076
16076
|
}
|
|
16077
|
-
if (!deepEq$
|
|
16077
|
+
if (!deepEq$3(this.props.options, prevProps.options) || !deepEq$3(this.props.box, prevProps.box) || !deepEq$3(this.props.range, prevProps.range)) {
|
|
16078
16078
|
this._setupGraphie();
|
|
16079
16079
|
}
|
|
16080
16080
|
this._updateMovables();
|
|
@@ -16218,7 +16218,7 @@ class Graphie extends React__namespace.Component {
|
|
|
16218
16218
|
|
|
16219
16219
|
// Instantiate the descriptor to turn it into a real Movable
|
|
16220
16220
|
const child = new childDescriptor.type(childDescriptor.props);
|
|
16221
|
-
assert$
|
|
16221
|
+
assert$4(child instanceof GraphieMovable, "All children of a Graphie component must be Graphie " + "movables");
|
|
16222
16222
|
|
|
16223
16223
|
// Give each child a key
|
|
16224
16224
|
const keyProp = childDescriptor.key;
|
|
@@ -18405,7 +18405,7 @@ const registerWidgets = widgets => {
|
|
|
18405
18405
|
* @param name - the widget that you are trying to replace
|
|
18406
18406
|
* @param replacementName - the name of the widget that takes its place
|
|
18407
18407
|
*
|
|
18408
|
-
* e.g. replaceWidget("transformer", "
|
|
18408
|
+
* e.g. replaceWidget("transformer", "deprecated-standin") will make it so the
|
|
18409
18409
|
* transformer widget is replaced by the always correct widget
|
|
18410
18410
|
*/
|
|
18411
18411
|
const replaceWidget = (name, replacementName) => {
|
|
@@ -18416,9 +18416,6 @@ const replaceWidget = (name, replacementName) => {
|
|
|
18416
18416
|
return;
|
|
18417
18417
|
}
|
|
18418
18418
|
registerWidget(name, substituteWidget);
|
|
18419
|
-
if (Log) {
|
|
18420
|
-
Log.log(`INFO: Replacing widget ${name} with ${replacementName}`);
|
|
18421
|
-
}
|
|
18422
18419
|
};
|
|
18423
18420
|
const registerEditors = editorsToRegister => {
|
|
18424
18421
|
editorsToRegister.forEach(editor => {
|
|
@@ -18445,9 +18442,6 @@ const replaceEditor = (name, replacementName) => {
|
|
|
18445
18442
|
return;
|
|
18446
18443
|
}
|
|
18447
18444
|
editors[name] = substituteEditor;
|
|
18448
|
-
if (Log) {
|
|
18449
|
-
Log.log(`INFO: Replacing editor ${name} with ${replacementName}`);
|
|
18450
|
-
}
|
|
18451
18445
|
};
|
|
18452
18446
|
const getWidget = name => {
|
|
18453
18447
|
// TODO(alex): Consider referring to these as renderers to avoid
|
|
@@ -20958,7 +20952,7 @@ class Tooltip extends React__namespace.Component {
|
|
|
20958
20952
|
|
|
20959
20953
|
/* eslint-disable react/sort-comp */
|
|
20960
20954
|
const {
|
|
20961
|
-
captureScratchpadTouchStart: captureScratchpadTouchStart$
|
|
20955
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$2
|
|
20962
20956
|
} = Util;
|
|
20963
20957
|
class InputWithExamples extends React__namespace.Component {
|
|
20964
20958
|
static defaultProps = {
|
|
@@ -21016,7 +21010,7 @@ class InputWithExamples extends React__namespace.Component {
|
|
|
21016
21010
|
// Add useful props required for MATH and TEXT modes
|
|
21017
21011
|
___default["default"].extend(inputProps, {
|
|
21018
21012
|
onChange: this.props.onChange,
|
|
21019
|
-
onTouchStart: captureScratchpadTouchStart$
|
|
21013
|
+
onTouchStart: captureScratchpadTouchStart$2
|
|
21020
21014
|
});
|
|
21021
21015
|
|
|
21022
21016
|
// And add final props that are MATH- and TEXT-specific
|
|
@@ -23044,7 +23038,7 @@ var ChoiceNoneAbove$1 = /*#__PURE__*/React__namespace.forwardRef((props, ref) =>
|
|
|
23044
23038
|
})));
|
|
23045
23039
|
|
|
23046
23040
|
const {
|
|
23047
|
-
captureScratchpadTouchStart: captureScratchpadTouchStart$
|
|
23041
|
+
captureScratchpadTouchStart: captureScratchpadTouchStart$1
|
|
23048
23042
|
} = Util;
|
|
23049
23043
|
|
|
23050
23044
|
// exported for tests
|
|
@@ -23296,7 +23290,7 @@ const BaseRadio = function (props) {
|
|
|
23296
23290
|
onClick: clickHandler
|
|
23297
23291
|
// @ts-expect-error - TS2322 - Type '((e: TouchEvent) => void) | null' is not assignable to type 'TouchEventHandler<HTMLLIElement> | undefined'.
|
|
23298
23292
|
,
|
|
23299
|
-
onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$
|
|
23293
|
+
onTouchStart: !labelWrap ? null : captureScratchpadTouchStart$1
|
|
23300
23294
|
}, /*#__PURE__*/React__namespace.createElement(Element, _extends({}, elementProps, {
|
|
23301
23295
|
ref: ref
|
|
23302
23296
|
})));
|
|
@@ -26841,9 +26835,9 @@ var Iframe$1 = {
|
|
|
26841
26835
|
};
|
|
26842
26836
|
|
|
26843
26837
|
/* eslint-disable react/sort-comp */
|
|
26844
|
-
const defaultBoxSize$
|
|
26838
|
+
const defaultBoxSize$1 = 400;
|
|
26845
26839
|
const defaultRange = [0, 10];
|
|
26846
|
-
const defaultBackgroundImage$
|
|
26840
|
+
const defaultBackgroundImage$2 = {
|
|
26847
26841
|
url: null,
|
|
26848
26842
|
width: 0,
|
|
26849
26843
|
height: 0
|
|
@@ -26858,8 +26852,8 @@ class ImageWidget extends React__namespace.Component {
|
|
|
26858
26852
|
alignment: DEFAULT_ALIGNMENT,
|
|
26859
26853
|
title: "",
|
|
26860
26854
|
range: [defaultRange, defaultRange],
|
|
26861
|
-
box: [defaultBoxSize$
|
|
26862
|
-
backgroundImage: defaultBackgroundImage$
|
|
26855
|
+
box: [defaultBoxSize$1, defaultBoxSize$1],
|
|
26856
|
+
backgroundImage: defaultBackgroundImage$2,
|
|
26863
26857
|
labels: [],
|
|
26864
26858
|
alt: "",
|
|
26865
26859
|
caption: "",
|
|
@@ -27677,7 +27671,7 @@ var Interactive = {
|
|
|
27677
27671
|
};
|
|
27678
27672
|
|
|
27679
27673
|
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
27680
|
-
const defaultBackgroundImage$
|
|
27674
|
+
const defaultBackgroundImage$1 = {
|
|
27681
27675
|
url: null
|
|
27682
27676
|
};
|
|
27683
27677
|
|
|
@@ -27713,7 +27707,7 @@ class Graph extends React__namespace.Component {
|
|
|
27713
27707
|
gridStep: [1, 1],
|
|
27714
27708
|
snapStep: [0.5, 0.5],
|
|
27715
27709
|
markings: "graph",
|
|
27716
|
-
backgroundImage: defaultBackgroundImage$
|
|
27710
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
27717
27711
|
showProtractor: false,
|
|
27718
27712
|
showRuler: false,
|
|
27719
27713
|
rulerLabel: "",
|
|
@@ -27981,7 +27975,7 @@ class Graph extends React__namespace.Component {
|
|
|
27981
27975
|
*/
|
|
27982
27976
|
const {
|
|
27983
27977
|
eq: eq$1,
|
|
27984
|
-
deepEq: deepEq$
|
|
27978
|
+
deepEq: deepEq$2
|
|
27985
27979
|
} = Util;
|
|
27986
27980
|
|
|
27987
27981
|
// This should really be a readonly tuple of [number, number]
|
|
@@ -28094,7 +28088,7 @@ function similar(coords1, coords2, tolerance) {
|
|
|
28094
28088
|
angles = rotate(angles, i);
|
|
28095
28089
|
// @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
|
|
28096
28090
|
sides = rotate(sides, i);
|
|
28097
|
-
if (deepEq$
|
|
28091
|
+
if (deepEq$2(angles1, angles)) {
|
|
28098
28092
|
const sidePairs = ___default["default"].zip(sides1, sides);
|
|
28099
28093
|
const factors = ___default["default"].map(sidePairs, function (pair) {
|
|
28100
28094
|
return pair[0] / pair[1];
|
|
@@ -28188,11 +28182,11 @@ const {
|
|
|
28188
28182
|
DeprecationMixin
|
|
28189
28183
|
} = Util;
|
|
28190
28184
|
const TRASH_ICON_URI = "https://ka-perseus-graphie.s3.amazonaws.com/b1452c0d79fd0f7ff4c3af9488474a0a0decb361.png";
|
|
28191
|
-
const defaultBackgroundImage
|
|
28185
|
+
const defaultBackgroundImage = {
|
|
28192
28186
|
url: null
|
|
28193
28187
|
};
|
|
28194
28188
|
const eq = Util.eq;
|
|
28195
|
-
const deepEq$
|
|
28189
|
+
const deepEq$1 = Util.deepEq;
|
|
28196
28190
|
const UNLIMITED = "unlimited";
|
|
28197
28191
|
|
|
28198
28192
|
// Sample background image:
|
|
@@ -28249,7 +28243,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
28249
28243
|
labels: ["x", "y"],
|
|
28250
28244
|
range: [[-10, 10], [-10, 10]],
|
|
28251
28245
|
step: [1, 1],
|
|
28252
|
-
backgroundImage: defaultBackgroundImage
|
|
28246
|
+
backgroundImage: defaultBackgroundImage,
|
|
28253
28247
|
markings: "graph",
|
|
28254
28248
|
showTooltips: false,
|
|
28255
28249
|
showProtractor: false,
|
|
@@ -29842,7 +29836,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29842
29836
|
const correctCoeffs = this.getQuadraticCoefficients(
|
|
29843
29837
|
// @ts-expect-error - TS2345 - Argument of type 'readonly Coord[] | undefined' is not assignable to parameter of type 'readonly Coord[]'.
|
|
29844
29838
|
rubric.correct.coords);
|
|
29845
|
-
if (deepEq$
|
|
29839
|
+
if (deepEq$1(guessCoeffs, correctCoeffs)) {
|
|
29846
29840
|
return {
|
|
29847
29841
|
type: "points",
|
|
29848
29842
|
earned: 1,
|
|
@@ -29858,7 +29852,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29858
29852
|
const canonicalGuessCoeffs = canonicalSineCoefficients(guessCoeffs);
|
|
29859
29853
|
const canonicalCorrectCoeffs = canonicalSineCoefficients(correctCoeffs);
|
|
29860
29854
|
// If the canonical coefficients match, it's correct.
|
|
29861
|
-
if (deepEq$
|
|
29855
|
+
if (deepEq$1(canonicalGuessCoeffs, canonicalCorrectCoeffs)) {
|
|
29862
29856
|
return {
|
|
29863
29857
|
type: "points",
|
|
29864
29858
|
earned: 1,
|
|
@@ -29867,7 +29861,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29867
29861
|
};
|
|
29868
29862
|
}
|
|
29869
29863
|
} else if (state.type === "circle" && rubric.correct.type === "circle") {
|
|
29870
|
-
if (deepEq$
|
|
29864
|
+
if (deepEq$1(state.center, rubric.correct.center) && eq(state.radius, rubric.correct.radius)) {
|
|
29871
29865
|
return {
|
|
29872
29866
|
type: "points",
|
|
29873
29867
|
earned: 1,
|
|
@@ -29886,7 +29880,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29886
29880
|
guess?.sort();
|
|
29887
29881
|
// @ts-expect-error - TS2339 - Property 'sort' does not exist on type 'readonly Coord[]'.
|
|
29888
29882
|
correct.sort();
|
|
29889
|
-
if (deepEq$
|
|
29883
|
+
if (deepEq$1(guess, correct)) {
|
|
29890
29884
|
return {
|
|
29891
29885
|
type: "points",
|
|
29892
29886
|
earned: 1,
|
|
@@ -29909,7 +29903,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29909
29903
|
/* exact */
|
|
29910
29904
|
guess.sort();
|
|
29911
29905
|
correct.sort();
|
|
29912
|
-
match = deepEq$
|
|
29906
|
+
match = deepEq$1(guess, correct);
|
|
29913
29907
|
}
|
|
29914
29908
|
if (match) {
|
|
29915
29909
|
return {
|
|
@@ -29925,7 +29919,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29925
29919
|
guess = ___default["default"].invoke(guess, "sort").sort();
|
|
29926
29920
|
// @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
29927
29921
|
correct = ___default["default"].invoke(correct, "sort").sort();
|
|
29928
|
-
if (deepEq$
|
|
29922
|
+
if (deepEq$1(guess, correct)) {
|
|
29929
29923
|
return {
|
|
29930
29924
|
type: "points",
|
|
29931
29925
|
earned: 1,
|
|
@@ -29938,7 +29932,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29938
29932
|
const correct = rubric.correct.coords;
|
|
29939
29933
|
if (
|
|
29940
29934
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'.
|
|
29941
|
-
deepEq$
|
|
29935
|
+
deepEq$1(guess[0], correct[0]) &&
|
|
29942
29936
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
29943
29937
|
collinear(correct[0], correct[1], guess[1])) {
|
|
29944
29938
|
return {
|
|
@@ -29969,7 +29963,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
29969
29963
|
/* exact */
|
|
29970
29964
|
match =
|
|
29971
29965
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
29972
|
-
deepEq$
|
|
29966
|
+
deepEq$1(guess[1], correct[1]) &&
|
|
29973
29967
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
29974
29968
|
collinear(correct[1], correct[0], guess[0]) &&
|
|
29975
29969
|
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'. | TS2532 - Object is possibly 'undefined'.
|
|
@@ -31108,7 +31102,7 @@ const AnswerPill = props => {
|
|
|
31108
31102
|
id: idFactory.get("perseus-label-image-widget-answer-pill"),
|
|
31109
31103
|
onClick: correct ? undefined : onClick,
|
|
31110
31104
|
ref: ref,
|
|
31111
|
-
style: [style, popperStyle, styles$h.
|
|
31105
|
+
style: [style, popperStyle, styles$h.pill, correct && styles$h.correct, incorrect && styles$h.incorrect, (focused || hovered) && BringToFront]
|
|
31112
31106
|
}, /*#__PURE__*/React__namespace.createElement(Renderer, {
|
|
31113
31107
|
content: answerString,
|
|
31114
31108
|
inline: true
|
|
@@ -31122,6 +31116,11 @@ const styles$h = aphrodite.StyleSheet.create({
|
|
|
31122
31116
|
},
|
|
31123
31117
|
incorrect: {
|
|
31124
31118
|
backgroundColor: Color__default["default"].offBlack64
|
|
31119
|
+
},
|
|
31120
|
+
pill: {
|
|
31121
|
+
// Reset the Pill's default height in order to account
|
|
31122
|
+
// for multi-line pills.
|
|
31123
|
+
height: "auto"
|
|
31125
31124
|
}
|
|
31126
31125
|
});
|
|
31127
31126
|
|
|
@@ -33127,7 +33126,7 @@ var Matcher$1 = {
|
|
|
33127
33126
|
|
|
33128
33127
|
const {
|
|
33129
33128
|
firstNumericalParse,
|
|
33130
|
-
captureScratchpadTouchStart
|
|
33129
|
+
captureScratchpadTouchStart
|
|
33131
33130
|
} = Util;
|
|
33132
33131
|
const toNumericString = KhanMath.toNumericString;
|
|
33133
33132
|
const getNumericFormat = KhanMath.getNumericFormat;
|
|
@@ -33200,7 +33199,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
33200
33199
|
onKeyDown: this._onKeyDown
|
|
33201
33200
|
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLInputElement>'.
|
|
33202
33201
|
,
|
|
33203
|
-
onTouchStart: captureScratchpadTouchStart
|
|
33202
|
+
onTouchStart: captureScratchpadTouchStart,
|
|
33204
33203
|
defaultValue: toNumericString(this.props.value, this.state.format),
|
|
33205
33204
|
value: undefined
|
|
33206
33205
|
}));
|
|
@@ -33326,7 +33325,7 @@ class NumberInput extends React__namespace.Component {
|
|
|
33326
33325
|
// Type imports
|
|
33327
33326
|
|
|
33328
33327
|
const {
|
|
33329
|
-
assert: assert$
|
|
33328
|
+
assert: assert$3
|
|
33330
33329
|
} = InteractiveUtil;
|
|
33331
33330
|
const {
|
|
33332
33331
|
stringArrayOfSize
|
|
@@ -33360,12 +33359,12 @@ const getDefaultPath$1 = function () {
|
|
|
33360
33359
|
};
|
|
33361
33360
|
const getRowFromPath$1 = function (path) {
|
|
33362
33361
|
// 'path' should be a (row, column) pair
|
|
33363
|
-
assert$
|
|
33362
|
+
assert$3(___default["default"].isArray(path) && path.length === 2);
|
|
33364
33363
|
return +path[0];
|
|
33365
33364
|
};
|
|
33366
33365
|
const getColumnFromPath$1 = function (path) {
|
|
33367
33366
|
// 'path' should be a (row, column) pair
|
|
33368
|
-
assert$
|
|
33367
|
+
assert$3(___default["default"].isArray(path) && path.length === 2);
|
|
33369
33368
|
return +path[1];
|
|
33370
33369
|
};
|
|
33371
33370
|
const getRefForPath$1 = function (path) {
|
|
@@ -34866,7 +34865,7 @@ const MovablePoint$1 = Graphie.MovablePoint;
|
|
|
34866
34865
|
// @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
|
|
34867
34866
|
const Line$1 = Graphie.Line;
|
|
34868
34867
|
const {
|
|
34869
|
-
assert: assert$
|
|
34868
|
+
assert: assert$2
|
|
34870
34869
|
} = InteractiveUtil;
|
|
34871
34870
|
const bound = (x, gt, lt) => Math.min(Math.max(x, gt), lt);
|
|
34872
34871
|
const EN_DASH = "\u2013";
|
|
@@ -35142,7 +35141,7 @@ class NumberLine extends React__namespace.Component {
|
|
|
35142
35141
|
const snapX = props.tickStep / props.snapDivisions;
|
|
35143
35142
|
let x = bound(numLinePosition, left, right);
|
|
35144
35143
|
x = left + kmath.number.roundTo(x - left, snapX);
|
|
35145
|
-
assert$
|
|
35144
|
+
assert$2(___default["default"].isFinite(x));
|
|
35146
35145
|
return x;
|
|
35147
35146
|
};
|
|
35148
35147
|
|
|
@@ -38249,7 +38248,7 @@ var PassageRefTarget$1 = {
|
|
|
38249
38248
|
|
|
38250
38249
|
/* eslint-disable react/no-unsafe */
|
|
38251
38250
|
const {
|
|
38252
|
-
deepEq
|
|
38251
|
+
deepEq
|
|
38253
38252
|
} = Util;
|
|
38254
38253
|
class Plotter extends React__namespace.Component {
|
|
38255
38254
|
// @ts-expect-error - TS2564 - Property 'shouldSetupGraphie' has no initializer and is not definitely assigned in the constructor.
|
|
@@ -39042,7 +39041,7 @@ class Plotter extends React__namespace.Component {
|
|
|
39042
39041
|
}
|
|
39043
39042
|
___default["default"].extend(Plotter, {
|
|
39044
39043
|
validate: function (guess, rubric) {
|
|
39045
|
-
if (deepEq
|
|
39044
|
+
if (deepEq(guess, rubric.starting)) {
|
|
39046
39045
|
return {
|
|
39047
39046
|
type: "invalid",
|
|
39048
39047
|
message: null
|
|
@@ -39050,7 +39049,7 @@ ___default["default"].extend(Plotter, {
|
|
|
39050
39049
|
}
|
|
39051
39050
|
return {
|
|
39052
39051
|
type: "points",
|
|
39053
|
-
earned: deepEq
|
|
39052
|
+
earned: deepEq(guess, rubric.correct) ? 1 : 0,
|
|
39054
39053
|
total: 1,
|
|
39055
39054
|
message: null
|
|
39056
39055
|
};
|
|
@@ -39412,7 +39411,7 @@ class InfoTip extends React__namespace.Component {
|
|
|
39412
39411
|
|
|
39413
39412
|
/* eslint-disable @typescript-eslint/no-unused-vars, react/no-unsafe, react/sort-comp */
|
|
39414
39413
|
const {
|
|
39415
|
-
assert: assert$
|
|
39414
|
+
assert: assert$1
|
|
39416
39415
|
} = InteractiveUtil;
|
|
39417
39416
|
// @ts-expect-error - TS2339 - Property 'Path' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Arc' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Circle' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Label' does not exist on type 'typeof Graphie'. | TS2339 - Property 'Line' does not exist on type 'typeof Graphie'. | TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'. | TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
|
|
39418
39417
|
const {
|
|
@@ -39424,7 +39423,7 @@ const {
|
|
|
39424
39423
|
MovablePoint,
|
|
39425
39424
|
MovableLine
|
|
39426
39425
|
} = Graphie;
|
|
39427
|
-
const defaultBoxSize
|
|
39426
|
+
const defaultBoxSize = 400;
|
|
39428
39427
|
const maxSampleSize = 1000;
|
|
39429
39428
|
class Histogram extends React__namespace.Component {
|
|
39430
39429
|
static propTypes = {
|
|
@@ -39437,7 +39436,7 @@ class Histogram extends React__namespace.Component {
|
|
|
39437
39436
|
data: null,
|
|
39438
39437
|
xAxisLabel: "Proportion (%)",
|
|
39439
39438
|
yAxisLabel: "Number of times seen",
|
|
39440
|
-
box: [defaultBoxSize
|
|
39439
|
+
box: [defaultBoxSize, defaultBoxSize]
|
|
39441
39440
|
};
|
|
39442
39441
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
39443
39442
|
// Reset the threshold if the range has changed
|
|
@@ -39940,7 +39939,7 @@ class Simulator extends React__namespace.Component {
|
|
|
39940
39939
|
return true;
|
|
39941
39940
|
};
|
|
39942
39941
|
focusInputPath = path => {
|
|
39943
|
-
assert$
|
|
39942
|
+
assert$1(path.length > 0);
|
|
39944
39943
|
const inputID = ___default["default"].head(path);
|
|
39945
39944
|
// eslint-disable-next-line react/no-string-refs
|
|
39946
39945
|
const inputComponent = this.refs[inputID];
|
|
@@ -39948,7 +39947,7 @@ class Simulator extends React__namespace.Component {
|
|
|
39948
39947
|
inputComponent.focus();
|
|
39949
39948
|
};
|
|
39950
39949
|
blurInputPath = path => {
|
|
39951
|
-
assert$
|
|
39950
|
+
assert$1(path.length > 0);
|
|
39952
39951
|
const inputID = ___default["default"].head(path);
|
|
39953
39952
|
// eslint-disable-next-line react/no-string-refs
|
|
39954
39953
|
const inputComponent = this.refs[inputID];
|
|
@@ -39956,17 +39955,17 @@ class Simulator extends React__namespace.Component {
|
|
|
39956
39955
|
inputComponent.blur();
|
|
39957
39956
|
};
|
|
39958
39957
|
getDOMNodeForPath = path => {
|
|
39959
|
-
assert$
|
|
39958
|
+
assert$1(path.length > 0);
|
|
39960
39959
|
const inputID = ___default["default"].head(path);
|
|
39961
39960
|
// eslint-disable-next-line react/no-string-refs
|
|
39962
39961
|
return ReactDOM__default["default"].findDOMNode(this.refs[inputID]);
|
|
39963
39962
|
};
|
|
39964
39963
|
getGrammarTypeForPath = path => {
|
|
39965
|
-
assert$
|
|
39964
|
+
assert$1(path.length > 0);
|
|
39966
39965
|
return "number";
|
|
39967
39966
|
};
|
|
39968
39967
|
setInputValue = (path, newValue, cb) => {
|
|
39969
|
-
assert$
|
|
39968
|
+
assert$1(path.length > 0);
|
|
39970
39969
|
const inputID = ___default["default"].head(path);
|
|
39971
39970
|
const capitalizedID = inputID.charAt(0).toUpperCase() + inputID.slice(1);
|
|
39972
39971
|
const functionName = "handle" + capitalizedID + "Change";
|
|
@@ -40126,7 +40125,7 @@ var Sorter$1 = {
|
|
|
40126
40125
|
};
|
|
40127
40126
|
|
|
40128
40127
|
const {
|
|
40129
|
-
assert
|
|
40128
|
+
assert
|
|
40130
40129
|
} = InteractiveUtil;
|
|
40131
40130
|
|
|
40132
40131
|
/* Input handling: Maps a (row, column) pair to a unique ref used by React,
|
|
@@ -40140,12 +40139,12 @@ const getDefaultPath = function () {
|
|
|
40140
40139
|
};
|
|
40141
40140
|
const getRowFromPath = function (path) {
|
|
40142
40141
|
// 'path' should be a (row, column) pair
|
|
40143
|
-
assert
|
|
40142
|
+
assert(___default["default"].isArray(path) && path.length === 2);
|
|
40144
40143
|
return +path[0];
|
|
40145
40144
|
};
|
|
40146
40145
|
const getColumnFromPath = function (path) {
|
|
40147
40146
|
// 'path' should be a (row, column) pair
|
|
40148
|
-
assert
|
|
40147
|
+
assert(___default["default"].isArray(path) && path.length === 2);
|
|
40149
40148
|
return +path[1];
|
|
40150
40149
|
};
|
|
40151
40150
|
const getRefForPath = function (path) {
|
|
@@ -40419,2415 +40418,6 @@ var Table$1 = {
|
|
|
40419
40418
|
isLintable: true
|
|
40420
40419
|
};
|
|
40421
40420
|
|
|
40422
|
-
const {
|
|
40423
|
-
deepEq,
|
|
40424
|
-
getGridStep,
|
|
40425
|
-
captureScratchpadTouchStart
|
|
40426
|
-
} = Util;
|
|
40427
|
-
const {
|
|
40428
|
-
assert
|
|
40429
|
-
} = InteractiveUtil;
|
|
40430
|
-
const ROTATE_SNAP_DEGREES = 15;
|
|
40431
|
-
const DEGREE_SIGN = "\u00B0";
|
|
40432
|
-
const RENDER_TRANSFORM_DELAY_IN_MS = 300;
|
|
40433
|
-
const ROTATE_HANDLE_DIST = 1.5;
|
|
40434
|
-
const REFLECT_ROTATE_HANDLE_DIST = 2;
|
|
40435
|
-
const REFLECT_BUTTON_SIZE = 1;
|
|
40436
|
-
const defaultBoxSize = 400;
|
|
40437
|
-
const defaultBackgroundImage = {
|
|
40438
|
-
url: null
|
|
40439
|
-
};
|
|
40440
|
-
|
|
40441
|
-
/* Does a pluck on keys inside objects in an object
|
|
40442
|
-
*
|
|
40443
|
-
* Ex:
|
|
40444
|
-
* tools = {
|
|
40445
|
-
* translation: {
|
|
40446
|
-
* enabled: true
|
|
40447
|
-
* },
|
|
40448
|
-
* rotation: {
|
|
40449
|
-
* enabled: false
|
|
40450
|
-
* }
|
|
40451
|
-
* };
|
|
40452
|
-
* pluckObject(tools, "enabled") returns {
|
|
40453
|
-
* translation: true
|
|
40454
|
-
* rotation: false
|
|
40455
|
-
* }
|
|
40456
|
-
*/
|
|
40457
|
-
function pluckObject(object, subKey) {
|
|
40458
|
-
return ___default["default"].object(___default["default"].map(object, function (value, key) {
|
|
40459
|
-
return [key, value[subKey]];
|
|
40460
|
-
}));
|
|
40461
|
-
}
|
|
40462
|
-
const defaultGraphProps = function (setProps, boxSize) {
|
|
40463
|
-
setProps = setProps || {};
|
|
40464
|
-
const labels = setProps.labels || ["x", "y"];
|
|
40465
|
-
const range = setProps.range || [[-10, 10], [-10, 10]];
|
|
40466
|
-
const step = setProps.step || [1, 1];
|
|
40467
|
-
const gridStep = setProps.gridStep || getGridStep(range, step, boxSize);
|
|
40468
|
-
return {
|
|
40469
|
-
box: [boxSize, boxSize],
|
|
40470
|
-
labels: labels,
|
|
40471
|
-
range: range,
|
|
40472
|
-
step: step,
|
|
40473
|
-
gridStep: gridStep,
|
|
40474
|
-
valid: true,
|
|
40475
|
-
backgroundImage: defaultBackgroundImage,
|
|
40476
|
-
markings: "grid",
|
|
40477
|
-
showProtractor: false
|
|
40478
|
-
};
|
|
40479
|
-
};
|
|
40480
|
-
const defaultTransformerProps = {
|
|
40481
|
-
apiOptions: ApiOptions.defaults,
|
|
40482
|
-
gradeEmpty: false,
|
|
40483
|
-
graphMode: "interactive",
|
|
40484
|
-
listMode: "dynamic",
|
|
40485
|
-
graph: {},
|
|
40486
|
-
tools: {
|
|
40487
|
-
translation: {
|
|
40488
|
-
enabled: true,
|
|
40489
|
-
required: false,
|
|
40490
|
-
constraints: {}
|
|
40491
|
-
},
|
|
40492
|
-
rotation: {
|
|
40493
|
-
enabled: true,
|
|
40494
|
-
required: false,
|
|
40495
|
-
constraints: {
|
|
40496
|
-
fixed: false
|
|
40497
|
-
},
|
|
40498
|
-
coord: [1, 6]
|
|
40499
|
-
},
|
|
40500
|
-
reflection: {
|
|
40501
|
-
enabled: true,
|
|
40502
|
-
required: false,
|
|
40503
|
-
constraints: {
|
|
40504
|
-
fixed: false
|
|
40505
|
-
},
|
|
40506
|
-
coords: [[2, -4], [2, 2]]
|
|
40507
|
-
},
|
|
40508
|
-
dilation: {
|
|
40509
|
-
enabled: true,
|
|
40510
|
-
required: false,
|
|
40511
|
-
constraints: {
|
|
40512
|
-
fixed: false
|
|
40513
|
-
},
|
|
40514
|
-
coord: [6, 6]
|
|
40515
|
-
}
|
|
40516
|
-
},
|
|
40517
|
-
drawSolutionShape: true,
|
|
40518
|
-
starting: {
|
|
40519
|
-
shape: {
|
|
40520
|
-
type: "polygon-3",
|
|
40521
|
-
coords: [[2, 2], [2, 6], [7, 2]]
|
|
40522
|
-
},
|
|
40523
|
-
transformations: []
|
|
40524
|
-
},
|
|
40525
|
-
correct: {
|
|
40526
|
-
shape: {
|
|
40527
|
-
type: "polygon-3",
|
|
40528
|
-
coords: [[2, 2], [2, 6], [7, 2]]
|
|
40529
|
-
},
|
|
40530
|
-
transformations: []
|
|
40531
|
-
}
|
|
40532
|
-
};
|
|
40533
|
-
function colorForTool(tool) {
|
|
40534
|
-
return tool.constraints.fixed ? KhanColors.DYNAMIC : KhanColors.INTERACTIVE;
|
|
40535
|
-
}
|
|
40536
|
-
|
|
40537
|
-
/* Scales a distance from the default range of
|
|
40538
|
-
* [-10, 10] to a given props.range pair
|
|
40539
|
-
*
|
|
40540
|
-
* Used for sizing various transformation tools
|
|
40541
|
-
* (rotation handle, dilation circle)
|
|
40542
|
-
*/
|
|
40543
|
-
function scaleToRange(dist, range) {
|
|
40544
|
-
const spreadX = range[0][1] - range[0][0];
|
|
40545
|
-
const spreadY = range[1][1] - range[1][0];
|
|
40546
|
-
return dist * Math.max(spreadX, spreadY) / 20;
|
|
40547
|
-
}
|
|
40548
|
-
function dilatePointFromCenter(point, dilationCenter, scale) {
|
|
40549
|
-
const pv = kmath.vector.subtract(point, dilationCenter);
|
|
40550
|
-
const pvScaled = kmath.vector.scale(pv, scale);
|
|
40551
|
-
const transformedPoint = kmath.vector.add(dilationCenter, pvScaled);
|
|
40552
|
-
return transformedPoint;
|
|
40553
|
-
}
|
|
40554
|
-
|
|
40555
|
-
// TODO(jack): i18nize this
|
|
40556
|
-
function stringFromDecimal(number) {
|
|
40557
|
-
return String(KhanMath.roundTo(9, number));
|
|
40558
|
-
}
|
|
40559
|
-
function stringFromFraction(number) {
|
|
40560
|
-
const frac = KhanMath.toFraction(number, kmath.number.DEFAULT_TOLERANCE);
|
|
40561
|
-
if (frac[1] === 1) {
|
|
40562
|
-
return stringFromDecimal(number);
|
|
40563
|
-
}
|
|
40564
|
-
return stringFromDecimal(frac[0]) + "/" + stringFromDecimal(frac[1]);
|
|
40565
|
-
}
|
|
40566
|
-
function texFromPoint(point) {
|
|
40567
|
-
const {
|
|
40568
|
-
TeX
|
|
40569
|
-
} = getDependencies();
|
|
40570
|
-
return [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40571
|
-
key: "("
|
|
40572
|
-
}, "("), stringFromDecimal(point[0]), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40573
|
-
key: ","
|
|
40574
|
-
}, ", {}"), stringFromDecimal(point[1]), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40575
|
-
key: ")"
|
|
40576
|
-
}, ")")];
|
|
40577
|
-
}
|
|
40578
|
-
function texFromVector(vector) {
|
|
40579
|
-
const {
|
|
40580
|
-
TeX
|
|
40581
|
-
} = getDependencies();
|
|
40582
|
-
return [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40583
|
-
key: "<"
|
|
40584
|
-
}, i18n__namespace.doNotTranslate("\\langle")), stringFromDecimal(vector[0]), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40585
|
-
key: ","
|
|
40586
|
-
}, ", {}"), stringFromDecimal(vector[1]), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40587
|
-
key: ">"
|
|
40588
|
-
}, i18n__namespace.doNotTranslate("\\rangle"))];
|
|
40589
|
-
}
|
|
40590
|
-
function texFromAngleDeg(angleDeg) {
|
|
40591
|
-
return stringFromDecimal(angleDeg) + DEGREE_SIGN;
|
|
40592
|
-
}
|
|
40593
|
-
function orderInsensitiveCoordsEqual(coords1, coords2) {
|
|
40594
|
-
coords1 = ___default["default"].clone(coords1).sort(kmath.point.compare);
|
|
40595
|
-
coords2 = ___default["default"].clone(coords2).sort(kmath.point.compare);
|
|
40596
|
-
return ___default["default"].all(___default["default"].map(coords1, function (coord1, i) {
|
|
40597
|
-
const coord2 = coords2[i];
|
|
40598
|
-
return kmath.point.equal(coord1, coord2);
|
|
40599
|
-
}));
|
|
40600
|
-
}
|
|
40601
|
-
const inputComponentForApiOptions = apiOptions => {
|
|
40602
|
-
if (apiOptions.customKeypad) {
|
|
40603
|
-
return SimpleKeypadInput;
|
|
40604
|
-
}
|
|
40605
|
-
return NumberInput;
|
|
40606
|
-
};
|
|
40607
|
-
|
|
40608
|
-
/* Perform operations on raw transform objects */
|
|
40609
|
-
const TransformOps = {
|
|
40610
|
-
apply: function (transform) {
|
|
40611
|
-
// Any transformation with empty text boxes is a no-op until
|
|
40612
|
-
// filled out (these show up as nulls in transform.vector/line/etc).
|
|
40613
|
-
// TODO (jack): Merge this just into reflections now that other
|
|
40614
|
-
// transforms are always valid (after merging transformation
|
|
40615
|
-
// collapsing, which may use isValid)
|
|
40616
|
-
// @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
|
|
40617
|
-
if (!Transformations[transform.type].isValid(transform)) {
|
|
40618
|
-
return ___default["default"].identity; // do not transform the coord
|
|
40619
|
-
}
|
|
40620
|
-
// @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
|
|
40621
|
-
return Transformations[transform.type].apply(transform);
|
|
40622
|
-
},
|
|
40623
|
-
append: function (transformList, newTransform) {
|
|
40624
|
-
// Append newTransform to transformList, and collapse the last
|
|
40625
|
-
// two transforms if they are collapsable
|
|
40626
|
-
const results = TransformOps._appendAndCollapseLastTwo(transformList, newTransform);
|
|
40627
|
-
// Collapse any no-ops at the end of the transformation list
|
|
40628
|
-
return TransformOps._collapseFinalNoOps(results);
|
|
40629
|
-
},
|
|
40630
|
-
_collapseFinalNoOps: function (transforms) {
|
|
40631
|
-
// Collapse no-op transformations at the end of the list
|
|
40632
|
-
if (transforms.length && TransformOps.isNoOp(___default["default"].last(transforms))) {
|
|
40633
|
-
return ___default["default"].initial(transforms);
|
|
40634
|
-
}
|
|
40635
|
-
return transforms;
|
|
40636
|
-
},
|
|
40637
|
-
_appendAndCollapseLastTwo: function (transformList, newTransform) {
|
|
40638
|
-
if (!transformList.length) {
|
|
40639
|
-
return [newTransform];
|
|
40640
|
-
}
|
|
40641
|
-
const collapsed = TransformOps.collapse(___default["default"].last(transformList), newTransform);
|
|
40642
|
-
return ___default["default"].initial(transformList).concat(collapsed);
|
|
40643
|
-
},
|
|
40644
|
-
isNoOp: function (transform) {
|
|
40645
|
-
return Transformations[transform.type].isNoOp(transform);
|
|
40646
|
-
},
|
|
40647
|
-
collapse: function (transform1, transform2) {
|
|
40648
|
-
// We can only collapse transforms that have the same type
|
|
40649
|
-
if (transform1.type !== transform2.type) {
|
|
40650
|
-
return [transform1, transform2];
|
|
40651
|
-
}
|
|
40652
|
-
|
|
40653
|
-
// Clicking the button again removes empty transformations
|
|
40654
|
-
if (TransformOps.isEmpty(transform1) && TransformOps.isEmpty(transform2)) {
|
|
40655
|
-
return [];
|
|
40656
|
-
}
|
|
40657
|
-
|
|
40658
|
-
// Don't collapse invalid transformations otherwise
|
|
40659
|
-
if (!TransformOps.isValid(transform1) || !TransformOps.isValid(transform2)) {
|
|
40660
|
-
return [transform1, transform2];
|
|
40661
|
-
}
|
|
40662
|
-
return TransformOps._collapseValidMonotypedTransforms(transform1, transform2);
|
|
40663
|
-
},
|
|
40664
|
-
isValid: function (transform) {
|
|
40665
|
-
// @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
|
|
40666
|
-
return Transformations[transform.type].isValid(transform);
|
|
40667
|
-
},
|
|
40668
|
-
isEmpty: function (transform) {
|
|
40669
|
-
// @ts-expect-error - TS2345 - Argument of type 'PerseusTransformerTransformation' is not assignable to parameter of type 'never'.
|
|
40670
|
-
return Transformations[transform.type].isEmpty(transform);
|
|
40671
|
-
},
|
|
40672
|
-
_collapseValidMonotypedTransforms: function (transform1, transform2) {
|
|
40673
|
-
let collapsed = Transformations[transform1.type].collapse(transform1, transform2);
|
|
40674
|
-
if (collapsed) {
|
|
40675
|
-
// Force all answers into an array
|
|
40676
|
-
if (!___default["default"].isArray(collapsed)) {
|
|
40677
|
-
collapsed = [collapsed];
|
|
40678
|
-
}
|
|
40679
|
-
// Add types to all transforms in the answer
|
|
40680
|
-
___default["default"].each(collapsed, function (transform) {
|
|
40681
|
-
transform.type = transform1.type;
|
|
40682
|
-
});
|
|
40683
|
-
return collapsed;
|
|
40684
|
-
}
|
|
40685
|
-
// These transforms can't be collapsed together
|
|
40686
|
-
return [transform1, transform2];
|
|
40687
|
-
},
|
|
40688
|
-
toTeX: function (transform) {
|
|
40689
|
-
return Transformations[transform.type].toTeX(transform);
|
|
40690
|
-
},
|
|
40691
|
-
/* A react representation of this transform object */
|
|
40692
|
-
ListItem: createReactClass__default["default"]({
|
|
40693
|
-
displayName: "ListItem",
|
|
40694
|
-
render: function () {
|
|
40695
|
-
if (this.props.mode === "dynamic") {
|
|
40696
|
-
return /*#__PURE__*/React__namespace.createElement("div", null, TransformOps.toTeX(this.props.transform));
|
|
40697
|
-
}
|
|
40698
|
-
if (this.props.mode === "interactive") {
|
|
40699
|
-
const TransformClass = Transformations[this.props.transform.type].Input;
|
|
40700
|
-
return /*#__PURE__*/React__namespace.createElement(TransformClass
|
|
40701
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40702
|
-
, _extends({
|
|
40703
|
-
ref: "transform",
|
|
40704
|
-
onChange: this.handleChange,
|
|
40705
|
-
onFocus: this.props.onFocus,
|
|
40706
|
-
onBlur: this.props.onBlur,
|
|
40707
|
-
keypadElement: this.props.keypadElement,
|
|
40708
|
-
apiOptions: this.props.apiOptions
|
|
40709
|
-
}, this.props.transform));
|
|
40710
|
-
}
|
|
40711
|
-
throw new PerseusError("Invalid mode: " + this.props.mode, Errors.InvalidInput);
|
|
40712
|
-
},
|
|
40713
|
-
value: function () {
|
|
40714
|
-
if (this.props.mode === "interactive") {
|
|
40715
|
-
return ___default["default"].extend({
|
|
40716
|
-
type: this.props.transform.type
|
|
40717
|
-
},
|
|
40718
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40719
|
-
this.refs.transform.value());
|
|
40720
|
-
}
|
|
40721
|
-
return this.props.transform;
|
|
40722
|
-
},
|
|
40723
|
-
handleChange: ___default["default"].debounce(function (callback) {
|
|
40724
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
40725
|
-
this.props.onChange(this.value(), callback);
|
|
40726
|
-
}, RENDER_TRANSFORM_DELAY_IN_MS),
|
|
40727
|
-
/* InputPath API: depending on the API call, this could involve simply
|
|
40728
|
-
* navigating to the right ref and calling the function on that
|
|
40729
|
-
* component, or threading the call down and returning the result. */
|
|
40730
|
-
_getComponentAtPath: function (path) {
|
|
40731
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40732
|
-
const transform = this.refs.transform;
|
|
40733
|
-
const ref = ___default["default"].head(path);
|
|
40734
|
-
return transform.refs[ref];
|
|
40735
|
-
},
|
|
40736
|
-
focus: function () {
|
|
40737
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40738
|
-
const transform = this.refs.transform;
|
|
40739
|
-
const path = ___default["default"].head(transform.getInputPaths());
|
|
40740
|
-
if (path) {
|
|
40741
|
-
this.focusInputPath(path);
|
|
40742
|
-
}
|
|
40743
|
-
},
|
|
40744
|
-
focusInputPath: function (path) {
|
|
40745
|
-
this._getComponentAtPath(path).focus();
|
|
40746
|
-
},
|
|
40747
|
-
blurInputPath: function (path) {
|
|
40748
|
-
this._getComponentAtPath(path).blur();
|
|
40749
|
-
},
|
|
40750
|
-
getDOMNodeForPath: function (path) {
|
|
40751
|
-
return ReactDOM__default["default"].findDOMNode(this._getComponentAtPath(path));
|
|
40752
|
-
},
|
|
40753
|
-
getGrammarTypeForPath: function (path) {
|
|
40754
|
-
return "number";
|
|
40755
|
-
},
|
|
40756
|
-
setInputValue: function (path, value, cb) {
|
|
40757
|
-
// `value` comes in as a string on mobile, but we need a number
|
|
40758
|
-
// We let through the empty string so that "Clear" works -- in
|
|
40759
|
-
// that case, the transformer widget will just act as if there is
|
|
40760
|
-
// no input, which is what we want.
|
|
40761
|
-
// @ts-expect-error - TS2339 - Property 'length' does not exist on type 'string | number'.
|
|
40762
|
-
if (value.length) {
|
|
40763
|
-
// @ts-expect-error - TS2345 - Argument of type 'string | number' is not assignable to parameter of type 'string'.
|
|
40764
|
-
value = parseFloat(value);
|
|
40765
|
-
if (isNaN(value)) {
|
|
40766
|
-
return;
|
|
40767
|
-
}
|
|
40768
|
-
}
|
|
40769
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40770
|
-
this.refs.transform.setInputValue(path, value, cb);
|
|
40771
|
-
},
|
|
40772
|
-
getInputPaths: function () {
|
|
40773
|
-
// If we're in dynamic mode, then the list items are made up of
|
|
40774
|
-
// static text.
|
|
40775
|
-
if (this.props.mode === "dynamic") {
|
|
40776
|
-
return [];
|
|
40777
|
-
}
|
|
40778
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40779
|
-
return this.refs.transform.getInputPaths();
|
|
40780
|
-
}
|
|
40781
|
-
})
|
|
40782
|
-
};
|
|
40783
|
-
const Transformations = {
|
|
40784
|
-
translation: {
|
|
40785
|
-
// I18N: As in the command, "Translate the polygon"
|
|
40786
|
-
verbName: i18n__namespace._("Translate"),
|
|
40787
|
-
nounName: i18n__namespace._("Translation"),
|
|
40788
|
-
lowerNounName: i18n__namespace._("translation"),
|
|
40789
|
-
apply: function (transform) {
|
|
40790
|
-
return function (coord) {
|
|
40791
|
-
return kmath.vector.add(coord, transform.vector);
|
|
40792
|
-
};
|
|
40793
|
-
},
|
|
40794
|
-
isValid: function (transform) {
|
|
40795
|
-
return ___default["default"].isFinite(transform.vector[0]) && ___default["default"].isFinite(transform.vector[1]);
|
|
40796
|
-
},
|
|
40797
|
-
isEmpty: function (transform) {
|
|
40798
|
-
return transform.vector[0] === null && transform.vector[1] === null;
|
|
40799
|
-
},
|
|
40800
|
-
isNoOp: function (transform) {
|
|
40801
|
-
return kmath.vector.equal(transform.vector, [0, 0]);
|
|
40802
|
-
},
|
|
40803
|
-
collapse: function (transform1, transform2) {
|
|
40804
|
-
return {
|
|
40805
|
-
vector: kmath.vector.add(transform1.vector, transform2.vector)
|
|
40806
|
-
};
|
|
40807
|
-
},
|
|
40808
|
-
toTeX: function (transform) {
|
|
40809
|
-
// I18N: As in the command, "Translation by <3, 1>"
|
|
40810
|
-
return i18n__namespace.$_("Translation by %(vector)s", {
|
|
40811
|
-
vector: texFromVector(transform.vector)
|
|
40812
|
-
});
|
|
40813
|
-
},
|
|
40814
|
-
Input: class extends React__namespace.Component {
|
|
40815
|
-
state = {
|
|
40816
|
-
vector: this.props.vector || [null, null]
|
|
40817
|
-
};
|
|
40818
|
-
componentDidUpdate(prevProps) {
|
|
40819
|
-
if (!deepEq(this.props, prevProps)) {
|
|
40820
|
-
this.setState({
|
|
40821
|
-
vector: this.props.vector
|
|
40822
|
-
});
|
|
40823
|
-
}
|
|
40824
|
-
}
|
|
40825
|
-
render() {
|
|
40826
|
-
const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
|
|
40827
|
-
const {
|
|
40828
|
-
TeX
|
|
40829
|
-
} = getDependencies();
|
|
40830
|
-
const vector = [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40831
|
-
key: "<"
|
|
40832
|
-
}, i18n__namespace.doNotTranslate("\\langle")), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
40833
|
-
key: "vec_x"
|
|
40834
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40835
|
-
,
|
|
40836
|
-
ref: "x",
|
|
40837
|
-
placeholder: 0,
|
|
40838
|
-
value: this.state.vector[0],
|
|
40839
|
-
useArrowKeys: true,
|
|
40840
|
-
onChange: val0 => {
|
|
40841
|
-
const val1 = this.state.vector[1];
|
|
40842
|
-
this.setState({
|
|
40843
|
-
vector: [val0, val1]
|
|
40844
|
-
}, () => {
|
|
40845
|
-
this.props.onChange();
|
|
40846
|
-
});
|
|
40847
|
-
},
|
|
40848
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "x"),
|
|
40849
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "x"),
|
|
40850
|
-
keypadElement: this.props.keypadElement
|
|
40851
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40852
|
-
key: ","
|
|
40853
|
-
}, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
40854
|
-
key: "vec_y"
|
|
40855
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40856
|
-
,
|
|
40857
|
-
ref: "y",
|
|
40858
|
-
placeholder: 0,
|
|
40859
|
-
value: this.state.vector[1],
|
|
40860
|
-
useArrowKeys: true,
|
|
40861
|
-
onChange: val1 => {
|
|
40862
|
-
const val0 = this.state.vector[0];
|
|
40863
|
-
this.setState({
|
|
40864
|
-
vector: [val0, val1]
|
|
40865
|
-
}, () => {
|
|
40866
|
-
this.props.onChange();
|
|
40867
|
-
});
|
|
40868
|
-
},
|
|
40869
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "y"),
|
|
40870
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "y"),
|
|
40871
|
-
keypadElement: this.props.keypadElement
|
|
40872
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40873
|
-
key: ">"
|
|
40874
|
-
}, i18n__namespace.doNotTranslate("\\rangle"))];
|
|
40875
|
-
return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Translation by %(vector)s", {
|
|
40876
|
-
vector: vector
|
|
40877
|
-
}));
|
|
40878
|
-
}
|
|
40879
|
-
value = () => {
|
|
40880
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40881
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
40882
|
-
const x = this.refs.x.getValue();
|
|
40883
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40884
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
40885
|
-
const y = this.refs.y.getValue();
|
|
40886
|
-
return {
|
|
40887
|
-
vector: [x, y]
|
|
40888
|
-
};
|
|
40889
|
-
};
|
|
40890
|
-
|
|
40891
|
-
/* InputPath API */
|
|
40892
|
-
setInputValue = (path, value, cb) => {
|
|
40893
|
-
const id = ___default["default"].first(path);
|
|
40894
|
-
const vector = ___default["default"].clone(this.state.vector);
|
|
40895
|
-
if (id === "x") {
|
|
40896
|
-
vector[0] = value;
|
|
40897
|
-
} else if (id === "y") {
|
|
40898
|
-
vector[1] = value;
|
|
40899
|
-
}
|
|
40900
|
-
this.setState({
|
|
40901
|
-
vector: vector
|
|
40902
|
-
}, () => {
|
|
40903
|
-
this.props.onChange(cb);
|
|
40904
|
-
});
|
|
40905
|
-
};
|
|
40906
|
-
getInputPaths = () => {
|
|
40907
|
-
return [["x"], ["y"]];
|
|
40908
|
-
};
|
|
40909
|
-
}
|
|
40910
|
-
},
|
|
40911
|
-
rotation: {
|
|
40912
|
-
// I18N: As in the command, "Rotate the polygon"
|
|
40913
|
-
verbName: i18n__namespace._("Rotate"),
|
|
40914
|
-
nounName: i18n__namespace._("Rotation"),
|
|
40915
|
-
lowerNounName: i18n__namespace._("rotation"),
|
|
40916
|
-
apply: function (transform) {
|
|
40917
|
-
return function (coord) {
|
|
40918
|
-
return kmath.point.rotateDeg(coord, transform.angleDeg, transform.center);
|
|
40919
|
-
};
|
|
40920
|
-
},
|
|
40921
|
-
isValid: function (transform) {
|
|
40922
|
-
return ___default["default"].isFinite(transform.angleDeg) && ___default["default"].isFinite(transform.center[0]) && ___default["default"].isFinite(transform.center[1]);
|
|
40923
|
-
},
|
|
40924
|
-
isEmpty: function (transform) {
|
|
40925
|
-
return transform.angleDeg === null && transform.center[0] === null && transform.center[1] === null;
|
|
40926
|
-
},
|
|
40927
|
-
isNoOp: function (transform) {
|
|
40928
|
-
return kmath.number.equal(transform.angleDeg, 0);
|
|
40929
|
-
},
|
|
40930
|
-
collapse: function (transform1, transform2) {
|
|
40931
|
-
if (!kmath.point.equal(transform1.center, transform2.center)) {
|
|
40932
|
-
return false;
|
|
40933
|
-
}
|
|
40934
|
-
return {
|
|
40935
|
-
center: transform1.center,
|
|
40936
|
-
angleDeg: transform1.angleDeg + transform2.angleDeg
|
|
40937
|
-
};
|
|
40938
|
-
},
|
|
40939
|
-
toTeX: function (transform) {
|
|
40940
|
-
return i18n__namespace.$_("Rotation by %(degrees)s about %(point)s", {
|
|
40941
|
-
degrees: texFromAngleDeg(transform.angleDeg),
|
|
40942
|
-
point: texFromPoint(transform.center)
|
|
40943
|
-
});
|
|
40944
|
-
},
|
|
40945
|
-
Input: class extends React__namespace.Component {
|
|
40946
|
-
state = {
|
|
40947
|
-
center: this.props.center || [null, null],
|
|
40948
|
-
angleDeg: this.props.angleDeg || null
|
|
40949
|
-
};
|
|
40950
|
-
componentDidUpdate(prevProps) {
|
|
40951
|
-
if (!deepEq(this.props, prevProps)) {
|
|
40952
|
-
this.setState({
|
|
40953
|
-
center: this.props.center,
|
|
40954
|
-
angleDeg: this.props.angleDeg
|
|
40955
|
-
});
|
|
40956
|
-
}
|
|
40957
|
-
}
|
|
40958
|
-
render() {
|
|
40959
|
-
const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
|
|
40960
|
-
const {
|
|
40961
|
-
TeX
|
|
40962
|
-
} = getDependencies();
|
|
40963
|
-
const point = [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40964
|
-
key: "("
|
|
40965
|
-
}, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
40966
|
-
key: "X"
|
|
40967
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40968
|
-
,
|
|
40969
|
-
ref: "centerX",
|
|
40970
|
-
placeholder: 0,
|
|
40971
|
-
value: this.state.center[0],
|
|
40972
|
-
useArrowKeys: true,
|
|
40973
|
-
onChange: val0 => {
|
|
40974
|
-
const val1 = this.state.center[1];
|
|
40975
|
-
this.setState({
|
|
40976
|
-
center: [val0, val1]
|
|
40977
|
-
}, () => {
|
|
40978
|
-
this.props.onChange();
|
|
40979
|
-
});
|
|
40980
|
-
},
|
|
40981
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "centerX"),
|
|
40982
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "centerX"),
|
|
40983
|
-
keypadElement: this.props.keypadElement
|
|
40984
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
40985
|
-
key: ","
|
|
40986
|
-
}, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
40987
|
-
key: "Y"
|
|
40988
|
-
// eslint-disable-next-line react/no-string-refs
|
|
40989
|
-
,
|
|
40990
|
-
ref: "centerY",
|
|
40991
|
-
placeholder: 0,
|
|
40992
|
-
value: this.state.center[1],
|
|
40993
|
-
useArrowKeys: true,
|
|
40994
|
-
onChange: val1 => {
|
|
40995
|
-
const val0 = this.state.center[0];
|
|
40996
|
-
this.setState({
|
|
40997
|
-
center: [val0, val1]
|
|
40998
|
-
}, () => {
|
|
40999
|
-
this.props.onChange();
|
|
41000
|
-
});
|
|
41001
|
-
},
|
|
41002
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "centerY"),
|
|
41003
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "centerY"),
|
|
41004
|
-
keypadElement: this.props.keypadElement
|
|
41005
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41006
|
-
key: ")"
|
|
41007
|
-
}, ")")];
|
|
41008
|
-
const degrees = [/*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41009
|
-
key: "deg"
|
|
41010
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41011
|
-
,
|
|
41012
|
-
ref: "angleDeg",
|
|
41013
|
-
placeholder: 0,
|
|
41014
|
-
value: this.state.angleDeg,
|
|
41015
|
-
useArrowKeys: true,
|
|
41016
|
-
onChange: val => {
|
|
41017
|
-
this.setState({
|
|
41018
|
-
angleDeg: val
|
|
41019
|
-
}, () => {
|
|
41020
|
-
this.props.onChange();
|
|
41021
|
-
});
|
|
41022
|
-
},
|
|
41023
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "angleDeg"),
|
|
41024
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "angleDeg"),
|
|
41025
|
-
keypadElement: this.props.keypadElement
|
|
41026
|
-
}), DEGREE_SIGN];
|
|
41027
|
-
// I18N: %(point)s must come before %(degrees)s in this phrase
|
|
41028
|
-
const text = i18n__namespace.$_("Rotation about %(point)s by %(degrees)s", {
|
|
41029
|
-
point,
|
|
41030
|
-
degrees
|
|
41031
|
-
});
|
|
41032
|
-
return /*#__PURE__*/React__namespace.createElement("div", null, text);
|
|
41033
|
-
}
|
|
41034
|
-
value = () => {
|
|
41035
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41036
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41037
|
-
const angleDeg = this.refs.angleDeg.getValue();
|
|
41038
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41039
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41040
|
-
const centerX = this.refs.centerX.getValue();
|
|
41041
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41042
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41043
|
-
const centerY = this.refs.centerY.getValue();
|
|
41044
|
-
return {
|
|
41045
|
-
angleDeg: angleDeg,
|
|
41046
|
-
center: [centerX, centerY]
|
|
41047
|
-
};
|
|
41048
|
-
};
|
|
41049
|
-
|
|
41050
|
-
/* InputPath API */
|
|
41051
|
-
setInputValue = (path, value, cb) => {
|
|
41052
|
-
const id = ___default["default"].first(path);
|
|
41053
|
-
let angleDeg = ___default["default"].clone(this.state.angleDeg);
|
|
41054
|
-
const center = ___default["default"].clone(this.state.center);
|
|
41055
|
-
if (id === "angleDeg") {
|
|
41056
|
-
angleDeg = value;
|
|
41057
|
-
} else if (id === "centerX") {
|
|
41058
|
-
center[0] = value;
|
|
41059
|
-
} else if (id === "centerY") {
|
|
41060
|
-
center[1] = value;
|
|
41061
|
-
}
|
|
41062
|
-
this.setState({
|
|
41063
|
-
angleDeg: angleDeg,
|
|
41064
|
-
center: center
|
|
41065
|
-
}, () => {
|
|
41066
|
-
this.props.onChange(cb);
|
|
41067
|
-
});
|
|
41068
|
-
};
|
|
41069
|
-
getInputPaths = () => {
|
|
41070
|
-
return [["centerX"], ["centerY"], ["angleDeg"]];
|
|
41071
|
-
};
|
|
41072
|
-
}
|
|
41073
|
-
},
|
|
41074
|
-
reflection: {
|
|
41075
|
-
// I18N: As in the command, "Reflect the polygon"
|
|
41076
|
-
verbName: i18n__namespace._("Reflect"),
|
|
41077
|
-
nounName: i18n__namespace._("Reflection"),
|
|
41078
|
-
lowerNounName: i18n__namespace._("reflection"),
|
|
41079
|
-
apply: function (transform) {
|
|
41080
|
-
return function (coord) {
|
|
41081
|
-
return kmath.point.reflectOverLine(coord, transform.line);
|
|
41082
|
-
};
|
|
41083
|
-
},
|
|
41084
|
-
isValid: function (transform) {
|
|
41085
|
-
// A bit hacky, but we'll also define reflecting over a
|
|
41086
|
-
// single point as a no-op, to avoid NaN fun.
|
|
41087
|
-
return ___default["default"].all(___default["default"].flatten(transform.line), ___default["default"].isFinite) && !kmath.point.equal(transform.line[0], transform.line[1]);
|
|
41088
|
-
},
|
|
41089
|
-
isEmpty: function (transform) {
|
|
41090
|
-
return ___default["default"].all(___default["default"].flatten(transform.line), ___default["default"].isNull);
|
|
41091
|
-
},
|
|
41092
|
-
isNoOp: function (transform) {
|
|
41093
|
-
// Invalid transforms are implicitly no-ops, so we don't
|
|
41094
|
-
// have to catch that case here.
|
|
41095
|
-
return false;
|
|
41096
|
-
},
|
|
41097
|
-
collapse: function (transform1, transform2) {
|
|
41098
|
-
if (!kmath.line.equal(transform1.line, transform2.line)) {
|
|
41099
|
-
return false;
|
|
41100
|
-
}
|
|
41101
|
-
return [];
|
|
41102
|
-
},
|
|
41103
|
-
toTeX: function (transform) {
|
|
41104
|
-
const point1 = transform.line[0];
|
|
41105
|
-
const point2 = transform.line[1];
|
|
41106
|
-
return i18n__namespace.$_("Reflection over the line from %(point1)s to %(point2)s", {
|
|
41107
|
-
point1: texFromPoint(point1),
|
|
41108
|
-
point2: texFromPoint(point2)
|
|
41109
|
-
});
|
|
41110
|
-
},
|
|
41111
|
-
Input: class extends React__namespace.Component {
|
|
41112
|
-
state = {
|
|
41113
|
-
line: this.props.line || [[null, null], [null, null]]
|
|
41114
|
-
};
|
|
41115
|
-
componentDidUpdate(prevProps) {
|
|
41116
|
-
if (!deepEq(this.props, prevProps)) {
|
|
41117
|
-
this.setState({
|
|
41118
|
-
line: this.props.line
|
|
41119
|
-
});
|
|
41120
|
-
}
|
|
41121
|
-
}
|
|
41122
|
-
render() {
|
|
41123
|
-
const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
|
|
41124
|
-
const {
|
|
41125
|
-
TeX
|
|
41126
|
-
} = getDependencies();
|
|
41127
|
-
const point1 = [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41128
|
-
key: "("
|
|
41129
|
-
}, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41130
|
-
key: "x1"
|
|
41131
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41132
|
-
,
|
|
41133
|
-
ref: "x1",
|
|
41134
|
-
value: this.state.line[0][0],
|
|
41135
|
-
useArrowKeys: true
|
|
41136
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41137
|
-
,
|
|
41138
|
-
onChange: this.changePoint.bind(this, 0, 0),
|
|
41139
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "x1"),
|
|
41140
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "x1"),
|
|
41141
|
-
keypadElement: this.props.keypadElement
|
|
41142
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41143
|
-
key: ","
|
|
41144
|
-
}, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41145
|
-
key: "y1"
|
|
41146
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41147
|
-
,
|
|
41148
|
-
ref: "y1",
|
|
41149
|
-
value: this.state.line[0][1],
|
|
41150
|
-
useArrowKeys: true
|
|
41151
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41152
|
-
,
|
|
41153
|
-
onChange: this.changePoint.bind(this, 0, 1),
|
|
41154
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "y1"),
|
|
41155
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "y1"),
|
|
41156
|
-
keypadElement: this.props.keypadElement
|
|
41157
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41158
|
-
key: ")"
|
|
41159
|
-
}, ")")];
|
|
41160
|
-
const point2 = [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41161
|
-
key: "("
|
|
41162
|
-
}, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41163
|
-
key: "x2"
|
|
41164
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41165
|
-
,
|
|
41166
|
-
ref: "x2",
|
|
41167
|
-
value: this.state.line[1][0],
|
|
41168
|
-
useArrowKeys: true
|
|
41169
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41170
|
-
,
|
|
41171
|
-
onChange: this.changePoint.bind(this, 1, 0),
|
|
41172
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "x2"),
|
|
41173
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "x2"),
|
|
41174
|
-
keypadElement: this.props.keypadElement
|
|
41175
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41176
|
-
key: ","
|
|
41177
|
-
}, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41178
|
-
key: "y2"
|
|
41179
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41180
|
-
,
|
|
41181
|
-
ref: "y2",
|
|
41182
|
-
value: this.state.line[1][1],
|
|
41183
|
-
useArrowKeys: true
|
|
41184
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41185
|
-
,
|
|
41186
|
-
onChange: this.changePoint.bind(this, 1, 1),
|
|
41187
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "y2"),
|
|
41188
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "y2"),
|
|
41189
|
-
keypadElement: this.props.keypadElement
|
|
41190
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41191
|
-
key: ")"
|
|
41192
|
-
}, ")")];
|
|
41193
|
-
return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Reflection over the line from " + "%(point1)s to %(point2)s", {
|
|
41194
|
-
point1,
|
|
41195
|
-
point2
|
|
41196
|
-
}));
|
|
41197
|
-
}
|
|
41198
|
-
changePoint = (i, j, val, cb) => {
|
|
41199
|
-
const line = ___default["default"].map(this.state.line, ___default["default"].clone);
|
|
41200
|
-
// @ts-expect-error - TS2538 - Type 'undefined' cannot be used as an index type.
|
|
41201
|
-
line[i][j] = val;
|
|
41202
|
-
this.setState({
|
|
41203
|
-
line: line
|
|
41204
|
-
}, () => {
|
|
41205
|
-
this.props.onChange(cb);
|
|
41206
|
-
});
|
|
41207
|
-
};
|
|
41208
|
-
value = () => {
|
|
41209
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41210
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41211
|
-
const x1 = this.refs.x1.getValue();
|
|
41212
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41213
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41214
|
-
const y1 = this.refs.y1.getValue();
|
|
41215
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41216
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41217
|
-
const x2 = this.refs.x2.getValue();
|
|
41218
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41219
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41220
|
-
const y2 = this.refs.y2.getValue();
|
|
41221
|
-
return {
|
|
41222
|
-
line: [[x1, y1], [x2, y2]]
|
|
41223
|
-
};
|
|
41224
|
-
};
|
|
41225
|
-
|
|
41226
|
-
/* InputPath API */
|
|
41227
|
-
setInputValue = (path, value, cb) => {
|
|
41228
|
-
const id = ___default["default"].first(path);
|
|
41229
|
-
let j;
|
|
41230
|
-
if (id[0] === "x") {
|
|
41231
|
-
j = 0;
|
|
41232
|
-
} else if (id[0] === "y") {
|
|
41233
|
-
j = 1;
|
|
41234
|
-
}
|
|
41235
|
-
let i;
|
|
41236
|
-
if (id[1] === "1") {
|
|
41237
|
-
i = 0;
|
|
41238
|
-
} else if (id[1] === "2") {
|
|
41239
|
-
i = 1;
|
|
41240
|
-
}
|
|
41241
|
-
this.changePoint(i, j, value, cb);
|
|
41242
|
-
};
|
|
41243
|
-
getInputPaths = () => {
|
|
41244
|
-
return [["x1"], ["y1"], ["x2"], ["y2"]];
|
|
41245
|
-
};
|
|
41246
|
-
}
|
|
41247
|
-
},
|
|
41248
|
-
dilation: {
|
|
41249
|
-
// I18N: As in the command, "Dilate the polygon"
|
|
41250
|
-
verbName: i18n__namespace._("Dilate"),
|
|
41251
|
-
nounName: i18n__namespace._("Dilation"),
|
|
41252
|
-
lowerNounName: i18n__namespace._("dilation"),
|
|
41253
|
-
apply: function (transform) {
|
|
41254
|
-
return function (coord) {
|
|
41255
|
-
return dilatePointFromCenter(coord, transform.center, transform.scale);
|
|
41256
|
-
};
|
|
41257
|
-
},
|
|
41258
|
-
isValid: function (transform) {
|
|
41259
|
-
return ___default["default"].isFinite(transform.scale) && ___default["default"].isFinite(transform.center[0]) && ___default["default"].isFinite(transform.center[1]);
|
|
41260
|
-
},
|
|
41261
|
-
isEmpty: function (transform) {
|
|
41262
|
-
return transform.scale === null && transform.center[0] === null && transform.center[1] === null;
|
|
41263
|
-
},
|
|
41264
|
-
isNoOp: function (transform) {
|
|
41265
|
-
return kmath.number.equal(transform.scale, 1);
|
|
41266
|
-
},
|
|
41267
|
-
collapse: function (transform1, transform2) {
|
|
41268
|
-
if (!kmath.point.equal(transform1.center, transform2.center)) {
|
|
41269
|
-
return false;
|
|
41270
|
-
}
|
|
41271
|
-
return {
|
|
41272
|
-
center: transform1.center,
|
|
41273
|
-
scale: transform1.scale * transform2.scale
|
|
41274
|
-
};
|
|
41275
|
-
},
|
|
41276
|
-
toTeX: function (transform) {
|
|
41277
|
-
const scaleString = stringFromFraction(transform.scale);
|
|
41278
|
-
return i18n__namespace.$_("Dilation of scale %(scale)s about %(point)s", {
|
|
41279
|
-
scale: scaleString,
|
|
41280
|
-
point: texFromPoint(transform.center)
|
|
41281
|
-
});
|
|
41282
|
-
},
|
|
41283
|
-
Input: class extends React__namespace.Component {
|
|
41284
|
-
state = {
|
|
41285
|
-
center: this.props.center || [null, null],
|
|
41286
|
-
scale: this.props.scale || null
|
|
41287
|
-
};
|
|
41288
|
-
componentDidUpdate(prevProps) {
|
|
41289
|
-
if (!deepEq(this.props, prevProps)) {
|
|
41290
|
-
this.setState({
|
|
41291
|
-
center: this.props.center,
|
|
41292
|
-
scale: this.props.scale
|
|
41293
|
-
});
|
|
41294
|
-
}
|
|
41295
|
-
}
|
|
41296
|
-
render() {
|
|
41297
|
-
const InputComponent = inputComponentForApiOptions(this.props.apiOptions);
|
|
41298
|
-
const {
|
|
41299
|
-
TeX
|
|
41300
|
-
} = getDependencies();
|
|
41301
|
-
const point = [/*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41302
|
-
key: "("
|
|
41303
|
-
}, "("), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41304
|
-
key: "point_x"
|
|
41305
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41306
|
-
,
|
|
41307
|
-
ref: "x",
|
|
41308
|
-
placeholder: 0,
|
|
41309
|
-
value: this.state.center[0],
|
|
41310
|
-
useArrowKeys: true,
|
|
41311
|
-
onChange: val0 => {
|
|
41312
|
-
const val1 = this.state.center[1];
|
|
41313
|
-
this.setState({
|
|
41314
|
-
center: [val0, val1]
|
|
41315
|
-
}, () => {
|
|
41316
|
-
this.props.onChange();
|
|
41317
|
-
});
|
|
41318
|
-
},
|
|
41319
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "x"),
|
|
41320
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "x"),
|
|
41321
|
-
keypadElement: this.props.keypadElement
|
|
41322
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41323
|
-
key: ","
|
|
41324
|
-
}, ", {}"), /*#__PURE__*/React__namespace.createElement(InputComponent, {
|
|
41325
|
-
key: "point_y"
|
|
41326
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41327
|
-
,
|
|
41328
|
-
ref: "y",
|
|
41329
|
-
placeholder: 0,
|
|
41330
|
-
value: this.state.center[1],
|
|
41331
|
-
useArrowKeys: true,
|
|
41332
|
-
onChange: val1 => {
|
|
41333
|
-
const val0 = this.state.center[0];
|
|
41334
|
-
this.setState({
|
|
41335
|
-
center: [val0, val1]
|
|
41336
|
-
}, () => {
|
|
41337
|
-
this.props.onChange();
|
|
41338
|
-
});
|
|
41339
|
-
},
|
|
41340
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "y"),
|
|
41341
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "y"),
|
|
41342
|
-
keypadElement: this.props.keypadElement
|
|
41343
|
-
}), /*#__PURE__*/React__namespace.createElement(TeX, {
|
|
41344
|
-
key: ")"
|
|
41345
|
-
}, ")")];
|
|
41346
|
-
const scale = /*#__PURE__*/React__namespace.createElement(InputComponent
|
|
41347
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41348
|
-
, {
|
|
41349
|
-
ref: "scale",
|
|
41350
|
-
placeholder: 1,
|
|
41351
|
-
value: this.state.scale,
|
|
41352
|
-
useArrowKeys: true,
|
|
41353
|
-
onChange: val => {
|
|
41354
|
-
this.setState({
|
|
41355
|
-
scale: val
|
|
41356
|
-
}, () => {
|
|
41357
|
-
this.props.onChange();
|
|
41358
|
-
});
|
|
41359
|
-
},
|
|
41360
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "scale"),
|
|
41361
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "scale"),
|
|
41362
|
-
keypadElement: this.props.keypadElement
|
|
41363
|
-
});
|
|
41364
|
-
return /*#__PURE__*/React__namespace.createElement("div", null, i18n__namespace.$_("Dilation about %(point)s by %(scale)s", {
|
|
41365
|
-
point,
|
|
41366
|
-
scale
|
|
41367
|
-
}));
|
|
41368
|
-
}
|
|
41369
|
-
value = () => {
|
|
41370
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41371
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41372
|
-
const scale = this.refs.scale.getValue();
|
|
41373
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41374
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41375
|
-
const x = this.refs.x.getValue();
|
|
41376
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41377
|
-
// @ts-expect-error - TS2339 - Property 'getValue' does not exist on type 'ReactInstance'.
|
|
41378
|
-
const y = this.refs.y.getValue();
|
|
41379
|
-
return {
|
|
41380
|
-
scale: scale,
|
|
41381
|
-
center: [x, y]
|
|
41382
|
-
};
|
|
41383
|
-
};
|
|
41384
|
-
|
|
41385
|
-
/* InputPath API */
|
|
41386
|
-
setInputValue = (path, value, cb) => {
|
|
41387
|
-
const id = ___default["default"].first(path);
|
|
41388
|
-
let scale = this.state.scale;
|
|
41389
|
-
const center = ___default["default"].clone(this.state.center);
|
|
41390
|
-
if (id === "x") {
|
|
41391
|
-
center[0] = value;
|
|
41392
|
-
} else if (id === "y") {
|
|
41393
|
-
center[1] = value;
|
|
41394
|
-
} else if (id === "scale") {
|
|
41395
|
-
scale = value;
|
|
41396
|
-
}
|
|
41397
|
-
this.setState({
|
|
41398
|
-
scale: scale,
|
|
41399
|
-
center: center
|
|
41400
|
-
}, () => {
|
|
41401
|
-
this.props.onChange(cb);
|
|
41402
|
-
});
|
|
41403
|
-
};
|
|
41404
|
-
getInputPaths = () => {
|
|
41405
|
-
return [["x"], ["y"], ["scale"]];
|
|
41406
|
-
};
|
|
41407
|
-
}
|
|
41408
|
-
}
|
|
41409
|
-
};
|
|
41410
|
-
|
|
41411
|
-
/* Various functions to deal with different shape types */
|
|
41412
|
-
const ShapeTypes = {
|
|
41413
|
-
getPointCountForType: function (type) {
|
|
41414
|
-
const splitType = type.split("-");
|
|
41415
|
-
if (splitType[0] === "polygon") {
|
|
41416
|
-
return splitType[1] || 3;
|
|
41417
|
-
}
|
|
41418
|
-
if (splitType[0] === "line" || splitType[0] === "lineSegment") {
|
|
41419
|
-
return 2;
|
|
41420
|
-
}
|
|
41421
|
-
if (splitType[0] === "angle") {
|
|
41422
|
-
return 3;
|
|
41423
|
-
}
|
|
41424
|
-
if (splitType[0] === "circle") {
|
|
41425
|
-
return 2;
|
|
41426
|
-
}
|
|
41427
|
-
if (splitType[0] === "point") {
|
|
41428
|
-
return 1;
|
|
41429
|
-
}
|
|
41430
|
-
},
|
|
41431
|
-
addMovableShape: function (graphie, options) {
|
|
41432
|
-
if (options.editable && options.translatable) {
|
|
41433
|
-
throw new PerseusError("It doesn't make sense to have a movable shape " + "where you can stretch the points and translate them " + "simultaneously. options: " + JSON.stringify(options), Errors.InvalidInput);
|
|
41434
|
-
}
|
|
41435
|
-
const points = ___default["default"].map(options.shape.coords, function (coord) {
|
|
41436
|
-
let isMoving = false;
|
|
41437
|
-
let previousCoord = coord;
|
|
41438
|
-
const onMove = function (x, y) {
|
|
41439
|
-
if (!isMoving) {
|
|
41440
|
-
previousCoord = currentPoint.coord;
|
|
41441
|
-
isMoving = true;
|
|
41442
|
-
}
|
|
41443
|
-
let moveVector = kmath.vector.subtract([x, y], currentPoint.coord);
|
|
41444
|
-
|
|
41445
|
-
// Translate from (x, y) semantics to (dX, dY) semantics
|
|
41446
|
-
// This is more useful for translations on multiple points,
|
|
41447
|
-
// where we care about how the points moved, not where any
|
|
41448
|
-
// individual point ended up
|
|
41449
|
-
if (options.onMove) {
|
|
41450
|
-
moveVector = options.onMove(moveVector[0], moveVector[1]);
|
|
41451
|
-
}
|
|
41452
|
-
|
|
41453
|
-
// Perform a translation on all points in this shape when
|
|
41454
|
-
// any point moves
|
|
41455
|
-
if (options.translatable) {
|
|
41456
|
-
___default["default"].each(points, function (point) {
|
|
41457
|
-
// The point itself will be updated by the
|
|
41458
|
-
// movablePoint class, so only translate the other
|
|
41459
|
-
// points
|
|
41460
|
-
if (point !== currentPoint) {
|
|
41461
|
-
point.setCoord(kmath.vector.add(point.coord, moveVector));
|
|
41462
|
-
}
|
|
41463
|
-
});
|
|
41464
|
-
}
|
|
41465
|
-
|
|
41466
|
-
// Update our shape and our currentPoint
|
|
41467
|
-
// Without this, some shapes (circles, angles) appear
|
|
41468
|
-
// "bouncy" as they are updated with currentPoint at the
|
|
41469
|
-
// current mouse coordinate (oldCoord), rather than newCoord
|
|
41470
|
-
const oldCoord = currentPoint.coord;
|
|
41471
|
-
const newCoord = kmath.vector.add(currentPoint.coord, moveVector);
|
|
41472
|
-
// Temporarily change our coordinate so that
|
|
41473
|
-
// shape.update() sees the new coordinate
|
|
41474
|
-
currentPoint.coord = newCoord;
|
|
41475
|
-
shape.update();
|
|
41476
|
-
// ...But don't break onMove, which assumes it
|
|
41477
|
-
// is the only thing changing our coord
|
|
41478
|
-
currentPoint.coord = oldCoord;
|
|
41479
|
-
return newCoord;
|
|
41480
|
-
};
|
|
41481
|
-
const onMoveEnd = function () {
|
|
41482
|
-
// onMove isn't guaranteed to be called before onMoveEnd, so
|
|
41483
|
-
// we have to take into account that we may not have moved and
|
|
41484
|
-
// set previousCoord.
|
|
41485
|
-
if (options.onMoveEnd && isMoving) {
|
|
41486
|
-
isMoving = false;
|
|
41487
|
-
// We don't use the supplied x and y parameters here
|
|
41488
|
-
// because MovablePoint's onMoveEnd semantics suck.
|
|
41489
|
-
// It returns the mouseX, mouseY without processing them
|
|
41490
|
-
// through onMove, leaving us with weird fractional moves
|
|
41491
|
-
const change = kmath.vector.subtract(currentPoint.coord, previousCoord);
|
|
41492
|
-
options.onMoveEnd(change[0], change[1]);
|
|
41493
|
-
}
|
|
41494
|
-
shape.update();
|
|
41495
|
-
};
|
|
41496
|
-
const currentPoint = graphie.addMovablePoint({
|
|
41497
|
-
coord: coord,
|
|
41498
|
-
normalStyle: options.normalPointStyle,
|
|
41499
|
-
highlightStyle: options.highlightPointStyle,
|
|
41500
|
-
constraints: {
|
|
41501
|
-
fixed: !options.translatable && !options.editable
|
|
41502
|
-
},
|
|
41503
|
-
visible: options.showPoints,
|
|
41504
|
-
snapX: options.snap && options.snap[0] || 0,
|
|
41505
|
-
snapY: options.snap && options.snap[1] || 0,
|
|
41506
|
-
bounded: false,
|
|
41507
|
-
// Don't bound it when placing it on the graph
|
|
41508
|
-
onMove: onMove,
|
|
41509
|
-
onMoveEnd: onMoveEnd
|
|
41510
|
-
});
|
|
41511
|
-
|
|
41512
|
-
// Bound it when moving
|
|
41513
|
-
// We can't set this earlier, because doing so would mean any
|
|
41514
|
-
// points outside of the graph would be moved into a moved into
|
|
41515
|
-
// a position that doesn't preserve the shape
|
|
41516
|
-
currentPoint.bounded = true;
|
|
41517
|
-
return currentPoint;
|
|
41518
|
-
});
|
|
41519
|
-
const shape = ShapeTypes.addShape(graphie, options, points);
|
|
41520
|
-
const removeShapeWithoutPoints = shape.remove;
|
|
41521
|
-
shape.remove = function () {
|
|
41522
|
-
removeShapeWithoutPoints.apply(shape);
|
|
41523
|
-
___default["default"].invoke(points, "remove");
|
|
41524
|
-
};
|
|
41525
|
-
return shape;
|
|
41526
|
-
},
|
|
41527
|
-
addShape: function (graphie, options, points) {
|
|
41528
|
-
points = points || options.shape.coords;
|
|
41529
|
-
const types = ShapeTypes._typesOf(options.shape);
|
|
41530
|
-
const typeOptions = options.shape.options || ShapeTypes.defaultOptions(types);
|
|
41531
|
-
|
|
41532
|
-
// @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
|
|
41533
|
-
const shapes = ShapeTypes._mapTypes(types, points, function (type, points, i) {
|
|
41534
|
-
const shapeOptions = ___default["default"].extend({}, options, typeOptions[i]);
|
|
41535
|
-
return ShapeTypes._addType(graphie, type, points, shapeOptions);
|
|
41536
|
-
});
|
|
41537
|
-
const updateFuncs = ___default["default"].filter(___default["default"].pluck(shapes, "update"), ___default["default"].identity);
|
|
41538
|
-
const update = function () {
|
|
41539
|
-
___default["default"].invoke(updateFuncs, "call");
|
|
41540
|
-
};
|
|
41541
|
-
const removeFuncs = ___default["default"].filter(___default["default"].pluck(shapes, "remove"), ___default["default"].identity);
|
|
41542
|
-
const remove = function () {
|
|
41543
|
-
___default["default"].invoke(removeFuncs, "call");
|
|
41544
|
-
};
|
|
41545
|
-
const getOptions = function () {
|
|
41546
|
-
return ___default["default"].map(shapes, function (shape) {
|
|
41547
|
-
if (shape.getOptions) {
|
|
41548
|
-
return shape.getOptions();
|
|
41549
|
-
}
|
|
41550
|
-
return {};
|
|
41551
|
-
});
|
|
41552
|
-
};
|
|
41553
|
-
const toJSON = function () {
|
|
41554
|
-
const coords = ___default["default"].map(points, function (pt) {
|
|
41555
|
-
if (___default["default"].isArray(pt)) {
|
|
41556
|
-
return pt;
|
|
41557
|
-
}
|
|
41558
|
-
return pt.coord;
|
|
41559
|
-
});
|
|
41560
|
-
return {
|
|
41561
|
-
type: types,
|
|
41562
|
-
coords: coords,
|
|
41563
|
-
options: getOptions()
|
|
41564
|
-
};
|
|
41565
|
-
};
|
|
41566
|
-
return {
|
|
41567
|
-
type: types,
|
|
41568
|
-
points: points,
|
|
41569
|
-
update: update,
|
|
41570
|
-
remove: remove,
|
|
41571
|
-
toJSON: toJSON,
|
|
41572
|
-
getOptions: getOptions
|
|
41573
|
-
};
|
|
41574
|
-
},
|
|
41575
|
-
equal: function (shape1, shape2) {
|
|
41576
|
-
const types1 = ShapeTypes._typesOf(shape1);
|
|
41577
|
-
const types2 = ShapeTypes._typesOf(shape2);
|
|
41578
|
-
if (types1.length !== types2.length) {
|
|
41579
|
-
return false;
|
|
41580
|
-
}
|
|
41581
|
-
// @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
|
|
41582
|
-
const shapes1 = ShapeTypes._mapTypes(types1, shape1.coords, ShapeTypes._combine);
|
|
41583
|
-
// @ts-expect-error - TS2554 - Expected 4 arguments, but got 3.
|
|
41584
|
-
const shapes2 = ShapeTypes._mapTypes(types2, shape2.coords, ShapeTypes._combine);
|
|
41585
|
-
return ___default["default"].all(___default["default"].map(shapes1, function (partialShape1, i) {
|
|
41586
|
-
const partialShape2 = shapes2[i];
|
|
41587
|
-
if (partialShape1.type !== partialShape2.type) {
|
|
41588
|
-
return false;
|
|
41589
|
-
}
|
|
41590
|
-
return ShapeTypes._forType(partialShape1.type).equal(partialShape1.coords, partialShape2.coords);
|
|
41591
|
-
}));
|
|
41592
|
-
},
|
|
41593
|
-
_typesOf: function (shape) {
|
|
41594
|
-
let types = shape.type;
|
|
41595
|
-
if (!___default["default"].isArray(types)) {
|
|
41596
|
-
types = [types];
|
|
41597
|
-
}
|
|
41598
|
-
return ___default["default"].map(types, function (type) {
|
|
41599
|
-
if (type === "polygon") {
|
|
41600
|
-
return "polygon-3";
|
|
41601
|
-
}
|
|
41602
|
-
return type;
|
|
41603
|
-
});
|
|
41604
|
-
},
|
|
41605
|
-
defaultOptions: function (types) {
|
|
41606
|
-
return ___default["default"].map(types, function (type) {
|
|
41607
|
-
const typeDefaultOptions = ShapeTypes._forType(type).defaultOptions;
|
|
41608
|
-
return ___default["default"].extend({}, typeDefaultOptions);
|
|
41609
|
-
});
|
|
41610
|
-
},
|
|
41611
|
-
_forType: function (type) {
|
|
41612
|
-
const baseType = type.split("-")[0];
|
|
41613
|
-
return ShapeTypes[baseType];
|
|
41614
|
-
},
|
|
41615
|
-
_mapTypes: function (types, points, func, context) {
|
|
41616
|
-
return ___default["default"].map(types, function (type, i) {
|
|
41617
|
-
const pointCount = ShapeTypes.getPointCountForType(type);
|
|
41618
|
-
const currentPoints = ___default["default"].first(points, pointCount);
|
|
41619
|
-
points = ___default["default"].rest(points, pointCount);
|
|
41620
|
-
return func.call(context, type, currentPoints, i);
|
|
41621
|
-
});
|
|
41622
|
-
},
|
|
41623
|
-
_addType: function (graphie, type, points, options) {
|
|
41624
|
-
const lineCoords = ___default["default"].isArray(points[0]) ? {
|
|
41625
|
-
coordA: points[0],
|
|
41626
|
-
coordZ: points[1]
|
|
41627
|
-
} : {
|
|
41628
|
-
pointA: points[0],
|
|
41629
|
-
pointZ: points[1]
|
|
41630
|
-
};
|
|
41631
|
-
type = type.split("-")[0];
|
|
41632
|
-
if (type === "polygon") {
|
|
41633
|
-
const polygon = graphie.addMovablePolygon(___default["default"].extend({}, options, {
|
|
41634
|
-
fixed: !options.editable,
|
|
41635
|
-
snapX: options.snap && options.snap[0] || 0,
|
|
41636
|
-
snapY: options.snap && options.snap[1] || 0,
|
|
41637
|
-
points: points,
|
|
41638
|
-
constrainToGraph: false
|
|
41639
|
-
}));
|
|
41640
|
-
return {
|
|
41641
|
-
update: polygon.transform.bind(polygon),
|
|
41642
|
-
remove: polygon.remove.bind(polygon)
|
|
41643
|
-
};
|
|
41644
|
-
}
|
|
41645
|
-
if (type === "line" || type === "lineSegment") {
|
|
41646
|
-
const line = graphie.addMovableLineSegment(___default["default"].extend({}, options, lineCoords, {
|
|
41647
|
-
movePointsWithLine: true,
|
|
41648
|
-
fixed: true,
|
|
41649
|
-
constraints: {
|
|
41650
|
-
fixed: true
|
|
41651
|
-
},
|
|
41652
|
-
extendLine: type === "line"
|
|
41653
|
-
}));
|
|
41654
|
-
|
|
41655
|
-
// TODO(jack): Hide points on uneditable lines when translation
|
|
41656
|
-
// is a vector.
|
|
41657
|
-
// We can't just remove the points yet, because they are the
|
|
41658
|
-
// translation handle for the line.
|
|
41659
|
-
return {
|
|
41660
|
-
update: line.transform.bind(line, true),
|
|
41661
|
-
remove: line.remove.bind(line)
|
|
41662
|
-
};
|
|
41663
|
-
}
|
|
41664
|
-
if (type === "angle") {
|
|
41665
|
-
// If this angle is editable, we want to be able to make angles
|
|
41666
|
-
// both larger and smaller than 180 degrees.
|
|
41667
|
-
// If this angle is not editable, it should always maintain
|
|
41668
|
-
// it's angle measure, even if it is reflected (causing the
|
|
41669
|
-
// clockwise-ness of the points to change)
|
|
41670
|
-
const shouldChangeReflexivity = options.editable ? null : false;
|
|
41671
|
-
const angle = graphie.addMovableAngle({
|
|
41672
|
-
angleLabel: "$deg0",
|
|
41673
|
-
fixed: true,
|
|
41674
|
-
points: points,
|
|
41675
|
-
normalStyle: options.normalStyle,
|
|
41676
|
-
reflex: options.reflex
|
|
41677
|
-
});
|
|
41678
|
-
|
|
41679
|
-
// Hide non-vertex points on uneditable angles
|
|
41680
|
-
if (!___default["default"].isArray(points[0]) && !options.editable) {
|
|
41681
|
-
points[0].remove();
|
|
41682
|
-
points[2].remove();
|
|
41683
|
-
}
|
|
41684
|
-
return {
|
|
41685
|
-
update: angle.update.bind(angle, shouldChangeReflexivity),
|
|
41686
|
-
remove: angle.remove.bind(angle),
|
|
41687
|
-
getOptions: function () {
|
|
41688
|
-
return {
|
|
41689
|
-
reflex: angle.isReflex()
|
|
41690
|
-
};
|
|
41691
|
-
}
|
|
41692
|
-
};
|
|
41693
|
-
}
|
|
41694
|
-
if (type === "circle") {
|
|
41695
|
-
let perimeter = {
|
|
41696
|
-
// temporary object for the first removal
|
|
41697
|
-
remove: ___default["default"].identity
|
|
41698
|
-
};
|
|
41699
|
-
const redrawPerim = function () {
|
|
41700
|
-
const coord0 = points[0].coord || points[0];
|
|
41701
|
-
const coord1 = points[1].coord || points[1];
|
|
41702
|
-
const radius = kmath.point.distanceToPoint(coord0, coord1);
|
|
41703
|
-
// @ts-expect-error - TS2554 - Expected 1 arguments, but got 0.
|
|
41704
|
-
perimeter.remove();
|
|
41705
|
-
perimeter = graphie.circle(coord0, radius, ___default["default"].extend({
|
|
41706
|
-
stroke: KhanColors.DYNAMIC,
|
|
41707
|
-
"stroke-width": 2
|
|
41708
|
-
}, options.normalStyle));
|
|
41709
|
-
};
|
|
41710
|
-
redrawPerim();
|
|
41711
|
-
if (points[1].remove && !options.editable) {
|
|
41712
|
-
points[1].remove();
|
|
41713
|
-
}
|
|
41714
|
-
return {
|
|
41715
|
-
update: redrawPerim,
|
|
41716
|
-
remove: function () {
|
|
41717
|
-
// Not _.bind because the remove function changes
|
|
41718
|
-
// when the perimeter is redrawn
|
|
41719
|
-
// @ts-expect-error - TS2554 - Expected 1 arguments, but got 0.
|
|
41720
|
-
perimeter.remove();
|
|
41721
|
-
}
|
|
41722
|
-
};
|
|
41723
|
-
}
|
|
41724
|
-
if (type === "point") {
|
|
41725
|
-
// do nothing
|
|
41726
|
-
return {
|
|
41727
|
-
update: null,
|
|
41728
|
-
remove: null
|
|
41729
|
-
};
|
|
41730
|
-
}
|
|
41731
|
-
throw new PerseusError("Invalid shape type " + type, Errors.InvalidInput);
|
|
41732
|
-
},
|
|
41733
|
-
_combine: function (type, coords) {
|
|
41734
|
-
return {
|
|
41735
|
-
type: type,
|
|
41736
|
-
coords: coords
|
|
41737
|
-
};
|
|
41738
|
-
},
|
|
41739
|
-
polygon: {
|
|
41740
|
-
equal: orderInsensitiveCoordsEqual
|
|
41741
|
-
},
|
|
41742
|
-
line: {
|
|
41743
|
-
equal: kmath.line.equal
|
|
41744
|
-
},
|
|
41745
|
-
lineSegment: {
|
|
41746
|
-
equal: orderInsensitiveCoordsEqual
|
|
41747
|
-
},
|
|
41748
|
-
angle: {
|
|
41749
|
-
equal: function (points1, points2) {
|
|
41750
|
-
if (!kmath.point.equal(points1[1], points2[1])) {
|
|
41751
|
-
return false;
|
|
41752
|
-
}
|
|
41753
|
-
const line1_0 = [points1[1], points1[0]];
|
|
41754
|
-
const line1_2 = [points1[1], points1[2]];
|
|
41755
|
-
const line2_0 = [points2[1], points2[0]];
|
|
41756
|
-
const line2_2 = [points2[1], points2[2]];
|
|
41757
|
-
const equalUnflipped =
|
|
41758
|
-
// @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
|
|
41759
|
-
kmath.ray.equal(line1_0, line2_0) && kmath.ray.equal(line1_2, line2_2);
|
|
41760
|
-
const equalFlipped =
|
|
41761
|
-
// @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'. | TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'Ray'.
|
|
41762
|
-
kmath.ray.equal(line1_0, line2_2) && kmath.ray.equal(line1_2, line2_0);
|
|
41763
|
-
return equalUnflipped || equalFlipped;
|
|
41764
|
-
},
|
|
41765
|
-
defaultOptions: {
|
|
41766
|
-
reflex: false
|
|
41767
|
-
}
|
|
41768
|
-
},
|
|
41769
|
-
circle: {
|
|
41770
|
-
equal: function (points1, points2) {
|
|
41771
|
-
const radius1 = kmath.point.distanceToPoint(points1[0], points1[1]);
|
|
41772
|
-
const radius2 = kmath.point.distanceToPoint(points2[0], points2[1]);
|
|
41773
|
-
return kmath.point.equal(points1[0], points2[0]) && kmath.number.equal(radius1, radius2);
|
|
41774
|
-
}
|
|
41775
|
-
},
|
|
41776
|
-
point: {
|
|
41777
|
-
equal: kmath.point.equal
|
|
41778
|
-
}
|
|
41779
|
-
};
|
|
41780
|
-
const TransformationListItem = TransformOps.ListItem;
|
|
41781
|
-
class TransformationList extends React__namespace.Component {
|
|
41782
|
-
render() {
|
|
41783
|
-
if (this.props.mode === "static") {
|
|
41784
|
-
return /*#__PURE__*/React__namespace.createElement("span", null); // don't render anything
|
|
41785
|
-
}
|
|
41786
|
-
|
|
41787
|
-
const transformationList = ___default["default"].map(this.props.transformations, function (transform, i) {
|
|
41788
|
-
return /*#__PURE__*/React__namespace.createElement(TransformationListItem, {
|
|
41789
|
-
ref: "transformation" + i,
|
|
41790
|
-
key: "transformation" + i,
|
|
41791
|
-
transform: transform
|
|
41792
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41793
|
-
,
|
|
41794
|
-
mode: this.props.mode
|
|
41795
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41796
|
-
,
|
|
41797
|
-
onChange: this.handleChange
|
|
41798
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41799
|
-
,
|
|
41800
|
-
onFocus: ___default["default"].partial(this.props.onFocus, "" + i)
|
|
41801
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41802
|
-
,
|
|
41803
|
-
onBlur: ___default["default"].partial(this.props.onBlur, "" + i)
|
|
41804
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41805
|
-
,
|
|
41806
|
-
keypadElement: this.props.keypadElement
|
|
41807
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41808
|
-
,
|
|
41809
|
-
apiOptions: this.props.apiOptions
|
|
41810
|
-
});
|
|
41811
|
-
}, this);
|
|
41812
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
41813
|
-
className: "perseus-transformation-list"
|
|
41814
|
-
}, transformationList);
|
|
41815
|
-
}
|
|
41816
|
-
_transformationRefs = () => {
|
|
41817
|
-
return ___default["default"].times(this.props.transformations.length, i => {
|
|
41818
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41819
|
-
return this.refs["transformation" + i];
|
|
41820
|
-
});
|
|
41821
|
-
};
|
|
41822
|
-
value = () => {
|
|
41823
|
-
return ___default["default"].invoke(this._transformationRefs(), "value");
|
|
41824
|
-
};
|
|
41825
|
-
handleChange = (changed, callback) => {
|
|
41826
|
-
this.props.onChange(this.value(), callback);
|
|
41827
|
-
};
|
|
41828
|
-
focusLast = () => {
|
|
41829
|
-
const transformationRefs = this._transformationRefs();
|
|
41830
|
-
if (transformationRefs.length !== 0) {
|
|
41831
|
-
// @ts-expect-error - TS2532 - Object is possibly 'undefined'. | TS2339 - Property 'focus' does not exist on type 'ReactInstance'.
|
|
41832
|
-
___default["default"].last(transformationRefs).focus();
|
|
41833
|
-
}
|
|
41834
|
-
};
|
|
41835
|
-
}
|
|
41836
|
-
class ToolButton extends React__namespace.Component {
|
|
41837
|
-
render() {
|
|
41838
|
-
const classes = this.props.toggled ? "simple-button exercise-orange toggled highlighted-tool-button" : "simple-button";
|
|
41839
|
-
return /*#__PURE__*/React__namespace.createElement("button", {
|
|
41840
|
-
type: "button",
|
|
41841
|
-
className: classes,
|
|
41842
|
-
disabled: this.props.disabled,
|
|
41843
|
-
onClick: this.props.onClick
|
|
41844
|
-
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
|
|
41845
|
-
,
|
|
41846
|
-
onTouchStart: captureScratchpadTouchStart
|
|
41847
|
-
}, this.props.children);
|
|
41848
|
-
}
|
|
41849
|
-
}
|
|
41850
|
-
class ToolsBar extends React__namespace.Component {
|
|
41851
|
-
state = {
|
|
41852
|
-
selected: null
|
|
41853
|
-
};
|
|
41854
|
-
render() {
|
|
41855
|
-
const tools = ___default["default"].map(Transformations, function (tool, type) {
|
|
41856
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41857
|
-
if (this.props.enabled[type]) {
|
|
41858
|
-
return /*#__PURE__*/React__namespace.createElement(ToolButton, {
|
|
41859
|
-
key: type
|
|
41860
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41861
|
-
,
|
|
41862
|
-
disabled: this.props.apiOptions.readOnly
|
|
41863
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41864
|
-
,
|
|
41865
|
-
toggled: this.state.selected === type
|
|
41866
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41867
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41868
|
-
,
|
|
41869
|
-
onClick: this.changeSelected.bind(this, type)
|
|
41870
|
-
}, tool.verbName);
|
|
41871
|
-
}
|
|
41872
|
-
}, this);
|
|
41873
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
41874
|
-
className: "transformer-tools-bar"
|
|
41875
|
-
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
41876
|
-
className: "simple-button-group"
|
|
41877
|
-
}, tools), /*#__PURE__*/React__namespace.createElement("button", {
|
|
41878
|
-
className: "transformer-undo-button simple-button",
|
|
41879
|
-
type: "button",
|
|
41880
|
-
disabled: this.props.apiOptions.readOnly,
|
|
41881
|
-
onClick: this.props.onUndoClick
|
|
41882
|
-
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
|
|
41883
|
-
,
|
|
41884
|
-
onTouchStart: captureScratchpadTouchStart
|
|
41885
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconUndo), " " + i18n__namespace._("Undo")), /*#__PURE__*/React__namespace.createElement("div", {
|
|
41886
|
-
className: "clear"
|
|
41887
|
-
}));
|
|
41888
|
-
}
|
|
41889
|
-
changeSelected = tool => {
|
|
41890
|
-
this.props.removeTool(this.state.selected);
|
|
41891
|
-
if (!tool || tool === this.state.selected) {
|
|
41892
|
-
this.setState({
|
|
41893
|
-
selected: null
|
|
41894
|
-
});
|
|
41895
|
-
} else {
|
|
41896
|
-
this.props.addTool(tool);
|
|
41897
|
-
this.setState({
|
|
41898
|
-
selected: tool
|
|
41899
|
-
});
|
|
41900
|
-
}
|
|
41901
|
-
};
|
|
41902
|
-
}
|
|
41903
|
-
class AddTransformBar extends React__namespace.Component {
|
|
41904
|
-
render() {
|
|
41905
|
-
const tools = ___default["default"].map(Transformations, function (tool, type) {
|
|
41906
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41907
|
-
if (this.props.enabled[type]) {
|
|
41908
|
-
return /*#__PURE__*/React__namespace.createElement(ToolButton, {
|
|
41909
|
-
key: type,
|
|
41910
|
-
toggled: false
|
|
41911
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41912
|
-
,
|
|
41913
|
-
disabled: this.props.apiOptions.readOnly
|
|
41914
|
-
// eslint-disable-next-line react/jsx-no-bind
|
|
41915
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation. | TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
41916
|
-
,
|
|
41917
|
-
onClick: this.changeSelected.bind(this, type)
|
|
41918
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconPlus), " ", tool.nounName);
|
|
41919
|
-
}
|
|
41920
|
-
}, this);
|
|
41921
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
41922
|
-
className: "transformer-tools-bar"
|
|
41923
|
-
}, tools, /*#__PURE__*/React__namespace.createElement("button", {
|
|
41924
|
-
className: "transformer-undo-button simple-button",
|
|
41925
|
-
type: "button",
|
|
41926
|
-
onClick: this.props.onUndoClick,
|
|
41927
|
-
disabled: this.props.apiOptions.readOnly
|
|
41928
|
-
// @ts-expect-error - TS2322 - Type '(e: TouchEvent) => void' is not assignable to type 'TouchEventHandler<HTMLButtonElement>'.
|
|
41929
|
-
,
|
|
41930
|
-
onTouchStart: captureScratchpadTouchStart
|
|
41931
|
-
}, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconUndo), " " + i18n__namespace._("Undo")), /*#__PURE__*/React__namespace.createElement("div", {
|
|
41932
|
-
className: "clear"
|
|
41933
|
-
}));
|
|
41934
|
-
}
|
|
41935
|
-
changeSelected = tool => {
|
|
41936
|
-
if (tool) {
|
|
41937
|
-
this.props.addTool(tool);
|
|
41938
|
-
}
|
|
41939
|
-
};
|
|
41940
|
-
}
|
|
41941
|
-
|
|
41942
|
-
// there's no transform in the exports
|
|
41943
|
-
|
|
41944
|
-
class Transformer extends React__namespace.Component {
|
|
41945
|
-
// @ts-expect-error - TS2564 - Property 'tools' has no initializer and is not definitely assigned in the constructor.
|
|
41946
|
-
|
|
41947
|
-
// @ts-expect-error - TS2564 - Property 'transformations' has no initializer and is not definitely assigned in the constructor.
|
|
41948
|
-
|
|
41949
|
-
// This is not the same as TransformerShape
|
|
41950
|
-
|
|
41951
|
-
static defaultProps = ___default["default"].defaults({
|
|
41952
|
-
transformations: []
|
|
41953
|
-
}, defaultTransformerProps);
|
|
41954
|
-
render() {
|
|
41955
|
-
// Fill in any missing value in this.props.graph
|
|
41956
|
-
// this can happen because the graph json doesn't include
|
|
41957
|
-
// box, for example
|
|
41958
|
-
const graph = ___default["default"].extend(defaultGraphProps(this.props.graph, defaultBoxSize), this.props.graph);
|
|
41959
|
-
const interactiveToolsMode = this.props.graphMode === "interactive";
|
|
41960
|
-
const ToolsBarClass = interactiveToolsMode ? ToolsBar : AddTransformBar;
|
|
41961
|
-
|
|
41962
|
-
// This style is applied inline because it is dependent on the
|
|
41963
|
-
// size of the graph as set by the graph.box prop, and this also
|
|
41964
|
-
// lets us specify it in the same place the graph's width is
|
|
41965
|
-
// specified.
|
|
41966
|
-
const toolsBar = /*#__PURE__*/React__namespace.createElement("div", {
|
|
41967
|
-
style: {
|
|
41968
|
-
width: graph.box[0]
|
|
41969
|
-
}
|
|
41970
|
-
}, /*#__PURE__*/React__namespace.createElement(ToolsBarClass
|
|
41971
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41972
|
-
, {
|
|
41973
|
-
ref: "toolsBar",
|
|
41974
|
-
enabled: pluckObject(this.props.tools, "enabled"),
|
|
41975
|
-
apiOptions: this.props.apiOptions,
|
|
41976
|
-
addTool: this.addTool,
|
|
41977
|
-
removeTool: this.removeTool,
|
|
41978
|
-
onUndoClick: this.handleUndoClick
|
|
41979
|
-
}));
|
|
41980
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
41981
|
-
className: "perseus-widget " + "perseus-widget-transformer"
|
|
41982
|
-
}, /*#__PURE__*/React__namespace.createElement(Graph
|
|
41983
|
-
// eslint-disable-next-line react/no-string-refs
|
|
41984
|
-
, {
|
|
41985
|
-
ref: "graph",
|
|
41986
|
-
box: graph.box,
|
|
41987
|
-
range: graph.range,
|
|
41988
|
-
labels: graph.labels,
|
|
41989
|
-
step: graph.step,
|
|
41990
|
-
gridStep: graph.gridStep,
|
|
41991
|
-
markings: graph.markings,
|
|
41992
|
-
backgroundImage: graph.backgroundImage,
|
|
41993
|
-
showProtractor: graph.showProtractor,
|
|
41994
|
-
onGraphieUpdated: this.setupGraphie,
|
|
41995
|
-
setDrawingAreaAvailable: this.props.apiOptions.setDrawingAreaAvailable
|
|
41996
|
-
}), !interactiveToolsMode && i18n__namespace._("Add transformations below:"), this.props.graphMode === "static" && [/*#__PURE__*/React__namespace.createElement("br", {
|
|
41997
|
-
key: "static-br"
|
|
41998
|
-
}), /*#__PURE__*/React__namespace.createElement("em", {
|
|
41999
|
-
key: "static-nomove"
|
|
42000
|
-
}, " ", i18n__namespace._("Note: For this question, the shape will not move."), " ")], interactiveToolsMode && toolsBar, /*#__PURE__*/React__namespace.createElement(TransformationList
|
|
42001
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42002
|
-
, {
|
|
42003
|
-
ref: "transformationList",
|
|
42004
|
-
mode: this.props.listMode,
|
|
42005
|
-
transformations: this.props.transformations,
|
|
42006
|
-
onChange: this.setTransformationProps,
|
|
42007
|
-
onFocus: this._handleFocus,
|
|
42008
|
-
onBlur: this._handleBlur,
|
|
42009
|
-
keypadElement: this.props.keypadElement,
|
|
42010
|
-
apiOptions: this.props.apiOptions
|
|
42011
|
-
}), !interactiveToolsMode && toolsBar);
|
|
42012
|
-
}
|
|
42013
|
-
componentDidMount() {
|
|
42014
|
-
this.setupGraphie(this.graphie());
|
|
42015
|
-
}
|
|
42016
|
-
componentDidUpdate(prevProps) {
|
|
42017
|
-
if (this.shouldSetupGraphie(this.props, prevProps)) {
|
|
42018
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42019
|
-
// @ts-expect-error - TS2339 - Property 'reset' does not exist on type 'ReactInstance'.
|
|
42020
|
-
this.refs.graph.reset();
|
|
42021
|
-
} else if (!deepEq(this.props.transformations, this.transformations)) {
|
|
42022
|
-
this.setTransformations(this.props.transformations);
|
|
42023
|
-
}
|
|
42024
|
-
}
|
|
42025
|
-
shouldSetupGraphie = (nextProps, prevProps) => {
|
|
42026
|
-
if (!deepEq(prevProps.starting, nextProps.starting)) {
|
|
42027
|
-
return true;
|
|
42028
|
-
}
|
|
42029
|
-
if (prevProps.graphMode !== nextProps.graphMode) {
|
|
42030
|
-
return true;
|
|
42031
|
-
}
|
|
42032
|
-
if (prevProps.listMode !== nextProps.listMode) {
|
|
42033
|
-
return true;
|
|
42034
|
-
}
|
|
42035
|
-
if (prevProps.drawSolutionShape !== nextProps.drawSolutionShape) {
|
|
42036
|
-
return true;
|
|
42037
|
-
}
|
|
42038
|
-
if (nextProps.drawSolutionShape && !deepEq(prevProps.correct.shape, nextProps.correct.shape)) {
|
|
42039
|
-
return true;
|
|
42040
|
-
}
|
|
42041
|
-
if (!deepEq(this.tools, nextProps.tools)) {
|
|
42042
|
-
return true;
|
|
42043
|
-
}
|
|
42044
|
-
return false;
|
|
42045
|
-
};
|
|
42046
|
-
graphie = () => {
|
|
42047
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42048
|
-
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
|
|
42049
|
-
return this.refs.graph.graphie();
|
|
42050
|
-
};
|
|
42051
|
-
setupGraphie = graphie => {
|
|
42052
|
-
// A background image of our solution:
|
|
42053
|
-
if (this.props.drawSolutionShape && this.props.correct.shape && this.props.correct.shape.coords) {
|
|
42054
|
-
// @ts-expect-error - TS2554 - Expected 3 arguments, but got 2.
|
|
42055
|
-
ShapeTypes.addShape(graphie, {
|
|
42056
|
-
fixed: true,
|
|
42057
|
-
shape: this.props.correct.shape,
|
|
42058
|
-
normalStyle: {
|
|
42059
|
-
stroke: KhanColors.GRAY,
|
|
42060
|
-
"stroke-dasharray": "",
|
|
42061
|
-
"stroke-width": 2
|
|
42062
|
-
}
|
|
42063
|
-
});
|
|
42064
|
-
}
|
|
42065
|
-
this.currentTool = null;
|
|
42066
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42067
|
-
// @ts-expect-error - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
|
|
42068
|
-
this.refs.toolsBar.changeSelected(null);
|
|
42069
|
-
this.addTransformerShape(this.props.starting.shape, /* translatable */false);
|
|
42070
|
-
this.setTransformations(this.props.transformations);
|
|
42071
|
-
|
|
42072
|
-
// Save a copy of our tools so that we can check future
|
|
42073
|
-
// this.props.tools changes against them
|
|
42074
|
-
// This seems weird, but gives us an easy way to tell whether
|
|
42075
|
-
// props changes were self-inflicted (for which a graphie reset
|
|
42076
|
-
// is not required, and is in fact a bad idea right now because
|
|
42077
|
-
// of resetting the size of the dilation tool).
|
|
42078
|
-
// TODO (jack): A deepClone method would be nice here
|
|
42079
|
-
this.tools = {
|
|
42080
|
-
translation: ___default["default"].clone(this.props.tools.translation),
|
|
42081
|
-
rotation: ___default["default"].clone(this.props.tools.rotation),
|
|
42082
|
-
reflection: ___default["default"].clone(this.props.tools.reflection),
|
|
42083
|
-
dilation: ___default["default"].clone(this.props.tools.dilation)
|
|
42084
|
-
};
|
|
42085
|
-
};
|
|
42086
|
-
|
|
42087
|
-
/* Applies all transformations in `transformations`
|
|
42088
|
-
* to the starting shape, and updates this.transformations
|
|
42089
|
-
* to reflect this
|
|
42090
|
-
*
|
|
42091
|
-
* Usually called with this.props.transformations
|
|
42092
|
-
*/
|
|
42093
|
-
setTransformations = transformations => {
|
|
42094
|
-
this.resetCoords();
|
|
42095
|
-
this.transformations = ___default["default"].clone(transformations);
|
|
42096
|
-
___default["default"].each(this.transformations, this.applyTransform);
|
|
42097
|
-
};
|
|
42098
|
-
|
|
42099
|
-
// the polygon that we transform
|
|
42100
|
-
addTransformerShape = (shape, translatable) => {
|
|
42101
|
-
const self = this;
|
|
42102
|
-
const graphie = this.graphie();
|
|
42103
|
-
this.shape = ShapeTypes.addMovableShape(graphie, {
|
|
42104
|
-
shape: shape,
|
|
42105
|
-
editable: false,
|
|
42106
|
-
showPoints: this.props.graphMode !== "static",
|
|
42107
|
-
translatable: translatable,
|
|
42108
|
-
onMove: function (dX, dY) {
|
|
42109
|
-
dX = KhanMath.roundToNearest(graphie.snap[0], dX);
|
|
42110
|
-
dY = KhanMath.roundToNearest(graphie.snap[1], dY);
|
|
42111
|
-
// NOTE(kevinb): object is missing .constraints property
|
|
42112
|
-
// @ts-expect-error - TS2345 - Argument of type '{ type: "translation"; vector: [any, any]; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
|
|
42113
|
-
self.addTransform({
|
|
42114
|
-
type: "translation",
|
|
42115
|
-
vector: [dX, dY]
|
|
42116
|
-
});
|
|
42117
|
-
return [dX, dY];
|
|
42118
|
-
},
|
|
42119
|
-
normalPointStyle: {
|
|
42120
|
-
fill: translatable ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC,
|
|
42121
|
-
stroke: translatable ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC
|
|
42122
|
-
},
|
|
42123
|
-
highlightPointStyle: {
|
|
42124
|
-
fill: KhanColors.INTERACTING,
|
|
42125
|
-
stroke: KhanColors.INTERACTING
|
|
42126
|
-
}
|
|
42127
|
-
});
|
|
42128
|
-
};
|
|
42129
|
-
addTool = toolId => {
|
|
42130
|
-
const self = this;
|
|
42131
|
-
if (this.props.graphMode === "interactive") {
|
|
42132
|
-
if (toolId === "translation") {
|
|
42133
|
-
this.currentTool = this.addTranslationTool();
|
|
42134
|
-
} else if (toolId === "rotation") {
|
|
42135
|
-
this.currentTool = this.addRotationTool();
|
|
42136
|
-
} else if (toolId === "reflection") {
|
|
42137
|
-
this.currentTool = this.addReflectionTool();
|
|
42138
|
-
} else if (toolId === "dilation") {
|
|
42139
|
-
this.currentTool = this.addDilationTool();
|
|
42140
|
-
} else {
|
|
42141
|
-
throw new PerseusError("Invalid tool id: " + toolId, Errors.InvalidInput);
|
|
42142
|
-
}
|
|
42143
|
-
} else {
|
|
42144
|
-
let transform;
|
|
42145
|
-
if (toolId === "translation") {
|
|
42146
|
-
// NOTE(kevinb): object is missing .constraints property
|
|
42147
|
-
transform = {
|
|
42148
|
-
type: "translation",
|
|
42149
|
-
// NOTE(kevib): these should be numbers
|
|
42150
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42151
|
-
vector: [null, null]
|
|
42152
|
-
};
|
|
42153
|
-
} else if (toolId === "rotation") {
|
|
42154
|
-
// NOTE(kevinb): object is missing .constraints property
|
|
42155
|
-
transform = {
|
|
42156
|
-
type: "rotation",
|
|
42157
|
-
// NOTE(kevib): these should be numbers
|
|
42158
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42159
|
-
center: [null, null],
|
|
42160
|
-
// NOTE(kevib): this should be a number
|
|
42161
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42162
|
-
angleDeg: null
|
|
42163
|
-
};
|
|
42164
|
-
} else if (toolId === "reflection") {
|
|
42165
|
-
// Reflections with nulls in them won't be applied until
|
|
42166
|
-
// fills in the blanks
|
|
42167
|
-
transform = {
|
|
42168
|
-
type: "reflection",
|
|
42169
|
-
line: [
|
|
42170
|
-
// NOTE(kevib): these should be numbers
|
|
42171
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42172
|
-
[null, null],
|
|
42173
|
-
// NOTE(kevib): these should be numbers
|
|
42174
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42175
|
-
[null, null]]
|
|
42176
|
-
};
|
|
42177
|
-
} else if (toolId === "dilation") {
|
|
42178
|
-
// NOTE(kevinb): object is missing .constraints property
|
|
42179
|
-
transform = {
|
|
42180
|
-
type: "dilation",
|
|
42181
|
-
// NOTE(kevib): these should be numbers
|
|
42182
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'. | TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42183
|
-
center: [null, null],
|
|
42184
|
-
// NOTE(kevib): this should be a number
|
|
42185
|
-
// @ts-expect-error - TS2322 - Type 'null' is not assignable to type 'number'.
|
|
42186
|
-
scale: null
|
|
42187
|
-
};
|
|
42188
|
-
} else {
|
|
42189
|
-
throw new PerseusError("Invalid tool id: " + toolId, Errors.InvalidInput);
|
|
42190
|
-
}
|
|
42191
|
-
this.doTransform(transform, function () {
|
|
42192
|
-
// @ts-expect-error - TS2339 - Property 'focusLast' does not exist on type 'ReactInstance'.
|
|
42193
|
-
self.refs.transformationList.focusLast();
|
|
42194
|
-
});
|
|
42195
|
-
}
|
|
42196
|
-
};
|
|
42197
|
-
removeTool = toolId => {
|
|
42198
|
-
if (this.currentTool) {
|
|
42199
|
-
this.currentTool.remove();
|
|
42200
|
-
}
|
|
42201
|
-
this.currentTool = null;
|
|
42202
|
-
};
|
|
42203
|
-
addTranslationTool = () => {
|
|
42204
|
-
const self = this;
|
|
42205
|
-
this.shape?.remove();
|
|
42206
|
-
this.addTransformerShape(this.shape?.toJSON(), /* translatable */true);
|
|
42207
|
-
return {
|
|
42208
|
-
remove: function () {
|
|
42209
|
-
self.shape?.remove();
|
|
42210
|
-
self.addTransformerShape(self.shape?.toJSON(), /* translatable */false);
|
|
42211
|
-
}
|
|
42212
|
-
};
|
|
42213
|
-
};
|
|
42214
|
-
|
|
42215
|
-
// Snaps a coord to this.graphie()'s snap
|
|
42216
|
-
// @ts-expect-error - TS2322 - Type '(coord: Coord) => number[]' is not assignable to type '(arg1: Coord) => Coord'.
|
|
42217
|
-
snapCoord = coord => {
|
|
42218
|
-
const graphie = this.graphie();
|
|
42219
|
-
return ___default["default"].map(coord, function (val, dim) {
|
|
42220
|
-
return KhanMath.roundToNearest(graphie.snap[dim], val);
|
|
42221
|
-
});
|
|
42222
|
-
};
|
|
42223
|
-
|
|
42224
|
-
// Normalize the coords into something that fits the new 45 degree
|
|
42225
|
-
// reflection line.
|
|
42226
|
-
// @ts-expect-error - TS2322 - Type '(messyCoords: [Coord, Coord]) => any[]' is not assignable to type '(arg1: [Coord, Coord]) => [Coord, Coord]'.
|
|
42227
|
-
normalizeReflectionCoords = messyCoords => {
|
|
42228
|
-
// @ts-expect-error - TS2345 - Argument of type 'Point' is not assignable to parameter of type 'Coord'.
|
|
42229
|
-
const midpoint = this.snapCoord(kmath.line.midpoint(messyCoords));
|
|
42230
|
-
const origDirectionPolar = kmath.vector.polarDegFromCart(kmath.vector.subtract(messyCoords[0], messyCoords[1]));
|
|
42231
|
-
const direction = kmath.vector.cartFromPolarDeg(1, KhanMath.roundToNearest(45, origDirectionPolar[1]));
|
|
42232
|
-
const coords = ___default["default"].map([-1, 1], function (directionCoefficient) {
|
|
42233
|
-
const coord = kmath.vector.add(midpoint, kmath.vector.scale(direction, directionCoefficient *
|
|
42234
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
42235
|
-
this.scaleToCurrentRange(REFLECT_ROTATE_HANDLE_DIST)));
|
|
42236
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
42237
|
-
return this.snapCoord(coord);
|
|
42238
|
-
}, this);
|
|
42239
|
-
return coords;
|
|
42240
|
-
};
|
|
42241
|
-
addReflectionTool = () => {
|
|
42242
|
-
const options = this.props.tools.reflection;
|
|
42243
|
-
if (!options.enabled) {
|
|
42244
|
-
return;
|
|
42245
|
-
}
|
|
42246
|
-
const self = this;
|
|
42247
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42248
|
-
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
|
|
42249
|
-
const graphie = this.refs.graph.graphie();
|
|
42250
|
-
const updateReflectionTool = function () {
|
|
42251
|
-
self.changeTool("reflection", {
|
|
42252
|
-
coords: ___default["default"].pluck(reflectPoints, "coord")
|
|
42253
|
-
});
|
|
42254
|
-
};
|
|
42255
|
-
const coords = this.normalizeReflectionCoords(options.coords);
|
|
42256
|
-
|
|
42257
|
-
// The points defining the line of reflection; hidden from the
|
|
42258
|
-
// user.
|
|
42259
|
-
const reflectPoints = ___default["default"].map(coords, function (coord) {
|
|
42260
|
-
return graphie.addMovablePoint({
|
|
42261
|
-
coord: coord,
|
|
42262
|
-
visible: false
|
|
42263
|
-
});
|
|
42264
|
-
}, this);
|
|
42265
|
-
|
|
42266
|
-
// the line of reflection
|
|
42267
|
-
// TODO(jack): graphie.style here is a hack to prevent the dashed
|
|
42268
|
-
// style from leaking into the rest of the shapes. Remove when
|
|
42269
|
-
// graphie.addMovableLineSegment doesn't leak styles anymore.
|
|
42270
|
-
let reflectLine;
|
|
42271
|
-
const normalColor = colorForTool(options);
|
|
42272
|
-
graphie.style({}, function () {
|
|
42273
|
-
reflectLine = graphie.addMovableLineSegment({
|
|
42274
|
-
fixed: options.constraints.fixed,
|
|
42275
|
-
constraints: options.constraints,
|
|
42276
|
-
pointA: reflectPoints[0],
|
|
42277
|
-
pointZ: reflectPoints[1],
|
|
42278
|
-
snapX: graphie.snap[0],
|
|
42279
|
-
snapY: graphie.snap[1],
|
|
42280
|
-
extendLine: true,
|
|
42281
|
-
normalStyle: {
|
|
42282
|
-
stroke: normalColor,
|
|
42283
|
-
"stroke-width": 2,
|
|
42284
|
-
"stroke-dasharray": "- "
|
|
42285
|
-
},
|
|
42286
|
-
highlightStyle: {
|
|
42287
|
-
stroke: KhanColors.INTERACTING,
|
|
42288
|
-
"stroke-width": 2,
|
|
42289
|
-
"stroke-dasharray": "- " // TODO(jack) solid doesn't
|
|
42290
|
-
// work here, but would be
|
|
42291
|
-
// nicer
|
|
42292
|
-
},
|
|
42293
|
-
|
|
42294
|
-
movePointsWithLine: true,
|
|
42295
|
-
onMoveEnd: updateReflectionTool
|
|
42296
|
-
});
|
|
42297
|
-
});
|
|
42298
|
-
|
|
42299
|
-
// the "button" point in the center of the line of reflection
|
|
42300
|
-
const reflectButton = graphie.addReflectButton({
|
|
42301
|
-
fixed: options.constraints.fixed,
|
|
42302
|
-
line: reflectLine,
|
|
42303
|
-
size: this.scaleToCurrentRange(REFLECT_BUTTON_SIZE),
|
|
42304
|
-
onClick: function () {
|
|
42305
|
-
self.doTransform({
|
|
42306
|
-
type: "reflection",
|
|
42307
|
-
// @ts-expect-error - TS2322 - Type 'any[]' is not assignable to type '[Coord, Coord]'.
|
|
42308
|
-
line: ___default["default"].pluck(reflectPoints, "coord")
|
|
42309
|
-
});
|
|
42310
|
-
if (reflectRotateHandle) {
|
|
42311
|
-
// flip the rotation handle
|
|
42312
|
-
// @ts-expect-error - TS2339 - Property 'setCoord' does not exist on type 'never'.
|
|
42313
|
-
reflectRotateHandle.setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.subtract(reflectButton.coord,
|
|
42314
|
-
// @ts-expect-error - TS2339 - Property 'coord' does not exist on type 'never'.
|
|
42315
|
-
reflectRotateHandle.coord)));
|
|
42316
|
-
// @ts-expect-error - TS2339 - Property 'update' does not exist on type 'never'.
|
|
42317
|
-
reflectRotateHandle.update();
|
|
42318
|
-
}
|
|
42319
|
-
},
|
|
42320
|
-
normalStyle: {
|
|
42321
|
-
stroke: normalColor,
|
|
42322
|
-
"stroke-width": 2,
|
|
42323
|
-
fill: normalColor
|
|
42324
|
-
},
|
|
42325
|
-
highlightStyle: {
|
|
42326
|
-
stroke: KhanColors.INTERACTING,
|
|
42327
|
-
"stroke-width": 3,
|
|
42328
|
-
fill: KhanColors.INTERACTING
|
|
42329
|
-
},
|
|
42330
|
-
onMoveEnd: updateReflectionTool
|
|
42331
|
-
});
|
|
42332
|
-
let reflectRotateHandle = null;
|
|
42333
|
-
if (!options.constraints.fixed) {
|
|
42334
|
-
// The rotation handle for rotating the line of reflection
|
|
42335
|
-
const initRotateHandleAngle = kmath.vector.polarDegFromCart(kmath.vector.subtract(reflectPoints[1].coord, reflectPoints[0].coord))[1] + 90; // 90 degrees off of the line
|
|
42336
|
-
reflectRotateHandle = graphie.addRotateHandle({
|
|
42337
|
-
center: reflectButton,
|
|
42338
|
-
radius: this.scaleToCurrentRange(REFLECT_ROTATE_HANDLE_DIST),
|
|
42339
|
-
angleDeg: initRotateHandleAngle,
|
|
42340
|
-
width: this.scaleToCurrentRange(0.24),
|
|
42341
|
-
hoverWidth: this.scaleToCurrentRange(0.4),
|
|
42342
|
-
lengthAngle: 17,
|
|
42343
|
-
onMove: function (newAngle) {
|
|
42344
|
-
return KhanMath.roundToNearest(45, newAngle);
|
|
42345
|
-
},
|
|
42346
|
-
onMoveEnd: updateReflectionTool
|
|
42347
|
-
});
|
|
42348
|
-
}
|
|
42349
|
-
|
|
42350
|
-
// Move the reflectButton and reflectRotateHandle with the line
|
|
42351
|
-
$__default["default"](reflectLine).on("move", function () {
|
|
42352
|
-
reflectButton.update();
|
|
42353
|
-
$__default["default"](reflectButton).trigger("move"); // update the rotation handle,
|
|
42354
|
-
// which watches for this in util/interactive.js.
|
|
42355
|
-
});
|
|
42356
|
-
|
|
42357
|
-
// Update the line and reflect button when the reflectRotateHandle is
|
|
42358
|
-
// rotated
|
|
42359
|
-
if (reflectRotateHandle) {
|
|
42360
|
-
$__default["default"](reflectRotateHandle).on("move", function () {
|
|
42361
|
-
const rotateHandleApprox = self.snapCoord(
|
|
42362
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
42363
|
-
reflectRotateHandle.coord);
|
|
42364
|
-
const rotateVector = kmath.vector.subtract(rotateHandleApprox, reflectButton.coord);
|
|
42365
|
-
const flipped = reflectButton.isFlipped() ? 1 : 0;
|
|
42366
|
-
reflectPoints[flipped].setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.rotateDeg(rotateVector, 90)));
|
|
42367
|
-
reflectPoints[1 - flipped].setCoord(kmath.vector.add(reflectButton.coord, kmath.vector.rotateDeg(rotateVector, -90)));
|
|
42368
|
-
reflectLine.transform(true);
|
|
42369
|
-
reflectButton.update();
|
|
42370
|
-
});
|
|
42371
|
-
}
|
|
42372
|
-
return {
|
|
42373
|
-
remove: function () {
|
|
42374
|
-
reflectButton.remove();
|
|
42375
|
-
if (reflectRotateHandle) {
|
|
42376
|
-
// @ts-expect-error - TS2339 - Property 'remove' does not exist on type 'never'.
|
|
42377
|
-
reflectRotateHandle.remove();
|
|
42378
|
-
}
|
|
42379
|
-
reflectLine.remove();
|
|
42380
|
-
reflectPoints[0].remove();
|
|
42381
|
-
reflectPoints[1].remove();
|
|
42382
|
-
}
|
|
42383
|
-
};
|
|
42384
|
-
};
|
|
42385
|
-
|
|
42386
|
-
/* Scales a distance from the default range of
|
|
42387
|
-
* [-10, 10] to the current this.props.graph.range
|
|
42388
|
-
*
|
|
42389
|
-
* Used for sizing various transformation tools
|
|
42390
|
-
* (rotation handle, dilation circle)
|
|
42391
|
-
*/
|
|
42392
|
-
scaleToCurrentRange = dist => {
|
|
42393
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42394
|
-
// @ts-expect-error - TS2339 - Property 'props' does not exist on type 'ReactInstance'.
|
|
42395
|
-
return scaleToRange(dist, this.refs.graph.props.range);
|
|
42396
|
-
};
|
|
42397
|
-
addRotationTool = () => {
|
|
42398
|
-
const options = this.props.tools.rotation;
|
|
42399
|
-
if (!options.enabled) {
|
|
42400
|
-
return;
|
|
42401
|
-
}
|
|
42402
|
-
const self = this;
|
|
42403
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42404
|
-
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
|
|
42405
|
-
const graphie = this.refs.graph.graphie();
|
|
42406
|
-
const pointColor = colorForTool(options);
|
|
42407
|
-
// The center of our rotation, which can be moved to change the
|
|
42408
|
-
// center of rotation
|
|
42409
|
-
this.rotatePoint = graphie.addMovablePoint({
|
|
42410
|
-
constraints: options.constraints,
|
|
42411
|
-
coord: options.coord,
|
|
42412
|
-
snapX: graphie.snap[0],
|
|
42413
|
-
snapY: graphie.snap[1],
|
|
42414
|
-
normalStyle: {
|
|
42415
|
-
// ugh, this seems to be a global and
|
|
42416
|
-
"stroke-dasharray": "",
|
|
42417
|
-
// is set to dash above
|
|
42418
|
-
stroke: pointColor,
|
|
42419
|
-
fill: pointColor
|
|
42420
|
-
},
|
|
42421
|
-
highlightStyle: {
|
|
42422
|
-
"stroke-dasharray": "",
|
|
42423
|
-
stroke: KhanColors.INTERACTING,
|
|
42424
|
-
fill: KhanColors.INTERACTING
|
|
42425
|
-
}
|
|
42426
|
-
});
|
|
42427
|
-
|
|
42428
|
-
// The point that we move around the center of rotation to actually
|
|
42429
|
-
// cause rotations
|
|
42430
|
-
this.rotateHandle = graphie.addRotateHandle({
|
|
42431
|
-
center: this.rotatePoint,
|
|
42432
|
-
radius: this.scaleToCurrentRange(ROTATE_HANDLE_DIST),
|
|
42433
|
-
width: this.scaleToCurrentRange(0.24),
|
|
42434
|
-
hoverWidth: this.scaleToCurrentRange(0.4),
|
|
42435
|
-
onMove: function (newAngle, oldAngle) {
|
|
42436
|
-
const transform = self.getRotationTransformFromAngle(self.rotatePoint.coord, newAngle - oldAngle);
|
|
42437
|
-
|
|
42438
|
-
// Rotate polygon with rotateHandle
|
|
42439
|
-
self.doTransform(transform);
|
|
42440
|
-
|
|
42441
|
-
// @ts-expect-error - TS2339 - Property 'angleDeg' does not exist on type 'PerseusTransformerTransformation'.
|
|
42442
|
-
return oldAngle + transform.angleDeg;
|
|
42443
|
-
}
|
|
42444
|
-
});
|
|
42445
|
-
|
|
42446
|
-
// Update tools.rotation.coord
|
|
42447
|
-
this.rotatePoint.onMoveEnd = (x, y) => {
|
|
42448
|
-
self.changeTool("rotation", {
|
|
42449
|
-
coord: [x, y]
|
|
42450
|
-
});
|
|
42451
|
-
};
|
|
42452
|
-
return {
|
|
42453
|
-
remove: function () {
|
|
42454
|
-
self.rotateHandle?.remove();
|
|
42455
|
-
self.rotatePoint?.remove();
|
|
42456
|
-
}
|
|
42457
|
-
};
|
|
42458
|
-
};
|
|
42459
|
-
addDilationTool = () => {
|
|
42460
|
-
const options = this.props.tools.dilation;
|
|
42461
|
-
if (!options.enabled) {
|
|
42462
|
-
return;
|
|
42463
|
-
}
|
|
42464
|
-
const self = this;
|
|
42465
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42466
|
-
// @ts-expect-error - TS2339 - Property 'graphie' does not exist on type 'ReactInstance'.
|
|
42467
|
-
const graphie = this.refs.graph.graphie();
|
|
42468
|
-
const pointColor = colorForTool(options);
|
|
42469
|
-
// the circle for causing dilation transforms
|
|
42470
|
-
self.dilationCircle = graphie.addCircleGraph({
|
|
42471
|
-
centerConstraints: options.constraints,
|
|
42472
|
-
center: options.coord,
|
|
42473
|
-
radius: self.scaleToCurrentRange(2),
|
|
42474
|
-
snapX: graphie.snap[0],
|
|
42475
|
-
snapY: graphie.snap[1],
|
|
42476
|
-
minRadius: self.scaleToCurrentRange(1),
|
|
42477
|
-
snapRadius: self.scaleToCurrentRange(0.5),
|
|
42478
|
-
onResize: function (newRadius, oldRadius) {
|
|
42479
|
-
// NOTE(kevinb): object is missing .constraints property
|
|
42480
|
-
// @ts-expect-error - TS2345 - Argument of type '{ type: "dilation"; center: any; scale: number; }' is not assignable to parameter of type 'PerseusTransformerTransformation'.
|
|
42481
|
-
self.doTransform({
|
|
42482
|
-
type: "dilation",
|
|
42483
|
-
center: self.dilationCircle.centerPoint.coord,
|
|
42484
|
-
scale: newRadius / oldRadius
|
|
42485
|
-
});
|
|
42486
|
-
},
|
|
42487
|
-
circleNormalStyle: {
|
|
42488
|
-
stroke: pointColor,
|
|
42489
|
-
"stroke-width": 2,
|
|
42490
|
-
"stroke-dasharray": "- ",
|
|
42491
|
-
"fill-opacity": 0
|
|
42492
|
-
},
|
|
42493
|
-
circleHighlightStyle: {
|
|
42494
|
-
stroke: KhanColors.INTERACTING,
|
|
42495
|
-
"stroke-width": 2,
|
|
42496
|
-
"stroke-dasharray": "",
|
|
42497
|
-
fill: KhanColors.INTERACTING,
|
|
42498
|
-
"fill-opacity": 0.05
|
|
42499
|
-
},
|
|
42500
|
-
centerNormalStyle: {
|
|
42501
|
-
stroke: pointColor,
|
|
42502
|
-
fill: pointColor,
|
|
42503
|
-
"stroke-width": 2,
|
|
42504
|
-
"stroke-dasharray": ""
|
|
42505
|
-
},
|
|
42506
|
-
centerHighlightStyle: {
|
|
42507
|
-
stroke: pointColor,
|
|
42508
|
-
fill: pointColor,
|
|
42509
|
-
"stroke-width": 2,
|
|
42510
|
-
"stroke-dasharray": ""
|
|
42511
|
-
}
|
|
42512
|
-
});
|
|
42513
|
-
const origOnMoveEnd = this.dilationCircle.centerPoint.onMoveEnd;
|
|
42514
|
-
this.dilationCircle.centerPoint.onMoveEnd = function () {
|
|
42515
|
-
if (origOnMoveEnd) {
|
|
42516
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
42517
|
-
args[_key] = arguments[_key];
|
|
42518
|
-
}
|
|
42519
|
-
origOnMoveEnd(args);
|
|
42520
|
-
}
|
|
42521
|
-
self.changeTool("dilation", {
|
|
42522
|
-
coord: self.dilationCircle.centerPoint.coord
|
|
42523
|
-
});
|
|
42524
|
-
};
|
|
42525
|
-
return {
|
|
42526
|
-
remove: function () {
|
|
42527
|
-
self.dilationCircle?.remove();
|
|
42528
|
-
}
|
|
42529
|
-
};
|
|
42530
|
-
};
|
|
42531
|
-
|
|
42532
|
-
// returns a transformation object representing a rotation
|
|
42533
|
-
// rounds the angle to the nearest 15 degrees
|
|
42534
|
-
// @ts-expect-error - TS2322 - Type '(center: Coord, angleChanged: number) => { type: "rotation"; center: Coord; angleDeg: number; }' is not assignable to type '(arg1: Coord, arg2: number) => PerseusTransformerTransformation'.
|
|
42535
|
-
getRotationTransformFromAngle = (center, angleChanged) => {
|
|
42536
|
-
angleChanged = (angleChanged + 360) % 360;
|
|
42537
|
-
if (angleChanged > 180) {
|
|
42538
|
-
angleChanged -= 360;
|
|
42539
|
-
}
|
|
42540
|
-
const roundedAngle = Math.round(angleChanged / ROTATE_SNAP_DEGREES) * ROTATE_SNAP_DEGREES;
|
|
42541
|
-
|
|
42542
|
-
// NOTE(kevinb): return object is missing .constraints property
|
|
42543
|
-
return {
|
|
42544
|
-
type: "rotation",
|
|
42545
|
-
center: center,
|
|
42546
|
-
angleDeg: roundedAngle
|
|
42547
|
-
};
|
|
42548
|
-
};
|
|
42549
|
-
|
|
42550
|
-
// apply and save a transform
|
|
42551
|
-
doTransform = (transform, callback) => {
|
|
42552
|
-
this.applyTransform(transform);
|
|
42553
|
-
this.addTransform(transform, callback);
|
|
42554
|
-
};
|
|
42555
|
-
|
|
42556
|
-
// apply a transform to our polygon (without modifying our transformation
|
|
42557
|
-
// list)
|
|
42558
|
-
applyTransform = transform => {
|
|
42559
|
-
if (this.props.graphMode !== "static") {
|
|
42560
|
-
const transformFunc = TransformOps.apply(transform);
|
|
42561
|
-
// @ts-expect-error - TS2345 - Argument of type '(coord: any) => any' is not assignable to parameter of type 'PerseusTransformerTransformation'.
|
|
42562
|
-
this.applyCoordTransformation(transformFunc);
|
|
42563
|
-
}
|
|
42564
|
-
};
|
|
42565
|
-
|
|
42566
|
-
// transform our polygon by transforming each point using a given function
|
|
42567
|
-
applyCoordTransformation = pointTransform => {
|
|
42568
|
-
___default["default"].each(this.shape.points, function (point) {
|
|
42569
|
-
// @ts-expect-error - TS2349 - This expression is not callable.
|
|
42570
|
-
const newCoord = pointTransform(point.coord);
|
|
42571
|
-
point.setCoord(newCoord);
|
|
42572
|
-
});
|
|
42573
|
-
this.shape?.update();
|
|
42574
|
-
};
|
|
42575
|
-
resetCoords = () => {
|
|
42576
|
-
const startCoords = this.props.starting.shape.coords;
|
|
42577
|
-
___default["default"].each(this.shape.points, function (point, i) {
|
|
42578
|
-
point.setCoord(startCoords[i]);
|
|
42579
|
-
});
|
|
42580
|
-
this.shape?.update();
|
|
42581
|
-
};
|
|
42582
|
-
|
|
42583
|
-
// Remove the last transformation
|
|
42584
|
-
handleUndoClick = () => {
|
|
42585
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42586
|
-
// @ts-expect-error - TS2339 - Property 'changeSelected' does not exist on type 'ReactInstance'.
|
|
42587
|
-
this.refs.toolsBar.changeSelected(null);
|
|
42588
|
-
if (this.props.transformations.length) {
|
|
42589
|
-
this.props.onChange({
|
|
42590
|
-
transformations: ___default["default"].initial(this.props.transformations)
|
|
42591
|
-
});
|
|
42592
|
-
}
|
|
42593
|
-
};
|
|
42594
|
-
setTransformationProps = (newTransfomationList, callback) => {
|
|
42595
|
-
this.props.onChange({
|
|
42596
|
-
transformations: newTransfomationList
|
|
42597
|
-
},
|
|
42598
|
-
// @ts-expect-error - TS2345 - Argument of type '(arg1: any) => unknown' is not assignable to parameter of type '() => unknown'.
|
|
42599
|
-
callback);
|
|
42600
|
-
};
|
|
42601
|
-
|
|
42602
|
-
// add a transformation to our props list of transformation
|
|
42603
|
-
addTransform = (transform, callback) => {
|
|
42604
|
-
this.transformations = TransformOps.append(this.transformations, transform);
|
|
42605
|
-
this.props.onChange({
|
|
42606
|
-
transformations: ___default["default"].clone(this.transformations)
|
|
42607
|
-
},
|
|
42608
|
-
// @ts-expect-error - TS2345 - Argument of type '((arg1: any) => unknown) | undefined' is not assignable to parameter of type '(() => unknown) | undefined'.
|
|
42609
|
-
callback);
|
|
42610
|
-
};
|
|
42611
|
-
changeTool = (tool, changes) => {
|
|
42612
|
-
const newTools = ___default["default"].clone(this.props.tools);
|
|
42613
|
-
newTools[tool] = ___default["default"].extend({}, this.props.tools[tool], changes);
|
|
42614
|
-
this.tools[tool] = ___default["default"].clone(newTools[tool]);
|
|
42615
|
-
this.props.onChange({
|
|
42616
|
-
// @ts-expect-error - TS2740 - Type '{ dilation: DilationTool; reflection: ReflectionTool; rotation: RotationTool; translation: TranslationTool; }' is missing the following properties from type 'readonly any[]': length, concat, join, slice, and 18 more.
|
|
42617
|
-
tools: newTools
|
|
42618
|
-
});
|
|
42619
|
-
this.props.trackInteraction();
|
|
42620
|
-
};
|
|
42621
|
-
simpleValidate = rubric => {
|
|
42622
|
-
return Transformer.validate(this.getUserInput(), rubric);
|
|
42623
|
-
};
|
|
42624
|
-
|
|
42625
|
-
/**
|
|
42626
|
-
* Calculate where the coordinates would be if they were
|
|
42627
|
-
* moved, even if we're in formal mode with no movement
|
|
42628
|
-
* (and thus the actual movablepoints may not have moved
|
|
42629
|
-
*/
|
|
42630
|
-
// @ts-expect-error - TS2322 - Type '() => [Coord, Coord] | readonly Coord[] | [Coord, Coord, Coord]' is not assignable to type '() => Coord'.
|
|
42631
|
-
getCoords = () => {
|
|
42632
|
-
const startCoords = this.props.starting.shape.coords;
|
|
42633
|
-
const transforms = this.props.transformations;
|
|
42634
|
-
return ___default["default"].reduce(transforms, function (coords, transform) {
|
|
42635
|
-
return ___default["default"].map(coords, TransformOps.apply(transform));
|
|
42636
|
-
}, startCoords);
|
|
42637
|
-
};
|
|
42638
|
-
getEditorJSON = () => {
|
|
42639
|
-
const json = ___default["default"].pick(this.props, "grading", "starting", "graphMode", "listMode", "tools", "drawSolutionShape", "gradeEmpty");
|
|
42640
|
-
// eslint-disable-next-line react/no-string-refs
|
|
42641
|
-
// @ts-expect-error - TS2339 - Property 'graph' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'. | TS2339 - Property 'toJSON' does not exist on type 'ReactInstance'.
|
|
42642
|
-
json.graph = this.refs.graph.toJSON();
|
|
42643
|
-
// @ts-expect-error - TS2339 - Property 'version' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
|
|
42644
|
-
json.version = 1.2; // Give us some safety to change the format
|
|
42645
|
-
// when we realize that I wrote
|
|
42646
|
-
// a horrible json spec for this widget
|
|
42647
|
-
|
|
42648
|
-
// @ts-expect-error - TS2339 - Property 'answer' does not exist on type 'Pick<Readonly<Props> & Readonly<{ children?: ReactNode; }>, "tools" | "starting" | "drawSolutionShape" | "gradeEmpty" | "graphMode" | "listMode">'.
|
|
42649
|
-
json.answer = this.getUserInput();
|
|
42650
|
-
return json;
|
|
42651
|
-
};
|
|
42652
|
-
getUserInput = () => {
|
|
42653
|
-
return {
|
|
42654
|
-
transformations: this.props.transformations,
|
|
42655
|
-
// This doesn't call this.shape.toJSON() because that doesn't
|
|
42656
|
-
// handle coordinates in formal mode without movement, since
|
|
42657
|
-
// the movablepoints never move
|
|
42658
|
-
shape: {
|
|
42659
|
-
type: this.shape.type,
|
|
42660
|
-
coords: this.getCoords(),
|
|
42661
|
-
options: this.shape?.getOptions()
|
|
42662
|
-
}
|
|
42663
|
-
};
|
|
42664
|
-
};
|
|
42665
|
-
|
|
42666
|
-
/* InputPath API */
|
|
42667
|
-
|
|
42668
|
-
_handleFocus = (() => {
|
|
42669
|
-
var _this = this;
|
|
42670
|
-
return function () {
|
|
42671
|
-
for (var _len2 = arguments.length, path = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
42672
|
-
path[_key2] = arguments[_key2];
|
|
42673
|
-
}
|
|
42674
|
-
_this.props.onFocus(path);
|
|
42675
|
-
};
|
|
42676
|
-
})();
|
|
42677
|
-
_handleBlur = (() => {
|
|
42678
|
-
var _this2 = this;
|
|
42679
|
-
return function () {
|
|
42680
|
-
for (var _len3 = arguments.length, path = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
42681
|
-
path[_key3] = arguments[_key3];
|
|
42682
|
-
}
|
|
42683
|
-
_this2.props.onBlur(path);
|
|
42684
|
-
};
|
|
42685
|
-
})();
|
|
42686
|
-
_getTransformationForID = transformationID => {
|
|
42687
|
-
// Returns the 'transformation' component corresponding to a given ID
|
|
42688
|
-
const refPath = ["transformationList", "transformation" + transformationID];
|
|
42689
|
-
|
|
42690
|
-
// Follow the path of references
|
|
42691
|
-
let component = this;
|
|
42692
|
-
___default["default"].each(refPath, ref => {
|
|
42693
|
-
// @ts-expect-error - TS2322 - Type 'ReactInstance' is not assignable to type 'this'.
|
|
42694
|
-
component = component.refs[ref];
|
|
42695
|
-
});
|
|
42696
|
-
return component;
|
|
42697
|
-
};
|
|
42698
|
-
getInputPaths = () => {
|
|
42699
|
-
// If we're in static mode, then there is no transformation list, and,
|
|
42700
|
-
// as a result, no input paths.
|
|
42701
|
-
if (this.props.listMode === "static") {
|
|
42702
|
-
return [];
|
|
42703
|
-
}
|
|
42704
|
-
let inputPaths = [];
|
|
42705
|
-
___default["default"].each(this.props.transformations, (transformation, i) => {
|
|
42706
|
-
// @ts-expect-error - TS2345 - Argument of type 'number' is not assignable to parameter of type 'string'.
|
|
42707
|
-
transformation = this._getTransformationForID(i);
|
|
42708
|
-
// @ts-expect-error - TS2339 - Property 'getInputPaths' does not exist on type 'PerseusTransformerTransformation'.
|
|
42709
|
-
const innerPaths = transformation.getInputPaths();
|
|
42710
|
-
const fullPaths = ___default["default"].map(innerPaths, innerPath => {
|
|
42711
|
-
return ["" + i].concat(innerPath);
|
|
42712
|
-
});
|
|
42713
|
-
// @ts-expect-error - TS2345 - Argument of type 'string[][]' is not assignable to parameter of type 'ConcatArray<never>'.
|
|
42714
|
-
inputPaths = inputPaths.concat(fullPaths);
|
|
42715
|
-
});
|
|
42716
|
-
return inputPaths;
|
|
42717
|
-
};
|
|
42718
|
-
_passToInner = function (functionName, path) {
|
|
42719
|
-
if (!path || !path.length) {
|
|
42720
|
-
return;
|
|
42721
|
-
}
|
|
42722
|
-
|
|
42723
|
-
// First argument tells us which transformation will receive the call;
|
|
42724
|
-
// remaining arguments are used within that transformation to identify
|
|
42725
|
-
// a specific input.
|
|
42726
|
-
const innerPath = ___default["default"].rest(path);
|
|
42727
|
-
|
|
42728
|
-
// Pass arguments down to appropriate 'transformation' component
|
|
42729
|
-
const transformationID = ___default["default"].head(path);
|
|
42730
|
-
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
42731
|
-
const caller = this._getTransformationForID(transformationID);
|
|
42732
|
-
for (var _len4 = arguments.length, args = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
|
|
42733
|
-
args[_key4 - 2] = arguments[_key4];
|
|
42734
|
-
}
|
|
42735
|
-
return caller[functionName](innerPath, ...args);
|
|
42736
|
-
};
|
|
42737
|
-
focus = () => {
|
|
42738
|
-
// Just focus the first showing input
|
|
42739
|
-
const inputs = this.getInputPaths();
|
|
42740
|
-
if (inputs.length > 0) {
|
|
42741
|
-
this.focusInputPath(inputs[0]);
|
|
42742
|
-
return true;
|
|
42743
|
-
}
|
|
42744
|
-
return false;
|
|
42745
|
-
};
|
|
42746
|
-
focusInputPath = path => {
|
|
42747
|
-
// Since the transformer exposes the input API, it needs to be robust
|
|
42748
|
-
// to empty paths. We don't expect this to happen, as entire-widget
|
|
42749
|
-
// focusing is typically done through the focus() method, which already
|
|
42750
|
-
// handles the empty path case properly, but it's better to be safe
|
|
42751
|
-
// here.
|
|
42752
|
-
if (path.length === 0) {
|
|
42753
|
-
return false;
|
|
42754
|
-
}
|
|
42755
|
-
assert(path.length >= 2);
|
|
42756
|
-
return this._passToInner("focusInputPath", path);
|
|
42757
|
-
};
|
|
42758
|
-
blurInputPath = path => {
|
|
42759
|
-
// Since the transformer exposes the input API, it needs to be robust
|
|
42760
|
-
// to empty paths (which indicate a blurring of the entire widget,
|
|
42761
|
-
// e.g., when switching from interacting with the transformer to
|
|
42762
|
-
// interacting with some other widget).
|
|
42763
|
-
if (path.length === 0) {
|
|
42764
|
-
return false;
|
|
42765
|
-
}
|
|
42766
|
-
assert(path.length >= 2);
|
|
42767
|
-
return this._passToInner("blurInputPath", path);
|
|
42768
|
-
};
|
|
42769
|
-
setInputValue = (path, value, cb) => {
|
|
42770
|
-
assert(path.length >= 2);
|
|
42771
|
-
return this._passToInner("setInputValue", path, value, cb);
|
|
42772
|
-
};
|
|
42773
|
-
getDOMNodeForPath = path => {
|
|
42774
|
-
assert(path.length >= 2);
|
|
42775
|
-
return this._passToInner("getDOMNodeForPath", path);
|
|
42776
|
-
};
|
|
42777
|
-
getGrammarTypeForPath = path => {
|
|
42778
|
-
assert(path.length >= 2);
|
|
42779
|
-
return this._passToInner("getGrammarTypeForPath", path);
|
|
42780
|
-
};
|
|
42781
|
-
static validate(guess, rubric) {
|
|
42782
|
-
// Check for any required transformations
|
|
42783
|
-
for (const type in Transformations) {
|
|
42784
|
-
if (rubric.tools[type].required) {
|
|
42785
|
-
const isUsed = ___default["default"].any(___default["default"].map(guess.transformations, function (transform) {
|
|
42786
|
-
// Required transformations must appear in the
|
|
42787
|
-
// transformation list, and must not be no-ops
|
|
42788
|
-
return transform.type === type && !TransformOps.isEmpty(transform) && !TransformOps.isNoOp(transform);
|
|
42789
|
-
}));
|
|
42790
|
-
if (!isUsed) {
|
|
42791
|
-
return {
|
|
42792
|
-
type: "invalid",
|
|
42793
|
-
message: i18n__namespace._("Your transformation must use a " + "%(type)s.", {
|
|
42794
|
-
type: Transformations[type].lowerNounName
|
|
42795
|
-
})
|
|
42796
|
-
};
|
|
42797
|
-
}
|
|
42798
|
-
}
|
|
42799
|
-
}
|
|
42800
|
-
|
|
42801
|
-
// Compare shapes
|
|
42802
|
-
if (ShapeTypes.equal(guess.shape, rubric.correct.shape)) {
|
|
42803
|
-
return {
|
|
42804
|
-
type: "points",
|
|
42805
|
-
earned: 1,
|
|
42806
|
-
total: 1,
|
|
42807
|
-
message: null
|
|
42808
|
-
};
|
|
42809
|
-
}
|
|
42810
|
-
if (!rubric.gradeEmpty && deepEq(guess.shape.coords, rubric.starting.shape.coords)) {
|
|
42811
|
-
return {
|
|
42812
|
-
type: "invalid",
|
|
42813
|
-
message: i18n__namespace._("Use the interactive graph to define a " + "correct transformation.")
|
|
42814
|
-
};
|
|
42815
|
-
}
|
|
42816
|
-
return {
|
|
42817
|
-
type: "points",
|
|
42818
|
-
earned: 0,
|
|
42819
|
-
total: 1,
|
|
42820
|
-
message: null
|
|
42821
|
-
};
|
|
42822
|
-
}
|
|
42823
|
-
}
|
|
42824
|
-
var Transformer$1 = {
|
|
42825
|
-
name: "transformer",
|
|
42826
|
-
displayName: "Transformer (deprecated)",
|
|
42827
|
-
hidden: true,
|
|
42828
|
-
widget: Transformer
|
|
42829
|
-
};
|
|
42830
|
-
|
|
42831
40421
|
var hubble = {exports: {}};
|
|
42832
40422
|
|
|
42833
40423
|
(function (module, exports) {
|
|
@@ -44053,7 +41643,7 @@ var Video$1 = {
|
|
|
44053
41643
|
};
|
|
44054
41644
|
|
|
44055
41645
|
/* eslint-disable import/no-named-as-default */
|
|
44056
|
-
var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1,
|
|
41646
|
+
var extraWidgets = [Categorizer$1, CSProgram$1, Dropdown$1, Explanation$1, Definition$1, Grapher$1, GradedGroup$1, GradedGroupSet$1, Group$1, Iframe$1, Image$1, Interactive, InteractiveGraph$1, LabelImage$1, LightsPuzzle$1, Matrix$1, Matcher$1, Measurer$1, Molecule$1, NumberLine$1, Orderer$1, Passage$1, PassageRef$1, PassageRefTarget$1, Plotter$1, ReactionDiagram, Sequence$1, Simulator$1, Sorter$1, Table$1, Unit, Video$1, DeprecatedStandin$1];
|
|
44057
41647
|
|
|
44058
41648
|
/**
|
|
44059
41649
|
* This should be called by all clients, specifying whether extra widgets are
|
|
@@ -44097,7 +41687,7 @@ const init = function (options) {
|
|
|
44097
41687
|
|
|
44098
41688
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44099
41689
|
const libName = "@khanacademy/perseus";
|
|
44100
|
-
const libVersion = "
|
|
41690
|
+
const libVersion = "19.0.0";
|
|
44101
41691
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44102
41692
|
|
|
44103
41693
|
const apiVersion = {
|
|
@@ -45542,8 +43132,6 @@ const ItemExtras = [
|
|
|
45542
43132
|
|
|
45543
43133
|
// prettier-ignore
|
|
45544
43134
|
|
|
45545
|
-
// prettier-ignore
|
|
45546
|
-
|
|
45547
43135
|
//prettier-ignore
|
|
45548
43136
|
|
|
45549
43137
|
// A background image applied to various widgets.
|
|
@@ -46668,10 +44256,7 @@ function violatingWidgets(itemData) {
|
|
|
46668
44256
|
*/
|
|
46669
44257
|
const registerAllWidgetsForTesting = () => {
|
|
46670
44258
|
registerWidgets(allWidgets);
|
|
46671
|
-
|
|
46672
|
-
// When it's time to replace the transformer widget
|
|
46673
|
-
// uncomment this line
|
|
46674
|
-
// Widgets.replaceWidget("transformer", "deprecated-standin");
|
|
44259
|
+
replaceWidget("transformer", "deprecated-standin");
|
|
46675
44260
|
};
|
|
46676
44261
|
|
|
46677
44262
|
/**
|
|
@@ -47131,7 +44716,6 @@ exports.Renderer = Renderer;
|
|
|
47131
44716
|
exports.ServerItemRenderer = ref;
|
|
47132
44717
|
exports.SizingUtils = sizingUtils;
|
|
47133
44718
|
exports.TableWidget = Table$1;
|
|
47134
|
-
exports.TransformerWidget = Transformer$1;
|
|
47135
44719
|
exports.Util = Util;
|
|
47136
44720
|
exports.WIDGET_PROP_DENYLIST = denylist;
|
|
47137
44721
|
exports.WidgetJsonifyDeprecated = WidgetJsonifyDeprecated;
|