@khanacademy/perseus 22.3.0 → 22.4.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 +3 -1
- package/dist/es/index.js +688 -459
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +3 -1
- package/dist/index.js +709 -471
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -0
- package/dist/perseus-types.d.ts +0 -1
- package/dist/server-item-renderer.d.ts +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/widgets/expression.d.ts +6 -0
- package/dist/widgets/interactive-graphs/graphs/circle.d.ts +5 -0
- package/dist/widgets/interactive-graphs/graphs/components/movable-point-view.d.ts +17 -0
- package/dist/widgets/interactive-graphs/graphs/components/segment.d.ts +27 -0
- package/dist/widgets/interactive-graphs/graphs/index.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +1 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +9 -8
- package/dist/widgets/interactive-graphs/mafs-supported-graph-types.d.ts +1 -1
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-action.d.ts +13 -1
- package/dist/widgets/interactive-graphs/reducer/interactive-graph-state.d.ts +8 -1
- package/dist/widgets/interactive-graphs/types.d.ts +2 -2
- package/dist/widgets/label-image.d.ts +2 -0
- package/package.json +2 -2
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +0 -17
- package/dist/widgets/interactive-graphs/graphs/types.d.ts +0 -6
package/dist/index.js
CHANGED
|
@@ -27,8 +27,8 @@ var Button = require('@khanacademy/wonder-blocks-button');
|
|
|
27
27
|
var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
|
|
28
28
|
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
29
29
|
var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
|
|
30
|
-
var caretDown = require('@phosphor-icons/core/
|
|
31
|
-
var caretUp = require('@phosphor-icons/core/
|
|
30
|
+
var caretDown = require('@phosphor-icons/core/regular/caret-down.svg');
|
|
31
|
+
var caretUp = require('@phosphor-icons/core/regular/caret-up.svg');
|
|
32
32
|
var debounce$1 = require('lodash.debounce');
|
|
33
33
|
var mafs = require('mafs');
|
|
34
34
|
var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
|
|
@@ -477,7 +477,7 @@ class InnerMathInput extends React__namespace.Component {
|
|
|
477
477
|
locale
|
|
478
478
|
} = this.context;
|
|
479
479
|
// Initialize MathQuill.MathField instance
|
|
480
|
-
this.__mathField = mathInput.createMathField(this.__mathFieldWrapperRef, this.props.mathInputStrings, baseConfig => ({
|
|
480
|
+
this.__mathField = mathInput.createMathField(this.__mathFieldWrapperRef, locale, this.props.mathInputStrings, baseConfig => ({
|
|
481
481
|
...baseConfig,
|
|
482
482
|
handlers: {
|
|
483
483
|
edit: debounce(mathField => {
|
|
@@ -29012,6 +29012,7 @@ const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).
|
|
|
29012
29012
|
function Arrowhead(props) {
|
|
29013
29013
|
const [point] = useTransformVectorsToPixels(props.tip);
|
|
29014
29014
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29015
|
+
className: "interactive-graph-arrowhead",
|
|
29015
29016
|
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
29016
29017
|
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29017
29018
|
transform: "translate(-1.5)"
|
|
@@ -29026,49 +29027,7 @@ function Arrowhead(props) {
|
|
|
29026
29027
|
})));
|
|
29027
29028
|
}
|
|
29028
29029
|
|
|
29029
|
-
function
|
|
29030
|
-
const {
|
|
29031
|
-
start,
|
|
29032
|
-
end,
|
|
29033
|
-
style,
|
|
29034
|
-
className,
|
|
29035
|
-
testId
|
|
29036
|
-
} = props;
|
|
29037
|
-
return /*#__PURE__*/React__namespace.createElement("line", {
|
|
29038
|
-
x1: start[0],
|
|
29039
|
-
y1: start[1],
|
|
29040
|
-
x2: end[0],
|
|
29041
|
-
y2: end[1],
|
|
29042
|
-
style: style,
|
|
29043
|
-
className: className,
|
|
29044
|
-
"data-testid": testId
|
|
29045
|
-
});
|
|
29046
|
-
}
|
|
29047
|
-
|
|
29048
|
-
function Vector(props) {
|
|
29049
|
-
const {
|
|
29050
|
-
tail,
|
|
29051
|
-
tip,
|
|
29052
|
-
color,
|
|
29053
|
-
style
|
|
29054
|
-
} = props;
|
|
29055
|
-
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
29056
|
-
const direction = mafs.vec.sub(tip, tail);
|
|
29057
|
-
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29058
|
-
style: {
|
|
29059
|
-
stroke: color,
|
|
29060
|
-
strokeWidth: 2
|
|
29061
|
-
}
|
|
29062
|
-
}, /*#__PURE__*/React__namespace.createElement(SVGLine, {
|
|
29063
|
-
start: tailPx,
|
|
29064
|
-
end: tipPx,
|
|
29065
|
-
style: style
|
|
29066
|
-
}), /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29067
|
-
tip: tip,
|
|
29068
|
-
angle: angleDegrees(direction)
|
|
29069
|
-
}));
|
|
29070
|
-
}
|
|
29071
|
-
function angleDegrees(_ref) {
|
|
29030
|
+
function calculateAngleInDegrees(_ref) {
|
|
29072
29031
|
let [x, y] = _ref;
|
|
29073
29032
|
return Math.atan2(y, x) * 180 / Math.PI;
|
|
29074
29033
|
}
|
|
@@ -29111,10 +29070,57 @@ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
|
29111
29070
|
return [xMax, yAtXMax];
|
|
29112
29071
|
}
|
|
29113
29072
|
};
|
|
29114
|
-
const getLines = points =>
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29073
|
+
const getLines = points => {
|
|
29074
|
+
return points.map((point, i) => {
|
|
29075
|
+
const next = points[(i + 1) % points.length];
|
|
29076
|
+
return [point, next];
|
|
29077
|
+
});
|
|
29078
|
+
};
|
|
29079
|
+
|
|
29080
|
+
function SVGLine(props) {
|
|
29081
|
+
const {
|
|
29082
|
+
start,
|
|
29083
|
+
end,
|
|
29084
|
+
style,
|
|
29085
|
+
className,
|
|
29086
|
+
testId
|
|
29087
|
+
} = props;
|
|
29088
|
+
return /*#__PURE__*/React__namespace.createElement("line", {
|
|
29089
|
+
x1: start[0],
|
|
29090
|
+
y1: start[1],
|
|
29091
|
+
x2: end[0],
|
|
29092
|
+
y2: end[1],
|
|
29093
|
+
style: style,
|
|
29094
|
+
className: className,
|
|
29095
|
+
"data-testid": testId
|
|
29096
|
+
});
|
|
29097
|
+
}
|
|
29098
|
+
|
|
29099
|
+
function Vector(props) {
|
|
29100
|
+
const {
|
|
29101
|
+
tail,
|
|
29102
|
+
tip,
|
|
29103
|
+
color,
|
|
29104
|
+
style
|
|
29105
|
+
} = props;
|
|
29106
|
+
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
29107
|
+
const direction = mafs.vec.sub(tip, tail);
|
|
29108
|
+
const angle = calculateAngleInDegrees(direction);
|
|
29109
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29110
|
+
style: {
|
|
29111
|
+
stroke: color,
|
|
29112
|
+
strokeWidth: 2
|
|
29113
|
+
}
|
|
29114
|
+
}, /*#__PURE__*/React__namespace.createElement(SVGLine, {
|
|
29115
|
+
start: tailPx,
|
|
29116
|
+
end: tipPx,
|
|
29117
|
+
style: style
|
|
29118
|
+
}), /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29119
|
+
angle: angle,
|
|
29120
|
+
tip: tip,
|
|
29121
|
+
color: color
|
|
29122
|
+
}));
|
|
29123
|
+
}
|
|
29118
29124
|
|
|
29119
29125
|
const LockedLine = props => {
|
|
29120
29126
|
const {
|
|
@@ -29130,27 +29136,38 @@ const LockedLine = props => {
|
|
|
29130
29136
|
let line;
|
|
29131
29137
|
if (kind === "ray") {
|
|
29132
29138
|
// Rays extend to the end of the graph in one direction.
|
|
29133
|
-
const
|
|
29139
|
+
const extendedPoint = getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
29134
29140
|
line = /*#__PURE__*/React__namespace.createElement(Vector, {
|
|
29135
29141
|
tail: point1.coord,
|
|
29136
|
-
tip:
|
|
29142
|
+
tip: extendedPoint,
|
|
29137
29143
|
color: lockedFigureColors[color],
|
|
29138
29144
|
style: {
|
|
29139
|
-
strokeDasharray: lineStyle === "dashed" ?
|
|
29140
|
-
// TODO(lems-1930): Uncomment this line when the
|
|
29141
|
-
// dashed style is updated in Mafs.
|
|
29142
|
-
// ? "var(--mafs-line-stroke-dash-style)"
|
|
29143
|
-
"4, 3" : undefined
|
|
29145
|
+
strokeDasharray: lineStyle === "dashed" ? "var(--mafs-line-stroke-dash-style)" : undefined
|
|
29144
29146
|
}
|
|
29145
29147
|
});
|
|
29146
29148
|
} else {
|
|
29147
29149
|
const LineType = kind === "segment" ? mafs.Line.Segment : mafs.Line.ThroughPoints;
|
|
29148
|
-
|
|
29150
|
+
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
29151
|
+
const direction = mafs.vec.sub(point2.coord, point1.coord);
|
|
29152
|
+
let angle = calculateAngleInDegrees(direction);
|
|
29153
|
+
const startArrowHead = kind !== "segment" && /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29154
|
+
angle: angle,
|
|
29155
|
+
tip: arrowTip,
|
|
29156
|
+
color: lockedFigureColors[color]
|
|
29157
|
+
});
|
|
29158
|
+
arrowTip = kind === "segment" ? point1.coord : getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
29159
|
+
angle = angle > 180 ? angle - 180 : angle + 180;
|
|
29160
|
+
const endArrowHead = kind !== "segment" && /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29161
|
+
angle: angle,
|
|
29162
|
+
tip: arrowTip,
|
|
29163
|
+
color: lockedFigureColors[color]
|
|
29164
|
+
});
|
|
29165
|
+
line = /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, startArrowHead, /*#__PURE__*/React__namespace.createElement(LineType, {
|
|
29149
29166
|
point1: point1.coord,
|
|
29150
29167
|
point2: point2.coord,
|
|
29151
29168
|
color: lockedFigureColors[color],
|
|
29152
29169
|
style: lineStyle
|
|
29153
|
-
});
|
|
29170
|
+
}), endArrowHead);
|
|
29154
29171
|
}
|
|
29155
29172
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29156
29173
|
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
@@ -29256,6 +29273,20 @@ function movePoint(index, destination) {
|
|
|
29256
29273
|
destination
|
|
29257
29274
|
};
|
|
29258
29275
|
}
|
|
29276
|
+
const MOVE_CENTER = "move-center";
|
|
29277
|
+
function moveCenter(destination) {
|
|
29278
|
+
return {
|
|
29279
|
+
type: MOVE_CENTER,
|
|
29280
|
+
destination
|
|
29281
|
+
};
|
|
29282
|
+
}
|
|
29283
|
+
const MOVE_RADIUS_POINT = "MOVE_RADIUS_POINT";
|
|
29284
|
+
function moveRadiusPoint(destination) {
|
|
29285
|
+
return {
|
|
29286
|
+
type: MOVE_RADIUS_POINT,
|
|
29287
|
+
destination
|
|
29288
|
+
};
|
|
29289
|
+
}
|
|
29259
29290
|
const CHANGE_SNAP_STEP = "change-snap-step";
|
|
29260
29291
|
function changeSnapStep(snapStep) {
|
|
29261
29292
|
return {
|
|
@@ -29302,6 +29333,194 @@ function snap(snapStep, point) {
|
|
|
29302
29333
|
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29303
29334
|
}
|
|
29304
29335
|
|
|
29336
|
+
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
29337
|
+
// graph.
|
|
29338
|
+
const hitboxSizePx = 48;
|
|
29339
|
+
|
|
29340
|
+
// MovablePointView is a purely presentational component (i.e. it is a pure
|
|
29341
|
+
// function with no state or effects) that renders the SVG for a movable point
|
|
29342
|
+
// on an interactive graph.
|
|
29343
|
+
//
|
|
29344
|
+
// It has two modes for managing tabbing / focus: "controlled" (where the caller
|
|
29345
|
+
// manages the display of the focus ring, and the point itself cannot be
|
|
29346
|
+
// focused) and "uncontrolled" (where the point is focusable, and the browser
|
|
29347
|
+
// manages the focus state and styling). For context on why we did this, see
|
|
29348
|
+
// the description of https://github.com/Khan/perseus/pull/1240
|
|
29349
|
+
const MovablePointView = /*#__PURE__*/React.forwardRef((props, hitboxRef) => {
|
|
29350
|
+
const {
|
|
29351
|
+
range,
|
|
29352
|
+
markings,
|
|
29353
|
+
showTooltips
|
|
29354
|
+
} = useGraphConfig();
|
|
29355
|
+
const {
|
|
29356
|
+
point,
|
|
29357
|
+
color = wonderBlocksTokens.color.blue,
|
|
29358
|
+
dragging,
|
|
29359
|
+
focusBehavior
|
|
29360
|
+
} = props;
|
|
29361
|
+
|
|
29362
|
+
// WB Tooltip requires a color name for the background color.
|
|
29363
|
+
// Since the color in props is a hex value, a reverse lookup is needed.
|
|
29364
|
+
const wbColorName = Object.entries(wonderBlocksTokens.color).find(_ref => {
|
|
29365
|
+
let [_, value] = _ref;
|
|
29366
|
+
return value === color;
|
|
29367
|
+
})?.[0] ?? "blue";
|
|
29368
|
+
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""} ${focusClass(focusBehavior)}`;
|
|
29369
|
+
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
29370
|
+
const [xMin, xMax] = range[0];
|
|
29371
|
+
const [yMin, yMax] = range[1];
|
|
29372
|
+
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
29373
|
+
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
29374
|
+
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
29375
|
+
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
29376
|
+
const showHairlines = dragging && markings !== "none";
|
|
29377
|
+
const hairlines = /*#__PURE__*/React__namespace.createElement("g", null, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29378
|
+
x1: verticalStartX,
|
|
29379
|
+
y1: y,
|
|
29380
|
+
x2: verticalEndX,
|
|
29381
|
+
y2: y,
|
|
29382
|
+
stroke: color
|
|
29383
|
+
}), /*#__PURE__*/React__namespace.createElement("line", {
|
|
29384
|
+
x1: x,
|
|
29385
|
+
y1: horizontalStartY,
|
|
29386
|
+
x2: x,
|
|
29387
|
+
y2: horizontalEndY,
|
|
29388
|
+
stroke: color
|
|
29389
|
+
}));
|
|
29390
|
+
const svgForPoint = /*#__PURE__*/React__namespace.createElement("g", {
|
|
29391
|
+
ref: hitboxRef,
|
|
29392
|
+
className: pointClasses,
|
|
29393
|
+
style: {
|
|
29394
|
+
"--movable-point-color": color
|
|
29395
|
+
},
|
|
29396
|
+
"data-testid": "movable-point",
|
|
29397
|
+
tabIndex: tabIndex(focusBehavior)
|
|
29398
|
+
}, /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29399
|
+
className: "movable-point-hitbox",
|
|
29400
|
+
r: hitboxSizePx / 2,
|
|
29401
|
+
cx: x,
|
|
29402
|
+
cy: y
|
|
29403
|
+
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29404
|
+
className: "movable-point-halo",
|
|
29405
|
+
cx: x,
|
|
29406
|
+
cy: y
|
|
29407
|
+
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29408
|
+
className: "movable-point-ring",
|
|
29409
|
+
cx: x,
|
|
29410
|
+
cy: y
|
|
29411
|
+
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29412
|
+
className: "movable-point-focus-outline",
|
|
29413
|
+
cx: x,
|
|
29414
|
+
cy: y
|
|
29415
|
+
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29416
|
+
className: "movable-point-center",
|
|
29417
|
+
cx: x,
|
|
29418
|
+
cy: y,
|
|
29419
|
+
style: {
|
|
29420
|
+
fill: color
|
|
29421
|
+
},
|
|
29422
|
+
"data-testid": "movable-point__center"
|
|
29423
|
+
}));
|
|
29424
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
29425
|
+
autoUpdate: true,
|
|
29426
|
+
backgroundColor: wbColorName,
|
|
29427
|
+
content: `(${point[0]}, ${point[1]})`,
|
|
29428
|
+
contentStyle: {
|
|
29429
|
+
color: "white"
|
|
29430
|
+
}
|
|
29431
|
+
}, svgForPoint) : svgForPoint);
|
|
29432
|
+
});
|
|
29433
|
+
function focusClass(config) {
|
|
29434
|
+
if (config.type === "controlled" && config.showFocusRing) {
|
|
29435
|
+
return "movable-point--focus";
|
|
29436
|
+
}
|
|
29437
|
+
return "";
|
|
29438
|
+
}
|
|
29439
|
+
function tabIndex(config) {
|
|
29440
|
+
if (config.type === "uncontrolled") {
|
|
29441
|
+
return config.tabIndex;
|
|
29442
|
+
}
|
|
29443
|
+
return undefined;
|
|
29444
|
+
}
|
|
29445
|
+
|
|
29446
|
+
const Segment = props => {
|
|
29447
|
+
const {
|
|
29448
|
+
onMoveLine,
|
|
29449
|
+
color,
|
|
29450
|
+
points: [start, end],
|
|
29451
|
+
extend
|
|
29452
|
+
} = props;
|
|
29453
|
+
|
|
29454
|
+
// We use separate focusableHandle elements, instead of letting the movable
|
|
29455
|
+
// points themselves be focusable, to allow the tab order of the points to
|
|
29456
|
+
// be different from the rendering order. We had to solve for the following
|
|
29457
|
+
// constraints:
|
|
29458
|
+
// - SVG has no equivalent of z-index, so the order of elements in the
|
|
29459
|
+
// document determines the order in which they're painted. We want the
|
|
29460
|
+
// movable line segment to render behind its endpoints (it looks weird
|
|
29461
|
+
// otherwise) so we have to render the line first.
|
|
29462
|
+
// - There isn't a browser-native way to customize tab order, other than
|
|
29463
|
+
// setting tabindex > 0. But that bumps elements to the front of the
|
|
29464
|
+
// tab order for the entire page, which is not what we want.
|
|
29465
|
+
const {
|
|
29466
|
+
visiblePoint: visiblePoint1,
|
|
29467
|
+
focusableHandle: focusableHandle1
|
|
29468
|
+
} = useControlPoint(start, color, p => props.onMovePoint(0, p));
|
|
29469
|
+
const {
|
|
29470
|
+
visiblePoint: visiblePoint2,
|
|
29471
|
+
focusableHandle: focusableHandle2
|
|
29472
|
+
} = useControlPoint(end, color, p => props.onMovePoint(1, p));
|
|
29473
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, focusableHandle1, /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
29474
|
+
start: start,
|
|
29475
|
+
end: end,
|
|
29476
|
+
stroke: color,
|
|
29477
|
+
extend: extend,
|
|
29478
|
+
onMove: onMoveLine
|
|
29479
|
+
}), focusableHandle2, visiblePoint1, visiblePoint2);
|
|
29480
|
+
};
|
|
29481
|
+
function useControlPoint(point, color, onMovePoint) {
|
|
29482
|
+
const {
|
|
29483
|
+
snapStep
|
|
29484
|
+
} = useGraphConfig();
|
|
29485
|
+
const [focused, setFocused] = React.useState(false);
|
|
29486
|
+
const keyboardHandleRef = React.useRef(null);
|
|
29487
|
+
mafs.useMovable({
|
|
29488
|
+
gestureTarget: keyboardHandleRef,
|
|
29489
|
+
point,
|
|
29490
|
+
onMove: onMovePoint,
|
|
29491
|
+
constrain: p => snap(snapStep, p)
|
|
29492
|
+
});
|
|
29493
|
+
const visiblePointRef = React.useRef(null);
|
|
29494
|
+
const {
|
|
29495
|
+
dragging
|
|
29496
|
+
} = mafs.useMovable({
|
|
29497
|
+
gestureTarget: visiblePointRef,
|
|
29498
|
+
point,
|
|
29499
|
+
onMove: onMovePoint,
|
|
29500
|
+
constrain: p => snap(snapStep, p)
|
|
29501
|
+
});
|
|
29502
|
+
const focusableHandle = /*#__PURE__*/React__namespace.createElement("g", {
|
|
29503
|
+
"data-testid": "movable-point__focusable-handle",
|
|
29504
|
+
tabIndex: 0,
|
|
29505
|
+
ref: keyboardHandleRef,
|
|
29506
|
+
onFocus: () => setFocused(true),
|
|
29507
|
+
onBlur: () => setFocused(false)
|
|
29508
|
+
});
|
|
29509
|
+
const visiblePoint = /*#__PURE__*/React__namespace.createElement(MovablePointView, {
|
|
29510
|
+
point: point,
|
|
29511
|
+
dragging: dragging,
|
|
29512
|
+
color: color,
|
|
29513
|
+
ref: visiblePointRef,
|
|
29514
|
+
focusBehavior: {
|
|
29515
|
+
type: "controlled",
|
|
29516
|
+
showFocusRing: focused
|
|
29517
|
+
}
|
|
29518
|
+
});
|
|
29519
|
+
return {
|
|
29520
|
+
focusableHandle,
|
|
29521
|
+
visiblePoint
|
|
29522
|
+
};
|
|
29523
|
+
}
|
|
29305
29524
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
29306
29525
|
const MovableLine = props => {
|
|
29307
29526
|
const {
|
|
@@ -29314,12 +29533,13 @@ const MovableLine = props => {
|
|
|
29314
29533
|
const midpoint = mafs.vec.midpoint(start, end);
|
|
29315
29534
|
const [startPtPx, endPtPx] = useTransformVectorsToPixels(start, end);
|
|
29316
29535
|
const {
|
|
29536
|
+
range,
|
|
29317
29537
|
graphDimensionsInPixels
|
|
29318
29538
|
} = useGraphConfig();
|
|
29319
29539
|
let startExtend = undefined;
|
|
29320
29540
|
let endExtend = undefined;
|
|
29321
29541
|
if (extend) {
|
|
29322
|
-
const trimmedRange = trimRange(
|
|
29542
|
+
const trimmedRange = trimRange(range, graphDimensionsInPixels);
|
|
29323
29543
|
startExtend = extend.start ? getIntersectionOfRayWithBox(start, end, trimmedRange) : undefined;
|
|
29324
29544
|
endExtend = extend.end ? getIntersectionOfRayWithBox(end, start, trimmedRange) : undefined;
|
|
29325
29545
|
}
|
|
@@ -29398,103 +29618,6 @@ function size(interval) {
|
|
|
29398
29618
|
return interval[1] - interval[0];
|
|
29399
29619
|
}
|
|
29400
29620
|
|
|
29401
|
-
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
29402
|
-
// graph.
|
|
29403
|
-
const hitboxSizePx = 48;
|
|
29404
|
-
const StyledMovablePoint = props => {
|
|
29405
|
-
const {
|
|
29406
|
-
range,
|
|
29407
|
-
snapStep,
|
|
29408
|
-
markings,
|
|
29409
|
-
showTooltips
|
|
29410
|
-
} = useGraphConfig();
|
|
29411
|
-
const hitboxRef = React.useRef(null);
|
|
29412
|
-
const {
|
|
29413
|
-
point,
|
|
29414
|
-
onMove,
|
|
29415
|
-
color = wonderBlocksTokens.color.blue
|
|
29416
|
-
} = props;
|
|
29417
|
-
|
|
29418
|
-
// WB Tooltip requires a color name for the background color.
|
|
29419
|
-
// Since the color in props is a hex value, a reverse lookup is needed.
|
|
29420
|
-
const wbColorName = Object.entries(wonderBlocksTokens.color).find(_ref => {
|
|
29421
|
-
let [_, value] = _ref;
|
|
29422
|
-
return value === color;
|
|
29423
|
-
})?.[0] ?? "blue";
|
|
29424
|
-
const {
|
|
29425
|
-
dragging
|
|
29426
|
-
} = mafs.useMovable({
|
|
29427
|
-
gestureTarget: hitboxRef,
|
|
29428
|
-
point,
|
|
29429
|
-
onMove,
|
|
29430
|
-
constrain: p => snap(snapStep, p)
|
|
29431
|
-
});
|
|
29432
|
-
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
|
|
29433
|
-
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
29434
|
-
const [xMin, xMax] = range[0];
|
|
29435
|
-
const [yMin, yMax] = range[1];
|
|
29436
|
-
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
29437
|
-
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
29438
|
-
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
29439
|
-
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
29440
|
-
const showHairlines = dragging && markings !== "none";
|
|
29441
|
-
const hairlines = /*#__PURE__*/React__namespace.createElement("g", null, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29442
|
-
x1: verticalStartX,
|
|
29443
|
-
y1: y,
|
|
29444
|
-
x2: verticalEndX,
|
|
29445
|
-
y2: y,
|
|
29446
|
-
stroke: color
|
|
29447
|
-
}), /*#__PURE__*/React__namespace.createElement("line", {
|
|
29448
|
-
x1: x,
|
|
29449
|
-
y1: horizontalStartY,
|
|
29450
|
-
x2: x,
|
|
29451
|
-
y2: horizontalEndY,
|
|
29452
|
-
stroke: color
|
|
29453
|
-
}));
|
|
29454
|
-
const svgForPoint = /*#__PURE__*/React__namespace.createElement("g", {
|
|
29455
|
-
ref: hitboxRef,
|
|
29456
|
-
className: pointClasses,
|
|
29457
|
-
tabIndex: 0,
|
|
29458
|
-
style: {
|
|
29459
|
-
"--movable-point-color": color
|
|
29460
|
-
},
|
|
29461
|
-
"data-testid": "movable-point"
|
|
29462
|
-
}, /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29463
|
-
className: "movable-point-hitbox",
|
|
29464
|
-
r: hitboxSizePx / 2,
|
|
29465
|
-
cx: x,
|
|
29466
|
-
cy: y
|
|
29467
|
-
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29468
|
-
className: "movable-point-halo",
|
|
29469
|
-
cx: x,
|
|
29470
|
-
cy: y
|
|
29471
|
-
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29472
|
-
className: "movable-point-ring",
|
|
29473
|
-
cx: x,
|
|
29474
|
-
cy: y
|
|
29475
|
-
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29476
|
-
className: "movable-point-focus-outline",
|
|
29477
|
-
cx: x,
|
|
29478
|
-
cy: y
|
|
29479
|
-
}), /*#__PURE__*/React__namespace.createElement("circle", {
|
|
29480
|
-
className: "movable-point-center",
|
|
29481
|
-
cx: x,
|
|
29482
|
-
cy: y,
|
|
29483
|
-
style: {
|
|
29484
|
-
fill: color
|
|
29485
|
-
},
|
|
29486
|
-
"data-testid": "movable-point__center"
|
|
29487
|
-
}));
|
|
29488
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, showHairlines && hairlines, showTooltips ? /*#__PURE__*/React__namespace.createElement(Tooltip__default["default"], {
|
|
29489
|
-
autoUpdate: true,
|
|
29490
|
-
backgroundColor: wbColorName,
|
|
29491
|
-
content: `(${point[0]}, ${point[1]})`,
|
|
29492
|
-
contentStyle: {
|
|
29493
|
-
color: "white"
|
|
29494
|
-
}
|
|
29495
|
-
}, svgForPoint) : svgForPoint);
|
|
29496
|
-
};
|
|
29497
|
-
|
|
29498
29621
|
const SegmentGraph = props => {
|
|
29499
29622
|
const {
|
|
29500
29623
|
dispatch
|
|
@@ -29502,7 +29625,7 @@ const SegmentGraph = props => {
|
|
|
29502
29625
|
const {
|
|
29503
29626
|
coords: segments
|
|
29504
29627
|
} = props.graphState;
|
|
29505
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, segments?.map((segment, i) => /*#__PURE__*/React__namespace.createElement(
|
|
29628
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, segments?.map((segment, i) => /*#__PURE__*/React__namespace.createElement(Segment, {
|
|
29506
29629
|
key: i,
|
|
29507
29630
|
points: segment,
|
|
29508
29631
|
onMoveLine: delta => {
|
|
@@ -29513,27 +29636,6 @@ const SegmentGraph = props => {
|
|
|
29513
29636
|
}
|
|
29514
29637
|
})));
|
|
29515
29638
|
};
|
|
29516
|
-
const SegmentView = props => {
|
|
29517
|
-
const {
|
|
29518
|
-
onMoveLine: onMoveSegment,
|
|
29519
|
-
points: [start, end]
|
|
29520
|
-
} = props;
|
|
29521
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
29522
|
-
start: start,
|
|
29523
|
-
end: end,
|
|
29524
|
-
onMove: onMoveSegment
|
|
29525
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29526
|
-
point: start,
|
|
29527
|
-
onMove: newPoint => {
|
|
29528
|
-
props.onMovePoint(0, newPoint);
|
|
29529
|
-
}
|
|
29530
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29531
|
-
point: end,
|
|
29532
|
-
onMove: newPoint => {
|
|
29533
|
-
props.onMovePoint(1, newPoint);
|
|
29534
|
-
}
|
|
29535
|
-
}));
|
|
29536
|
-
};
|
|
29537
29639
|
|
|
29538
29640
|
const LinearGraph = props => {
|
|
29539
29641
|
const {
|
|
@@ -29543,49 +29645,19 @@ const LinearGraph = props => {
|
|
|
29543
29645
|
coords: lines
|
|
29544
29646
|
} = props.graphState;
|
|
29545
29647
|
const colors = ["var(--movable-line-stroke-color)", "var(--mafs-violet)"];
|
|
29546
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(
|
|
29648
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lines?.map((line, i) => /*#__PURE__*/React__namespace.createElement(Segment, {
|
|
29547
29649
|
key: i,
|
|
29548
29650
|
points: line,
|
|
29549
29651
|
onMoveLine: delta => {
|
|
29550
29652
|
dispatch(moveLine(i, delta));
|
|
29551
29653
|
},
|
|
29552
|
-
onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, i)),
|
|
29553
|
-
stroke: colors[i]
|
|
29554
|
-
})));
|
|
29555
|
-
};
|
|
29556
|
-
const LineView = props => {
|
|
29557
|
-
const {
|
|
29558
|
-
onMoveLine,
|
|
29559
|
-
onMovePoint,
|
|
29560
|
-
points: [start, end],
|
|
29561
|
-
stroke
|
|
29562
|
-
} = props;
|
|
29563
|
-
const {
|
|
29564
|
-
range
|
|
29565
|
-
} = useGraphConfig();
|
|
29566
|
-
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(MovableLine, {
|
|
29567
|
-
start: start,
|
|
29568
|
-
end: end,
|
|
29569
|
-
onMove: onMoveLine,
|
|
29570
29654
|
extend: {
|
|
29571
29655
|
start: true,
|
|
29572
|
-
end: true
|
|
29573
|
-
range
|
|
29574
|
-
},
|
|
29575
|
-
stroke: stroke
|
|
29576
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29577
|
-
point: start,
|
|
29578
|
-
onMove: newPoint => {
|
|
29579
|
-
onMovePoint(0, newPoint);
|
|
29580
|
-
},
|
|
29581
|
-
color: stroke
|
|
29582
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29583
|
-
point: end,
|
|
29584
|
-
onMove: newPoint => {
|
|
29585
|
-
onMovePoint(1, newPoint);
|
|
29656
|
+
end: true
|
|
29586
29657
|
},
|
|
29587
|
-
|
|
29588
|
-
|
|
29658
|
+
onMovePoint: (endpointIndex, destination) => dispatch(moveControlPoint(endpointIndex, destination, i)),
|
|
29659
|
+
color: colors[i]
|
|
29660
|
+
})));
|
|
29589
29661
|
};
|
|
29590
29662
|
|
|
29591
29663
|
const RayGraph = props => {
|
|
@@ -29593,30 +29665,21 @@ const RayGraph = props => {
|
|
|
29593
29665
|
dispatch
|
|
29594
29666
|
} = props;
|
|
29595
29667
|
const {
|
|
29596
|
-
coords: lines
|
|
29597
|
-
range
|
|
29668
|
+
coords: lines
|
|
29598
29669
|
} = props.graphState;
|
|
29599
|
-
|
|
29600
|
-
// a ray only has one line
|
|
29601
|
-
const [start, end] = lines[0];
|
|
29602
29670
|
const handleMoveLine = delta => dispatch(moveLine(0, delta));
|
|
29603
|
-
const handleMovePoint = (
|
|
29604
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
29605
|
-
|
|
29606
|
-
|
|
29607
|
-
|
|
29671
|
+
const handleMovePoint = (pointIndex, newPoint) => dispatch(moveControlPoint(pointIndex, newPoint, 0));
|
|
29672
|
+
return /*#__PURE__*/React__namespace.createElement(Segment
|
|
29673
|
+
// a ray only has one line
|
|
29674
|
+
, {
|
|
29675
|
+
points: lines[0],
|
|
29676
|
+
onMoveLine: handleMoveLine,
|
|
29677
|
+
onMovePoint: handleMovePoint,
|
|
29608
29678
|
extend: {
|
|
29609
|
-
end: true,
|
|
29610
29679
|
start: false,
|
|
29611
|
-
|
|
29680
|
+
end: true
|
|
29612
29681
|
}
|
|
29613
|
-
})
|
|
29614
|
-
point: start,
|
|
29615
|
-
onMove: newPoint => handleMovePoint(newPoint, 0)
|
|
29616
|
-
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
29617
|
-
point: end,
|
|
29618
|
-
onMove: newPoint => handleMovePoint(newPoint, 1)
|
|
29619
|
-
}));
|
|
29682
|
+
});
|
|
29620
29683
|
};
|
|
29621
29684
|
|
|
29622
29685
|
/**
|
|
@@ -29788,6 +29851,36 @@ const linesIntersect = (_ref3, _ref4) => {
|
|
|
29788
29851
|
};
|
|
29789
29852
|
const isEven = n => n % 2 === 0;
|
|
29790
29853
|
|
|
29854
|
+
const StyledMovablePoint = props => {
|
|
29855
|
+
const {
|
|
29856
|
+
snapStep
|
|
29857
|
+
} = useGraphConfig();
|
|
29858
|
+
const elementRef = React.useRef(null);
|
|
29859
|
+
const {
|
|
29860
|
+
point,
|
|
29861
|
+
onMove,
|
|
29862
|
+
color = wonderBlocksTokens.color.blue
|
|
29863
|
+
} = props;
|
|
29864
|
+
const {
|
|
29865
|
+
dragging
|
|
29866
|
+
} = mafs.useMovable({
|
|
29867
|
+
gestureTarget: elementRef,
|
|
29868
|
+
point,
|
|
29869
|
+
onMove,
|
|
29870
|
+
constrain: p => snap(snapStep, p)
|
|
29871
|
+
});
|
|
29872
|
+
return /*#__PURE__*/React__namespace.createElement(MovablePointView, {
|
|
29873
|
+
ref: elementRef,
|
|
29874
|
+
point: point,
|
|
29875
|
+
color: color,
|
|
29876
|
+
dragging: dragging,
|
|
29877
|
+
focusBehavior: {
|
|
29878
|
+
type: "uncontrolled",
|
|
29879
|
+
tabIndex: 0
|
|
29880
|
+
}
|
|
29881
|
+
});
|
|
29882
|
+
};
|
|
29883
|
+
|
|
29791
29884
|
const PolygonGraph = props => {
|
|
29792
29885
|
const [focused, setFocused] = React__namespace.useState(false);
|
|
29793
29886
|
const [hovered, setHovered] = React__namespace.useState(false);
|
|
@@ -29801,17 +29894,19 @@ const PolygonGraph = props => {
|
|
|
29801
29894
|
range,
|
|
29802
29895
|
snapStep
|
|
29803
29896
|
} = props.graphState;
|
|
29897
|
+
|
|
29898
|
+
// TODO(benchristel): can the default set of points be removed here? I don't
|
|
29899
|
+
// think coords can be null.
|
|
29804
29900
|
const points = coords ?? [[0, 0]];
|
|
29805
|
-
const pointsSum = points.reduce((acc, point) => mafs.vec.add(acc, point), [0, 0]);
|
|
29806
|
-
const midpoint = pointsSum && mafs.vec.scale(pointsSum, 1 / (points.length ?? 1));
|
|
29807
29901
|
const ref = React__namespace.useRef(null);
|
|
29902
|
+
const dragReferencePoint = points[0];
|
|
29808
29903
|
const {
|
|
29809
29904
|
dragging
|
|
29810
29905
|
} = mafs.useMovable({
|
|
29811
29906
|
gestureTarget: ref,
|
|
29812
|
-
point:
|
|
29907
|
+
point: dragReferencePoint,
|
|
29813
29908
|
onMove: newPoint => {
|
|
29814
|
-
const delta = mafs.vec.sub(newPoint,
|
|
29909
|
+
const delta = mafs.vec.sub(newPoint, dragReferencePoint);
|
|
29815
29910
|
dispatch(moveAll(delta));
|
|
29816
29911
|
},
|
|
29817
29912
|
constrain: p => snap(snapStep, p)
|
|
@@ -29871,6 +29966,287 @@ const PolygonGraph = props => {
|
|
|
29871
29966
|
})));
|
|
29872
29967
|
};
|
|
29873
29968
|
|
|
29969
|
+
function initializeGraphState(params) {
|
|
29970
|
+
const {
|
|
29971
|
+
graph,
|
|
29972
|
+
step,
|
|
29973
|
+
snapStep,
|
|
29974
|
+
range,
|
|
29975
|
+
markings
|
|
29976
|
+
} = params;
|
|
29977
|
+
const shared = {
|
|
29978
|
+
hasBeenInteractedWith: false,
|
|
29979
|
+
range,
|
|
29980
|
+
snapStep,
|
|
29981
|
+
markings
|
|
29982
|
+
};
|
|
29983
|
+
switch (graph.type) {
|
|
29984
|
+
case "segment":
|
|
29985
|
+
return {
|
|
29986
|
+
...shared,
|
|
29987
|
+
type: "segment",
|
|
29988
|
+
coords: getDefaultSegments({
|
|
29989
|
+
graph,
|
|
29990
|
+
step,
|
|
29991
|
+
range
|
|
29992
|
+
})
|
|
29993
|
+
};
|
|
29994
|
+
case "linear":
|
|
29995
|
+
case "linear-system":
|
|
29996
|
+
case "ray":
|
|
29997
|
+
return {
|
|
29998
|
+
...shared,
|
|
29999
|
+
type: graph.type,
|
|
30000
|
+
// Linear and ray graphs have a single tuple of points, while a
|
|
30001
|
+
// linear system has two tuples of points.
|
|
30002
|
+
coords: getLineCoords({
|
|
30003
|
+
graph,
|
|
30004
|
+
range,
|
|
30005
|
+
step
|
|
30006
|
+
})
|
|
30007
|
+
};
|
|
30008
|
+
case "polygon":
|
|
30009
|
+
return {
|
|
30010
|
+
...shared,
|
|
30011
|
+
type: "polygon",
|
|
30012
|
+
showAngles: Boolean(graph.showAngles),
|
|
30013
|
+
showSides: Boolean(graph.showSides),
|
|
30014
|
+
coords: getPolygonCoords({
|
|
30015
|
+
graph,
|
|
30016
|
+
range,
|
|
30017
|
+
step
|
|
30018
|
+
})
|
|
30019
|
+
};
|
|
30020
|
+
case "point":
|
|
30021
|
+
return {
|
|
30022
|
+
...shared,
|
|
30023
|
+
type: graph.type,
|
|
30024
|
+
coords: getDefaultPoints({
|
|
30025
|
+
graph,
|
|
30026
|
+
step,
|
|
30027
|
+
range
|
|
30028
|
+
})
|
|
30029
|
+
};
|
|
30030
|
+
case "circle":
|
|
30031
|
+
return {
|
|
30032
|
+
...shared,
|
|
30033
|
+
type: graph.type,
|
|
30034
|
+
center: [0, 0],
|
|
30035
|
+
radiusPoint: [1, 0]
|
|
30036
|
+
};
|
|
30037
|
+
case "angle":
|
|
30038
|
+
case "sinusoid":
|
|
30039
|
+
case "quadratic":
|
|
30040
|
+
throw new Error("Mafs not yet implemented for graph type: " + graph.type);
|
|
30041
|
+
default:
|
|
30042
|
+
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
30043
|
+
}
|
|
30044
|
+
}
|
|
30045
|
+
const getDefaultPoints = _ref => {
|
|
30046
|
+
let {
|
|
30047
|
+
graph,
|
|
30048
|
+
range,
|
|
30049
|
+
step
|
|
30050
|
+
} = _ref;
|
|
30051
|
+
const numPoints = graph.numPoints || 1;
|
|
30052
|
+
let coords = graph.coords?.slice();
|
|
30053
|
+
if (coords) {
|
|
30054
|
+
return coords;
|
|
30055
|
+
}
|
|
30056
|
+
switch (numPoints) {
|
|
30057
|
+
case 1:
|
|
30058
|
+
// Back in the day, one point's coords were in graph.coord
|
|
30059
|
+
coords = [graph.coord || [0, 0]];
|
|
30060
|
+
break;
|
|
30061
|
+
case 2:
|
|
30062
|
+
coords = [[-5, 0], [5, 0]];
|
|
30063
|
+
break;
|
|
30064
|
+
case 3:
|
|
30065
|
+
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
30066
|
+
break;
|
|
30067
|
+
case 4:
|
|
30068
|
+
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
30069
|
+
break;
|
|
30070
|
+
case 5:
|
|
30071
|
+
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
30072
|
+
break;
|
|
30073
|
+
case 6:
|
|
30074
|
+
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
30075
|
+
break;
|
|
30076
|
+
default:
|
|
30077
|
+
coords = [];
|
|
30078
|
+
break;
|
|
30079
|
+
}
|
|
30080
|
+
// Transform coords from their -10 to 10 space to 0 to 1
|
|
30081
|
+
// because of the old graph.coord, and also it's easier.
|
|
30082
|
+
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
30083
|
+
return normalizePoints(range, step, newCoords);
|
|
30084
|
+
};
|
|
30085
|
+
|
|
30086
|
+
// TS v4 doesn't narrow return types, while v5 does.
|
|
30087
|
+
// Instead of updating to v5, using generic type to relate input and output types.
|
|
30088
|
+
function getGradableGraph(state, initialGraph) {
|
|
30089
|
+
if (!state.hasBeenInteractedWith) {
|
|
30090
|
+
return {
|
|
30091
|
+
...initialGraph
|
|
30092
|
+
};
|
|
30093
|
+
}
|
|
30094
|
+
if (initialGraph.type === "linear-system" && state.type === "linear-system") {
|
|
30095
|
+
return {
|
|
30096
|
+
...initialGraph,
|
|
30097
|
+
coords: state.coords
|
|
30098
|
+
};
|
|
30099
|
+
}
|
|
30100
|
+
if (state.type === "segment" && initialGraph.type === "segment") {
|
|
30101
|
+
return {
|
|
30102
|
+
...initialGraph,
|
|
30103
|
+
coords: state.coords
|
|
30104
|
+
};
|
|
30105
|
+
}
|
|
30106
|
+
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
30107
|
+
return {
|
|
30108
|
+
...initialGraph,
|
|
30109
|
+
coords: state.coords[0]
|
|
30110
|
+
};
|
|
30111
|
+
}
|
|
30112
|
+
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
30113
|
+
return {
|
|
30114
|
+
...initialGraph,
|
|
30115
|
+
coords: state.coords[0]
|
|
30116
|
+
};
|
|
30117
|
+
}
|
|
30118
|
+
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
30119
|
+
return {
|
|
30120
|
+
...initialGraph,
|
|
30121
|
+
coords: state.coords
|
|
30122
|
+
};
|
|
30123
|
+
}
|
|
30124
|
+
if (state.type === "point" && initialGraph.type === "point") {
|
|
30125
|
+
return {
|
|
30126
|
+
...initialGraph,
|
|
30127
|
+
coords: state.coords
|
|
30128
|
+
};
|
|
30129
|
+
}
|
|
30130
|
+
if (state.type === "circle" && initialGraph.type === "circle") {
|
|
30131
|
+
return {
|
|
30132
|
+
...initialGraph,
|
|
30133
|
+
center: state.center,
|
|
30134
|
+
radius: getRadius(state)
|
|
30135
|
+
};
|
|
30136
|
+
}
|
|
30137
|
+
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
30138
|
+
}
|
|
30139
|
+
const getDefaultSegments = _ref2 => {
|
|
30140
|
+
let {
|
|
30141
|
+
graph,
|
|
30142
|
+
range,
|
|
30143
|
+
step
|
|
30144
|
+
} = _ref2;
|
|
30145
|
+
const ys = n => {
|
|
30146
|
+
switch (n) {
|
|
30147
|
+
case 2:
|
|
30148
|
+
return [5, -5];
|
|
30149
|
+
case 3:
|
|
30150
|
+
return [5, 0, -5];
|
|
30151
|
+
case 4:
|
|
30152
|
+
return [6, 2, -2, -6];
|
|
30153
|
+
case 5:
|
|
30154
|
+
return [6, 3, 0, -3, -6];
|
|
30155
|
+
case 6:
|
|
30156
|
+
return [5, 3, 1, -1, -3, -5];
|
|
30157
|
+
default:
|
|
30158
|
+
return [5];
|
|
30159
|
+
}
|
|
30160
|
+
};
|
|
30161
|
+
const defaultRange = [[-10, 10], [-10, 10]];
|
|
30162
|
+
return ys(graph.numSegments).map(y => {
|
|
30163
|
+
let endpoints = [[-5, y], [5, y]];
|
|
30164
|
+
endpoints = normalizeCoords(endpoints, defaultRange);
|
|
30165
|
+
endpoints = normalizePoints(range, step, endpoints);
|
|
30166
|
+
return endpoints;
|
|
30167
|
+
});
|
|
30168
|
+
};
|
|
30169
|
+
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
30170
|
+
const getLineCoords = _ref3 => {
|
|
30171
|
+
let {
|
|
30172
|
+
graph,
|
|
30173
|
+
range,
|
|
30174
|
+
step
|
|
30175
|
+
} = _ref3;
|
|
30176
|
+
return (
|
|
30177
|
+
// Return two lines for a linear system, one for a ray or linear
|
|
30178
|
+
graph.coords ?? graph.type === "linear-system" ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
|
|
30179
|
+
);
|
|
30180
|
+
};
|
|
30181
|
+
const getPolygonCoords = _ref4 => {
|
|
30182
|
+
let {
|
|
30183
|
+
graph,
|
|
30184
|
+
range,
|
|
30185
|
+
step
|
|
30186
|
+
} = _ref4;
|
|
30187
|
+
let coords = graph.coords?.slice();
|
|
30188
|
+
if (coords) {
|
|
30189
|
+
return coords;
|
|
30190
|
+
}
|
|
30191
|
+
const n = graph.numSides || 3;
|
|
30192
|
+
if (n === "unlimited") {
|
|
30193
|
+
coords = [];
|
|
30194
|
+
} else {
|
|
30195
|
+
const angle = 2 * Math.PI / n;
|
|
30196
|
+
const offset = (1 / n - 1 / 2) * Math.PI;
|
|
30197
|
+
|
|
30198
|
+
// TODO(alex): Generalize this to more than just triangles so that
|
|
30199
|
+
// all polygons have whole number side lengths if snapping to sides
|
|
30200
|
+
const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
|
|
30201
|
+
|
|
30202
|
+
// Generate coords of a regular polygon with n sides
|
|
30203
|
+
coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
|
|
30204
|
+
}
|
|
30205
|
+
coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
30206
|
+
const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
|
|
30207
|
+
coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
|
|
30208
|
+
return coords;
|
|
30209
|
+
};
|
|
30210
|
+
|
|
30211
|
+
/**
|
|
30212
|
+
* determine radius of a circle graph
|
|
30213
|
+
*
|
|
30214
|
+
* @param graph - the graph object containing the circle
|
|
30215
|
+
* @returns the radius of the circle
|
|
30216
|
+
*/
|
|
30217
|
+
function getRadius(graph) {
|
|
30218
|
+
const [centerX, centerY] = graph.center;
|
|
30219
|
+
const [edgeX, edgeY] = graph.radiusPoint;
|
|
30220
|
+
return Math.sqrt(Math.pow(edgeX - centerX, 2) + Math.pow(edgeY - centerY, 2));
|
|
30221
|
+
}
|
|
30222
|
+
|
|
30223
|
+
function CircleGraph(props) {
|
|
30224
|
+
const {
|
|
30225
|
+
dispatch,
|
|
30226
|
+
graphState
|
|
30227
|
+
} = props;
|
|
30228
|
+
const {
|
|
30229
|
+
center,
|
|
30230
|
+
radiusPoint
|
|
30231
|
+
} = graphState;
|
|
30232
|
+
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Circle, {
|
|
30233
|
+
center: center,
|
|
30234
|
+
radius: getRadius(graphState),
|
|
30235
|
+
fillOpacity: 0,
|
|
30236
|
+
color: wonderBlocksTokens.color.blue
|
|
30237
|
+
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30238
|
+
point: center,
|
|
30239
|
+
onMove: newCenter => {
|
|
30240
|
+
dispatch(moveCenter(newCenter));
|
|
30241
|
+
}
|
|
30242
|
+
}), /*#__PURE__*/React__namespace.createElement(StyledMovablePoint, {
|
|
30243
|
+
point: radiusPoint,
|
|
30244
|
+
onMove: newRadiusPoint => {
|
|
30245
|
+
dispatch(moveRadiusPoint(newRadiusPoint));
|
|
30246
|
+
}
|
|
30247
|
+
}));
|
|
30248
|
+
}
|
|
30249
|
+
|
|
29874
30250
|
function PointGraph(props) {
|
|
29875
30251
|
const {
|
|
29876
30252
|
dispatch
|
|
@@ -30676,6 +31052,10 @@ function interactiveGraphReducer(state, action) {
|
|
|
30676
31052
|
return doMoveAll(state, action);
|
|
30677
31053
|
case MOVE_POINT:
|
|
30678
31054
|
return doMovePoint(state, action);
|
|
31055
|
+
case MOVE_CENTER:
|
|
31056
|
+
return doMoveCenter(state, action);
|
|
31057
|
+
case MOVE_RADIUS_POINT:
|
|
31058
|
+
return doMoveRadiusPoint(state, action);
|
|
30679
31059
|
case CHANGE_SNAP_STEP:
|
|
30680
31060
|
return doChangeSnapStep(state, action);
|
|
30681
31061
|
case CHANGE_RANGE:
|
|
@@ -30815,6 +31195,67 @@ function doMovePoint(state, action) {
|
|
|
30815
31195
|
throw new Error("The movePoint action is only for point and polygon graphs");
|
|
30816
31196
|
}
|
|
30817
31197
|
}
|
|
31198
|
+
function doMoveCenter(state, action) {
|
|
31199
|
+
switch (state.type) {
|
|
31200
|
+
case "circle":
|
|
31201
|
+
{
|
|
31202
|
+
// Constrain the center of the circle to the chart range
|
|
31203
|
+
const constrainedCenter = bound$1({
|
|
31204
|
+
snapStep: state.snapStep,
|
|
31205
|
+
range: state.range,
|
|
31206
|
+
point: action.destination
|
|
31207
|
+
});
|
|
31208
|
+
|
|
31209
|
+
// Reposition the radius point based on the new center
|
|
31210
|
+
// (spread to make sure we're not going to mutate anything)
|
|
31211
|
+
const newRadiusPoint = [...mafs.vec.add(state.radiusPoint, mafs.vec.sub(constrainedCenter, state.center))];
|
|
31212
|
+
|
|
31213
|
+
// Try to position the radius handle in a visible spot
|
|
31214
|
+
// if it otherwise would be off the chart
|
|
31215
|
+
// ex: if the handle is on the right and we move the center
|
|
31216
|
+
// to the rightmost position, move the handle to the left
|
|
31217
|
+
const [xMin, xMax] = state.range[0];
|
|
31218
|
+
const [radX] = newRadiusPoint;
|
|
31219
|
+
if (radX < xMin || radX > xMax) {
|
|
31220
|
+
const xJumpDist = (radX - constrainedCenter[0]) * 2;
|
|
31221
|
+
const possibleNewX = radX - xJumpDist;
|
|
31222
|
+
if (possibleNewX >= xMin && possibleNewX <= xMax) {
|
|
31223
|
+
newRadiusPoint[0] = possibleNewX;
|
|
31224
|
+
}
|
|
31225
|
+
}
|
|
31226
|
+
return {
|
|
31227
|
+
...state,
|
|
31228
|
+
hasBeenInteractedWith: true,
|
|
31229
|
+
center: constrainedCenter,
|
|
31230
|
+
radiusPoint: newRadiusPoint
|
|
31231
|
+
};
|
|
31232
|
+
}
|
|
31233
|
+
default:
|
|
31234
|
+
throw new Error("The doMoveCenter action is only for circle graphs");
|
|
31235
|
+
}
|
|
31236
|
+
}
|
|
31237
|
+
function doMoveRadiusPoint(state, action) {
|
|
31238
|
+
switch (state.type) {
|
|
31239
|
+
case "circle":
|
|
31240
|
+
{
|
|
31241
|
+
const [xMin, xMax] = state.range[0];
|
|
31242
|
+
const nextRadiusPoint = [
|
|
31243
|
+
// Constrain to graph range
|
|
31244
|
+
// The +0 is to convert -0 to +0
|
|
31245
|
+
Math.min(Math.max(xMin, action.destination[0] + 0), xMax), state.center[1]];
|
|
31246
|
+
if (___default["default"].isEqual(nextRadiusPoint, state.center)) {
|
|
31247
|
+
return state;
|
|
31248
|
+
}
|
|
31249
|
+
return {
|
|
31250
|
+
...state,
|
|
31251
|
+
hasBeenInteractedWith: true,
|
|
31252
|
+
radiusPoint: nextRadiusPoint
|
|
31253
|
+
};
|
|
31254
|
+
}
|
|
31255
|
+
default:
|
|
31256
|
+
throw new Error("The doMoveRadiusPoint action is only for circle graphs");
|
|
31257
|
+
}
|
|
31258
|
+
}
|
|
30818
31259
|
function doChangeSnapStep(state, action) {
|
|
30819
31260
|
if (
|
|
30820
31261
|
// Deep equality check since these are arrays
|
|
@@ -30933,235 +31374,6 @@ function setAtIndex(args) {
|
|
|
30933
31374
|
return copy;
|
|
30934
31375
|
}
|
|
30935
31376
|
|
|
30936
|
-
function initializeGraphState(params) {
|
|
30937
|
-
const {
|
|
30938
|
-
graph,
|
|
30939
|
-
step,
|
|
30940
|
-
snapStep,
|
|
30941
|
-
range,
|
|
30942
|
-
markings
|
|
30943
|
-
} = params;
|
|
30944
|
-
const shared = {
|
|
30945
|
-
hasBeenInteractedWith: false,
|
|
30946
|
-
range,
|
|
30947
|
-
snapStep,
|
|
30948
|
-
markings
|
|
30949
|
-
};
|
|
30950
|
-
switch (graph.type) {
|
|
30951
|
-
case "segment":
|
|
30952
|
-
return {
|
|
30953
|
-
...shared,
|
|
30954
|
-
type: "segment",
|
|
30955
|
-
coords: getDefaultSegments({
|
|
30956
|
-
graph,
|
|
30957
|
-
step,
|
|
30958
|
-
range
|
|
30959
|
-
})
|
|
30960
|
-
};
|
|
30961
|
-
case "linear":
|
|
30962
|
-
case "linear-system":
|
|
30963
|
-
case "ray":
|
|
30964
|
-
return {
|
|
30965
|
-
...shared,
|
|
30966
|
-
type: graph.type,
|
|
30967
|
-
// Linear and ray graphs have a single tuple of points, while a
|
|
30968
|
-
// linear system has two tuples of points.
|
|
30969
|
-
coords: getLineCoords({
|
|
30970
|
-
graph,
|
|
30971
|
-
range,
|
|
30972
|
-
step
|
|
30973
|
-
})
|
|
30974
|
-
};
|
|
30975
|
-
case "polygon":
|
|
30976
|
-
return {
|
|
30977
|
-
...shared,
|
|
30978
|
-
type: "polygon",
|
|
30979
|
-
showAngles: Boolean(graph.showAngles),
|
|
30980
|
-
showSides: Boolean(graph.showSides),
|
|
30981
|
-
coords: getPolygonCoords({
|
|
30982
|
-
graph,
|
|
30983
|
-
range,
|
|
30984
|
-
step
|
|
30985
|
-
})
|
|
30986
|
-
};
|
|
30987
|
-
case "point":
|
|
30988
|
-
return {
|
|
30989
|
-
...shared,
|
|
30990
|
-
type: graph.type,
|
|
30991
|
-
coords: getDefaultPoints({
|
|
30992
|
-
graph,
|
|
30993
|
-
step,
|
|
30994
|
-
range
|
|
30995
|
-
})
|
|
30996
|
-
};
|
|
30997
|
-
case "angle":
|
|
30998
|
-
case "circle":
|
|
30999
|
-
case "sinusoid":
|
|
31000
|
-
case "quadratic":
|
|
31001
|
-
throw new Error("Mafs not yet implemented for graph type: " + graph.type);
|
|
31002
|
-
default:
|
|
31003
|
-
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
31004
|
-
}
|
|
31005
|
-
}
|
|
31006
|
-
const getDefaultPoints = _ref => {
|
|
31007
|
-
let {
|
|
31008
|
-
graph,
|
|
31009
|
-
range,
|
|
31010
|
-
step
|
|
31011
|
-
} = _ref;
|
|
31012
|
-
const numPoints = graph.numPoints || 1;
|
|
31013
|
-
let coords = graph.coords?.slice();
|
|
31014
|
-
if (coords) {
|
|
31015
|
-
return coords;
|
|
31016
|
-
}
|
|
31017
|
-
switch (numPoints) {
|
|
31018
|
-
case 1:
|
|
31019
|
-
// Back in the day, one point's coords were in graph.coord
|
|
31020
|
-
coords = [graph.coord || [0, 0]];
|
|
31021
|
-
break;
|
|
31022
|
-
case 2:
|
|
31023
|
-
coords = [[-5, 0], [5, 0]];
|
|
31024
|
-
break;
|
|
31025
|
-
case 3:
|
|
31026
|
-
coords = [[-5, 0], [0, 0], [5, 0]];
|
|
31027
|
-
break;
|
|
31028
|
-
case 4:
|
|
31029
|
-
coords = [[-6, 0], [-2, 0], [2, 0], [6, 0]];
|
|
31030
|
-
break;
|
|
31031
|
-
case 5:
|
|
31032
|
-
coords = [[-6, 0], [-3, 0], [0, 0], [3, 0], [6, 0]];
|
|
31033
|
-
break;
|
|
31034
|
-
case 6:
|
|
31035
|
-
coords = [[-5, 0], [-3, 0], [-1, 0], [1, 0], [3, 0], [5, 0]];
|
|
31036
|
-
break;
|
|
31037
|
-
default:
|
|
31038
|
-
coords = [];
|
|
31039
|
-
break;
|
|
31040
|
-
}
|
|
31041
|
-
// Transform coords from their -10 to 10 space to 0 to 1
|
|
31042
|
-
// because of the old graph.coord, and also it's easier.
|
|
31043
|
-
const newCoords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
31044
|
-
return normalizePoints(range, step, newCoords);
|
|
31045
|
-
};
|
|
31046
|
-
|
|
31047
|
-
// TS v4 doesn't narrow return types, while v5 does.
|
|
31048
|
-
// Instead of updating to v5, using generic type to relate input and output types.
|
|
31049
|
-
function getGradableGraph(state, initialGraph) {
|
|
31050
|
-
if (!state.hasBeenInteractedWith) {
|
|
31051
|
-
return {
|
|
31052
|
-
...initialGraph
|
|
31053
|
-
};
|
|
31054
|
-
}
|
|
31055
|
-
if (initialGraph.type === "linear-system" && state.type === "linear-system") {
|
|
31056
|
-
return {
|
|
31057
|
-
...initialGraph,
|
|
31058
|
-
coords: state.coords
|
|
31059
|
-
};
|
|
31060
|
-
}
|
|
31061
|
-
if (state.type === "segment" && initialGraph.type === "segment") {
|
|
31062
|
-
return {
|
|
31063
|
-
...initialGraph,
|
|
31064
|
-
coords: state.coords
|
|
31065
|
-
};
|
|
31066
|
-
}
|
|
31067
|
-
if (state.type === "linear" && initialGraph.type === "linear") {
|
|
31068
|
-
return {
|
|
31069
|
-
...initialGraph,
|
|
31070
|
-
coords: state.coords[0]
|
|
31071
|
-
};
|
|
31072
|
-
}
|
|
31073
|
-
if (state.type === "ray" && initialGraph.type === "ray") {
|
|
31074
|
-
return {
|
|
31075
|
-
...initialGraph,
|
|
31076
|
-
coords: state.coords[0]
|
|
31077
|
-
};
|
|
31078
|
-
}
|
|
31079
|
-
if (state.type === "polygon" && initialGraph.type === "polygon") {
|
|
31080
|
-
return {
|
|
31081
|
-
...initialGraph,
|
|
31082
|
-
coords: state.coords
|
|
31083
|
-
};
|
|
31084
|
-
}
|
|
31085
|
-
if (state.type === "point" && initialGraph.type === "point") {
|
|
31086
|
-
return {
|
|
31087
|
-
...initialGraph,
|
|
31088
|
-
coords: state.coords
|
|
31089
|
-
};
|
|
31090
|
-
}
|
|
31091
|
-
throw new Error("Mafs is not yet implemented for graph type: " + initialGraph.type);
|
|
31092
|
-
}
|
|
31093
|
-
const getDefaultSegments = _ref2 => {
|
|
31094
|
-
let {
|
|
31095
|
-
graph,
|
|
31096
|
-
range,
|
|
31097
|
-
step
|
|
31098
|
-
} = _ref2;
|
|
31099
|
-
const ys = n => {
|
|
31100
|
-
switch (n) {
|
|
31101
|
-
case 2:
|
|
31102
|
-
return [5, -5];
|
|
31103
|
-
case 3:
|
|
31104
|
-
return [5, 0, -5];
|
|
31105
|
-
case 4:
|
|
31106
|
-
return [6, 2, -2, -6];
|
|
31107
|
-
case 5:
|
|
31108
|
-
return [6, 3, 0, -3, -6];
|
|
31109
|
-
case 6:
|
|
31110
|
-
return [5, 3, 1, -1, -3, -5];
|
|
31111
|
-
default:
|
|
31112
|
-
return [5];
|
|
31113
|
-
}
|
|
31114
|
-
};
|
|
31115
|
-
const defaultRange = [[-10, 10], [-10, 10]];
|
|
31116
|
-
return ys(graph.numSegments).map(y => {
|
|
31117
|
-
let endpoints = [[-5, y], [5, y]];
|
|
31118
|
-
endpoints = normalizeCoords(endpoints, defaultRange);
|
|
31119
|
-
endpoints = normalizePoints(range, step, endpoints);
|
|
31120
|
-
return endpoints;
|
|
31121
|
-
});
|
|
31122
|
-
};
|
|
31123
|
-
const defaultLinearCoords = [[[0.25, 0.75], [0.75, 0.75]], [[0.25, 0.25], [0.75, 0.25]]];
|
|
31124
|
-
const getLineCoords = _ref3 => {
|
|
31125
|
-
let {
|
|
31126
|
-
graph,
|
|
31127
|
-
range,
|
|
31128
|
-
step
|
|
31129
|
-
} = _ref3;
|
|
31130
|
-
return (
|
|
31131
|
-
// Return two lines for a linear system, one for a ray or linear
|
|
31132
|
-
graph.coords ?? graph.type === "linear-system" ? defaultLinearCoords.map(collinear => normalizePoints(range, step, collinear)) : [normalizePoints(range, step, defaultLinearCoords[0])]
|
|
31133
|
-
);
|
|
31134
|
-
};
|
|
31135
|
-
const getPolygonCoords = _ref4 => {
|
|
31136
|
-
let {
|
|
31137
|
-
graph,
|
|
31138
|
-
range,
|
|
31139
|
-
step
|
|
31140
|
-
} = _ref4;
|
|
31141
|
-
let coords = graph.coords?.slice();
|
|
31142
|
-
if (coords) {
|
|
31143
|
-
return coords;
|
|
31144
|
-
}
|
|
31145
|
-
const n = graph.numSides || 3;
|
|
31146
|
-
if (n === "unlimited") {
|
|
31147
|
-
coords = [];
|
|
31148
|
-
} else {
|
|
31149
|
-
const angle = 2 * Math.PI / n;
|
|
31150
|
-
const offset = (1 / n - 1 / 2) * Math.PI;
|
|
31151
|
-
|
|
31152
|
-
// TODO(alex): Generalize this to more than just triangles so that
|
|
31153
|
-
// all polygons have whole number side lengths if snapping to sides
|
|
31154
|
-
const radius = graph.snapTo === "sides" ? Math.sqrt(3) / 3 * 7 : 4;
|
|
31155
|
-
|
|
31156
|
-
// Generate coords of a regular polygon with n sides
|
|
31157
|
-
coords = [...Array(n).keys()].map(i => [radius * Math.cos(i * angle + offset), radius * Math.sin(i * angle + offset)]);
|
|
31158
|
-
}
|
|
31159
|
-
coords = normalizeCoords(coords, [[-10, 10], [-10, 10]]);
|
|
31160
|
-
const snapToGrid = !["angles", "sides"].includes(graph.snapTo || "");
|
|
31161
|
-
coords = normalizePoints(range, step, coords, /* noSnap */!snapToGrid);
|
|
31162
|
-
return coords;
|
|
31163
|
-
};
|
|
31164
|
-
|
|
31165
31377
|
const renderGraph = props => {
|
|
31166
31378
|
const {
|
|
31167
31379
|
state,
|
|
@@ -31198,20 +31410,46 @@ const renderGraph = props => {
|
|
|
31198
31410
|
dispatch: dispatch
|
|
31199
31411
|
});
|
|
31200
31412
|
case "circle":
|
|
31201
|
-
|
|
31413
|
+
return /*#__PURE__*/React__namespace.createElement(CircleGraph, {
|
|
31414
|
+
graphState: state,
|
|
31415
|
+
dispatch: dispatch
|
|
31416
|
+
});
|
|
31202
31417
|
default:
|
|
31203
31418
|
return new wonderStuffCore.UnreachableCaseError(type);
|
|
31204
31419
|
}
|
|
31205
31420
|
};
|
|
31421
|
+
|
|
31422
|
+
// Rather than be tightly bound to how data was structured in
|
|
31423
|
+
// the legacy interactive graph, this lets us store state
|
|
31424
|
+
// however we want and we just transform it before handing it off
|
|
31425
|
+
// the the parent InteractiveGraph
|
|
31426
|
+
function mafsStateToInteractiveGraph(state) {
|
|
31427
|
+
if (state.graph.type === "circle") {
|
|
31428
|
+
return {
|
|
31429
|
+
...state,
|
|
31430
|
+
graph: {
|
|
31431
|
+
...state.graph,
|
|
31432
|
+
radius: getRadius(state.graph)
|
|
31433
|
+
}
|
|
31434
|
+
};
|
|
31435
|
+
}
|
|
31436
|
+
return {
|
|
31437
|
+
...state
|
|
31438
|
+
};
|
|
31439
|
+
}
|
|
31206
31440
|
const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
|
|
31207
31441
|
const [state, dispatch] = React__namespace.useReducer(interactiveGraphReducer, props, initializeGraphState);
|
|
31208
31442
|
React.useImperativeHandle(ref, () => ({
|
|
31209
31443
|
getUserInput: () => getGradableGraph(state, props.graph)
|
|
31210
31444
|
}));
|
|
31211
|
-
|
|
31445
|
+
function onChange(next) {
|
|
31446
|
+
props.onChange(mafsStateToInteractiveGraph(next));
|
|
31447
|
+
}
|
|
31448
|
+
return /*#__PURE__*/React__namespace.createElement(MafsGraph, _extends({}, props, {
|
|
31212
31449
|
state: state,
|
|
31213
|
-
dispatch: dispatch
|
|
31214
|
-
|
|
31450
|
+
dispatch: dispatch,
|
|
31451
|
+
onChange: onChange
|
|
31452
|
+
}));
|
|
31215
31453
|
});
|
|
31216
31454
|
const MafsGraph = props => {
|
|
31217
31455
|
const {
|
|
@@ -43385,7 +43623,7 @@ const init = function (options) {
|
|
|
43385
43623
|
|
|
43386
43624
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43387
43625
|
const libName = "@khanacademy/perseus";
|
|
43388
|
-
const libVersion = "22.
|
|
43626
|
+
const libVersion = "22.4.1";
|
|
43389
43627
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43390
43628
|
|
|
43391
43629
|
const apiVersion = {
|