@khanacademy/perseus 22.0.2 → 22.2.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/components/info-tip/info-tip.d.ts +2 -10
- package/dist/es/index.css +15 -1
- package/dist/es/index.js +342 -310
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +15 -1
- package/dist/index.js +343 -305
- package/dist/index.js.map +1 -1
- package/dist/widgets/interactive-graph.d.ts +3 -3
- package/dist/widgets/interactive-graphs/axis-labels.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graph-locked-layer.d.ts +2 -0
- package/dist/widgets/interactive-graphs/graphs/components/arrowhead.d.ts +2 -2
- package/dist/widgets/interactive-graphs/graphs/components/movable-line.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/components/vector.d.ts +2 -1
- package/dist/widgets/interactive-graphs/graphs/use-transform.d.ts +9 -2
- package/dist/widgets/interactive-graphs/graphs/utils.d.ts +6 -4
- package/dist/widgets/interactive-graphs/locked-line.d.ts +5 -1
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +4 -0
- package/package.json +5 -5
package/dist/es/index.js
CHANGED
|
@@ -29,10 +29,10 @@ import { OptionItem, SingleSelect, MultiSelect } from '@khanacademy/wonder-block
|
|
|
29
29
|
import caretDown from '@phosphor-icons/core/assets/regular/caret-down.svg';
|
|
30
30
|
import caretUp from '@phosphor-icons/core/assets/regular/caret-up.svg';
|
|
31
31
|
import debounce$2 from 'lodash.debounce';
|
|
32
|
-
import { Line as Line$3, Point as Point$2,
|
|
32
|
+
import { vec, Line as Line$3, Point as Point$2, useMovable, Text as Text$1, Polygon, Coordinates, Mafs } from 'mafs';
|
|
33
33
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
34
|
+
import { Body, LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
34
35
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
35
|
-
import { LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
|
|
36
36
|
import createReactClass from 'create-react-class';
|
|
37
37
|
import Switch from '@khanacademy/wonder-blocks-switch';
|
|
38
38
|
import Pill from '@khanacademy/wonder-blocks-pill';
|
|
@@ -28477,6 +28477,89 @@ Graph.defaultProps = {
|
|
|
28477
28477
|
isMobile: false
|
|
28478
28478
|
};
|
|
28479
28479
|
|
|
28480
|
+
const defaultGraphConfig = {
|
|
28481
|
+
range: [[0, 1], [0, 1]],
|
|
28482
|
+
snapStep: [1, 1],
|
|
28483
|
+
markings: "none",
|
|
28484
|
+
showTooltips: false,
|
|
28485
|
+
graphDimensionsInPixels: [1, 1],
|
|
28486
|
+
width: 0,
|
|
28487
|
+
height: 0,
|
|
28488
|
+
labels: []
|
|
28489
|
+
};
|
|
28490
|
+
const GraphConfigContext = /*#__PURE__*/createContext(defaultGraphConfig);
|
|
28491
|
+
function useGraphConfig() {
|
|
28492
|
+
return React__default.useContext(GraphConfigContext);
|
|
28493
|
+
}
|
|
28494
|
+
|
|
28495
|
+
const matrixBuilder = vec.matrixBuilder;
|
|
28496
|
+
// When converting vectors, we don't need to translate because a vector
|
|
28497
|
+
// is like a pair of x and y distances, which are not bound to specific graph locations.
|
|
28498
|
+
function vectorsToPixels(vectors, graphState, translation = [0, 0]) {
|
|
28499
|
+
const {
|
|
28500
|
+
range,
|
|
28501
|
+
width,
|
|
28502
|
+
height
|
|
28503
|
+
} = graphState;
|
|
28504
|
+
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28505
|
+
const transformToPx = matrixBuilder().translate(...translation).scale(width / (xMax - xMin), -height / (yMax - yMin)).get();
|
|
28506
|
+
return vectors.map(p => vec.transform(p, transformToPx));
|
|
28507
|
+
}
|
|
28508
|
+
|
|
28509
|
+
// When converting points, we translate so the pixel point ends up in the right location.
|
|
28510
|
+
// This is because points are specific locations on graphs, unlike vectors.
|
|
28511
|
+
function pointToPixel(point, graphState) {
|
|
28512
|
+
const [[xMin], [, yMax]] = graphState.range;
|
|
28513
|
+
const [a, b] = [-xMin, -yMax];
|
|
28514
|
+
return vectorsToPixels([point], graphState, [a, b])[0];
|
|
28515
|
+
}
|
|
28516
|
+
const useTransformVectorsToPixels = (...vectors) => {
|
|
28517
|
+
const graphState = useGraphConfig();
|
|
28518
|
+
return vectorsToPixels(vectors, graphState);
|
|
28519
|
+
};
|
|
28520
|
+
|
|
28521
|
+
function AxisLabels() {
|
|
28522
|
+
const {
|
|
28523
|
+
range,
|
|
28524
|
+
labels,
|
|
28525
|
+
width,
|
|
28526
|
+
height
|
|
28527
|
+
} = useGraphConfig();
|
|
28528
|
+
const yAxisLabelLocation = [0, range[1][1]];
|
|
28529
|
+
const xAxisLabelLocation = [range[0][1], 0];
|
|
28530
|
+
const [xAxisLabelText, yAxisLabelText] = labels;
|
|
28531
|
+
const graphInfo = {
|
|
28532
|
+
range,
|
|
28533
|
+
width,
|
|
28534
|
+
height
|
|
28535
|
+
};
|
|
28536
|
+
const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
|
|
28537
|
+
// The default location for the y-axis-label is at the maximum y point
|
|
28538
|
+
// This is just underneath the tick line for that point. The -24 moves the
|
|
28539
|
+
// label up one grid square, so it sits on top of the graph
|
|
28540
|
+
const [x2, y2] = vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
|
|
28541
|
+
const {
|
|
28542
|
+
TeX
|
|
28543
|
+
} = getDependencies();
|
|
28544
|
+
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
|
|
28545
|
+
style: {
|
|
28546
|
+
position: "absolute",
|
|
28547
|
+
left: x1,
|
|
28548
|
+
top: y1,
|
|
28549
|
+
fontSize: "14px",
|
|
28550
|
+
transform: "translate(7px, -50%)"
|
|
28551
|
+
}
|
|
28552
|
+
}, /*#__PURE__*/React__default.createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default.createElement("span", {
|
|
28553
|
+
style: {
|
|
28554
|
+
position: "absolute",
|
|
28555
|
+
left: x2,
|
|
28556
|
+
top: y2,
|
|
28557
|
+
fontSize: "14px",
|
|
28558
|
+
transform: "translate(-50%, 0px)"
|
|
28559
|
+
}
|
|
28560
|
+
}, /*#__PURE__*/React__default.createElement(TeX, null, yAxisLabelText)));
|
|
28561
|
+
}
|
|
28562
|
+
|
|
28480
28563
|
// TODO(FEI-4010): Remove `Perseus` prefix for all types here
|
|
28481
28564
|
// TODO(FEI-4011): Use types generated by https://github.com/jaredly/generate-perseus-flowtypes
|
|
28482
28565
|
|
|
@@ -28594,6 +28677,163 @@ const lockedFigureColors = {
|
|
|
28594
28677
|
};
|
|
28595
28678
|
const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
|
|
28596
28679
|
|
|
28680
|
+
function pathBuilder() {
|
|
28681
|
+
return new PathBuilder();
|
|
28682
|
+
}
|
|
28683
|
+
class PathBuilder {
|
|
28684
|
+
constructor() {
|
|
28685
|
+
this.path = [];
|
|
28686
|
+
this.scaleFactor = 1;
|
|
28687
|
+
}
|
|
28688
|
+
build() {
|
|
28689
|
+
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28690
|
+
}
|
|
28691
|
+
|
|
28692
|
+
// add a move (M) command to the path
|
|
28693
|
+
move(x, y) {
|
|
28694
|
+
this.path.push({
|
|
28695
|
+
action: "M",
|
|
28696
|
+
coords: [x, y]
|
|
28697
|
+
});
|
|
28698
|
+
return this;
|
|
28699
|
+
}
|
|
28700
|
+
|
|
28701
|
+
// add a curve (C) command to the path
|
|
28702
|
+
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28703
|
+
this.path.push({
|
|
28704
|
+
action: "C",
|
|
28705
|
+
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28706
|
+
});
|
|
28707
|
+
return this;
|
|
28708
|
+
}
|
|
28709
|
+
|
|
28710
|
+
// Scale all coordinates of the path by a factor
|
|
28711
|
+
scale(factor) {
|
|
28712
|
+
this.scaleFactor *= factor;
|
|
28713
|
+
return this;
|
|
28714
|
+
}
|
|
28715
|
+
}
|
|
28716
|
+
function commandToString(command) {
|
|
28717
|
+
return `${command.action}${command.coords.join(" ")}`;
|
|
28718
|
+
}
|
|
28719
|
+
function scaleCommandBy(scaleFactor) {
|
|
28720
|
+
return command => _extends({}, command, {
|
|
28721
|
+
coords: command.coords.map(c => c * scaleFactor)
|
|
28722
|
+
});
|
|
28723
|
+
}
|
|
28724
|
+
|
|
28725
|
+
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
28726
|
+
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
28727
|
+
// transform because a transform would also scale up the stroke weight, and we
|
|
28728
|
+
// don't want that.
|
|
28729
|
+
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();
|
|
28730
|
+
function Arrowhead(props) {
|
|
28731
|
+
var _props$color;
|
|
28732
|
+
const [point] = useTransformVectorsToPixels(props.tip);
|
|
28733
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28734
|
+
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
28735
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
28736
|
+
transform: "translate(-1.5)"
|
|
28737
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
28738
|
+
d: arrowPath,
|
|
28739
|
+
fill: "none",
|
|
28740
|
+
style: {
|
|
28741
|
+
stroke: (_props$color = props.color) != null ? _props$color : "inherit"
|
|
28742
|
+
},
|
|
28743
|
+
strokeLinejoin: "round",
|
|
28744
|
+
strokeLinecap: "round"
|
|
28745
|
+
})));
|
|
28746
|
+
}
|
|
28747
|
+
|
|
28748
|
+
function SVGLine(props) {
|
|
28749
|
+
const {
|
|
28750
|
+
start,
|
|
28751
|
+
end,
|
|
28752
|
+
style,
|
|
28753
|
+
className,
|
|
28754
|
+
testId
|
|
28755
|
+
} = props;
|
|
28756
|
+
return /*#__PURE__*/React.createElement("line", {
|
|
28757
|
+
x1: start[0],
|
|
28758
|
+
y1: start[1],
|
|
28759
|
+
x2: end[0],
|
|
28760
|
+
y2: end[1],
|
|
28761
|
+
style: style,
|
|
28762
|
+
className: className,
|
|
28763
|
+
"data-testid": testId
|
|
28764
|
+
});
|
|
28765
|
+
}
|
|
28766
|
+
|
|
28767
|
+
function Vector(props) {
|
|
28768
|
+
const {
|
|
28769
|
+
tail,
|
|
28770
|
+
tip,
|
|
28771
|
+
color,
|
|
28772
|
+
style
|
|
28773
|
+
} = props;
|
|
28774
|
+
const [tailPx, tipPx] = useTransformVectorsToPixels(tail, tip);
|
|
28775
|
+
const direction = vec.sub(tip, tail);
|
|
28776
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
28777
|
+
style: {
|
|
28778
|
+
stroke: color,
|
|
28779
|
+
strokeWidth: 2
|
|
28780
|
+
}
|
|
28781
|
+
}, /*#__PURE__*/React.createElement(SVGLine, {
|
|
28782
|
+
start: tailPx,
|
|
28783
|
+
end: tipPx,
|
|
28784
|
+
style: style
|
|
28785
|
+
}), /*#__PURE__*/React.createElement(Arrowhead, {
|
|
28786
|
+
tip: tip,
|
|
28787
|
+
angle: angleDegrees(direction)
|
|
28788
|
+
}));
|
|
28789
|
+
}
|
|
28790
|
+
function angleDegrees([x, y]) {
|
|
28791
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28792
|
+
}
|
|
28793
|
+
|
|
28794
|
+
/**
|
|
28795
|
+
* Given a ray and a rectangular box, find the point where the ray intersects
|
|
28796
|
+
* the edge of the box. Assumes the `initialPoint` is inside the box.
|
|
28797
|
+
* @param initialPoint - The starting point of the ray.
|
|
28798
|
+
* @param throughPoint - A point that the ray passes through. Must be different from initialPoint.
|
|
28799
|
+
* @param box - The box with which to intersect the ray, in the form [[xMin, xMax], [yMin, yMax]]
|
|
28800
|
+
*/
|
|
28801
|
+
const getIntersectionOfRayWithBox = (initialPoint, throughPoint, box) => {
|
|
28802
|
+
const [[xMin, xMax], [yMin, yMax]] = box;
|
|
28803
|
+
const [aX, aY] = throughPoint;
|
|
28804
|
+
const [bX, bY] = initialPoint;
|
|
28805
|
+
const yDiff = bY - aY;
|
|
28806
|
+
const xDiff = bX - aX;
|
|
28807
|
+
const slope = yDiff / xDiff;
|
|
28808
|
+
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28809
|
+
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28810
|
+
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28811
|
+
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28812
|
+
|
|
28813
|
+
// clock analogy to describe quadrants
|
|
28814
|
+
switch (true) {
|
|
28815
|
+
// 12 o'clock to 2:59
|
|
28816
|
+
case yDiff > 0 && xDiff >= 0:
|
|
28817
|
+
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28818
|
+
// 3 o'clock to 5:59
|
|
28819
|
+
case yDiff <= 0 && xDiff > 0:
|
|
28820
|
+
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28821
|
+
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28822
|
+
// 9 o'clock to 11:59
|
|
28823
|
+
case yDiff >= 0 && xDiff < 0:
|
|
28824
|
+
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28825
|
+
// 6 o'clock to 8:59
|
|
28826
|
+
case yDiff < 0 && xDiff <= 0:
|
|
28827
|
+
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28828
|
+
default:
|
|
28829
|
+
return [xMax, yAtXMax];
|
|
28830
|
+
}
|
|
28831
|
+
};
|
|
28832
|
+
const getLines = points => points.map((point, i) => {
|
|
28833
|
+
const next = points[(i + 1) % points.length];
|
|
28834
|
+
return [point, next];
|
|
28835
|
+
});
|
|
28836
|
+
|
|
28597
28837
|
const LockedLine = props => {
|
|
28598
28838
|
const {
|
|
28599
28839
|
color: color$1,
|
|
@@ -28601,11 +28841,27 @@ const LockedLine = props => {
|
|
|
28601
28841
|
kind,
|
|
28602
28842
|
points,
|
|
28603
28843
|
showStartPoint,
|
|
28604
|
-
showEndPoint
|
|
28844
|
+
showEndPoint,
|
|
28845
|
+
range
|
|
28605
28846
|
} = props;
|
|
28606
28847
|
const [point1, point2] = points;
|
|
28607
28848
|
let line;
|
|
28608
|
-
if (kind === "
|
|
28849
|
+
if (kind === "ray") {
|
|
28850
|
+
// Rays extend to the end of the graph in one direction.
|
|
28851
|
+
const endExtend = getIntersectionOfRayWithBox(point2.coord, point1.coord, range);
|
|
28852
|
+
line = /*#__PURE__*/React.createElement(Vector, {
|
|
28853
|
+
tail: point1.coord,
|
|
28854
|
+
tip: endExtend,
|
|
28855
|
+
color: lockedFigureColors[color$1],
|
|
28856
|
+
style: {
|
|
28857
|
+
strokeDasharray: lineStyle === "dashed" ?
|
|
28858
|
+
// TODO(lems-1930): Uncomment this line when the
|
|
28859
|
+
// dashed style is updated in Mafs.
|
|
28860
|
+
// ? "var(--mafs-line-stroke-dash-style)"
|
|
28861
|
+
"4, 3" : undefined
|
|
28862
|
+
}
|
|
28863
|
+
});
|
|
28864
|
+
} else {
|
|
28609
28865
|
const LineType = kind === "segment" ? Line$3.Segment : Line$3.ThroughPoints;
|
|
28610
28866
|
line = /*#__PURE__*/React.createElement(LineType, {
|
|
28611
28867
|
point1: point1.coord,
|
|
@@ -28613,12 +28869,9 @@ const LockedLine = props => {
|
|
|
28613
28869
|
color: lockedFigureColors[color$1],
|
|
28614
28870
|
style: lineStyle
|
|
28615
28871
|
});
|
|
28616
|
-
} else {
|
|
28617
|
-
// TODO(LEMS-1928): Implement rays
|
|
28618
|
-
return null;
|
|
28619
28872
|
}
|
|
28620
28873
|
return /*#__PURE__*/React.createElement("g", {
|
|
28621
|
-
className: "locked-line"
|
|
28874
|
+
className: kind === "ray" ? "locked-ray" : "locked-line"
|
|
28622
28875
|
}, line, showStartPoint && /*#__PURE__*/React.createElement(Point$2, {
|
|
28623
28876
|
x: point1.coord[0],
|
|
28624
28877
|
y: point1.coord[1],
|
|
@@ -28667,14 +28920,16 @@ const GraphLockedLayer = props => {
|
|
|
28667
28920
|
lockedFigures
|
|
28668
28921
|
} = props;
|
|
28669
28922
|
return /*#__PURE__*/React.createElement(React.Fragment, null, lockedFigures.map((figure, index) => {
|
|
28670
|
-
let Figure;
|
|
28671
28923
|
switch (figure.type) {
|
|
28672
28924
|
case "point":
|
|
28673
|
-
|
|
28674
|
-
|
|
28925
|
+
return /*#__PURE__*/React.createElement(LockedPoint, _extends({
|
|
28926
|
+
key: `point-${index}`
|
|
28927
|
+
}, figure));
|
|
28675
28928
|
case "line":
|
|
28676
|
-
|
|
28677
|
-
|
|
28929
|
+
return /*#__PURE__*/React.createElement(LockedLine, _extends({
|
|
28930
|
+
key: `line-${index}`,
|
|
28931
|
+
range: props.range
|
|
28932
|
+
}, figure));
|
|
28678
28933
|
default:
|
|
28679
28934
|
/**
|
|
28680
28935
|
* Devlopment-time future-proofing: This should
|
|
@@ -28684,9 +28939,6 @@ const GraphLockedLayer = props => {
|
|
|
28684
28939
|
*/
|
|
28685
28940
|
throw new UnreachableCaseError(figure);
|
|
28686
28941
|
}
|
|
28687
|
-
return /*#__PURE__*/React.createElement(Figure, _extends({
|
|
28688
|
-
key: `${figure.type}-${index}`
|
|
28689
|
-
}, figure));
|
|
28690
28942
|
}));
|
|
28691
28943
|
};
|
|
28692
28944
|
|
|
@@ -28768,171 +29020,6 @@ function snap(snapStep, point) {
|
|
|
28768
29020
|
return [Math.round(requestedX / snapX) * snapX, Math.round(requestedY / snapY) * snapY];
|
|
28769
29021
|
}
|
|
28770
29022
|
|
|
28771
|
-
const useTransform = (...points) => {
|
|
28772
|
-
const {
|
|
28773
|
-
viewTransform,
|
|
28774
|
-
userTransform
|
|
28775
|
-
} = useTransformContext();
|
|
28776
|
-
const transformToPx = vec.matrixMult(viewTransform, userTransform);
|
|
28777
|
-
const transformedPoints = points.map(point => vec.transform(point, transformToPx));
|
|
28778
|
-
return transformedPoints;
|
|
28779
|
-
};
|
|
28780
|
-
|
|
28781
|
-
/**
|
|
28782
|
-
* Given two points, find the tips that extends through the points to the edge of the range.
|
|
28783
|
-
* @param collinearPoint - The point that the line passes through. Needed to establish slope.
|
|
28784
|
-
* @param extendFrom - The point that the line extends from to the edge of the graph.
|
|
28785
|
-
*/
|
|
28786
|
-
const getRayIntersectionCoords = (collinearPoint, extendFrom, range) => {
|
|
28787
|
-
// edges of the graph
|
|
28788
|
-
const [[xMin, xMax], [yMin, yMax]] = range;
|
|
28789
|
-
const [aX, aY] = collinearPoint;
|
|
28790
|
-
const [bX, bY] = extendFrom;
|
|
28791
|
-
const yDiff = bY - aY;
|
|
28792
|
-
const xDiff = bX - aX;
|
|
28793
|
-
const slope = yDiff / xDiff;
|
|
28794
|
-
const yAtXMin = slope * (xMin - aX) + aY;
|
|
28795
|
-
const yAtXMax = slope * (xMax - aX) + aY;
|
|
28796
|
-
const xAtYMin = (yMin - aY) / slope + aX;
|
|
28797
|
-
const xAtYMax = (yMax - aY) / slope + aX;
|
|
28798
|
-
|
|
28799
|
-
// clock analogy to describe quadrants
|
|
28800
|
-
switch (true) {
|
|
28801
|
-
// 12 o'clock to 2:59
|
|
28802
|
-
case yDiff > 0 && xDiff >= 0:
|
|
28803
|
-
return xAtYMax > xMax ? [xMax, yAtXMax] : [xAtYMax, yMax];
|
|
28804
|
-
// 3 o'clock to 5:59
|
|
28805
|
-
case yDiff <= 0 && xDiff > 0:
|
|
28806
|
-
// xAtYMin evaluates to -Infinity here, so we use absolute value
|
|
28807
|
-
return Math.abs(xAtYMin) > xMax ? [xMax, yAtXMax] : [xAtYMin, yMin];
|
|
28808
|
-
// 9 o'clock to 11:59
|
|
28809
|
-
case yDiff >= 0 && xDiff < 0:
|
|
28810
|
-
return xAtYMax < xMin ? [xMin, yAtXMin] : [xAtYMax, yMax];
|
|
28811
|
-
// 6 o'clock to 8:59
|
|
28812
|
-
case yDiff < 0 && xDiff <= 0:
|
|
28813
|
-
return xAtYMin < xMin ? [xMin, yAtXMin] : [xAtYMin, yMin];
|
|
28814
|
-
default:
|
|
28815
|
-
return [xMax, yAtXMax];
|
|
28816
|
-
}
|
|
28817
|
-
};
|
|
28818
|
-
const getLines = points => points.map((point, i) => {
|
|
28819
|
-
const next = points[(i + 1) % points.length];
|
|
28820
|
-
return [point, next];
|
|
28821
|
-
});
|
|
28822
|
-
|
|
28823
|
-
function SVGLine(props) {
|
|
28824
|
-
const {
|
|
28825
|
-
start,
|
|
28826
|
-
end,
|
|
28827
|
-
style,
|
|
28828
|
-
className,
|
|
28829
|
-
testId
|
|
28830
|
-
} = props;
|
|
28831
|
-
return /*#__PURE__*/React.createElement("line", {
|
|
28832
|
-
x1: start[0],
|
|
28833
|
-
y1: start[1],
|
|
28834
|
-
x2: end[0],
|
|
28835
|
-
y2: end[1],
|
|
28836
|
-
style: style,
|
|
28837
|
-
className: `${className}`,
|
|
28838
|
-
"data-testid": testId
|
|
28839
|
-
});
|
|
28840
|
-
}
|
|
28841
|
-
|
|
28842
|
-
function pathBuilder() {
|
|
28843
|
-
return new PathBuilder();
|
|
28844
|
-
}
|
|
28845
|
-
class PathBuilder {
|
|
28846
|
-
constructor() {
|
|
28847
|
-
this.path = [];
|
|
28848
|
-
this.scaleFactor = 1;
|
|
28849
|
-
}
|
|
28850
|
-
build() {
|
|
28851
|
-
return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
|
|
28852
|
-
}
|
|
28853
|
-
|
|
28854
|
-
// add a move (M) command to the path
|
|
28855
|
-
move(x, y) {
|
|
28856
|
-
this.path.push({
|
|
28857
|
-
action: "M",
|
|
28858
|
-
coords: [x, y]
|
|
28859
|
-
});
|
|
28860
|
-
return this;
|
|
28861
|
-
}
|
|
28862
|
-
|
|
28863
|
-
// add a curve (C) command to the path
|
|
28864
|
-
curve(control1X, control1Y, control2X, control2Y, endX, endY) {
|
|
28865
|
-
this.path.push({
|
|
28866
|
-
action: "C",
|
|
28867
|
-
coords: [control1X, control1Y, control2X, control2Y, endX, endY]
|
|
28868
|
-
});
|
|
28869
|
-
return this;
|
|
28870
|
-
}
|
|
28871
|
-
|
|
28872
|
-
// Scale all coordinates of the path by a factor
|
|
28873
|
-
scale(factor) {
|
|
28874
|
-
this.scaleFactor *= factor;
|
|
28875
|
-
return this;
|
|
28876
|
-
}
|
|
28877
|
-
}
|
|
28878
|
-
function commandToString(command) {
|
|
28879
|
-
return `${command.action}${command.coords.join(" ")}`;
|
|
28880
|
-
}
|
|
28881
|
-
function scaleCommandBy(scaleFactor) {
|
|
28882
|
-
return command => _extends({}, command, {
|
|
28883
|
-
coords: command.coords.map(c => c * scaleFactor)
|
|
28884
|
-
});
|
|
28885
|
-
}
|
|
28886
|
-
|
|
28887
|
-
// We use the pathBuilder here to scale up the SVG path coordinates used
|
|
28888
|
-
// elsewhere for arrowheads. We scale in the path itself instead of using a CSS
|
|
28889
|
-
// transform because a transform would also scale up the stroke weight, and we
|
|
28890
|
-
// don't want that.
|
|
28891
|
-
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();
|
|
28892
|
-
function Arrowhead(props) {
|
|
28893
|
-
var _props$color;
|
|
28894
|
-
const [point] = useTransform([props.x, props.y]);
|
|
28895
|
-
return /*#__PURE__*/React.createElement("g", {
|
|
28896
|
-
transform: `translate(${point[0]} ${point[1]}) rotate(${-props.angle})`
|
|
28897
|
-
}, /*#__PURE__*/React.createElement("g", {
|
|
28898
|
-
transform: "translate(-1.5)"
|
|
28899
|
-
}, /*#__PURE__*/React.createElement("path", {
|
|
28900
|
-
d: arrowPath,
|
|
28901
|
-
fill: "none",
|
|
28902
|
-
style: {
|
|
28903
|
-
stroke: (_props$color = props.color) != null ? _props$color : "inherit"
|
|
28904
|
-
},
|
|
28905
|
-
strokeLinejoin: "round",
|
|
28906
|
-
strokeLinecap: "round"
|
|
28907
|
-
})));
|
|
28908
|
-
}
|
|
28909
|
-
|
|
28910
|
-
function Vector(props) {
|
|
28911
|
-
const {
|
|
28912
|
-
tail,
|
|
28913
|
-
tip,
|
|
28914
|
-
color
|
|
28915
|
-
} = props;
|
|
28916
|
-
const [tailPx, tipPx] = useTransform(tail, tip);
|
|
28917
|
-
const direction = vec.sub(tip, tail);
|
|
28918
|
-
return /*#__PURE__*/React.createElement("g", {
|
|
28919
|
-
style: {
|
|
28920
|
-
stroke: color,
|
|
28921
|
-
strokeWidth: 2
|
|
28922
|
-
}
|
|
28923
|
-
}, /*#__PURE__*/React.createElement(SVGLine, {
|
|
28924
|
-
start: tailPx,
|
|
28925
|
-
end: tipPx
|
|
28926
|
-
}), /*#__PURE__*/React.createElement(Arrowhead, {
|
|
28927
|
-
x: tip[0],
|
|
28928
|
-
y: tip[1],
|
|
28929
|
-
angle: angleDegrees(direction)
|
|
28930
|
-
}));
|
|
28931
|
-
}
|
|
28932
|
-
function angleDegrees([x, y]) {
|
|
28933
|
-
return Math.atan2(y, x) * 180 / Math.PI;
|
|
28934
|
-
}
|
|
28935
|
-
|
|
28936
29023
|
const defaultStroke = "var(--movable-line-stroke-color)";
|
|
28937
29024
|
const MovableLine = props => {
|
|
28938
29025
|
const {
|
|
@@ -28943,12 +29030,16 @@ const MovableLine = props => {
|
|
|
28943
29030
|
stroke = defaultStroke
|
|
28944
29031
|
} = props;
|
|
28945
29032
|
const midpoint = vec.midpoint(start, end);
|
|
28946
|
-
const [startPtPx, endPtPx] =
|
|
29033
|
+
const [startPtPx, endPtPx] = useTransformVectorsToPixels(start, end);
|
|
29034
|
+
const {
|
|
29035
|
+
graphDimensionsInPixels
|
|
29036
|
+
} = useGraphConfig();
|
|
28947
29037
|
let startExtend = undefined;
|
|
28948
29038
|
let endExtend = undefined;
|
|
28949
29039
|
if (extend) {
|
|
28950
|
-
|
|
28951
|
-
|
|
29040
|
+
const trimmedRange = trimRange(extend.range, graphDimensionsInPixels);
|
|
29041
|
+
startExtend = extend.start ? getIntersectionOfRayWithBox(start, end, trimmedRange) : undefined;
|
|
29042
|
+
endExtend = extend.end ? getIntersectionOfRayWithBox(end, start, trimmedRange) : undefined;
|
|
28952
29043
|
}
|
|
28953
29044
|
const line = useRef(null);
|
|
28954
29045
|
const {
|
|
@@ -29005,16 +29096,24 @@ const MovableLine = props => {
|
|
|
29005
29096
|
color: stroke
|
|
29006
29097
|
}));
|
|
29007
29098
|
};
|
|
29008
|
-
|
|
29009
|
-
const
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
const
|
|
29016
|
-
|
|
29017
|
-
|
|
29099
|
+
function trimRange(range, graphDimensionsInPixels) {
|
|
29100
|
+
const pixelsToTrim = 4;
|
|
29101
|
+
const [xRange, yRange] = range;
|
|
29102
|
+
const [pixelsWide, pixelsTall] = graphDimensionsInPixels;
|
|
29103
|
+
const graphUnitsPerPixelX = size(xRange) / pixelsWide;
|
|
29104
|
+
const graphUnitsPerPixelY = size(yRange) / pixelsTall;
|
|
29105
|
+
const graphUnitsToTrimX = pixelsToTrim * graphUnitsPerPixelX;
|
|
29106
|
+
const graphUnitsToTrimY = pixelsToTrim * graphUnitsPerPixelY;
|
|
29107
|
+
return [trim(xRange, graphUnitsToTrimX), trim(yRange, graphUnitsToTrimY)];
|
|
29108
|
+
}
|
|
29109
|
+
function trim(interval, amount) {
|
|
29110
|
+
if (size(interval) < amount * 2) {
|
|
29111
|
+
return [0, 0];
|
|
29112
|
+
}
|
|
29113
|
+
return [interval[0] + amount, interval[1] - amount];
|
|
29114
|
+
}
|
|
29115
|
+
function size(interval) {
|
|
29116
|
+
return interval[1] - interval[0];
|
|
29018
29117
|
}
|
|
29019
29118
|
|
|
29020
29119
|
// The hitbox size of 48px by 48px is preserved from the legacy interactive
|
|
@@ -29047,13 +29146,13 @@ const StyledMovablePoint = props => {
|
|
|
29047
29146
|
constrain: p => snap(snapStep, p)
|
|
29048
29147
|
});
|
|
29049
29148
|
const pointClasses = `movable-point ${dragging ? "movable-point--dragging" : ""}`;
|
|
29050
|
-
const [[x, y]] =
|
|
29149
|
+
const [[x, y]] = useTransformVectorsToPixels(point);
|
|
29051
29150
|
const [xMin, xMax] = range[0];
|
|
29052
29151
|
const [yMin, yMax] = range[1];
|
|
29053
|
-
const [[verticalStartX]] =
|
|
29054
|
-
const [[verticalEndX]] =
|
|
29055
|
-
const [[_, horizontalStartY]] =
|
|
29056
|
-
const [[__, horizontalEndY]] =
|
|
29152
|
+
const [[verticalStartX]] = useTransformVectorsToPixels([xMin, 0]);
|
|
29153
|
+
const [[verticalEndX]] = useTransformVectorsToPixels([xMax, 0]);
|
|
29154
|
+
const [[_, horizontalStartY]] = useTransformVectorsToPixels([0, yMin]);
|
|
29155
|
+
const [[__, horizontalEndY]] = useTransformVectorsToPixels([0, yMax]);
|
|
29057
29156
|
const showHairlines = dragging && markings !== "none";
|
|
29058
29157
|
const hairlines = /*#__PURE__*/React.createElement("g", null, /*#__PURE__*/React.createElement("line", {
|
|
29059
29158
|
x1: verticalStartX,
|
|
@@ -29375,7 +29474,7 @@ const isRightAngle = angle => Math.abs(angle - Math.PI / 2) < 0.01;
|
|
|
29375
29474
|
*/
|
|
29376
29475
|
const shouldDrawArcOutside = (midpoint, vertex, range, polygonLines) => {
|
|
29377
29476
|
// Create a ray from the midpoint (inside angle) to the edge of the range
|
|
29378
|
-
const rangeIntersectionPoint =
|
|
29477
|
+
const rangeIntersectionPoint = getIntersectionOfRayWithBox(vertex, midpoint, range);
|
|
29379
29478
|
let lineIntersectionCount = 0;
|
|
29380
29479
|
polygonLines.forEach(line => linesIntersect([vertex, rangeIntersectionPoint], line) && lineIntersectionCount++);
|
|
29381
29480
|
|
|
@@ -29498,23 +29597,19 @@ function AxisArrows() {
|
|
|
29498
29597
|
const axisColor = "var(--mafs-fg)";
|
|
29499
29598
|
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29500
29599
|
color: axisColor,
|
|
29501
|
-
|
|
29502
|
-
y: 0,
|
|
29600
|
+
tip: [xMin, 0],
|
|
29503
29601
|
angle: 180
|
|
29504
29602
|
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29505
29603
|
color: axisColor,
|
|
29506
|
-
|
|
29507
|
-
y: 0,
|
|
29604
|
+
tip: [xMax, 0],
|
|
29508
29605
|
angle: 0
|
|
29509
29606
|
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29510
29607
|
color: axisColor,
|
|
29511
|
-
|
|
29512
|
-
y: yMin,
|
|
29608
|
+
tip: [0, yMin],
|
|
29513
29609
|
angle: 270
|
|
29514
29610
|
}), /*#__PURE__*/React__default.createElement(Arrowhead, {
|
|
29515
29611
|
color: axisColor,
|
|
29516
|
-
|
|
29517
|
-
y: yMax,
|
|
29612
|
+
tip: [0, yMax],
|
|
29518
29613
|
angle: 90
|
|
29519
29614
|
}));
|
|
29520
29615
|
}
|
|
@@ -29539,7 +29634,7 @@ const YGridTick = ({
|
|
|
29539
29634
|
tickStep
|
|
29540
29635
|
}) => {
|
|
29541
29636
|
const pointOnAxis = [0, y];
|
|
29542
|
-
const [[xPosition, yPosition]] =
|
|
29637
|
+
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
29543
29638
|
return /*#__PURE__*/React.createElement("g", {
|
|
29544
29639
|
className: "y-axis-ticks"
|
|
29545
29640
|
}, /*#__PURE__*/React.createElement("line", {
|
|
@@ -29562,7 +29657,7 @@ const XGridTick = ({
|
|
|
29562
29657
|
tickStep
|
|
29563
29658
|
}) => {
|
|
29564
29659
|
const pointOnAxis = [x, 0];
|
|
29565
|
-
const [[xPosition, yPosition]] =
|
|
29660
|
+
const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
|
|
29566
29661
|
return /*#__PURE__*/React.createElement("g", {
|
|
29567
29662
|
className: "x-axis-ticks"
|
|
29568
29663
|
}, /*#__PURE__*/React.createElement("line", {
|
|
@@ -29783,97 +29878,26 @@ const styles$k = StyleSheet.create({
|
|
|
29783
29878
|
}
|
|
29784
29879
|
});
|
|
29785
29880
|
|
|
29786
|
-
const
|
|
29787
|
-
|
|
29788
|
-
|
|
29789
|
-
|
|
29790
|
-
}
|
|
29791
|
-
|
|
29792
|
-
|
|
29793
|
-
|
|
29794
|
-
|
|
29795
|
-
|
|
29796
|
-
|
|
29797
|
-
top: "0",
|
|
29798
|
-
width: "0"
|
|
29881
|
+
const InfoTip$1 = props => {
|
|
29882
|
+
return /*#__PURE__*/React.createElement(Tooltip$1, {
|
|
29883
|
+
content: /*#__PURE__*/React.createElement(Body, {
|
|
29884
|
+
style: styles$j.body
|
|
29885
|
+
}, props.children),
|
|
29886
|
+
placement: "right"
|
|
29887
|
+
}, /*#__PURE__*/React.createElement(PhosphorIcon, {
|
|
29888
|
+
size: "small",
|
|
29889
|
+
icon: questionIcon,
|
|
29890
|
+
style: styles$j.spacingLeft
|
|
29891
|
+
}));
|
|
29799
29892
|
};
|
|
29800
29893
|
const styles$j = StyleSheet.create({
|
|
29801
|
-
|
|
29802
|
-
|
|
29803
|
-
marginLeft: "5px",
|
|
29804
|
-
position: "relative"
|
|
29805
|
-
},
|
|
29806
|
-
infoTipContainer: {
|
|
29807
|
-
position: "absolute",
|
|
29808
|
-
top: "-12px",
|
|
29809
|
-
left: "22px",
|
|
29810
|
-
zIndex: 1000
|
|
29811
|
-
},
|
|
29812
|
-
infoTipTriangle: {
|
|
29813
|
-
height: "10px",
|
|
29814
|
-
left: "0",
|
|
29815
|
-
position: "absolute",
|
|
29816
|
-
top: "8px",
|
|
29817
|
-
width: "0",
|
|
29818
|
-
zIndex: 1,
|
|
29819
|
-
":before": _extends({}, triangleBeforeAfter, {
|
|
29820
|
-
borderRight: "9px solid #bbb",
|
|
29821
|
-
right: "0"
|
|
29822
|
-
}),
|
|
29823
|
-
":after": _extends({}, triangleBeforeAfter, {
|
|
29824
|
-
borderRight: `9px solid ${colors$1.white}`,
|
|
29825
|
-
right: "-1px"
|
|
29826
|
-
})
|
|
29827
|
-
},
|
|
29828
|
-
verticalShadow: {
|
|
29829
|
-
border: `1px solid ${colors$1.basicBorderColor}`,
|
|
29830
|
-
boxShadow: `0 1px 3px ${colors$1.basicBorderColor}`,
|
|
29831
|
-
borderBottom: `1px solid ${colors$1.grayLight}`
|
|
29894
|
+
spacingLeft: {
|
|
29895
|
+
marginInlineStart: spacing.xxxSmall_4
|
|
29832
29896
|
},
|
|
29833
|
-
|
|
29834
|
-
|
|
29835
|
-
padding: "5px 10px",
|
|
29836
|
-
width: "240px"
|
|
29897
|
+
body: {
|
|
29898
|
+
padding: spacing.medium_16
|
|
29837
29899
|
}
|
|
29838
29900
|
});
|
|
29839
|
-
class InfoTip$1 extends React.Component {
|
|
29840
|
-
constructor(...args) {
|
|
29841
|
-
super(...args);
|
|
29842
|
-
this.state = {
|
|
29843
|
-
hover: false
|
|
29844
|
-
};
|
|
29845
|
-
this.handleMouseEnter = () => {
|
|
29846
|
-
this.setState({
|
|
29847
|
-
hover: true
|
|
29848
|
-
});
|
|
29849
|
-
};
|
|
29850
|
-
this.handleMouseLeave = () => {
|
|
29851
|
-
this.setState({
|
|
29852
|
-
hover: false
|
|
29853
|
-
});
|
|
29854
|
-
};
|
|
29855
|
-
}
|
|
29856
|
-
render() {
|
|
29857
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
29858
|
-
className: css(styles$j.infoTip)
|
|
29859
|
-
}, /*#__PURE__*/React.createElement(View, {
|
|
29860
|
-
onMouseEnter: this.handleMouseEnter,
|
|
29861
|
-
onMouseLeave: this.handleMouseLeave
|
|
29862
|
-
}, /*#__PURE__*/React.createElement(PhosphorIcon, {
|
|
29863
|
-
size: "small",
|
|
29864
|
-
icon: questionIcon
|
|
29865
|
-
})), /*#__PURE__*/React.createElement("div", {
|
|
29866
|
-
className: css(styles$j.infoTipContainer),
|
|
29867
|
-
style: {
|
|
29868
|
-
display: this.state.hover ? "block" : "none"
|
|
29869
|
-
}
|
|
29870
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
29871
|
-
className: css(styles$j.infoTipTriangle)
|
|
29872
|
-
}), /*#__PURE__*/React.createElement("div", {
|
|
29873
|
-
className: css(styles$j.verticalShadow, styles$j.infoTipContentContainer)
|
|
29874
|
-
}, this.props.children)));
|
|
29875
|
-
}
|
|
29876
|
-
}
|
|
29877
29901
|
|
|
29878
29902
|
/**
|
|
29879
29903
|
* A wrapper around info-tip/info-tip.jsx that can be rendered on the
|
|
@@ -30713,9 +30737,7 @@ const getDefaultPoints = ({
|
|
|
30713
30737
|
// Instead of updating to v5, using generic type to relate input and output types.
|
|
30714
30738
|
function getGradableGraph(state, initialGraph) {
|
|
30715
30739
|
if (!state.hasBeenInteractedWith) {
|
|
30716
|
-
return {
|
|
30717
|
-
type: initialGraph.type
|
|
30718
|
-
};
|
|
30740
|
+
return _extends({}, initialGraph);
|
|
30719
30741
|
}
|
|
30720
30742
|
if (initialGraph.type === "linear-system" && state.type === "linear-system") {
|
|
30721
30743
|
return _extends({}, initialGraph, {
|
|
@@ -30874,7 +30896,8 @@ const StatefulMafsGraph = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
30874
30896
|
const MafsGraph = props => {
|
|
30875
30897
|
const {
|
|
30876
30898
|
state,
|
|
30877
|
-
dispatch
|
|
30899
|
+
dispatch,
|
|
30900
|
+
labels
|
|
30878
30901
|
} = props;
|
|
30879
30902
|
const [width, height] = props.box;
|
|
30880
30903
|
const prevState = useRef(state);
|
|
@@ -30903,7 +30926,11 @@ const MafsGraph = props => {
|
|
|
30903
30926
|
range: state.range,
|
|
30904
30927
|
snapStep: state.snapStep,
|
|
30905
30928
|
markings: props.markings,
|
|
30906
|
-
showTooltips: !!props.showTooltips
|
|
30929
|
+
showTooltips: !!props.showTooltips,
|
|
30930
|
+
graphDimensionsInPixels: props.box,
|
|
30931
|
+
width,
|
|
30932
|
+
height,
|
|
30933
|
+
labels
|
|
30907
30934
|
}
|
|
30908
30935
|
}, /*#__PURE__*/React.createElement(View, {
|
|
30909
30936
|
style: {
|
|
@@ -30922,7 +30949,7 @@ const MafsGraph = props => {
|
|
|
30922
30949
|
bottom: 0,
|
|
30923
30950
|
left: 0
|
|
30924
30951
|
}
|
|
30925
|
-
}, /*#__PURE__*/React.createElement(Mafs, {
|
|
30952
|
+
}, props.markings === "graph" && /*#__PURE__*/React.createElement(AxisLabels, null), /*#__PURE__*/React.createElement(Mafs, {
|
|
30926
30953
|
preserveAspectRatio: false,
|
|
30927
30954
|
viewBox: {
|
|
30928
30955
|
x: props.range[0],
|
|
@@ -30940,7 +30967,8 @@ const MafsGraph = props => {
|
|
|
30940
30967
|
containerSizeClass: props.containerSizeClass,
|
|
30941
30968
|
markings: props.markings
|
|
30942
30969
|
}), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
|
|
30943
|
-
lockedFigures: props.lockedFigures
|
|
30970
|
+
lockedFigures: props.lockedFigures,
|
|
30971
|
+
range: props.range
|
|
30944
30972
|
}), renderGraph({
|
|
30945
30973
|
state,
|
|
30946
30974
|
dispatch
|
|
@@ -32104,8 +32132,6 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
32104
32132
|
graph: graph
|
|
32105
32133
|
});
|
|
32106
32134
|
};
|
|
32107
|
-
this.getUserInput = () => InteractiveGraph.getUserInputFromProps(this.props);
|
|
32108
|
-
this.simpleValidate = rubric => InteractiveGraph.validate(this.getUserInput(), rubric, this);
|
|
32109
32135
|
this.focus = $.noop;
|
|
32110
32136
|
}
|
|
32111
32137
|
// TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
|
|
@@ -32157,6 +32183,12 @@ class LegacyInteractiveGraph extends React.Component {
|
|
|
32157
32183
|
areSegmentGraphsEqual(prevGraph, currentGraph) {
|
|
32158
32184
|
return prevGraph.numSegments !== currentGraph.numSegments;
|
|
32159
32185
|
}
|
|
32186
|
+
getUserInput() {
|
|
32187
|
+
return InteractiveGraph.getUserInputFromProps(this.props);
|
|
32188
|
+
}
|
|
32189
|
+
simpleValidate(rubric) {
|
|
32190
|
+
return InteractiveGraph.validate(this.getUserInput(), rubric, this);
|
|
32191
|
+
}
|
|
32160
32192
|
render() {
|
|
32161
32193
|
const box = getInteractiveBoxFromSizeClass(this.props.containerSizeClass);
|
|
32162
32194
|
const gridStep = this.props.gridStep || Util.getGridStep(this.props.range, this.props.step, box[0]);
|
|
@@ -32238,10 +32270,10 @@ class InteractiveGraph extends React.Component {
|
|
|
32238
32270
|
}
|
|
32239
32271
|
throw new PerseusError("Cannot getUserInput from a graph that has never rendered", Errors.NotAllowed);
|
|
32240
32272
|
};
|
|
32241
|
-
|
|
32242
|
-
|
|
32243
|
-
|
|
32244
|
-
|
|
32273
|
+
}
|
|
32274
|
+
simpleValidate(rubric) {
|
|
32275
|
+
var _this$getUserInput;
|
|
32276
|
+
return InteractiveGraph.validate((_this$getUserInput = this.getUserInput) == null ? void 0 : _this$getUserInput.call(this), rubric, this);
|
|
32245
32277
|
}
|
|
32246
32278
|
render() {
|
|
32247
32279
|
var _this$props$apiOption;
|
|
@@ -43037,7 +43069,7 @@ const init = function init(options) {
|
|
|
43037
43069
|
|
|
43038
43070
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
43039
43071
|
const libName = "@khanacademy/perseus";
|
|
43040
|
-
const libVersion = "22.0
|
|
43072
|
+
const libVersion = "22.2.0";
|
|
43041
43073
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
43042
43074
|
|
|
43043
43075
|
const apiVersion = {
|