@khanacademy/perseus 22.4.2 → 22.5.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 +35 -0
- package/dist/es/index.js +145 -62
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +35 -0
- package/dist/index.js +146 -60
- 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/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
|
|
|
@@ -30224,16 +30242,10 @@ function CircleGraph(props) {
|
|
|
30224
30242
|
center,
|
|
30225
30243
|
radiusPoint
|
|
30226
30244
|
} = graphState;
|
|
30227
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(
|
|
30245
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(MovableCircle, {
|
|
30228
30246
|
center: center,
|
|
30229
30247
|
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
|
-
}
|
|
30248
|
+
onMove: newCenter => dispatch(moveCenter(newCenter))
|
|
30237
30249
|
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30238
30250
|
point: radiusPoint,
|
|
30239
30251
|
onMove: newRadiusPoint => {
|
|
@@ -30241,6 +30253,80 @@ function CircleGraph(props) {
|
|
|
30241
30253
|
}
|
|
30242
30254
|
}));
|
|
30243
30255
|
}
|
|
30256
|
+
function MovableCircle(props) {
|
|
30257
|
+
const {
|
|
30258
|
+
center,
|
|
30259
|
+
radius,
|
|
30260
|
+
onMove
|
|
30261
|
+
} = props;
|
|
30262
|
+
const {
|
|
30263
|
+
snapStep
|
|
30264
|
+
} = useGraphConfig();
|
|
30265
|
+
const draggableRef = React.useRef(null);
|
|
30266
|
+
const {
|
|
30267
|
+
dragging
|
|
30268
|
+
} = mafs.useMovable({
|
|
30269
|
+
gestureTarget: draggableRef,
|
|
30270
|
+
point: center,
|
|
30271
|
+
onMove,
|
|
30272
|
+
constrain: p => snap(snapStep, p)
|
|
30273
|
+
});
|
|
30274
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
30275
|
+
const [radiiPx] = useTransformDimensionsToPixels([radius, radius]);
|
|
30276
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
30277
|
+
ref: draggableRef,
|
|
30278
|
+
tabIndex: 0,
|
|
30279
|
+
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`
|
|
30280
|
+
}, /*#__PURE__*/React__namespace.createElement("ellipse", {
|
|
30281
|
+
className: "focus-ring",
|
|
30282
|
+
cx: centerPx[0],
|
|
30283
|
+
cy: centerPx[1],
|
|
30284
|
+
rx: radiiPx[0] + 3,
|
|
30285
|
+
ry: radiiPx[1] + 3
|
|
30286
|
+
}), /*#__PURE__*/React__namespace.createElement(mafs.Circle, {
|
|
30287
|
+
center: center,
|
|
30288
|
+
radius: radius,
|
|
30289
|
+
fillOpacity: 0,
|
|
30290
|
+
color: wonderBlocksTokens.color.blue
|
|
30291
|
+
}), /*#__PURE__*/React__namespace.createElement(DragHandle, {
|
|
30292
|
+
center: center
|
|
30293
|
+
}));
|
|
30294
|
+
}
|
|
30295
|
+
const dragHandleDimensions = [24, 14];
|
|
30296
|
+
const dragHandleDotPositions = crossProduct([-4.4, 0, 4.4], [-2.1, 2.1]);
|
|
30297
|
+
function DragHandle(props) {
|
|
30298
|
+
const {
|
|
30299
|
+
center
|
|
30300
|
+
} = props;
|
|
30301
|
+
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
30302
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
30303
|
+
const topLeft = mafs.vec.sub(centerPx, mafs.vec.scale(dragHandleDimensions, 0.5));
|
|
30304
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("rect", {
|
|
30305
|
+
className: "movable-circle-handle",
|
|
30306
|
+
x: topLeft[0],
|
|
30307
|
+
y: topLeft[1],
|
|
30308
|
+
width: dragHandleDimensions[0],
|
|
30309
|
+
height: dragHandleDimensions[1],
|
|
30310
|
+
rx: cornerRadius,
|
|
30311
|
+
ry: cornerRadius
|
|
30312
|
+
}), dragHandleDotPositions.map(offsetPx => {
|
|
30313
|
+
const [xPx, yPx] = mafs.vec.add(offsetPx, centerPx);
|
|
30314
|
+
return /*#__PURE__*/React__namespace.createElement("circle", {
|
|
30315
|
+
className: "movable-circle-handle-dot",
|
|
30316
|
+
cx: xPx,
|
|
30317
|
+
cy: yPx
|
|
30318
|
+
});
|
|
30319
|
+
}));
|
|
30320
|
+
}
|
|
30321
|
+
function crossProduct(as, bs) {
|
|
30322
|
+
const result = [];
|
|
30323
|
+
for (const a of as) {
|
|
30324
|
+
for (const b of bs) {
|
|
30325
|
+
result.push([a, b]);
|
|
30326
|
+
}
|
|
30327
|
+
}
|
|
30328
|
+
return result;
|
|
30329
|
+
}
|
|
30244
30330
|
|
|
30245
30331
|
function PointGraph(props) {
|
|
30246
30332
|
const {
|
|
@@ -43618,7 +43704,7 @@ const init = function (options) {
|
|
|
43618
43704
|
|
|
43619
43705
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43620
43706
|
const libName = "@khanacademy/perseus";
|
|
43621
|
-
const libVersion = "22.
|
|
43707
|
+
const libVersion = "22.5.0";
|
|
43622
43708
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43623
43709
|
|
|
43624
43710
|
const apiVersion = {
|