@khanacademy/perseus 33.0.0 → 33.1.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 +15 -44
- package/dist/es/index.js +310 -435
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +15 -44
- package/dist/index.js +311 -438
- package/dist/index.js.map +1 -1
- package/dist/perseus-api.d.ts +0 -7
- package/dist/server-item-renderer.d.ts +0 -7
- package/dist/types.d.ts +1 -4
- package/dist/widgets/expression/expression.d.ts +0 -42
- package/dist/widgets/interactive-graphs/backgrounds/axis-ticks.d.ts +2 -0
- package/dist/widgets/interactive-graphs/backgrounds/grid.d.ts +2 -10
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +5 -0
- package/dist/widgets/label-image/label-image.d.ts +0 -14
- package/package.json +1 -1
- package/dist/widgets/interactive-graphs/backgrounds/axis-tick-labels.d.ts +0 -13
package/dist/index.js
CHANGED
|
@@ -28617,6 +28617,95 @@ class Graph extends React__namespace.Component {
|
|
|
28617
28617
|
}
|
|
28618
28618
|
}
|
|
28619
28619
|
|
|
28620
|
+
function pathBuilder() {
|
|
28621
|
+
return new PathBuilder();
|
|
28622
|
+
}
|
|
28623
|
+
class PathBuilder {
|
|
28624
|
+
path = [];
|
|
28625
|
+
scaleFactor = 1;
|
|
28626
|
+
build() {
|
|
28627
|
+
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28628
|
+
}
|
|
28629
|
+
|
|
28630
|
+
// add a move (M) command to the path
|
|
28631
|
+
move(x, y) {
|
|
28632
|
+
this.path.push({
|
|
28633
|
+
action: "M",
|
|
28634
|
+
args: [x, y]
|
|
28635
|
+
});
|
|
28636
|
+
return this;
|
|
28637
|
+
}
|
|
28638
|
+
line(x, y) {
|
|
28639
|
+
this.path.push({
|
|
28640
|
+
action: "L",
|
|
28641
|
+
args: [x, y]
|
|
28642
|
+
});
|
|
28643
|
+
return this;
|
|
28644
|
+
}
|
|
28645
|
+
circularArc(radius, toX, toY) {
|
|
28646
|
+
let {
|
|
28647
|
+
sweep = false,
|
|
28648
|
+
largeArc = false
|
|
28649
|
+
} = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
28650
|
+
this.path.push({
|
|
28651
|
+
action: "A",
|
|
28652
|
+
args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
|
|
28653
|
+
});
|
|
28654
|
+
return this;
|
|
28655
|
+
}
|
|
28656
|
+
|
|
28657
|
+
// add a curve (C) command to the path
|
|
28658
|
+
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28659
|
+
this.path.push({
|
|
28660
|
+
action: "C",
|
|
28661
|
+
args: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28662
|
+
});
|
|
28663
|
+
return this;
|
|
28664
|
+
}
|
|
28665
|
+
|
|
28666
|
+
// Scale all coordinates of the path by a factor
|
|
28667
|
+
scale(factor) {
|
|
28668
|
+
this.scaleFactor *= factor;
|
|
28669
|
+
return this;
|
|
28670
|
+
}
|
|
28671
|
+
}
|
|
28672
|
+
function commandToString(command) {
|
|
28673
|
+
return `${command.action}${command.args.join(" ")}`;
|
|
28674
|
+
}
|
|
28675
|
+
function scaleCommandBy(scaleFactor) {
|
|
28676
|
+
return command => {
|
|
28677
|
+
switch (command.action) {
|
|
28678
|
+
case "A":
|
|
28679
|
+
// TODO(benchristel): do we want to refactor this switch to
|
|
28680
|
+
// use polymorphism?
|
|
28681
|
+
// Arc command
|
|
28682
|
+
return {
|
|
28683
|
+
...command,
|
|
28684
|
+
args: [command.args[0] * scaleFactor,
|
|
28685
|
+
// x radius
|
|
28686
|
+
command.args[1] * scaleFactor,
|
|
28687
|
+
// y radius
|
|
28688
|
+
command.args[2],
|
|
28689
|
+
// rotation
|
|
28690
|
+
command.args[3],
|
|
28691
|
+
// largeArc flag
|
|
28692
|
+
command.args[4],
|
|
28693
|
+
// sweep flag
|
|
28694
|
+
command.args[5] * scaleFactor,
|
|
28695
|
+
// end x
|
|
28696
|
+
command.args[6] * scaleFactor // end y
|
|
28697
|
+
]
|
|
28698
|
+
};
|
|
28699
|
+
|
|
28700
|
+
default:
|
|
28701
|
+
return {
|
|
28702
|
+
...command,
|
|
28703
|
+
args: command.args.map(c => c * scaleFactor)
|
|
28704
|
+
};
|
|
28705
|
+
}
|
|
28706
|
+
};
|
|
28707
|
+
}
|
|
28708
|
+
|
|
28620
28709
|
// Restricts `value` to be between `min` and `max`.
|
|
28621
28710
|
function clamp(value, min, max) {
|
|
28622
28711
|
if (value < min) {
|
|
@@ -28846,380 +28935,6 @@ function pixelsToVectors(pixels, graphState) {
|
|
|
28846
28935
|
});
|
|
28847
28936
|
}
|
|
28848
28937
|
|
|
28849
|
-
function AxisLabels() {
|
|
28850
|
-
const {
|
|
28851
|
-
range,
|
|
28852
|
-
labels,
|
|
28853
|
-
width,
|
|
28854
|
-
height
|
|
28855
|
-
} = useGraphConfig();
|
|
28856
|
-
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
28857
|
-
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
28858
|
-
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
28859
|
-
const graphInfo = {
|
|
28860
|
-
range,
|
|
28861
|
-
width,
|
|
28862
|
-
height
|
|
28863
|
-
};
|
|
28864
|
-
const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
|
|
28865
|
-
// The default location for the y-axis-label is at the maximum y point
|
|
28866
|
-
// This is just underneath the tick line for that point. The -24 moves the
|
|
28867
|
-
// label up one grid square, so it sits on top of the graph
|
|
28868
|
-
const [x2, y2] = mafs.vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
|
|
28869
|
-
const {
|
|
28870
|
-
TeX
|
|
28871
|
-
} = getDependencies();
|
|
28872
|
-
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("span", {
|
|
28873
|
-
style: {
|
|
28874
|
-
position: "absolute",
|
|
28875
|
-
left: x1,
|
|
28876
|
-
top: y1,
|
|
28877
|
-
fontSize: "14px",
|
|
28878
|
-
transform: "translate(7px, -50%)"
|
|
28879
|
-
}
|
|
28880
|
-
}, /*#__PURE__*/React__default["default"].createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default["default"].createElement("span", {
|
|
28881
|
-
style: {
|
|
28882
|
-
position: "absolute",
|
|
28883
|
-
left: x2,
|
|
28884
|
-
top: y2,
|
|
28885
|
-
fontSize: "14px",
|
|
28886
|
-
transform: "translate(-50%, 0px)"
|
|
28887
|
-
}
|
|
28888
|
-
}, /*#__PURE__*/React__default["default"].createElement(TeX, null, yAxisLabelText)));
|
|
28889
|
-
}
|
|
28890
|
-
|
|
28891
|
-
// Universal padding for the axis ticks to ensure that the labels
|
|
28892
|
-
// have enough space to render without overlapping the tick lines
|
|
28893
|
-
const tickPadding = 5;
|
|
28894
|
-
const AxisTickLabels = () => {
|
|
28895
|
-
const graphConfig = useGraphConfig();
|
|
28896
|
-
const {
|
|
28897
|
-
tickStep,
|
|
28898
|
-
range
|
|
28899
|
-
} = graphConfig;
|
|
28900
|
-
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28901
|
-
const [xTickStep, yTickStep] = tickStep;
|
|
28902
|
-
const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
|
|
28903
|
-
const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
|
|
28904
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
28905
|
-
className: "axis-tick-labels"
|
|
28906
|
-
}, /*#__PURE__*/React__namespace.createElement(YGridAxis, {
|
|
28907
|
-
axisTicks: yGridTicks,
|
|
28908
|
-
graphConfig: graphConfig
|
|
28909
|
-
}), /*#__PURE__*/React__namespace.createElement(XGridAxis, {
|
|
28910
|
-
axisTicks: xGridTicks,
|
|
28911
|
-
graphConfig: graphConfig
|
|
28912
|
-
}));
|
|
28913
|
-
};
|
|
28914
|
-
|
|
28915
|
-
// Generate the necessary styles and ticks for the y-axis tick labels container
|
|
28916
|
-
const YGridAxis = props => {
|
|
28917
|
-
const {
|
|
28918
|
-
axisTicks,
|
|
28919
|
-
graphConfig
|
|
28920
|
-
} = props;
|
|
28921
|
-
const {
|
|
28922
|
-
width,
|
|
28923
|
-
height
|
|
28924
|
-
} = graphConfig;
|
|
28925
|
-
|
|
28926
|
-
// First get the label height by calculating the difference between the first two y-axis labels
|
|
28927
|
-
const yTopPoint = pointToPixel([0, axisTicks[0]], graphConfig);
|
|
28928
|
-
const ySecondPoint = pointToPixel([0, axisTicks[1]], graphConfig);
|
|
28929
|
-
const yLabelHeight = ySecondPoint[1] - yTopPoint[1];
|
|
28930
|
-
|
|
28931
|
-
// When rendering purely positive y-axis labels, we want to adjust the left position
|
|
28932
|
-
// from the lowest calculated tick, as yMin may be negative
|
|
28933
|
-
const yLowestTick = axisTicks[axisTicks.length - 1];
|
|
28934
|
-
const yLeftAdjustment = Math.min(Math.max(yTopPoint[0] - tickPadding, 0), width);
|
|
28935
|
-
|
|
28936
|
-
// We only want to render the 0 label on the y-axis if it is left of the grid
|
|
28937
|
-
const yAxisIsLeftOfGrid = yLeftAdjustment === 0;
|
|
28938
|
-
|
|
28939
|
-
// If the y-axis is right of the graph's viewbox/range,
|
|
28940
|
-
// we want to adjust both the positioning and text alignment
|
|
28941
|
-
const yAxisRightOfGrid = yLeftAdjustment === width;
|
|
28942
|
-
|
|
28943
|
-
// Determine the default spacing for the labels based on whether the y-axis is right of the grid
|
|
28944
|
-
const defaultSpacing = yAxisRightOfGrid ? 0.5 : 0;
|
|
28945
|
-
|
|
28946
|
-
// We also want to adjust the spacing if there are no negative y-axis labels as the extra space is not needed
|
|
28947
|
-
const marginSpacing = yLowestTick >= 0 ? defaultSpacing * 2 : defaultSpacing;
|
|
28948
|
-
|
|
28949
|
-
// Determine the text alignment based on whether the y-axis is right of the grid
|
|
28950
|
-
// We need to cast this as a const as it is used in the inline styles
|
|
28951
|
-
const textAlign = yAxisRightOfGrid ? "left" : "right";
|
|
28952
|
-
const yAxisStyles = {
|
|
28953
|
-
left: `calc(${yLeftAdjustment}px - ${marginSpacing}em)`,
|
|
28954
|
-
top: `calc(${yTopPoint[1]}px - 0.5em)`,
|
|
28955
|
-
height,
|
|
28956
|
-
textAlign,
|
|
28957
|
-
"--y-axis-label-height": yLabelHeight + "px"
|
|
28958
|
-
};
|
|
28959
|
-
const classNames = yAxisRightOfGrid ? "y-axis-tick-labels y-axis-right-of-grid" : "y-axis-tick-labels ";
|
|
28960
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
28961
|
-
className: classNames,
|
|
28962
|
-
"data-testid": "y-axis-tick-labels",
|
|
28963
|
-
style: yAxisStyles
|
|
28964
|
-
}, axisTicks.map(label => {
|
|
28965
|
-
return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
|
|
28966
|
-
label: label,
|
|
28967
|
-
axis: "y",
|
|
28968
|
-
key: `y-grid-tick-${label}`,
|
|
28969
|
-
graphConfig: graphConfig,
|
|
28970
|
-
axisOutOfBounds: yAxisIsLeftOfGrid
|
|
28971
|
-
});
|
|
28972
|
-
}));
|
|
28973
|
-
};
|
|
28974
|
-
|
|
28975
|
-
// Generate the necessary styles and ticks for the x-axis tick labels container
|
|
28976
|
-
const XGridAxis = props => {
|
|
28977
|
-
const {
|
|
28978
|
-
axisTicks,
|
|
28979
|
-
graphConfig
|
|
28980
|
-
} = props;
|
|
28981
|
-
const {
|
|
28982
|
-
width,
|
|
28983
|
-
height
|
|
28984
|
-
} = graphConfig;
|
|
28985
|
-
|
|
28986
|
-
// Determine label width by calculating the difference between the first two x-axis labels
|
|
28987
|
-
const xFirstPoint = pointToPixel([axisTicks[0], 0], graphConfig);
|
|
28988
|
-
const xSecondPoint = pointToPixel([axisTicks[1], 0], graphConfig);
|
|
28989
|
-
const xLabelWidth = Math.abs(xSecondPoint[0] - xFirstPoint[0]);
|
|
28990
|
-
|
|
28991
|
-
// Determine the top position of the x-axis labels based on
|
|
28992
|
-
// whether the x-axis is above, within, or below the graph
|
|
28993
|
-
const xAxisAboveGraph = xFirstPoint[1] < 0;
|
|
28994
|
-
const xTopAdjustment = xAxisAboveGraph ? 0 : Math.min(xFirstPoint[1] + tickPadding, height);
|
|
28995
|
-
|
|
28996
|
-
// Determine whether the x-axis is outside of the graph's viewbox/range
|
|
28997
|
-
// This is used to conditionally render the 0 label on the x-axis
|
|
28998
|
-
const xAxisOutOfBounds = xTopAdjustment === height || xAxisAboveGraph;
|
|
28999
|
-
|
|
29000
|
-
// Determine the available space to the right of the x-axis labels
|
|
29001
|
-
const availableSpaceRight = width - xFirstPoint[0];
|
|
29002
|
-
|
|
29003
|
-
// Calculate the total combined width of ALL the x-axis labels
|
|
29004
|
-
const axisTicksWidth = axisTicks.length * xLabelWidth;
|
|
29005
|
-
|
|
29006
|
-
// Determine if we need to increase the width of the axis past the graph width
|
|
29007
|
-
const calculatedWidth = axisTicksWidth > width ? axisTicksWidth : width;
|
|
29008
|
-
|
|
29009
|
-
// Determine the right adjustment for the x-axis labels based on the available space
|
|
29010
|
-
// We're adjusting the right as the flex-direction is row-reverse
|
|
29011
|
-
const xRightAdjustment = availableSpaceRight - xLabelWidth / 2;
|
|
29012
|
-
const xAxisStyles = {
|
|
29013
|
-
top: xTopAdjustment,
|
|
29014
|
-
right: xRightAdjustment,
|
|
29015
|
-
width: calculatedWidth,
|
|
29016
|
-
"--x-axis-label-width": xLabelWidth + "px"
|
|
29017
|
-
};
|
|
29018
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
29019
|
-
className: `x-axis-tick-labels ${xAxisAboveGraph && "x-axis-top-of-grid"}`,
|
|
29020
|
-
"data-testid": "x-axis-tick-labels",
|
|
29021
|
-
style: xAxisStyles
|
|
29022
|
-
}, axisTicks.map(label => {
|
|
29023
|
-
return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
|
|
29024
|
-
axis: "x",
|
|
29025
|
-
label: label,
|
|
29026
|
-
key: `x-grid-tick-${label}`,
|
|
29027
|
-
graphConfig: graphConfig,
|
|
29028
|
-
axisOutOfBounds: xAxisOutOfBounds
|
|
29029
|
-
});
|
|
29030
|
-
}));
|
|
29031
|
-
};
|
|
29032
|
-
|
|
29033
|
-
// Generate the individual tick label elements
|
|
29034
|
-
const AxisTickLabel = _ref => {
|
|
29035
|
-
let {
|
|
29036
|
-
label,
|
|
29037
|
-
graphConfig,
|
|
29038
|
-
axisOutOfBounds,
|
|
29039
|
-
axis
|
|
29040
|
-
} = _ref;
|
|
29041
|
-
const {
|
|
29042
|
-
gridStep,
|
|
29043
|
-
tickStep
|
|
29044
|
-
} = graphConfig;
|
|
29045
|
-
// Determine the point on the axis based on the axis type
|
|
29046
|
-
const pointOnAxis = axis === "x" ? [label, 0] : [0, label];
|
|
29047
|
-
const pixelPoint = pointToPixel(pointOnAxis, graphConfig);
|
|
29048
|
-
|
|
29049
|
-
// Determine the relevant edge of the graph based on the axis type
|
|
29050
|
-
const graphEdge = axis === "x" ? graphConfig.width : graphConfig.height;
|
|
29051
|
-
|
|
29052
|
-
// Determine the vector index based on the axis type
|
|
29053
|
-
const vectorIndex = axis === "x" ? 0 : 1;
|
|
29054
|
-
|
|
29055
|
-
// Determine whether or not to render the tick label text
|
|
29056
|
-
const shouldShowLabel = showTickLabel({
|
|
29057
|
-
label,
|
|
29058
|
-
axisOutOfBounds,
|
|
29059
|
-
graphEdge,
|
|
29060
|
-
position: pixelPoint[vectorIndex],
|
|
29061
|
-
gridStep: gridStep[vectorIndex],
|
|
29062
|
-
tickStep: tickStep[vectorIndex]
|
|
29063
|
-
});
|
|
29064
|
-
return /*#__PURE__*/React__namespace.createElement("span", {
|
|
29065
|
-
className: `${axis}-axis-tick-label`
|
|
29066
|
-
}, shouldShowLabel && label);
|
|
29067
|
-
};
|
|
29068
|
-
|
|
29069
|
-
// Determine whether or not to show the tick label text
|
|
29070
|
-
const showTickLabel = _ref2 => {
|
|
29071
|
-
let {
|
|
29072
|
-
gridStep,
|
|
29073
|
-
tickStep,
|
|
29074
|
-
label,
|
|
29075
|
-
graphEdge,
|
|
29076
|
-
position,
|
|
29077
|
-
axisOutOfBounds
|
|
29078
|
-
} = _ref2;
|
|
29079
|
-
let showLabel = true;
|
|
29080
|
-
|
|
29081
|
-
// We only want to show the initial negative tick labels (e.g. -1) on each
|
|
29082
|
-
// axis if the tickStep > gridStep, to ensure that these labels do not overlap.
|
|
29083
|
-
// e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
|
|
29084
|
-
// which allows enough room for both these tick labels to render.
|
|
29085
|
-
showLabel = tickStep > gridStep ? true : label !== -tickStep;
|
|
29086
|
-
|
|
29087
|
-
// If the tick label position is greater than the relevant edge of the graph, don't render it
|
|
29088
|
-
if (position <= -graphEdge || position >= graphEdge) {
|
|
29089
|
-
showLabel = false;
|
|
29090
|
-
}
|
|
29091
|
-
|
|
29092
|
-
// If the label is 0, we only want to show it if the axis is to the left of the graph's viewbox/range
|
|
29093
|
-
// otherwise it will overlap with graph axis labels
|
|
29094
|
-
if (label === 0 && !axisOutOfBounds) {
|
|
29095
|
-
showLabel = false;
|
|
29096
|
-
}
|
|
29097
|
-
return showLabel;
|
|
29098
|
-
};
|
|
29099
|
-
|
|
29100
|
-
// Generate the tick labels for an axis based on the tick step
|
|
29101
|
-
function generateTickLocations$1(tickStep, min, max) {
|
|
29102
|
-
const positiveTicks = [];
|
|
29103
|
-
const negativeTicks = [];
|
|
29104
|
-
const ticks = [];
|
|
29105
|
-
|
|
29106
|
-
// Add 0 if it is applicable.
|
|
29107
|
-
// This will be conditionally rendered using showTickLabel.
|
|
29108
|
-
if (min <= 0 && max >= 0) {
|
|
29109
|
-
positiveTicks.push(0);
|
|
29110
|
-
}
|
|
29111
|
-
|
|
29112
|
-
// Add ticks on the positive axis
|
|
29113
|
-
// Start at the first tick after 0 or the minimum value,
|
|
29114
|
-
// taking into account that the graph may be zoomed in on the positive axis
|
|
29115
|
-
let i = Math.max(min, 0) + tickStep;
|
|
29116
|
-
for (i; min < i && i < max; i += tickStep) {
|
|
29117
|
-
positiveTicks.push(i);
|
|
29118
|
-
}
|
|
29119
|
-
|
|
29120
|
-
// Add ticks on the negative axis
|
|
29121
|
-
// Start at the first tick before 0 or the maximum value,
|
|
29122
|
-
// taking into account that the graph may be zoomed in on the negative axis
|
|
29123
|
-
i = Math.min(max, 0) - tickStep;
|
|
29124
|
-
for (i; i > min; i -= tickStep) {
|
|
29125
|
-
negativeTicks.push(i);
|
|
29126
|
-
}
|
|
29127
|
-
|
|
29128
|
-
// Reverse the ticks so that they are in the correct render order
|
|
29129
|
-
positiveTicks.reverse();
|
|
29130
|
-
ticks.push(...positiveTicks, ...negativeTicks);
|
|
29131
|
-
return ticks;
|
|
29132
|
-
}
|
|
29133
|
-
|
|
29134
|
-
function pathBuilder() {
|
|
29135
|
-
return new PathBuilder();
|
|
29136
|
-
}
|
|
29137
|
-
class PathBuilder {
|
|
29138
|
-
path = [];
|
|
29139
|
-
scaleFactor = 1;
|
|
29140
|
-
build() {
|
|
29141
|
-
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
29142
|
-
}
|
|
29143
|
-
|
|
29144
|
-
// add a move (M) command to the path
|
|
29145
|
-
move(x, y) {
|
|
29146
|
-
this.path.push({
|
|
29147
|
-
action: "M",
|
|
29148
|
-
args: [x, y]
|
|
29149
|
-
});
|
|
29150
|
-
return this;
|
|
29151
|
-
}
|
|
29152
|
-
line(x, y) {
|
|
29153
|
-
this.path.push({
|
|
29154
|
-
action: "L",
|
|
29155
|
-
args: [x, y]
|
|
29156
|
-
});
|
|
29157
|
-
return this;
|
|
29158
|
-
}
|
|
29159
|
-
circularArc(radius, toX, toY) {
|
|
29160
|
-
let {
|
|
29161
|
-
sweep = false,
|
|
29162
|
-
largeArc = false
|
|
29163
|
-
} = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
29164
|
-
this.path.push({
|
|
29165
|
-
action: "A",
|
|
29166
|
-
args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
|
|
29167
|
-
});
|
|
29168
|
-
return this;
|
|
29169
|
-
}
|
|
29170
|
-
|
|
29171
|
-
// add a curve (C) command to the path
|
|
29172
|
-
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
29173
|
-
this.path.push({
|
|
29174
|
-
action: "C",
|
|
29175
|
-
args: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
29176
|
-
});
|
|
29177
|
-
return this;
|
|
29178
|
-
}
|
|
29179
|
-
|
|
29180
|
-
// Scale all coordinates of the path by a factor
|
|
29181
|
-
scale(factor) {
|
|
29182
|
-
this.scaleFactor *= factor;
|
|
29183
|
-
return this;
|
|
29184
|
-
}
|
|
29185
|
-
}
|
|
29186
|
-
function commandToString(command) {
|
|
29187
|
-
return `${command.action}${command.args.join(" ")}`;
|
|
29188
|
-
}
|
|
29189
|
-
function scaleCommandBy(scaleFactor) {
|
|
29190
|
-
return command => {
|
|
29191
|
-
switch (command.action) {
|
|
29192
|
-
case "A":
|
|
29193
|
-
// TODO(benchristel): do we want to refactor this switch to
|
|
29194
|
-
// use polymorphism?
|
|
29195
|
-
// Arc command
|
|
29196
|
-
return {
|
|
29197
|
-
...command,
|
|
29198
|
-
args: [command.args[0] * scaleFactor,
|
|
29199
|
-
// x radius
|
|
29200
|
-
command.args[1] * scaleFactor,
|
|
29201
|
-
// y radius
|
|
29202
|
-
command.args[2],
|
|
29203
|
-
// rotation
|
|
29204
|
-
command.args[3],
|
|
29205
|
-
// largeArc flag
|
|
29206
|
-
command.args[4],
|
|
29207
|
-
// sweep flag
|
|
29208
|
-
command.args[5] * scaleFactor,
|
|
29209
|
-
// end x
|
|
29210
|
-
command.args[6] * scaleFactor // end y
|
|
29211
|
-
]
|
|
29212
|
-
};
|
|
29213
|
-
|
|
29214
|
-
default:
|
|
29215
|
-
return {
|
|
29216
|
-
...command,
|
|
29217
|
-
args: command.args.map(c => c * scaleFactor)
|
|
29218
|
-
};
|
|
29219
|
-
}
|
|
29220
|
-
};
|
|
29221
|
-
}
|
|
29222
|
-
|
|
29223
28938
|
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
29224
28939
|
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
29225
28940
|
// transform because a transform would also scale up the stroke weight, and we
|
|
@@ -29249,7 +28964,10 @@ function AxisArrows() {
|
|
|
29249
28964
|
range: [[xMin, xMax], [yMin, yMax]]
|
|
29250
28965
|
} = useGraphConfig();
|
|
29251
28966
|
const axisColor = "var(--mafs-fg)";
|
|
29252
|
-
|
|
28967
|
+
|
|
28968
|
+
// Only render the arrows if the axis is within the visible range
|
|
28969
|
+
// as otherwise the arrows will be rendered outside the graph
|
|
28970
|
+
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, !(yMin > 0 || yMax < 0) && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
|
|
29253
28971
|
color: axisColor,
|
|
29254
28972
|
tip: [xMin, 0],
|
|
29255
28973
|
angle: 180
|
|
@@ -29257,7 +28975,7 @@ function AxisArrows() {
|
|
|
29257
28975
|
color: axisColor,
|
|
29258
28976
|
tip: [xMax, 0],
|
|
29259
28977
|
angle: 0
|
|
29260
|
-
}), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
|
|
28978
|
+
})), !(xMin > 0 || xMax < 0) && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
|
|
29261
28979
|
color: axisColor,
|
|
29262
28980
|
tip: [0, yMin],
|
|
29263
28981
|
angle: 90
|
|
@@ -29265,39 +28983,76 @@ function AxisArrows() {
|
|
|
29265
28983
|
color: axisColor,
|
|
29266
28984
|
tip: [0, yMax],
|
|
29267
28985
|
angle: 270
|
|
29268
|
-
}));
|
|
28986
|
+
})));
|
|
28987
|
+
}
|
|
28988
|
+
|
|
28989
|
+
function AxisLabels() {
|
|
28990
|
+
const {
|
|
28991
|
+
range,
|
|
28992
|
+
labels,
|
|
28993
|
+
width,
|
|
28994
|
+
height
|
|
28995
|
+
} = useGraphConfig();
|
|
28996
|
+
const yAxisLabelLocation = [0, range[Y][MAX]];
|
|
28997
|
+
const xAxisLabelLocation = [range[X][MAX], 0];
|
|
28998
|
+
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
28999
|
+
const graphInfo = {
|
|
29000
|
+
range,
|
|
29001
|
+
width,
|
|
29002
|
+
height
|
|
29003
|
+
};
|
|
29004
|
+
const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
|
|
29005
|
+
// The default location for the y-axis-label is at the maximum y point
|
|
29006
|
+
// This is just underneath the tick line for that point. The -24 moves the
|
|
29007
|
+
// label up one grid square, so it sits on top of the graph
|
|
29008
|
+
const [x2, y2] = mafs.vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
|
|
29009
|
+
const {
|
|
29010
|
+
TeX
|
|
29011
|
+
} = getDependencies();
|
|
29012
|
+
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("span", {
|
|
29013
|
+
style: {
|
|
29014
|
+
position: "absolute",
|
|
29015
|
+
left: x1,
|
|
29016
|
+
top: y1,
|
|
29017
|
+
fontSize: "14px",
|
|
29018
|
+
transform: "translate(7px, -50%)"
|
|
29019
|
+
}
|
|
29020
|
+
}, /*#__PURE__*/React__default["default"].createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default["default"].createElement("span", {
|
|
29021
|
+
style: {
|
|
29022
|
+
position: "absolute",
|
|
29023
|
+
left: x2,
|
|
29024
|
+
top: y2,
|
|
29025
|
+
fontSize: "14px",
|
|
29026
|
+
transform: "translate(-50%, 0px)"
|
|
29027
|
+
}
|
|
29028
|
+
}, /*#__PURE__*/React__default["default"].createElement(TeX, null, yAxisLabelText)));
|
|
29269
29029
|
}
|
|
29270
29030
|
|
|
29031
|
+
// The size of the ticks and labels in pixels
|
|
29271
29032
|
const tickSize = 10;
|
|
29272
|
-
const
|
|
29273
|
-
stroke: "black",
|
|
29274
|
-
strokeWidth: 1
|
|
29275
|
-
};
|
|
29033
|
+
const tickLabelSize = 14;
|
|
29276
29034
|
const YGridTick = _ref => {
|
|
29277
29035
|
let {
|
|
29278
29036
|
y,
|
|
29279
|
-
|
|
29037
|
+
range
|
|
29280
29038
|
} = _ref;
|
|
29039
|
+
// If the graph requires out-of-bounds labels, we want to make sure to set the
|
|
29040
|
+
// coordinates to the edge of the visible range of the graph. Otherwise,
|
|
29041
|
+
// the ticks and labels would render outside of the clipping-mask.
|
|
29281
29042
|
let xPointOnAxis = 0;
|
|
29282
|
-
|
|
29283
|
-
// If the graph is zoomed in, we want to make sure the ticks are still visible
|
|
29284
|
-
// even if they are outside the graph's range.
|
|
29285
|
-
if (graphInfo.range[X][MIN] > 0) {
|
|
29043
|
+
if (range[X][MIN] > 0) {
|
|
29286
29044
|
// If the graph is on the positive side of the x-axis, lock the ticks to the left side of the graph
|
|
29287
|
-
xPointOnAxis =
|
|
29045
|
+
xPointOnAxis = range[X][MIN];
|
|
29288
29046
|
}
|
|
29289
|
-
if (
|
|
29047
|
+
if (range[X][MAX] < 0) {
|
|
29290
29048
|
// If the graph is on the negative side of the x-axis, lock the ticks to the right side of the graph
|
|
29291
|
-
xPointOnAxis =
|
|
29049
|
+
xPointOnAxis = range[X][MAX];
|
|
29292
29050
|
}
|
|
29051
|
+
|
|
29052
|
+
// Convert the Vector2 coordinates to pixel coordinates
|
|
29293
29053
|
const pointOnAxis = [xPointOnAxis, y];
|
|
29294
29054
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
29295
29055
|
|
|
29296
|
-
// If the tick is on the edge of the graph's range, don't render it
|
|
29297
|
-
if (yPosition === -graphInfo.height || yPosition === graphInfo.height + 20) {
|
|
29298
|
-
return null;
|
|
29299
|
-
}
|
|
29300
|
-
|
|
29301
29056
|
// Position of the start of the tick
|
|
29302
29057
|
const x1 = xPosition - tickSize / 2;
|
|
29303
29058
|
const y1 = yPosition;
|
|
@@ -29305,40 +29060,56 @@ const YGridTick = _ref => {
|
|
|
29305
29060
|
// Position of the end of the tick
|
|
29306
29061
|
const x2 = xPosition + tickSize / 2;
|
|
29307
29062
|
const y2 = yPosition;
|
|
29063
|
+
|
|
29064
|
+
// Adjust the y position of the x-axis labels based on
|
|
29065
|
+
// whether the x-axis is above, within, or below the graph
|
|
29066
|
+
const xAdjustment = range[X][MAX] <= 0 ? tickLabelSize * 1.5 : -tickLabelSize * 1.1;
|
|
29067
|
+
const xPositionText = xPosition + xAdjustment;
|
|
29068
|
+
const yPositionText = yPosition + tickLabelSize * 0.25; // Center the text vertically on the tick
|
|
29069
|
+
|
|
29070
|
+
// If the graph displays both the y and x axis lines within the graph, we want
|
|
29071
|
+
// to hide the label at -1 on the y-axis to prevent overlap with the x-axis label
|
|
29072
|
+
const showLabel = shouldShowLabel(y, range);
|
|
29308
29073
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29309
|
-
className: "
|
|
29074
|
+
className: "tick"
|
|
29310
29075
|
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29311
29076
|
x1: x1,
|
|
29312
29077
|
y1: y1,
|
|
29313
29078
|
x2: x2,
|
|
29314
29079
|
y2: y2,
|
|
29315
|
-
|
|
29316
|
-
})
|
|
29080
|
+
className: "axis-tick"
|
|
29081
|
+
}), showLabel && /*#__PURE__*/React__namespace.createElement("text", {
|
|
29082
|
+
className: "axis-tick-label",
|
|
29083
|
+
style: {
|
|
29084
|
+
fontSize: tickLabelSize
|
|
29085
|
+
},
|
|
29086
|
+
textAnchor: "end",
|
|
29087
|
+
x: xPositionText,
|
|
29088
|
+
y: yPositionText
|
|
29089
|
+
}, y.toString()));
|
|
29317
29090
|
};
|
|
29318
29091
|
const XGridTick = _ref2 => {
|
|
29319
29092
|
let {
|
|
29320
29093
|
x,
|
|
29321
|
-
|
|
29094
|
+
range
|
|
29322
29095
|
} = _ref2;
|
|
29096
|
+
// If the graph requires out-of-bounds labels, we want to make sure to set the
|
|
29097
|
+
// coordinates to the edge of the visible range of the graph. Otherwise,
|
|
29098
|
+
// the ticks and labels would render outside of the clipping-mask.
|
|
29323
29099
|
let yPointOnAxis = 0;
|
|
29324
|
-
|
|
29325
|
-
// even if they are outside the graph's range.
|
|
29326
|
-
if (graphInfo.range[Y][MIN] > 0) {
|
|
29100
|
+
if (range[Y][MIN] > 0) {
|
|
29327
29101
|
// If the graph is on the positive side of the y-axis, lock the ticks to the top of the graph
|
|
29328
|
-
yPointOnAxis =
|
|
29102
|
+
yPointOnAxis = range[Y][MIN];
|
|
29329
29103
|
}
|
|
29330
|
-
if (
|
|
29104
|
+
if (range[Y][MAX] < 0) {
|
|
29331
29105
|
// If the graph is on the negative side of the x-axis, lock the ticks to the bottom of the graph
|
|
29332
|
-
yPointOnAxis =
|
|
29106
|
+
yPointOnAxis = range[Y][MAX];
|
|
29333
29107
|
}
|
|
29108
|
+
|
|
29109
|
+
// Convert the Vector2 coordinates to pixel coordinates
|
|
29334
29110
|
const pointOnAxis = [x, yPointOnAxis];
|
|
29335
29111
|
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
29336
29112
|
|
|
29337
|
-
// If the tick is on the edge of the graph's range, don't render it
|
|
29338
|
-
if (xPosition === -graphInfo.width / 2 || xPosition === graphInfo.width) {
|
|
29339
|
-
return null;
|
|
29340
|
-
}
|
|
29341
|
-
|
|
29342
29113
|
// Position of the start of the tick
|
|
29343
29114
|
const x1 = xPosition;
|
|
29344
29115
|
const y1 = yPosition + tickSize / 2;
|
|
@@ -29346,21 +29117,56 @@ const XGridTick = _ref2 => {
|
|
|
29346
29117
|
// Position of the end of the tick
|
|
29347
29118
|
const x2 = xPosition;
|
|
29348
29119
|
const y2 = yPosition - tickSize / 2;
|
|
29120
|
+
|
|
29121
|
+
// Adjust the Y position of the x-axis labels based on
|
|
29122
|
+
// whether the x-axis is above, within, or below the graph
|
|
29123
|
+
const yAdjustment = range[Y][MAX] < 0 ? -tickLabelSize : tickLabelSize * 1.75;
|
|
29124
|
+
|
|
29125
|
+
// Adjust the X position of the x-axis labels based on
|
|
29126
|
+
// whether the label is positive or negative, in order to
|
|
29127
|
+
// account for the width of the negative sign
|
|
29128
|
+
const xAdjustment = x < 0 ? -2 : 0;
|
|
29129
|
+
|
|
29130
|
+
// Apply the adjustments to the x and y positions for the text
|
|
29131
|
+
const xPositionText = xPosition + xAdjustment;
|
|
29132
|
+
const yPositionText = yPosition + yAdjustment;
|
|
29349
29133
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29350
|
-
className: "
|
|
29134
|
+
className: "tick"
|
|
29351
29135
|
}, /*#__PURE__*/React__namespace.createElement("line", {
|
|
29352
29136
|
x1: x1,
|
|
29353
29137
|
y1: y1,
|
|
29354
29138
|
x2: x2,
|
|
29355
29139
|
y2: y2,
|
|
29356
|
-
|
|
29357
|
-
})
|
|
29140
|
+
className: "axis-tick"
|
|
29141
|
+
}), /*#__PURE__*/React__namespace.createElement("text", {
|
|
29142
|
+
className: "axis-tick-label",
|
|
29143
|
+
style: {
|
|
29144
|
+
fontSize: tickLabelSize
|
|
29145
|
+
},
|
|
29146
|
+
textAnchor: "middle",
|
|
29147
|
+
x: xPositionText,
|
|
29148
|
+
y: yPositionText
|
|
29149
|
+
}, x.toString()));
|
|
29150
|
+
};
|
|
29151
|
+
|
|
29152
|
+
// Determines whether to show the label for the given tick
|
|
29153
|
+
// Currently, the only condition is to hide the label at -1
|
|
29154
|
+
// on the y-axis when the x-axis is within the graph
|
|
29155
|
+
const shouldShowLabel = (number, range) => {
|
|
29156
|
+
let showLabel = true;
|
|
29157
|
+
|
|
29158
|
+
// If the x-axis is within the graph and the y-axis is at -1, hide the label
|
|
29159
|
+
if (range[X][MIN] < -1 && range[X][MAX] > 0 && number === -1) {
|
|
29160
|
+
showLabel = false;
|
|
29161
|
+
}
|
|
29162
|
+
return showLabel;
|
|
29358
29163
|
};
|
|
29359
29164
|
function generateTickLocations(tickStep, min, max) {
|
|
29360
29165
|
const ticks = [];
|
|
29361
29166
|
|
|
29362
29167
|
// Add ticks in the positive direction
|
|
29363
|
-
|
|
29168
|
+
const start = Math.max(min, 0);
|
|
29169
|
+
for (let i = start + tickStep; i < max; i += tickStep) {
|
|
29364
29170
|
ticks.push(i);
|
|
29365
29171
|
}
|
|
29366
29172
|
|
|
@@ -29375,34 +29181,34 @@ function generateTickLocations(tickStep, min, max) {
|
|
|
29375
29181
|
const AxisTicks = () => {
|
|
29376
29182
|
const {
|
|
29377
29183
|
tickStep,
|
|
29378
|
-
range
|
|
29379
|
-
width,
|
|
29380
|
-
height
|
|
29184
|
+
range
|
|
29381
29185
|
} = useGraphConfig();
|
|
29382
|
-
const graphInfo = {
|
|
29383
|
-
range,
|
|
29384
|
-
width,
|
|
29385
|
-
height
|
|
29386
|
-
};
|
|
29387
29186
|
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
29388
29187
|
const [xTickStep, yTickStep] = tickStep;
|
|
29188
|
+
|
|
29189
|
+
// Generate the tick locations & labels for the x and y axes
|
|
29389
29190
|
const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
|
|
29390
29191
|
const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
|
|
29391
29192
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29392
|
-
className: "axis-ticks"
|
|
29193
|
+
className: "axis-ticks",
|
|
29194
|
+
role: "presentation"
|
|
29195
|
+
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29196
|
+
className: "y-axis-ticks"
|
|
29393
29197
|
}, yGridTicks.map(y => {
|
|
29394
29198
|
return /*#__PURE__*/React__namespace.createElement(YGridTick, {
|
|
29395
29199
|
y: y,
|
|
29396
29200
|
key: `y-grid-tick-${y}`,
|
|
29397
|
-
|
|
29201
|
+
range: range
|
|
29398
29202
|
});
|
|
29399
|
-
}),
|
|
29203
|
+
})), /*#__PURE__*/React__namespace.createElement("g", {
|
|
29204
|
+
className: "x-axis-ticks"
|
|
29205
|
+
}, xGridTicks.map(x => {
|
|
29400
29206
|
return /*#__PURE__*/React__namespace.createElement(XGridTick, {
|
|
29401
29207
|
x: x,
|
|
29402
29208
|
key: `x-grid-tick-${x}`,
|
|
29403
|
-
|
|
29209
|
+
range: range
|
|
29404
29210
|
});
|
|
29405
|
-
}));
|
|
29211
|
+
})));
|
|
29406
29212
|
};
|
|
29407
29213
|
|
|
29408
29214
|
/**
|
|
@@ -29423,12 +29229,10 @@ const axisOptions = (props, axisIndex) => {
|
|
|
29423
29229
|
};
|
|
29424
29230
|
};
|
|
29425
29231
|
const Grid = props => {
|
|
29426
|
-
return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(
|
|
29232
|
+
return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
|
|
29427
29233
|
xAxis: axisOptions(props, X),
|
|
29428
29234
|
yAxis: axisOptions(props, Y)
|
|
29429
|
-
})
|
|
29430
|
-
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
29431
|
-
props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)));
|
|
29235
|
+
});
|
|
29432
29236
|
};
|
|
29433
29237
|
|
|
29434
29238
|
// Displays a stylized open eye: lint warnings are visible
|
|
@@ -32370,6 +32174,22 @@ const MafsGraph = props => {
|
|
|
32370
32174
|
const uniqueId = React__namespace.useId();
|
|
32371
32175
|
const descriptionId = `interactive-graph-description-${uniqueId}`;
|
|
32372
32176
|
const graphRef = React__namespace.useRef(null);
|
|
32177
|
+
|
|
32178
|
+
// Set up the SVG attributes for the nested SVGs that help lock
|
|
32179
|
+
// the grid and graph elements to the bounds of the graph.
|
|
32180
|
+
const {
|
|
32181
|
+
viewboxX,
|
|
32182
|
+
viewboxY
|
|
32183
|
+
} = calculateNestedSVGCoords(state.range, width, height);
|
|
32184
|
+
const viewBox = `${viewboxX} ${viewboxY} ${width} ${height}`;
|
|
32185
|
+
const nestedSVGAttributes = {
|
|
32186
|
+
width,
|
|
32187
|
+
height,
|
|
32188
|
+
viewBox,
|
|
32189
|
+
preserveAspectRatio: "xMidYMin",
|
|
32190
|
+
x: viewboxX,
|
|
32191
|
+
y: viewboxY
|
|
32192
|
+
};
|
|
32373
32193
|
return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
|
|
32374
32194
|
value: {
|
|
32375
32195
|
range: state.range,
|
|
@@ -32391,7 +32211,7 @@ const MafsGraph = props => {
|
|
|
32391
32211
|
padding: "25px 25px 0 0",
|
|
32392
32212
|
boxSizing: "content-box",
|
|
32393
32213
|
marginLeft: "20px",
|
|
32394
|
-
marginBottom: "
|
|
32214
|
+
marginBottom: "30px",
|
|
32395
32215
|
pointerEvents: props.static ? "none" : "auto",
|
|
32396
32216
|
userSelect: "none",
|
|
32397
32217
|
width,
|
|
@@ -32426,7 +32246,7 @@ const MafsGraph = props => {
|
|
|
32426
32246
|
bottom: 0,
|
|
32427
32247
|
left: 0
|
|
32428
32248
|
}
|
|
32429
|
-
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null)
|
|
32249
|
+
}, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
|
|
32430
32250
|
preserveAspectRatio: false,
|
|
32431
32251
|
viewBox: {
|
|
32432
32252
|
x: state.range[X],
|
|
@@ -32437,19 +32257,22 @@ const MafsGraph = props => {
|
|
|
32437
32257
|
zoom: false,
|
|
32438
32258
|
width: width,
|
|
32439
32259
|
height: height
|
|
32440
|
-
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
32441
|
-
tickStep: props.step,
|
|
32260
|
+
}, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, /*#__PURE__*/React__namespace.createElement(Grid, {
|
|
32442
32261
|
gridStep: props.gridStep,
|
|
32443
32262
|
range: state.range,
|
|
32444
32263
|
containerSizeClass: props.containerSizeClass,
|
|
32445
|
-
markings: props.markings
|
|
32446
|
-
|
|
32264
|
+
markings: props.markings,
|
|
32265
|
+
width: width,
|
|
32266
|
+
height: height
|
|
32267
|
+
})),
|
|
32268
|
+
// Only render the axis ticks and arrows if the markings are set to a full "graph"
|
|
32269
|
+
props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)), /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
32447
32270
|
lockedFigures: props.lockedFigures,
|
|
32448
32271
|
range: state.range
|
|
32449
32272
|
}), props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
|
|
32450
32273
|
state,
|
|
32451
32274
|
dispatch
|
|
32452
|
-
})))), renderGraphControls({
|
|
32275
|
+
}))))), renderGraphControls({
|
|
32453
32276
|
state,
|
|
32454
32277
|
dispatch
|
|
32455
32278
|
})));
|
|
@@ -32485,6 +32308,56 @@ const renderGraphControls = props => {
|
|
|
32485
32308
|
return null;
|
|
32486
32309
|
}
|
|
32487
32310
|
};
|
|
32311
|
+
|
|
32312
|
+
// Calculate the difference between the min and max values of a range
|
|
32313
|
+
const getRangeDiff = range => {
|
|
32314
|
+
const [min, max] = range;
|
|
32315
|
+
return Math.abs(max - min);
|
|
32316
|
+
};
|
|
32317
|
+
|
|
32318
|
+
// We need to adjust the nested SVG viewbox x and Y values based on the range of the graph in order
|
|
32319
|
+
// to ensure that the graph is sized and positioned correctly within the Mafs SVG and the clipping mask.
|
|
32320
|
+
// Exported for testing.
|
|
32321
|
+
const calculateNestedSVGCoords = (range, width, height) => {
|
|
32322
|
+
// X RANGE
|
|
32323
|
+
let viewboxX = 0; // When xMin is 0, we want to use 0 as the viewboxX value
|
|
32324
|
+
const totalXRange = getRangeDiff(range[X]);
|
|
32325
|
+
const gridCellWidth = width / totalXRange;
|
|
32326
|
+
const minX = range[X][MIN];
|
|
32327
|
+
|
|
32328
|
+
// If xMin is entirely positive, we need to adjust the
|
|
32329
|
+
// viewboxX to be the grid cell width multiplied by xMin
|
|
32330
|
+
if (minX > 0) {
|
|
32331
|
+
viewboxX = gridCellWidth * Math.abs(minX);
|
|
32332
|
+
}
|
|
32333
|
+
// If xMin is negative, we need to adjust the viewboxX to be
|
|
32334
|
+
// the negative value of the grid cell width multiplied by xMin
|
|
32335
|
+
if (minX < 0) {
|
|
32336
|
+
viewboxX = -gridCellWidth * Math.abs(minX);
|
|
32337
|
+
}
|
|
32338
|
+
|
|
32339
|
+
// Y RANGE
|
|
32340
|
+
let viewboxY = -height; // When yMin is 0, we want to use the negative value of the graph height
|
|
32341
|
+
const totalYRange = getRangeDiff(range[Y]);
|
|
32342
|
+
const gridCellHeight = height / totalYRange;
|
|
32343
|
+
const minY = range[Y][MIN];
|
|
32344
|
+
|
|
32345
|
+
// If the y range is entirely positive, we want a negative sum of the
|
|
32346
|
+
// height and the gridcell height multiplied by the absolute value of yMin
|
|
32347
|
+
if (minY > 0) {
|
|
32348
|
+
viewboxY = -height - gridCellHeight * Math.abs(minY);
|
|
32349
|
+
}
|
|
32350
|
+
|
|
32351
|
+
// If the yMin is negative, we want to multiply the gridcell height
|
|
32352
|
+
// by the absolute value of yMin, and subtract the full height of the graph
|
|
32353
|
+
if (minY < 0) {
|
|
32354
|
+
viewboxY = gridCellHeight * Math.abs(minY) - height;
|
|
32355
|
+
}
|
|
32356
|
+
return {
|
|
32357
|
+
viewboxX,
|
|
32358
|
+
viewboxY
|
|
32359
|
+
};
|
|
32360
|
+
};
|
|
32488
32361
|
const renderGraph = props => {
|
|
32489
32362
|
const {
|
|
32490
32363
|
state,
|
|
@@ -45099,7 +44972,7 @@ const init = function (options) {
|
|
|
45099
44972
|
|
|
45100
44973
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45101
44974
|
const libName = "@khanacademy/perseus";
|
|
45102
|
-
const libVersion = "33.
|
|
44975
|
+
const libVersion = "33.1.0";
|
|
45103
44976
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45104
44977
|
|
|
45105
44978
|
const apiVersion = {
|