@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/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/index.js
CHANGED
|
@@ -28952,19 +28952,170 @@ const ItemExtras = [
|
|
|
28952
28952
|
|
|
28953
28953
|
const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
|
|
28954
28954
|
const lockedFigureColors = {
|
|
28955
|
-
blue: "#3D7586",
|
|
28956
28955
|
green: "#447A53",
|
|
28957
|
-
gray: "#5D5F66",
|
|
28958
28956
|
grayH: "#3B3D45",
|
|
28959
|
-
grayI: "#21242C",
|
|
28960
28957
|
purple: "#594094",
|
|
28961
|
-
purpleD: "#8351E8",
|
|
28962
28958
|
pink: "#B25071",
|
|
28963
|
-
orange: "#946700",
|
|
28964
28959
|
red: "#D92916"
|
|
28965
28960
|
};
|
|
28966
28961
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28967
28962
|
|
|
28963
|
+
function pathBuilder() {
|
|
28964
|
+
return new PathBuilder();
|
|
28965
|
+
}
|
|
28966
|
+
class PathBuilder {
|
|
28967
|
+
path = [];
|
|
28968
|
+
scaleFactor = 1;
|
|
28969
|
+
build() {
|
|
28970
|
+
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28971
|
+
}
|
|
28972
|
+
|
|
28973
|
+
// add a move (M) command to the path
|
|
28974
|
+
move(x, y) {
|
|
28975
|
+
this.path.push({
|
|
28976
|
+
action: "M",
|
|
28977
|
+
coords: [x, y]
|
|
28978
|
+
});
|
|
28979
|
+
return this;
|
|
28980
|
+
}
|
|
28981
|
+
|
|
28982
|
+
// add a curve (C) command to the path
|
|
28983
|
+
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28984
|
+
this.path.push({
|
|
28985
|
+
action: "C",
|
|
28986
|
+
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28987
|
+
});
|
|
28988
|
+
return this;
|
|
28989
|
+
}
|
|
28990
|
+
|
|
28991
|
+
// Scale all coordinates of the path by a factor
|
|
28992
|
+
scale(factor) {
|
|
28993
|
+
this.scaleFactor *= factor;
|
|
28994
|
+
return this;
|
|
28995
|
+
}
|
|
28996
|
+
}
|
|
28997
|
+
function commandToString(command) {
|
|
28998
|
+
return `${command.action}${command.coords.join(" ")}`;
|
|
28999
|
+
}
|
|
29000
|
+
function scaleCommandBy(scaleFactor) {
|
|
29001
|
+
return command => ({
|
|
29002
|
+
...command,
|
|
29003
|
+
coords: command.coords.map(c => c * scaleFactor)
|
|
29004
|
+
});
|
|
29005
|
+
}
|
|
29006
|
+
|
|
29007
|
+
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
29008
|
+
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
29009
|
+
// transform because a transform would also scale up the stroke weight, and we
|
|
29010
|
+
// don't want that.
|
|
29011
|
+
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();
|
|
29012
|
+
function Arrowhead(props) {
|
|
29013
|
+
const [point] = useTransformVectorsToPixels(props.tip);
|
|
29014
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29015
|
+
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
29016
|
+
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29017
|
+
transform: "translate(-1.5)"
|
|
29018
|
+
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
29019
|
+
d: arrowPath,
|
|
29020
|
+
fill: "none",
|
|
29021
|
+
style: {
|
|
29022
|
+
stroke: props.color ?? "inherit"
|
|
29023
|
+
},
|
|
29024
|
+
strokeLinejoin: "round",
|
|
29025
|
+
strokeLinecap: "round"
|
|
29026
|
+
})));
|
|
29027
|
+
}
|
|
29028
|
+
|
|
29029
|
+
function SVGLine(props) {
|
|
29030
|
+
const {
|
|
29031
|
+
start,
|
|
29032
|
+
end,
|
|
29033
|
+
style,
|
|
29034
|
+
className,
|
|
29035
|
+
testId
|
|
29036
|
+
} = props;
|
|
29037
|
+
return /*#__PURE__*/React__namespace.createElement("line", {
|
|
29038
|
+
x1: start[0],
|
|
29039
|
+
y1: start[1],
|
|
29040
|
+
x2: end[0],
|
|
29041
|
+
y2: end[1],
|
|
29042
|
+
style: style,
|
|
29043
|
+
className: className,
|
|
29044
|
+
"data-testid": testId
|
|
29045
|
+
});
|
|
29046
|
+
}
|
|
29047
|
+
|
|
29048
|
+
function Vector(props) {
|
|
29049
|
+
const {
|
|
29050
|
+
tail,
|
|
29051
|
+
tip,
|
|
29052
|
+
color,
|
|
29053
|
+
style
|
|
29054
|
+
} = props;
|
|
29055
|
+
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
29056
|
+
const direction = mafs.vec.sub(tip, tail);
|
|
29057
|
+
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29058
|
+
style: {
|
|
29059
|
+
stroke: color,
|
|
29060
|
+
strokeWidth: 2
|
|
29061
|
+
}
|
|
29062
|
+
}, /*#__PURE__*/React__namespace.createElement(SVGLine, {
|
|
29063
|
+
start: tailPx,
|
|
29064
|
+
end: tipPx,
|
|
29065
|
+
style: style
|
|
29066
|
+
}), /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29067
|
+
tip: tip,
|
|
29068
|
+
angle: angleDegrees(direction)
|
|
29069
|
+
}));
|
|
29070
|
+
}
|
|
29071
|
+
function angleDegrees(_ref) {
|
|
29072
|
+
let [x, y] = _ref;
|
|
29073
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
|
29074
|
+
}
|
|
29075
|
+
|
|
29076
|
+
/**
|
|
29077
|
+
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
29078
|
+
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
29079
|
+
* @param initialPoint - The starting point of the ray.
|
|
29080
|
+
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
29081
|
+
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
29082
|
+
*/
|
|
29083
|
+
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
29084
|
+
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
29085
|
+
const [aX, aY] = throughPoint;
|
|
29086
|
+
const [bX, bY] = initialPoint;
|
|
29087
|
+
const yDiff = bY - aY;
|
|
29088
|
+
const xDiff = bX - aX;
|
|
29089
|
+
const slope = yDiff / xDiff;
|
|
29090
|
+
const yAtXMin = slope * (xMin - aX) + aY;
|
|
29091
|
+
const yAtXMax = slope * (xMax - aX) + aY;
|
|
29092
|
+
const xAtYMin = (yMin - aY) / slope + aX;
|
|
29093
|
+
const xAtYMax = (yMax - aY) / slope + aX;
|
|
29094
|
+
|
|
29095
|
+
// clock analogy to describe quadrants
|
|
29096
|
+
switch (true) {
|
|
29097
|
+
// 12 o'clock to 2:59
|
|
29098
|
+
case yDiff > 0 && xDiff >= 0:
|
|
29099
|
+
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
29100
|
+
// 3 o'clock to 5:59
|
|
29101
|
+
case yDiff <= 0 && xDiff > 0:
|
|
29102
|
+
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
29103
|
+
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
29104
|
+
// 9 o'clock to 11:59
|
|
29105
|
+
case yDiff >= 0 && xDiff < 0:
|
|
29106
|
+
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
29107
|
+
// 6 o'clock to 8:59
|
|
29108
|
+
case yDiff < 0 && xDiff <= 0:
|
|
29109
|
+
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
29110
|
+
default:
|
|
29111
|
+
return [xMax, yAtXMax];
|
|
29112
|
+
}
|
|
29113
|
+
};
|
|
29114
|
+
const getLines = points => points.map((point, i) => {
|
|
29115
|
+
const next = points[(i + 1) % points.length];
|
|
29116
|
+
return [point, next];
|
|
29117
|
+
});
|
|
29118
|
+
|
|
28968
29119
|
const LockedLine = props => {
|
|
28969
29120
|
const {
|
|
28970
29121
|
color,
|
|
@@ -28972,11 +29123,27 @@ const LockedLine = props => {
|
|
|
28972
29123
|
kind,
|
|
28973
29124
|
points,
|
|
28974
29125
|
showStartPoint,
|
|
28975
|
-
showEndPoint
|
|
29126
|
+
showEndPoint,
|
|
29127
|
+
range
|
|
28976
29128
|
} = props;
|
|
28977
29129
|
const [point1, point2] = points;
|
|
28978
29130
|
let line;
|
|
28979
|
-
if (kind === "
|
|
29131
|
+
if (kind === "ray") {
|
|
29132
|
+
// Rays extend to the end of the graph in one direction.
|
|
29133
|
+
const endExtend = getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
29134
|
+
line = /*#__PURE__*/React__namespace.createElement(Vector, {
|
|
29135
|
+
tail: point1.coord,
|
|
29136
|
+
tip: endExtend,
|
|
29137
|
+
color: lockedFigureColors[color],
|
|
29138
|
+
style: {
|
|
29139
|
+
strokeDasharray: lineStyle === "dashed" ?
|
|
29140
|
+
// TODO(lems-1930): Uncomment this line when the
|
|
29141
|
+
// dashed style is updated in Mafs.
|
|
29142
|
+
// ? "var(--mafs-line-stroke-dash-style)"
|
|
29143
|
+
"4, 3" : undefined
|
|
29144
|
+
}
|
|
29145
|
+
});
|
|
29146
|
+
} else {
|
|
28980
29147
|
const LineType = kind === "segment" ? mafs.Line.Segment : mafs.Line.ThroughPoints;
|
|
28981
29148
|
line = /*#__PURE__*/React__namespace.createElement(LineType, {
|
|
28982
29149
|
point1: point1.coord,
|
|
@@ -28984,12 +29151,9 @@ const LockedLine = props => {
|
|
|
28984
29151
|
color: lockedFigureColors[color],
|
|
28985
29152
|
style: lineStyle
|
|
28986
29153
|
});
|
|
28987
|
-
} else {
|
|
28988
|
-
// TODO(LEMS-1928): Implement rays
|
|
28989
|
-
return null;
|
|
28990
29154
|
}
|
|
28991
29155
|
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
28992
|
-
className: "locked-line"
|
|
29156
|
+
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
28993
29157
|
}, line, showStartPoint && /*#__PURE__*/React__namespace.createElement(mafs.Point, {
|
|
28994
29158
|
x: point1.coord[0],
|
|
28995
29159
|
y: point1.coord[1],
|
|
@@ -29038,14 +29202,16 @@ const GraphLockedLayer = props => {
|
|
|
29038
29202
|
lockedFigures
|
|
29039
29203
|
} = props;
|
|
29040
29204
|
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, lockedFigures.map((figure, index) => {
|
|
29041
|
-
let Figure;
|
|
29042
29205
|
switch (figure.type) {
|
|
29043
29206
|
case "point":
|
|
29044
|
-
|
|
29045
|
-
|
|
29207
|
+
return /*#__PURE__*/React__namespace.createElement(LockedPoint, _extends({
|
|
29208
|
+
key: `point-${index}`
|
|
29209
|
+
}, figure));
|
|
29046
29210
|
case "line":
|
|
29047
|
-
|
|
29048
|
-
|
|
29211
|
+
return /*#__PURE__*/React__namespace.createElement(LockedLine, _extends({
|
|
29212
|
+
key: `line-${index}`,
|
|
29213
|
+
range: props.range
|
|
29214
|
+
}, figure));
|
|
29049
29215
|
default:
|
|
29050
29216
|
/**
|
|
29051
29217
|
* Devlopment-time future-proofing: This should
|
|
@@ -29055,9 +29221,6 @@ const GraphLockedLayer = props => {
|
|
|
29055
29221
|
*/
|
|
29056
29222
|
throw new wonderStuffCore.UnreachableCaseError(figure);
|
|
29057
29223
|
}
|
|
29058
|
-
return /*#__PURE__*/React__namespace.createElement(Figure, _extends({
|
|
29059
|
-
key: `${figure.type}-${index}`
|
|
29060
|
-
}, figure));
|
|
29061
29224
|
}));
|
|
29062
29225
|
};
|
|
29063
29226
|
|
|
@@ -29139,160 +29302,6 @@ function snap(snapStep, point) {
|
|
|
29139
29302
|
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
29140
29303
|
}
|
|
29141
29304
|
|
|
29142
|
-
/**
|
|
29143
|
-
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
29144
|
-
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
29145
|
-
* @param initialPoint - The starting point of the ray.
|
|
29146
|
-
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
29147
|
-
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
29148
|
-
*/
|
|
29149
|
-
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
29150
|
-
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
29151
|
-
const [aX, aY] = throughPoint;
|
|
29152
|
-
const [bX, bY] = initialPoint;
|
|
29153
|
-
const yDiff = bY - aY;
|
|
29154
|
-
const xDiff = bX - aX;
|
|
29155
|
-
const slope = yDiff / xDiff;
|
|
29156
|
-
const yAtXMin = slope * (xMin - aX) + aY;
|
|
29157
|
-
const yAtXMax = slope * (xMax - aX) + aY;
|
|
29158
|
-
const xAtYMin = (yMin - aY) / slope + aX;
|
|
29159
|
-
const xAtYMax = (yMax - aY) / slope + aX;
|
|
29160
|
-
|
|
29161
|
-
// clock analogy to describe quadrants
|
|
29162
|
-
switch (true) {
|
|
29163
|
-
// 12 o'clock to 2:59
|
|
29164
|
-
case yDiff > 0 && xDiff >= 0:
|
|
29165
|
-
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
29166
|
-
// 3 o'clock to 5:59
|
|
29167
|
-
case yDiff <= 0 && xDiff > 0:
|
|
29168
|
-
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
29169
|
-
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
29170
|
-
// 9 o'clock to 11:59
|
|
29171
|
-
case yDiff >= 0 && xDiff < 0:
|
|
29172
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
29173
|
-
// 6 o'clock to 8:59
|
|
29174
|
-
case yDiff < 0 && xDiff <= 0:
|
|
29175
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
29176
|
-
default:
|
|
29177
|
-
return [xMax, yAtXMax];
|
|
29178
|
-
}
|
|
29179
|
-
};
|
|
29180
|
-
const getLines = points => points.map((point, i) => {
|
|
29181
|
-
const next = points[(i + 1) % points.length];
|
|
29182
|
-
return [point, next];
|
|
29183
|
-
});
|
|
29184
|
-
|
|
29185
|
-
function SVGLine(props) {
|
|
29186
|
-
const {
|
|
29187
|
-
start,
|
|
29188
|
-
end,
|
|
29189
|
-
style,
|
|
29190
|
-
className,
|
|
29191
|
-
testId
|
|
29192
|
-
} = props;
|
|
29193
|
-
return /*#__PURE__*/React__namespace.createElement("line", {
|
|
29194
|
-
x1: start[0],
|
|
29195
|
-
y1: start[1],
|
|
29196
|
-
x2: end[0],
|
|
29197
|
-
y2: end[1],
|
|
29198
|
-
style: style,
|
|
29199
|
-
className: `${className}`,
|
|
29200
|
-
"data-testid": testId
|
|
29201
|
-
});
|
|
29202
|
-
}
|
|
29203
|
-
|
|
29204
|
-
function pathBuilder() {
|
|
29205
|
-
return new PathBuilder();
|
|
29206
|
-
}
|
|
29207
|
-
class PathBuilder {
|
|
29208
|
-
path = [];
|
|
29209
|
-
scaleFactor = 1;
|
|
29210
|
-
build() {
|
|
29211
|
-
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
29212
|
-
}
|
|
29213
|
-
|
|
29214
|
-
// add a move (M) command to the path
|
|
29215
|
-
move(x, y) {
|
|
29216
|
-
this.path.push({
|
|
29217
|
-
action: "M",
|
|
29218
|
-
coords: [x, y]
|
|
29219
|
-
});
|
|
29220
|
-
return this;
|
|
29221
|
-
}
|
|
29222
|
-
|
|
29223
|
-
// add a curve (C) command to the path
|
|
29224
|
-
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
29225
|
-
this.path.push({
|
|
29226
|
-
action: "C",
|
|
29227
|
-
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
29228
|
-
});
|
|
29229
|
-
return this;
|
|
29230
|
-
}
|
|
29231
|
-
|
|
29232
|
-
// Scale all coordinates of the path by a factor
|
|
29233
|
-
scale(factor) {
|
|
29234
|
-
this.scaleFactor *= factor;
|
|
29235
|
-
return this;
|
|
29236
|
-
}
|
|
29237
|
-
}
|
|
29238
|
-
function commandToString(command) {
|
|
29239
|
-
return `${command.action}${command.coords.join(" ")}`;
|
|
29240
|
-
}
|
|
29241
|
-
function scaleCommandBy(scaleFactor) {
|
|
29242
|
-
return command => ({
|
|
29243
|
-
...command,
|
|
29244
|
-
coords: command.coords.map(c => c * scaleFactor)
|
|
29245
|
-
});
|
|
29246
|
-
}
|
|
29247
|
-
|
|
29248
|
-
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
29249
|
-
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
29250
|
-
// transform because a transform would also scale up the stroke weight, and we
|
|
29251
|
-
// don't want that.
|
|
29252
|
-
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();
|
|
29253
|
-
function Arrowhead(props) {
|
|
29254
|
-
const [point] = useTransformVectorsToPixels(props.tip);
|
|
29255
|
-
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29256
|
-
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
29257
|
-
}, /*#__PURE__*/React__namespace.createElement("g", {
|
|
29258
|
-
transform: "translate(-1.5)"
|
|
29259
|
-
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
29260
|
-
d: arrowPath,
|
|
29261
|
-
fill: "none",
|
|
29262
|
-
style: {
|
|
29263
|
-
stroke: props.color ?? "inherit"
|
|
29264
|
-
},
|
|
29265
|
-
strokeLinejoin: "round",
|
|
29266
|
-
strokeLinecap: "round"
|
|
29267
|
-
})));
|
|
29268
|
-
}
|
|
29269
|
-
|
|
29270
|
-
function Vector(props) {
|
|
29271
|
-
const {
|
|
29272
|
-
tail,
|
|
29273
|
-
tip,
|
|
29274
|
-
color
|
|
29275
|
-
} = props;
|
|
29276
|
-
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
29277
|
-
const direction = mafs.vec.sub(tip, tail);
|
|
29278
|
-
return /*#__PURE__*/React__namespace.createElement("g", {
|
|
29279
|
-
style: {
|
|
29280
|
-
stroke: color,
|
|
29281
|
-
strokeWidth: 2
|
|
29282
|
-
}
|
|
29283
|
-
}, /*#__PURE__*/React__namespace.createElement(SVGLine, {
|
|
29284
|
-
start: tailPx,
|
|
29285
|
-
end: tipPx
|
|
29286
|
-
}), /*#__PURE__*/React__namespace.createElement(Arrowhead, {
|
|
29287
|
-
tip: tip,
|
|
29288
|
-
angle: angleDegrees(direction)
|
|
29289
|
-
}));
|
|
29290
|
-
}
|
|
29291
|
-
function angleDegrees(_ref) {
|
|
29292
|
-
let [x, y] = _ref;
|
|
29293
|
-
return Math.atan2(y, x) * 180 / Math.PI;
|
|
29294
|
-
}
|
|
29295
|
-
|
|
29296
29305
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
29297
29306
|
const MovableLine = props => {
|
|
29298
29307
|
const {
|
|
@@ -31244,6 +31253,7 @@ const MafsGraph = props => {
|
|
|
31244
31253
|
labels
|
|
31245
31254
|
}
|
|
31246
31255
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
31256
|
+
className: "mafs-graph",
|
|
31247
31257
|
style: {
|
|
31248
31258
|
width,
|
|
31249
31259
|
height,
|
|
@@ -31278,7 +31288,8 @@ const MafsGraph = props => {
|
|
|
31278
31288
|
containerSizeClass: props.containerSizeClass,
|
|
31279
31289
|
markings: props.markings
|
|
31280
31290
|
}), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
|
|
31281
|
-
lockedFigures: props.lockedFigures
|
|
31291
|
+
lockedFigures: props.lockedFigures,
|
|
31292
|
+
range: props.range
|
|
31282
31293
|
}), renderGraph({
|
|
31283
31294
|
state,
|
|
31284
31295
|
dispatch
|
|
@@ -43374,7 +43385,7 @@ const init = function (options) {
|
|
|
43374
43385
|
|
|
43375
43386
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43376
43387
|
const libName = "@khanacademy/perseus";
|
|
43377
|
-
const libVersion = "22.
|
|
43388
|
+
const libVersion = "22.3.0";
|
|
43378
43389
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43379
43390
|
|
|
43380
43391
|
const apiVersion = {
|