@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/es/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/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, Line as Line$
|
|
32
|
+
import { vec, Line as Line$4, Point as Point$2, useMovable, Text as Text$1, Polygon, Circle as Circle$1, 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';
|
|
@@ -16523,7 +16523,7 @@ const Label$1 = GraphieClasses.createSimpleClass((graphie, props) => {
|
|
|
16523
16523
|
}
|
|
16524
16524
|
return elem;
|
|
16525
16525
|
});
|
|
16526
|
-
const Line$
|
|
16526
|
+
const Line$3 = GraphieClasses.createClass({
|
|
16527
16527
|
displayName: "Line",
|
|
16528
16528
|
movableProps: ["children"],
|
|
16529
16529
|
add: function (graphie) {
|
|
@@ -16642,7 +16642,7 @@ var Movables = {
|
|
|
16642
16642
|
Arc: Arc,
|
|
16643
16643
|
Circle: Circle,
|
|
16644
16644
|
Label: Label$1,
|
|
16645
|
-
Line: Line$
|
|
16645
|
+
Line: Line$3,
|
|
16646
16646
|
MovableLine: MovableLine$3,
|
|
16647
16647
|
MovablePoint: MovablePoint$3,
|
|
16648
16648
|
Parabola: Parabola,
|
|
@@ -27570,7 +27570,7 @@ var Image$1 = {
|
|
|
27570
27570
|
// @ts-expect-error - TS2339 - Property 'Label' does not exist on type 'typeof Graphie'.
|
|
27571
27571
|
const Label = Graphie.Label;
|
|
27572
27572
|
// @ts-expect-error - TS2339 - Property 'Line' does not exist on type 'typeof Graphie'.
|
|
27573
|
-
const Line$
|
|
27573
|
+
const Line$2 = Graphie.Line;
|
|
27574
27574
|
// @ts-expect-error - TS2339 - Property 'MovablePoint' does not exist on type 'typeof Graphie'.
|
|
27575
27575
|
const MovablePoint$1 = Graphie.MovablePoint;
|
|
27576
27576
|
// @ts-expect-error - TS2339 - Property 'MovableLine' does not exist on type 'typeof Graphie'.
|
|
@@ -27792,7 +27792,7 @@ class Interaction extends React.Component {
|
|
|
27792
27792
|
this._eval(element.options.endX),
|
|
27793
27793
|
// @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
27794
27794
|
this._eval(element.options.endY)];
|
|
27795
|
-
return /*#__PURE__*/React.createElement(Line$
|
|
27795
|
+
return /*#__PURE__*/React.createElement(Line$2, {
|
|
27796
27796
|
key: element.key,
|
|
27797
27797
|
start: start,
|
|
27798
27798
|
end: end,
|
|
@@ -28500,6 +28500,16 @@ function vectorsToPixels(vectors, graphState, translation = [0, 0]) {
|
|
|
28500
28500
|
const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
|
|
28501
28501
|
return vectors.map(p => vec.transform(p, transformToPx));
|
|
28502
28502
|
}
|
|
28503
|
+
function dimensionsToPixels(dimens, graphState) {
|
|
28504
|
+
const {
|
|
28505
|
+
range,
|
|
28506
|
+
width,
|
|
28507
|
+
height
|
|
28508
|
+
} = graphState;
|
|
28509
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28510
|
+
const transformToPx = matrixBuilder().scale(width / (xMax - xMin), height / (yMax - yMin)).get();
|
|
28511
|
+
return dimens.map(d => vec.transform(d, transformToPx));
|
|
28512
|
+
}
|
|
28503
28513
|
|
|
28504
28514
|
// When converting points, we translate so the pixel point ends up in the right location.
|
|
28505
28515
|
// This is because points are specific locations on graphs, unlike vectors.
|
|
@@ -28512,6 +28522,10 @@ const useTransformVectorsToPixels = (...vectors) => {
|
|
|
28512
28522
|
const graphState = useGraphConfig();
|
|
28513
28523
|
return vectorsToPixels(vectors, graphState);
|
|
28514
28524
|
};
|
|
28525
|
+
const useTransformDimensionsToPixels = (...dimens) => {
|
|
28526
|
+
const graphState = useGraphConfig();
|
|
28527
|
+
return dimensionsToPixels(dimens, graphState);
|
|
28528
|
+
};
|
|
28515
28529
|
|
|
28516
28530
|
function AxisLabels() {
|
|
28517
28531
|
const {
|
|
@@ -28749,33 +28763,29 @@ function calculateAngleInDegrees([x, y]) {
|
|
|
28749
28763
|
*/
|
|
28750
28764
|
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
28751
28765
|
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
28752
|
-
const [aX, aY] =
|
|
28753
|
-
const [bX, bY] =
|
|
28766
|
+
const [aX, aY] = initialPoint;
|
|
28767
|
+
const [bX, bY] = throughPoint;
|
|
28754
28768
|
const yDiff = bY - aY;
|
|
28755
28769
|
const xDiff = bX - aX;
|
|
28756
28770
|
const slope = yDiff / xDiff;
|
|
28757
|
-
const
|
|
28758
|
-
const
|
|
28759
|
-
const
|
|
28760
|
-
const
|
|
28761
|
-
|
|
28762
|
-
// clock analogy to describe quadrants
|
|
28771
|
+
const inverseSlope = 1 / slope;
|
|
28772
|
+
const xExtreme = xDiff < 0 ? xMin : xMax;
|
|
28773
|
+
const yExtreme = yDiff < 0 ? yMin : yMax;
|
|
28774
|
+
const yAtXExtreme = aY + (xExtreme - aX) * slope;
|
|
28775
|
+
const xAtYExtreme = aX + (yExtreme - aY) * inverseSlope;
|
|
28763
28776
|
switch (true) {
|
|
28764
|
-
//
|
|
28765
|
-
case
|
|
28766
|
-
return
|
|
28767
|
-
|
|
28768
|
-
|
|
28769
|
-
|
|
28770
|
-
return
|
|
28771
|
-
// 9 o'clock to 11:59
|
|
28772
|
-
case yDiff >= 0 && xDiff < 0:
|
|
28773
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28774
|
-
// 6 o'clock to 8:59
|
|
28775
|
-
case yDiff < 0 && xDiff <= 0:
|
|
28776
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28777
|
+
// does the ray exit the graph bounding box via the left or right edge?
|
|
28778
|
+
case isBetween(yAtXExtreme, yMin, yMax):
|
|
28779
|
+
return [xExtreme, yAtXExtreme];
|
|
28780
|
+
|
|
28781
|
+
// does the ray exit the graph bounding box via the top or bottom edge?
|
|
28782
|
+
case isBetween(xAtYExtreme, xMin, xMax):
|
|
28783
|
+
return [xAtYExtreme, yExtreme];
|
|
28777
28784
|
default:
|
|
28778
|
-
|
|
28785
|
+
// This default case is only reachable if the input is invalid
|
|
28786
|
+
// (initialPoint is outside the graph bounds, or initialPoint and
|
|
28787
|
+
// throughPoint are the same).
|
|
28788
|
+
return [0, 0];
|
|
28779
28789
|
}
|
|
28780
28790
|
};
|
|
28781
28791
|
const getLines = points => {
|
|
@@ -28784,6 +28794,9 @@ const getLines = points => {
|
|
|
28784
28794
|
return [point, next];
|
|
28785
28795
|
});
|
|
28786
28796
|
};
|
|
28797
|
+
function isBetween(x, low, high) {
|
|
28798
|
+
return x >= low && x <= high;
|
|
28799
|
+
}
|
|
28787
28800
|
|
|
28788
28801
|
function SVGLine(props) {
|
|
28789
28802
|
const {
|
|
@@ -28836,15 +28849,15 @@ const LockedLine = props => {
|
|
|
28836
28849
|
lineStyle,
|
|
28837
28850
|
kind,
|
|
28838
28851
|
points,
|
|
28839
|
-
|
|
28840
|
-
|
|
28852
|
+
showPoint1,
|
|
28853
|
+
showPoint2,
|
|
28841
28854
|
range
|
|
28842
28855
|
} = props;
|
|
28843
28856
|
const [point1, point2] = points;
|
|
28844
28857
|
let line;
|
|
28845
28858
|
if (kind === "ray") {
|
|
28846
28859
|
// Rays extend to the end of the graph in one direction.
|
|
28847
|
-
const extendedPoint = getIntersectionOfRayWithBox(
|
|
28860
|
+
const extendedPoint = getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
28848
28861
|
line = /*#__PURE__*/React.createElement(Vector, {
|
|
28849
28862
|
tail: point1.coord,
|
|
28850
28863
|
tip: extendedPoint,
|
|
@@ -28854,8 +28867,8 @@ const LockedLine = props => {
|
|
|
28854
28867
|
}
|
|
28855
28868
|
});
|
|
28856
28869
|
} else {
|
|
28857
|
-
const LineType = kind === "segment" ? Line$
|
|
28858
|
-
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(
|
|
28870
|
+
const LineType = kind === "segment" ? Line$4.Segment : Line$4.ThroughPoints;
|
|
28871
|
+
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
28859
28872
|
const direction = vec.sub(point2.coord, point1.coord);
|
|
28860
28873
|
let angle = calculateAngleInDegrees(direction);
|
|
28861
28874
|
const startArrowHead = kind !== "segment" && /*#__PURE__*/React.createElement(Arrowhead, {
|
|
@@ -28863,7 +28876,7 @@ const LockedLine = props => {
|
|
|
28863
28876
|
tip: arrowTip,
|
|
28864
28877
|
color: lockedFigureColors[color$1]
|
|
28865
28878
|
});
|
|
28866
|
-
arrowTip = kind === "segment" ? point1.coord : getIntersectionOfRayWithBox(
|
|
28879
|
+
arrowTip = kind === "segment" ? point1.coord : getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
28867
28880
|
angle = angle > 180 ? angle - 180 : angle + 180;
|
|
28868
28881
|
const endArrowHead = kind !== "segment" && /*#__PURE__*/React.createElement(Arrowhead, {
|
|
28869
28882
|
angle: angle,
|
|
@@ -28879,7 +28892,7 @@ const LockedLine = props => {
|
|
|
28879
28892
|
}
|
|
28880
28893
|
return /*#__PURE__*/React.createElement("g", {
|
|
28881
28894
|
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
28882
|
-
}, line,
|
|
28895
|
+
}, line, showPoint1 && /*#__PURE__*/React.createElement(Point$2, {
|
|
28883
28896
|
x: point1.coord[0],
|
|
28884
28897
|
y: point1.coord[1],
|
|
28885
28898
|
svgCircleProps: {
|
|
@@ -28889,7 +28902,7 @@ const LockedLine = props => {
|
|
|
28889
28902
|
strokeWidth: spacing.xxxxSmall_2
|
|
28890
28903
|
}
|
|
28891
28904
|
}
|
|
28892
|
-
}),
|
|
28905
|
+
}), showPoint2 && /*#__PURE__*/React.createElement(Point$2, {
|
|
28893
28906
|
x: point2.coord[0],
|
|
28894
28907
|
y: point2.coord[1],
|
|
28895
28908
|
svgCircleProps: {
|
|
@@ -29149,9 +29162,10 @@ function tabIndex(config) {
|
|
|
29149
29162
|
return undefined;
|
|
29150
29163
|
}
|
|
29151
29164
|
|
|
29152
|
-
const
|
|
29165
|
+
const MovableLine = props => {
|
|
29153
29166
|
const {
|
|
29154
|
-
onMoveLine,
|
|
29167
|
+
onMoveLine = () => {},
|
|
29168
|
+
onMovePoint = () => {},
|
|
29155
29169
|
color,
|
|
29156
29170
|
points: [start, end],
|
|
29157
29171
|
extend
|
|
@@ -29171,18 +29185,19 @@ const Segment = props => {
|
|
|
29171
29185
|
const {
|
|
29172
29186
|
visiblePoint: visiblePoint1,
|
|
29173
29187
|
focusableHandle: focusableHandle1
|
|
29174
|
-
} = useControlPoint(start, color, p =>
|
|
29188
|
+
} = useControlPoint(start, color, p => onMovePoint(0, p));
|
|
29175
29189
|
const {
|
|
29176
29190
|
visiblePoint: visiblePoint2,
|
|
29177
29191
|
focusableHandle: focusableHandle2
|
|
29178
|
-
} = useControlPoint(end, color, p =>
|
|
29179
|
-
|
|
29192
|
+
} = useControlPoint(end, color, p => onMovePoint(1, p));
|
|
29193
|
+
const line = /*#__PURE__*/React.createElement(Line$1, {
|
|
29180
29194
|
start: start,
|
|
29181
29195
|
end: end,
|
|
29182
29196
|
stroke: color,
|
|
29183
29197
|
extend: extend,
|
|
29184
29198
|
onMove: onMoveLine
|
|
29185
|
-
})
|
|
29199
|
+
});
|
|
29200
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, focusableHandle1, line, focusableHandle2, visiblePoint1, visiblePoint2);
|
|
29186
29201
|
};
|
|
29187
29202
|
function useControlPoint(point, color, onMovePoint) {
|
|
29188
29203
|
const {
|
|
@@ -29228,7 +29243,7 @@ function useControlPoint(point, color, onMovePoint) {
|
|
|
29228
29243
|
};
|
|
29229
29244
|
}
|
|
29230
29245
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
29231
|
-
const
|
|
29246
|
+
const Line$1 = props => {
|
|
29232
29247
|
const {
|
|
29233
29248
|
start,
|
|
29234
29249
|
end,
|
|
@@ -29236,29 +29251,29 @@ const MovableLine = props => {
|
|
|
29236
29251
|
extend,
|
|
29237
29252
|
stroke = defaultStroke
|
|
29238
29253
|
} = props;
|
|
29239
|
-
const midpoint = vec.midpoint(start, end);
|
|
29240
29254
|
const [startPtPx, endPtPx] = useTransformVectorsToPixels(start, end);
|
|
29241
29255
|
const {
|
|
29242
29256
|
range,
|
|
29243
|
-
graphDimensionsInPixels
|
|
29257
|
+
graphDimensionsInPixels,
|
|
29258
|
+
snapStep
|
|
29244
29259
|
} = useGraphConfig();
|
|
29245
29260
|
let startExtend = undefined;
|
|
29246
29261
|
let endExtend = undefined;
|
|
29247
29262
|
if (extend) {
|
|
29248
29263
|
const trimmedRange = trimRange(range, graphDimensionsInPixels);
|
|
29249
|
-
startExtend = extend.start ? getIntersectionOfRayWithBox(
|
|
29250
|
-
endExtend = extend.end ? getIntersectionOfRayWithBox(
|
|
29264
|
+
startExtend = extend.start ? getIntersectionOfRayWithBox(end, start, trimmedRange) : undefined;
|
|
29265
|
+
endExtend = extend.end ? getIntersectionOfRayWithBox(start, end, trimmedRange) : undefined;
|
|
29251
29266
|
}
|
|
29252
29267
|
const line = useRef(null);
|
|
29253
29268
|
const {
|
|
29254
29269
|
dragging
|
|
29255
29270
|
} = useMovable({
|
|
29256
29271
|
gestureTarget: line,
|
|
29257
|
-
point:
|
|
29272
|
+
point: start,
|
|
29258
29273
|
onMove: newPoint => {
|
|
29259
|
-
onMove(vec.sub(newPoint,
|
|
29274
|
+
onMove(vec.sub(newPoint, start));
|
|
29260
29275
|
},
|
|
29261
|
-
constrain: p => p
|
|
29276
|
+
constrain: p => snap(snapStep, p)
|
|
29262
29277
|
});
|
|
29263
29278
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("g", {
|
|
29264
29279
|
ref: line,
|
|
@@ -29331,7 +29346,7 @@ const SegmentGraph = props => {
|
|
|
29331
29346
|
const {
|
|
29332
29347
|
coords: segments
|
|
29333
29348
|
} = props.graphState;
|
|
29334
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, segments == null ? void 0 : segments.map((segment, i) => /*#__PURE__*/React.createElement(
|
|
29349
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, segments == null ? void 0 : segments.map((segment, i) => /*#__PURE__*/React.createElement(MovableLine, {
|
|
29335
29350
|
key: i,
|
|
29336
29351
|
points: segment,
|
|
29337
29352
|
onMoveLine: delta => {
|
|
@@ -29351,7 +29366,7 @@ const LinearGraph = props => {
|
|
|
29351
29366
|
coords: lines
|
|
29352
29367
|
} = props.graphState;
|
|
29353
29368
|
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
29354
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, lines == null ? void 0 : lines.map((line, i) => /*#__PURE__*/React.createElement(
|
|
29369
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, lines == null ? void 0 : lines.map((line, i) => /*#__PURE__*/React.createElement(MovableLine, {
|
|
29355
29370
|
key: i,
|
|
29356
29371
|
points: line,
|
|
29357
29372
|
onMoveLine: delta => {
|
|
@@ -29375,7 +29390,7 @@ const RayGraph = props => {
|
|
|
29375
29390
|
} = props.graphState;
|
|
29376
29391
|
const handleMoveLine = delta => dispatch(moveLine(0, delta));
|
|
29377
29392
|
const handleMovePoint = (pointIndex, newPoint) => dispatch(moveControlPoint(pointIndex, newPoint, 0));
|
|
29378
|
-
return /*#__PURE__*/React.createElement(
|
|
29393
|
+
return /*#__PURE__*/React.createElement(MovableLine
|
|
29379
29394
|
// a ray only has one line
|
|
29380
29395
|
, {
|
|
29381
29396
|
points: lines[0],
|
|
@@ -29527,7 +29542,7 @@ const isRightAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
|
|
|
29527
29542
|
*/
|
|
29528
29543
|
const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
|
|
29529
29544
|
// Create a ray from the midpoint (inside angle) to the edge of the range
|
|
29530
|
-
const rangeIntersectionPoint = getIntersectionOfRayWithBox(
|
|
29545
|
+
const rangeIntersectionPoint = getIntersectionOfRayWithBox(midpoint, vertex, range);
|
|
29531
29546
|
let lineIntersectionCount = 0;
|
|
29532
29547
|
polygonLines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
|
|
29533
29548
|
|
|
@@ -29668,14 +29683,12 @@ function initializeGraphState(params) {
|
|
|
29668
29683
|
graph,
|
|
29669
29684
|
step,
|
|
29670
29685
|
snapStep,
|
|
29671
|
-
range
|
|
29672
|
-
markings
|
|
29686
|
+
range
|
|
29673
29687
|
} = params;
|
|
29674
29688
|
const shared = {
|
|
29675
29689
|
hasBeenInteractedWith: false,
|
|
29676
29690
|
range,
|
|
29677
|
-
snapStep
|
|
29678
|
-
markings
|
|
29691
|
+
snapStep
|
|
29679
29692
|
};
|
|
29680
29693
|
switch (graph.type) {
|
|
29681
29694
|
case "segment":
|
|
@@ -29911,16 +29924,10 @@ function CircleGraph(props) {
|
|
|
29911
29924
|
center,
|
|
29912
29925
|
radiusPoint
|
|
29913
29926
|
} = graphState;
|
|
29914
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(
|
|
29927
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MovableCircle, {
|
|
29915
29928
|
center: center,
|
|
29916
29929
|
radius: getRadius(graphState),
|
|
29917
|
-
|
|
29918
|
-
color: color.blue
|
|
29919
|
-
}), /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
29920
|
-
point: center,
|
|
29921
|
-
onMove: newCenter => {
|
|
29922
|
-
dispatch(moveCenter(newCenter));
|
|
29923
|
-
}
|
|
29930
|
+
onMove: newCenter => dispatch(moveCenter(newCenter))
|
|
29924
29931
|
}), /*#__PURE__*/React.createElement(StyledMovablePoint, {
|
|
29925
29932
|
point: radiusPoint,
|
|
29926
29933
|
onMove: newRadiusPoint => {
|
|
@@ -29928,6 +29935,80 @@ function CircleGraph(props) {
|
|
|
29928
29935
|
}
|
|
29929
29936
|
}));
|
|
29930
29937
|
}
|
|
29938
|
+
function MovableCircle(props) {
|
|
29939
|
+
const {
|
|
29940
|
+
center,
|
|
29941
|
+
radius,
|
|
29942
|
+
onMove
|
|
29943
|
+
} = props;
|
|
29944
|
+
const {
|
|
29945
|
+
snapStep
|
|
29946
|
+
} = useGraphConfig();
|
|
29947
|
+
const draggableRef = useRef(null);
|
|
29948
|
+
const {
|
|
29949
|
+
dragging
|
|
29950
|
+
} = useMovable({
|
|
29951
|
+
gestureTarget: draggableRef,
|
|
29952
|
+
point: center,
|
|
29953
|
+
onMove,
|
|
29954
|
+
constrain: p => snap(snapStep, p)
|
|
29955
|
+
});
|
|
29956
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
29957
|
+
const [radiiPx] = useTransformDimensionsToPixels([radius, radius]);
|
|
29958
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
29959
|
+
ref: draggableRef,
|
|
29960
|
+
tabIndex: 0,
|
|
29961
|
+
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`
|
|
29962
|
+
}, /*#__PURE__*/React.createElement("ellipse", {
|
|
29963
|
+
className: "focus-ring",
|
|
29964
|
+
cx: centerPx[0],
|
|
29965
|
+
cy: centerPx[1],
|
|
29966
|
+
rx: radiiPx[0] + 3,
|
|
29967
|
+
ry: radiiPx[1] + 3
|
|
29968
|
+
}), /*#__PURE__*/React.createElement(Circle$1, {
|
|
29969
|
+
center: center,
|
|
29970
|
+
radius: radius,
|
|
29971
|
+
fillOpacity: 0,
|
|
29972
|
+
color: color.blue
|
|
29973
|
+
}), /*#__PURE__*/React.createElement(DragHandle, {
|
|
29974
|
+
center: center
|
|
29975
|
+
}));
|
|
29976
|
+
}
|
|
29977
|
+
const dragHandleDimensions = [24, 14];
|
|
29978
|
+
const dragHandleDotPositions = crossProduct([-4.4, 0, 4.4], [-2.1, 2.1]);
|
|
29979
|
+
function DragHandle(props) {
|
|
29980
|
+
const {
|
|
29981
|
+
center
|
|
29982
|
+
} = props;
|
|
29983
|
+
const cornerRadius = Math.min(...dragHandleDimensions) / 2;
|
|
29984
|
+
const [centerPx] = useTransformVectorsToPixels(center);
|
|
29985
|
+
const topLeft = vec.sub(centerPx, vec.scale(dragHandleDimensions, 0.5));
|
|
29986
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
|
|
29987
|
+
className: "movable-circle-handle",
|
|
29988
|
+
x: topLeft[0],
|
|
29989
|
+
y: topLeft[1],
|
|
29990
|
+
width: dragHandleDimensions[0],
|
|
29991
|
+
height: dragHandleDimensions[1],
|
|
29992
|
+
rx: cornerRadius,
|
|
29993
|
+
ry: cornerRadius
|
|
29994
|
+
}), dragHandleDotPositions.map(offsetPx => {
|
|
29995
|
+
const [xPx, yPx] = vec.add(offsetPx, centerPx);
|
|
29996
|
+
return /*#__PURE__*/React.createElement("circle", {
|
|
29997
|
+
className: "movable-circle-handle-dot",
|
|
29998
|
+
cx: xPx,
|
|
29999
|
+
cy: yPx
|
|
30000
|
+
});
|
|
30001
|
+
}));
|
|
30002
|
+
}
|
|
30003
|
+
function crossProduct(as, bs) {
|
|
30004
|
+
const result = [];
|
|
30005
|
+
for (const a of as) {
|
|
30006
|
+
for (const b of bs) {
|
|
30007
|
+
result.push([a, b]);
|
|
30008
|
+
}
|
|
30009
|
+
}
|
|
30010
|
+
return result;
|
|
30011
|
+
}
|
|
29931
30012
|
|
|
29932
30013
|
function PointGraph(props) {
|
|
29933
30014
|
const {
|
|
@@ -31099,35 +31180,22 @@ function mafsStateToInteractiveGraph(state) {
|
|
|
31099
31180
|
return _extends({}, state);
|
|
31100
31181
|
}
|
|
31101
31182
|
const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
31183
|
+
const {
|
|
31184
|
+
onChange
|
|
31185
|
+
} = props;
|
|
31102
31186
|
const [state, dispatch] = React.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
31103
31187
|
useImperativeHandle(ref, () => ({
|
|
31104
31188
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
31105
31189
|
}));
|
|
31106
|
-
function onChange(next) {
|
|
31107
|
-
props.onChange(mafsStateToInteractiveGraph(next));
|
|
31108
|
-
}
|
|
31109
|
-
return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, props, {
|
|
31110
|
-
state: state,
|
|
31111
|
-
dispatch: dispatch,
|
|
31112
|
-
onChange: onChange
|
|
31113
|
-
}));
|
|
31114
|
-
});
|
|
31115
|
-
const MafsGraph = props => {
|
|
31116
|
-
const {
|
|
31117
|
-
state,
|
|
31118
|
-
dispatch,
|
|
31119
|
-
labels
|
|
31120
|
-
} = props;
|
|
31121
|
-
const [width, height] = props.box;
|
|
31122
31190
|
const prevState = useRef(state);
|
|
31123
31191
|
useEffect(() => {
|
|
31124
31192
|
if (prevState.current !== state) {
|
|
31125
|
-
|
|
31193
|
+
onChange(mafsStateToInteractiveGraph({
|
|
31126
31194
|
graph: state
|
|
31127
|
-
});
|
|
31195
|
+
}));
|
|
31128
31196
|
}
|
|
31129
31197
|
prevState.current = state;
|
|
31130
|
-
}, [
|
|
31198
|
+
}, [onChange, state]);
|
|
31131
31199
|
|
|
31132
31200
|
// Destructuring first to keep useEffect from making excess calls
|
|
31133
31201
|
const [xSnap, ySnap] = props.snapStep;
|
|
@@ -31140,6 +31208,18 @@ const MafsGraph = props => {
|
|
|
31140
31208
|
useEffect(() => {
|
|
31141
31209
|
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
31142
31210
|
}, [dispatch, xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
31211
|
+
return /*#__PURE__*/React.createElement(MafsGraph, _extends({}, props, {
|
|
31212
|
+
state: state,
|
|
31213
|
+
dispatch: dispatch
|
|
31214
|
+
}));
|
|
31215
|
+
});
|
|
31216
|
+
const MafsGraph = props => {
|
|
31217
|
+
const {
|
|
31218
|
+
state,
|
|
31219
|
+
dispatch,
|
|
31220
|
+
labels
|
|
31221
|
+
} = props;
|
|
31222
|
+
const [width, height] = props.box;
|
|
31143
31223
|
return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
|
|
31144
31224
|
value: {
|
|
31145
31225
|
range: state.range,
|
|
@@ -31172,8 +31252,8 @@ const MafsGraph = props => {
|
|
|
31172
31252
|
}, props.markings === "graph" && /*#__PURE__*/React.createElement(AxisLabels, null), /*#__PURE__*/React.createElement(Mafs, {
|
|
31173
31253
|
preserveAspectRatio: false,
|
|
31174
31254
|
viewBox: {
|
|
31175
|
-
x:
|
|
31176
|
-
y:
|
|
31255
|
+
x: state.range[0],
|
|
31256
|
+
y: state.range[1],
|
|
31177
31257
|
padding: 0
|
|
31178
31258
|
},
|
|
31179
31259
|
pan: false,
|
|
@@ -31183,12 +31263,12 @@ const MafsGraph = props => {
|
|
|
31183
31263
|
}, /*#__PURE__*/React.createElement(SvgDefs, null), /*#__PURE__*/React.createElement(Grid, {
|
|
31184
31264
|
tickStep: props.step,
|
|
31185
31265
|
gridStep: props.gridStep,
|
|
31186
|
-
range:
|
|
31266
|
+
range: state.range,
|
|
31187
31267
|
containerSizeClass: props.containerSizeClass,
|
|
31188
31268
|
markings: props.markings
|
|
31189
31269
|
}), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
|
|
31190
31270
|
lockedFigures: props.lockedFigures,
|
|
31191
|
-
range:
|
|
31271
|
+
range: state.range
|
|
31192
31272
|
}), renderGraph({
|
|
31193
31273
|
state,
|
|
31194
31274
|
dispatch
|
|
@@ -43289,7 +43369,7 @@ const init = function init(options) {
|
|
|
43289
43369
|
|
|
43290
43370
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43291
43371
|
const libName = "@khanacademy/perseus";
|
|
43292
|
-
const libVersion = "22.
|
|
43372
|
+
const libVersion = "22.5.1";
|
|
43293
43373
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43294
43374
|
|
|
43295
43375
|
const apiVersion = {
|