@khanacademy/perseus 23.1.0 → 23.4.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 +8 -0
- package/dist/es/index.js +578 -320
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +8 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +593 -330
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +0 -1
- package/dist/perseus-types.d.ts +17 -9
- package/dist/server-item-renderer.d.ts +0 -1
- package/dist/types.d.ts +1 -1
- package/dist/util/geometry.d.ts +1 -0
- package/dist/widgets/expression.d.ts +0 -6
- package/dist/widgets/interactive-graphs/graphs/components/angle.d.ts +2 -1
- package/dist/widgets/interactive-graphs/graphs/components/css-cursor.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point-view.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +3 -0
- package/dist/widgets/interactive-graphs/graphs/index.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/linear-system.d.ts +5 -0
- package/dist/widgets/interactive-graphs/graphs/linear.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graphs/quadratic.d.ts +1 -2
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +6 -3
- package/dist/widgets/interactive-graphs/locked-ellipse.d.ts +4 -0
- package/dist/widgets/interactive-graphs/locked-vector.d.ts +4 -0
- package/dist/widgets/interactive-graphs/reducer/initialize-graph-state.d.ts +9 -0
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-state.d.ts +2 -9
- package/dist/widgets/interactive-graphs/types.d.ts +9 -9
- package/dist/widgets/label-image.d.ts +0 -2
- package/package.json +3 -3
- package/dist/widgets/interactive-graphs/locked-circle.d.ts +0 -4
package/dist/es/index.js
CHANGED
|
@@ -29,7 +29,7 @@ import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-block
|
|
|
29
29
|
import caretDown from '@phosphor-icons/core/regular/caret-down.svg';
|
|
30
30
|
import caretUp from '@phosphor-icons/core/regular/caret-up.svg';
|
|
31
31
|
import debounce$2 from 'lodash.debounce';
|
|
32
|
-
import { vec,
|
|
32
|
+
import { vec, Ellipse, Line as Line$4, Point as Point$2, useMovable, Text as Text$1, Polygon, Plot as Plot$3, Coordinates, Mafs } from 'mafs';
|
|
33
33
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
34
34
|
import { Body, LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
35
35
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
@@ -3202,7 +3202,7 @@ const DeprecationMixin$1 = {
|
|
|
3202
3202
|
/**
|
|
3203
3203
|
* Approximate equality on numbers and primitives.
|
|
3204
3204
|
*/
|
|
3205
|
-
function eq$
|
|
3205
|
+
function eq$3(x, y) {
|
|
3206
3206
|
if (typeof x === "number" && typeof y === "number") {
|
|
3207
3207
|
return Math.abs(x - y) < 1e-9;
|
|
3208
3208
|
}
|
|
@@ -3229,7 +3229,7 @@ function deepEq$5(x, y) {
|
|
|
3229
3229
|
return false;
|
|
3230
3230
|
}
|
|
3231
3231
|
if (typeof x === "function" && typeof y === "function") {
|
|
3232
|
-
return eq$
|
|
3232
|
+
return eq$3(x, y);
|
|
3233
3233
|
}
|
|
3234
3234
|
if (typeof x === "function" || typeof y === "function") {
|
|
3235
3235
|
return false;
|
|
@@ -3246,7 +3246,7 @@ function deepEq$5(x, y) {
|
|
|
3246
3246
|
if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
|
|
3247
3247
|
return false;
|
|
3248
3248
|
}
|
|
3249
|
-
return eq$
|
|
3249
|
+
return eq$3(x, y);
|
|
3250
3250
|
}
|
|
3251
3251
|
|
|
3252
3252
|
/**
|
|
@@ -3547,7 +3547,7 @@ const Util = {
|
|
|
3547
3547
|
tickStepFromNumTicks,
|
|
3548
3548
|
constrainedTickStepsFromTickSteps,
|
|
3549
3549
|
DeprecationMixin: DeprecationMixin$1,
|
|
3550
|
-
eq: eq$
|
|
3550
|
+
eq: eq$3,
|
|
3551
3551
|
deepEq: deepEq$5,
|
|
3552
3552
|
parseQueryString,
|
|
3553
3553
|
updateQueryString: updateQueryString$2,
|
|
@@ -10784,7 +10784,7 @@ class WrappedLine extends WrappedDrawing {
|
|
|
10784
10784
|
* A collection of geomtry-related utility functions
|
|
10785
10785
|
*/
|
|
10786
10786
|
const {
|
|
10787
|
-
eq: eq$
|
|
10787
|
+
eq: eq$2,
|
|
10788
10788
|
deepEq: deepEq$4
|
|
10789
10789
|
} = Util;
|
|
10790
10790
|
|
|
@@ -10792,17 +10792,21 @@ const {
|
|
|
10792
10792
|
|
|
10793
10793
|
// a, b, c
|
|
10794
10794
|
|
|
10795
|
+
// Given a number, return whether it is positive (1), negative (-1), or zero (0)
|
|
10795
10796
|
function sign(val) {
|
|
10796
|
-
if (eq$
|
|
10797
|
+
if (eq$2(val, 0)) {
|
|
10797
10798
|
return 0;
|
|
10798
10799
|
}
|
|
10799
10800
|
return val > 0 ? 1 : -1;
|
|
10800
10801
|
}
|
|
10802
|
+
|
|
10803
|
+
// Determine whether three points are collinear (0), for a clockwise turn (negative),
|
|
10804
|
+
// or counterclockwise turn (positive)
|
|
10801
10805
|
function ccw(a, b, c) {
|
|
10802
10806
|
return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
|
|
10803
10807
|
}
|
|
10804
10808
|
function collinear(a, b, c) {
|
|
10805
|
-
return eq$
|
|
10809
|
+
return eq$2(ccw(a, b, c), 0);
|
|
10806
10810
|
}
|
|
10807
10811
|
|
|
10808
10812
|
// Given rect bounding points A and B, whether point C is inside the rect
|
|
@@ -10827,6 +10831,33 @@ function intersects(ab, cd) {
|
|
|
10827
10831
|
}
|
|
10828
10832
|
return false;
|
|
10829
10833
|
}
|
|
10834
|
+
|
|
10835
|
+
// Whether any two sides of a polygon intersect each other
|
|
10836
|
+
function polygonSidesIntersect(vertices) {
|
|
10837
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
10838
|
+
for (let k = i + 1; k < vertices.length; k++) {
|
|
10839
|
+
// If any two vertices are the same point, sides overlap
|
|
10840
|
+
if (point.equal(vertices[i], vertices[k])) {
|
|
10841
|
+
return true;
|
|
10842
|
+
}
|
|
10843
|
+
|
|
10844
|
+
// Find the other end of the sides starting at vertices i and k
|
|
10845
|
+
const iNext = (i + 1) % vertices.length;
|
|
10846
|
+
const kNext = (k + 1) % vertices.length;
|
|
10847
|
+
|
|
10848
|
+
// Adjacent sides always intersect (at the vertex); skip those
|
|
10849
|
+
if (iNext === k || kNext === i) {
|
|
10850
|
+
continue;
|
|
10851
|
+
}
|
|
10852
|
+
const side1 = [vertices[i], vertices[iNext]];
|
|
10853
|
+
const side2 = [vertices[k], vertices[kNext]];
|
|
10854
|
+
if (intersects(side1, side2)) {
|
|
10855
|
+
return true;
|
|
10856
|
+
}
|
|
10857
|
+
}
|
|
10858
|
+
}
|
|
10859
|
+
return false;
|
|
10860
|
+
}
|
|
10830
10861
|
function vector(a, b) {
|
|
10831
10862
|
return _.map(_.zip(a, b), function (pair) {
|
|
10832
10863
|
return pair[0] - pair[1];
|
|
@@ -10920,7 +10951,7 @@ function similar(coords1, coords2, tolerance) {
|
|
|
10920
10951
|
return pair[0] / pair[1];
|
|
10921
10952
|
});
|
|
10922
10953
|
const same = _.all(factors, function (factor) {
|
|
10923
|
-
return eq$
|
|
10954
|
+
return eq$2(factors[0], factor);
|
|
10924
10955
|
});
|
|
10925
10956
|
const congruentEnough = _.all(sidePairs, function (pair) {
|
|
10926
10957
|
return number.equal(pair[0], pair[1], tolerance);
|
|
@@ -10972,7 +11003,7 @@ function rotate(array, n) {
|
|
|
10972
11003
|
return array.slice(n).concat(array.slice(0, n));
|
|
10973
11004
|
}
|
|
10974
11005
|
function getLineEquation(first, second) {
|
|
10975
|
-
if (eq$
|
|
11006
|
+
if (eq$2(first[0], second[0])) {
|
|
10976
11007
|
return "x = " + first[0].toFixed(3);
|
|
10977
11008
|
}
|
|
10978
11009
|
const m = (second[1] - first[1]) / (second[0] - first[0]);
|
|
@@ -28631,25 +28662,27 @@ const lockedFigureColors = {
|
|
|
28631
28662
|
pink: "#B25071",
|
|
28632
28663
|
red: "#D92916"
|
|
28633
28664
|
};
|
|
28665
|
+
const lockedEllipseFillStyles = {
|
|
28666
|
+
none: 0,
|
|
28667
|
+
solid: 1,
|
|
28668
|
+
translucent: 0.4
|
|
28669
|
+
};
|
|
28634
28670
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28635
28671
|
|
|
28636
|
-
const
|
|
28672
|
+
const LockedEllipse = props => {
|
|
28637
28673
|
const {
|
|
28638
28674
|
center,
|
|
28639
28675
|
radius,
|
|
28676
|
+
angle,
|
|
28640
28677
|
color,
|
|
28641
28678
|
fillStyle,
|
|
28642
28679
|
strokeStyle
|
|
28643
28680
|
} = props;
|
|
28644
|
-
|
|
28645
|
-
none: 0,
|
|
28646
|
-
solid: 1,
|
|
28647
|
-
translucent: 0.4
|
|
28648
|
-
};
|
|
28649
|
-
return /*#__PURE__*/React.createElement(Circle$1, {
|
|
28681
|
+
return /*#__PURE__*/React.createElement(Ellipse, {
|
|
28650
28682
|
center: center,
|
|
28651
28683
|
radius: radius,
|
|
28652
|
-
|
|
28684
|
+
angle: angle,
|
|
28685
|
+
fillOpacity: lockedEllipseFillStyles[fillStyle],
|
|
28653
28686
|
strokeStyle: strokeStyle,
|
|
28654
28687
|
color: lockedFigureColors[color]
|
|
28655
28688
|
});
|
|
@@ -28909,6 +28942,21 @@ const LockedPoint = props => {
|
|
|
28909
28942
|
});
|
|
28910
28943
|
};
|
|
28911
28944
|
|
|
28945
|
+
const LockedVector = props => {
|
|
28946
|
+
const {
|
|
28947
|
+
color,
|
|
28948
|
+
points
|
|
28949
|
+
} = props;
|
|
28950
|
+
const [tail, tip] = points;
|
|
28951
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28952
|
+
className: "locked-vector"
|
|
28953
|
+
}, /*#__PURE__*/React.createElement(Vector, {
|
|
28954
|
+
tail: tail,
|
|
28955
|
+
tip: tip,
|
|
28956
|
+
color: lockedFigureColors[color]
|
|
28957
|
+
}));
|
|
28958
|
+
};
|
|
28959
|
+
|
|
28912
28960
|
const GraphLockedLayer = props => {
|
|
28913
28961
|
const {
|
|
28914
28962
|
lockedFigures
|
|
@@ -28924,9 +28972,13 @@ const GraphLockedLayer = props => {
|
|
|
28924
28972
|
key: `line-${index}`,
|
|
28925
28973
|
range: props.range
|
|
28926
28974
|
}, figure));
|
|
28927
|
-
case "
|
|
28928
|
-
return /*#__PURE__*/React.createElement(
|
|
28929
|
-
key: `
|
|
28975
|
+
case "ellipse":
|
|
28976
|
+
return /*#__PURE__*/React.createElement(LockedEllipse, _extends({
|
|
28977
|
+
key: `ellipse-${index}`
|
|
28978
|
+
}, figure));
|
|
28979
|
+
case "vector":
|
|
28980
|
+
return /*#__PURE__*/React.createElement(LockedVector, _extends({
|
|
28981
|
+
key: `vector-${index}`
|
|
28930
28982
|
}, figure));
|
|
28931
28983
|
default:
|
|
28932
28984
|
/**
|
|
@@ -29056,7 +29108,8 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
29056
29108
|
point,
|
|
29057
29109
|
color: color$1 = color.blue,
|
|
29058
29110
|
dragging,
|
|
29059
|
-
focusBehavior
|
|
29111
|
+
focusBehavior,
|
|
29112
|
+
cursor
|
|
29060
29113
|
} = props;
|
|
29061
29114
|
|
|
29062
29115
|
// WB Tooltip requires a color name for the background color.
|
|
@@ -29088,7 +29141,8 @@ const MovablePointView = /*#__PURE__*/forwardRef((props, hitboxRef) => {
|
|
|
29088
29141
|
ref: hitboxRef,
|
|
29089
29142
|
className: pointClasses,
|
|
29090
29143
|
style: {
|
|
29091
|
-
"--movable-point-color": color$1
|
|
29144
|
+
"--movable-point-color": color$1,
|
|
29145
|
+
cursor
|
|
29092
29146
|
},
|
|
29093
29147
|
"data-testid": "movable-point",
|
|
29094
29148
|
tabIndex: tabIndex(focusBehavior)
|
|
@@ -29200,6 +29254,7 @@ function useControlPoint(point, color, onMovePoint) {
|
|
|
29200
29254
|
});
|
|
29201
29255
|
const focusableHandle = /*#__PURE__*/React.createElement("g", {
|
|
29202
29256
|
"data-testid": "movable-point__focusable-handle",
|
|
29257
|
+
className: "movable-point__focusable-handle",
|
|
29203
29258
|
tabIndex: 0,
|
|
29204
29259
|
ref: keyboardHandleRef,
|
|
29205
29260
|
onFocus: () => setFocused(true),
|
|
@@ -29336,14 +29391,39 @@ const SegmentGraph = props => {
|
|
|
29336
29391
|
})));
|
|
29337
29392
|
};
|
|
29338
29393
|
|
|
29339
|
-
const LinearGraph = props => {
|
|
29394
|
+
const LinearGraph = (props, key) => {
|
|
29395
|
+
const {
|
|
29396
|
+
dispatch
|
|
29397
|
+
} = props;
|
|
29398
|
+
const {
|
|
29399
|
+
coords: line
|
|
29400
|
+
} = props.graphState;
|
|
29401
|
+
|
|
29402
|
+
// Linear graphs only have one line
|
|
29403
|
+
// (LEMS-2050): Update the reducer so that we have a separate action for moving one line
|
|
29404
|
+
// and another action for moving multiple lines
|
|
29405
|
+
return /*#__PURE__*/React.createElement(MovableLine, {
|
|
29406
|
+
key: 0,
|
|
29407
|
+
points: line,
|
|
29408
|
+
onMoveLine: delta => {
|
|
29409
|
+
dispatch(moveLine(0, delta));
|
|
29410
|
+
},
|
|
29411
|
+
extend: {
|
|
29412
|
+
start: true,
|
|
29413
|
+
end: true
|
|
29414
|
+
},
|
|
29415
|
+
onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, 0)),
|
|
29416
|
+
color: "var(--movable-line-stroke-color)"
|
|
29417
|
+
});
|
|
29418
|
+
};
|
|
29419
|
+
|
|
29420
|
+
const LinearSystemGraph = props => {
|
|
29340
29421
|
const {
|
|
29341
29422
|
dispatch
|
|
29342
29423
|
} = props;
|
|
29343
29424
|
const {
|
|
29344
29425
|
coords: lines
|
|
29345
29426
|
} = props.graphState;
|
|
29346
|
-
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
29347
29427
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lines == null ? void 0 : lines.map((line, i) => /*#__PURE__*/React.createElement(MovableLine, {
|
|
29348
29428
|
key: i,
|
|
29349
29429
|
points: line,
|
|
@@ -29355,8 +29435,8 @@ const LinearGraph = props => {
|
|
|
29355
29435
|
end: true
|
|
29356
29436
|
},
|
|
29357
29437
|
onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, i)),
|
|
29358
|
-
color:
|
|
29359
|
-
})));
|
|
29438
|
+
color: "var(--movable-line-stroke-color)"
|
|
29439
|
+
})), ";");
|
|
29360
29440
|
};
|
|
29361
29441
|
|
|
29362
29442
|
const RayGraph = props => {
|
|
@@ -29364,14 +29444,14 @@ const RayGraph = props => {
|
|
|
29364
29444
|
dispatch
|
|
29365
29445
|
} = props;
|
|
29366
29446
|
const {
|
|
29367
|
-
coords:
|
|
29447
|
+
coords: line
|
|
29368
29448
|
} = props.graphState;
|
|
29369
29449
|
const handleMoveLine = delta => dispatch(moveLine(0, delta));
|
|
29370
29450
|
const handleMovePoint = (pointIndex, newPoint) => dispatch(moveControlPoint(pointIndex, newPoint, 0));
|
|
29371
|
-
|
|
29372
|
-
//
|
|
29373
|
-
, {
|
|
29374
|
-
points:
|
|
29451
|
+
|
|
29452
|
+
// Ray graphs only have one line
|
|
29453
|
+
return /*#__PURE__*/React.createElement(MovableLine, {
|
|
29454
|
+
points: line,
|
|
29375
29455
|
onMoveLine: handleMoveLine,
|
|
29376
29456
|
onMovePoint: handleMovePoint,
|
|
29377
29457
|
extend: {
|
|
@@ -29427,7 +29507,8 @@ const Angle = ({
|
|
|
29427
29507
|
endPoints,
|
|
29428
29508
|
range,
|
|
29429
29509
|
polygonLines,
|
|
29430
|
-
showAngles
|
|
29510
|
+
showAngles,
|
|
29511
|
+
snapTo
|
|
29431
29512
|
}) => {
|
|
29432
29513
|
const [centerX, centerY] = centerPoint;
|
|
29433
29514
|
const areClockwise = clockwise$1([centerPoint, ...endPoints]);
|
|
@@ -29465,7 +29546,9 @@ const Angle = ({
|
|
|
29465
29546
|
if (isOutside) {
|
|
29466
29547
|
angleInDegrees = 360 - angleInDegrees;
|
|
29467
29548
|
}
|
|
29468
|
-
|
|
29549
|
+
|
|
29550
|
+
// Only want to show whole numbers when in angles mode
|
|
29551
|
+
const angleLabelNumber = parseFloat(angleInDegrees.toFixed(snapTo === "angles" ? 0 : 1));
|
|
29469
29552
|
const angleLabel = Number.isInteger(angleLabelNumber) ? angleLabelNumber : "≈ " + angleLabelNumber;
|
|
29470
29553
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("filter", {
|
|
29471
29554
|
id: "background",
|
|
@@ -29550,15 +29633,18 @@ const StyledMovablePoint = props => {
|
|
|
29550
29633
|
const {
|
|
29551
29634
|
point,
|
|
29552
29635
|
onMove,
|
|
29553
|
-
|
|
29636
|
+
cursor,
|
|
29637
|
+
color: color$1 = color.blue,
|
|
29638
|
+
snapTo
|
|
29554
29639
|
} = props;
|
|
29640
|
+
const snapToValue = snapTo != null ? snapTo : "grid";
|
|
29555
29641
|
const {
|
|
29556
29642
|
dragging
|
|
29557
29643
|
} = useMovable({
|
|
29558
29644
|
gestureTarget: elementRef,
|
|
29559
29645
|
point,
|
|
29560
29646
|
onMove,
|
|
29561
|
-
constrain: p => snap(snapStep, p)
|
|
29647
|
+
constrain: p => ["angles", "sides"].includes(snapToValue) ? p : snap(snapStep, p)
|
|
29562
29648
|
});
|
|
29563
29649
|
return /*#__PURE__*/React.createElement(MovablePointView, {
|
|
29564
29650
|
ref: elementRef,
|
|
@@ -29568,7 +29654,8 @@ const StyledMovablePoint = props => {
|
|
|
29568
29654
|
focusBehavior: {
|
|
29569
29655
|
type: "uncontrolled",
|
|
29570
29656
|
tabIndex: 0
|
|
29571
|
-
}
|
|
29657
|
+
},
|
|
29658
|
+
cursor: cursor
|
|
29572
29659
|
});
|
|
29573
29660
|
};
|
|
29574
29661
|
|
|
@@ -29583,7 +29670,8 @@ const PolygonGraph = props => {
|
|
|
29583
29670
|
showAngles,
|
|
29584
29671
|
showSides,
|
|
29585
29672
|
range,
|
|
29586
|
-
snapStep
|
|
29673
|
+
snapStep,
|
|
29674
|
+
snapTo
|
|
29587
29675
|
} = props.graphState;
|
|
29588
29676
|
|
|
29589
29677
|
// TODO(benchristel): can the default set of points be removed here? I don't
|
|
@@ -29591,6 +29679,7 @@ const PolygonGraph = props => {
|
|
|
29591
29679
|
const points = coords != null ? coords : [[0, 0]];
|
|
29592
29680
|
const ref = React.useRef(null);
|
|
29593
29681
|
const dragReferencePoint = points[0];
|
|
29682
|
+
const snapToValue = snapTo != null ? snapTo : "grid";
|
|
29594
29683
|
const {
|
|
29595
29684
|
dragging
|
|
29596
29685
|
} = useMovable({
|
|
@@ -29600,7 +29689,7 @@ const PolygonGraph = props => {
|
|
|
29600
29689
|
const delta = vec.sub(newPoint, dragReferencePoint);
|
|
29601
29690
|
dispatch(moveAll(delta));
|
|
29602
29691
|
},
|
|
29603
|
-
constrain: p => snap(snapStep, p)
|
|
29692
|
+
constrain: p => ["angles", "sides"].includes(snapToValue) ? p : snap(snapStep, p)
|
|
29604
29693
|
});
|
|
29605
29694
|
const active = hovered || focused || dragging;
|
|
29606
29695
|
const lines = getLines(points);
|
|
@@ -29623,11 +29712,12 @@ const PolygonGraph = props => {
|
|
|
29623
29712
|
active: active,
|
|
29624
29713
|
range: range,
|
|
29625
29714
|
polygonLines: lines,
|
|
29626
|
-
showAngles: !!showAngles
|
|
29715
|
+
showAngles: !!showAngles,
|
|
29716
|
+
snapTo: snapToValue
|
|
29627
29717
|
});
|
|
29628
29718
|
}), showSides && lines.map(([start, end], i) => {
|
|
29629
29719
|
const [x, y] = vec.midpoint(start, end);
|
|
29630
|
-
const length = parseFloat(vec.dist(start, end).toFixed(1));
|
|
29720
|
+
const length = parseFloat(vec.dist(start, end).toFixed(snapTo === "sides" ? 0 : 1));
|
|
29631
29721
|
return /*#__PURE__*/React.createElement(TextLabel, {
|
|
29632
29722
|
key: "side-" + i,
|
|
29633
29723
|
x: x,
|
|
@@ -29651,131 +29741,12 @@ const PolygonGraph = props => {
|
|
|
29651
29741
|
}
|
|
29652
29742
|
}), points.map((point, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
29653
29743
|
key: "point-" + i,
|
|
29744
|
+
snapTo: snapTo,
|
|
29654
29745
|
point: point,
|
|
29655
29746
|
onMove: destination => dispatch(movePoint(i, destination))
|
|
29656
29747
|
})));
|
|
29657
29748
|
};
|
|
29658
29749
|
|
|
29659
|
-
function initializeGraphState(params) {
|
|
29660
|
-
const {
|
|
29661
|
-
graph,
|
|
29662
|
-
step,
|
|
29663
|
-
snapStep,
|
|
29664
|
-
range
|
|
29665
|
-
} = params;
|
|
29666
|
-
const shared = {
|
|
29667
|
-
hasBeenInteractedWith: false,
|
|
29668
|
-
range,
|
|
29669
|
-
snapStep
|
|
29670
|
-
};
|
|
29671
|
-
switch (graph.type) {
|
|
29672
|
-
case "segment":
|
|
29673
|
-
return _extends({}, shared, {
|
|
29674
|
-
type: "segment",
|
|
29675
|
-
coords: getDefaultSegments({
|
|
29676
|
-
graph,
|
|
29677
|
-
step,
|
|
29678
|
-
range
|
|
29679
|
-
})
|
|
29680
|
-
});
|
|
29681
|
-
case "linear":
|
|
29682
|
-
case "linear-system":
|
|
29683
|
-
case "ray":
|
|
29684
|
-
return _extends({}, shared, {
|
|
29685
|
-
type: graph.type,
|
|
29686
|
-
// Linear and ray graphs have a single tuple of points, while a
|
|
29687
|
-
// linear system has two tuples of points.
|
|
29688
|
-
coords: getLineCoords({
|
|
29689
|
-
graph,
|
|
29690
|
-
range,
|
|
29691
|
-
step
|
|
29692
|
-
})
|
|
29693
|
-
});
|
|
29694
|
-
case "polygon":
|
|
29695
|
-
return _extends({}, shared, {
|
|
29696
|
-
type: "polygon",
|
|
29697
|
-
showAngles: Boolean(graph.showAngles),
|
|
29698
|
-
showSides: Boolean(graph.showSides),
|
|
29699
|
-
coords: getPolygonCoords({
|
|
29700
|
-
graph,
|
|
29701
|
-
range,
|
|
29702
|
-
step
|
|
29703
|
-
})
|
|
29704
|
-
});
|
|
29705
|
-
case "point":
|
|
29706
|
-
return _extends({}, shared, {
|
|
29707
|
-
type: graph.type,
|
|
29708
|
-
coords: getDefaultPoints({
|
|
29709
|
-
graph,
|
|
29710
|
-
step,
|
|
29711
|
-
range
|
|
29712
|
-
})
|
|
29713
|
-
});
|
|
29714
|
-
case "circle":
|
|
29715
|
-
return _extends({}, shared, {
|
|
29716
|
-
type: graph.type,
|
|
29717
|
-
center: [0, 0],
|
|
29718
|
-
radiusPoint: [1, 0]
|
|
29719
|
-
});
|
|
29720
|
-
case "quadratic":
|
|
29721
|
-
return _extends({}, shared, {
|
|
29722
|
-
type: graph.type,
|
|
29723
|
-
coords: getQuadraticCoords(graph, range, step)
|
|
29724
|
-
});
|
|
29725
|
-
case "sinusoid":
|
|
29726
|
-
return _extends({}, shared, {
|
|
29727
|
-
type: graph.type,
|
|
29728
|
-
coords: getSinusoidCoords(graph, range, step)
|
|
29729
|
-
});
|
|
29730
|
-
case "angle":
|
|
29731
|
-
throw new Error("Mafs not yet implemented for graph type: " + graph.type);
|
|
29732
|
-
default:
|
|
29733
|
-
throw new UnreachableCaseError(graph);
|
|
29734
|
-
}
|
|
29735
|
-
}
|
|
29736
|
-
const getDefaultPoints = ({
|
|
29737
|
-
graph,
|
|
29738
|
-
range,
|
|
29739
|
-
step
|
|
29740
|
-
}) => {
|
|
29741
|
-
var _graph$coords;
|
|
29742
|
-
const numPoints = graph.numPoints || 1;
|
|
29743
|
-
let coords = (_graph$coords = graph.coords) == null ? void 0 : _graph$coords.slice();
|
|
29744
|
-
if (coords) {
|
|
29745
|
-
return coords;
|
|
29746
|
-
}
|
|
29747
|
-
switch (numPoints) {
|
|
29748
|
-
case 1:
|
|
29749
|
-
// Back in the day, one point's coords were in graph.coord
|
|
29750
|
-
coords = [graph.coord || [0, 0]];
|
|
29751
|
-
break;
|
|
29752
|
-
case 2:
|
|
29753
|
-
coords = [[-5, 0], [5, 0]];
|
|
29754
|
-
break;
|
|
29755
|
-
case 3:
|
|
29756
|
-
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
29757
|
-
break;
|
|
29758
|
-
case 4:
|
|
29759
|
-
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
29760
|
-
break;
|
|
29761
|
-
case 5:
|
|
29762
|
-
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
29763
|
-
break;
|
|
29764
|
-
case 6:
|
|
29765
|
-
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
29766
|
-
break;
|
|
29767
|
-
default:
|
|
29768
|
-
coords = [];
|
|
29769
|
-
break;
|
|
29770
|
-
}
|
|
29771
|
-
// Transform coords from their -10 to 10 space to 0 to 1
|
|
29772
|
-
// because of the old graph.coord, and also it's easier.
|
|
29773
|
-
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
29774
|
-
return normalizePoints(range, step, newCoords);
|
|
29775
|
-
};
|
|
29776
|
-
|
|
29777
|
-
// TS v4 doesn't narrow return types, while v5 does.
|
|
29778
|
-
// Instead of updating to v5, using generic type to relate input and output types.
|
|
29779
29750
|
function getGradableGraph(state, initialGraph) {
|
|
29780
29751
|
if (!state.hasBeenInteractedWith) {
|
|
29781
29752
|
return _extends({}, initialGraph);
|
|
@@ -29792,12 +29763,12 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29792
29763
|
}
|
|
29793
29764
|
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
29794
29765
|
return _extends({}, initialGraph, {
|
|
29795
|
-
coords: state.coords
|
|
29766
|
+
coords: state.coords
|
|
29796
29767
|
});
|
|
29797
29768
|
}
|
|
29798
29769
|
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
29799
29770
|
return _extends({}, initialGraph, {
|
|
29800
|
-
coords: state.coords
|
|
29771
|
+
coords: state.coords
|
|
29801
29772
|
});
|
|
29802
29773
|
}
|
|
29803
29774
|
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
@@ -29828,91 +29799,6 @@ function getGradableGraph(state, initialGraph) {
|
|
|
29828
29799
|
}
|
|
29829
29800
|
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
29830
29801
|
}
|
|
29831
|
-
const getDefaultSegments = ({
|
|
29832
|
-
graph,
|
|
29833
|
-
range,
|
|
29834
|
-
step
|
|
29835
|
-
}) => {
|
|
29836
|
-
const ys = n => {
|
|
29837
|
-
switch (n) {
|
|
29838
|
-
case 2:
|
|
29839
|
-
return [5, -5];
|
|
29840
|
-
case 3:
|
|
29841
|
-
return [5, 0, -5];
|
|
29842
|
-
case 4:
|
|
29843
|
-
return [6, 2, -2, -6];
|
|
29844
|
-
case 5:
|
|
29845
|
-
return [6, 3, 0, -3, -6];
|
|
29846
|
-
case 6:
|
|
29847
|
-
return [5, 3, 1, -1, -3, -5];
|
|
29848
|
-
default:
|
|
29849
|
-
return [5];
|
|
29850
|
-
}
|
|
29851
|
-
};
|
|
29852
|
-
const defaultRange = [[-10, 10], [-10, 10]];
|
|
29853
|
-
return ys(graph.numSegments).map(y => {
|
|
29854
|
-
let endpoints = [[-5, y], [5, y]];
|
|
29855
|
-
endpoints = normalizeCoords(endpoints, defaultRange);
|
|
29856
|
-
endpoints = normalizePoints(range, step, endpoints);
|
|
29857
|
-
return endpoints;
|
|
29858
|
-
});
|
|
29859
|
-
};
|
|
29860
|
-
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
29861
|
-
const getLineCoords = ({
|
|
29862
|
-
graph,
|
|
29863
|
-
range,
|
|
29864
|
-
step
|
|
29865
|
-
}) => {
|
|
29866
|
-
// Return two lines for a linear system, one for a ray or linear
|
|
29867
|
-
switch (graph.type) {
|
|
29868
|
-
case "linear-system":
|
|
29869
|
-
return defaultLinearCoords.map(points => normalizePoints(range, step, points));
|
|
29870
|
-
case "linear":
|
|
29871
|
-
case "ray":
|
|
29872
|
-
return [normalizePoints(range, step, defaultLinearCoords[0])];
|
|
29873
|
-
default:
|
|
29874
|
-
throw new UnreachableCaseError(graph);
|
|
29875
|
-
}
|
|
29876
|
-
};
|
|
29877
|
-
const getPolygonCoords = ({
|
|
29878
|
-
graph,
|
|
29879
|
-
range,
|
|
29880
|
-
step
|
|
29881
|
-
}) => {
|
|
29882
|
-
var _graph$coords2;
|
|
29883
|
-
let coords = (_graph$coords2 = graph.coords) == null ? void 0 : _graph$coords2.slice();
|
|
29884
|
-
if (coords) {
|
|
29885
|
-
return coords;
|
|
29886
|
-
}
|
|
29887
|
-
const n = graph.numSides || 3;
|
|
29888
|
-
if (n === "unlimited") {
|
|
29889
|
-
coords = [];
|
|
29890
|
-
} else {
|
|
29891
|
-
const angle = 2 * Math.PI / n;
|
|
29892
|
-
const offset = (1 / n - 1 / 2) * Math.PI;
|
|
29893
|
-
|
|
29894
|
-
// TODO(alex): Generalize this to more than just triangles so that
|
|
29895
|
-
// all polygons have whole number side lengths if snapping to sides
|
|
29896
|
-
const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
|
|
29897
|
-
|
|
29898
|
-
// Generate coords of a regular polygon with n sides
|
|
29899
|
-
coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
|
|
29900
|
-
}
|
|
29901
|
-
coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
29902
|
-
const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
|
|
29903
|
-
coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
|
|
29904
|
-
return coords;
|
|
29905
|
-
};
|
|
29906
|
-
const getSinusoidCoords = (graph, range, step) => {
|
|
29907
|
-
let coords = [[0.5, 0.5], [0.65, 0.6]];
|
|
29908
|
-
coords = normalizePoints(range, step, coords, true);
|
|
29909
|
-
return coords;
|
|
29910
|
-
};
|
|
29911
|
-
const getQuadraticCoords = (graph, range, step) => {
|
|
29912
|
-
let coords = [[0.25, 0.75], [0.5, 0.25], [0.75, 0.75]];
|
|
29913
|
-
coords = normalizePoints(range, step, coords, true);
|
|
29914
|
-
return coords;
|
|
29915
|
-
};
|
|
29916
29802
|
|
|
29917
29803
|
/**
|
|
29918
29804
|
* determine radius of a circle graph
|
|
@@ -29941,6 +29827,7 @@ function CircleGraph(props) {
|
|
|
29941
29827
|
onMove: newCenter => dispatch(moveCenter(newCenter))
|
|
29942
29828
|
}), /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
29943
29829
|
point: radiusPoint,
|
|
29830
|
+
cursor: "ew-resize",
|
|
29944
29831
|
onMove: newRadiusPoint => {
|
|
29945
29832
|
dispatch(moveRadiusPoint(newRadiusPoint));
|
|
29946
29833
|
}
|
|
@@ -30045,38 +29932,16 @@ function QuadraticGraph(props) {
|
|
|
30045
29932
|
|
|
30046
29933
|
// Calculate the y value based on the current x value
|
|
30047
29934
|
const y = x => (a * x + b) * x + c;
|
|
30048
|
-
const handleOnMove = (destination, elementId) => {
|
|
30049
|
-
// If the destination is invalid, we want do not want to move the point
|
|
30050
|
-
const validDestination = isValidDestination(destination, elementId, coords);
|
|
30051
|
-
if (validDestination === false) {
|
|
30052
|
-
return;
|
|
30053
|
-
}
|
|
30054
|
-
dispatch(movePoint(elementId, destination));
|
|
30055
|
-
};
|
|
30056
29935
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Plot$3.OfX, {
|
|
30057
29936
|
y: y,
|
|
30058
29937
|
color: color.blue
|
|
30059
29938
|
}), coords.map((coord, i) => /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
30060
29939
|
key: "point-" + i,
|
|
30061
29940
|
point: coord,
|
|
30062
|
-
onMove: destination =>
|
|
29941
|
+
onMove: destination => dispatch(movePoint(i, destination))
|
|
30063
29942
|
})));
|
|
30064
29943
|
}
|
|
30065
29944
|
|
|
30066
|
-
// Ensure that we are only snapping to coordinates that result in a valid quadratic equation
|
|
30067
|
-
const isValidDestination = (destination, elementId, coords) => {
|
|
30068
|
-
// Set up the new coords and check if the quadratic coefficients are valid
|
|
30069
|
-
const newCoords = [...coords];
|
|
30070
|
-
newCoords[elementId] = destination;
|
|
30071
|
-
const QuadraticCoefficients = getQuadraticCoefficients(newCoords);
|
|
30072
|
-
|
|
30073
|
-
// If the new destination results in an invalid quadratic equation, we don't want to move the point
|
|
30074
|
-
if (QuadraticCoefficients === undefined) {
|
|
30075
|
-
return false;
|
|
30076
|
-
}
|
|
30077
|
-
return true;
|
|
30078
|
-
};
|
|
30079
|
-
|
|
30080
29945
|
// Get the quadratic coefficients from the 3 control points
|
|
30081
29946
|
// These equations were originally set up in 2013 and may require some
|
|
30082
29947
|
// additional comments to help clarify the quadratic formula manipulations
|
|
@@ -31220,6 +31085,203 @@ const LegacyGrid = ({
|
|
|
31220
31085
|
return null;
|
|
31221
31086
|
};
|
|
31222
31087
|
|
|
31088
|
+
function initializeGraphState(params) {
|
|
31089
|
+
var _graph$snapTo;
|
|
31090
|
+
const {
|
|
31091
|
+
graph,
|
|
31092
|
+
step,
|
|
31093
|
+
snapStep,
|
|
31094
|
+
range
|
|
31095
|
+
} = params;
|
|
31096
|
+
const shared = {
|
|
31097
|
+
hasBeenInteractedWith: false,
|
|
31098
|
+
range,
|
|
31099
|
+
snapStep
|
|
31100
|
+
};
|
|
31101
|
+
switch (graph.type) {
|
|
31102
|
+
case "segment":
|
|
31103
|
+
return _extends({}, shared, {
|
|
31104
|
+
type: "segment",
|
|
31105
|
+
coords: getSegmentCoords(graph, range, step)
|
|
31106
|
+
});
|
|
31107
|
+
case "linear":
|
|
31108
|
+
return _extends({}, shared, {
|
|
31109
|
+
type: graph.type,
|
|
31110
|
+
coords: getLineCoords(graph, range, step)
|
|
31111
|
+
});
|
|
31112
|
+
case "ray":
|
|
31113
|
+
return _extends({}, shared, {
|
|
31114
|
+
type: graph.type,
|
|
31115
|
+
coords: getLineCoords(graph, range, step)
|
|
31116
|
+
});
|
|
31117
|
+
case "linear-system":
|
|
31118
|
+
return _extends({}, shared, {
|
|
31119
|
+
type: graph.type,
|
|
31120
|
+
coords: getLinearSystemCoords(graph, range, step)
|
|
31121
|
+
});
|
|
31122
|
+
case "polygon":
|
|
31123
|
+
return _extends({}, shared, {
|
|
31124
|
+
type: "polygon",
|
|
31125
|
+
showAngles: Boolean(graph.showAngles),
|
|
31126
|
+
showSides: Boolean(graph.showSides),
|
|
31127
|
+
coords: getPolygonCoords(graph, range, step),
|
|
31128
|
+
snapTo: (_graph$snapTo = graph.snapTo) != null ? _graph$snapTo : "grid"
|
|
31129
|
+
});
|
|
31130
|
+
case "point":
|
|
31131
|
+
return _extends({}, shared, {
|
|
31132
|
+
type: graph.type,
|
|
31133
|
+
coords: getPointCoords(graph, range, step)
|
|
31134
|
+
});
|
|
31135
|
+
case "circle":
|
|
31136
|
+
return _extends({}, shared, {
|
|
31137
|
+
type: graph.type
|
|
31138
|
+
}, getCircleCoords(graph));
|
|
31139
|
+
case "quadratic":
|
|
31140
|
+
return _extends({}, shared, {
|
|
31141
|
+
type: graph.type,
|
|
31142
|
+
coords: getQuadraticCoords(graph, range, step)
|
|
31143
|
+
});
|
|
31144
|
+
case "sinusoid":
|
|
31145
|
+
return _extends({}, shared, {
|
|
31146
|
+
type: graph.type,
|
|
31147
|
+
coords: getSinusoidCoords(graph, range, step)
|
|
31148
|
+
});
|
|
31149
|
+
case "angle":
|
|
31150
|
+
throw new Error("Mafs not yet implemented for graph type: " + graph.type);
|
|
31151
|
+
default:
|
|
31152
|
+
throw new UnreachableCaseError(graph);
|
|
31153
|
+
}
|
|
31154
|
+
}
|
|
31155
|
+
function getPointCoords(graph, range, step) {
|
|
31156
|
+
var _graph$coords;
|
|
31157
|
+
const numPoints = graph.numPoints || 1;
|
|
31158
|
+
let coords = (_graph$coords = graph.coords) == null ? void 0 : _graph$coords.slice();
|
|
31159
|
+
if (coords) {
|
|
31160
|
+
return coords;
|
|
31161
|
+
}
|
|
31162
|
+
switch (numPoints) {
|
|
31163
|
+
case 1:
|
|
31164
|
+
// Back in the day, one point's coords were in graph.coord
|
|
31165
|
+
coords = [graph.coord || [0, 0]];
|
|
31166
|
+
break;
|
|
31167
|
+
case 2:
|
|
31168
|
+
coords = [[-5, 0], [5, 0]];
|
|
31169
|
+
break;
|
|
31170
|
+
case 3:
|
|
31171
|
+
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
31172
|
+
break;
|
|
31173
|
+
case 4:
|
|
31174
|
+
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
31175
|
+
break;
|
|
31176
|
+
case 5:
|
|
31177
|
+
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
31178
|
+
break;
|
|
31179
|
+
case 6:
|
|
31180
|
+
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
31181
|
+
break;
|
|
31182
|
+
default:
|
|
31183
|
+
coords = [];
|
|
31184
|
+
break;
|
|
31185
|
+
}
|
|
31186
|
+
// Transform coords from their -10 to 10 space to 0 to 1
|
|
31187
|
+
// because of the old graph.coord, and also it's easier.
|
|
31188
|
+
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
31189
|
+
return normalizePoints(range, step, newCoords);
|
|
31190
|
+
}
|
|
31191
|
+
function getSegmentCoords(graph, range, step) {
|
|
31192
|
+
if (graph.coords) {
|
|
31193
|
+
return graph.coords;
|
|
31194
|
+
}
|
|
31195
|
+
const ys = n => {
|
|
31196
|
+
switch (n) {
|
|
31197
|
+
case 2:
|
|
31198
|
+
return [5, -5];
|
|
31199
|
+
case 3:
|
|
31200
|
+
return [5, 0, -5];
|
|
31201
|
+
case 4:
|
|
31202
|
+
return [6, 2, -2, -6];
|
|
31203
|
+
case 5:
|
|
31204
|
+
return [6, 3, 0, -3, -6];
|
|
31205
|
+
case 6:
|
|
31206
|
+
return [5, 3, 1, -1, -3, -5];
|
|
31207
|
+
default:
|
|
31208
|
+
return [5];
|
|
31209
|
+
}
|
|
31210
|
+
};
|
|
31211
|
+
const defaultRange = [[-10, 10], [-10, 10]];
|
|
31212
|
+
return ys(graph.numSegments).map(y => {
|
|
31213
|
+
let endpoints = [[-5, y], [5, y]];
|
|
31214
|
+
endpoints = normalizeCoords(endpoints, defaultRange);
|
|
31215
|
+
endpoints = normalizePoints(range, step, endpoints);
|
|
31216
|
+
return endpoints;
|
|
31217
|
+
});
|
|
31218
|
+
}
|
|
31219
|
+
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
31220
|
+
function getLineCoords(graph, range, step) {
|
|
31221
|
+
if (graph.coords) {
|
|
31222
|
+
return graph.coords;
|
|
31223
|
+
}
|
|
31224
|
+
return normalizePoints(range, step, defaultLinearCoords[0]);
|
|
31225
|
+
}
|
|
31226
|
+
function getLinearSystemCoords(graph, range, step) {
|
|
31227
|
+
if (graph.coords) {
|
|
31228
|
+
return graph.coords;
|
|
31229
|
+
}
|
|
31230
|
+
return defaultLinearCoords.map(points => normalizePoints(range, step, points));
|
|
31231
|
+
}
|
|
31232
|
+
function getPolygonCoords(graph, range, step) {
|
|
31233
|
+
var _graph$coords2;
|
|
31234
|
+
let coords = (_graph$coords2 = graph.coords) == null ? void 0 : _graph$coords2.slice();
|
|
31235
|
+
if (coords) {
|
|
31236
|
+
return coords;
|
|
31237
|
+
}
|
|
31238
|
+
const n = graph.numSides || 3;
|
|
31239
|
+
if (n === "unlimited") {
|
|
31240
|
+
coords = [];
|
|
31241
|
+
} else {
|
|
31242
|
+
const angle = 2 * Math.PI / n;
|
|
31243
|
+
const offset = (1 / n - 1 / 2) * Math.PI;
|
|
31244
|
+
|
|
31245
|
+
// TODO(alex): Generalize this to more than just triangles so that
|
|
31246
|
+
// all polygons have whole number side lengths if snapping to sides
|
|
31247
|
+
const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
|
|
31248
|
+
|
|
31249
|
+
// Generate coords of a regular polygon with n sides
|
|
31250
|
+
coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
|
|
31251
|
+
}
|
|
31252
|
+
coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
31253
|
+
const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
|
|
31254
|
+
coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
|
|
31255
|
+
return coords;
|
|
31256
|
+
}
|
|
31257
|
+
function getSinusoidCoords(graph, range, step) {
|
|
31258
|
+
if (graph.coords) {
|
|
31259
|
+
return [graph.coords[0], graph.coords[1]];
|
|
31260
|
+
}
|
|
31261
|
+
let coords = [[0.5, 0.5], [0.65, 0.6]];
|
|
31262
|
+
coords = normalizePoints(range, step, coords, true);
|
|
31263
|
+
return coords;
|
|
31264
|
+
}
|
|
31265
|
+
function getQuadraticCoords(graph, range, step) {
|
|
31266
|
+
if (graph.coords) {
|
|
31267
|
+
return graph.coords;
|
|
31268
|
+
}
|
|
31269
|
+
const defaultCoords = [[0.25, 0.75], [0.5, 0.25], [0.75, 0.75]];
|
|
31270
|
+
return normalizePoints(range, step, defaultCoords, true);
|
|
31271
|
+
}
|
|
31272
|
+
function getCircleCoords(graph) {
|
|
31273
|
+
if (graph.center != null && graph.radius != null) {
|
|
31274
|
+
return {
|
|
31275
|
+
center: graph.center,
|
|
31276
|
+
radiusPoint: vec.add(graph.center, [graph.radius, 0])
|
|
31277
|
+
};
|
|
31278
|
+
}
|
|
31279
|
+
return {
|
|
31280
|
+
center: [0, 0],
|
|
31281
|
+
radiusPoint: [2, 0]
|
|
31282
|
+
};
|
|
31283
|
+
}
|
|
31284
|
+
|
|
31223
31285
|
function interactiveGraphReducer(state, action) {
|
|
31224
31286
|
switch (action.type) {
|
|
31225
31287
|
case MOVE_CONTROL_POINT:
|
|
@@ -31243,15 +31305,9 @@ function interactiveGraphReducer(state, action) {
|
|
|
31243
31305
|
}
|
|
31244
31306
|
}
|
|
31245
31307
|
function doMoveControlPoint(state, action) {
|
|
31246
|
-
const {
|
|
31247
|
-
snapStep,
|
|
31248
|
-
range
|
|
31249
|
-
} = state;
|
|
31250
31308
|
switch (state.type) {
|
|
31251
31309
|
case "segment":
|
|
31252
|
-
case "linear":
|
|
31253
31310
|
case "linear-system":
|
|
31254
|
-
case "ray":
|
|
31255
31311
|
{
|
|
31256
31312
|
const newCoords = updateAtIndex({
|
|
31257
31313
|
array: state.coords,
|
|
@@ -31259,11 +31315,7 @@ function doMoveControlPoint(state, action) {
|
|
|
31259
31315
|
update: tuple => setAtIndex({
|
|
31260
31316
|
array: tuple,
|
|
31261
31317
|
index: action.pointIndex,
|
|
31262
|
-
newValue:
|
|
31263
|
-
snapStep,
|
|
31264
|
-
range,
|
|
31265
|
-
point: action.destination
|
|
31266
|
-
}))
|
|
31318
|
+
newValue: boundAndSnapToGrid(action.destination, state)
|
|
31267
31319
|
})
|
|
31268
31320
|
});
|
|
31269
31321
|
const coordsToCheck = newCoords[action.itemIndex];
|
|
@@ -31275,6 +31327,19 @@ function doMoveControlPoint(state, action) {
|
|
|
31275
31327
|
coords: newCoords
|
|
31276
31328
|
});
|
|
31277
31329
|
}
|
|
31330
|
+
case "linear":
|
|
31331
|
+
case "ray":
|
|
31332
|
+
{
|
|
31333
|
+
const newCoords = setAtIndex({
|
|
31334
|
+
array: state.coords,
|
|
31335
|
+
index: action.pointIndex,
|
|
31336
|
+
newValue: boundAndSnapToGrid(action.destination, state)
|
|
31337
|
+
});
|
|
31338
|
+
return _extends({}, state, {
|
|
31339
|
+
hasBeenInteractedWith: true,
|
|
31340
|
+
coords: newCoords
|
|
31341
|
+
});
|
|
31342
|
+
}
|
|
31278
31343
|
case "circle":
|
|
31279
31344
|
throw new Error("FIXME implement circle reducer");
|
|
31280
31345
|
case "point":
|
|
@@ -31286,6 +31351,9 @@ function doMoveControlPoint(state, action) {
|
|
|
31286
31351
|
throw new UnreachableCaseError(state);
|
|
31287
31352
|
}
|
|
31288
31353
|
}
|
|
31354
|
+
|
|
31355
|
+
// (LEMS-2050): Update the reducer so that we have a separate action for moving one line
|
|
31356
|
+
// and another action for moving multiple lines
|
|
31289
31357
|
function doMoveLine(state, action) {
|
|
31290
31358
|
const {
|
|
31291
31359
|
snapStep,
|
|
@@ -31293,9 +31361,7 @@ function doMoveLine(state, action) {
|
|
|
31293
31361
|
} = state;
|
|
31294
31362
|
switch (state.type) {
|
|
31295
31363
|
case "segment":
|
|
31296
|
-
case "linear":
|
|
31297
31364
|
case "linear-system":
|
|
31298
|
-
case "ray":
|
|
31299
31365
|
{
|
|
31300
31366
|
if (action.itemIndex === undefined) {
|
|
31301
31367
|
throw new Error("Please provide index of line to move");
|
|
@@ -31320,6 +31386,21 @@ function doMoveLine(state, action) {
|
|
|
31320
31386
|
coords: newCoords
|
|
31321
31387
|
});
|
|
31322
31388
|
}
|
|
31389
|
+
case "linear":
|
|
31390
|
+
case "ray":
|
|
31391
|
+
{
|
|
31392
|
+
const currentLine = state.coords;
|
|
31393
|
+
const change = getChange(currentLine, action.delta, {
|
|
31394
|
+
snapStep,
|
|
31395
|
+
range
|
|
31396
|
+
});
|
|
31397
|
+
const newLine = [snap(snapStep, vec.add(currentLine[0], change)), snap(snapStep, vec.add(currentLine[1], change))];
|
|
31398
|
+
return _extends({}, state, {
|
|
31399
|
+
type: state.type,
|
|
31400
|
+
hasBeenInteractedWith: true,
|
|
31401
|
+
coords: newLine
|
|
31402
|
+
});
|
|
31403
|
+
}
|
|
31323
31404
|
default:
|
|
31324
31405
|
// The MoveLine action doesn't make sense for other graph types;
|
|
31325
31406
|
// ignore it if it somehow happens
|
|
@@ -31334,11 +31415,20 @@ function doMoveAll(state, action) {
|
|
|
31334
31415
|
switch (state.type) {
|
|
31335
31416
|
case "polygon":
|
|
31336
31417
|
{
|
|
31337
|
-
|
|
31338
|
-
|
|
31339
|
-
|
|
31340
|
-
|
|
31341
|
-
|
|
31418
|
+
let newCoords;
|
|
31419
|
+
if (state.snapTo === "sides" || state.snapTo === "angles") {
|
|
31420
|
+
const change = getChange(state.coords, action.delta, {
|
|
31421
|
+
snapStep: [0, 0],
|
|
31422
|
+
range
|
|
31423
|
+
});
|
|
31424
|
+
newCoords = state.coords.map(point => vec.add(point, change));
|
|
31425
|
+
} else {
|
|
31426
|
+
const change = getChange(state.coords, action.delta, {
|
|
31427
|
+
snapStep,
|
|
31428
|
+
range
|
|
31429
|
+
});
|
|
31430
|
+
newCoords = state.coords.map(point => snap(snapStep, vec.add(point, change)));
|
|
31431
|
+
}
|
|
31342
31432
|
return _extends({}, state, {
|
|
31343
31433
|
hasBeenInteractedWith: true,
|
|
31344
31434
|
coords: newCoords
|
|
@@ -31352,6 +31442,28 @@ function doMoveAll(state, action) {
|
|
|
31352
31442
|
function doMovePoint(state, action) {
|
|
31353
31443
|
switch (state.type) {
|
|
31354
31444
|
case "polygon":
|
|
31445
|
+
let newValue;
|
|
31446
|
+
if (state.snapTo === "sides") {
|
|
31447
|
+
newValue = boundAndSnapToSides(action.destination, state, action.index);
|
|
31448
|
+
} else if (state.snapTo === "angles") {
|
|
31449
|
+
newValue = boundAndSnapToAngle(action.destination, state, action.index);
|
|
31450
|
+
} else {
|
|
31451
|
+
newValue = boundAndSnapToGrid(action.destination, state);
|
|
31452
|
+
}
|
|
31453
|
+
const newCoords = setAtIndex({
|
|
31454
|
+
array: state.coords,
|
|
31455
|
+
index: action.index,
|
|
31456
|
+
newValue: newValue
|
|
31457
|
+
});
|
|
31458
|
+
|
|
31459
|
+
// Reject the move if it would cause the sides of the polygon to cross
|
|
31460
|
+
if (polygonSidesIntersect(newCoords)) {
|
|
31461
|
+
return state;
|
|
31462
|
+
}
|
|
31463
|
+
return _extends({}, state, {
|
|
31464
|
+
hasBeenInteractedWith: true,
|
|
31465
|
+
coords: newCoords
|
|
31466
|
+
});
|
|
31355
31467
|
case "point":
|
|
31356
31468
|
{
|
|
31357
31469
|
return _extends({}, state, {
|
|
@@ -31359,11 +31471,7 @@ function doMovePoint(state, action) {
|
|
|
31359
31471
|
coords: setAtIndex({
|
|
31360
31472
|
array: state.coords,
|
|
31361
31473
|
index: action.index,
|
|
31362
|
-
newValue:
|
|
31363
|
-
snapStep: state.snapStep,
|
|
31364
|
-
range: state.range,
|
|
31365
|
-
point: action.destination
|
|
31366
|
-
}))
|
|
31474
|
+
newValue: boundAndSnapToGrid(action.destination, state)
|
|
31367
31475
|
})
|
|
31368
31476
|
});
|
|
31369
31477
|
}
|
|
@@ -31372,9 +31480,9 @@ function doMovePoint(state, action) {
|
|
|
31372
31480
|
// First, we need to verify that the new coordinates are not on the same vertical line
|
|
31373
31481
|
// If they are, we don't want to move the point
|
|
31374
31482
|
const destination = action.destination;
|
|
31375
|
-
const
|
|
31376
|
-
|
|
31377
|
-
if (
|
|
31483
|
+
const _newCoords = [...state.coords];
|
|
31484
|
+
_newCoords[action.index] = action.destination;
|
|
31485
|
+
if (_newCoords[0][0] === _newCoords[1][0]) {
|
|
31378
31486
|
return state;
|
|
31379
31487
|
}
|
|
31380
31488
|
return _extends({}, state, {
|
|
@@ -31382,26 +31490,27 @@ function doMovePoint(state, action) {
|
|
|
31382
31490
|
coords: setAtIndex({
|
|
31383
31491
|
array: state.coords,
|
|
31384
31492
|
index: action.index,
|
|
31385
|
-
newValue:
|
|
31386
|
-
snapStep: state.snapStep,
|
|
31387
|
-
range: state.range,
|
|
31388
|
-
point: destination
|
|
31389
|
-
}))
|
|
31493
|
+
newValue: boundAndSnapToGrid(destination, state)
|
|
31390
31494
|
})
|
|
31391
31495
|
});
|
|
31392
31496
|
}
|
|
31393
31497
|
case "quadratic":
|
|
31394
31498
|
{
|
|
31499
|
+
// Set up the new coords and check if the quadratic coefficients are valid
|
|
31500
|
+
const _newCoords2 = [...state.coords];
|
|
31501
|
+
_newCoords2[action.index] = action.destination;
|
|
31502
|
+
const QuadraticCoefficients = getQuadraticCoefficients(_newCoords2);
|
|
31503
|
+
|
|
31504
|
+
// If the new destination results in an invalid quadratic equation, we don't want to move the point
|
|
31505
|
+
if (QuadraticCoefficients === undefined) {
|
|
31506
|
+
return state;
|
|
31507
|
+
}
|
|
31395
31508
|
return _extends({}, state, {
|
|
31396
31509
|
hasBeenInteractedWith: true,
|
|
31397
31510
|
coords: setAtIndex({
|
|
31398
31511
|
array: state.coords,
|
|
31399
31512
|
index: action.index,
|
|
31400
|
-
newValue:
|
|
31401
|
-
snapStep: state.snapStep,
|
|
31402
|
-
range: state.range,
|
|
31403
|
-
point: action.destination
|
|
31404
|
-
}))
|
|
31513
|
+
newValue: boundAndSnapToGrid(action.destination, state)
|
|
31405
31514
|
})
|
|
31406
31515
|
});
|
|
31407
31516
|
}
|
|
@@ -31488,14 +31597,8 @@ function doChangeRange(state, action) {
|
|
|
31488
31597
|
range: action.range
|
|
31489
31598
|
});
|
|
31490
31599
|
}
|
|
31491
|
-
const
|
|
31600
|
+
const getDeltaVertex = (maxMoves, minMoves, delta) => {
|
|
31492
31601
|
const [deltaX, deltaY] = delta;
|
|
31493
|
-
const maxMoves = coords.map(point => maxMove(_extends({}, constraintOpts, {
|
|
31494
|
-
point
|
|
31495
|
-
})));
|
|
31496
|
-
const minMoves = coords.map(point => minMove(_extends({}, constraintOpts, {
|
|
31497
|
-
point
|
|
31498
|
-
})));
|
|
31499
31602
|
const maxXMove = Math.min(...maxMoves.map(move => move[0]));
|
|
31500
31603
|
const maxYMove = Math.min(...maxMoves.map(move => move[1]));
|
|
31501
31604
|
const minXMove = Math.max(...minMoves.map(move => move[0]));
|
|
@@ -31504,6 +31607,158 @@ const getChange = (coords, delta, constraintOpts) => {
|
|
|
31504
31607
|
const dy = clamp(deltaY, minYMove, maxYMove);
|
|
31505
31608
|
return [dx, dy];
|
|
31506
31609
|
};
|
|
31610
|
+
const getChange = (coords, delta, constraintOpts) => {
|
|
31611
|
+
const maxMoves = coords.map(point => maxMove(_extends({}, constraintOpts, {
|
|
31612
|
+
point
|
|
31613
|
+
})));
|
|
31614
|
+
const minMoves = coords.map(point => minMove(_extends({}, constraintOpts, {
|
|
31615
|
+
point
|
|
31616
|
+
})));
|
|
31617
|
+
const [dx, dy] = getDeltaVertex(maxMoves, minMoves, delta);
|
|
31618
|
+
return [dx, dy];
|
|
31619
|
+
};
|
|
31620
|
+
const eq$1 = Util.eq;
|
|
31621
|
+
|
|
31622
|
+
// Less than or approximately equal
|
|
31623
|
+
function leq$1(a, b) {
|
|
31624
|
+
return a < b || eq$1(a, b);
|
|
31625
|
+
}
|
|
31626
|
+
function boundAndSnapToGrid(point, {
|
|
31627
|
+
snapStep,
|
|
31628
|
+
range
|
|
31629
|
+
}) {
|
|
31630
|
+
return snap(snapStep, bound$1({
|
|
31631
|
+
snapStep,
|
|
31632
|
+
range,
|
|
31633
|
+
point
|
|
31634
|
+
}));
|
|
31635
|
+
}
|
|
31636
|
+
function boundAndSnapToAngle(destinationPoint, {
|
|
31637
|
+
range,
|
|
31638
|
+
coords
|
|
31639
|
+
}, index) {
|
|
31640
|
+
const startingPoint = coords[index];
|
|
31641
|
+
|
|
31642
|
+
// Needed to prevent updating the original coords before the checks for
|
|
31643
|
+
// degenerate triangles and overlapping sides
|
|
31644
|
+
const coordsCopy = [...coords];
|
|
31645
|
+
|
|
31646
|
+
// Takes the destination point and makes sure it is within the bounds of the graph
|
|
31647
|
+
// SnapStep is [0, 0] because we don't want to snap to the grid
|
|
31648
|
+
coordsCopy[index] = bound$1({
|
|
31649
|
+
snapStep: [0, 0],
|
|
31650
|
+
range,
|
|
31651
|
+
point: destinationPoint
|
|
31652
|
+
});
|
|
31653
|
+
|
|
31654
|
+
// Gets the radian angles between the coords and maps them to degrees
|
|
31655
|
+
const angles = angleMeasures(coordsCopy).map(angle => angle * 180 / Math.PI);
|
|
31656
|
+
|
|
31657
|
+
// Gets the relative index of a point
|
|
31658
|
+
const rel = j => {
|
|
31659
|
+
return (index + j + coordsCopy.length) % coordsCopy.length;
|
|
31660
|
+
};
|
|
31661
|
+
|
|
31662
|
+
// Round the angles to left and right of the current point
|
|
31663
|
+
_.each([-1, 1], function (j) {
|
|
31664
|
+
angles[rel(j)] = Math.round(angles[rel(j)]);
|
|
31665
|
+
});
|
|
31666
|
+
const getAngle = function getAngle(a, vertex, b) {
|
|
31667
|
+
const angle = GraphUtils.findAngle(coordsCopy[rel(a)], coordsCopy[rel(b)], coordsCopy[rel(vertex)]);
|
|
31668
|
+
return (angle + 360) % 360;
|
|
31669
|
+
};
|
|
31670
|
+
const innerAngles = [angles[rel(-1)] - getAngle(-2, -1, 1), angles[rel(1)] - getAngle(-1, 1, 2)];
|
|
31671
|
+
innerAngles[2] = 180 - (innerAngles[0] + innerAngles[1]);
|
|
31672
|
+
|
|
31673
|
+
// Avoid degenerate triangles
|
|
31674
|
+
if (innerAngles.some(function (angle) {
|
|
31675
|
+
return leq$1(angle, 1);
|
|
31676
|
+
})) {
|
|
31677
|
+
return startingPoint;
|
|
31678
|
+
}
|
|
31679
|
+
const knownSide = magnitude(
|
|
31680
|
+
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'.
|
|
31681
|
+
vector(coordsCopy[rel(-1)], coordsCopy[rel(1)]));
|
|
31682
|
+
|
|
31683
|
+
// Returns true if the points form a counter-clockwise turn;
|
|
31684
|
+
// a.k.a if the point is on the left or right of the polygon.
|
|
31685
|
+
// This is used to determine how to adjust the point: if the point is on the left,
|
|
31686
|
+
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
31687
|
+
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
31688
|
+
// for is then used in the polar function to determine the new point.
|
|
31689
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
31690
|
+
|
|
31691
|
+
// Solve for side by using the law of sines
|
|
31692
|
+
const side = Math.sin(innerAngles[1] * Math.PI / 180) / Math.sin(innerAngles[2] * Math.PI / 180) * knownSide;
|
|
31693
|
+
|
|
31694
|
+
// Angle at the second vertex of the polygon
|
|
31695
|
+
const outerAngle = GraphUtils.findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
31696
|
+
|
|
31697
|
+
// Uses the length of the side of the polygon (radial coordinate)
|
|
31698
|
+
// and the angle between the first and second sides of the
|
|
31699
|
+
// polygon (angular coordinate) to determine how to adjust the point
|
|
31700
|
+
const offset = polar(side, outerAngle + (onLeft ? 1 : -1) * innerAngles[0]);
|
|
31701
|
+
return vector$1.add(coordsCopy[rel(-1)], offset);
|
|
31702
|
+
}
|
|
31703
|
+
function boundAndSnapToSides(destinationPoint, {
|
|
31704
|
+
range,
|
|
31705
|
+
coords
|
|
31706
|
+
}, index) {
|
|
31707
|
+
const startingPoint = coords[index];
|
|
31708
|
+
|
|
31709
|
+
// Needed to prevent updating the original coords before the checks for
|
|
31710
|
+
// degenerate triangles and overlapping sides
|
|
31711
|
+
const coordsCopy = [...coords];
|
|
31712
|
+
|
|
31713
|
+
// Takes the destination point and makes sure it is within the bounds of the graph
|
|
31714
|
+
// SnapStep is [0, 0] because we don't want to snap to the grid
|
|
31715
|
+
coordsCopy[index] = bound$1({
|
|
31716
|
+
snapStep: [0, 0],
|
|
31717
|
+
range,
|
|
31718
|
+
point: destinationPoint
|
|
31719
|
+
});
|
|
31720
|
+
|
|
31721
|
+
// Gets the relative index of a point
|
|
31722
|
+
const rel = j => {
|
|
31723
|
+
return (index + j + coordsCopy.length) % coordsCopy.length;
|
|
31724
|
+
};
|
|
31725
|
+
const sides = _.map([[coordsCopy[rel(-1)], coordsCopy[index]], [coordsCopy[index], coordsCopy[rel(1)]], [coordsCopy[rel(-1)], coordsCopy[rel(1)]]], function (coordsCopy) {
|
|
31726
|
+
// @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.
|
|
31727
|
+
return magnitude(vector(...coordsCopy));
|
|
31728
|
+
});
|
|
31729
|
+
|
|
31730
|
+
// Round the sides to left and right of the current point
|
|
31731
|
+
_.each([0, 1], function (j) {
|
|
31732
|
+
sides[j] = Math.round(sides[j]);
|
|
31733
|
+
});
|
|
31734
|
+
|
|
31735
|
+
// Avoid degenerate triangles
|
|
31736
|
+
if (leq$1(sides[1] + sides[2], sides[0]) || leq$1(sides[0] + sides[2], sides[1]) || leq$1(sides[0] + sides[1], sides[2])) {
|
|
31737
|
+
return startingPoint;
|
|
31738
|
+
}
|
|
31739
|
+
|
|
31740
|
+
// Solve for angle by using the law of cosines
|
|
31741
|
+
// Angle at the first vertex of the polygon
|
|
31742
|
+
const innerAngle = lawOfCosines(sides[0], sides[2], sides[1]);
|
|
31743
|
+
|
|
31744
|
+
// Angle at the second vertex of the polygon
|
|
31745
|
+
const outerAngle = GraphUtils.findAngle(coordsCopy[rel(1)], coordsCopy[rel(-1)]);
|
|
31746
|
+
|
|
31747
|
+
// Returns true if the points form a counter-clockwise turn;
|
|
31748
|
+
// a.k.a if the point is on the left or right of the polygon.
|
|
31749
|
+
// This is used to determine how to adjust the point: if the point is on the left,
|
|
31750
|
+
// we want to add the inner angle to the outer angle, and if it's on the right,
|
|
31751
|
+
// we want to subtract the inner angle from the outer angle. The angle solved
|
|
31752
|
+
// for is then used in the polar function to determine the new point.
|
|
31753
|
+
const onLeft = sign(ccw(coordsCopy[rel(-1)], coordsCopy[rel(1)], coordsCopy[index])) === 1;
|
|
31754
|
+
|
|
31755
|
+
// Uses the length of the first side of the polygon (radial coordinate)
|
|
31756
|
+
// and the angle between the first and second sides of the
|
|
31757
|
+
// polygon (angular coordinate) to determine how to adjust the point
|
|
31758
|
+
const offset = polar(sides[0], outerAngle + (onLeft ? 1 : -1) * innerAngle);
|
|
31759
|
+
return vector$1.add(coordsCopy[rel(-1)], offset);
|
|
31760
|
+
}
|
|
31761
|
+
|
|
31507
31762
|
// Returns the closest point to the given `point` that is within the graph
|
|
31508
31763
|
// bounds given in `state`.
|
|
31509
31764
|
function bound$1({
|
|
@@ -31517,7 +31772,7 @@ function bound$1({
|
|
|
31517
31772
|
return [clamp(requestedX, minX + snapX, maxX - snapX), clamp(requestedY, minY + snapY, maxY - snapY)];
|
|
31518
31773
|
}
|
|
31519
31774
|
|
|
31520
|
-
// Returns the vector from the given point to the top-right corner of the graph
|
|
31775
|
+
// Returns the vector from the given point to the top-right corner of the graph when snapped to the grid
|
|
31521
31776
|
function maxMove({
|
|
31522
31777
|
snapStep,
|
|
31523
31778
|
range,
|
|
@@ -31531,8 +31786,7 @@ function maxMove({
|
|
|
31531
31786
|
return vec.sub(topRight, point);
|
|
31532
31787
|
}
|
|
31533
31788
|
|
|
31534
|
-
// Returns the vector from the given point to the bottom-left corner of the
|
|
31535
|
-
// graph
|
|
31789
|
+
// Returns the vector from the given point to the bottom-left corner of the graph when snapped to the grid
|
|
31536
31790
|
function minMove({
|
|
31537
31791
|
snapStep,
|
|
31538
31792
|
range,
|
|
@@ -31593,8 +31847,12 @@ const renderGraph = props => {
|
|
|
31593
31847
|
graphState: state,
|
|
31594
31848
|
dispatch: dispatch
|
|
31595
31849
|
});
|
|
31596
|
-
case "linear":
|
|
31597
31850
|
case "linear-system":
|
|
31851
|
+
return /*#__PURE__*/React.createElement(LinearSystemGraph, {
|
|
31852
|
+
graphState: state,
|
|
31853
|
+
dispatch: dispatch
|
|
31854
|
+
});
|
|
31855
|
+
case "linear":
|
|
31598
31856
|
return /*#__PURE__*/React.createElement(LinearGraph, {
|
|
31599
31857
|
graphState: state,
|
|
31600
31858
|
dispatch: dispatch
|
|
@@ -43843,7 +44101,7 @@ const init = function init(options) {
|
|
|
43843
44101
|
|
|
43844
44102
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43845
44103
|
const libName = "@khanacademy/perseus";
|
|
43846
|
-
const libVersion = "23.
|
|
44104
|
+
const libVersion = "23.4.0";
|
|
43847
44105
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43848
44106
|
|
|
43849
44107
|
const apiVersion = {
|
|
@@ -46844,5 +47102,5 @@ const EditorJsonify = {
|
|
|
46844
47102
|
}
|
|
46845
47103
|
};
|
|
46846
47104
|
|
|
46847
|
-
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
47105
|
+
export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Errors, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusError, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedEllipseFillStyles, lockedFigureColors, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
|
|
46848
47106
|
//# sourceMappingURL=index.js.map
|