@khanacademy/perseus 22.5.1 → 22.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.css +69 -1
- package/dist/es/index.js +377 -79
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +69 -1
- package/dist/index.js +374 -73
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +1 -1
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/widgets/expression.d.ts +6 -6
- package/dist/widgets/interactive-graphs/axis-ticks.d.ts +1 -8
- package/dist/widgets/interactive-graphs/graphs/components/axis-tick-labels.d.ts +13 -0
- package/dist/widgets/interactive-graphs/graphs/use-transform.d.ts +2 -6
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +6 -0
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +3 -2
- package/dist/widgets/interactive-graphs/types.d.ts +5 -0
- package/dist/widgets/label-image.d.ts +2 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -28758,6 +28758,8 @@ class Graph extends React__namespace.Component {
|
|
|
28758
28758
|
|
|
28759
28759
|
const defaultGraphConfig = {
|
|
28760
28760
|
range: [[0, 1], [0, 1]],
|
|
28761
|
+
tickStep: [1, 1],
|
|
28762
|
+
gridStep: [1, 1],
|
|
28761
28763
|
snapStep: [1, 1],
|
|
28762
28764
|
markings: "none",
|
|
28763
28765
|
showTooltips: false,
|
|
@@ -28772,6 +28774,7 @@ function useGraphConfig() {
|
|
|
28772
28774
|
}
|
|
28773
28775
|
|
|
28774
28776
|
const matrixBuilder = mafs.vec.matrixBuilder;
|
|
28777
|
+
|
|
28775
28778
|
// When converting vectors, we don't need to translate because a vector
|
|
28776
28779
|
// is like a pair of x and y distances, which are not bound to specific graph locations.
|
|
28777
28780
|
function vectorsToPixels(vectors, graphState) {
|
|
@@ -29025,7 +29028,7 @@ function Arrowhead(props) {
|
|
|
29025
29028
|
const [point] = useTransformVectorsToPixels(props.tip);
|
|
29026
29029
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29027
29030
|
className: "interactive-graph-arrowhead",
|
|
29028
|
-
transform: `translate(${point[0]} ${point[1]}) rotate(${
|
|
29031
|
+
transform: `translate(${point[0]} ${point[1]}) rotate(${props.angle})`
|
|
29029
29032
|
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29030
29033
|
transform: "translate(-1.5)"
|
|
29031
29034
|
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
@@ -29035,7 +29038,8 @@ function Arrowhead(props) {
|
|
|
29035
29038
|
stroke: props.color ?? "inherit"
|
|
29036
29039
|
},
|
|
29037
29040
|
strokeLinejoin: "round",
|
|
29038
|
-
strokeLinecap: "round"
|
|
29041
|
+
strokeLinecap: "round",
|
|
29042
|
+
strokeWidth: "2px"
|
|
29039
29043
|
})));
|
|
29040
29044
|
}
|
|
29041
29045
|
|
|
@@ -29072,10 +29076,7 @@ const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
|
29072
29076
|
case isBetween(xAtYExtreme, xMin, xMax):
|
|
29073
29077
|
return [xAtYExtreme, yExtreme];
|
|
29074
29078
|
default:
|
|
29075
|
-
|
|
29076
|
-
// (initialPoint is outside the graph bounds, or initialPoint and
|
|
29077
|
-
// throughPoint are the same).
|
|
29078
|
-
return [0, 0];
|
|
29079
|
+
return [xExtreme, yExtreme];
|
|
29079
29080
|
}
|
|
29080
29081
|
};
|
|
29081
29082
|
const getLines = points => {
|
|
@@ -29115,7 +29116,7 @@ function Vector(props) {
|
|
|
29115
29116
|
style
|
|
29116
29117
|
} = props;
|
|
29117
29118
|
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
29118
|
-
const direction = mafs.vec.sub(
|
|
29119
|
+
const direction = mafs.vec.sub(tipPx, tailPx);
|
|
29119
29120
|
const angle = calculateAngleInDegrees(direction);
|
|
29120
29121
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29121
29122
|
style: {
|
|
@@ -29159,7 +29160,9 @@ const LockedLine = props => {
|
|
|
29159
29160
|
} else {
|
|
29160
29161
|
const LineType = kind === "segment" ? mafs.Line.Segment : mafs.Line.ThroughPoints;
|
|
29161
29162
|
let arrowTip = kind === "segment" ? point2.coord : getIntersectionOfRayWithBox(point1.coord, point2.coord, range);
|
|
29162
|
-
|
|
29163
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
29164
|
+
const [tailPx, tipPx] = useTransformVectorsToPixels(point2.coord, point1.coord);
|
|
29165
|
+
const direction = mafs.vec.sub(tailPx, tipPx);
|
|
29163
29166
|
let angle = calculateAngleInDegrees(direction);
|
|
29164
29167
|
const startArrowHead = kind !== "segment" && /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29165
29168
|
angle: angle,
|
|
@@ -30184,10 +30187,16 @@ const getLineCoords = _ref3 => {
|
|
|
30184
30187
|
range,
|
|
30185
30188
|
step
|
|
30186
30189
|
} = _ref3;
|
|
30187
|
-
|
|
30188
|
-
|
|
30189
|
-
|
|
30190
|
-
|
|
30190
|
+
// Return two lines for a linear system, one for a ray or linear
|
|
30191
|
+
switch (graph.type) {
|
|
30192
|
+
case "linear-system":
|
|
30193
|
+
return defaultLinearCoords.map(points => normalizePoints(range, step, points));
|
|
30194
|
+
case "linear":
|
|
30195
|
+
case "ray":
|
|
30196
|
+
return [normalizePoints(range, step, defaultLinearCoords[0])];
|
|
30197
|
+
default:
|
|
30198
|
+
throw new wonderStuffCore.UnreachableCaseError(graph);
|
|
30199
|
+
}
|
|
30191
30200
|
};
|
|
30192
30201
|
const getPolygonCoords = _ref4 => {
|
|
30193
30202
|
let {
|
|
@@ -30281,11 +30290,12 @@ function MovableCircle(props) {
|
|
|
30281
30290
|
cy: centerPx[1],
|
|
30282
30291
|
rx: radiiPx[0] + 3,
|
|
30283
30292
|
ry: radiiPx[1] + 3
|
|
30284
|
-
}), /*#__PURE__*/React__namespace.createElement(
|
|
30285
|
-
|
|
30286
|
-
|
|
30287
|
-
|
|
30288
|
-
|
|
30293
|
+
}), /*#__PURE__*/React__namespace.createElement("ellipse", {
|
|
30294
|
+
className: "circle",
|
|
30295
|
+
cx: centerPx[0],
|
|
30296
|
+
cy: centerPx[1],
|
|
30297
|
+
rx: radiiPx[0],
|
|
30298
|
+
ry: radiiPx[1]
|
|
30289
30299
|
}), /*#__PURE__*/React__namespace.createElement(DragHandle, {
|
|
30290
30300
|
center: center
|
|
30291
30301
|
}));
|
|
@@ -30326,6 +30336,260 @@ function crossProduct(as, bs) {
|
|
|
30326
30336
|
return result;
|
|
30327
30337
|
}
|
|
30328
30338
|
|
|
30339
|
+
// Universal padding for the axis ticks to ensure that the labels
|
|
30340
|
+
// have enough space to render without overlapping the tick lines
|
|
30341
|
+
const tickPadding = 5;
|
|
30342
|
+
const AxisTickLabels = () => {
|
|
30343
|
+
const graphConfig = useGraphConfig();
|
|
30344
|
+
const {
|
|
30345
|
+
tickStep,
|
|
30346
|
+
range
|
|
30347
|
+
} = graphConfig;
|
|
30348
|
+
const [xMin, xMax] = range[0];
|
|
30349
|
+
const [yMin, yMax] = range[1];
|
|
30350
|
+
const yTickStep = tickStep[1];
|
|
30351
|
+
const xTickStep = tickStep[0];
|
|
30352
|
+
const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
|
|
30353
|
+
const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
|
|
30354
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
30355
|
+
className: "axis-tick-labels"
|
|
30356
|
+
}, /*#__PURE__*/React__namespace.createElement(YGridAxis, {
|
|
30357
|
+
axisTicks: yGridTicks,
|
|
30358
|
+
graphConfig: graphConfig
|
|
30359
|
+
}), /*#__PURE__*/React__namespace.createElement(XGridAxis, {
|
|
30360
|
+
axisTicks: xGridTicks,
|
|
30361
|
+
graphConfig: graphConfig
|
|
30362
|
+
}));
|
|
30363
|
+
};
|
|
30364
|
+
|
|
30365
|
+
// Generate the necessary styles and ticks for the y-axis tick labels container
|
|
30366
|
+
const YGridAxis = props => {
|
|
30367
|
+
const {
|
|
30368
|
+
axisTicks,
|
|
30369
|
+
graphConfig
|
|
30370
|
+
} = props;
|
|
30371
|
+
const {
|
|
30372
|
+
width,
|
|
30373
|
+
height
|
|
30374
|
+
} = graphConfig;
|
|
30375
|
+
|
|
30376
|
+
// First get the label height by calculating the difference between the first two y-axis labels
|
|
30377
|
+
const yTopPoint = pointToPixel([0, axisTicks[0]], graphConfig);
|
|
30378
|
+
const ySecondPoint = pointToPixel([0, axisTicks[1]], graphConfig);
|
|
30379
|
+
const yLabelHeight = ySecondPoint[1] - yTopPoint[1];
|
|
30380
|
+
|
|
30381
|
+
// When rendering purely positive y-axis labels, we want to adjust the left position
|
|
30382
|
+
// from the lowest calculated tick, as yMin may be negative
|
|
30383
|
+
const yLowestTick = axisTicks[axisTicks.length - 1];
|
|
30384
|
+
const yLeftAdjustment = Math.min(Math.max(yTopPoint[0] - tickPadding, 0), width);
|
|
30385
|
+
|
|
30386
|
+
// We only want to render the 0 label on the y-axis if it is left of the grid
|
|
30387
|
+
const yAxisIsLeftOfGrid = yLeftAdjustment === 0;
|
|
30388
|
+
|
|
30389
|
+
// If the y-axis is right of the graph's viewbox/range,
|
|
30390
|
+
// we want to adjust both the positioning and text alignment
|
|
30391
|
+
const yAxisRightOfGrid = yLeftAdjustment === width;
|
|
30392
|
+
|
|
30393
|
+
// Determine the default spacing for the labels based on whether the y-axis is right of the grid
|
|
30394
|
+
const defaultSpacing = yAxisRightOfGrid ? 0.5 : 0;
|
|
30395
|
+
|
|
30396
|
+
// We also want to adjust the spacing if there are no negative y-axis labels as the extra space is not needed
|
|
30397
|
+
const marginSpacing = yLowestTick >= 0 ? defaultSpacing * 2 : defaultSpacing;
|
|
30398
|
+
|
|
30399
|
+
// Determine the text alignment based on whether the y-axis is right of the grid
|
|
30400
|
+
// We need to cast this as a const as it is used in the inline styles
|
|
30401
|
+
const textAlign = yAxisRightOfGrid ? "left" : "right";
|
|
30402
|
+
const yAxisStyles = {
|
|
30403
|
+
left: `calc(${yLeftAdjustment}px - ${marginSpacing}em)`,
|
|
30404
|
+
top: `calc(${yTopPoint[1]}px - 0.5em)`,
|
|
30405
|
+
height,
|
|
30406
|
+
textAlign,
|
|
30407
|
+
"--y-axis-label-height": yLabelHeight + "px"
|
|
30408
|
+
};
|
|
30409
|
+
const classNames = yAxisRightOfGrid ? "y-axis-tick-labels y-axis-right-of-grid" : "y-axis-tick-labels ";
|
|
30410
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
30411
|
+
className: classNames,
|
|
30412
|
+
"data-testid": "y-axis-tick-labels",
|
|
30413
|
+
style: yAxisStyles
|
|
30414
|
+
}, axisTicks.map(label => {
|
|
30415
|
+
return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
|
|
30416
|
+
label: label,
|
|
30417
|
+
axis: "y",
|
|
30418
|
+
key: `y-grid-tick-${label}`,
|
|
30419
|
+
graphConfig: graphConfig,
|
|
30420
|
+
axisOutOfBounds: yAxisIsLeftOfGrid
|
|
30421
|
+
});
|
|
30422
|
+
}));
|
|
30423
|
+
};
|
|
30424
|
+
|
|
30425
|
+
// Generate the necessary styles and ticks for the x-axis tick labels container
|
|
30426
|
+
const XGridAxis = props => {
|
|
30427
|
+
const {
|
|
30428
|
+
axisTicks,
|
|
30429
|
+
graphConfig
|
|
30430
|
+
} = props;
|
|
30431
|
+
const {
|
|
30432
|
+
width,
|
|
30433
|
+
height
|
|
30434
|
+
} = graphConfig;
|
|
30435
|
+
|
|
30436
|
+
// Determine label width by calculating the difference between the first two x-axis labels
|
|
30437
|
+
const xFirstPoint = pointToPixel([axisTicks[0], 0], graphConfig);
|
|
30438
|
+
const xSecondPoint = pointToPixel([axisTicks[1], 0], graphConfig);
|
|
30439
|
+
const xLabelWidth = Math.abs(xSecondPoint[0] - xFirstPoint[0]);
|
|
30440
|
+
|
|
30441
|
+
// Determine the top position of the x-axis labels based on
|
|
30442
|
+
// whether the x-axis is above, within, or below the graph
|
|
30443
|
+
const xAxisAboveGraph = xFirstPoint[1] < 0;
|
|
30444
|
+
const xTopAdjustment = xAxisAboveGraph ? 0 : Math.min(xFirstPoint[1] + tickPadding, height);
|
|
30445
|
+
|
|
30446
|
+
// Determine whether the x-axis is outside of the graph's viewbox/range
|
|
30447
|
+
// This is used to conditionally render the 0 label on the x-axis
|
|
30448
|
+
const xAxisOutOfBounds = xTopAdjustment === height || xAxisAboveGraph;
|
|
30449
|
+
|
|
30450
|
+
// Determine the available space to the right of the x-axis labels
|
|
30451
|
+
const availableSpaceRight = width - xFirstPoint[0];
|
|
30452
|
+
|
|
30453
|
+
// Calculate the total combined width of ALL the x-axis labels
|
|
30454
|
+
const axisTicksWidth = axisTicks.length * xLabelWidth;
|
|
30455
|
+
|
|
30456
|
+
// Determine if we need to increase the width of the axis past the graph width
|
|
30457
|
+
const calculatedWidth = axisTicksWidth > width ? axisTicksWidth : width;
|
|
30458
|
+
|
|
30459
|
+
// Determine the right adjustment for the x-axis labels based on the available space
|
|
30460
|
+
// We're adjusting the right as the flex-direction is row-reverse
|
|
30461
|
+
const xRightAdjustment = availableSpaceRight - xLabelWidth / 2;
|
|
30462
|
+
const xAxisStyles = {
|
|
30463
|
+
top: xTopAdjustment,
|
|
30464
|
+
right: xRightAdjustment,
|
|
30465
|
+
width: calculatedWidth,
|
|
30466
|
+
"--x-axis-label-width": xLabelWidth + "px"
|
|
30467
|
+
};
|
|
30468
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
30469
|
+
className: `x-axis-tick-labels ${xAxisAboveGraph && "x-axis-top-of-grid"}`,
|
|
30470
|
+
"data-testid": "x-axis-tick-labels",
|
|
30471
|
+
style: xAxisStyles
|
|
30472
|
+
}, axisTicks.map(label => {
|
|
30473
|
+
return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
|
|
30474
|
+
axis: "x",
|
|
30475
|
+
label: label,
|
|
30476
|
+
key: `x-grid-tick-${label}`,
|
|
30477
|
+
graphConfig: graphConfig,
|
|
30478
|
+
axisOutOfBounds: xAxisOutOfBounds
|
|
30479
|
+
});
|
|
30480
|
+
}));
|
|
30481
|
+
};
|
|
30482
|
+
|
|
30483
|
+
// Generate the individual tick label elements
|
|
30484
|
+
const AxisTickLabel = _ref => {
|
|
30485
|
+
let {
|
|
30486
|
+
label,
|
|
30487
|
+
graphConfig,
|
|
30488
|
+
axisOutOfBounds,
|
|
30489
|
+
axis
|
|
30490
|
+
} = _ref;
|
|
30491
|
+
const {
|
|
30492
|
+
gridStep,
|
|
30493
|
+
tickStep
|
|
30494
|
+
} = graphConfig;
|
|
30495
|
+
// Determine the point on the axis based on the axis type
|
|
30496
|
+
const pointOnAxis = axis === "x" ? [label, 0] : [0, label];
|
|
30497
|
+
const pixelPoint = pointToPixel(pointOnAxis, graphConfig);
|
|
30498
|
+
|
|
30499
|
+
// Remove the negative sign from the label string as it is handled in the data-content attribute
|
|
30500
|
+
const labelString = Math.abs(label).toString();
|
|
30501
|
+
|
|
30502
|
+
// Determine the relevant edge of the graph based on the axis type
|
|
30503
|
+
const graphEdge = axis === "x" ? graphConfig.width : graphConfig.height;
|
|
30504
|
+
|
|
30505
|
+
// Determine the vector index based on the axis type
|
|
30506
|
+
const vectorIndex = axis === "x" ? 0 : 1;
|
|
30507
|
+
|
|
30508
|
+
// Determine whether or not to render the tick label text
|
|
30509
|
+
const shouldShowLabel = showTickLabel({
|
|
30510
|
+
label,
|
|
30511
|
+
axisOutOfBounds,
|
|
30512
|
+
graphEdge,
|
|
30513
|
+
position: pixelPoint[vectorIndex],
|
|
30514
|
+
gridStep: gridStep[vectorIndex],
|
|
30515
|
+
tickStep: tickStep[vectorIndex]
|
|
30516
|
+
});
|
|
30517
|
+
|
|
30518
|
+
// Determine whether or not to render a negative symbol for the tick label
|
|
30519
|
+
// as the negative sign is handled in the data-content attribute in order to
|
|
30520
|
+
// maintain the correct spacing between the labels
|
|
30521
|
+
const dataContent = label < 0 && shouldShowLabel ? "−" : null;
|
|
30522
|
+
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
30523
|
+
className: `${axis}-axis-tick-label`,
|
|
30524
|
+
"data-content": dataContent
|
|
30525
|
+
}, shouldShowLabel && labelString);
|
|
30526
|
+
};
|
|
30527
|
+
|
|
30528
|
+
// Determine whether or not to show the tick label text
|
|
30529
|
+
const showTickLabel = _ref2 => {
|
|
30530
|
+
let {
|
|
30531
|
+
gridStep,
|
|
30532
|
+
tickStep,
|
|
30533
|
+
label,
|
|
30534
|
+
graphEdge,
|
|
30535
|
+
position,
|
|
30536
|
+
axisOutOfBounds
|
|
30537
|
+
} = _ref2;
|
|
30538
|
+
let showLabel = true;
|
|
30539
|
+
|
|
30540
|
+
// We only want to show the initial negative tick labels (e.g. -1) on each
|
|
30541
|
+
// axis if the tickStep > gridStep, to ensure that these labels do not overlap.
|
|
30542
|
+
// e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
|
|
30543
|
+
// which allows enough room for both these tick labels to render.
|
|
30544
|
+
showLabel = tickStep > gridStep ? true : label !== -tickStep;
|
|
30545
|
+
|
|
30546
|
+
// If the tick label position is greater than the relevant edge of the graph, don't render it
|
|
30547
|
+
if (position <= -graphEdge || position >= graphEdge) {
|
|
30548
|
+
showLabel = false;
|
|
30549
|
+
}
|
|
30550
|
+
|
|
30551
|
+
// If the label is 0, we only want to show it if the axis is to the left of the graph's viewbox/range
|
|
30552
|
+
// otherwise it will overlap with graph axis labels
|
|
30553
|
+
if (label === 0 && !axisOutOfBounds) {
|
|
30554
|
+
showLabel = false;
|
|
30555
|
+
}
|
|
30556
|
+
return showLabel;
|
|
30557
|
+
};
|
|
30558
|
+
|
|
30559
|
+
// Generate the tick labels for an axis based on the tick step
|
|
30560
|
+
function generateTickLocations$1(tickStep, min, max) {
|
|
30561
|
+
const positiveTicks = [];
|
|
30562
|
+
const negativeTicks = [];
|
|
30563
|
+
const ticks = [];
|
|
30564
|
+
|
|
30565
|
+
// Add 0 if it is applicable.
|
|
30566
|
+
// This will be conditionally rendered using showTickLabel.
|
|
30567
|
+
if (min <= 0 && max >= 0) {
|
|
30568
|
+
positiveTicks.push(0);
|
|
30569
|
+
}
|
|
30570
|
+
|
|
30571
|
+
// Add ticks on the positive axis
|
|
30572
|
+
// Start at the first tick after 0 or the minimum value,
|
|
30573
|
+
// taking into account that the graph may be zoomed in on the positive axis
|
|
30574
|
+
let i = Math.max(min, 0) + tickStep;
|
|
30575
|
+
for (i; min < i && i < max; i += tickStep) {
|
|
30576
|
+
positiveTicks.push(i);
|
|
30577
|
+
}
|
|
30578
|
+
|
|
30579
|
+
// Add ticks on the negative axis
|
|
30580
|
+
// Start at the first tick before 0 or the maximum value,
|
|
30581
|
+
// taking into account that the graph may be zoomed in on the negative axis
|
|
30582
|
+
i = Math.min(max, 0) - tickStep;
|
|
30583
|
+
for (i; i > min; i -= tickStep) {
|
|
30584
|
+
negativeTicks.push(i);
|
|
30585
|
+
}
|
|
30586
|
+
|
|
30587
|
+
// Reverse the ticks so that they are in the correct render order
|
|
30588
|
+
positiveTicks.reverse();
|
|
30589
|
+
ticks.push(...positiveTicks, ...negativeTicks);
|
|
30590
|
+
return ticks;
|
|
30591
|
+
}
|
|
30592
|
+
|
|
30329
30593
|
function PointGraph(props) {
|
|
30330
30594
|
const {
|
|
30331
30595
|
dispatch
|
|
@@ -30353,11 +30617,11 @@ function AxisArrows() {
|
|
|
30353
30617
|
}), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
|
|
30354
30618
|
color: axisColor,
|
|
30355
30619
|
tip: [0, yMin],
|
|
30356
|
-
angle:
|
|
30620
|
+
angle: 90
|
|
30357
30621
|
}), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
|
|
30358
30622
|
color: axisColor,
|
|
30359
30623
|
tip: [0, yMax],
|
|
30360
|
-
angle:
|
|
30624
|
+
angle: 270
|
|
30361
30625
|
}));
|
|
30362
30626
|
}
|
|
30363
30627
|
|
|
@@ -30366,62 +30630,88 @@ const tickStyle = {
|
|
|
30366
30630
|
stroke: "black",
|
|
30367
30631
|
strokeWidth: 1
|
|
30368
30632
|
};
|
|
30369
|
-
|
|
30370
|
-
// We only want to show the initial negative tick labels (e.g. -1) on each
|
|
30371
|
-
// axis if the tickStep > gridStep, to ensure that these labels do not overlap.
|
|
30372
|
-
// e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
|
|
30373
|
-
// which allows enough room for both these tick labels to render.
|
|
30374
|
-
const showTickLabel = (gridStep, tickStep, label) => {
|
|
30375
|
-
const showLabel = tickStep > gridStep ? true : label !== -tickStep;
|
|
30376
|
-
return showLabel;
|
|
30377
|
-
};
|
|
30378
30633
|
const YGridTick = _ref => {
|
|
30379
30634
|
let {
|
|
30380
30635
|
y,
|
|
30381
|
-
|
|
30382
|
-
tickStep
|
|
30636
|
+
graphInfo
|
|
30383
30637
|
} = _ref;
|
|
30384
|
-
|
|
30638
|
+
let xPointOnAxis = 0;
|
|
30639
|
+
|
|
30640
|
+
// If the graph is zoomed in, we want to make sure the ticks are still visible
|
|
30641
|
+
// even if they are outside the graph's range.
|
|
30642
|
+
if (graphInfo.range[0][0] > 0) {
|
|
30643
|
+
// If the graph is on the positive side of the x-axis, lock the ticks to the left side of the graph
|
|
30644
|
+
xPointOnAxis = graphInfo.range[0][0];
|
|
30645
|
+
}
|
|
30646
|
+
if (graphInfo.range[0][1] < 0) {
|
|
30647
|
+
// If the graph is on the negative side of the x-axis, lock the ticks to the right side of the graph
|
|
30648
|
+
xPointOnAxis = graphInfo.range[0][1];
|
|
30649
|
+
}
|
|
30650
|
+
const pointOnAxis = [xPointOnAxis, y];
|
|
30385
30651
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
30652
|
+
|
|
30653
|
+
// If the tick is on the edge of the graph's range, don't render it
|
|
30654
|
+
if (yPosition === -graphInfo.height || yPosition === graphInfo.height + 20) {
|
|
30655
|
+
return null;
|
|
30656
|
+
}
|
|
30657
|
+
|
|
30658
|
+
// Position of the start of the tick
|
|
30659
|
+
const x1 = xPosition - tickSize / 2;
|
|
30660
|
+
const y1 = yPosition;
|
|
30661
|
+
|
|
30662
|
+
// Position of the end of the tick
|
|
30663
|
+
const x2 = xPosition + tickSize / 2;
|
|
30664
|
+
const y2 = yPosition;
|
|
30386
30665
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
30387
30666
|
className: "y-axis-ticks"
|
|
30388
30667
|
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
30389
|
-
x1:
|
|
30390
|
-
y1:
|
|
30391
|
-
x2:
|
|
30392
|
-
y2:
|
|
30668
|
+
x1: x1,
|
|
30669
|
+
y1: y1,
|
|
30670
|
+
x2: x2,
|
|
30671
|
+
y2: y2,
|
|
30393
30672
|
style: tickStyle
|
|
30394
|
-
})
|
|
30395
|
-
height: 20,
|
|
30396
|
-
width: 50,
|
|
30397
|
-
textAnchor: "end",
|
|
30398
|
-
x: xPosition - 10,
|
|
30399
|
-
y: yPosition + 5
|
|
30400
|
-
}, y.toString()));
|
|
30673
|
+
}));
|
|
30401
30674
|
};
|
|
30402
30675
|
const XGridTick = _ref2 => {
|
|
30403
30676
|
let {
|
|
30404
30677
|
x,
|
|
30405
|
-
|
|
30406
|
-
tickStep
|
|
30678
|
+
graphInfo
|
|
30407
30679
|
} = _ref2;
|
|
30408
|
-
|
|
30680
|
+
let yPointOnAxis = 0;
|
|
30681
|
+
// If the graph is zoomed in, we want to make sure the ticks are still visible
|
|
30682
|
+
// even if they are outside the graph's range.
|
|
30683
|
+
if (graphInfo.range[1][0] > 0) {
|
|
30684
|
+
// If the graph is on the positive side of the y-axis, lock the ticks to the top of the graph
|
|
30685
|
+
yPointOnAxis = graphInfo.range[1][0];
|
|
30686
|
+
}
|
|
30687
|
+
if (graphInfo.range[1][1] < 0) {
|
|
30688
|
+
// If the graph is on the negative side of the x-axis, lock the ticks to the bottom of the graph
|
|
30689
|
+
yPointOnAxis = graphInfo.range[1][1];
|
|
30690
|
+
}
|
|
30691
|
+
const pointOnAxis = [x, yPointOnAxis];
|
|
30409
30692
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
30693
|
+
|
|
30694
|
+
// If the tick is on the edge of the graph's range, don't render it
|
|
30695
|
+
if (xPosition === -graphInfo.width / 2 || xPosition === graphInfo.width) {
|
|
30696
|
+
return null;
|
|
30697
|
+
}
|
|
30698
|
+
|
|
30699
|
+
// Position of the start of the tick
|
|
30700
|
+
const x1 = xPosition;
|
|
30701
|
+
const y1 = yPosition + tickSize / 2;
|
|
30702
|
+
|
|
30703
|
+
// Position of the end of the tick
|
|
30704
|
+
const x2 = xPosition;
|
|
30705
|
+
const y2 = yPosition - tickSize / 2;
|
|
30410
30706
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
30411
30707
|
className: "x-axis-ticks"
|
|
30412
30708
|
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
30413
|
-
x1:
|
|
30414
|
-
y1:
|
|
30415
|
-
x2:
|
|
30416
|
-
y2:
|
|
30709
|
+
x1: x1,
|
|
30710
|
+
y1: y1,
|
|
30711
|
+
x2: x2,
|
|
30712
|
+
y2: y2,
|
|
30417
30713
|
style: tickStyle
|
|
30418
|
-
})
|
|
30419
|
-
height: 20,
|
|
30420
|
-
width: 50,
|
|
30421
|
-
textAnchor: "middle",
|
|
30422
|
-
x: xPosition,
|
|
30423
|
-
y: yPosition + 25
|
|
30424
|
-
}, x.toString()));
|
|
30714
|
+
}));
|
|
30425
30715
|
};
|
|
30426
30716
|
function generateTickLocations(tickStep, min, max) {
|
|
30427
30717
|
const ticks = [];
|
|
@@ -30432,17 +30722,29 @@ function generateTickLocations(tickStep, min, max) {
|
|
|
30432
30722
|
}
|
|
30433
30723
|
|
|
30434
30724
|
// Add ticks in the negative direction
|
|
30435
|
-
|
|
30725
|
+
// Start at the first tick after 0 or the maximum value if it is negative
|
|
30726
|
+
let i = Math.min(max, 0) - tickStep;
|
|
30727
|
+
for (i; i > min; i -= tickStep) {
|
|
30436
30728
|
ticks.push(i);
|
|
30437
30729
|
}
|
|
30438
30730
|
return ticks;
|
|
30439
30731
|
}
|
|
30440
|
-
const AxisTicks =
|
|
30441
|
-
const
|
|
30732
|
+
const AxisTicks = () => {
|
|
30733
|
+
const {
|
|
30734
|
+
tickStep,
|
|
30735
|
+
range,
|
|
30736
|
+
width,
|
|
30737
|
+
height
|
|
30738
|
+
} = useGraphConfig();
|
|
30739
|
+
const graphInfo = {
|
|
30740
|
+
range,
|
|
30741
|
+
width,
|
|
30742
|
+
height
|
|
30743
|
+
};
|
|
30442
30744
|
const [xMin, xMax] = range[0];
|
|
30443
30745
|
const [yMin, yMax] = range[1];
|
|
30444
|
-
const yTickStep =
|
|
30445
|
-
const xTickStep =
|
|
30746
|
+
const yTickStep = tickStep[1];
|
|
30747
|
+
const xTickStep = tickStep[0];
|
|
30446
30748
|
const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
|
|
30447
30749
|
const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
|
|
30448
30750
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
@@ -30451,15 +30753,13 @@ const AxisTicks = props => {
|
|
|
30451
30753
|
return /*#__PURE__*/React__namespace.createElement(YGridTick, {
|
|
30452
30754
|
y: y,
|
|
30453
30755
|
key: `y-grid-tick-${y}`,
|
|
30454
|
-
|
|
30455
|
-
tickStep: yTickStep
|
|
30756
|
+
graphInfo: graphInfo
|
|
30456
30757
|
});
|
|
30457
30758
|
}), xGridTicks.map(x => {
|
|
30458
30759
|
return /*#__PURE__*/React__namespace.createElement(XGridTick, {
|
|
30459
30760
|
x: x,
|
|
30460
30761
|
key: `x-grid-tick-${x}`,
|
|
30461
|
-
|
|
30462
|
-
tickStep: xTickStep
|
|
30762
|
+
graphInfo: graphInfo
|
|
30463
30763
|
});
|
|
30464
30764
|
}));
|
|
30465
30765
|
};
|
|
@@ -30487,11 +30787,7 @@ const Grid = props => {
|
|
|
30487
30787
|
yAxis: axisOptions(props, 1)
|
|
30488
30788
|
}),
|
|
30489
30789
|
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
30490
|
-
props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks,
|
|
30491
|
-
range: props.range,
|
|
30492
|
-
tickStep: props.tickStep,
|
|
30493
|
-
gridStep: props.gridStep
|
|
30494
|
-
}), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)));
|
|
30790
|
+
props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)));
|
|
30495
30791
|
};
|
|
30496
30792
|
|
|
30497
30793
|
// Displays a stylized open eye: lint warnings are visible
|
|
@@ -31557,11 +31853,14 @@ const MafsGraph = props => {
|
|
|
31557
31853
|
labels
|
|
31558
31854
|
} = props;
|
|
31559
31855
|
const [width, height] = props.box;
|
|
31856
|
+
const tickStep = props.step;
|
|
31560
31857
|
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
31561
31858
|
value: {
|
|
31562
31859
|
range: state.range,
|
|
31563
31860
|
snapStep: state.snapStep,
|
|
31564
31861
|
markings: props.markings,
|
|
31862
|
+
tickStep: tickStep,
|
|
31863
|
+
gridStep: props.gridStep,
|
|
31565
31864
|
showTooltips: !!props.showTooltips,
|
|
31566
31865
|
graphDimensionsInPixels: props.box,
|
|
31567
31866
|
width,
|
|
@@ -31575,7 +31874,9 @@ const MafsGraph = props => {
|
|
|
31575
31874
|
height,
|
|
31576
31875
|
position: "relative",
|
|
31577
31876
|
padding: "25px 25px 0 0",
|
|
31578
|
-
boxSizing: "content-box"
|
|
31877
|
+
boxSizing: "content-box",
|
|
31878
|
+
marginLeft: "20px",
|
|
31879
|
+
marginBottom: "20px"
|
|
31579
31880
|
}
|
|
31580
31881
|
}, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
|
|
31581
31882
|
box: props.box,
|
|
@@ -31586,7 +31887,7 @@ const MafsGraph = props => {
|
|
|
31586
31887
|
bottom: 0,
|
|
31587
31888
|
left: 0
|
|
31588
31889
|
}
|
|
31589
|
-
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
31890
|
+
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
31590
31891
|
preserveAspectRatio: false,
|
|
31591
31892
|
viewBox: {
|
|
31592
31893
|
x: state.range[0],
|
|
@@ -43701,7 +44002,7 @@ const init = function (options) {
|
|
|
43701
44002
|
|
|
43702
44003
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43703
44004
|
const libName = "@khanacademy/perseus";
|
|
43704
|
-
const libVersion = "22.
|
|
44005
|
+
const libVersion = "22.6.0";
|
|
43705
44006
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43706
44007
|
|
|
43707
44008
|
const apiVersion = {
|