@khanacademy/perseus 22.1.0 → 22.3.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 +4 -6
- package/dist/es/index.js +187 -176
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +4 -6
- package/dist/index.js +186 -175
- package/dist/index.js.map +1 -1
- package/dist/perseus-types.d.ts +1 -1
- package/dist/widgets/interactive-graphs/graph-locked-layer.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/components/vector.d.ts +2 -1
- package/dist/widgets/interactive-graphs/locked-line.d.ts +5 -1
- package/package.json +5 -5
package/dist/es/index.css
CHANGED
|
@@ -1864,8 +1864,7 @@ body.mobile ul.inequalities-one-line-radios > li {
|
|
|
1864
1864
|
.framework-perseus.perseus-mobile .perseus-image-caption.has-title .paragraph .paragraph strong:first-child {
|
|
1865
1865
|
color: #3b3e40;
|
|
1866
1866
|
}
|
|
1867
|
-
.framework-perseus.perseus-mobile .katex,
|
|
1868
|
-
.framework-perseus.perseus-mobile mjx-container {
|
|
1867
|
+
.framework-perseus.perseus-mobile :is(.katex, mjx-container):not(.mafs-graph *) {
|
|
1869
1868
|
font-size: 21px;
|
|
1870
1869
|
line-height: 1.2;
|
|
1871
1870
|
color: #21242c;
|
|
@@ -2007,8 +2006,7 @@ body.mobile ul.inequalities-one-line-radios > li {
|
|
|
2007
2006
|
.framework-perseus.perseus-mobile .perseus-image-caption.has-title .paragraph .paragraph strong:first-child {
|
|
2008
2007
|
color: #3b3e40;
|
|
2009
2008
|
}
|
|
2010
|
-
.framework-perseus.perseus-mobile .katex,
|
|
2011
|
-
.framework-perseus.perseus-mobile mjx-container {
|
|
2009
|
+
.framework-perseus.perseus-mobile :is(.katex, mjx-container):not(.mafs-graph *) {
|
|
2012
2010
|
font-size: 23px;
|
|
2013
2011
|
line-height: 1.3;
|
|
2014
2012
|
color: #21242c;
|
|
@@ -2150,8 +2148,7 @@ body.mobile ul.inequalities-one-line-radios > li {
|
|
|
2150
2148
|
.framework-perseus.perseus-mobile .perseus-image-caption.has-title .paragraph .paragraph strong:first-child {
|
|
2151
2149
|
color: #3b3e40;
|
|
2152
2150
|
}
|
|
2153
|
-
.framework-perseus.perseus-mobile .katex,
|
|
2154
|
-
.framework-perseus.perseus-mobile mjx-container {
|
|
2151
|
+
.framework-perseus.perseus-mobile :is(.katex, mjx-container):not(.mafs-graph *) {
|
|
2155
2152
|
font-size: 25px;
|
|
2156
2153
|
line-height: 1.2;
|
|
2157
2154
|
color: #21242c;
|
|
@@ -4172,6 +4169,7 @@ html body .mq-editable-field .mq-selection .mq-nthroot-container * {
|
|
|
4172
4169
|
|
|
4173
4170
|
--mafs-origin-color: var(--mafs-fg);
|
|
4174
4171
|
--mafs-line-color: #555;
|
|
4172
|
+
--mafs-line-stroke-dash-style: 4, 3;
|
|
4175
4173
|
--grid-line-subdivision-color: #222;
|
|
4176
4174
|
|
|
4177
4175
|
--mafs-red: #f11d0e;
|
package/dist/es/index.js
CHANGED
|
@@ -28664,19 +28664,171 @@ const ItemExtras = [
|
|
|
28664
28664
|
|
|
28665
28665
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28666
28666
|
const lockedFigureColors = {
|
|
28667
|
-
blue: "#3D7586",
|
|
28668
28667
|
green: "#447A53",
|
|
28669
|
-
gray: "#5D5F66",
|
|
28670
28668
|
grayH: "#3B3D45",
|
|
28671
|
-
grayI: "#21242C",
|
|
28672
28669
|
purple: "#594094",
|
|
28673
|
-
purpleD: "#8351E8",
|
|
28674
28670
|
pink: "#B25071",
|
|
28675
|
-
orange: "#946700",
|
|
28676
28671
|
red: "#D92916"
|
|
28677
28672
|
};
|
|
28678
28673
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28679
28674
|
|
|
28675
|
+
function pathBuilder() {
|
|
28676
|
+
return new PathBuilder();
|
|
28677
|
+
}
|
|
28678
|
+
class PathBuilder {
|
|
28679
|
+
constructor() {
|
|
28680
|
+
this.path = [];
|
|
28681
|
+
this.scaleFactor = 1;
|
|
28682
|
+
}
|
|
28683
|
+
build() {
|
|
28684
|
+
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28685
|
+
}
|
|
28686
|
+
|
|
28687
|
+
// add a move (M) command to the path
|
|
28688
|
+
move(x, y) {
|
|
28689
|
+
this.path.push({
|
|
28690
|
+
action: "M",
|
|
28691
|
+
coords: [x, y]
|
|
28692
|
+
});
|
|
28693
|
+
return this;
|
|
28694
|
+
}
|
|
28695
|
+
|
|
28696
|
+
// add a curve (C) command to the path
|
|
28697
|
+
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28698
|
+
this.path.push({
|
|
28699
|
+
action: "C",
|
|
28700
|
+
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28701
|
+
});
|
|
28702
|
+
return this;
|
|
28703
|
+
}
|
|
28704
|
+
|
|
28705
|
+
// Scale all coordinates of the path by a factor
|
|
28706
|
+
scale(factor) {
|
|
28707
|
+
this.scaleFactor *= factor;
|
|
28708
|
+
return this;
|
|
28709
|
+
}
|
|
28710
|
+
}
|
|
28711
|
+
function commandToString(command) {
|
|
28712
|
+
return `${command.action}${command.coords.join(" ")}`;
|
|
28713
|
+
}
|
|
28714
|
+
function scaleCommandBy(scaleFactor) {
|
|
28715
|
+
return command => _extends({}, command, {
|
|
28716
|
+
coords: command.coords.map(c => c * scaleFactor)
|
|
28717
|
+
});
|
|
28718
|
+
}
|
|
28719
|
+
|
|
28720
|
+
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
28721
|
+
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
28722
|
+
// transform because a transform would also scale up the stroke weight, and we
|
|
28723
|
+
// don't want that.
|
|
28724
|
+
const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).curve(0, -0.25, -2.75, -2.5, -3, -4).scale(1.4).build();
|
|
28725
|
+
function Arrowhead(props) {
|
|
28726
|
+
var _props$color;
|
|
28727
|
+
const [point] = useTransformVectorsToPixels(props.tip);
|
|
28728
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28729
|
+
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
28730
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
28731
|
+
transform: "translate(-1.5)"
|
|
28732
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
28733
|
+
d: arrowPath,
|
|
28734
|
+
fill: "none",
|
|
28735
|
+
style: {
|
|
28736
|
+
stroke: (_props$color = props.color) != null ? _props$color : "inherit"
|
|
28737
|
+
},
|
|
28738
|
+
strokeLinejoin: "round",
|
|
28739
|
+
strokeLinecap: "round"
|
|
28740
|
+
})));
|
|
28741
|
+
}
|
|
28742
|
+
|
|
28743
|
+
function SVGLine(props) {
|
|
28744
|
+
const {
|
|
28745
|
+
start,
|
|
28746
|
+
end,
|
|
28747
|
+
style,
|
|
28748
|
+
className,
|
|
28749
|
+
testId
|
|
28750
|
+
} = props;
|
|
28751
|
+
return /*#__PURE__*/React.createElement("line", {
|
|
28752
|
+
x1: start[0],
|
|
28753
|
+
y1: start[1],
|
|
28754
|
+
x2: end[0],
|
|
28755
|
+
y2: end[1],
|
|
28756
|
+
style: style,
|
|
28757
|
+
className: className,
|
|
28758
|
+
"data-testid": testId
|
|
28759
|
+
});
|
|
28760
|
+
}
|
|
28761
|
+
|
|
28762
|
+
function Vector(props) {
|
|
28763
|
+
const {
|
|
28764
|
+
tail,
|
|
28765
|
+
tip,
|
|
28766
|
+
color,
|
|
28767
|
+
style
|
|
28768
|
+
} = props;
|
|
28769
|
+
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
28770
|
+
const direction = vec.sub(tip, tail);
|
|
28771
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28772
|
+
style: {
|
|
28773
|
+
stroke: color,
|
|
28774
|
+
strokeWidth: 2
|
|
28775
|
+
}
|
|
28776
|
+
}, /*#__PURE__*/React.createElement(SVGLine, {
|
|
28777
|
+
start: tailPx,
|
|
28778
|
+
end: tipPx,
|
|
28779
|
+
style: style
|
|
28780
|
+
}), /*#__PURE__*/React.createElement(Arrowhead, {
|
|
28781
|
+
tip: tip,
|
|
28782
|
+
angle: angleDegrees(direction)
|
|
28783
|
+
}));
|
|
28784
|
+
}
|
|
28785
|
+
function angleDegrees([x, y]) {
|
|
28786
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28787
|
+
}
|
|
28788
|
+
|
|
28789
|
+
/**
|
|
28790
|
+
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
28791
|
+
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
28792
|
+
* @param initialPoint - The starting point of the ray.
|
|
28793
|
+
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
28794
|
+
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
28795
|
+
*/
|
|
28796
|
+
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
28797
|
+
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
28798
|
+
const [aX, aY] = throughPoint;
|
|
28799
|
+
const [bX, bY] = initialPoint;
|
|
28800
|
+
const yDiff = bY - aY;
|
|
28801
|
+
const xDiff = bX - aX;
|
|
28802
|
+
const slope = yDiff / xDiff;
|
|
28803
|
+
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28804
|
+
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28805
|
+
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28806
|
+
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28807
|
+
|
|
28808
|
+
// clock analogy to describe quadrants
|
|
28809
|
+
switch (true) {
|
|
28810
|
+
// 12 o'clock to 2:59
|
|
28811
|
+
case yDiff > 0 && xDiff >= 0:
|
|
28812
|
+
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28813
|
+
// 3 o'clock to 5:59
|
|
28814
|
+
case yDiff <= 0 && xDiff > 0:
|
|
28815
|
+
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28816
|
+
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28817
|
+
// 9 o'clock to 11:59
|
|
28818
|
+
case yDiff >= 0 && xDiff < 0:
|
|
28819
|
+
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28820
|
+
// 6 o'clock to 8:59
|
|
28821
|
+
case yDiff < 0 && xDiff <= 0:
|
|
28822
|
+
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28823
|
+
default:
|
|
28824
|
+
return [xMax, yAtXMax];
|
|
28825
|
+
}
|
|
28826
|
+
};
|
|
28827
|
+
const getLines = points => points.map((point, i) => {
|
|
28828
|
+
const next = points[(i + 1) % points.length];
|
|
28829
|
+
return [point, next];
|
|
28830
|
+
});
|
|
28831
|
+
|
|
28680
28832
|
const LockedLine = props => {
|
|
28681
28833
|
const {
|
|
28682
28834
|
color: color$1,
|
|
@@ -28684,11 +28836,27 @@ const LockedLine = props => {
|
|
|
28684
28836
|
kind,
|
|
28685
28837
|
points,
|
|
28686
28838
|
showStartPoint,
|
|
28687
|
-
showEndPoint
|
|
28839
|
+
showEndPoint,
|
|
28840
|
+
range
|
|
28688
28841
|
} = props;
|
|
28689
28842
|
const [point1, point2] = points;
|
|
28690
28843
|
let line;
|
|
28691
|
-
if (kind === "
|
|
28844
|
+
if (kind === "ray") {
|
|
28845
|
+
// Rays extend to the end of the graph in one direction.
|
|
28846
|
+
const endExtend = getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
28847
|
+
line = /*#__PURE__*/React.createElement(Vector, {
|
|
28848
|
+
tail: point1.coord,
|
|
28849
|
+
tip: endExtend,
|
|
28850
|
+
color: lockedFigureColors[color$1],
|
|
28851
|
+
style: {
|
|
28852
|
+
strokeDasharray: lineStyle === "dashed" ?
|
|
28853
|
+
// TODO(lems-1930): Uncomment this line when the
|
|
28854
|
+
// dashed style is updated in Mafs.
|
|
28855
|
+
// ? "var(--mafs-line-stroke-dash-style)"
|
|
28856
|
+
"4, 3" : undefined
|
|
28857
|
+
}
|
|
28858
|
+
});
|
|
28859
|
+
} else {
|
|
28692
28860
|
const LineType = kind === "segment" ? Line$3.Segment : Line$3.ThroughPoints;
|
|
28693
28861
|
line = /*#__PURE__*/React.createElement(LineType, {
|
|
28694
28862
|
point1: point1.coord,
|
|
@@ -28696,12 +28864,9 @@ const LockedLine = props => {
|
|
|
28696
28864
|
color: lockedFigureColors[color$1],
|
|
28697
28865
|
style: lineStyle
|
|
28698
28866
|
});
|
|
28699
|
-
} else {
|
|
28700
|
-
// TODO(LEMS-1928): Implement rays
|
|
28701
|
-
return null;
|
|
28702
28867
|
}
|
|
28703
28868
|
return /*#__PURE__*/React.createElement("g", {
|
|
28704
|
-
className: "locked-line"
|
|
28869
|
+
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
28705
28870
|
}, line, showStartPoint && /*#__PURE__*/React.createElement(Point$2, {
|
|
28706
28871
|
x: point1.coord[0],
|
|
28707
28872
|
y: point1.coord[1],
|
|
@@ -28750,14 +28915,16 @@ const GraphLockedLayer = props => {
|
|
|
28750
28915
|
lockedFigures
|
|
28751
28916
|
} = props;
|
|
28752
28917
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lockedFigures.map((figure, index) => {
|
|
28753
|
-
let Figure;
|
|
28754
28918
|
switch (figure.type) {
|
|
28755
28919
|
case "point":
|
|
28756
|
-
|
|
28757
|
-
|
|
28920
|
+
return /*#__PURE__*/React.createElement(LockedPoint, _extends({
|
|
28921
|
+
key: `point-${index}`
|
|
28922
|
+
}, figure));
|
|
28758
28923
|
case "line":
|
|
28759
|
-
|
|
28760
|
-
|
|
28924
|
+
return /*#__PURE__*/React.createElement(LockedLine, _extends({
|
|
28925
|
+
key: `line-${index}`,
|
|
28926
|
+
range: props.range
|
|
28927
|
+
}, figure));
|
|
28761
28928
|
default:
|
|
28762
28929
|
/**
|
|
28763
28930
|
* Devlopment-time future-proofing: This should
|
|
@@ -28767,9 +28934,6 @@ const GraphLockedLayer = props => {
|
|
|
28767
28934
|
*/
|
|
28768
28935
|
throw new UnreachableCaseError(figure);
|
|
28769
28936
|
}
|
|
28770
|
-
return /*#__PURE__*/React.createElement(Figure, _extends({
|
|
28771
|
-
key: `${figure.type}-${index}`
|
|
28772
|
-
}, figure));
|
|
28773
28937
|
}));
|
|
28774
28938
|
};
|
|
28775
28939
|
|
|
@@ -28851,161 +29015,6 @@ function snap(snapStep, point) {
|
|
|
28851
29015
|
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
28852
29016
|
}
|
|
28853
29017
|
|
|
28854
|
-
/**
|
|
28855
|
-
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
28856
|
-
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
28857
|
-
* @param initialPoint - The starting point of the ray.
|
|
28858
|
-
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
28859
|
-
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
28860
|
-
*/
|
|
28861
|
-
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
28862
|
-
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
28863
|
-
const [aX, aY] = throughPoint;
|
|
28864
|
-
const [bX, bY] = initialPoint;
|
|
28865
|
-
const yDiff = bY - aY;
|
|
28866
|
-
const xDiff = bX - aX;
|
|
28867
|
-
const slope = yDiff / xDiff;
|
|
28868
|
-
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28869
|
-
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28870
|
-
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28871
|
-
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28872
|
-
|
|
28873
|
-
// clock analogy to describe quadrants
|
|
28874
|
-
switch (true) {
|
|
28875
|
-
// 12 o'clock to 2:59
|
|
28876
|
-
case yDiff > 0 && xDiff >= 0:
|
|
28877
|
-
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28878
|
-
// 3 o'clock to 5:59
|
|
28879
|
-
case yDiff <= 0 && xDiff > 0:
|
|
28880
|
-
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28881
|
-
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28882
|
-
// 9 o'clock to 11:59
|
|
28883
|
-
case yDiff >= 0 && xDiff < 0:
|
|
28884
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28885
|
-
// 6 o'clock to 8:59
|
|
28886
|
-
case yDiff < 0 && xDiff <= 0:
|
|
28887
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28888
|
-
default:
|
|
28889
|
-
return [xMax, yAtXMax];
|
|
28890
|
-
}
|
|
28891
|
-
};
|
|
28892
|
-
const getLines = points => points.map((point, i) => {
|
|
28893
|
-
const next = points[(i + 1) % points.length];
|
|
28894
|
-
return [point, next];
|
|
28895
|
-
});
|
|
28896
|
-
|
|
28897
|
-
function SVGLine(props) {
|
|
28898
|
-
const {
|
|
28899
|
-
start,
|
|
28900
|
-
end,
|
|
28901
|
-
style,
|
|
28902
|
-
className,
|
|
28903
|
-
testId
|
|
28904
|
-
} = props;
|
|
28905
|
-
return /*#__PURE__*/React.createElement("line", {
|
|
28906
|
-
x1: start[0],
|
|
28907
|
-
y1: start[1],
|
|
28908
|
-
x2: end[0],
|
|
28909
|
-
y2: end[1],
|
|
28910
|
-
style: style,
|
|
28911
|
-
className: `${className}`,
|
|
28912
|
-
"data-testid": testId
|
|
28913
|
-
});
|
|
28914
|
-
}
|
|
28915
|
-
|
|
28916
|
-
function pathBuilder() {
|
|
28917
|
-
return new PathBuilder();
|
|
28918
|
-
}
|
|
28919
|
-
class PathBuilder {
|
|
28920
|
-
constructor() {
|
|
28921
|
-
this.path = [];
|
|
28922
|
-
this.scaleFactor = 1;
|
|
28923
|
-
}
|
|
28924
|
-
build() {
|
|
28925
|
-
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28926
|
-
}
|
|
28927
|
-
|
|
28928
|
-
// add a move (M) command to the path
|
|
28929
|
-
move(x, y) {
|
|
28930
|
-
this.path.push({
|
|
28931
|
-
action: "M",
|
|
28932
|
-
coords: [x, y]
|
|
28933
|
-
});
|
|
28934
|
-
return this;
|
|
28935
|
-
}
|
|
28936
|
-
|
|
28937
|
-
// add a curve (C) command to the path
|
|
28938
|
-
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28939
|
-
this.path.push({
|
|
28940
|
-
action: "C",
|
|
28941
|
-
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28942
|
-
});
|
|
28943
|
-
return this;
|
|
28944
|
-
}
|
|
28945
|
-
|
|
28946
|
-
// Scale all coordinates of the path by a factor
|
|
28947
|
-
scale(factor) {
|
|
28948
|
-
this.scaleFactor *= factor;
|
|
28949
|
-
return this;
|
|
28950
|
-
}
|
|
28951
|
-
}
|
|
28952
|
-
function commandToString(command) {
|
|
28953
|
-
return `${command.action}${command.coords.join(" ")}`;
|
|
28954
|
-
}
|
|
28955
|
-
function scaleCommandBy(scaleFactor) {
|
|
28956
|
-
return command => _extends({}, command, {
|
|
28957
|
-
coords: command.coords.map(c => c * scaleFactor)
|
|
28958
|
-
});
|
|
28959
|
-
}
|
|
28960
|
-
|
|
28961
|
-
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
28962
|
-
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
28963
|
-
// transform because a transform would also scale up the stroke weight, and we
|
|
28964
|
-
// don't want that.
|
|
28965
|
-
const arrowPath = pathBuilder().move(-3, 4).curve(-2.75, 2.5, 0, 0.25, 0.75, 0).curve(0, -0.25, -2.75, -2.5, -3, -4).scale(1.4).build();
|
|
28966
|
-
function Arrowhead(props) {
|
|
28967
|
-
var _props$color;
|
|
28968
|
-
const [point] = useTransformVectorsToPixels(props.tip);
|
|
28969
|
-
return /*#__PURE__*/React.createElement("g", {
|
|
28970
|
-
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
28971
|
-
}, /*#__PURE__*/React.createElement("g", {
|
|
28972
|
-
transform: "translate(-1.5)"
|
|
28973
|
-
}, /*#__PURE__*/React.createElement("path", {
|
|
28974
|
-
d: arrowPath,
|
|
28975
|
-
fill: "none",
|
|
28976
|
-
style: {
|
|
28977
|
-
stroke: (_props$color = props.color) != null ? _props$color : "inherit"
|
|
28978
|
-
},
|
|
28979
|
-
strokeLinejoin: "round",
|
|
28980
|
-
strokeLinecap: "round"
|
|
28981
|
-
})));
|
|
28982
|
-
}
|
|
28983
|
-
|
|
28984
|
-
function Vector(props) {
|
|
28985
|
-
const {
|
|
28986
|
-
tail,
|
|
28987
|
-
tip,
|
|
28988
|
-
color
|
|
28989
|
-
} = props;
|
|
28990
|
-
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
28991
|
-
const direction = vec.sub(tip, tail);
|
|
28992
|
-
return /*#__PURE__*/React.createElement("g", {
|
|
28993
|
-
style: {
|
|
28994
|
-
stroke: color,
|
|
28995
|
-
strokeWidth: 2
|
|
28996
|
-
}
|
|
28997
|
-
}, /*#__PURE__*/React.createElement(SVGLine, {
|
|
28998
|
-
start: tailPx,
|
|
28999
|
-
end: tipPx
|
|
29000
|
-
}), /*#__PURE__*/React.createElement(Arrowhead, {
|
|
29001
|
-
tip: tip,
|
|
29002
|
-
angle: angleDegrees(direction)
|
|
29003
|
-
}));
|
|
29004
|
-
}
|
|
29005
|
-
function angleDegrees([x, y]) {
|
|
29006
|
-
return Math.atan2(y, x) * 180 / Math.PI;
|
|
29007
|
-
}
|
|
29008
|
-
|
|
29009
29018
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
29010
29019
|
const MovableLine = props => {
|
|
29011
29020
|
const {
|
|
@@ -30919,6 +30928,7 @@ const MafsGraph = props => {
|
|
|
30919
30928
|
labels
|
|
30920
30929
|
}
|
|
30921
30930
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30931
|
+
className: "mafs-graph",
|
|
30922
30932
|
style: {
|
|
30923
30933
|
width,
|
|
30924
30934
|
height,
|
|
@@ -30953,7 +30963,8 @@ const MafsGraph = props => {
|
|
|
30953
30963
|
containerSizeClass: props.containerSizeClass,
|
|
30954
30964
|
markings: props.markings
|
|
30955
30965
|
}), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
|
|
30956
|
-
lockedFigures: props.lockedFigures
|
|
30966
|
+
lockedFigures: props.lockedFigures,
|
|
30967
|
+
range: props.range
|
|
30957
30968
|
}), renderGraph({
|
|
30958
30969
|
state,
|
|
30959
30970
|
dispatch
|
|
@@ -43054,7 +43065,7 @@ const init = function init(options) {
|
|
|
43054
43065
|
|
|
43055
43066
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43056
43067
|
const libName = "@khanacademy/perseus";
|
|
43057
|
-
const libVersion = "22.
|
|
43068
|
+
const libVersion = "22.3.0";
|
|
43058
43069
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43059
43070
|
|
|
43060
43071
|
const apiVersion = {
|