@khanacademy/perseus 21.1.0 → 21.2.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 +28 -4
- package/dist/es/index.js +231 -64
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +28 -4
- package/dist/index.js +239 -72
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -1
- package/dist/perseus-types.d.ts +6 -2
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/util.d.ts +3 -0
- package/dist/widgets/expression.d.ts +6 -6
- package/dist/widgets/interactive-graph.d.ts +4 -1
- package/dist/widgets/interactive-graphs/axis-ticks.d.ts +8 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +6 -4
- package/dist/widgets/interactive-graphs/grid.d.ts +14 -3
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +2 -2
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +14 -1
- package/dist/widgets/interactive-graphs/utils.d.ts +2 -0
- package/dist/widgets/label-image.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -4284,6 +4284,7 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
|
|
|
4284
4284
|
--movable-point-ring-radius: calc(2px + var(--movable-point-center-radius));
|
|
4285
4285
|
--movable-point-halo-radius: calc(3px + var(--movable-point-ring-radius));
|
|
4286
4286
|
--movable-point-hover-expansion: 2px;
|
|
4287
|
+
--movable-point-focus-ring-offset: 2px;
|
|
4287
4288
|
|
|
4288
4289
|
--movable-line-stroke-color: var(--mafs-blue);
|
|
4289
4290
|
--movable-line-stroke-weight: 2px;
|
|
@@ -4305,7 +4306,13 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
|
|
|
4305
4306
|
fill: transparent;
|
|
4306
4307
|
}
|
|
4307
4308
|
|
|
4308
|
-
.MafsView
|
|
4309
|
+
.MafsView
|
|
4310
|
+
:is(
|
|
4311
|
+
.movable-point-center,
|
|
4312
|
+
.movable-point-ring,
|
|
4313
|
+
.movable-point-halo,
|
|
4314
|
+
.movable-point-focus-outline
|
|
4315
|
+
) {
|
|
4309
4316
|
transition: r 0.15s ease-out;
|
|
4310
4317
|
}
|
|
4311
4318
|
|
|
@@ -4344,7 +4351,24 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
|
|
|
4344
4351
|
);
|
|
4345
4352
|
}
|
|
4346
4353
|
|
|
4347
|
-
.MafsView .movable-point
|
|
4348
|
-
|
|
4349
|
-
|
|
4354
|
+
.MafsView .movable-point .movable-point-focus-outline {
|
|
4355
|
+
visibility: hidden;
|
|
4356
|
+
r: calc(
|
|
4357
|
+
var(--movable-point-halo-radius) +
|
|
4358
|
+
var(--movable-point-focus-ring-offset)
|
|
4359
|
+
);
|
|
4360
|
+
stroke-width: 2px;
|
|
4361
|
+
fill: none;
|
|
4362
|
+
stroke: var(--mafs-blue);
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
.MafsView .movable-point:hover .movable-point-focus-outline {
|
|
4366
|
+
r: calc(
|
|
4367
|
+
var(--movable-point-hover-expansion) + var(--movable-point-halo-radius) +
|
|
4368
|
+
var(--movable-point-focus-ring-offset)
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
.MafsView .movable-point:focus-visible .movable-point-focus-outline {
|
|
4373
|
+
visibility: visible;
|
|
4350
4374
|
}
|
package/dist/index.js
CHANGED
|
@@ -3281,6 +3281,15 @@ const textarea = {
|
|
|
3281
3281
|
*/
|
|
3282
3282
|
const unescapeMathMode$1 = label => label.startsWith("$") && label.endsWith("$") ? label.slice(1, -1) : label;
|
|
3283
3283
|
const random$1 = seededRNG$1(new Date().getTime() & 0xffffffff);
|
|
3284
|
+
|
|
3285
|
+
// TODO(benchristel): in the future, we may want to make deepClone work for
|
|
3286
|
+
// Record<string, Cloneable> as well. Currently, it only does arrays.
|
|
3287
|
+
function deepClone(obj) {
|
|
3288
|
+
if (Array.isArray(obj)) {
|
|
3289
|
+
return obj.map(deepClone);
|
|
3290
|
+
}
|
|
3291
|
+
return obj;
|
|
3292
|
+
}
|
|
3284
3293
|
const Util = {
|
|
3285
3294
|
inputPathsEqual,
|
|
3286
3295
|
nestedMap: nestedMap$2,
|
|
@@ -3326,7 +3335,8 @@ const Util = {
|
|
|
3326
3335
|
getDataUrl: getDataUrl,
|
|
3327
3336
|
textarea,
|
|
3328
3337
|
unescapeMathMode: unescapeMathMode$1,
|
|
3329
|
-
random: random$1
|
|
3338
|
+
random: random$1,
|
|
3339
|
+
deepClone
|
|
3330
3340
|
};
|
|
3331
3341
|
|
|
3332
3342
|
// Derived from the MIT-licensed:
|
|
@@ -28364,6 +28374,28 @@ function movePoint(index, destination) {
|
|
|
28364
28374
|
destination
|
|
28365
28375
|
};
|
|
28366
28376
|
}
|
|
28377
|
+
const CHANGE_SNAP_STEP = "change-snap-step";
|
|
28378
|
+
function changeSnapStep(snapStep) {
|
|
28379
|
+
return {
|
|
28380
|
+
type: CHANGE_SNAP_STEP,
|
|
28381
|
+
snapStep
|
|
28382
|
+
};
|
|
28383
|
+
}
|
|
28384
|
+
const CHANGE_RANGE = "change-range";
|
|
28385
|
+
function changeRange(range) {
|
|
28386
|
+
return {
|
|
28387
|
+
type: CHANGE_RANGE,
|
|
28388
|
+
range
|
|
28389
|
+
};
|
|
28390
|
+
}
|
|
28391
|
+
|
|
28392
|
+
const GraphStateContext = /*#__PURE__*/React.createContext({
|
|
28393
|
+
state: {},
|
|
28394
|
+
dispatch: () => {}
|
|
28395
|
+
});
|
|
28396
|
+
function useGraphState() {
|
|
28397
|
+
return React__default["default"].useContext(GraphStateContext);
|
|
28398
|
+
}
|
|
28367
28399
|
|
|
28368
28400
|
/**
|
|
28369
28401
|
* 44 is touch best practice and AAA compliant for WCAG
|
|
@@ -28390,6 +28422,11 @@ const normalizeCoords = (coordsList, ranges) => coordsList.map(coords => coords.
|
|
|
28390
28422
|
const extent = ranges[i][1] - ranges[i][0];
|
|
28391
28423
|
return (coord + ranges[i][1]) / extent;
|
|
28392
28424
|
}));
|
|
28425
|
+
function snap(snapStep, point) {
|
|
28426
|
+
const [requestedX, requestedY] = point;
|
|
28427
|
+
const [snapX, snapY] = snapStep;
|
|
28428
|
+
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
28429
|
+
}
|
|
28393
28430
|
|
|
28394
28431
|
const useTransform = function () {
|
|
28395
28432
|
const {
|
|
@@ -28448,6 +28485,9 @@ const getLines = points => points.map((point, i) => {
|
|
|
28448
28485
|
|
|
28449
28486
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
28450
28487
|
const MovableLine = props => {
|
|
28488
|
+
const {
|
|
28489
|
+
state
|
|
28490
|
+
} = useGraphState();
|
|
28451
28491
|
const {
|
|
28452
28492
|
start,
|
|
28453
28493
|
end,
|
|
@@ -28472,7 +28512,7 @@ const MovableLine = props => {
|
|
|
28472
28512
|
onMove: newPoint => {
|
|
28473
28513
|
onMove(mafs.vec.sub(newPoint, midpoint));
|
|
28474
28514
|
},
|
|
28475
|
-
constrain: p => p
|
|
28515
|
+
constrain: p => snap(state.snapStep, p)
|
|
28476
28516
|
});
|
|
28477
28517
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("g", {
|
|
28478
28518
|
ref: line,
|
|
@@ -28523,7 +28563,13 @@ function SVGLine(props) {
|
|
|
28523
28563
|
});
|
|
28524
28564
|
}
|
|
28525
28565
|
|
|
28566
|
+
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
28567
|
+
// graph.
|
|
28568
|
+
const hitboxSizePx = 48;
|
|
28526
28569
|
const StyledMovablePoint = props => {
|
|
28570
|
+
const {
|
|
28571
|
+
state
|
|
28572
|
+
} = useGraphState();
|
|
28527
28573
|
const hitboxRef = React.useRef(null);
|
|
28528
28574
|
const {
|
|
28529
28575
|
point,
|
|
@@ -28536,7 +28582,7 @@ const StyledMovablePoint = props => {
|
|
|
28536
28582
|
gestureTarget: hitboxRef,
|
|
28537
28583
|
point,
|
|
28538
28584
|
onMove,
|
|
28539
|
-
constrain: p => p
|
|
28585
|
+
constrain: p => snap(state.snapStep, p)
|
|
28540
28586
|
});
|
|
28541
28587
|
const [[x, y]] = useTransform(point);
|
|
28542
28588
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -28551,7 +28597,7 @@ const StyledMovablePoint = props => {
|
|
|
28551
28597
|
}
|
|
28552
28598
|
}, /*#__PURE__*/React__namespace.createElement("circle", {
|
|
28553
28599
|
className: "movable-point-hitbox",
|
|
28554
|
-
r:
|
|
28600
|
+
r: hitboxSizePx / 2,
|
|
28555
28601
|
cx: x,
|
|
28556
28602
|
cy: y
|
|
28557
28603
|
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
@@ -28562,6 +28608,10 @@ const StyledMovablePoint = props => {
|
|
|
28562
28608
|
className: "movable-point-ring",
|
|
28563
28609
|
cx: x,
|
|
28564
28610
|
cy: y
|
|
28611
|
+
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
28612
|
+
className: "movable-point-focus-outline",
|
|
28613
|
+
cx: x,
|
|
28614
|
+
cy: y
|
|
28565
28615
|
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
28566
28616
|
className: "movable-point-center",
|
|
28567
28617
|
cx: x,
|
|
@@ -28887,7 +28937,8 @@ const PolygonGraph = props => {
|
|
|
28887
28937
|
type,
|
|
28888
28938
|
showAngles,
|
|
28889
28939
|
showSides,
|
|
28890
|
-
range
|
|
28940
|
+
range,
|
|
28941
|
+
snapStep
|
|
28891
28942
|
} = props.graphState;
|
|
28892
28943
|
const points = coords ?? [[0, 0]];
|
|
28893
28944
|
const pointsSum = points.reduce((acc, point) => mafs.vec.add(acc, point), [0, 0]);
|
|
@@ -28902,7 +28953,7 @@ const PolygonGraph = props => {
|
|
|
28902
28953
|
const delta = mafs.vec.sub(newPoint, midpoint);
|
|
28903
28954
|
dispatch(moveAll(delta));
|
|
28904
28955
|
},
|
|
28905
|
-
constrain: p => p
|
|
28956
|
+
constrain: p => snap(snapStep, p)
|
|
28906
28957
|
});
|
|
28907
28958
|
const active = hovered || focused || dragging;
|
|
28908
28959
|
const lines = getLines(points);
|
|
@@ -28971,14 +29022,6 @@ function PointGraph(props) {
|
|
|
28971
29022
|
})));
|
|
28972
29023
|
}
|
|
28973
29024
|
|
|
28974
|
-
const GraphStateContext = /*#__PURE__*/React.createContext({
|
|
28975
|
-
state: {},
|
|
28976
|
-
dispatch: () => {}
|
|
28977
|
-
});
|
|
28978
|
-
function useGraphState() {
|
|
28979
|
-
return React__default["default"].useContext(GraphStateContext);
|
|
28980
|
-
}
|
|
28981
|
-
|
|
28982
29025
|
function Arrow(props) {
|
|
28983
29026
|
const {
|
|
28984
29027
|
userTransform,
|
|
@@ -29022,20 +29065,122 @@ function AxisArrows() {
|
|
|
29022
29065
|
}));
|
|
29023
29066
|
}
|
|
29024
29067
|
|
|
29025
|
-
const
|
|
29026
|
-
|
|
29027
|
-
|
|
29068
|
+
const tickSize = 10;
|
|
29069
|
+
const tickStyle = {
|
|
29070
|
+
stroke: "black",
|
|
29071
|
+
strokeWidth: 1
|
|
29072
|
+
};
|
|
29073
|
+
const YGridTick = _ref => {
|
|
29074
|
+
let {
|
|
29075
|
+
y
|
|
29076
|
+
} = _ref;
|
|
29077
|
+
const pointOnAxis = [0, y];
|
|
29078
|
+
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
29079
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29080
|
+
className: "y-axis-ticks"
|
|
29081
|
+
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29082
|
+
x1: xPosition - tickSize / 2,
|
|
29083
|
+
y1: yPosition,
|
|
29084
|
+
x2: xPosition + tickSize / 2,
|
|
29085
|
+
y2: yPosition,
|
|
29086
|
+
style: tickStyle
|
|
29087
|
+
}));
|
|
29088
|
+
};
|
|
29089
|
+
const XGridTick = _ref2 => {
|
|
29090
|
+
let {
|
|
29091
|
+
x
|
|
29092
|
+
} = _ref2;
|
|
29093
|
+
const pointOnAxis = [x, 0];
|
|
29094
|
+
const [[xPosition, yPosition]] = useTransform(pointOnAxis);
|
|
29095
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29096
|
+
className: "x-axis-ticks"
|
|
29097
|
+
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29098
|
+
x1: xPosition,
|
|
29099
|
+
y1: yPosition + tickSize / 2,
|
|
29100
|
+
x2: xPosition,
|
|
29101
|
+
y2: yPosition - tickSize / 2,
|
|
29102
|
+
style: tickStyle
|
|
29103
|
+
}));
|
|
29104
|
+
};
|
|
29105
|
+
function generateTickLocations(tickStep, min, max) {
|
|
29106
|
+
const ticks = [];
|
|
29107
|
+
for (let i = 0 + tickStep; i < max; i += tickStep) {
|
|
29108
|
+
ticks.push(i);
|
|
29109
|
+
}
|
|
29110
|
+
for (let i = 0 - tickStep; i > min; i -= tickStep) {
|
|
29111
|
+
ticks.push(i);
|
|
29112
|
+
}
|
|
29113
|
+
return ticks;
|
|
29114
|
+
}
|
|
29115
|
+
const AxisTicks = props => {
|
|
29116
|
+
const range = props.range;
|
|
29117
|
+
const [xMin, xMax] = range[0];
|
|
29118
|
+
const [yMin, yMax] = range[1];
|
|
29119
|
+
const yTickStep = props.tickStep[1];
|
|
29120
|
+
const xTickStep = props.tickStep[0];
|
|
29121
|
+
const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
|
|
29122
|
+
const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
|
|
29123
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29124
|
+
className: "axis-ticks"
|
|
29125
|
+
}, yGridTicks.map(y => {
|
|
29126
|
+
return /*#__PURE__*/React__namespace.createElement(YGridTick, {
|
|
29127
|
+
y: y,
|
|
29128
|
+
key: `y-grid-tick-${y}`
|
|
29129
|
+
});
|
|
29130
|
+
}), xGridTicks.map(x => {
|
|
29131
|
+
return /*#__PURE__*/React__namespace.createElement(XGridTick, {
|
|
29132
|
+
x: x,
|
|
29133
|
+
key: `x-grid-tick-${x}`
|
|
29134
|
+
});
|
|
29135
|
+
}));
|
|
29136
|
+
};
|
|
29137
|
+
|
|
29138
|
+
/**
|
|
29139
|
+
* lineLabelText get the text that should
|
|
29140
|
+
* be displayed for a specific tick place
|
|
29141
|
+
*
|
|
29142
|
+
* @param {number} n the tick number
|
|
29143
|
+
* @param {number} tickStep how frequently a label should appear
|
|
29144
|
+
* @param {vec.Vector2} range the min/max range on the axis
|
|
29145
|
+
*/
|
|
29146
|
+
const lineLabelText = (n, tickStep, range) => {
|
|
29147
|
+
const [min, max] = range;
|
|
29148
|
+
const isOnStep = n % tickStep === 0;
|
|
29149
|
+
const isNegativeOne = n === -1;
|
|
29150
|
+
const isMin = n === min;
|
|
29151
|
+
const isMax = n === max;
|
|
29152
|
+
const shouldRender = isOnStep && !isNegativeOne && !isMin && !isMax;
|
|
29153
|
+
return shouldRender ? `${n}` : "";
|
|
29154
|
+
};
|
|
29155
|
+
|
|
29156
|
+
/**
|
|
29157
|
+
* axisOptions determine axis options for Mafs
|
|
29158
|
+
*
|
|
29159
|
+
* axisIndex is for grabbing data in an array that contains
|
|
29160
|
+
* data for multiple axes. For example range: [[-10, 10], [-10, 10]]
|
|
29161
|
+
* range[0] is data for the x axis and range[1] is data for the y axis
|
|
29162
|
+
*
|
|
29163
|
+
* @param {GridProps} props
|
|
29164
|
+
* @param {number} axisIndex which axis we're getting options for
|
|
29165
|
+
*/
|
|
29166
|
+
const axisOptions = (props, axisIndex) => {
|
|
29167
|
+
const axisStep = props.tickStep[axisIndex];
|
|
29168
|
+
const axisRange = props.range[axisIndex];
|
|
29169
|
+
return {
|
|
29170
|
+
axis: props.markings === "graph",
|
|
29171
|
+
lines: props.gridStep[axisIndex],
|
|
29172
|
+
labels: n => lineLabelText(n, axisStep, axisRange)
|
|
29173
|
+
};
|
|
29174
|
+
};
|
|
29175
|
+
const Grid = props => {
|
|
29176
|
+
return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
29177
|
+
xAxis: axisOptions(props, 0),
|
|
29178
|
+
yAxis: axisOptions(props, 1)
|
|
29179
|
+
}), /*#__PURE__*/React__namespace.createElement(AxisTicks, {
|
|
29180
|
+
range: props.range,
|
|
29181
|
+
tickStep: props.tickStep
|
|
29182
|
+
}), props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisArrows, null));
|
|
29028
29183
|
};
|
|
29029
|
-
const axisOptions = (props, index) => ({
|
|
29030
|
-
axis: props.markings === "graph",
|
|
29031
|
-
lines: props.step[index],
|
|
29032
|
-
subdivisions: props.step[index] / props.gridStep[index],
|
|
29033
|
-
labels: n => renderLineLabel(n, props.range[index]) ? n : ""
|
|
29034
|
-
});
|
|
29035
|
-
const Grid = props => props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
29036
|
-
xAxis: axisOptions(props, 0),
|
|
29037
|
-
yAxis: axisOptions(props, 1)
|
|
29038
|
-
}), props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisArrows, null));
|
|
29039
29184
|
|
|
29040
29185
|
// Displays a stylized open eye: lint warnings are visible
|
|
29041
29186
|
const VisibleIcon = () => /*#__PURE__*/React__namespace.createElement("svg", {
|
|
@@ -29743,6 +29888,10 @@ function interactiveGraphReducer(state, action) {
|
|
|
29743
29888
|
return doMoveAll(state, action);
|
|
29744
29889
|
case MOVE_POINT:
|
|
29745
29890
|
return doMovePoint(state, action);
|
|
29891
|
+
case CHANGE_SNAP_STEP:
|
|
29892
|
+
return doChangeSnapStep(state, action);
|
|
29893
|
+
case CHANGE_RANGE:
|
|
29894
|
+
return doChangeRange(state, action);
|
|
29746
29895
|
default:
|
|
29747
29896
|
throw new wonderStuffCore.UnreachableCaseError(action);
|
|
29748
29897
|
}
|
|
@@ -29764,14 +29913,11 @@ function doMoveControlPoint(state, action) {
|
|
|
29764
29913
|
update: tuple => setAtIndex({
|
|
29765
29914
|
array: tuple,
|
|
29766
29915
|
index: action.pointIndex,
|
|
29767
|
-
newValue: snap({
|
|
29916
|
+
newValue: snap(snapStep, bound$1({
|
|
29768
29917
|
snapStep,
|
|
29769
|
-
|
|
29770
|
-
|
|
29771
|
-
|
|
29772
|
-
point: action.destination
|
|
29773
|
-
})
|
|
29774
|
-
})
|
|
29918
|
+
range,
|
|
29919
|
+
point: action.destination
|
|
29920
|
+
}))
|
|
29775
29921
|
})
|
|
29776
29922
|
});
|
|
29777
29923
|
const coordsToCheck = newCoords[action.itemIndex];
|
|
@@ -29815,13 +29961,7 @@ function doMoveLine(state, action) {
|
|
|
29815
29961
|
snapStep,
|
|
29816
29962
|
range
|
|
29817
29963
|
});
|
|
29818
|
-
const newLine = [snap(
|
|
29819
|
-
snapStep,
|
|
29820
|
-
point: mafs.vec.add(currentLine[0], change)
|
|
29821
|
-
}), snap({
|
|
29822
|
-
snapStep,
|
|
29823
|
-
point: mafs.vec.add(currentLine[1], change)
|
|
29824
|
-
})];
|
|
29964
|
+
const newLine = [snap(snapStep, mafs.vec.add(currentLine[0], change)), snap(snapStep, mafs.vec.add(currentLine[1], change))];
|
|
29825
29965
|
const newCoords = setAtIndex({
|
|
29826
29966
|
array: state.coords,
|
|
29827
29967
|
index: action.itemIndex,
|
|
@@ -29852,10 +29992,7 @@ function doMoveAll(state, action) {
|
|
|
29852
29992
|
snapStep,
|
|
29853
29993
|
range
|
|
29854
29994
|
});
|
|
29855
|
-
const newCoords = state.coords.map(point => snap(
|
|
29856
|
-
snapStep,
|
|
29857
|
-
point: mafs.vec.add(point, change)
|
|
29858
|
-
}));
|
|
29995
|
+
const newCoords = state.coords.map(point => snap(snapStep, mafs.vec.add(point, change)));
|
|
29859
29996
|
return {
|
|
29860
29997
|
...state,
|
|
29861
29998
|
hasBeenInteractedWith: true,
|
|
@@ -29878,14 +30015,11 @@ function doMovePoint(state, action) {
|
|
|
29878
30015
|
coords: setAtIndex({
|
|
29879
30016
|
array: state.coords,
|
|
29880
30017
|
index: action.index,
|
|
29881
|
-
newValue: snap({
|
|
30018
|
+
newValue: snap(state.snapStep, bound$1({
|
|
29882
30019
|
snapStep: state.snapStep,
|
|
29883
|
-
|
|
29884
|
-
|
|
29885
|
-
|
|
29886
|
-
point: action.destination
|
|
29887
|
-
})
|
|
29888
|
-
})
|
|
30020
|
+
range: state.range,
|
|
30021
|
+
point: action.destination
|
|
30022
|
+
}))
|
|
29889
30023
|
})
|
|
29890
30024
|
};
|
|
29891
30025
|
}
|
|
@@ -29893,6 +30027,28 @@ function doMovePoint(state, action) {
|
|
|
29893
30027
|
throw new Error("The movePoint action is only for point and polygon graphs");
|
|
29894
30028
|
}
|
|
29895
30029
|
}
|
|
30030
|
+
function doChangeSnapStep(state, action) {
|
|
30031
|
+
if (
|
|
30032
|
+
// Deep equality check since these are arrays
|
|
30033
|
+
___default["default"].isEqual(state.snapStep, action.snapStep)) {
|
|
30034
|
+
return state;
|
|
30035
|
+
}
|
|
30036
|
+
return {
|
|
30037
|
+
...state,
|
|
30038
|
+
snapStep: action.snapStep
|
|
30039
|
+
};
|
|
30040
|
+
}
|
|
30041
|
+
function doChangeRange(state, action) {
|
|
30042
|
+
if (
|
|
30043
|
+
// Deep equality check since these are arrays
|
|
30044
|
+
___default["default"].isEqual(state.range, action.range)) {
|
|
30045
|
+
return state;
|
|
30046
|
+
}
|
|
30047
|
+
return {
|
|
30048
|
+
...state,
|
|
30049
|
+
range: action.range
|
|
30050
|
+
};
|
|
30051
|
+
}
|
|
29896
30052
|
const getChange = (coords, delta, constraintOpts) => {
|
|
29897
30053
|
const [deltaX, deltaY] = delta;
|
|
29898
30054
|
const maxMoves = coords.map(point => maxMove({
|
|
@@ -29911,24 +30067,14 @@ const getChange = (coords, delta, constraintOpts) => {
|
|
|
29911
30067
|
const dy = clamp(deltaY, minYMove, maxYMove);
|
|
29912
30068
|
return [dx, dy];
|
|
29913
30069
|
};
|
|
29914
|
-
function snap(_ref) {
|
|
29915
|
-
let {
|
|
29916
|
-
snapStep,
|
|
29917
|
-
point
|
|
29918
|
-
} = _ref;
|
|
29919
|
-
const [requestedX, requestedY] = point;
|
|
29920
|
-
const [snapX, snapY] = snapStep;
|
|
29921
|
-
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29922
|
-
}
|
|
29923
|
-
|
|
29924
30070
|
// Returns the closest point to the given `point` that is within the graph
|
|
29925
30071
|
// bounds given in `state`.
|
|
29926
|
-
function bound$1(
|
|
30072
|
+
function bound$1(_ref) {
|
|
29927
30073
|
let {
|
|
29928
30074
|
snapStep,
|
|
29929
30075
|
range,
|
|
29930
30076
|
point
|
|
29931
|
-
} =
|
|
30077
|
+
} = _ref;
|
|
29932
30078
|
const [requestedX, requestedY] = point;
|
|
29933
30079
|
const [snapX, snapY] = snapStep;
|
|
29934
30080
|
const [[minX, maxX], [minY, maxY]] = range;
|
|
@@ -29936,12 +30082,12 @@ function bound$1(_ref2) {
|
|
|
29936
30082
|
}
|
|
29937
30083
|
|
|
29938
30084
|
// Returns the vector from the given point to the top-right corner of the graph
|
|
29939
|
-
function maxMove(
|
|
30085
|
+
function maxMove(_ref2) {
|
|
29940
30086
|
let {
|
|
29941
30087
|
snapStep,
|
|
29942
30088
|
range,
|
|
29943
30089
|
point
|
|
29944
|
-
} =
|
|
30090
|
+
} = _ref2;
|
|
29945
30091
|
const topRight = bound$1({
|
|
29946
30092
|
snapStep,
|
|
29947
30093
|
range,
|
|
@@ -29952,12 +30098,12 @@ function maxMove(_ref3) {
|
|
|
29952
30098
|
|
|
29953
30099
|
// Returns the vector from the given point to the bottom-left corner of the
|
|
29954
30100
|
// graph
|
|
29955
|
-
function minMove(
|
|
30101
|
+
function minMove(_ref3) {
|
|
29956
30102
|
let {
|
|
29957
30103
|
snapStep,
|
|
29958
30104
|
range,
|
|
29959
30105
|
point
|
|
29960
|
-
} =
|
|
30106
|
+
} = _ref3;
|
|
29961
30107
|
const bottomLeft = bound$1({
|
|
29962
30108
|
snapStep,
|
|
29963
30109
|
range,
|
|
@@ -30282,6 +30428,18 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
|
30282
30428
|
}
|
|
30283
30429
|
prevState.current = state;
|
|
30284
30430
|
}, [props, state]);
|
|
30431
|
+
|
|
30432
|
+
// Destructuring first to keep useEffect from making excess calls
|
|
30433
|
+
const [xSnap, ySnap] = props.snapStep;
|
|
30434
|
+
React.useEffect(() => {
|
|
30435
|
+
dispatch(changeSnapStep([xSnap, ySnap]));
|
|
30436
|
+
}, [xSnap, ySnap]);
|
|
30437
|
+
|
|
30438
|
+
// Destructuring first to keep useEffect from making excess calls
|
|
30439
|
+
const [[xMinRange, xMaxRange], [yMinRange, yMaxRange]] = props.range;
|
|
30440
|
+
React.useEffect(() => {
|
|
30441
|
+
dispatch(changeRange([[xMinRange, xMaxRange], [yMinRange, yMaxRange]]));
|
|
30442
|
+
}, [xMinRange, xMaxRange, yMinRange, yMaxRange]);
|
|
30285
30443
|
React__namespace.useImperativeHandle(ref, () => ({
|
|
30286
30444
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
30287
30445
|
}));
|
|
@@ -30316,7 +30474,13 @@ const MafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
|
30316
30474
|
zoom: false,
|
|
30317
30475
|
width: width,
|
|
30318
30476
|
height: height
|
|
30319
|
-
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid,
|
|
30477
|
+
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
30478
|
+
tickStep: props.step,
|
|
30479
|
+
gridStep: props.gridStep,
|
|
30480
|
+
range: props.range,
|
|
30481
|
+
containerSizeClass: props.containerSizeClass,
|
|
30482
|
+
markings: props.markings
|
|
30483
|
+
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
30320
30484
|
lockedFigures: props.lockedFigures
|
|
30321
30485
|
}), renderGraph({
|
|
30322
30486
|
state,
|
|
@@ -32066,8 +32230,8 @@ class InteractiveGraph extends React__namespace.Component {
|
|
|
32066
32230
|
};
|
|
32067
32231
|
}
|
|
32068
32232
|
} else if (userInput.type === "segment" && rubric.correct.type === "segment" && userInput.coords != null) {
|
|
32069
|
-
let guess = userInput.coords
|
|
32070
|
-
let correct = rubric.correct
|
|
32233
|
+
let guess = Util.deepClone(userInput.coords);
|
|
32234
|
+
let correct = Util.deepClone(rubric.correct?.coords);
|
|
32071
32235
|
guess = ___default["default"].invoke(guess, "sort").sort();
|
|
32072
32236
|
// @ts-expect-error - TS2345 - Argument of type '(readonly Coord[])[] | undefined' is not assignable to parameter of type 'Collection<any>'.
|
|
32073
32237
|
correct = ___default["default"].invoke(correct, "sort").sort();
|
|
@@ -42329,7 +42493,7 @@ const init = function (options) {
|
|
|
42329
42493
|
|
|
42330
42494
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
42331
42495
|
const libName = "@khanacademy/perseus";
|
|
42332
|
-
const libVersion = "21.1
|
|
42496
|
+
const libVersion = "21.2.1";
|
|
42333
42497
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
42334
42498
|
|
|
42335
42499
|
const apiVersion = {
|
|
@@ -43458,6 +43622,9 @@ const ItemExtras = [
|
|
|
43458
43622
|
// A background image applied to various widgets.
|
|
43459
43623
|
|
|
43460
43624
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
43625
|
+
|
|
43626
|
+
// 2D range: xMin, xMax, yMin, yMax
|
|
43627
|
+
|
|
43461
43628
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
43462
43629
|
|
|
43463
43630
|
/**
|