@khanacademy/perseus 24.2.0 → 25.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.css +7 -0
- package/dist/es/index.js +845 -377
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +7 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +927 -449
- package/dist/index.js.map +1 -1
- package/dist/logging/log.d.ts +1 -41
- package/dist/perseus-api.d.ts +1 -0
- package/dist/perseus-types.d.ts +17 -2
- package/dist/server-item-renderer.d.ts +2 -1
- package/dist/types.d.ts +1 -1
- package/dist/widgets/expression.d.ts +8 -2
- package/dist/widgets/interactive-graph.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/angle.d.ts +5 -0
- package/dist/widgets/interactive-graphs/graphs/components/{angle.d.ts → angle-indicators.d.ts} +12 -2
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +11 -0
- package/dist/widgets/interactive-graphs/graphs/components/text-label.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/index.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +0 -3
- package/dist/widgets/interactive-graphs/index.d.ts +1 -1
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +3 -1
- package/dist/widgets/interactive-graphs/locked-figures/locked-function.d.ts +4 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +0 -19
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
- package/dist/widgets/interactive-graphs/math/angles.d.ts +5 -0
- package/dist/widgets/interactive-graphs/math/box.d.ts +4 -0
- package/dist/widgets/interactive-graphs/math/clamp.d.ts +1 -0
- package/dist/widgets/interactive-graphs/math/coordinates.d.ts +2 -0
- package/dist/widgets/interactive-graphs/math/geometry.d.ts +3 -0
- package/dist/widgets/interactive-graphs/math/index.d.ts +8 -0
- package/dist/widgets/interactive-graphs/math/interpolation.d.ts +1 -0
- package/dist/widgets/interactive-graphs/math/interval.d.ts +5 -0
- package/dist/widgets/interactive-graphs/math/snap.d.ts +2 -0
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +21 -0
- package/dist/widgets/interactive-graphs/types.d.ts +9 -1
- package/dist/widgets/interactive-graphs/utils.d.ts +0 -2
- package/dist/widgets/label-image.d.ts +2 -0
- package/package.json +8 -8
- package/dist/perseus-error.d.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var KAS = require('@khanacademy/kas');
|
|
6
6
|
var mathInput = require('@khanacademy/math-input');
|
|
7
|
+
var perseusCore = require('@khanacademy/perseus-core');
|
|
7
8
|
var PerseusLinter = require('@khanacademy/perseus-linter');
|
|
8
9
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
9
10
|
var Tooltip$1 = require('@khanacademy/wonder-blocks-tooltip');
|
|
@@ -40,7 +41,6 @@ var Switch = require('@khanacademy/wonder-blocks-switch');
|
|
|
40
41
|
var Pill = require('@khanacademy/wonder-blocks-pill');
|
|
41
42
|
var reactPopper = require('react-popper');
|
|
42
43
|
var Link = require('@khanacademy/wonder-blocks-link');
|
|
43
|
-
var perseusCore = require('@khanacademy/perseus-core');
|
|
44
44
|
|
|
45
45
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
46
46
|
|
|
@@ -803,52 +803,9 @@ var dependencies = /*#__PURE__*/Object.freeze({
|
|
|
803
803
|
// TODO(LP-11481): Change the primary API we use for logging in Perseus to use
|
|
804
804
|
// getDependencies() internally... simplify usage to just using a "singleton"
|
|
805
805
|
// which get's the injected logger.
|
|
806
|
-
/**
|
|
807
|
-
* @typedef {Object} Errors utility for referencing the Perseus error taxonomy.
|
|
808
|
-
*/
|
|
809
|
-
const Errors = Object.freeze({
|
|
810
|
-
/**
|
|
811
|
-
* @property {ErrorKind} Unknown The kind of error is not known.
|
|
812
|
-
*/
|
|
813
|
-
Unknown: "Unknown",
|
|
814
|
-
/**
|
|
815
|
-
* @property {ErrorKind} Internal The error is internal to the executing code.
|
|
816
|
-
*/
|
|
817
|
-
Internal: "Internal",
|
|
818
|
-
/**
|
|
819
|
-
* @property {ErrorKind} InvalidInput There was a problem with the provided
|
|
820
|
-
* input, such as the wrong format or a null value.
|
|
821
|
-
*/
|
|
822
|
-
InvalidInput: "InvalidInput",
|
|
823
|
-
/**
|
|
824
|
-
* @property {ErrorKind} NotAllowed There was a problem due to the state of
|
|
825
|
-
* the system not matching the requested operation or input. For example,
|
|
826
|
-
* trying to create a username that is valid, but is already taken by
|
|
827
|
-
* another user. Use {@link InvalidInput} instead when the input isn't
|
|
828
|
-
* valid regardless of the state of the system. Use {@link NotFound} when
|
|
829
|
-
* the failure is due to not being able to find a resource.
|
|
830
|
-
*/
|
|
831
|
-
NotAllowed: "NotAllowed",
|
|
832
|
-
/**
|
|
833
|
-
* @property {ErrorKind} TransientService There was a problem when making a
|
|
834
|
-
* request to a service.
|
|
835
|
-
*/
|
|
836
|
-
TransientService: "TransientService",
|
|
837
|
-
/**
|
|
838
|
-
* @property {ErrorKind} Service There was a non-transient problem when
|
|
839
|
-
* making a request to service.
|
|
840
|
-
*/
|
|
841
|
-
Service: "Service"
|
|
842
|
-
});
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* @type {ErrorKind} The kind of error being reported
|
|
846
|
-
*/
|
|
847
|
-
|
|
848
806
|
/**
|
|
849
807
|
* Provides logging infrastructure for Perseus
|
|
850
808
|
*/
|
|
851
|
-
|
|
852
809
|
const Log = {
|
|
853
810
|
// Logs a message
|
|
854
811
|
log: (message, extra) => {
|
|
@@ -860,16 +817,6 @@ const Log = {
|
|
|
860
817
|
}
|
|
861
818
|
};
|
|
862
819
|
|
|
863
|
-
class PerseusError extends Error {
|
|
864
|
-
kind;
|
|
865
|
-
metadata;
|
|
866
|
-
constructor(message, kind, options) {
|
|
867
|
-
super(message);
|
|
868
|
-
this.kind = kind;
|
|
869
|
-
this.metadata = options?.metadata;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
820
|
/**
|
|
874
821
|
* These are things that widgets should exclude when serializing themselves.
|
|
875
822
|
*
|
|
@@ -973,9 +920,9 @@ const change = function (newPropsOrSinglePropName, propValue, callback) {
|
|
|
973
920
|
// string propName
|
|
974
921
|
propValue, callback);
|
|
975
922
|
}
|
|
976
|
-
throw new PerseusError("Invalid types sent to this.change(): " +
|
|
923
|
+
throw new perseusCore.PerseusError("Invalid types sent to this.change(): " +
|
|
977
924
|
// eslint-disable-next-line prefer-rest-params
|
|
978
|
-
___default["default"].toArray(arguments).join() + "\n" + USAGE, Errors.Internal);
|
|
925
|
+
___default["default"].toArray(arguments).join() + "\n" + USAGE, perseusCore.Errors.Internal);
|
|
979
926
|
};
|
|
980
927
|
const propTypes = {
|
|
981
928
|
onChange: PropTypes__default["default"].func.isRequired
|
|
@@ -2148,9 +2095,9 @@ const KhanAnswerTypes = {
|
|
|
2148
2095
|
parseSolution: function (solutionString, options) {
|
|
2149
2096
|
let solution = KAS__namespace.parse(solutionString, options);
|
|
2150
2097
|
if (!solution.parsed) {
|
|
2151
|
-
throw new PerseusError("The provided solution (" + solutionString + ") didn't parse.", Errors.InvalidInput);
|
|
2098
|
+
throw new perseusCore.PerseusError("The provided solution (" + solutionString + ") didn't parse.", perseusCore.Errors.InvalidInput);
|
|
2152
2099
|
} else if (options.simplified && !solution.expr.isSimplified()) {
|
|
2153
|
-
throw new PerseusError("The provided solution (" + solutionString + ") isn't fully expanded and simplified.", Errors.InvalidInput);
|
|
2100
|
+
throw new perseusCore.PerseusError("The provided solution (" + solutionString + ") isn't fully expanded and simplified.", perseusCore.Errors.InvalidInput);
|
|
2154
2101
|
} else {
|
|
2155
2102
|
solution = solution.expr;
|
|
2156
2103
|
}
|
|
@@ -2341,7 +2288,7 @@ class Expression extends React__namespace.Component {
|
|
|
2341
2288
|
// in the function variables list for the expression.
|
|
2342
2289
|
if (!expression.parsed) {
|
|
2343
2290
|
/* c8 ignore next */
|
|
2344
|
-
Log.error("Unable to parse solution answer for expression", Errors.InvalidInput, {
|
|
2291
|
+
Log.error("Unable to parse solution answer for expression", perseusCore.Errors.InvalidInput, {
|
|
2345
2292
|
loggedMetadata: {
|
|
2346
2293
|
rubric: JSON.stringify(rubric)
|
|
2347
2294
|
}
|
|
@@ -3032,7 +2979,7 @@ function combineScores(scoreA, scoreB) {
|
|
|
3032
2979
|
* The above checks cover all combinations of score type, so if we get here
|
|
3033
2980
|
* then something is amiss with our inputs.
|
|
3034
2981
|
*/
|
|
3035
|
-
throw new PerseusError("PerseusScore with unknown type encountered", Errors.InvalidInput, {
|
|
2982
|
+
throw new perseusCore.PerseusError("PerseusScore with unknown type encountered", perseusCore.Errors.InvalidInput, {
|
|
3036
2983
|
metadata: {
|
|
3037
2984
|
scoreA: JSON.stringify(scoreA),
|
|
3038
2985
|
scoreB: JSON.stringify(scoreB)
|
|
@@ -3062,9 +3009,9 @@ function keScoreFromPerseusScore(score, guess, state) {
|
|
|
3062
3009
|
state: state
|
|
3063
3010
|
};
|
|
3064
3011
|
}
|
|
3065
|
-
throw new PerseusError(
|
|
3012
|
+
throw new perseusCore.PerseusError(
|
|
3066
3013
|
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
3067
|
-
"Invalid score type: " + score.type, Errors.InvalidInput, {
|
|
3014
|
+
"Invalid score type: " + score.type, perseusCore.Errors.InvalidInput, {
|
|
3068
3015
|
metadata: {
|
|
3069
3016
|
score: JSON.stringify(score),
|
|
3070
3017
|
guess: JSON.stringify(guess),
|
|
@@ -4433,7 +4380,7 @@ const MovableHelperMethods = {
|
|
|
4433
4380
|
return memo;
|
|
4434
4381
|
}
|
|
4435
4382
|
// Anything else is an error
|
|
4436
|
-
throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
|
|
4383
|
+
throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
|
|
4437
4384
|
}, current, this);
|
|
4438
4385
|
},
|
|
4439
4386
|
/**
|
|
@@ -4539,7 +4486,7 @@ const FUNCTION_ARRAY_OPTIONS = ["add", "modify", "draw", "remove", "constraints"
|
|
|
4539
4486
|
const InteractiveUtil = {
|
|
4540
4487
|
assert: function (isTrue, message) {
|
|
4541
4488
|
if (!isTrue) {
|
|
4542
|
-
throw new PerseusError("Assertion Error" + (message ? ": " + message : ""), Errors.Internal);
|
|
4489
|
+
throw new perseusCore.PerseusError("Assertion Error" + (message ? ": " + message : ""), perseusCore.Errors.Internal);
|
|
4543
4490
|
}
|
|
4544
4491
|
},
|
|
4545
4492
|
/**
|
|
@@ -9068,7 +9015,7 @@ var Tex$1 = {
|
|
|
9068
9015
|
const {
|
|
9069
9016
|
processMath: processMath$1
|
|
9070
9017
|
} = Tex$1;
|
|
9071
|
-
function polar(r, th) {
|
|
9018
|
+
function polar$1(r, th) {
|
|
9072
9019
|
if (typeof r === "number") {
|
|
9073
9020
|
r = [r, r];
|
|
9074
9021
|
}
|
|
@@ -9120,7 +9067,7 @@ class Graphie$1 {
|
|
|
9120
9067
|
// TODO(jeremy): This can be removed once we're confident that callers
|
|
9121
9068
|
// obey the Typescript types.
|
|
9122
9069
|
if (options.range == null) {
|
|
9123
|
-
throw new PerseusError("range should be specified in graph init", Errors.Internal);
|
|
9070
|
+
throw new perseusCore.PerseusError("range should be specified in graph init", perseusCore.Errors.Internal);
|
|
9124
9071
|
}
|
|
9125
9072
|
this.#bounds = new GraphBounds(...options.range);
|
|
9126
9073
|
this.#drawingTransform = new DrawingTransform(this.raphael, scale, this.bounds());
|
|
@@ -9404,8 +9351,8 @@ class Graphie$1 {
|
|
|
9404
9351
|
endAngle = (endAngle % 360 + 360) % 360;
|
|
9405
9352
|
const cent = this.scalePoint(center);
|
|
9406
9353
|
const radii = this.scaleVector(radius);
|
|
9407
|
-
const startVector = polar(radius, startAngle);
|
|
9408
|
-
const endVector = polar(radius, endAngle);
|
|
9354
|
+
const startVector = polar$1(radius, startAngle);
|
|
9355
|
+
const endVector = polar$1(radius, endAngle);
|
|
9409
9356
|
|
|
9410
9357
|
// We round the coordinates to make testing easier, because trig
|
|
9411
9358
|
// operations return unround numbers.
|
|
@@ -13707,7 +13654,7 @@ function MovableAngle(graphie, options) {
|
|
|
13707
13654
|
|
|
13708
13655
|
// @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.
|
|
13709
13656
|
if (!this.points || this.points.length !== 3) {
|
|
13710
|
-
throw new PerseusError("MovableAngle requires 3 points", Errors.InvalidInput);
|
|
13657
|
+
throw new perseusCore.PerseusError("MovableAngle requires 3 points", perseusCore.Errors.InvalidInput);
|
|
13711
13658
|
}
|
|
13712
13659
|
|
|
13713
13660
|
// Handle coordinates that are not MovablePoints (i.e. [2, 4])
|
|
@@ -13834,7 +13781,7 @@ ___default["default"].extend(MovableAngle.prototype, {
|
|
|
13834
13781
|
let angle = GraphUtils.findAngle(newPoint, vertex);
|
|
13835
13782
|
angle = Math.round((angle - snapOffset) / snap) * snap + snapOffset;
|
|
13836
13783
|
const distance = GraphUtils.getDistance(newPoint, vertex);
|
|
13837
|
-
return kmath.vector.add(vertex, polar(distance, angle));
|
|
13784
|
+
return kmath.vector.add(vertex, polar$1(distance, angle));
|
|
13838
13785
|
}
|
|
13839
13786
|
return true;
|
|
13840
13787
|
};
|
|
@@ -13998,9 +13945,9 @@ function GraphieMovable$1(descriptor) {
|
|
|
13998
13945
|
___default["default"].extend(this, descriptor);
|
|
13999
13946
|
}
|
|
14000
13947
|
const abstractMethod = function () {
|
|
14001
|
-
throw new PerseusError("Abstract method! Must be implemented by Graphie Movable" +
|
|
13948
|
+
throw new perseusCore.PerseusError("Abstract method! Must be implemented by Graphie Movable" +
|
|
14002
13949
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
14003
|
-
this.constructor.displayName, Errors.NotAllowed);
|
|
13950
|
+
this.constructor.displayName, perseusCore.Errors.NotAllowed);
|
|
14004
13951
|
};
|
|
14005
13952
|
___default["default"].extend(GraphieMovable$1.prototype, {
|
|
14006
13953
|
movableProps: [],
|
|
@@ -14040,7 +13987,7 @@ const createClass = function (spec) {
|
|
|
14040
13987
|
const GraphieClass = function (props) {
|
|
14041
13988
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
14042
13989
|
if (!(this instanceof GraphieClass)) {
|
|
14043
|
-
throw new PerseusError("Use createElement or JSX with graphie movables", Errors.NotAllowed);
|
|
13990
|
+
throw new perseusCore.PerseusError("Use createElement or JSX with graphie movables", perseusCore.Errors.NotAllowed);
|
|
14044
13991
|
}
|
|
14045
13992
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
14046
13993
|
this.props = rewriteProps(props, props.children || []);
|
|
@@ -14359,7 +14306,7 @@ class Movable {
|
|
|
14359
14306
|
return memo;
|
|
14360
14307
|
}
|
|
14361
14308
|
// Anything else is an error
|
|
14362
|
-
throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
|
|
14309
|
+
throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
|
|
14363
14310
|
}, current);
|
|
14364
14311
|
}
|
|
14365
14312
|
|
|
@@ -15709,7 +15656,7 @@ class MovablePoint$4 {
|
|
|
15709
15656
|
return memo;
|
|
15710
15657
|
}
|
|
15711
15658
|
// Anything else is an error
|
|
15712
|
-
throw new PerseusError("Constraint returned invalid result: " + result, Errors.Internal);
|
|
15659
|
+
throw new perseusCore.PerseusError("Constraint returned invalid result: " + result, perseusCore.Errors.Internal);
|
|
15713
15660
|
}, current);
|
|
15714
15661
|
}
|
|
15715
15662
|
|
|
@@ -16794,7 +16741,7 @@ const Path = GraphieClasses.createClass({
|
|
|
16794
16741
|
this.path.toFront();
|
|
16795
16742
|
}
|
|
16796
16743
|
});
|
|
16797
|
-
const Arc = GraphieClasses.createSimpleClass((graphie, props) => {
|
|
16744
|
+
const Arc$1 = GraphieClasses.createSimpleClass((graphie, props) => {
|
|
16798
16745
|
let center = props.center;
|
|
16799
16746
|
let radius = props.radius;
|
|
16800
16747
|
if (props.unscaled) {
|
|
@@ -16810,7 +16757,7 @@ const Rect$1 = GraphieClasses.createSimpleClass((graphie, props) => {
|
|
|
16810
16757
|
return graphie.rect(props.x, props.y, props.width, props.height, props.style);
|
|
16811
16758
|
});
|
|
16812
16759
|
var Movables = {
|
|
16813
|
-
Arc: Arc,
|
|
16760
|
+
Arc: Arc$1,
|
|
16814
16761
|
Circle: Circle,
|
|
16815
16762
|
Label: Label$1,
|
|
16816
16763
|
Line: Line$3,
|
|
@@ -16864,7 +16811,7 @@ class Graphie extends React__namespace.Component {
|
|
|
16864
16811
|
// would have horrible performance implications. In order to avoid
|
|
16865
16812
|
// those, we just warn here.
|
|
16866
16813
|
if (this.props.setup !== prevProps.setup) {
|
|
16867
|
-
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);
|
|
16814
|
+
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.", perseusCore.Errors.Internal);
|
|
16868
16815
|
}
|
|
16869
16816
|
if (!deepEq$2(this.props.options, prevProps.options) || !deepEq$2(this.props.box, prevProps.box) || !deepEq$2(this.props.range, prevProps.range)) {
|
|
16870
16817
|
this._setupGraphie();
|
|
@@ -17043,7 +16990,7 @@ class Graphie extends React__namespace.Component {
|
|
|
17043
16990
|
// This generally is a bad idea, so warn about it if this
|
|
17044
16991
|
// is being caused by implicit keys
|
|
17045
16992
|
if (keyProp == null) {
|
|
17046
|
-
Log.error("Replacing a <Graphie> child with a " + "child of a different type. Please add keys " + "to your <Graphie> children", Errors.Internal);
|
|
16993
|
+
Log.error("Replacing a <Graphie> child with a " + "child of a different type. Please add keys " + "to your <Graphie> children", perseusCore.Errors.Internal);
|
|
17047
16994
|
}
|
|
17048
16995
|
prevMovable.remove();
|
|
17049
16996
|
child.add(graphie);
|
|
@@ -17320,7 +17267,7 @@ function getLocalizedDataUrl(url) {
|
|
|
17320
17267
|
function getUrlHash(url) {
|
|
17321
17268
|
const match = url.match(hashRegex);
|
|
17322
17269
|
if (match == null) {
|
|
17323
|
-
throw new PerseusError("not a valid URL", Errors.InvalidInput);
|
|
17270
|
+
throw new perseusCore.PerseusError("not a valid URL", perseusCore.Errors.InvalidInput);
|
|
17324
17271
|
}
|
|
17325
17272
|
return match && match[1];
|
|
17326
17273
|
}
|
|
@@ -17457,7 +17404,7 @@ class SvgImage extends React__namespace.Component {
|
|
|
17457
17404
|
// If there is isn't any localized data, fall back to
|
|
17458
17405
|
// the original, unlocalized data
|
|
17459
17406
|
retrieveData(Util.getDataUrl(this.props.src), (x, status, error) => {
|
|
17460
|
-
Log.error("Data load failed for svg-image", Errors.Service, {
|
|
17407
|
+
Log.error("Data load failed for svg-image", perseusCore.Errors.Service, {
|
|
17461
17408
|
cause: error,
|
|
17462
17409
|
loggedMetadata: {
|
|
17463
17410
|
dataUrl: Util.getDataUrl(this.props.src),
|
|
@@ -17468,7 +17415,7 @@ class SvgImage extends React__namespace.Component {
|
|
|
17468
17415
|
});
|
|
17469
17416
|
} else {
|
|
17470
17417
|
retrieveData(Util.getDataUrl(this.props.src), (x, status, error) => {
|
|
17471
|
-
Log.error("Data load failed for svg-image", Errors.Service, {
|
|
17418
|
+
Log.error("Data load failed for svg-image", perseusCore.Errors.Service, {
|
|
17472
17419
|
cause: error,
|
|
17473
17420
|
loggedMetadata: {
|
|
17474
17421
|
dataUrl: Util.getDataUrl(this.props.src),
|
|
@@ -17720,7 +17667,7 @@ class SvgImage extends React__namespace.Component {
|
|
|
17720
17667
|
} else if (this.state.imageDimensions) {
|
|
17721
17668
|
box = [this.state.imageDimensions[0] * this.props.scale, this.state.imageDimensions[1] * this.props.scale];
|
|
17722
17669
|
} else {
|
|
17723
|
-
throw new PerseusError("svg-image has no dimensions", Errors.InvalidInput, {
|
|
17670
|
+
throw new perseusCore.PerseusError("svg-image has no dimensions", perseusCore.Errors.InvalidInput, {
|
|
17724
17671
|
metadata: {
|
|
17725
17672
|
src: this.props.src
|
|
17726
17673
|
}
|
|
@@ -18148,7 +18095,7 @@ class ErrorBoundary extends React__namespace.Component {
|
|
|
18148
18095
|
// differentiate between the different errors that are thrown, they
|
|
18149
18096
|
// all end up being grouped as a single Sentry event, which is very
|
|
18150
18097
|
// unhelpful.
|
|
18151
|
-
"Unhandled Perseus error: " + error.message, Errors.Internal, {
|
|
18098
|
+
"Unhandled Perseus error: " + error.message, perseusCore.Errors.Internal, {
|
|
18152
18099
|
cause: error,
|
|
18153
18100
|
loggedMetadata: {
|
|
18154
18101
|
componentStack: !!info && "componentStack" in info ? info.componentStack : "componentStack not provided",
|
|
@@ -19201,7 +19148,7 @@ const replaceWidget = (name, replacementName) => {
|
|
|
19201
19148
|
// that doesn't exist at all.
|
|
19202
19149
|
if (!substituteWidget) {
|
|
19203
19150
|
const errorMsg = `Failed to replace ${name} with ${replacementName}`;
|
|
19204
|
-
throw new PerseusError(errorMsg, Errors.Internal);
|
|
19151
|
+
throw new perseusCore.PerseusError(errorMsg, perseusCore.Errors.Internal);
|
|
19205
19152
|
}
|
|
19206
19153
|
registerWidget(name, substituteWidget);
|
|
19207
19154
|
};
|
|
@@ -19215,7 +19162,7 @@ const replaceDeprecatedWidgets = () => {
|
|
|
19215
19162
|
const registerEditors = editorsToRegister => {
|
|
19216
19163
|
editorsToRegister.forEach(editor => {
|
|
19217
19164
|
if (!editor.widgetName) {
|
|
19218
|
-
throw new PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, Errors.Internal);
|
|
19165
|
+
throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`, perseusCore.Errors.Internal);
|
|
19219
19166
|
}
|
|
19220
19167
|
editors[editor.widgetName] = editor;
|
|
19221
19168
|
});
|
|
@@ -19233,7 +19180,7 @@ const replaceEditor = (name, replacementName) => {
|
|
|
19233
19180
|
const substituteEditor = editors[replacementName];
|
|
19234
19181
|
if (!substituteEditor && Log) {
|
|
19235
19182
|
const errorMsg = `Failed to replace editor ${name} with ${replacementName}`;
|
|
19236
|
-
Log.error(errorMsg, Errors.Internal);
|
|
19183
|
+
Log.error(errorMsg, perseusCore.Errors.Internal);
|
|
19237
19184
|
return;
|
|
19238
19185
|
}
|
|
19239
19186
|
editors[name] = substituteEditor;
|
|
@@ -19307,7 +19254,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
19307
19254
|
// suspect we have legacy data (potentially unpublished) and we should
|
|
19308
19255
|
// figure that out before depending solely on types.
|
|
19309
19256
|
if (!___default["default"].isString(type)) {
|
|
19310
|
-
throw new PerseusError("widget type must be a string, but was: " + type, Errors.Internal);
|
|
19257
|
+
throw new perseusCore.PerseusError("widget type must be a string, but was: " + type, perseusCore.Errors.Internal);
|
|
19311
19258
|
}
|
|
19312
19259
|
const widgetExports = widgets[type];
|
|
19313
19260
|
if (widgetExports == null) {
|
|
@@ -19358,7 +19305,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
19358
19305
|
// This is a Log.error because it is unlikely to be hit in
|
|
19359
19306
|
// local testing, and a Log.error is slightly less scary in
|
|
19360
19307
|
// prod than a `throw new Error`
|
|
19361
|
-
Log.error("No upgrade found for widget. Cannot render.", Errors.Internal, {
|
|
19308
|
+
Log.error("No upgrade found for widget. Cannot render.", perseusCore.Errors.Internal, {
|
|
19362
19309
|
loggedMetadata: {
|
|
19363
19310
|
type,
|
|
19364
19311
|
fromMajorVersion: nextVersion - 1,
|
|
@@ -19431,7 +19378,7 @@ const getRendererPropsForWidgetInfo = (widgetInfo, strings, problemNum) => {
|
|
|
19431
19378
|
};
|
|
19432
19379
|
const traverseChildWidgets$3 = (widgetInfo, traverseRenderer) => {
|
|
19433
19380
|
if (!traverseRenderer) {
|
|
19434
|
-
throw new PerseusError("traverseRenderer must be provided, but was not", Errors.Internal);
|
|
19381
|
+
throw new perseusCore.PerseusError("traverseRenderer must be provided, but was not", perseusCore.Errors.Internal);
|
|
19435
19382
|
}
|
|
19436
19383
|
if (!widgetInfo || !widgetInfo.type || !widgets[widgetInfo.type]) {
|
|
19437
19384
|
return widgetInfo;
|
|
@@ -19500,12 +19447,12 @@ const validAlignments = ["block", "inline-block", "inline", "float-left", "float
|
|
|
19500
19447
|
const validateAlignments = () => {
|
|
19501
19448
|
___default["default"].each(widgets, function (widgetInfo) {
|
|
19502
19449
|
if (widgetInfo.defaultAlignment && !___default["default"].contains(validAlignments, widgetInfo.defaultAlignment)) {
|
|
19503
|
-
throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid defaultAlignment value: " + widgetInfo.defaultAlignment, Errors.InvalidInput);
|
|
19450
|
+
throw new perseusCore.PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid defaultAlignment value: " + widgetInfo.defaultAlignment, perseusCore.Errors.InvalidInput);
|
|
19504
19451
|
}
|
|
19505
19452
|
if (widgetInfo.supportedAlignments) {
|
|
19506
19453
|
const unknownAlignments = ___default["default"].difference(widgetInfo.supportedAlignments, validAlignments);
|
|
19507
19454
|
if (unknownAlignments.length) {
|
|
19508
|
-
throw new PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid value for supportedAlignments: " + unknownAlignments.join(" "), Errors.InvalidInput);
|
|
19455
|
+
throw new perseusCore.PerseusError("Widget '" + widgetInfo.displayName + "' has an invalid value for supportedAlignments: " + unknownAlignments.join(" "), perseusCore.Errors.InvalidInput);
|
|
19509
19456
|
}
|
|
19510
19457
|
}
|
|
19511
19458
|
});
|
|
@@ -20131,7 +20078,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20131
20078
|
|
|
20132
20079
|
// If the two lists of IDs match (ignoring order)
|
|
20133
20080
|
if (serializedWidgetIds.length !== widgetPropIds.length || ___default["default"].intersection(serializedWidgetIds, widgetPropIds).length !== serializedWidgetIds.length) {
|
|
20134
|
-
Log.error("Refusing to restore bad serialized state:", Errors.Internal, {
|
|
20081
|
+
Log.error("Refusing to restore bad serialized state:", perseusCore.Errors.Internal, {
|
|
20135
20082
|
loggedMetadata: {
|
|
20136
20083
|
serializedState: JSON.stringify(serializedState),
|
|
20137
20084
|
currentProps: JSON.stringify(this.state.widgetProps)
|
|
@@ -20289,7 +20236,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20289
20236
|
return function (id) {
|
|
20290
20237
|
let focusPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
20291
20238
|
if (!___default["default"].isArray(focusPath)) {
|
|
20292
|
-
throw new PerseusError("widget props.onFocus focusPath must be an Array, " + "but was" + JSON.stringify(focusPath), Errors.Internal);
|
|
20239
|
+
throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, " + "but was" + JSON.stringify(focusPath), perseusCore.Errors.Internal);
|
|
20293
20240
|
}
|
|
20294
20241
|
_this2._setCurrentFocus([id].concat(focusPath));
|
|
20295
20242
|
};
|
|
@@ -20773,7 +20720,7 @@ class Renderer extends React__namespace.Component {
|
|
|
20773
20720
|
// object return value.
|
|
20774
20721
|
// The result of focus was a {path, id} object itself
|
|
20775
20722
|
path = [id].concat(focusResult.path || []);
|
|
20776
|
-
Log.error("Renderer received a focus result of type 'object' " + "instead of the expected type 'boolean'", Errors.Internal, {
|
|
20723
|
+
Log.error("Renderer received a focus result of type 'object' " + "instead of the expected type 'boolean'", perseusCore.Errors.Internal, {
|
|
20777
20724
|
loggedMetadata: {
|
|
20778
20725
|
focusResult: JSON.stringify(focusResult),
|
|
20779
20726
|
currentProps: JSON.stringify(this.state.widgetProps)
|
|
@@ -28657,6 +28604,129 @@ const useTransformDimensionsToPixels = function () {
|
|
|
28657
28604
|
return dimensionsToPixels(dimens, graphState);
|
|
28658
28605
|
};
|
|
28659
28606
|
|
|
28607
|
+
// Restricts `value` to be between `min` and `max`.
|
|
28608
|
+
function clamp(value, min, max) {
|
|
28609
|
+
if (value < min) {
|
|
28610
|
+
return min;
|
|
28611
|
+
}
|
|
28612
|
+
if (value > max) {
|
|
28613
|
+
return max;
|
|
28614
|
+
}
|
|
28615
|
+
return value;
|
|
28616
|
+
}
|
|
28617
|
+
|
|
28618
|
+
// Rounds each component of `point` to the nearest multiple of the
|
|
28619
|
+
// corresponding component of `snapStep`. E.g. if the snap step is [2, 3],
|
|
28620
|
+
// the x-coord of the point will be rounded to the nearest multiple of 2, and
|
|
28621
|
+
// the y-coord of the point will be rounded to the nearest multiple of 3.
|
|
28622
|
+
function snap(snapStep, point) {
|
|
28623
|
+
const [requestedX, requestedY] = point;
|
|
28624
|
+
const [snapX, snapY] = snapStep;
|
|
28625
|
+
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
28626
|
+
}
|
|
28627
|
+
|
|
28628
|
+
// Use X and Y to index into arrays that represent coordinate pairs.
|
|
28629
|
+
// e.g. point[X]
|
|
28630
|
+
const X = 0;
|
|
28631
|
+
const Y = 1;
|
|
28632
|
+
|
|
28633
|
+
// Use MIN and MAX to index into arrays that represent intervals.
|
|
28634
|
+
// e.g. range[MAX]
|
|
28635
|
+
const MIN = 0;
|
|
28636
|
+
const MAX = 1;
|
|
28637
|
+
function size(_ref) {
|
|
28638
|
+
let [min, max] = _ref;
|
|
28639
|
+
return max - min;
|
|
28640
|
+
}
|
|
28641
|
+
|
|
28642
|
+
// Removes an equal amount from each end of the interval.
|
|
28643
|
+
//
|
|
28644
|
+
// If the given amount cannot be removed (because the interval is too small),
|
|
28645
|
+
// half the interval's size is removed from each end instead, so the interval
|
|
28646
|
+
// ends up with size = 0, and both MAX and MIN equal to its former midpoint.
|
|
28647
|
+
//
|
|
28648
|
+
// If `amount` is negative, the interval is expanded instead.
|
|
28649
|
+
function trim(amount, interval) {
|
|
28650
|
+
if (amount * 2 > size(interval)) {
|
|
28651
|
+
const middle = average(...interval);
|
|
28652
|
+
return [middle, middle];
|
|
28653
|
+
}
|
|
28654
|
+
return [interval[MIN] + amount, interval[MAX] - amount];
|
|
28655
|
+
}
|
|
28656
|
+
function average(a, b) {
|
|
28657
|
+
return (a + b) / 2;
|
|
28658
|
+
}
|
|
28659
|
+
|
|
28660
|
+
// Restricts the `point` to be within `box`, by clamping each coordinate to the
|
|
28661
|
+
// corresponding interval.
|
|
28662
|
+
function clampToBox(box, point) {
|
|
28663
|
+
return [clamp(point[X], ...box[X]), clamp(point[Y], ...box[Y])];
|
|
28664
|
+
}
|
|
28665
|
+
|
|
28666
|
+
// Reduces the size of `box`, trimming each corner by the given positive
|
|
28667
|
+
// `amount`. If a component of `amount` is negative, the box is expanded in
|
|
28668
|
+
// that dimension instead.
|
|
28669
|
+
function inset(amount, box) {
|
|
28670
|
+
return [trim(amount[X], box[X]), trim(amount[Y], box[Y])];
|
|
28671
|
+
}
|
|
28672
|
+
|
|
28673
|
+
// [L]inear Int[erp]olation: gets the weighted average of two values `a` and
|
|
28674
|
+
// `b`, with the given `fraction` specifying how much weight `a` and `b` get:
|
|
28675
|
+
// - if `fraction` is 0, `lerp` returns `a`.
|
|
28676
|
+
// - if `fraction` is 0.5, `lerp` returns the average of `a` and `b`.
|
|
28677
|
+
// - if `fraction` is 1, `lerp` returns `b`.
|
|
28678
|
+
function lerp(a, b, fraction) {
|
|
28679
|
+
return (b - a) * clamp(fraction, 0, 1) + a;
|
|
28680
|
+
}
|
|
28681
|
+
|
|
28682
|
+
// Determines whether two line segments have exactly one intersection point.
|
|
28683
|
+
// The segments are treated as "open" - that is, not inclusive of their
|
|
28684
|
+
// endpoints.
|
|
28685
|
+
// Algorithm from https://stackoverflow.com/a/24392281/7347484
|
|
28686
|
+
const segmentsIntersect = (_ref, _ref2) => {
|
|
28687
|
+
let [[a, b], [c, d]] = _ref;
|
|
28688
|
+
let [[p, q], [r, s]] = _ref2;
|
|
28689
|
+
const determinant = (c - a) * (s - q) - (r - p) * (d - b);
|
|
28690
|
+
if (determinant === 0) {
|
|
28691
|
+
return false;
|
|
28692
|
+
} else {
|
|
28693
|
+
const lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / determinant;
|
|
28694
|
+
const gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / determinant;
|
|
28695
|
+
return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
|
|
28696
|
+
}
|
|
28697
|
+
};
|
|
28698
|
+
|
|
28699
|
+
// This file contains helper functions for working with angles.
|
|
28700
|
+
|
|
28701
|
+
function convertDegreesToRadians(degrees) {
|
|
28702
|
+
return degrees / 180 * Math.PI;
|
|
28703
|
+
}
|
|
28704
|
+
|
|
28705
|
+
// Returns a value between -180 and 180, inclusive. The angle is measured
|
|
28706
|
+
// between the positive x-axis and the given vector.
|
|
28707
|
+
function calculateAngleInDegrees(_ref) {
|
|
28708
|
+
let [x, y] = _ref;
|
|
28709
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28710
|
+
}
|
|
28711
|
+
function polar(r, th) {
|
|
28712
|
+
if (typeof r === "number") {
|
|
28713
|
+
r = [r, r];
|
|
28714
|
+
}
|
|
28715
|
+
th = th * Math.PI / 180;
|
|
28716
|
+
return [r[0] * Math.cos(th), r[1] * Math.sin(th)];
|
|
28717
|
+
}
|
|
28718
|
+
const findAngle = (point1, point2, vertex) => {
|
|
28719
|
+
if (vertex === undefined) {
|
|
28720
|
+
const x = point1[0] - point2[0];
|
|
28721
|
+
const y = point1[1] - point2[1];
|
|
28722
|
+
if (!x && !y) {
|
|
28723
|
+
return 0;
|
|
28724
|
+
}
|
|
28725
|
+
return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
|
|
28726
|
+
}
|
|
28727
|
+
return findAngle(point1, vertex) - findAngle(point2, vertex);
|
|
28728
|
+
};
|
|
28729
|
+
|
|
28660
28730
|
function AxisLabels() {
|
|
28661
28731
|
const {
|
|
28662
28732
|
range,
|
|
@@ -28664,8 +28734,8 @@ function AxisLabels() {
|
|
|
28664
28734
|
width,
|
|
28665
28735
|
height
|
|
28666
28736
|
} = useGraphConfig();
|
|
28667
|
-
const yAxisLabelLocation = [0, range[
|
|
28668
|
-
const xAxisLabelLocation = [range[
|
|
28737
|
+
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
28738
|
+
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
28669
28739
|
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
28670
28740
|
const graphInfo = {
|
|
28671
28741
|
range,
|
|
@@ -28836,6 +28906,32 @@ const LockedEllipse = props => {
|
|
|
28836
28906
|
});
|
|
28837
28907
|
};
|
|
28838
28908
|
|
|
28909
|
+
const LockedFunction = props => {
|
|
28910
|
+
const {
|
|
28911
|
+
color,
|
|
28912
|
+
strokeStyle,
|
|
28913
|
+
directionalAxis,
|
|
28914
|
+
domain
|
|
28915
|
+
} = props;
|
|
28916
|
+
const plotProps = {
|
|
28917
|
+
color: lockedFigureColors[color],
|
|
28918
|
+
style: strokeStyle,
|
|
28919
|
+
domain
|
|
28920
|
+
};
|
|
28921
|
+
const equation = props.equationParsed || KAS__namespace.parse(props.equation).expr;
|
|
28922
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
28923
|
+
className: "locked-function"
|
|
28924
|
+
}, directionalAxis === "x" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfX, _extends({
|
|
28925
|
+
y: x => equation.eval({
|
|
28926
|
+
x
|
|
28927
|
+
})
|
|
28928
|
+
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React__namespace.createElement(mafs.Plot.OfY, _extends({
|
|
28929
|
+
x: y => equation.eval({
|
|
28930
|
+
y
|
|
28931
|
+
})
|
|
28932
|
+
}, plotProps)));
|
|
28933
|
+
};
|
|
28934
|
+
|
|
28839
28935
|
function pathBuilder() {
|
|
28840
28936
|
return new PathBuilder();
|
|
28841
28937
|
}
|
|
@@ -28934,7 +29030,7 @@ function Arrowhead(props) {
|
|
|
28934
29030
|
const [point] = useTransformVectorsToPixels(props.tip);
|
|
28935
29031
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
28936
29032
|
className: "interactive-graph-arrowhead",
|
|
28937
|
-
transform: `translate(${point[
|
|
29033
|
+
transform: `translate(${point[X]} ${point[Y]}) rotate(${props.angle})`
|
|
28938
29034
|
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
28939
29035
|
transform: "translate(-1.5)"
|
|
28940
29036
|
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
@@ -28949,52 +29045,6 @@ function Arrowhead(props) {
|
|
|
28949
29045
|
})));
|
|
28950
29046
|
}
|
|
28951
29047
|
|
|
28952
|
-
function calculateAngleInDegrees(_ref) {
|
|
28953
|
-
let [x, y] = _ref;
|
|
28954
|
-
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28955
|
-
}
|
|
28956
|
-
|
|
28957
|
-
/**
|
|
28958
|
-
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
28959
|
-
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
28960
|
-
* @param initialPoint - The starting point of the ray.
|
|
28961
|
-
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
28962
|
-
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
28963
|
-
*/
|
|
28964
|
-
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
28965
|
-
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
28966
|
-
const [aX, aY] = initialPoint;
|
|
28967
|
-
const [bX, bY] = throughPoint;
|
|
28968
|
-
const yDiff = bY - aY;
|
|
28969
|
-
const xDiff = bX - aX;
|
|
28970
|
-
const slope = yDiff / xDiff;
|
|
28971
|
-
const inverseSlope = 1 / slope;
|
|
28972
|
-
const xExtreme = xDiff < 0 ? xMin : xMax;
|
|
28973
|
-
const yExtreme = yDiff < 0 ? yMin : yMax;
|
|
28974
|
-
const yAtXExtreme = aY + (xExtreme - aX) * slope;
|
|
28975
|
-
const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
|
|
28976
|
-
switch (true) {
|
|
28977
|
-
// does the ray exit the graph bounding box via the left or right edge?
|
|
28978
|
-
case isBetween(yAtXExtreme, yMin, yMax):
|
|
28979
|
-
return [xExtreme, yAtXExtreme];
|
|
28980
|
-
|
|
28981
|
-
// does the ray exit the graph bounding box via the top or bottom edge?
|
|
28982
|
-
case isBetween(xAtYExtreme, xMin, xMax):
|
|
28983
|
-
return [xAtYExtreme, yExtreme];
|
|
28984
|
-
default:
|
|
28985
|
-
return [xExtreme, yExtreme];
|
|
28986
|
-
}
|
|
28987
|
-
};
|
|
28988
|
-
const getLines = points => {
|
|
28989
|
-
return points.map((point, i) => {
|
|
28990
|
-
const next = points[(i + 1) % points.length];
|
|
28991
|
-
return [point, next];
|
|
28992
|
-
});
|
|
28993
|
-
};
|
|
28994
|
-
function isBetween(x, low, high) {
|
|
28995
|
-
return x >= low && x <= high;
|
|
28996
|
-
}
|
|
28997
|
-
|
|
28998
29048
|
function SVGLine(props) {
|
|
28999
29049
|
const {
|
|
29000
29050
|
start,
|
|
@@ -29004,10 +29054,10 @@ function SVGLine(props) {
|
|
|
29004
29054
|
testId
|
|
29005
29055
|
} = props;
|
|
29006
29056
|
return /*#__PURE__*/React__namespace.createElement("line", {
|
|
29007
|
-
x1: start[
|
|
29008
|
-
y1: start[
|
|
29009
|
-
x2: end[
|
|
29010
|
-
y2: end[
|
|
29057
|
+
x1: start[X],
|
|
29058
|
+
y1: start[Y],
|
|
29059
|
+
x2: end[X],
|
|
29060
|
+
y2: end[Y],
|
|
29011
29061
|
style: style,
|
|
29012
29062
|
className: className,
|
|
29013
29063
|
"data-testid": testId
|
|
@@ -29040,6 +29090,41 @@ function Vector(props) {
|
|
|
29040
29090
|
}));
|
|
29041
29091
|
}
|
|
29042
29092
|
|
|
29093
|
+
/**
|
|
29094
|
+
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
29095
|
+
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
29096
|
+
* @param initialPoint - The starting point of the ray.
|
|
29097
|
+
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
29098
|
+
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
29099
|
+
*/
|
|
29100
|
+
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
29101
|
+
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
29102
|
+
const [aX, aY] = initialPoint;
|
|
29103
|
+
const [bX, bY] = throughPoint;
|
|
29104
|
+
const yDiff = bY - aY;
|
|
29105
|
+
const xDiff = bX - aX;
|
|
29106
|
+
const slope = yDiff / xDiff;
|
|
29107
|
+
const inverseSlope = 1 / slope;
|
|
29108
|
+
const xExtreme = xDiff < 0 ? xMin : xMax;
|
|
29109
|
+
const yExtreme = yDiff < 0 ? yMin : yMax;
|
|
29110
|
+
const yAtXExtreme = aY + (xExtreme - aX) * slope;
|
|
29111
|
+
const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
|
|
29112
|
+
switch (true) {
|
|
29113
|
+
// does the ray exit the graph bounding box via the left or right edge?
|
|
29114
|
+
case isBetween(yAtXExtreme, yMin, yMax):
|
|
29115
|
+
return [xExtreme, yAtXExtreme];
|
|
29116
|
+
|
|
29117
|
+
// does the ray exit the graph bounding box via the top or bottom edge?
|
|
29118
|
+
case isBetween(xAtYExtreme, xMin, xMax):
|
|
29119
|
+
return [xAtYExtreme, yExtreme];
|
|
29120
|
+
default:
|
|
29121
|
+
return [xExtreme, yExtreme];
|
|
29122
|
+
}
|
|
29123
|
+
};
|
|
29124
|
+
function isBetween(x, low, high) {
|
|
29125
|
+
return x >= low && x <= high;
|
|
29126
|
+
}
|
|
29127
|
+
|
|
29043
29128
|
const LockedLine = props => {
|
|
29044
29129
|
const {
|
|
29045
29130
|
color,
|
|
@@ -29092,8 +29177,8 @@ const LockedLine = props => {
|
|
|
29092
29177
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29093
29178
|
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
29094
29179
|
}, line, showPoint1 && /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
29095
|
-
x: point1.coord[
|
|
29096
|
-
y: point1.coord[
|
|
29180
|
+
x: point1.coord[X],
|
|
29181
|
+
y: point1.coord[Y],
|
|
29097
29182
|
svgCircleProps: {
|
|
29098
29183
|
style: {
|
|
29099
29184
|
fill: point1.filled ? lockedFigureColors[point1.color] : wonderBlocksTokens.color.white,
|
|
@@ -29102,8 +29187,8 @@ const LockedLine = props => {
|
|
|
29102
29187
|
}
|
|
29103
29188
|
}
|
|
29104
29189
|
}), showPoint2 && /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
29105
|
-
x: point2.coord[
|
|
29106
|
-
y: point2.coord[
|
|
29190
|
+
x: point2.coord[X],
|
|
29191
|
+
y: point2.coord[Y],
|
|
29107
29192
|
svgCircleProps: {
|
|
29108
29193
|
style: {
|
|
29109
29194
|
fill: point2.filled ? lockedFigureColors[point2.color] : wonderBlocksTokens.color.white,
|
|
@@ -29151,8 +29236,8 @@ const LockedPolygon = props => {
|
|
|
29151
29236
|
color: lockedFigureColors[color]
|
|
29152
29237
|
}), showVertices && points.map((point, index) => /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
29153
29238
|
key: `locked-polygon-point-${index}`,
|
|
29154
|
-
x: point[
|
|
29155
|
-
y: point[
|
|
29239
|
+
x: point[X],
|
|
29240
|
+
y: point[Y],
|
|
29156
29241
|
color: lockedFigureColors[color]
|
|
29157
29242
|
})));
|
|
29158
29243
|
};
|
|
@@ -29199,6 +29284,10 @@ const GraphLockedLayer = props => {
|
|
|
29199
29284
|
return /*#__PURE__*/React__namespace.createElement(LockedPolygon, _extends({
|
|
29200
29285
|
key: `polygon-${index}`
|
|
29201
29286
|
}, figure));
|
|
29287
|
+
case "function":
|
|
29288
|
+
return /*#__PURE__*/React__namespace.createElement(LockedFunction, _extends({
|
|
29289
|
+
key: `function-${index}`
|
|
29290
|
+
}, figure));
|
|
29202
29291
|
default:
|
|
29203
29292
|
/**
|
|
29204
29293
|
* Devlopment-time future-proofing: This should
|
|
@@ -29291,24 +29380,18 @@ const normalizePoints = (range, step, coordsList, noSnap) => coordsList.map(coor
|
|
|
29291
29380
|
coords.map((coord, i) => {
|
|
29292
29381
|
const axisRange = range[i];
|
|
29293
29382
|
if (noSnap) {
|
|
29294
|
-
return axisRange[
|
|
29383
|
+
return axisRange[MIN] + size(axisRange) * coord;
|
|
29295
29384
|
}
|
|
29296
29385
|
const axisStep = step[i];
|
|
29297
|
-
const nSteps = Math.floor((axisRange
|
|
29386
|
+
const nSteps = Math.floor(size(axisRange) / axisStep);
|
|
29298
29387
|
const tick = Math.round(coord * nSteps);
|
|
29299
|
-
return axisRange[
|
|
29388
|
+
return axisRange[MIN] + axisStep * tick;
|
|
29300
29389
|
}));
|
|
29301
29390
|
|
|
29302
29391
|
// same as normalizeCoords in interactive-graph.tsx
|
|
29303
29392
|
const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.map((coord, i) => {
|
|
29304
|
-
|
|
29305
|
-
return (coord + ranges[i][1]) / extent;
|
|
29393
|
+
return (coord + ranges[i][1]) / size(ranges[i]);
|
|
29306
29394
|
}));
|
|
29307
|
-
function snap(snapStep, point) {
|
|
29308
|
-
const [requestedX, requestedY] = point;
|
|
29309
|
-
const [snapX, snapY] = snapStep;
|
|
29310
|
-
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29311
|
-
}
|
|
29312
29395
|
|
|
29313
29396
|
// Returns the closest point to the given `point` that is within the graph
|
|
29314
29397
|
// bounds given in `state`.
|
|
@@ -29318,19 +29401,8 @@ function bound$1(_ref) {
|
|
|
29318
29401
|
range,
|
|
29319
29402
|
point
|
|
29320
29403
|
} = _ref;
|
|
29321
|
-
const
|
|
29322
|
-
|
|
29323
|
-
const [[minX, maxX], [minY, maxY]] = range;
|
|
29324
|
-
return [clamp(requestedX, minX + snapX, maxX - snapX), clamp(requestedY, minY + snapY, maxY - snapY)];
|
|
29325
|
-
}
|
|
29326
|
-
function clamp(value, min, max) {
|
|
29327
|
-
if (value < min) {
|
|
29328
|
-
return min;
|
|
29329
|
-
}
|
|
29330
|
-
if (value > max) {
|
|
29331
|
-
return max;
|
|
29332
|
-
}
|
|
29333
|
-
return value;
|
|
29404
|
+
const boundingBox = inset(snapStep, range);
|
|
29405
|
+
return clampToBox(boundingBox, point);
|
|
29334
29406
|
}
|
|
29335
29407
|
|
|
29336
29408
|
var isProduction = process.env.NODE_ENV === 'production';
|
|
@@ -29400,8 +29472,8 @@ function useDraggable(args) {
|
|
|
29400
29472
|
metaKey,
|
|
29401
29473
|
shiftKey
|
|
29402
29474
|
} = state;
|
|
29403
|
-
const direction = [yDownDirection[
|
|
29404
|
-
const span = Math.abs(direction[
|
|
29475
|
+
const direction = [yDownDirection[X], -yDownDirection[Y]];
|
|
29476
|
+
const span = Math.abs(direction[X]) ? xSpan : ySpan;
|
|
29405
29477
|
let divisions = 50;
|
|
29406
29478
|
if (altKey || metaKey) {
|
|
29407
29479
|
divisions = 200;
|
|
@@ -29512,8 +29584,7 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
|
|
|
29512
29584
|
})?.[0] ?? "blue";
|
|
29513
29585
|
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""} ${focusClass(focusBehavior)}`;
|
|
29514
29586
|
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
29515
|
-
const [xMin, xMax] = range
|
|
29516
|
-
const [yMin, yMax] = range[1];
|
|
29587
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
29517
29588
|
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
29518
29589
|
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
29519
29590
|
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
@@ -29570,7 +29641,7 @@ const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
|
|
|
29570
29641
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
29571
29642
|
autoUpdate: true,
|
|
29572
29643
|
backgroundColor: wbColorName,
|
|
29573
|
-
content: `(${point[
|
|
29644
|
+
content: `(${point[X]}, ${point[Y]})`,
|
|
29574
29645
|
contentStyle: {
|
|
29575
29646
|
color: "white"
|
|
29576
29647
|
}
|
|
@@ -29755,16 +29826,7 @@ function trimRange(range, graphDimensionsInPixels) {
|
|
|
29755
29826
|
const graphUnitsPerPixelY = size(yRange) / pixelsTall;
|
|
29756
29827
|
const graphUnitsToTrimX = pixelsToTrim * graphUnitsPerPixelX;
|
|
29757
29828
|
const graphUnitsToTrimY = pixelsToTrim * graphUnitsPerPixelY;
|
|
29758
|
-
return [
|
|
29759
|
-
}
|
|
29760
|
-
function trim(interval, amount) {
|
|
29761
|
-
if (size(interval) < amount * 2) {
|
|
29762
|
-
return [0, 0];
|
|
29763
|
-
}
|
|
29764
|
-
return [interval[0] + amount, interval[1] - amount];
|
|
29765
|
-
}
|
|
29766
|
-
function size(interval) {
|
|
29767
|
-
return interval[1] - interval[0];
|
|
29829
|
+
return inset([graphUnitsToTrimX, graphUnitsToTrimY], range);
|
|
29768
29830
|
}
|
|
29769
29831
|
|
|
29770
29832
|
const SegmentGraph = props => {
|
|
@@ -29899,7 +29961,7 @@ const SvgDefs = () => /*#__PURE__*/React__default["default"].createElement("defs
|
|
|
29899
29961
|
in: "SourceGraphic"
|
|
29900
29962
|
})));
|
|
29901
29963
|
|
|
29902
|
-
const
|
|
29964
|
+
const PolygonAngle = _ref => {
|
|
29903
29965
|
let {
|
|
29904
29966
|
centerPoint,
|
|
29905
29967
|
endPoints,
|
|
@@ -29927,7 +29989,7 @@ const Angle = _ref => {
|
|
|
29927
29989
|
// Used to calculate the inside of the angle and to create square
|
|
29928
29990
|
const [x3, y3] = mafs.vec.add(centerPoint, mafs.vec.add(mafs.vec.sub([x1, y1], centerPoint), mafs.vec.sub([x2, y2], centerPoint)));
|
|
29929
29991
|
if (!showAngles) {
|
|
29930
|
-
return
|
|
29992
|
+
return isRightPolygonAngle(angle) ? /*#__PURE__*/React__namespace.createElement(RightAngleSquare, {
|
|
29931
29993
|
start: [x1, y1],
|
|
29932
29994
|
vertex: [x2, y2],
|
|
29933
29995
|
end: [x3, y3]
|
|
@@ -29964,35 +30026,138 @@ const Angle = _ref => {
|
|
|
29964
30026
|
start: [x1, y1],
|
|
29965
30027
|
vertex: [x2, y2],
|
|
29966
30028
|
end: [x3, y3]
|
|
29967
|
-
}) : /*#__PURE__*/React__namespace.createElement(
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
fill: "none"
|
|
29971
|
-
})), /*#__PURE__*/React__namespace.createElement(TextLabel, {
|
|
30029
|
+
}) : /*#__PURE__*/React__namespace.createElement(Arc, {
|
|
30030
|
+
arc: arc
|
|
30031
|
+
}), /*#__PURE__*/React__namespace.createElement(TextLabel, {
|
|
29972
30032
|
x: x3,
|
|
29973
30033
|
y: y3,
|
|
29974
30034
|
attach: y3 - centerY > 0 ? "s" : "n",
|
|
29975
30035
|
attachDistance: Math.abs(y3 - centerY) < 0.2 || mafs.vec.dist([x3, y3], centerPoint) < 0.3 ? 20 : 10
|
|
29976
30036
|
}, angleLabel, "\xB0"));
|
|
29977
30037
|
};
|
|
30038
|
+
const Angle = _ref2 => {
|
|
30039
|
+
let {
|
|
30040
|
+
vertex,
|
|
30041
|
+
coords,
|
|
30042
|
+
showAngles,
|
|
30043
|
+
allowReflexAngles,
|
|
30044
|
+
range
|
|
30045
|
+
} = _ref2;
|
|
30046
|
+
// Check if the points are clockwise or not, depending on whether we allow reflex angles
|
|
30047
|
+
const areClockwise = clockwise$1([...coords, vertex]);
|
|
30048
|
+
const shouldReverseCoords = areClockwise && !allowReflexAngles;
|
|
30049
|
+
|
|
30050
|
+
// Reverse the coordinates accordingly to ensure the angle is calculated correctly
|
|
30051
|
+
const clockwiseCoords = shouldReverseCoords ? coords : coords.reverse();
|
|
30052
|
+
|
|
30053
|
+
// Calculate the angles between the two points
|
|
30054
|
+
const startAngle = findAngle(clockwiseCoords[0], vertex);
|
|
30055
|
+
const endAngle = findAngle(clockwiseCoords[1], vertex);
|
|
30056
|
+
const angle = (startAngle + 360 - endAngle) % 360;
|
|
30057
|
+
|
|
30058
|
+
// Check if the angle is reflexive
|
|
30059
|
+
const isReflexive = angle > 180;
|
|
30060
|
+
|
|
30061
|
+
// Break out the necessary points for the arc calculation
|
|
30062
|
+
const [centerX, centerY] = vertex;
|
|
30063
|
+
const [point1, point2] = clockwiseCoords;
|
|
30064
|
+
const [startX, startY] = point1;
|
|
30065
|
+
const [endX, endY] = point2;
|
|
30066
|
+
const a = mafs.vec.dist(vertex, point1);
|
|
30067
|
+
const b = mafs.vec.dist(vertex, point2);
|
|
30068
|
+
|
|
30069
|
+
// Set the radius of the arc
|
|
30070
|
+
const radius = 2;
|
|
30071
|
+
|
|
30072
|
+
// Calculate the end points of the arc
|
|
30073
|
+
const y1 = centerY + (startY - centerY) / a * radius;
|
|
30074
|
+
const x2 = centerX + (endX - centerX) / b * radius;
|
|
30075
|
+
const x1 = centerX + (startX - centerX) / a * radius;
|
|
30076
|
+
const y2 = centerY + (endY - centerY) / b * radius;
|
|
30077
|
+
|
|
30078
|
+
// Used to calculate the inside of the angle and to create square
|
|
30079
|
+
const [x3, y3] = mafs.vec.add(vertex, mafs.vec.add(mafs.vec.sub([x1, y1], vertex), mafs.vec.sub([x2, y2], vertex)));
|
|
30080
|
+
|
|
30081
|
+
// Determine whether the arc should be drawn outside the angle
|
|
30082
|
+
const isOutside = shouldDrawArcOutside([x3, y3], vertex, range, [[vertex, point1], [vertex, point2]]);
|
|
30083
|
+
|
|
30084
|
+
// Determine the flags for the arc
|
|
30085
|
+
// If the angle is outside OR reflexive, we want to draw a large arc
|
|
30086
|
+
// If the angle is outside AND reflexive, we want to sweep the arc
|
|
30087
|
+
const largeArcFlag = isOutside || isReflexive ? 1 : 0;
|
|
30088
|
+
const sweepFlag = isOutside && isReflexive ? 1 : 0;
|
|
30089
|
+
|
|
30090
|
+
// Create the SVG path for the arc
|
|
30091
|
+
const arc = `M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${x2} ${y2}`;
|
|
30092
|
+
|
|
30093
|
+
// We only ever want to show whole angles
|
|
30094
|
+
const angleLabel = parseFloat(angle.toFixed(0)); // Only want to show whole angles
|
|
30095
|
+
|
|
30096
|
+
// Calculate the text position based on the angle and whether we allow reflex angles
|
|
30097
|
+
// Let's try the angle bisector method to find the midpoint of the arc
|
|
30098
|
+
const [textX, textY] = calculateBisectorPoint(point1, point2, vertex, isReflexive, allowReflexAngles, radius);
|
|
30099
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("filter", {
|
|
30100
|
+
id: "background",
|
|
30101
|
+
x: "-5%",
|
|
30102
|
+
width: "110%",
|
|
30103
|
+
y: "0%",
|
|
30104
|
+
height: "100%"
|
|
30105
|
+
}, /*#__PURE__*/React__namespace.createElement("feFlood", {
|
|
30106
|
+
floodColor: "#FFF",
|
|
30107
|
+
floodOpacity: "0.5"
|
|
30108
|
+
}), /*#__PURE__*/React__namespace.createElement("feComposite", {
|
|
30109
|
+
operator: "over",
|
|
30110
|
+
in: "SourceGraphic"
|
|
30111
|
+
}))), isRightAngle(angle) ? /*#__PURE__*/React__namespace.createElement(RightAngleSquare, {
|
|
30112
|
+
start: [x1, y1],
|
|
30113
|
+
vertex: [x2, y2],
|
|
30114
|
+
end: [x3, y3],
|
|
30115
|
+
className: "arc-right-angle"
|
|
30116
|
+
}) : /*#__PURE__*/React__namespace.createElement(Arc, {
|
|
30117
|
+
arc: arc,
|
|
30118
|
+
className: "angle-arc"
|
|
30119
|
+
}), showAngles && /*#__PURE__*/React__namespace.createElement(TextLabel, {
|
|
30120
|
+
x: textX,
|
|
30121
|
+
y: textY,
|
|
30122
|
+
color: wonderBlocksTokens.color.blue
|
|
30123
|
+
}, angleLabel, "\xB0"));
|
|
30124
|
+
};
|
|
29978
30125
|
|
|
29979
30126
|
/**
|
|
29980
30127
|
* This is broken out into its own component so that it can be used for an early return
|
|
29981
30128
|
* (see line 55 or https://github.com/Khan/perseus/blob/84bbd882b11d16871e1b813a0b901f3b903d5479/packages/perseus/src/widgets/interactive-graphs/graphs/components/angle.tsx#L53-L57)
|
|
29982
30129
|
*/
|
|
29983
|
-
const RightAngleSquare =
|
|
30130
|
+
const RightAngleSquare = _ref3 => {
|
|
29984
30131
|
let {
|
|
29985
30132
|
start: [x1, y1],
|
|
29986
30133
|
vertex: [x2, y2],
|
|
29987
|
-
end: [x3, y3]
|
|
29988
|
-
|
|
30134
|
+
end: [x3, y3],
|
|
30135
|
+
className
|
|
30136
|
+
} = _ref3;
|
|
29989
30137
|
return /*#__PURE__*/React__namespace.createElement(MafsCssTransformWrapper, null, /*#__PURE__*/React__namespace.createElement("path", {
|
|
29990
30138
|
d: `M ${x1} ${y1} L ${x3} ${y3} M ${x3} ${y3} L ${x2} ${y2}`,
|
|
29991
30139
|
strokeWidth: 0.02,
|
|
29992
|
-
fill: "none"
|
|
30140
|
+
fill: "none",
|
|
30141
|
+
className: className
|
|
30142
|
+
}));
|
|
30143
|
+
};
|
|
30144
|
+
|
|
30145
|
+
// We're conditionally adding the class name here so that we can style the arc differently
|
|
30146
|
+
// based on whether it's an angle or a polygon angle
|
|
30147
|
+
const Arc = _ref4 => {
|
|
30148
|
+
let {
|
|
30149
|
+
arc,
|
|
30150
|
+
className
|
|
30151
|
+
} = _ref4;
|
|
30152
|
+
return /*#__PURE__*/React__namespace.createElement(MafsCssTransformWrapper, null, /*#__PURE__*/React__namespace.createElement("path", {
|
|
30153
|
+
d: arc,
|
|
30154
|
+
strokeWidth: 0.02,
|
|
30155
|
+
fill: "none",
|
|
30156
|
+
className: className
|
|
29993
30157
|
}));
|
|
29994
30158
|
};
|
|
29995
|
-
const
|
|
30159
|
+
const isRightPolygonAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
|
|
30160
|
+
const isRightAngle = angle => Math.round(angle) === 90;
|
|
29996
30161
|
|
|
29997
30162
|
/**
|
|
29998
30163
|
* Determines if an angle is an inside (false) or outside (true) angle.
|
|
@@ -30006,27 +30171,81 @@ const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
|
|
|
30006
30171
|
// Create a ray from the midpoint (inside angle) to the edge of the range
|
|
30007
30172
|
const rangeIntersectionPoint = getIntersectionOfRayWithBox(midpoint, vertex, range);
|
|
30008
30173
|
let lineIntersectionCount = 0;
|
|
30009
|
-
polygonLines.forEach(line =>
|
|
30174
|
+
polygonLines.forEach(line => segmentsIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
|
|
30010
30175
|
|
|
30011
30176
|
// If the number of intersections is even, the angle is inside the polygon
|
|
30012
30177
|
return !isEven(lineIntersectionCount);
|
|
30013
30178
|
};
|
|
30179
|
+
const isEven = n => n % 2 === 0;
|
|
30014
30180
|
|
|
30015
|
-
//
|
|
30016
|
-
//
|
|
30017
|
-
|
|
30018
|
-
|
|
30019
|
-
|
|
30020
|
-
const
|
|
30021
|
-
|
|
30022
|
-
|
|
30181
|
+
// This function calculates the bisector point of an angle formed by two points
|
|
30182
|
+
// and a vertex. It is used to position the angle label so that it is always
|
|
30183
|
+
// outside the arc at the exact midpoint of the angle.
|
|
30184
|
+
// Reflex angles make use of polar coordinates to determine the correct direction
|
|
30185
|
+
function calculateBisectorPoint(point1, point2, vertex, isReflex, allowReflex, arcRadius) {
|
|
30186
|
+
const [originX, originY] = vertex;
|
|
30187
|
+
const [x1, y1] = point1;
|
|
30188
|
+
const [x2, y2] = point2;
|
|
30189
|
+
|
|
30190
|
+
// Convert the Cartesian Coordinates to vectors
|
|
30191
|
+
const vectorA = [x1 - originX, y1 - originY];
|
|
30192
|
+
const vectorB = [x2 - originX, y2 - originY];
|
|
30193
|
+
|
|
30194
|
+
// Calculate the average angle of the vectors
|
|
30195
|
+
// so that we can point the bisector in the correct direction using polar coordinates
|
|
30196
|
+
const angleA = Math.atan2(vectorA[1], vectorA[0]);
|
|
30197
|
+
const angleB = Math.atan2(vectorB[1], vectorB[0]);
|
|
30198
|
+
|
|
30199
|
+
// Calculate the average of these two angles
|
|
30200
|
+
let averageAngle = (angleA + angleB) / 2;
|
|
30201
|
+
const angleRadians = Math.abs(angleA - angleB);
|
|
30202
|
+
|
|
30203
|
+
// Adjust the average angle to point in the correct direction
|
|
30204
|
+
// and to account for reflex angles and a bug with 180 degrees
|
|
30205
|
+
// that occurs due to our angleOffsetDegrees option in the graph
|
|
30206
|
+
if (allowReflex) {
|
|
30207
|
+
// If the resulting angles are less than 180 degrees,
|
|
30208
|
+
// or if the user has flipped the points on the interactive element
|
|
30209
|
+
// ensure that we have the correct direction for the reflex angle
|
|
30210
|
+
if (angleRadians <= Math.PI && isReflex || angleB > angleA) {
|
|
30211
|
+
averageAngle += Math.PI; // Add 180 degrees
|
|
30212
|
+
}
|
|
30023
30213
|
} else {
|
|
30024
|
-
|
|
30025
|
-
|
|
30026
|
-
|
|
30214
|
+
// If the resulting angles are greater than 180 degrees, adjust
|
|
30215
|
+
// to get the correct angle, as we already know that the angle is not reflexive
|
|
30216
|
+
// This fixes a bug that occurs at 180 degrees due to our angleOffsetDegrees option in the graph
|
|
30217
|
+
if (angleRadians > Math.PI) {
|
|
30218
|
+
averageAngle -= Math.PI; // Subract 180 degrees
|
|
30219
|
+
}
|
|
30027
30220
|
}
|
|
30028
|
-
|
|
30029
|
-
|
|
30221
|
+
|
|
30222
|
+
// Convert the average angle back to Cartesian coordinates
|
|
30223
|
+
const sum = [Math.cos(averageAngle), Math.sin(averageAngle)];
|
|
30224
|
+
|
|
30225
|
+
// Calculate the magnitude of the sum to normalize it
|
|
30226
|
+
const sumMagnitude = Math.sqrt(sum[0] ** 2 + sum[1] ** 2);
|
|
30227
|
+
const bisectorDirection = [sum[0] / sumMagnitude, sum[1] / sumMagnitude];
|
|
30228
|
+
|
|
30229
|
+
// Calculate the initial distance of the bisector direction from the origin
|
|
30230
|
+
const initialDistance = Math.sqrt(bisectorDirection[0] ** 2 + bisectorDirection[1] ** 2);
|
|
30231
|
+
|
|
30232
|
+
// Determine the minimum radius to ensure that the text is always outside the arc
|
|
30233
|
+
const requiredDistance = arcRadius * 1.75;
|
|
30234
|
+
let radius = requiredDistance / initialDistance;
|
|
30235
|
+
|
|
30236
|
+
// Apply radius only if the initial distance is less than required
|
|
30237
|
+
if (initialDistance >= requiredDistance) {
|
|
30238
|
+
radius = 1; // Use the unit vector as is
|
|
30239
|
+
}
|
|
30240
|
+
|
|
30241
|
+
// Scale the bisector direction by the radius
|
|
30242
|
+
const bisectorPoint = [bisectorDirection[0] * radius, bisectorDirection[1] * radius];
|
|
30243
|
+
|
|
30244
|
+
// Add the vertex to the bisector point to get the final position
|
|
30245
|
+
// to ensure that the angle label moves with the interactive element
|
|
30246
|
+
const scaledBisector = mafs.vec.add(bisectorPoint, vertex);
|
|
30247
|
+
return scaledBisector;
|
|
30248
|
+
}
|
|
30030
30249
|
|
|
30031
30250
|
const StyledMovablePoint = props => {
|
|
30032
30251
|
const {
|
|
@@ -30108,7 +30327,7 @@ const PolygonGraph = props => {
|
|
|
30108
30327
|
if (!pt1 || !pt2) {
|
|
30109
30328
|
return null;
|
|
30110
30329
|
}
|
|
30111
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
30330
|
+
return /*#__PURE__*/React__namespace.createElement(PolygonAngle, {
|
|
30112
30331
|
key: "angle-" + i,
|
|
30113
30332
|
centerPoint: point,
|
|
30114
30333
|
endPoints: [pt1, pt2],
|
|
@@ -30150,6 +30369,12 @@ const PolygonGraph = props => {
|
|
|
30150
30369
|
onMove: destination => dispatch(movePoint(i, destination))
|
|
30151
30370
|
})));
|
|
30152
30371
|
};
|
|
30372
|
+
function getLines(points) {
|
|
30373
|
+
return points.map((point, i) => {
|
|
30374
|
+
const next = points[(i + 1) % points.length];
|
|
30375
|
+
return [point, next];
|
|
30376
|
+
});
|
|
30377
|
+
}
|
|
30153
30378
|
|
|
30154
30379
|
function getGradableGraph(state, initialGraph) {
|
|
30155
30380
|
if (!state.hasBeenInteractedWith) {
|
|
@@ -30212,6 +30437,13 @@ function getGradableGraph(state, initialGraph) {
|
|
|
30212
30437
|
coords: state.coords
|
|
30213
30438
|
};
|
|
30214
30439
|
}
|
|
30440
|
+
if (state.type === "angle" && initialGraph.type === "angle") {
|
|
30441
|
+
return {
|
|
30442
|
+
...initialGraph,
|
|
30443
|
+
coords: state.coords,
|
|
30444
|
+
allowReflexAngles: state.allowReflexAngles
|
|
30445
|
+
};
|
|
30446
|
+
}
|
|
30215
30447
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
30216
30448
|
}
|
|
30217
30449
|
|
|
@@ -30274,16 +30506,16 @@ function MovableCircle(props) {
|
|
|
30274
30506
|
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`
|
|
30275
30507
|
}, /*#__PURE__*/React__namespace.createElement("ellipse", {
|
|
30276
30508
|
className: "focus-ring",
|
|
30277
|
-
cx: centerPx[
|
|
30278
|
-
cy: centerPx[
|
|
30279
|
-
rx: radiiPx[
|
|
30280
|
-
ry: radiiPx[
|
|
30509
|
+
cx: centerPx[X],
|
|
30510
|
+
cy: centerPx[Y],
|
|
30511
|
+
rx: radiiPx[X] + 3,
|
|
30512
|
+
ry: radiiPx[Y] + 3
|
|
30281
30513
|
}), /*#__PURE__*/React__namespace.createElement("ellipse", {
|
|
30282
30514
|
className: "circle",
|
|
30283
|
-
cx: centerPx[
|
|
30284
|
-
cy: centerPx[
|
|
30285
|
-
rx: radiiPx[
|
|
30286
|
-
ry: radiiPx[
|
|
30515
|
+
cx: centerPx[X],
|
|
30516
|
+
cy: centerPx[Y],
|
|
30517
|
+
rx: radiiPx[X],
|
|
30518
|
+
ry: radiiPx[Y]
|
|
30287
30519
|
}), /*#__PURE__*/React__namespace.createElement(DragHandle, {
|
|
30288
30520
|
center: center
|
|
30289
30521
|
}));
|
|
@@ -30299,10 +30531,10 @@ function DragHandle(props) {
|
|
|
30299
30531
|
const topLeft = mafs.vec.sub(centerPx, mafs.vec.scale(dragHandleDimensions, 0.5));
|
|
30300
30532
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("rect", {
|
|
30301
30533
|
className: "movable-circle-handle",
|
|
30302
|
-
x: topLeft[
|
|
30303
|
-
y: topLeft[
|
|
30304
|
-
width: dragHandleDimensions[
|
|
30305
|
-
height: dragHandleDimensions[
|
|
30534
|
+
x: topLeft[X],
|
|
30535
|
+
y: topLeft[Y],
|
|
30536
|
+
width: dragHandleDimensions[X],
|
|
30537
|
+
height: dragHandleDimensions[Y],
|
|
30306
30538
|
rx: cornerRadius,
|
|
30307
30539
|
ry: cornerRadius
|
|
30308
30540
|
}), dragHandleDotPositions.map(offsetPx => {
|
|
@@ -30437,15 +30669,15 @@ const getSinusoidCoefficients = coords => {
|
|
|
30437
30669
|
const p2 = coords[1];
|
|
30438
30670
|
|
|
30439
30671
|
// If the x-coordinates are the same, we are unable to calculate the coefficients
|
|
30440
|
-
if (p2[
|
|
30672
|
+
if (p2[X] === p1[X]) {
|
|
30441
30673
|
return;
|
|
30442
30674
|
}
|
|
30443
30675
|
|
|
30444
30676
|
// Resulting coefficients are canonical for this sine curve
|
|
30445
|
-
const amplitude = p2[
|
|
30446
|
-
const angularFrequency = Math.PI / (2 * (p2[
|
|
30447
|
-
const phase = p1[
|
|
30448
|
-
const verticalOffset = p1[
|
|
30677
|
+
const amplitude = p2[Y] - p1[Y];
|
|
30678
|
+
const angularFrequency = Math.PI / (2 * (p2[X] - p1[X]));
|
|
30679
|
+
const phase = p1[X] * angularFrequency;
|
|
30680
|
+
const verticalOffset = p1[Y];
|
|
30449
30681
|
return {
|
|
30450
30682
|
amplitude,
|
|
30451
30683
|
angularFrequency,
|
|
@@ -30454,6 +30686,75 @@ const getSinusoidCoefficients = coords => {
|
|
|
30454
30686
|
};
|
|
30455
30687
|
};
|
|
30456
30688
|
|
|
30689
|
+
function AngleGraph(props) {
|
|
30690
|
+
const {
|
|
30691
|
+
dispatch,
|
|
30692
|
+
graphState
|
|
30693
|
+
} = props;
|
|
30694
|
+
const {
|
|
30695
|
+
graphDimensionsInPixels
|
|
30696
|
+
} = useGraphConfig();
|
|
30697
|
+
const {
|
|
30698
|
+
coords,
|
|
30699
|
+
showAngles,
|
|
30700
|
+
range,
|
|
30701
|
+
allowReflexAngles,
|
|
30702
|
+
angleOffsetDeg,
|
|
30703
|
+
snapDegrees
|
|
30704
|
+
} = graphState;
|
|
30705
|
+
|
|
30706
|
+
// Break the coords into the two end points and the center point
|
|
30707
|
+
const endPoints = [coords[0], coords[2]];
|
|
30708
|
+
const centerPoint = coords[1];
|
|
30709
|
+
|
|
30710
|
+
// Convert the vectors to pixels for rendering the svg lines
|
|
30711
|
+
const angleLines = [[centerPoint, endPoints[0]], [centerPoint, endPoints[1]]];
|
|
30712
|
+
const linePixelCoords = [useTransformVectorsToPixels(centerPoint, endPoints[0]), useTransformVectorsToPixels(centerPoint, endPoints[1])];
|
|
30713
|
+
|
|
30714
|
+
// Create the SVG lines for the angle
|
|
30715
|
+
const svgLines = linePixelCoords.map((_ref, i) => {
|
|
30716
|
+
let [startPtPx, endPtPx] = _ref;
|
|
30717
|
+
const trimmedRange = trimRange(range, graphDimensionsInPixels);
|
|
30718
|
+
const endExtend = getIntersectionOfRayWithBox(angleLines[i][0], angleLines[i][1], trimmedRange);
|
|
30719
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
30720
|
+
key: `line-${i}`
|
|
30721
|
+
}, /*#__PURE__*/React__namespace.createElement(SVGLine, {
|
|
30722
|
+
start: startPtPx,
|
|
30723
|
+
end: endPtPx,
|
|
30724
|
+
style: {
|
|
30725
|
+
stroke: "var(--movable-line-stroke-color)",
|
|
30726
|
+
strokeWidth: "var(--movable-line-stroke-weight)"
|
|
30727
|
+
}
|
|
30728
|
+
}), /*#__PURE__*/React__namespace.createElement(Vector, {
|
|
30729
|
+
tail: angleLines[i][1],
|
|
30730
|
+
tip: endExtend,
|
|
30731
|
+
color: "var(--movable-line-stroke-color)"
|
|
30732
|
+
}));
|
|
30733
|
+
});
|
|
30734
|
+
|
|
30735
|
+
// Create the angle indicator parameters
|
|
30736
|
+
const angleParams = {
|
|
30737
|
+
vertex: centerPoint,
|
|
30738
|
+
coords: endPoints,
|
|
30739
|
+
allowReflexAngles: allowReflexAngles || false,
|
|
30740
|
+
// Whether to allow reflex angles or not
|
|
30741
|
+
angleOffsetDeg: angleOffsetDeg || 0,
|
|
30742
|
+
// The angle offset from the x-axis
|
|
30743
|
+
snapDegrees: snapDegrees || 1,
|
|
30744
|
+
// The multiple of degrees to snap to
|
|
30745
|
+
range: range,
|
|
30746
|
+
showAngles: showAngles || false // Whether to show the angle or not
|
|
30747
|
+
};
|
|
30748
|
+
|
|
30749
|
+
// Render the lines, angle, and then movable points
|
|
30750
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, svgLines, /*#__PURE__*/React__namespace.createElement(Angle, angleParams), coords.map((point, i) => /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30751
|
+
key: "point-" + i,
|
|
30752
|
+
snapTo: "angles",
|
|
30753
|
+
point: point,
|
|
30754
|
+
onMove: destination => dispatch(movePoint(i, destination))
|
|
30755
|
+
})));
|
|
30756
|
+
}
|
|
30757
|
+
|
|
30457
30758
|
// Universal padding for the axis ticks to ensure that the labels
|
|
30458
30759
|
// have enough space to render without overlapping the tick lines
|
|
30459
30760
|
const tickPadding = 5;
|
|
@@ -30463,10 +30764,8 @@ const AxisTickLabels = () => {
|
|
|
30463
30764
|
tickStep,
|
|
30464
30765
|
range
|
|
30465
30766
|
} = graphConfig;
|
|
30466
|
-
const [xMin, xMax] = range
|
|
30467
|
-
const [
|
|
30468
|
-
const yTickStep = tickStep[1];
|
|
30469
|
-
const xTickStep = tickStep[0];
|
|
30767
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
30768
|
+
const [xTickStep, yTickStep] = tickStep;
|
|
30470
30769
|
const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
|
|
30471
30770
|
const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
|
|
30472
30771
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
@@ -30748,13 +31047,13 @@ const YGridTick = _ref => {
|
|
|
30748
31047
|
|
|
30749
31048
|
// If the graph is zoomed in, we want to make sure the ticks are still visible
|
|
30750
31049
|
// even if they are outside the graph's range.
|
|
30751
|
-
if (graphInfo.range[
|
|
31050
|
+
if (graphInfo.range[X][MIN] > 0) {
|
|
30752
31051
|
// If the graph is on the positive side of the x-axis, lock the ticks to the left side of the graph
|
|
30753
|
-
xPointOnAxis = graphInfo.range[
|
|
31052
|
+
xPointOnAxis = graphInfo.range[X][MIN];
|
|
30754
31053
|
}
|
|
30755
|
-
if (graphInfo.range[
|
|
31054
|
+
if (graphInfo.range[X][MAX] < 0) {
|
|
30756
31055
|
// If the graph is on the negative side of the x-axis, lock the ticks to the right side of the graph
|
|
30757
|
-
xPointOnAxis = graphInfo.range[
|
|
31056
|
+
xPointOnAxis = graphInfo.range[X][MAX];
|
|
30758
31057
|
}
|
|
30759
31058
|
const pointOnAxis = [xPointOnAxis, y];
|
|
30760
31059
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
@@ -30789,13 +31088,13 @@ const XGridTick = _ref2 => {
|
|
|
30789
31088
|
let yPointOnAxis = 0;
|
|
30790
31089
|
// If the graph is zoomed in, we want to make sure the ticks are still visible
|
|
30791
31090
|
// even if they are outside the graph's range.
|
|
30792
|
-
if (graphInfo.range[
|
|
31091
|
+
if (graphInfo.range[Y][MIN] > 0) {
|
|
30793
31092
|
// If the graph is on the positive side of the y-axis, lock the ticks to the top of the graph
|
|
30794
|
-
yPointOnAxis = graphInfo.range[
|
|
31093
|
+
yPointOnAxis = graphInfo.range[Y][MIN];
|
|
30795
31094
|
}
|
|
30796
|
-
if (graphInfo.range[
|
|
31095
|
+
if (graphInfo.range[Y][MAX] < 0) {
|
|
30797
31096
|
// If the graph is on the negative side of the x-axis, lock the ticks to the bottom of the graph
|
|
30798
|
-
yPointOnAxis = graphInfo.range[
|
|
31097
|
+
yPointOnAxis = graphInfo.range[Y][MAX];
|
|
30799
31098
|
}
|
|
30800
31099
|
const pointOnAxis = [x, yPointOnAxis];
|
|
30801
31100
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
@@ -30850,10 +31149,8 @@ const AxisTicks = () => {
|
|
|
30850
31149
|
width,
|
|
30851
31150
|
height
|
|
30852
31151
|
};
|
|
30853
|
-
const [xMin, xMax] = range
|
|
30854
|
-
const [
|
|
30855
|
-
const yTickStep = tickStep[1];
|
|
30856
|
-
const xTickStep = tickStep[0];
|
|
31152
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
31153
|
+
const [xTickStep, yTickStep] = tickStep;
|
|
30857
31154
|
const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
|
|
30858
31155
|
const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
|
|
30859
31156
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -30892,8 +31189,8 @@ const axisOptions = (props, axisIndex) => {
|
|
|
30892
31189
|
};
|
|
30893
31190
|
const Grid = props => {
|
|
30894
31191
|
return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
30895
|
-
xAxis: axisOptions(props,
|
|
30896
|
-
yAxis: axisOptions(props,
|
|
31192
|
+
xAxis: axisOptions(props, X),
|
|
31193
|
+
yAxis: axisOptions(props, Y)
|
|
30897
31194
|
}),
|
|
30898
31195
|
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
30899
31196
|
props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)));
|
|
@@ -31390,7 +31687,7 @@ const PropCheckBox = createReactClass__default["default"]({
|
|
|
31390
31687
|
return !___default["default"].has(this.DEFAULT_PROPS, localPropName);
|
|
31391
31688
|
}, this);
|
|
31392
31689
|
if (!propName) {
|
|
31393
|
-
throw new PerseusError("Attempted to create a PropCheckBox with no prop!", Errors.InvalidInput);
|
|
31690
|
+
throw new perseusCore.PerseusError("Attempted to create a PropCheckBox with no prop!", perseusCore.Errors.InvalidInput);
|
|
31394
31691
|
}
|
|
31395
31692
|
return propName;
|
|
31396
31693
|
},
|
|
@@ -31501,7 +31798,7 @@ const LegacyGrid = _ref => {
|
|
|
31501
31798
|
height
|
|
31502
31799
|
} = backgroundImage ?? {};
|
|
31503
31800
|
if (url && typeof url === "string") {
|
|
31504
|
-
const scale = box[
|
|
31801
|
+
const scale = box[X] / interactiveSizes$1.defaultBoxSize;
|
|
31505
31802
|
return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31506
31803
|
style: {
|
|
31507
31804
|
position: "absolute",
|
|
@@ -31569,9 +31866,9 @@ function Protractor() {
|
|
|
31569
31866
|
const angle = calculateAngleInDegrees(rotationHandleOffset) - calculateAngleInDegrees(centerToRotationHandle);
|
|
31570
31867
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
31571
31868
|
ref: draggableRef,
|
|
31572
|
-
transform: `translate(${topLeftPx[
|
|
31869
|
+
transform: `translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,
|
|
31573
31870
|
style: {
|
|
31574
|
-
transformOrigin: `${-centerToTopLeft[
|
|
31871
|
+
transformOrigin: `${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`
|
|
31575
31872
|
}
|
|
31576
31873
|
}, /*#__PURE__*/React__namespace.createElement("image", {
|
|
31577
31874
|
href: protractorImage
|
|
@@ -31583,7 +31880,7 @@ function Protractor() {
|
|
|
31583
31880
|
function RotationArrow() {
|
|
31584
31881
|
const radius = 175;
|
|
31585
31882
|
const angleDeg = 10;
|
|
31586
|
-
const angleRad =
|
|
31883
|
+
const angleRad = convertDegreesToRadians(angleDeg);
|
|
31587
31884
|
const endX = radius * (1 - Math.cos(angleRad));
|
|
31588
31885
|
const endY = radius * -Math.sin(angleRad);
|
|
31589
31886
|
const rotationArrow = pathBuilder().move(0, 0).circularArc(radius, endX, endY, {
|
|
@@ -31662,17 +31959,135 @@ function useDraggablePx(args) {
|
|
|
31662
31959
|
});
|
|
31663
31960
|
}
|
|
31664
31961
|
|
|
31665
|
-
|
|
31666
|
-
|
|
31667
|
-
|
|
31668
|
-
|
|
31669
|
-
|
|
31670
|
-
|
|
31671
|
-
|
|
31672
|
-
|
|
31673
|
-
|
|
31674
|
-
|
|
31675
|
-
|
|
31962
|
+
const MafsGraph = props => {
|
|
31963
|
+
const {
|
|
31964
|
+
state,
|
|
31965
|
+
dispatch,
|
|
31966
|
+
labels
|
|
31967
|
+
} = props;
|
|
31968
|
+
const [width, height] = props.box;
|
|
31969
|
+
const tickStep = props.step;
|
|
31970
|
+
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
31971
|
+
value: {
|
|
31972
|
+
range: state.range,
|
|
31973
|
+
snapStep: state.snapStep,
|
|
31974
|
+
markings: props.markings,
|
|
31975
|
+
tickStep: tickStep,
|
|
31976
|
+
gridStep: props.gridStep,
|
|
31977
|
+
showTooltips: !!props.showTooltips,
|
|
31978
|
+
graphDimensionsInPixels: props.box,
|
|
31979
|
+
width,
|
|
31980
|
+
height,
|
|
31981
|
+
labels
|
|
31982
|
+
}
|
|
31983
|
+
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31984
|
+
className: "mafs-graph",
|
|
31985
|
+
style: {
|
|
31986
|
+
width,
|
|
31987
|
+
height,
|
|
31988
|
+
position: "relative",
|
|
31989
|
+
padding: "25px 25px 0 0",
|
|
31990
|
+
boxSizing: "content-box",
|
|
31991
|
+
marginLeft: "20px",
|
|
31992
|
+
marginBottom: "20px"
|
|
31993
|
+
}
|
|
31994
|
+
}, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
|
|
31995
|
+
box: props.box,
|
|
31996
|
+
backgroundImage: props.backgroundImage
|
|
31997
|
+
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31998
|
+
style: {
|
|
31999
|
+
position: "absolute",
|
|
32000
|
+
bottom: 0,
|
|
32001
|
+
left: 0
|
|
32002
|
+
}
|
|
32003
|
+
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
32004
|
+
preserveAspectRatio: false,
|
|
32005
|
+
viewBox: {
|
|
32006
|
+
x: state.range[X],
|
|
32007
|
+
y: state.range[Y],
|
|
32008
|
+
padding: 0
|
|
32009
|
+
},
|
|
32010
|
+
pan: false,
|
|
32011
|
+
zoom: false,
|
|
32012
|
+
width: width,
|
|
32013
|
+
height: height
|
|
32014
|
+
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
32015
|
+
tickStep: props.step,
|
|
32016
|
+
gridStep: props.gridStep,
|
|
32017
|
+
range: state.range,
|
|
32018
|
+
containerSizeClass: props.containerSizeClass,
|
|
32019
|
+
markings: props.markings
|
|
32020
|
+
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
32021
|
+
lockedFigures: props.lockedFigures,
|
|
32022
|
+
range: state.range
|
|
32023
|
+
}), "/* Protractor */", props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32024
|
+
state,
|
|
32025
|
+
dispatch
|
|
32026
|
+
})))));
|
|
32027
|
+
};
|
|
32028
|
+
const renderGraph = props => {
|
|
32029
|
+
const {
|
|
32030
|
+
state,
|
|
32031
|
+
dispatch
|
|
32032
|
+
} = props;
|
|
32033
|
+
const {
|
|
32034
|
+
type
|
|
32035
|
+
} = state;
|
|
32036
|
+
switch (type) {
|
|
32037
|
+
case "angle":
|
|
32038
|
+
return /*#__PURE__*/React__namespace.createElement(AngleGraph, {
|
|
32039
|
+
graphState: state,
|
|
32040
|
+
dispatch: dispatch
|
|
32041
|
+
});
|
|
32042
|
+
case "segment":
|
|
32043
|
+
return /*#__PURE__*/React__namespace.createElement(SegmentGraph, {
|
|
32044
|
+
graphState: state,
|
|
32045
|
+
dispatch: dispatch
|
|
32046
|
+
});
|
|
32047
|
+
case "linear-system":
|
|
32048
|
+
return /*#__PURE__*/React__namespace.createElement(LinearSystemGraph, {
|
|
32049
|
+
graphState: state,
|
|
32050
|
+
dispatch: dispatch
|
|
32051
|
+
});
|
|
32052
|
+
case "linear":
|
|
32053
|
+
return /*#__PURE__*/React__namespace.createElement(LinearGraph, {
|
|
32054
|
+
graphState: state,
|
|
32055
|
+
dispatch: dispatch
|
|
32056
|
+
});
|
|
32057
|
+
case "ray":
|
|
32058
|
+
return /*#__PURE__*/React__namespace.createElement(RayGraph, {
|
|
32059
|
+
graphState: state,
|
|
32060
|
+
dispatch: dispatch
|
|
32061
|
+
});
|
|
32062
|
+
case "polygon":
|
|
32063
|
+
return /*#__PURE__*/React__namespace.createElement(PolygonGraph, {
|
|
32064
|
+
graphState: state,
|
|
32065
|
+
dispatch: dispatch
|
|
32066
|
+
});
|
|
32067
|
+
case "point":
|
|
32068
|
+
return /*#__PURE__*/React__namespace.createElement(PointGraph, {
|
|
32069
|
+
graphState: state,
|
|
32070
|
+
dispatch: dispatch
|
|
32071
|
+
});
|
|
32072
|
+
case "circle":
|
|
32073
|
+
return /*#__PURE__*/React__namespace.createElement(CircleGraph, {
|
|
32074
|
+
graphState: state,
|
|
32075
|
+
dispatch: dispatch
|
|
32076
|
+
});
|
|
32077
|
+
case "quadratic":
|
|
32078
|
+
return /*#__PURE__*/React__namespace.createElement(QuadraticGraph, {
|
|
32079
|
+
graphState: state,
|
|
32080
|
+
dispatch: dispatch
|
|
32081
|
+
});
|
|
32082
|
+
case "sinusoid":
|
|
32083
|
+
return /*#__PURE__*/React__namespace.createElement(SinusoidGraph, {
|
|
32084
|
+
graphState: state,
|
|
32085
|
+
dispatch: dispatch
|
|
32086
|
+
});
|
|
32087
|
+
default:
|
|
32088
|
+
return new wonderStuffCore.UnreachableCaseError(type);
|
|
32089
|
+
}
|
|
32090
|
+
};
|
|
31676
32091
|
|
|
31677
32092
|
function initializeGraphState(params) {
|
|
31678
32093
|
const {
|
|
@@ -31745,7 +32160,19 @@ function initializeGraphState(params) {
|
|
|
31745
32160
|
coords: getSinusoidCoords(graph, range, step)
|
|
31746
32161
|
};
|
|
31747
32162
|
case "angle":
|
|
31748
|
-
|
|
32163
|
+
return {
|
|
32164
|
+
...shared,
|
|
32165
|
+
type: graph.type,
|
|
32166
|
+
showAngles: Boolean(graph.showAngles),
|
|
32167
|
+
coords: getAngleCoords({
|
|
32168
|
+
graph,
|
|
32169
|
+
range,
|
|
32170
|
+
step
|
|
32171
|
+
}),
|
|
32172
|
+
angleOffsetDeg: Number(graph.angleOffsetDeg),
|
|
32173
|
+
allowReflexAngles: Boolean(graph.allowReflexAngles),
|
|
32174
|
+
snapDegrees: Number(graph.snapDegrees)
|
|
32175
|
+
};
|
|
31749
32176
|
default:
|
|
31750
32177
|
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
31751
32178
|
}
|
|
@@ -31877,6 +32304,43 @@ function getCircleCoords(graph) {
|
|
|
31877
32304
|
radiusPoint: [2, 0]
|
|
31878
32305
|
};
|
|
31879
32306
|
}
|
|
32307
|
+
const getAngleCoords = params => {
|
|
32308
|
+
const {
|
|
32309
|
+
graph,
|
|
32310
|
+
range,
|
|
32311
|
+
step
|
|
32312
|
+
} = params;
|
|
32313
|
+
if (graph.coords) {
|
|
32314
|
+
return graph.coords;
|
|
32315
|
+
}
|
|
32316
|
+
const {
|
|
32317
|
+
snapDegrees,
|
|
32318
|
+
angleOffsetDeg
|
|
32319
|
+
} = graph;
|
|
32320
|
+
const snap = snapDegrees || 1;
|
|
32321
|
+
let angle = snap;
|
|
32322
|
+
while (angle < 20) {
|
|
32323
|
+
angle += snap;
|
|
32324
|
+
}
|
|
32325
|
+
angle = angle * Math.PI / 180;
|
|
32326
|
+
const offset = (angleOffsetDeg || 0) * Math.PI / 180;
|
|
32327
|
+
let defaultCoords = [[0.85, 0.5], [0.5, 0.5]];
|
|
32328
|
+
defaultCoords = normalizePoints(range, step, defaultCoords, true);
|
|
32329
|
+
|
|
32330
|
+
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
32331
|
+
const radius = magnitude(vector(...defaultCoords));
|
|
32332
|
+
|
|
32333
|
+
// We're adding a placeholder for the third point to appease ts and so that we
|
|
32334
|
+
// can calculate it after we've adjusted the first point by the angleOffsetDeg
|
|
32335
|
+
const coords = [...defaultCoords, [0, 0]];
|
|
32336
|
+
|
|
32337
|
+
// Adjust the lower point by angleOffsetDeg degrees
|
|
32338
|
+
coords[0] = [coords[1][0] + radius * Math.cos(offset), coords[1][1] + radius * Math.sin(offset)];
|
|
32339
|
+
// Position the upper point angle radians from the
|
|
32340
|
+
// lower point
|
|
32341
|
+
coords[2] = [coords[1][0] + radius * Math.cos(angle + offset), coords[1][1] + radius * Math.sin(angle + offset)];
|
|
32342
|
+
return coords;
|
|
32343
|
+
};
|
|
31880
32344
|
|
|
31881
32345
|
function interactiveGraphReducer(state, action) {
|
|
31882
32346
|
switch (action.type) {
|
|
@@ -31940,6 +32404,7 @@ function doMoveControlPoint(state, action) {
|
|
|
31940
32404
|
coords: newCoords
|
|
31941
32405
|
};
|
|
31942
32406
|
}
|
|
32407
|
+
case "angle":
|
|
31943
32408
|
case "circle":
|
|
31944
32409
|
throw new Error("FIXME implement circle reducer");
|
|
31945
32410
|
case "point":
|
|
@@ -32044,12 +32509,32 @@ function doMoveAll(state, action) {
|
|
|
32044
32509
|
}
|
|
32045
32510
|
function doMovePoint(state, action) {
|
|
32046
32511
|
switch (state.type) {
|
|
32512
|
+
case "angle":
|
|
32513
|
+
// If the index is 1, we are moving the vertex of the angle,
|
|
32514
|
+
// which will move the other two points as well
|
|
32515
|
+
if (action.index === 1) {
|
|
32516
|
+
const updatedCoords = boundAndSnapAngleVertex(state, action);
|
|
32517
|
+
return {
|
|
32518
|
+
...state,
|
|
32519
|
+
hasBeenInteractedWith: true,
|
|
32520
|
+
coords: updatedCoords
|
|
32521
|
+
};
|
|
32522
|
+
}
|
|
32523
|
+
return {
|
|
32524
|
+
...state,
|
|
32525
|
+
hasBeenInteractedWith: true,
|
|
32526
|
+
coords: setAtIndex({
|
|
32527
|
+
array: state.coords,
|
|
32528
|
+
index: action.index,
|
|
32529
|
+
newValue: boundAndSnapAngleEndPoints(action.destination, state, action.index)
|
|
32530
|
+
})
|
|
32531
|
+
};
|
|
32047
32532
|
case "polygon":
|
|
32048
32533
|
let newValue;
|
|
32049
32534
|
if (state.snapTo === "sides") {
|
|
32050
32535
|
newValue = boundAndSnapToSides(action.destination, state, action.index);
|
|
32051
32536
|
} else if (state.snapTo === "angles") {
|
|
32052
|
-
newValue =
|
|
32537
|
+
newValue = boundAndSnapToPolygonAngle(action.destination, state, action.index);
|
|
32053
32538
|
} else {
|
|
32054
32539
|
newValue = boundAndSnapToGrid(action.destination, state);
|
|
32055
32540
|
}
|
|
@@ -32090,7 +32575,7 @@ function doMovePoint(state, action) {
|
|
|
32090
32575
|
// vertical line. If they are, then we don't want to move the point
|
|
32091
32576
|
const newCoords = [...state.coords];
|
|
32092
32577
|
newCoords[action.index] = boundDestination;
|
|
32093
|
-
if (newCoords[0][
|
|
32578
|
+
if (newCoords[0][X] === newCoords[1][X]) {
|
|
32094
32579
|
return state;
|
|
32095
32580
|
}
|
|
32096
32581
|
return {
|
|
@@ -32150,13 +32635,13 @@ function doMoveCenter(state, action) {
|
|
|
32150
32635
|
// if it otherwise would be off the chart
|
|
32151
32636
|
// ex: if the handle is on the right and we move the center
|
|
32152
32637
|
// to the rightmost position, move the handle to the left
|
|
32153
|
-
const [xMin, xMax] = state.range[
|
|
32638
|
+
const [xMin, xMax] = state.range[X];
|
|
32154
32639
|
const [radX] = newRadiusPoint;
|
|
32155
32640
|
if (radX < xMin || radX > xMax) {
|
|
32156
|
-
const xJumpDist = (radX - constrainedCenter[
|
|
32641
|
+
const xJumpDist = (radX - constrainedCenter[X]) * 2;
|
|
32157
32642
|
const possibleNewX = radX - xJumpDist;
|
|
32158
32643
|
if (possibleNewX >= xMin && possibleNewX <= xMax) {
|
|
32159
|
-
newRadiusPoint[
|
|
32644
|
+
newRadiusPoint[X] = possibleNewX;
|
|
32160
32645
|
}
|
|
32161
32646
|
}
|
|
32162
32647
|
return {
|
|
@@ -32174,11 +32659,11 @@ function doMoveRadiusPoint(state, action) {
|
|
|
32174
32659
|
switch (state.type) {
|
|
32175
32660
|
case "circle":
|
|
32176
32661
|
{
|
|
32177
|
-
const [xMin, xMax] = state.range[
|
|
32662
|
+
const [xMin, xMax] = state.range[X];
|
|
32178
32663
|
const nextRadiusPoint = [
|
|
32179
32664
|
// Constrain to graph range
|
|
32180
32665
|
// The +0 is to convert -0 to +0
|
|
32181
|
-
|
|
32666
|
+
clamp(action.destination[X] + 0, xMin, xMax), state.center[1]];
|
|
32182
32667
|
if (___default["default"].isEqual(nextRadiusPoint, state.center)) {
|
|
32183
32668
|
return state;
|
|
32184
32669
|
}
|
|
@@ -32216,10 +32701,10 @@ function doChangeRange(state, action) {
|
|
|
32216
32701
|
}
|
|
32217
32702
|
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
32218
32703
|
const [deltaX, deltaY] = delta;
|
|
32219
|
-
const maxXMove = Math.min(...maxMoves.map(move => move[
|
|
32220
|
-
const maxYMove = Math.min(...maxMoves.map(move => move[
|
|
32221
|
-
const minXMove = Math.max(...minMoves.map(move => move[
|
|
32222
|
-
const minYMove = Math.max(...minMoves.map(move => move[
|
|
32704
|
+
const maxXMove = Math.min(...maxMoves.map(move => move[X]));
|
|
32705
|
+
const maxYMove = Math.min(...maxMoves.map(move => move[Y]));
|
|
32706
|
+
const minXMove = Math.max(...minMoves.map(move => move[X]));
|
|
32707
|
+
const minYMove = Math.max(...minMoves.map(move => move[Y]));
|
|
32223
32708
|
const dx = clamp(deltaX, minXMove, maxXMove);
|
|
32224
32709
|
const dy = clamp(deltaY, minYMove, maxYMove);
|
|
32225
32710
|
return [dx, dy];
|
|
@@ -32253,11 +32738,130 @@ function boundAndSnapToGrid(point, _ref) {
|
|
|
32253
32738
|
point
|
|
32254
32739
|
}));
|
|
32255
32740
|
}
|
|
32256
|
-
function
|
|
32741
|
+
function boundAndSnapAngleVertex(_ref2, _ref3) {
|
|
32257
32742
|
let {
|
|
32258
32743
|
range,
|
|
32259
|
-
coords
|
|
32744
|
+
coords,
|
|
32745
|
+
snapStep
|
|
32260
32746
|
} = _ref2;
|
|
32747
|
+
let {
|
|
32748
|
+
destination
|
|
32749
|
+
} = _ref3;
|
|
32750
|
+
// Needed to prevent updating the original coords before the checks for
|
|
32751
|
+
// degenerate triangles and overlapping sides
|
|
32752
|
+
const coordsCopy = [...coords];
|
|
32753
|
+
|
|
32754
|
+
// Get the current and upcoming positions of the vertex
|
|
32755
|
+
const startingVertex = coordsCopy[1];
|
|
32756
|
+
const newVertex = bound$1({
|
|
32757
|
+
snapStep,
|
|
32758
|
+
range,
|
|
32759
|
+
point: snap(snapStep, destination)
|
|
32760
|
+
});
|
|
32761
|
+
|
|
32762
|
+
// Get the vector from the starting vertex to the new vertex
|
|
32763
|
+
const delta = mafs.vec.add(newVertex, reverseVector(startingVertex));
|
|
32764
|
+
|
|
32765
|
+
// Apply the delta to each of the other two points so that the angle is maintained
|
|
32766
|
+
let valid = true;
|
|
32767
|
+
const newPoints = {};
|
|
32768
|
+
for (const i of [0, 2]) {
|
|
32769
|
+
const oldPoint = coordsCopy[i];
|
|
32770
|
+
let newPoint = mafs.vec.add(oldPoint, delta);
|
|
32771
|
+
let angle = findAngle(newVertex, newPoint);
|
|
32772
|
+
angle *= Math.PI / 180;
|
|
32773
|
+
newPoint = constrainToBoundsOnAngle(newPoint, angle, range, snapStep);
|
|
32774
|
+
newPoints[i] = newPoint;
|
|
32775
|
+
|
|
32776
|
+
// Check if the new point is too close to the vertex
|
|
32777
|
+
if (tooClose(newVertex, newPoint)) {
|
|
32778
|
+
valid = false;
|
|
32779
|
+
}
|
|
32780
|
+
}
|
|
32781
|
+
|
|
32782
|
+
// Update the vertex after snapping to the snapStep
|
|
32783
|
+
newPoints[1] = newVertex;
|
|
32784
|
+
// Only move points if all new positions are valid
|
|
32785
|
+
if (valid) {
|
|
32786
|
+
Object.entries(newPoints).forEach(_ref4 => {
|
|
32787
|
+
let [i, newPoint] = _ref4;
|
|
32788
|
+
coordsCopy[i] = newPoint;
|
|
32789
|
+
});
|
|
32790
|
+
}
|
|
32791
|
+
return coordsCopy;
|
|
32792
|
+
}
|
|
32793
|
+
|
|
32794
|
+
// This function is used to ensure that the vertex of
|
|
32795
|
+
// an angle is not too close to the other points
|
|
32796
|
+
function tooClose(point1, point2, range) {
|
|
32797
|
+
const safeDistance = 2;
|
|
32798
|
+
const distance = mafs.vec.dist(point1, point2);
|
|
32799
|
+
return distance < safeDistance;
|
|
32800
|
+
}
|
|
32801
|
+
function constrainToBoundsOnAngle(point, angle, range, snapStep) {
|
|
32802
|
+
// We're subtracting the snapStep from the lower bound and adding it to the upper bound
|
|
32803
|
+
// to ensure that the point is within the bounds of the graph even after snapping to the nearest degree
|
|
32804
|
+
const lower = [range[0][0] + snapStep[0], range[1][0] + snapStep[0]];
|
|
32805
|
+
const upper = [range[0][1] - snapStep[1], range[1][1] - snapStep[1]];
|
|
32806
|
+
let result = point;
|
|
32807
|
+
if (result[0] < lower[0]) {
|
|
32808
|
+
result = [lower[0], result[1] + (lower[0] - result[0]) * Math.tan(angle)];
|
|
32809
|
+
} else if (result[0] > upper[0]) {
|
|
32810
|
+
result = [upper[0], result[1] - (result[0] - upper[0]) * Math.tan(angle)];
|
|
32811
|
+
}
|
|
32812
|
+
if (result[1] < lower[1]) {
|
|
32813
|
+
result = [result[0] + (lower[1] - result[1]) / Math.tan(angle), lower[1]];
|
|
32814
|
+
} else if (result[1] > upper[1]) {
|
|
32815
|
+
result = [result[0] - (result[1] - upper[1]) / Math.tan(angle), upper[1]];
|
|
32816
|
+
}
|
|
32817
|
+
return result;
|
|
32818
|
+
}
|
|
32819
|
+
function boundAndSnapAngleEndPoints(destinationPoint, _ref5, index) {
|
|
32820
|
+
let {
|
|
32821
|
+
range,
|
|
32822
|
+
coords,
|
|
32823
|
+
snapDegrees,
|
|
32824
|
+
angleOffsetDeg,
|
|
32825
|
+
snapStep
|
|
32826
|
+
} = _ref5;
|
|
32827
|
+
const snap = snapDegrees || 1;
|
|
32828
|
+
const offsetDegrees = angleOffsetDeg || 0;
|
|
32829
|
+
|
|
32830
|
+
// Needed to prevent updating the original coords before the checks for
|
|
32831
|
+
// degenerate triangles and overlapping sides
|
|
32832
|
+
const coordsCopy = [...coords];
|
|
32833
|
+
|
|
32834
|
+
// We want to subtract or add the snapStep to the lower and upper bounds
|
|
32835
|
+
// respectively to ensure that the point is within the bounds of the graph
|
|
32836
|
+
// even after snapping to the nearest degree
|
|
32837
|
+
const angleRange = [[range[0][0] + snapStep[0], range[0][1] - snapStep[0]], [range[1][0] + snapStep[1], range[1][1] - snapStep[1]]];
|
|
32838
|
+
|
|
32839
|
+
// Takes the destination point and makes sure it is within the bounds of the graph
|
|
32840
|
+
// SnapStep is [0, 0] because we don't want to snap these points to the grid at all
|
|
32841
|
+
const boundPoint = bound$1({
|
|
32842
|
+
snapStep: [0, 0],
|
|
32843
|
+
range: angleRange,
|
|
32844
|
+
point: destinationPoint
|
|
32845
|
+
});
|
|
32846
|
+
coordsCopy[index] = boundPoint;
|
|
32847
|
+
|
|
32848
|
+
// Get the vertex of the angle
|
|
32849
|
+
const vertex = coords[1];
|
|
32850
|
+
|
|
32851
|
+
// Gets the angle between the coords and the vertex
|
|
32852
|
+
let angle = findAngle(coordsCopy[index], vertex);
|
|
32853
|
+
|
|
32854
|
+
// Snap the angle to the nearest multiple of snapDegrees (if provided)
|
|
32855
|
+
angle = Math.round((angle - offsetDegrees) / snap) * snap + offsetDegrees;
|
|
32856
|
+
const distance = mafs.vec.dist(coordsCopy[index], vertex);
|
|
32857
|
+
const snappedValue = mafs.vec.add(vertex, polar(distance, angle));
|
|
32858
|
+
return snappedValue;
|
|
32859
|
+
}
|
|
32860
|
+
function boundAndSnapToPolygonAngle(destinationPoint, _ref6, index) {
|
|
32861
|
+
let {
|
|
32862
|
+
range,
|
|
32863
|
+
coords
|
|
32864
|
+
} = _ref6;
|
|
32261
32865
|
const startingPoint = coords[index];
|
|
32262
32866
|
|
|
32263
32867
|
// Needed to prevent updating the original coords before the checks for
|
|
@@ -32285,7 +32889,7 @@ function boundAndSnapToAngle(destinationPoint, _ref2, index) {
|
|
|
32285
32889
|
angles[rel(j)] = Math.round(angles[rel(j)]);
|
|
32286
32890
|
});
|
|
32287
32891
|
const getAngle = function (a, vertex, b) {
|
|
32288
|
-
const angle =
|
|
32892
|
+
const angle = findAngle(coordsCopy[rel(a)], coordsCopy[rel(b)], coordsCopy[rel(vertex)]);
|
|
32289
32893
|
return (angle + 360) % 360;
|
|
32290
32894
|
};
|
|
32291
32895
|
const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
|
|
@@ -32313,7 +32917,7 @@ function boundAndSnapToAngle(destinationPoint, _ref2, index) {
|
|
|
32313
32917
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
32314
32918
|
|
|
32315
32919
|
// Angle at the second vertex of the polygon
|
|
32316
|
-
const outerAngle =
|
|
32920
|
+
const outerAngle = findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
32317
32921
|
|
|
32318
32922
|
// Uses the length of the side of the polygon (radial coordinate)
|
|
32319
32923
|
// and the angle between the first and second sides of the
|
|
@@ -32321,11 +32925,11 @@ function boundAndSnapToAngle(destinationPoint, _ref2, index) {
|
|
|
32321
32925
|
const offset = polar(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
32322
32926
|
return kmath.vector.add(coordsCopy[rel(-1)], offset);
|
|
32323
32927
|
}
|
|
32324
|
-
function boundAndSnapToSides(destinationPoint,
|
|
32928
|
+
function boundAndSnapToSides(destinationPoint, _ref7, index) {
|
|
32325
32929
|
let {
|
|
32326
32930
|
range,
|
|
32327
32931
|
coords
|
|
32328
|
-
} =
|
|
32932
|
+
} = _ref7;
|
|
32329
32933
|
const startingPoint = coords[index];
|
|
32330
32934
|
|
|
32331
32935
|
// Needed to prevent updating the original coords before the checks for
|
|
@@ -32364,7 +32968,7 @@ function boundAndSnapToSides(destinationPoint, _ref3, index) {
|
|
|
32364
32968
|
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
32365
32969
|
|
|
32366
32970
|
// Angle at the second vertex of the polygon
|
|
32367
|
-
const outerAngle =
|
|
32971
|
+
const outerAngle = findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
32368
32972
|
|
|
32369
32973
|
// Returns true if the points form a counter-clockwise turn;
|
|
32370
32974
|
// a.k.a if the point is on the left or right of the polygon.
|
|
@@ -32382,12 +32986,12 @@ function boundAndSnapToSides(destinationPoint, _ref3, index) {
|
|
|
32382
32986
|
}
|
|
32383
32987
|
|
|
32384
32988
|
// Returns the vector from the given point to the top-right corner of the graph when snapped to the grid
|
|
32385
|
-
function maxMove(
|
|
32989
|
+
function maxMove(_ref8) {
|
|
32386
32990
|
let {
|
|
32387
32991
|
snapStep,
|
|
32388
32992
|
range,
|
|
32389
32993
|
point
|
|
32390
|
-
} =
|
|
32994
|
+
} = _ref8;
|
|
32391
32995
|
const topRight = bound$1({
|
|
32392
32996
|
snapStep,
|
|
32393
32997
|
range,
|
|
@@ -32397,12 +33001,12 @@ function maxMove(_ref4) {
|
|
|
32397
33001
|
}
|
|
32398
33002
|
|
|
32399
33003
|
// Returns the vector from the given point to the bottom-left corner of the graph when snapped to the grid
|
|
32400
|
-
function minMove(
|
|
33004
|
+
function minMove(_ref9) {
|
|
32401
33005
|
let {
|
|
32402
33006
|
snapStep,
|
|
32403
33007
|
range,
|
|
32404
33008
|
point
|
|
32405
|
-
} =
|
|
33009
|
+
} = _ref9;
|
|
32406
33010
|
const bottomLeft = bound$1({
|
|
32407
33011
|
snapStep,
|
|
32408
33012
|
range,
|
|
@@ -32435,65 +33039,6 @@ function setAtIndex(args) {
|
|
|
32435
33039
|
return copy;
|
|
32436
33040
|
}
|
|
32437
33041
|
|
|
32438
|
-
const renderGraph = props => {
|
|
32439
|
-
const {
|
|
32440
|
-
state,
|
|
32441
|
-
dispatch
|
|
32442
|
-
} = props;
|
|
32443
|
-
const {
|
|
32444
|
-
type
|
|
32445
|
-
} = state;
|
|
32446
|
-
switch (type) {
|
|
32447
|
-
case "segment":
|
|
32448
|
-
return /*#__PURE__*/React__namespace.createElement(SegmentGraph, {
|
|
32449
|
-
graphState: state,
|
|
32450
|
-
dispatch: dispatch
|
|
32451
|
-
});
|
|
32452
|
-
case "linear-system":
|
|
32453
|
-
return /*#__PURE__*/React__namespace.createElement(LinearSystemGraph, {
|
|
32454
|
-
graphState: state,
|
|
32455
|
-
dispatch: dispatch
|
|
32456
|
-
});
|
|
32457
|
-
case "linear":
|
|
32458
|
-
return /*#__PURE__*/React__namespace.createElement(LinearGraph, {
|
|
32459
|
-
graphState: state,
|
|
32460
|
-
dispatch: dispatch
|
|
32461
|
-
});
|
|
32462
|
-
case "ray":
|
|
32463
|
-
return /*#__PURE__*/React__namespace.createElement(RayGraph, {
|
|
32464
|
-
graphState: state,
|
|
32465
|
-
dispatch: dispatch
|
|
32466
|
-
});
|
|
32467
|
-
case "polygon":
|
|
32468
|
-
return /*#__PURE__*/React__namespace.createElement(PolygonGraph, {
|
|
32469
|
-
graphState: state,
|
|
32470
|
-
dispatch: dispatch
|
|
32471
|
-
});
|
|
32472
|
-
case "point":
|
|
32473
|
-
return /*#__PURE__*/React__namespace.createElement(PointGraph, {
|
|
32474
|
-
graphState: state,
|
|
32475
|
-
dispatch: dispatch
|
|
32476
|
-
});
|
|
32477
|
-
case "circle":
|
|
32478
|
-
return /*#__PURE__*/React__namespace.createElement(CircleGraph, {
|
|
32479
|
-
graphState: state,
|
|
32480
|
-
dispatch: dispatch
|
|
32481
|
-
});
|
|
32482
|
-
case "quadratic":
|
|
32483
|
-
return /*#__PURE__*/React__namespace.createElement(QuadraticGraph, {
|
|
32484
|
-
graphState: state,
|
|
32485
|
-
dispatch: dispatch
|
|
32486
|
-
});
|
|
32487
|
-
case "sinusoid":
|
|
32488
|
-
return /*#__PURE__*/React__namespace.createElement(SinusoidGraph, {
|
|
32489
|
-
graphState: state,
|
|
32490
|
-
dispatch: dispatch
|
|
32491
|
-
});
|
|
32492
|
-
default:
|
|
32493
|
-
return new wonderStuffCore.UnreachableCaseError(type);
|
|
32494
|
-
}
|
|
32495
|
-
};
|
|
32496
|
-
|
|
32497
33042
|
// Rather than be tightly bound to how data was structured in
|
|
32498
33043
|
// the legacy interactive graph, this lets us store state
|
|
32499
33044
|
// however we want and we just transform it before handing it off
|
|
@@ -32563,72 +33108,6 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
|
|
|
32563
33108
|
dispatch: dispatch
|
|
32564
33109
|
}));
|
|
32565
33110
|
});
|
|
32566
|
-
const MafsGraph = props => {
|
|
32567
|
-
const {
|
|
32568
|
-
state,
|
|
32569
|
-
dispatch,
|
|
32570
|
-
labels
|
|
32571
|
-
} = props;
|
|
32572
|
-
const [width, height] = props.box;
|
|
32573
|
-
const tickStep = props.step;
|
|
32574
|
-
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
32575
|
-
value: {
|
|
32576
|
-
range: state.range,
|
|
32577
|
-
snapStep: state.snapStep,
|
|
32578
|
-
markings: props.markings,
|
|
32579
|
-
tickStep: tickStep,
|
|
32580
|
-
gridStep: props.gridStep,
|
|
32581
|
-
showTooltips: !!props.showTooltips,
|
|
32582
|
-
graphDimensionsInPixels: props.box,
|
|
32583
|
-
width,
|
|
32584
|
-
height,
|
|
32585
|
-
labels
|
|
32586
|
-
}
|
|
32587
|
-
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32588
|
-
className: "mafs-graph",
|
|
32589
|
-
style: {
|
|
32590
|
-
width,
|
|
32591
|
-
height,
|
|
32592
|
-
position: "relative",
|
|
32593
|
-
padding: "25px 25px 0 0",
|
|
32594
|
-
boxSizing: "content-box",
|
|
32595
|
-
marginLeft: "20px",
|
|
32596
|
-
marginBottom: "20px"
|
|
32597
|
-
}
|
|
32598
|
-
}, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
|
|
32599
|
-
box: props.box,
|
|
32600
|
-
backgroundImage: props.backgroundImage
|
|
32601
|
-
}), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
32602
|
-
style: {
|
|
32603
|
-
position: "absolute",
|
|
32604
|
-
bottom: 0,
|
|
32605
|
-
left: 0
|
|
32606
|
-
}
|
|
32607
|
-
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
32608
|
-
preserveAspectRatio: false,
|
|
32609
|
-
viewBox: {
|
|
32610
|
-
x: state.range[0],
|
|
32611
|
-
y: state.range[1],
|
|
32612
|
-
padding: 0
|
|
32613
|
-
},
|
|
32614
|
-
pan: false,
|
|
32615
|
-
zoom: false,
|
|
32616
|
-
width: width,
|
|
32617
|
-
height: height
|
|
32618
|
-
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
32619
|
-
tickStep: props.step,
|
|
32620
|
-
gridStep: props.gridStep,
|
|
32621
|
-
range: state.range,
|
|
32622
|
-
containerSizeClass: props.containerSizeClass,
|
|
32623
|
-
markings: props.markings
|
|
32624
|
-
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
32625
|
-
lockedFigures: props.lockedFigures,
|
|
32626
|
-
range: state.range
|
|
32627
|
-
}), "/* Protractor */", props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32628
|
-
state,
|
|
32629
|
-
dispatch
|
|
32630
|
-
})))));
|
|
32631
|
-
};
|
|
32632
33111
|
|
|
32633
33112
|
const {
|
|
32634
33113
|
DeprecationMixin
|
|
@@ -32677,7 +33156,7 @@ const _isClickToAddPoints = props => {
|
|
|
32677
33156
|
return props.graph.type === "point" && props.graph.numPoints === UNLIMITED || props.graph.type === "polygon" && props.graph.numSides === UNLIMITED;
|
|
32678
33157
|
};
|
|
32679
33158
|
const makeInvalidTypeError = (functionName, graphType) => {
|
|
32680
|
-
return new PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, Errors.NotAllowed, {
|
|
33159
|
+
return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`, perseusCore.Errors.NotAllowed, {
|
|
32681
33160
|
metadata: {
|
|
32682
33161
|
graphType
|
|
32683
33162
|
}
|
|
@@ -32776,7 +33255,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
32776
33255
|
// This function should only be called when this.isClickToAddPoints()
|
|
32777
33256
|
// is true
|
|
32778
33257
|
if (!this.isClickToAddPoints()) {
|
|
32779
|
-
throw new PerseusError("handleAddPointsClick should not be registered" + "when isClickToAddPoints() is false", Errors.NotAllowed);
|
|
33258
|
+
throw new perseusCore.PerseusError("handleAddPointsClick should not be registered" + "when isClickToAddPoints() is false", perseusCore.Errors.NotAllowed);
|
|
32780
33259
|
}
|
|
32781
33260
|
if (!this.isCoordInTrash(coord)) {
|
|
32782
33261
|
let point;
|
|
@@ -33492,7 +33971,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
33492
33971
|
// Solve for side by using the law of sines
|
|
33493
33972
|
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
33494
33973
|
const outerAngle = GraphUtils.findAngle(coords[rel(1)], coords[rel(-1)]);
|
|
33495
|
-
const offset = polar(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
33974
|
+
const offset = polar$1(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
33496
33975
|
return this.graphie?.addPoints(coords[rel(-1)], offset);
|
|
33497
33976
|
}
|
|
33498
33977
|
// @ts-expect-error - TS2339 - Property 'snapTo' does not exist on type 'PerseusGraphType'.
|
|
@@ -33516,7 +33995,7 @@ class LegacyInteractiveGraph extends React__namespace.Component {
|
|
|
33516
33995
|
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
33517
33996
|
const outerAngle = GraphUtils.findAngle(coords[rel(1)], coords[rel(-1)]);
|
|
33518
33997
|
const onLeft = sign(ccw(coords[rel(-1)], coords[rel(1)], coords[i])) === 1;
|
|
33519
|
-
const offset = polar(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
|
|
33998
|
+
const offset = polar$1(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
|
|
33520
33999
|
return this.graphie?.addPoints(coords[rel(-1)], offset);
|
|
33521
34000
|
}
|
|
33522
34001
|
// Snap to grid (already done)
|
|
@@ -33914,7 +34393,7 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
33914
34393
|
if (this.legacyGraphRef.current) {
|
|
33915
34394
|
return this.legacyGraphRef.current.getUserInput();
|
|
33916
34395
|
}
|
|
33917
|
-
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
34396
|
+
throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered", perseusCore.Errors.NotAllowed);
|
|
33918
34397
|
};
|
|
33919
34398
|
simpleValidate(rubric) {
|
|
33920
34399
|
return InteractiveGraph.validate(this.getUserInput?.(), rubric, this);
|
|
@@ -34123,11 +34602,9 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
34123
34602
|
const radius = magnitude(vector(...coords));
|
|
34124
34603
|
|
|
34125
34604
|
// Adjust the lower point by angleOffsetDeg degrees
|
|
34126
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly Coord[]' only permits reading.
|
|
34127
34605
|
coords[0] = [coords[1][0] + radius * Math.cos(offset), coords[1][1] + radius * Math.sin(offset)];
|
|
34128
34606
|
// Position the upper point angle radians from the
|
|
34129
34607
|
// lower point
|
|
34130
|
-
// @ts-expect-error - TS2542 - Index signature in type 'readonly Coord[]' only permits reading.
|
|
34131
34608
|
coords[2] = [coords[1][0] + radius * Math.cos(angle + offset), coords[1][1] + radius * Math.sin(angle + offset)];
|
|
34132
34609
|
return coords;
|
|
34133
34610
|
}
|
|
@@ -39642,7 +40119,7 @@ class Card extends React__namespace.Component {
|
|
|
39642
40119
|
// Event handlers should be unbound before component unmounting, but
|
|
39643
40120
|
// just in case...
|
|
39644
40121
|
if (this.mouseMoveUpBound) {
|
|
39645
|
-
Log.error("Removing an element with bound event handlers.", Errors.Internal);
|
|
40122
|
+
Log.error("Removing an element with bound event handlers.", perseusCore.Errors.Internal);
|
|
39646
40123
|
this.unbindMouseMoveUp();
|
|
39647
40124
|
Util.resetTouchHandlers();
|
|
39648
40125
|
}
|
|
@@ -40463,7 +40940,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
|
|
|
40463
40940
|
} = serializedHighlight.range;
|
|
40464
40941
|
const firstWord = wordRanges[firstWordIndex];
|
|
40465
40942
|
if (!firstWord) {
|
|
40466
|
-
throw new PerseusError(`first word index ${firstWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
|
|
40943
|
+
throw new perseusCore.PerseusError(`first word index ${firstWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, perseusCore.Errors.InvalidInput, {
|
|
40467
40944
|
metadata: {
|
|
40468
40945
|
firstWord,
|
|
40469
40946
|
wordRanges: JSON.stringify(wordRanges)
|
|
@@ -40472,7 +40949,7 @@ function deserializeHighlight(serializedHighlight, wordRanges) {
|
|
|
40472
40949
|
}
|
|
40473
40950
|
const lastWord = wordRanges[lastWordIndex];
|
|
40474
40951
|
if (!lastWord) {
|
|
40475
|
-
throw new PerseusError(`last word index ${lastWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, Errors.InvalidInput, {
|
|
40952
|
+
throw new perseusCore.PerseusError(`last word index ${lastWord} is out of bounds: ` + `must be 0–${wordRanges.length - 1} inclusive`, perseusCore.Errors.InvalidInput, {
|
|
40476
40953
|
metadata: {
|
|
40477
40954
|
lastWord,
|
|
40478
40955
|
wordRanges: JSON.stringify(wordRanges)
|
|
@@ -41225,7 +41702,7 @@ class WordIndexer extends React__namespace.PureComponent {
|
|
|
41225
41702
|
_getWordRanges() {
|
|
41226
41703
|
const container = this._container;
|
|
41227
41704
|
if (!container) {
|
|
41228
|
-
throw new PerseusError("invariant violation: `this._container` is not defined, but " + "this method is only called after mount/update", Errors.NotAllowed);
|
|
41705
|
+
throw new perseusCore.PerseusError("invariant violation: `this._container` is not defined, but " + "this method is only called after mount/update", perseusCore.Errors.NotAllowed);
|
|
41229
41706
|
}
|
|
41230
41707
|
|
|
41231
41708
|
// Create a TreeWalker that visits text nodes and element nodes.
|
|
@@ -41691,6 +42168,7 @@ const rules = {
|
|
|
41691
42168
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
41692
42169
|
style: SQUARE_LABEL_STYLE
|
|
41693
42170
|
}, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
42171
|
+
key: "alt-text",
|
|
41694
42172
|
id: "questionMarker",
|
|
41695
42173
|
number: node.content
|
|
41696
42174
|
}), node.space ? "\u00A0" : null];
|
|
@@ -41715,6 +42193,7 @@ const rules = {
|
|
|
41715
42193
|
}, /*#__PURE__*/React__namespace.createElement("span", {
|
|
41716
42194
|
style: CIRCLE_LABEL_STYLE
|
|
41717
42195
|
}, node.content)), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
42196
|
+
key: "alt-text",
|
|
41718
42197
|
id: "circleMarker",
|
|
41719
42198
|
number: node.content
|
|
41720
42199
|
}), node.space ? "\u00A0" : null];
|
|
@@ -41738,6 +42217,7 @@ const rules = {
|
|
|
41738
42217
|
className: "perseus-passage-bracket-label",
|
|
41739
42218
|
"aria-hidden": "true"
|
|
41740
42219
|
}, "[", node.content, "]"), /*#__PURE__*/React__namespace.createElement(AltText, {
|
|
42220
|
+
key: "alt-text",
|
|
41741
42221
|
id: "sentenceMarker",
|
|
41742
42222
|
number: node.content
|
|
41743
42223
|
}), node.space ? "\u00A0" : null];
|
|
@@ -44747,7 +45227,7 @@ const init = function (options) {
|
|
|
44747
45227
|
|
|
44748
45228
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
44749
45229
|
const libName = "@khanacademy/perseus";
|
|
44750
|
-
const libVersion = "
|
|
45230
|
+
const libVersion = "25.0.0";
|
|
44751
45231
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
44752
45232
|
|
|
44753
45233
|
const apiVersion = {
|
|
@@ -46123,9 +46603,9 @@ tree, shape, path, mappers
|
|
|
46123
46603
|
// @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
|
|
46124
46604
|
const array = tree;
|
|
46125
46605
|
if (!Array.isArray(array)) {
|
|
46126
|
-
throw new PerseusError(`Invalid object of type "${typeof array}" found at path ` +
|
|
46606
|
+
throw new perseusCore.PerseusError(`Invalid object of type "${typeof array}" found at path ` +
|
|
46127
46607
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46128
|
-
`${["<root>"].concat(path).join(".")}. Expected array.`, Errors.Internal);
|
|
46608
|
+
`${["<root>"].concat(path).join(".")}. Expected array.`, perseusCore.Errors.Internal);
|
|
46129
46609
|
}
|
|
46130
46610
|
const elementShape = shape.elementShape;
|
|
46131
46611
|
// @ts-expect-error - TS2315 - Type 'ArrayNode' is not generic.
|
|
@@ -46135,30 +46615,30 @@ tree, shape, path, mappers
|
|
|
46135
46615
|
if (shape.type === "object") {
|
|
46136
46616
|
const object = tree;
|
|
46137
46617
|
if (object && typeof object !== "object") {
|
|
46138
|
-
throw new PerseusError(`Invalid object of type "${typeof object}" found at ` +
|
|
46618
|
+
throw new perseusCore.PerseusError(`Invalid object of type "${typeof object}" found at ` +
|
|
46139
46619
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46140
|
-
`path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, Errors.InvalidInput);
|
|
46620
|
+
`path ${["<root>"].concat(path).join(".")}. Expected ` + `"object" type.`, perseusCore.Errors.InvalidInput);
|
|
46141
46621
|
}
|
|
46142
46622
|
const valueShapes = shape.shape;
|
|
46143
46623
|
if (!valueShapes) {
|
|
46144
|
-
throw new PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
|
|
46624
|
+
throw new perseusCore.PerseusError(`Unexpected shape ${JSON.stringify(shape)} at path ` +
|
|
46145
46625
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46146
|
-
`${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
|
|
46626
|
+
`${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
|
|
46147
46627
|
}
|
|
46148
46628
|
const newObject = {};
|
|
46149
46629
|
Object.keys(valueShapes).forEach(key => {
|
|
46150
46630
|
if (!(key in object)) {
|
|
46151
|
-
throw new PerseusError(`Key "${key}" is missing from shape at path ` +
|
|
46631
|
+
throw new perseusCore.PerseusError(`Key "${key}" is missing from shape at path ` +
|
|
46152
46632
|
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
46153
|
-
`${["<root>"].concat(path).join(".")}.`, Errors.InvalidInput);
|
|
46633
|
+
`${["<root>"].concat(path).join(".")}.`, perseusCore.Errors.InvalidInput);
|
|
46154
46634
|
}
|
|
46155
46635
|
newObject[key] = mapTree(object[key], valueShapes[key], path.concat(key), mappers);
|
|
46156
46636
|
});
|
|
46157
46637
|
return newObject;
|
|
46158
46638
|
}
|
|
46159
|
-
throw new PerseusError(
|
|
46639
|
+
throw new perseusCore.PerseusError(
|
|
46160
46640
|
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
46161
|
-
`unexpected shape type ${shape.type}`, Errors.InvalidInput);
|
|
46641
|
+
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
46162
46642
|
}
|
|
46163
46643
|
|
|
46164
46644
|
/**
|
|
@@ -46210,9 +46690,9 @@ function buildEmptyItemTreeForShape(shape) {
|
|
|
46210
46690
|
});
|
|
46211
46691
|
return object;
|
|
46212
46692
|
}
|
|
46213
|
-
throw new PerseusError(
|
|
46693
|
+
throw new perseusCore.PerseusError(
|
|
46214
46694
|
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
46215
|
-
`unexpected shape type ${shape.type}`, Errors.InvalidInput);
|
|
46695
|
+
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
46216
46696
|
}
|
|
46217
46697
|
|
|
46218
46698
|
/**
|
|
@@ -46287,7 +46767,7 @@ function inferItemTreeShape(node) {
|
|
|
46287
46767
|
});
|
|
46288
46768
|
return shapes.shape(valueShapes);
|
|
46289
46769
|
}
|
|
46290
|
-
throw new PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, Errors.InvalidInput);
|
|
46770
|
+
throw new perseusCore.PerseusError(`unexpected multi-item node ${JSON.stringify(node)}`, perseusCore.Errors.InvalidInput);
|
|
46291
46771
|
}
|
|
46292
46772
|
|
|
46293
46773
|
/**
|
|
@@ -46365,7 +46845,7 @@ class MultiRenderer extends React__namespace.Component {
|
|
|
46365
46845
|
renderError: null
|
|
46366
46846
|
};
|
|
46367
46847
|
} catch (e) {
|
|
46368
|
-
Log.error("Error building tree state", Errors.Internal, {
|
|
46848
|
+
Log.error("Error building tree state", perseusCore.Errors.Internal, {
|
|
46369
46849
|
cause: e
|
|
46370
46850
|
});
|
|
46371
46851
|
return {
|
|
@@ -46729,9 +47209,9 @@ function buildTreePropTypeForShape(shape) {
|
|
|
46729
47209
|
});
|
|
46730
47210
|
return PropTypes__default["default"].shape(propTypeShape);
|
|
46731
47211
|
}
|
|
46732
|
-
throw new PerseusError(
|
|
47212
|
+
throw new perseusCore.PerseusError(
|
|
46733
47213
|
// @ts-expect-error - TS2339 - Property 'type' does not exist on type 'never'.
|
|
46734
|
-
`unexpected shape type ${shape.type}`, Errors.InvalidInput);
|
|
47214
|
+
`unexpected shape type ${shape.type}`, perseusCore.Errors.InvalidInput);
|
|
46735
47215
|
}
|
|
46736
47216
|
|
|
46737
47217
|
/**
|
|
@@ -46854,7 +47334,7 @@ const isRendererContentRenderableBy = function (rendererOptions, rendererContent
|
|
|
46854
47334
|
};
|
|
46855
47335
|
const isItemRenderableByVersion = function (itemData, rendererContentVersion) {
|
|
46856
47336
|
if (itemData == null || rendererContentVersion == null) {
|
|
46857
|
-
throw new PerseusError("missing parameter to Perseus.isRenderable.item", Errors.InvalidInput);
|
|
47337
|
+
throw new perseusCore.PerseusError("missing parameter to Perseus.isRenderable.item", perseusCore.Errors.InvalidInput);
|
|
46858
47338
|
}
|
|
46859
47339
|
if (itemData._multi) {
|
|
46860
47340
|
const shape = inferItemShape$1(itemData);
|
|
@@ -47775,7 +48255,6 @@ exports.DashPicker = DashPicker;
|
|
|
47775
48255
|
exports.Dependencies = dependencies;
|
|
47776
48256
|
exports.EditorJsonify = EditorJsonify;
|
|
47777
48257
|
exports.ElementContainer = ElementContainer;
|
|
47778
|
-
exports.Errors = Errors;
|
|
47779
48258
|
exports.Expression = Expression;
|
|
47780
48259
|
exports.GrapherUtil = util;
|
|
47781
48260
|
exports.GrapherWidget = Grapher$1;
|
|
@@ -47792,7 +48271,6 @@ exports.Log = Log;
|
|
|
47792
48271
|
exports.MatrixWidget = Matrix$1;
|
|
47793
48272
|
exports.MultiItems = MultiItems;
|
|
47794
48273
|
exports.NumericInput = NumericInput$1;
|
|
47795
|
-
exports.PerseusError = PerseusError;
|
|
47796
48274
|
exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
|
|
47797
48275
|
exports.PerseusI18nContext = PerseusI18nContext;
|
|
47798
48276
|
exports.PerseusI18nContextProvider = PerseusI18nContextProvider;
|