@khanacademy/perseus 22.4.2 → 22.5.1
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 +35 -0
- package/dist/es/index.js +169 -89
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +35 -0
- package/dist/index.js +170 -87
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +3 -3
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +16 -0
- package/dist/widgets/interactive-graphs/graphs/use-transform.d.ts +2 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +1 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +12 -4
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +5 -6
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-state.d.ts +0 -1
- package/dist/widgets/interactive-graphs/types.d.ts +0 -1
- package/package.json +51 -51
- package/dist/widgets/interactive-graphs/graphs/components/segment.d.ts +0 -27
package/dist/index.css
CHANGED
|
@@ -4425,6 +4425,41 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
|
|
|
4425
4425
|
visibility: visible;
|
|
4426
4426
|
}
|
|
4427
4427
|
|
|
4428
|
+
.MafsView .movable-circle {
|
|
4429
|
+
cursor: grab;
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
.MafsView .movable-circle.movable-circle--dragging {
|
|
4433
|
+
cursor: grabbing;
|
|
4434
|
+
outline: none;
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
.MafsView .movable-circle .focus-ring {
|
|
4438
|
+
visibility: hidden; /* overridden when the circle is focused */
|
|
4439
|
+
stroke: var(--mafs-blue);
|
|
4440
|
+
stroke-width: 2px;
|
|
4441
|
+
fill: transparent;
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
.MafsView .movable-circle:focus {
|
|
4445
|
+
outline: none;
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
.MafsView .movable-circle:focus-visible .focus-ring {
|
|
4449
|
+
visibility: visible;
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
.MafsView .movable-circle .movable-circle-handle {
|
|
4453
|
+
fill: var(--mafs-blue); /* WB fadedOffBlack64 */
|
|
4454
|
+
stroke: #fff;
|
|
4455
|
+
stroke-width: 2px;
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4458
|
+
.MafsView .movable-circle .movable-circle-handle-dot {
|
|
4459
|
+
fill: #fff;
|
|
4460
|
+
r: 1.25px;
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4428
4463
|
@font-face {
|
|
4429
4464
|
font-family: Mafs-MJXTEX;
|
|
4430
4465
|
src: url("https://cdn.kastatic.org/fonts/mathjax/MathJax_Main-Regular.woff")
|
package/dist/index.js
CHANGED
|
@@ -16669,7 +16669,7 @@ const Label$1 = GraphieClasses.createSimpleClass((graphie, props) => {
|
|
|
16669
16669
|
}
|
|
16670
16670
|
return elem;
|
|
16671
16671
|
});
|
|
16672
|
-
const Line$
|
|
16672
|
+
const Line$3 = GraphieClasses.createClass({
|
|
16673
16673
|
displayName: "Line",
|
|
16674
16674
|
movableProps: ["children"],
|
|
16675
16675
|
add: function (graphie) {
|
|
@@ -16788,7 +16788,7 @@ var Movables = {
|
|
|
16788
16788
|
Arc: Arc,
|
|
16789
16789
|
Circle: Circle,
|
|
16790
16790
|
Label: Label$1,
|
|
16791
|
-
Line: Line$
|
|
16791
|
+
Line: Line$3,
|
|
16792
16792
|
MovableLine: MovableLine$3,
|
|
16793
16793
|
MovablePoint: MovablePoint$3,
|
|
16794
16794
|
Parabola: Parabola,
|
|
@@ -27849,7 +27849,7 @@ var Image$1 = {
|
|
|
27849
27849
|
// @ts-expect-error - TS2339 - Property 'Label' does not exist on type 'typeof Graphie'.
|
|
27850
27850
|
const Label = Graphie.Label;
|
|
27851
27851
|
// @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
|
|
27852
|
-
const Line$
|
|
27852
|
+
const Line$2 = Graphie.Line;
|
|
27853
27853
|
// @ts-expect-error - TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'.
|
|
27854
27854
|
const MovablePoint$1 = Graphie.MovablePoint;
|
|
27855
27855
|
// @ts-expect-error - TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
|
|
@@ -28076,7 +28076,7 @@ class Interaction extends React__namespace.Component {
|
|
|
28076
28076
|
this._eval(element.options.endX),
|
|
28077
28077
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
28078
28078
|
this._eval(element.options.endY)];
|
|
28079
|
-
return /*#__PURE__*/React__namespace.createElement(Line$
|
|
28079
|
+
return /*#__PURE__*/React__namespace.createElement(Line$2, {
|
|
28080
28080
|
key: element.key,
|
|
28081
28081
|
start: start,
|
|
28082
28082
|
end: end,
|
|
@@ -28785,6 +28785,16 @@ function vectorsToPixels(vectors, graphState) {
|
|
|
28785
28785
|
const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
|
|
28786
28786
|
return vectors.map(p => mafs.vec.transform(p, transformToPx));
|
|
28787
28787
|
}
|
|
28788
|
+
function dimensionsToPixels(dimens, graphState) {
|
|
28789
|
+
const {
|
|
28790
|
+
range,
|
|
28791
|
+
width,
|
|
28792
|
+
height
|
|
28793
|
+
} = graphState;
|
|
28794
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28795
|
+
const transformToPx = matrixBuilder().scale(width / (xMax - xMin), height / (yMax - yMin)).get();
|
|
28796
|
+
return dimens.map(d => mafs.vec.transform(d, transformToPx));
|
|
28797
|
+
}
|
|
28788
28798
|
|
|
28789
28799
|
// When converting points, we translate so the pixel point ends up in the right location.
|
|
28790
28800
|
// This is because points are specific locations on graphs, unlike vectors.
|
|
@@ -28800,6 +28810,13 @@ const useTransformVectorsToPixels = function () {
|
|
|
28800
28810
|
}
|
|
28801
28811
|
return vectorsToPixels(vectors, graphState);
|
|
28802
28812
|
};
|
|
28813
|
+
const useTransformDimensionsToPixels = function () {
|
|
28814
|
+
const graphState = useGraphConfig();
|
|
28815
|
+
for (var _len2 = arguments.length, dimens = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
28816
|
+
dimens[_key2] = arguments[_key2];
|
|
28817
|
+
}
|
|
28818
|
+
return dimensionsToPixels(dimens, graphState);
|
|
28819
|
+
};
|
|
28803
28820
|
|
|
28804
28821
|
function AxisLabels() {
|
|
28805
28822
|
const {
|
|
@@ -29036,33 +29053,29 @@ function calculateAngleInDegrees(_ref) {
|
|
|
29036
29053
|
*/
|
|
29037
29054
|
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
29038
29055
|
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
29039
|
-
const [aX, aY] =
|
|
29040
|
-
const [bX, bY] =
|
|
29056
|
+
const [aX, aY] = initialPoint;
|
|
29057
|
+
const [bX, bY] = throughPoint;
|
|
29041
29058
|
const yDiff = bY - aY;
|
|
29042
29059
|
const xDiff = bX - aX;
|
|
29043
29060
|
const slope = yDiff / xDiff;
|
|
29044
|
-
const
|
|
29045
|
-
const
|
|
29046
|
-
const
|
|
29047
|
-
const
|
|
29048
|
-
|
|
29049
|
-
// clock analogy to describe quadrants
|
|
29061
|
+
const inverseSlope = 1 / slope;
|
|
29062
|
+
const xExtreme = xDiff < 0 ? xMin : xMax;
|
|
29063
|
+
const yExtreme = yDiff < 0 ? yMin : yMax;
|
|
29064
|
+
const yAtXExtreme = aY + (xExtreme - aX) * slope;
|
|
29065
|
+
const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
|
|
29050
29066
|
switch (true) {
|
|
29051
|
-
//
|
|
29052
|
-
case
|
|
29053
|
-
return
|
|
29054
|
-
|
|
29055
|
-
|
|
29056
|
-
|
|
29057
|
-
return
|
|
29058
|
-
// 9 o'clock to 11:59
|
|
29059
|
-
case yDiff >= 0 && xDiff < 0:
|
|
29060
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
29061
|
-
// 6 o'clock to 8:59
|
|
29062
|
-
case yDiff < 0 && xDiff <= 0:
|
|
29063
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
29067
|
+
// does the ray exit the graph bounding box via the left or right edge?
|
|
29068
|
+
case isBetween(yAtXExtreme, yMin, yMax):
|
|
29069
|
+
return [xExtreme, yAtXExtreme];
|
|
29070
|
+
|
|
29071
|
+
// does the ray exit the graph bounding box via the top or bottom edge?
|
|
29072
|
+
case isBetween(xAtYExtreme, xMin, xMax):
|
|
29073
|
+
return [xAtYExtreme, yExtreme];
|
|
29064
29074
|
default:
|
|
29065
|
-
|
|
29075
|
+
// This default case is only reachable if the input is invalid
|
|
29076
|
+
// (initialPoint is outside the graph bounds, or initialPoint and
|
|
29077
|
+
// throughPoint are the same).
|
|
29078
|
+
return [0, 0];
|
|
29066
29079
|
}
|
|
29067
29080
|
};
|
|
29068
29081
|
const getLines = points => {
|
|
@@ -29071,6 +29084,9 @@ const getLines = points => {
|
|
|
29071
29084
|
return [point, next];
|
|
29072
29085
|
});
|
|
29073
29086
|
};
|
|
29087
|
+
function isBetween(x, low, high) {
|
|
29088
|
+
return x >= low && x <= high;
|
|
29089
|
+
}
|
|
29074
29090
|
|
|
29075
29091
|
function SVGLine(props) {
|
|
29076
29092
|
const {
|
|
@@ -29123,15 +29139,15 @@ const LockedLine = props => {
|
|
|
29123
29139
|
lineStyle,
|
|
29124
29140
|
kind,
|
|
29125
29141
|
points,
|
|
29126
|
-
|
|
29127
|
-
|
|
29142
|
+
showPoint1,
|
|
29143
|
+
showPoint2,
|
|
29128
29144
|
range
|
|
29129
29145
|
} = props;
|
|
29130
29146
|
const [point1, point2] = points;
|
|
29131
29147
|
let line;
|
|
29132
29148
|
if (kind === "ray") {
|
|
29133
29149
|
// Rays extend to the end of the graph in one direction.
|
|
29134
|
-
const extendedPoint = getIntersectionOfRayWithBox(
|
|
29150
|
+
const extendedPoint = getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
29135
29151
|
line = /*#__PURE__*/React__namespace.createElement(Vector, {
|
|
29136
29152
|
tail: point1.coord,
|
|
29137
29153
|
tip: extendedPoint,
|
|
@@ -29142,7 +29158,7 @@ const LockedLine = props => {
|
|
|
29142
29158
|
});
|
|
29143
29159
|
} else {
|
|
29144
29160
|
const LineType = kind === "segment" ? mafs.Line.Segment : mafs.Line.ThroughPoints;
|
|
29145
|
-
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(
|
|
29161
|
+
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
29146
29162
|
const direction = mafs.vec.sub(point2.coord, point1.coord);
|
|
29147
29163
|
let angle = calculateAngleInDegrees(direction);
|
|
29148
29164
|
const startArrowHead = kind !== "segment" && /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
@@ -29150,7 +29166,7 @@ const LockedLine = props => {
|
|
|
29150
29166
|
tip: arrowTip,
|
|
29151
29167
|
color: lockedFigureColors[color]
|
|
29152
29168
|
});
|
|
29153
|
-
arrowTip = kind === "segment" ? point1.coord : getIntersectionOfRayWithBox(
|
|
29169
|
+
arrowTip = kind === "segment" ? point1.coord : getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
29154
29170
|
angle = angle > 180 ? angle - 180 : angle + 180;
|
|
29155
29171
|
const endArrowHead = kind !== "segment" && /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29156
29172
|
angle: angle,
|
|
@@ -29166,7 +29182,7 @@ const LockedLine = props => {
|
|
|
29166
29182
|
}
|
|
29167
29183
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29168
29184
|
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
29169
|
-
}, line,
|
|
29185
|
+
}, line, showPoint1 && /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
29170
29186
|
x: point1.coord[0],
|
|
29171
29187
|
y: point1.coord[1],
|
|
29172
29188
|
svgCircleProps: {
|
|
@@ -29176,7 +29192,7 @@ const LockedLine = props => {
|
|
|
29176
29192
|
strokeWidth: wonderBlocksTokens.spacing.xxxxSmall_2
|
|
29177
29193
|
}
|
|
29178
29194
|
}
|
|
29179
|
-
}),
|
|
29195
|
+
}), showPoint2 && /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
29180
29196
|
x: point2.coord[0],
|
|
29181
29197
|
y: point2.coord[1],
|
|
29182
29198
|
svgCircleProps: {
|
|
@@ -29438,9 +29454,10 @@ function tabIndex(config) {
|
|
|
29438
29454
|
return undefined;
|
|
29439
29455
|
}
|
|
29440
29456
|
|
|
29441
|
-
const
|
|
29457
|
+
const MovableLine = props => {
|
|
29442
29458
|
const {
|
|
29443
|
-
onMoveLine,
|
|
29459
|
+
onMoveLine = () => {},
|
|
29460
|
+
onMovePoint = () => {},
|
|
29444
29461
|
color,
|
|
29445
29462
|
points: [start, end],
|
|
29446
29463
|
extend
|
|
@@ -29460,18 +29477,19 @@ const Segment = props => {
|
|
|
29460
29477
|
const {
|
|
29461
29478
|
visiblePoint: visiblePoint1,
|
|
29462
29479
|
focusableHandle: focusableHandle1
|
|
29463
|
-
} = useControlPoint(start, color, p =>
|
|
29480
|
+
} = useControlPoint(start, color, p => onMovePoint(0, p));
|
|
29464
29481
|
const {
|
|
29465
29482
|
visiblePoint: visiblePoint2,
|
|
29466
29483
|
focusableHandle: focusableHandle2
|
|
29467
|
-
} = useControlPoint(end, color, p =>
|
|
29468
|
-
|
|
29484
|
+
} = useControlPoint(end, color, p => onMovePoint(1, p));
|
|
29485
|
+
const line = /*#__PURE__*/React__namespace.createElement(Line$1, {
|
|
29469
29486
|
start: start,
|
|
29470
29487
|
end: end,
|
|
29471
29488
|
stroke: color,
|
|
29472
29489
|
extend: extend,
|
|
29473
29490
|
onMove: onMoveLine
|
|
29474
|
-
})
|
|
29491
|
+
});
|
|
29492
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, focusableHandle1, line, focusableHandle2, visiblePoint1, visiblePoint2);
|
|
29475
29493
|
};
|
|
29476
29494
|
function useControlPoint(point, color, onMovePoint) {
|
|
29477
29495
|
const {
|
|
@@ -29517,7 +29535,7 @@ function useControlPoint(point, color, onMovePoint) {
|
|
|
29517
29535
|
};
|
|
29518
29536
|
}
|
|
29519
29537
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
29520
|
-
const
|
|
29538
|
+
const Line$1 = props => {
|
|
29521
29539
|
const {
|
|
29522
29540
|
start,
|
|
29523
29541
|
end,
|
|
@@ -29525,29 +29543,29 @@ const MovableLine = props => {
|
|
|
29525
29543
|
extend,
|
|
29526
29544
|
stroke = defaultStroke
|
|
29527
29545
|
} = props;
|
|
29528
|
-
const midpoint = mafs.vec.midpoint(start, end);
|
|
29529
29546
|
const [startPtPx, endPtPx] = useTransformVectorsToPixels(start, end);
|
|
29530
29547
|
const {
|
|
29531
29548
|
range,
|
|
29532
|
-
graphDimensionsInPixels
|
|
29549
|
+
graphDimensionsInPixels,
|
|
29550
|
+
snapStep
|
|
29533
29551
|
} = useGraphConfig();
|
|
29534
29552
|
let startExtend = undefined;
|
|
29535
29553
|
let endExtend = undefined;
|
|
29536
29554
|
if (extend) {
|
|
29537
29555
|
const trimmedRange = trimRange(range, graphDimensionsInPixels);
|
|
29538
|
-
startExtend = extend.start ? getIntersectionOfRayWithBox(
|
|
29539
|
-
endExtend = extend.end ? getIntersectionOfRayWithBox(
|
|
29556
|
+
startExtend = extend.start ? getIntersectionOfRayWithBox(end, start, trimmedRange) : undefined;
|
|
29557
|
+
endExtend = extend.end ? getIntersectionOfRayWithBox(start, end, trimmedRange) : undefined;
|
|
29540
29558
|
}
|
|
29541
29559
|
const line = React.useRef(null);
|
|
29542
29560
|
const {
|
|
29543
29561
|
dragging
|
|
29544
29562
|
} = mafs.useMovable({
|
|
29545
29563
|
gestureTarget: line,
|
|
29546
|
-
point:
|
|
29564
|
+
point: start,
|
|
29547
29565
|
onMove: newPoint => {
|
|
29548
|
-
onMove(mafs.vec.sub(newPoint,
|
|
29566
|
+
onMove(mafs.vec.sub(newPoint, start));
|
|
29549
29567
|
},
|
|
29550
|
-
constrain: p => p
|
|
29568
|
+
constrain: p => snap(snapStep, p)
|
|
29551
29569
|
});
|
|
29552
29570
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29553
29571
|
ref: line,
|
|
@@ -29620,7 +29638,7 @@ const SegmentGraph = props => {
|
|
|
29620
29638
|
const {
|
|
29621
29639
|
coords: segments
|
|
29622
29640
|
} = props.graphState;
|
|
29623
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, segments?.map((segment, i) => /*#__PURE__*/React__namespace.createElement(
|
|
29641
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, segments?.map((segment, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
29624
29642
|
key: i,
|
|
29625
29643
|
points: segment,
|
|
29626
29644
|
onMoveLine: delta => {
|
|
@@ -29640,7 +29658,7 @@ const LinearGraph = props => {
|
|
|
29640
29658
|
coords: lines
|
|
29641
29659
|
} = props.graphState;
|
|
29642
29660
|
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
29643
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(
|
|
29661
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
29644
29662
|
key: i,
|
|
29645
29663
|
points: line,
|
|
29646
29664
|
onMoveLine: delta => {
|
|
@@ -29664,7 +29682,7 @@ const RayGraph = props => {
|
|
|
29664
29682
|
} = props.graphState;
|
|
29665
29683
|
const handleMoveLine = delta => dispatch(moveLine(0, delta));
|
|
29666
29684
|
const handleMovePoint = (pointIndex, newPoint) => dispatch(moveControlPoint(pointIndex, newPoint, 0));
|
|
29667
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
29685
|
+
return /*#__PURE__*/React__namespace.createElement(MovableLine
|
|
29668
29686
|
// a ray only has one line
|
|
29669
29687
|
, {
|
|
29670
29688
|
points: lines[0],
|
|
@@ -29822,7 +29840,7 @@ const isRightAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
|
|
|
29822
29840
|
*/
|
|
29823
29841
|
const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
|
|
29824
29842
|
// Create a ray from the midpoint (inside angle) to the edge of the range
|
|
29825
|
-
const rangeIntersectionPoint = getIntersectionOfRayWithBox(
|
|
29843
|
+
const rangeIntersectionPoint = getIntersectionOfRayWithBox(midpoint, vertex, range);
|
|
29826
29844
|
let lineIntersectionCount = 0;
|
|
29827
29845
|
polygonLines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
|
|
29828
29846
|
|
|
@@ -29966,14 +29984,12 @@ function initializeGraphState(params) {
|
|
|
29966
29984
|
graph,
|
|
29967
29985
|
step,
|
|
29968
29986
|
snapStep,
|
|
29969
|
-
range
|
|
29970
|
-
markings
|
|
29987
|
+
range
|
|
29971
29988
|
} = params;
|
|
29972
29989
|
const shared = {
|
|
29973
29990
|
hasBeenInteractedWith: false,
|
|
29974
29991
|
range,
|
|
29975
|
-
snapStep
|
|
29976
|
-
markings
|
|
29992
|
+
snapStep
|
|
29977
29993
|
};
|
|
29978
29994
|
switch (graph.type) {
|
|
29979
29995
|
case "segment":
|
|
@@ -30224,16 +30240,10 @@ function CircleGraph(props) {
|
|
|
30224
30240
|
center,
|
|
30225
30241
|
radiusPoint
|
|
30226
30242
|
} = graphState;
|
|
30227
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(
|
|
30243
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(MovableCircle, {
|
|
30228
30244
|
center: center,
|
|
30229
30245
|
radius: getRadius(graphState),
|
|
30230
|
-
|
|
30231
|
-
color: wonderBlocksTokens.color.blue
|
|
30232
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30233
|
-
point: center,
|
|
30234
|
-
onMove: newCenter => {
|
|
30235
|
-
dispatch(moveCenter(newCenter));
|
|
30236
|
-
}
|
|
30246
|
+
onMove: newCenter => dispatch(moveCenter(newCenter))
|
|
30237
30247
|
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30238
30248
|
point: radiusPoint,
|
|
30239
30249
|
onMove: newRadiusPoint => {
|
|
@@ -30241,6 +30251,80 @@ function CircleGraph(props) {
|
|
|
30241
30251
|
}
|
|
30242
30252
|
}));
|
|
30243
30253
|
}
|
|
30254
|
+
function MovableCircle(props) {
|
|
30255
|
+
const {
|
|
30256
|
+
center,
|
|
30257
|
+
radius,
|
|
30258
|
+
onMove
|
|
30259
|
+
} = props;
|
|
30260
|
+
const {
|
|
30261
|
+
snapStep
|
|
30262
|
+
} = useGraphConfig();
|
|
30263
|
+
const draggableRef = React.useRef(null);
|
|
30264
|
+
const {
|
|
30265
|
+
dragging
|
|
30266
|
+
} = mafs.useMovable({
|
|
30267
|
+
gestureTarget: draggableRef,
|
|
30268
|
+
point: center,
|
|
30269
|
+
onMove,
|
|
30270
|
+
constrain: p => snap(snapStep, p)
|
|
30271
|
+
});
|
|
30272
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
30273
|
+
const [radiiPx] = useTransformDimensionsToPixels([radius, radius]);
|
|
30274
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
30275
|
+
ref: draggableRef,
|
|
30276
|
+
tabIndex: 0,
|
|
30277
|
+
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`
|
|
30278
|
+
}, /*#__PURE__*/React__namespace.createElement("ellipse", {
|
|
30279
|
+
className: "focus-ring",
|
|
30280
|
+
cx: centerPx[0],
|
|
30281
|
+
cy: centerPx[1],
|
|
30282
|
+
rx: radiiPx[0] + 3,
|
|
30283
|
+
ry: radiiPx[1] + 3
|
|
30284
|
+
}), /*#__PURE__*/React__namespace.createElement(mafs.Circle, {
|
|
30285
|
+
center: center,
|
|
30286
|
+
radius: radius,
|
|
30287
|
+
fillOpacity: 0,
|
|
30288
|
+
color: wonderBlocksTokens.color.blue
|
|
30289
|
+
}), /*#__PURE__*/React__namespace.createElement(DragHandle, {
|
|
30290
|
+
center: center
|
|
30291
|
+
}));
|
|
30292
|
+
}
|
|
30293
|
+
const dragHandleDimensions = [24, 14];
|
|
30294
|
+
const dragHandleDotPositions = crossProduct([-4.4, 0, 4.4], [-2.1, 2.1]);
|
|
30295
|
+
function DragHandle(props) {
|
|
30296
|
+
const {
|
|
30297
|
+
center
|
|
30298
|
+
} = props;
|
|
30299
|
+
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
30300
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
30301
|
+
const topLeft = mafs.vec.sub(centerPx, mafs.vec.scale(dragHandleDimensions, 0.5));
|
|
30302
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("rect", {
|
|
30303
|
+
className: "movable-circle-handle",
|
|
30304
|
+
x: topLeft[0],
|
|
30305
|
+
y: topLeft[1],
|
|
30306
|
+
width: dragHandleDimensions[0],
|
|
30307
|
+
height: dragHandleDimensions[1],
|
|
30308
|
+
rx: cornerRadius,
|
|
30309
|
+
ry: cornerRadius
|
|
30310
|
+
}), dragHandleDotPositions.map(offsetPx => {
|
|
30311
|
+
const [xPx, yPx] = mafs.vec.add(offsetPx, centerPx);
|
|
30312
|
+
return /*#__PURE__*/React__namespace.createElement("circle", {
|
|
30313
|
+
className: "movable-circle-handle-dot",
|
|
30314
|
+
cx: xPx,
|
|
30315
|
+
cy: yPx
|
|
30316
|
+
});
|
|
30317
|
+
}));
|
|
30318
|
+
}
|
|
30319
|
+
function crossProduct(as, bs) {
|
|
30320
|
+
const result = [];
|
|
30321
|
+
for (const a of as) {
|
|
30322
|
+
for (const b of bs) {
|
|
30323
|
+
result.push([a, b]);
|
|
30324
|
+
}
|
|
30325
|
+
}
|
|
30326
|
+
return result;
|
|
30327
|
+
}
|
|
30244
30328
|
|
|
30245
30329
|
function PointGraph(props) {
|
|
30246
30330
|
const {
|
|
@@ -31433,35 +31517,22 @@ function mafsStateToInteractiveGraph(state) {
|
|
|
31433
31517
|
};
|
|
31434
31518
|
}
|
|
31435
31519
|
const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
31520
|
+
const {
|
|
31521
|
+
onChange
|
|
31522
|
+
} = props;
|
|
31436
31523
|
const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
31437
31524
|
React.useImperativeHandle(ref, () => ({
|
|
31438
31525
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
31439
31526
|
}));
|
|
31440
|
-
function onChange(next) {
|
|
31441
|
-
props.onChange(mafsStateToInteractiveGraph(next));
|
|
31442
|
-
}
|
|
31443
|
-
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
|
|
31444
|
-
state: state,
|
|
31445
|
-
dispatch: dispatch,
|
|
31446
|
-
onChange: onChange
|
|
31447
|
-
}));
|
|
31448
|
-
});
|
|
31449
|
-
const MafsGraph = props => {
|
|
31450
|
-
const {
|
|
31451
|
-
state,
|
|
31452
|
-
dispatch,
|
|
31453
|
-
labels
|
|
31454
|
-
} = props;
|
|
31455
|
-
const [width, height] = props.box;
|
|
31456
31527
|
const prevState = React.useRef(state);
|
|
31457
31528
|
React.useEffect(() => {
|
|
31458
31529
|
if (prevState.current !== state) {
|
|
31459
|
-
|
|
31530
|
+
onChange(mafsStateToInteractiveGraph({
|
|
31460
31531
|
graph: state
|
|
31461
|
-
});
|
|
31532
|
+
}));
|
|
31462
31533
|
}
|
|
31463
31534
|
prevState.current = state;
|
|
31464
|
-
}, [
|
|
31535
|
+
}, [onChange, state]);
|
|
31465
31536
|
|
|
31466
31537
|
// Destructuring first to keep useEffect from making excess calls
|
|
31467
31538
|
const [xSnap, ySnap] = props.snapStep;
|
|
@@ -31474,6 +31545,18 @@ const MafsGraph = props => {
|
|
|
31474
31545
|
React.useEffect(() => {
|
|
31475
31546
|
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
31476
31547
|
}, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
31548
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
|
|
31549
|
+
state: state,
|
|
31550
|
+
dispatch: dispatch
|
|
31551
|
+
}));
|
|
31552
|
+
});
|
|
31553
|
+
const MafsGraph = props => {
|
|
31554
|
+
const {
|
|
31555
|
+
state,
|
|
31556
|
+
dispatch,
|
|
31557
|
+
labels
|
|
31558
|
+
} = props;
|
|
31559
|
+
const [width, height] = props.box;
|
|
31477
31560
|
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
31478
31561
|
value: {
|
|
31479
31562
|
range: state.range,
|
|
@@ -31506,8 +31589,8 @@ const MafsGraph = props => {
|
|
|
31506
31589
|
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
31507
31590
|
preserveAspectRatio: false,
|
|
31508
31591
|
viewBox: {
|
|
31509
|
-
x:
|
|
31510
|
-
y:
|
|
31592
|
+
x: state.range[0],
|
|
31593
|
+
y: state.range[1],
|
|
31511
31594
|
padding: 0
|
|
31512
31595
|
},
|
|
31513
31596
|
pan: false,
|
|
@@ -31517,12 +31600,12 @@ const MafsGraph = props => {
|
|
|
31517
31600
|
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
31518
31601
|
tickStep: props.step,
|
|
31519
31602
|
gridStep: props.gridStep,
|
|
31520
|
-
range:
|
|
31603
|
+
range: state.range,
|
|
31521
31604
|
containerSizeClass: props.containerSizeClass,
|
|
31522
31605
|
markings: props.markings
|
|
31523
31606
|
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
31524
31607
|
lockedFigures: props.lockedFigures,
|
|
31525
|
-
range:
|
|
31608
|
+
range: state.range
|
|
31526
31609
|
}), renderGraph({
|
|
31527
31610
|
state,
|
|
31528
31611
|
dispatch
|
|
@@ -43618,7 +43701,7 @@ const init = function (options) {
|
|
|
43618
43701
|
|
|
43619
43702
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43620
43703
|
const libName = "@khanacademy/perseus";
|
|
43621
|
-
const libVersion = "22.
|
|
43704
|
+
const libVersion = "22.5.1";
|
|
43622
43705
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43623
43706
|
|
|
43624
43707
|
const apiVersion = {
|