@khanacademy/perseus 57.1.0 → 57.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.js +109 -24
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +109 -24
- package/dist/index.js.map +1 -1
- package/dist/widgets/interactive-graphs/backgrounds/axis-labels.d.ts +9 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +3 -1
- package/dist/widgets/interactive-graphs/locked-figures/utils.d.ts +1 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +2 -1
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +1 -0
- package/package.json +7 -7
package/dist/es/index.js
CHANGED
|
@@ -24998,7 +24998,7 @@ class GradedGroupAnswerBar extends React.Component {
|
|
|
24998
24998
|
}
|
|
24999
24999
|
}
|
|
25000
25000
|
GradedGroupAnswerBar.contextType = PerseusI18nContext;
|
|
25001
|
-
const fontSize = 17;
|
|
25001
|
+
const fontSize$1 = 17;
|
|
25002
25002
|
const styles$j = {
|
|
25003
25003
|
answerBar: {
|
|
25004
25004
|
display: "flex",
|
|
@@ -25023,7 +25023,7 @@ const styles$j = {
|
|
|
25023
25023
|
flexDirection: "row",
|
|
25024
25024
|
alignItems: "center",
|
|
25025
25025
|
fontWeight: "bold",
|
|
25026
|
-
fontSize: fontSize
|
|
25026
|
+
fontSize: fontSize$1
|
|
25027
25027
|
}
|
|
25028
25028
|
};
|
|
25029
25029
|
|
|
@@ -27679,6 +27679,7 @@ const defaultGraphConfig = {
|
|
|
27679
27679
|
width: 0,
|
|
27680
27680
|
height: 0,
|
|
27681
27681
|
labels: [],
|
|
27682
|
+
labelLocation: "onAxis",
|
|
27682
27683
|
disableKeyboardInteraction: false,
|
|
27683
27684
|
interactiveColor: "var(--mafs-blue)"
|
|
27684
27685
|
};
|
|
@@ -27894,6 +27895,8 @@ function escapeIfUnescaped(character) {
|
|
|
27894
27895
|
}
|
|
27895
27896
|
}
|
|
27896
27897
|
|
|
27898
|
+
// Exported for testing purposes
|
|
27899
|
+
const fontSize = 14;
|
|
27897
27900
|
function AxisLabels({
|
|
27898
27901
|
i18n
|
|
27899
27902
|
}) {
|
|
@@ -27901,24 +27904,27 @@ function AxisLabels({
|
|
|
27901
27904
|
range,
|
|
27902
27905
|
labels,
|
|
27903
27906
|
width,
|
|
27904
|
-
height
|
|
27907
|
+
height,
|
|
27908
|
+
labelLocation
|
|
27905
27909
|
} = useGraphConfig();
|
|
27906
27910
|
const {
|
|
27907
27911
|
strings
|
|
27908
27912
|
} = i18n;
|
|
27909
|
-
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
27910
|
-
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
27911
|
-
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
27912
27913
|
const graphInfo = {
|
|
27913
27914
|
range,
|
|
27914
27915
|
width,
|
|
27915
27916
|
height
|
|
27916
27917
|
};
|
|
27917
|
-
|
|
27918
|
-
//
|
|
27919
|
-
|
|
27920
|
-
|
|
27921
|
-
|
|
27918
|
+
|
|
27919
|
+
// Get the position of the main axis labels
|
|
27920
|
+
const [xAxisLabelLocation, yAxisLabelLocation] = getLabelPosition(graphInfo, labelLocation);
|
|
27921
|
+
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
27922
|
+
|
|
27923
|
+
// Get the transform for the labels
|
|
27924
|
+
const {
|
|
27925
|
+
xLabelTransform,
|
|
27926
|
+
yLabelTransform
|
|
27927
|
+
} = getLabelTransform(labelLocation);
|
|
27922
27928
|
const {
|
|
27923
27929
|
TeX
|
|
27924
27930
|
} = getDependencies();
|
|
@@ -27926,23 +27932,72 @@ function AxisLabels({
|
|
|
27926
27932
|
"aria-label": strings.xAxis,
|
|
27927
27933
|
style: {
|
|
27928
27934
|
position: "absolute",
|
|
27929
|
-
left:
|
|
27930
|
-
top:
|
|
27931
|
-
fontSize: "
|
|
27932
|
-
transform:
|
|
27935
|
+
left: xAxisLabelLocation[X],
|
|
27936
|
+
top: xAxisLabelLocation[Y],
|
|
27937
|
+
fontSize: fontSize + "px",
|
|
27938
|
+
transform: xLabelTransform
|
|
27933
27939
|
}
|
|
27934
27940
|
}, /*#__PURE__*/React__default.createElement(TeX, null, replaceOutsideTeX(xAxisLabelText))), /*#__PURE__*/React__default.createElement("span", {
|
|
27935
27941
|
"aria-label": strings.yAxis,
|
|
27936
27942
|
style: {
|
|
27937
27943
|
position: "absolute",
|
|
27938
|
-
left:
|
|
27939
|
-
top:
|
|
27940
|
-
fontSize: "
|
|
27941
|
-
transform:
|
|
27944
|
+
left: yAxisLabelLocation[X],
|
|
27945
|
+
top: yAxisLabelLocation[Y],
|
|
27946
|
+
fontSize: fontSize + "px",
|
|
27947
|
+
transform: yLabelTransform
|
|
27942
27948
|
}
|
|
27943
27949
|
}, /*#__PURE__*/React__default.createElement(TeX, null, replaceOutsideTeX(yAxisLabelText))));
|
|
27944
27950
|
}
|
|
27945
27951
|
|
|
27952
|
+
/* Get the transform for the labels based on the labelLocation
|
|
27953
|
+
* Exported for testing purposes.
|
|
27954
|
+
*/
|
|
27955
|
+
const getLabelTransform = labelLocation => {
|
|
27956
|
+
// onAxis is the default label location
|
|
27957
|
+
const isOnAxis = labelLocation === undefined || labelLocation === "onAxis";
|
|
27958
|
+
const xLabelTransform = isOnAxis ? "translate(7px, -50%)" : "translate(-50%, -50%)";
|
|
27959
|
+
const yLabelTransform = isOnAxis ? "translate(-50%, 0px)" : "translate(-50%, 0px) rotate(-90deg)";
|
|
27960
|
+
return {
|
|
27961
|
+
xLabelTransform,
|
|
27962
|
+
yLabelTransform
|
|
27963
|
+
};
|
|
27964
|
+
};
|
|
27965
|
+
|
|
27966
|
+
/* Calculate the position of the main axis labels based on the labelLocation
|
|
27967
|
+
* and the ranges of the graph. Exported for testing purposes.
|
|
27968
|
+
*/
|
|
27969
|
+
const getLabelPosition = (graphInfo, labelLocation) => {
|
|
27970
|
+
// If the labels are placed along the edge of the graph, we need to place them at the
|
|
27971
|
+
// center of the graph, which is the average of the min and max values of the axes.
|
|
27972
|
+
if (labelLocation === "alongEdge") {
|
|
27973
|
+
// Offset the labels by a certain amount based on the range of the graph, to ensure that
|
|
27974
|
+
// the labels do not overlap with the axis tick if they are out of the graph bounds.
|
|
27975
|
+
const xAxisLabelOffset = graphInfo.range[Y][MIN] >= 0 ? [0, fontSize * 3] // Move the label down by 3 font sizes if the y-axis min is positive
|
|
27976
|
+
: [0, fontSize]; // Move the label down by 1 font size if the y-axis min is negative
|
|
27977
|
+
const yAxisLabelOffset = graphInfo.range[X][MIN] >= 0 ? [-fontSize * 3, -fontSize] // Move the label left by 3 font sizes if the x-axis min is positive
|
|
27978
|
+
: [-fontSize, -fontSize]; // Move the label left by 1 font size if the x-axis min is negative
|
|
27979
|
+
|
|
27980
|
+
// Calculate the location of the labels to be halfway between the min and max values of the axes
|
|
27981
|
+
const xAxisLabelLocation = [(graphInfo.range[X][MIN] + graphInfo.range[X][MAX]) / 2, graphInfo.range[Y][MIN]];
|
|
27982
|
+
const yAxisLabelLocation = [graphInfo.range[X][MIN], (graphInfo.range[Y][MIN] + graphInfo.range[Y][MAX]) / 2];
|
|
27983
|
+
|
|
27984
|
+
// Convert the Vector2 coordinates to pixel coordinates and add the offsets
|
|
27985
|
+
const _xLabel = vec.add(pointToPixel(xAxisLabelLocation, graphInfo), xAxisLabelOffset);
|
|
27986
|
+
const _yLabel = vec.add(pointToPixel(yAxisLabelLocation, graphInfo), yAxisLabelOffset);
|
|
27987
|
+
return [_xLabel, _yLabel];
|
|
27988
|
+
}
|
|
27989
|
+
|
|
27990
|
+
// Otherwise, the labels are placed on the axes (default), and we need to
|
|
27991
|
+
// place them at the end of the axis, which is the maximum value of the axis.
|
|
27992
|
+
const xLabelInitial = [graphInfo.range[X][MAX], 0];
|
|
27993
|
+
const yLabelInitial = [0, graphInfo.range[Y][MAX]];
|
|
27994
|
+
const yLabelOffset = [0, -fontSize * 2]; // Move the y-axis label up by 2 font sizes
|
|
27995
|
+
|
|
27996
|
+
const xLabel = pointToPixel(xLabelInitial, graphInfo);
|
|
27997
|
+
const yLabel = vec.add(pointToPixel(yLabelInitial, graphInfo), yLabelOffset);
|
|
27998
|
+
return [xLabel, yLabel];
|
|
27999
|
+
};
|
|
28000
|
+
|
|
27946
28001
|
// The size of the ticks and labels in pixels
|
|
27947
28002
|
const tickSize = 10;
|
|
27948
28003
|
const tickLabelSize = 14;
|
|
@@ -28873,7 +28928,28 @@ const LockedEllipse = props => {
|
|
|
28873
28928
|
}));
|
|
28874
28929
|
};
|
|
28875
28930
|
|
|
28931
|
+
function clampDomain(domain, graphBounds) {
|
|
28932
|
+
// If the domain is invalid, return the graph bounds
|
|
28933
|
+
if (domain[0] > domain[1]) {
|
|
28934
|
+
return graphBounds;
|
|
28935
|
+
}
|
|
28936
|
+
|
|
28937
|
+
// If the domain is outside the graph bounds, return null
|
|
28938
|
+
if (domain[0] < graphBounds[0] && domain[1] < graphBounds[0] || domain[0] > graphBounds[1] && domain[1] > graphBounds[1]) {
|
|
28939
|
+
return null;
|
|
28940
|
+
}
|
|
28941
|
+
|
|
28942
|
+
// Clamp the function to the bounds of the graph to prevent memory
|
|
28943
|
+
// leaks when the domain is set to something like [-Infinity, Infinity].
|
|
28944
|
+
const min = Math.max(domain[0], graphBounds[0]);
|
|
28945
|
+
const max = Math.min(domain[1], graphBounds[1]);
|
|
28946
|
+
return [min, max];
|
|
28947
|
+
}
|
|
28948
|
+
|
|
28876
28949
|
const LockedFunction = props => {
|
|
28950
|
+
const {
|
|
28951
|
+
range
|
|
28952
|
+
} = useGraphConfig();
|
|
28877
28953
|
const [equation, setEquation] = useState();
|
|
28878
28954
|
const {
|
|
28879
28955
|
color,
|
|
@@ -28883,8 +28959,7 @@ const LockedFunction = props => {
|
|
|
28883
28959
|
} = props;
|
|
28884
28960
|
const plotProps = {
|
|
28885
28961
|
color: lockedFigureColors[color],
|
|
28886
|
-
style: strokeStyle
|
|
28887
|
-
domain
|
|
28962
|
+
style: strokeStyle
|
|
28888
28963
|
};
|
|
28889
28964
|
const hasAria = !!props.ariaLabel;
|
|
28890
28965
|
useEffect(() => {
|
|
@@ -28895,6 +28970,12 @@ const LockedFunction = props => {
|
|
|
28895
28970
|
if (typeof equation === "undefined") {
|
|
28896
28971
|
return null;
|
|
28897
28972
|
}
|
|
28973
|
+
const clampedDomain = directionalAxis === "x" ? clampDomain(domain, range[0]) : clampDomain(domain, range[1]);
|
|
28974
|
+
|
|
28975
|
+
// The domain entirely is outside the bounds of the graph. Don't render.
|
|
28976
|
+
if (clampedDomain === null) {
|
|
28977
|
+
return null;
|
|
28978
|
+
}
|
|
28898
28979
|
return /*#__PURE__*/React.createElement("g", {
|
|
28899
28980
|
className: "locked-function",
|
|
28900
28981
|
"aria-label": hasAria ? props.ariaLabel : undefined,
|
|
@@ -28903,11 +28984,13 @@ const LockedFunction = props => {
|
|
|
28903
28984
|
}, directionalAxis === "x" && /*#__PURE__*/React.createElement(Plot$2.OfX, _extends({
|
|
28904
28985
|
y: x => equation.eval({
|
|
28905
28986
|
x
|
|
28906
|
-
})
|
|
28987
|
+
}),
|
|
28988
|
+
domain: clampedDomain
|
|
28907
28989
|
}, plotProps)), directionalAxis === "y" && /*#__PURE__*/React.createElement(Plot$2.OfY, _extends({
|
|
28908
28990
|
x: y => equation.eval({
|
|
28909
28991
|
y
|
|
28910
|
-
})
|
|
28992
|
+
}),
|
|
28993
|
+
domain: clampedDomain
|
|
28911
28994
|
}, plotProps)));
|
|
28912
28995
|
};
|
|
28913
28996
|
|
|
@@ -34200,6 +34283,7 @@ const MafsGraph = props => {
|
|
|
34200
34283
|
state,
|
|
34201
34284
|
dispatch,
|
|
34202
34285
|
labels,
|
|
34286
|
+
labelLocation,
|
|
34203
34287
|
readOnly,
|
|
34204
34288
|
fullGraphAriaLabel,
|
|
34205
34289
|
fullGraphAriaDescription
|
|
@@ -34280,6 +34364,7 @@ const MafsGraph = props => {
|
|
|
34280
34364
|
width,
|
|
34281
34365
|
height,
|
|
34282
34366
|
labels,
|
|
34367
|
+
labelLocation,
|
|
34283
34368
|
disableKeyboardInteraction: disableInteraction,
|
|
34284
34369
|
// If the graph is read-only or static, we want to make it
|
|
34285
34370
|
// visually clear that the graph is no longer interactive.
|
|
@@ -41391,7 +41476,7 @@ const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
|
41391
41476
|
|
|
41392
41477
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
41393
41478
|
const libName = "@khanacademy/perseus";
|
|
41394
|
-
const libVersion = "57.1
|
|
41479
|
+
const libVersion = "57.2.1";
|
|
41395
41480
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
41396
41481
|
|
|
41397
41482
|
const apiVersion = {
|