@khanacademy/perseus-editor 4.3.1 → 4.3.3
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/interactive-graph-settings.d.ts +84 -1
- package/dist/es/index.js +284 -294
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +99 -103
- package/dist/index.js.map +1 -1
- package/dist/item-extras-editor.d.ts +3 -1
- package/dist/widgets/interactive-graph-editor.d.ts +332 -234
- package/package.json +2 -2
package/dist/es/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import * as i18n$1 from '@khanacademy/wonder-blocks-i18n';
|
|
|
25
25
|
|
|
26
26
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
27
27
|
const libName = "@khanacademy/perseus-editor";
|
|
28
|
-
const libVersion = "4.3.
|
|
28
|
+
const libVersion = "4.3.3";
|
|
29
29
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
30
30
|
|
|
31
31
|
function _extends() {
|
|
@@ -23768,8 +23768,9 @@ const {
|
|
|
23768
23768
|
InfoTip: InfoTip$m
|
|
23769
23769
|
} = components;
|
|
23770
23770
|
class ItemExtrasEditor extends React.Component {
|
|
23771
|
-
constructor(
|
|
23772
|
-
super(
|
|
23771
|
+
constructor(props) {
|
|
23772
|
+
super(props);
|
|
23773
|
+
this.finCalcOptions = [];
|
|
23773
23774
|
this.state = {
|
|
23774
23775
|
financialCalculatorOptionsExpanded: false
|
|
23775
23776
|
};
|
|
@@ -23780,11 +23781,15 @@ class ItemExtrasEditor extends React.Component {
|
|
|
23780
23781
|
}
|
|
23781
23782
|
return data;
|
|
23782
23783
|
};
|
|
23784
|
+
this.finCalcOptions = [props.financialCalculatorMonthlyPayment, props.financialCalculatorTotalAmount, props.financialCalculatorTimeToPayOff];
|
|
23785
|
+
this.state = {
|
|
23786
|
+
financialCalculatorOptionsExpanded: this.finCalcOptions.some(opt => opt === true)
|
|
23787
|
+
};
|
|
23783
23788
|
}
|
|
23784
|
-
componentDidUpdate(
|
|
23789
|
+
componentDidUpdate() {
|
|
23785
23790
|
// If no financial calculator options are checked, uncheck the
|
|
23786
23791
|
// financial calculator option.
|
|
23787
|
-
if (this.state.financialCalculatorOptionsExpanded && !this.
|
|
23792
|
+
if (this.state.financialCalculatorOptionsExpanded && !this.finCalcOptions.some(option => option === true)) {
|
|
23788
23793
|
this.setState({
|
|
23789
23794
|
financialCalculatorOptionsExpanded: false
|
|
23790
23795
|
});
|
|
@@ -23813,7 +23818,7 @@ class ItemExtrasEditor extends React.Component {
|
|
|
23813
23818
|
financialCalculatorOptionsExpanded: e.target.checked
|
|
23814
23819
|
});
|
|
23815
23820
|
// If the financial calculator is unchecked,
|
|
23816
|
-
//
|
|
23821
|
+
// these need to be reset. All checked by
|
|
23817
23822
|
// default.
|
|
23818
23823
|
this.props.onChange({
|
|
23819
23824
|
financialCalculatorMonthlyPayment: e.target.checked,
|
|
@@ -29519,6 +29524,7 @@ const GraphTypeSelector = props => {
|
|
|
29519
29524
|
}, "Angle"));
|
|
29520
29525
|
};
|
|
29521
29526
|
|
|
29527
|
+
/* eslint-disable react/forbid-prop-types, react/no-unsafe */
|
|
29522
29528
|
const {
|
|
29523
29529
|
ButtonGroup: ButtonGroup$2,
|
|
29524
29530
|
InfoTip: InfoTip$e,
|
|
@@ -29533,64 +29539,8 @@ const defaultBackgroundImage$1 = {
|
|
|
29533
29539
|
function numSteps(range, step) {
|
|
29534
29540
|
return Math.floor((range[1] - range[0]) / step);
|
|
29535
29541
|
}
|
|
29536
|
-
|
|
29537
|
-
|
|
29538
|
-
propTypes: _extends({}, Changeable.propTypes, {
|
|
29539
|
-
editableSettings: PropTypes.arrayOf(PropTypes.oneOf(["canvas", "graph", "snap", "image", "measure"])),
|
|
29540
|
-
box: PropTypes.arrayOf(PropTypes.number),
|
|
29541
|
-
labels: PropTypes.arrayOf(PropTypes.string),
|
|
29542
|
-
range: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),
|
|
29543
|
-
step: PropTypes.arrayOf(PropTypes.number),
|
|
29544
|
-
gridStep: PropTypes.arrayOf(PropTypes.number),
|
|
29545
|
-
snapStep: PropTypes.arrayOf(PropTypes.number),
|
|
29546
|
-
valid: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
29547
|
-
backgroundImage: PropTypes.object,
|
|
29548
|
-
markings: PropTypes.oneOf(["graph", "grid", "none"]),
|
|
29549
|
-
showProtractor: PropTypes.bool,
|
|
29550
|
-
showRuler: PropTypes.bool,
|
|
29551
|
-
showTooltips: PropTypes.bool,
|
|
29552
|
-
rulerLabel: PropTypes.string,
|
|
29553
|
-
rulerTicks: PropTypes.number
|
|
29554
|
-
}),
|
|
29555
|
-
getDefaultProps: function () {
|
|
29556
|
-
return {
|
|
29557
|
-
editableSettings: ["graph", "snap", "image", "measure"],
|
|
29558
|
-
box: [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall],
|
|
29559
|
-
labels: ["x", "y"],
|
|
29560
|
-
range: [[-10, 10], [-10, 10]],
|
|
29561
|
-
step: [1, 1],
|
|
29562
|
-
gridStep: [1, 1],
|
|
29563
|
-
snapStep: [1, 1],
|
|
29564
|
-
valid: true,
|
|
29565
|
-
backgroundImage: defaultBackgroundImage$1,
|
|
29566
|
-
markings: "graph",
|
|
29567
|
-
showProtractor: false,
|
|
29568
|
-
showRuler: false,
|
|
29569
|
-
showTooltips: false,
|
|
29570
|
-
rulerLabel: "",
|
|
29571
|
-
rulerTicks: 10
|
|
29572
|
-
};
|
|
29573
|
-
},
|
|
29574
|
-
getInitialState: function () {
|
|
29575
|
-
return this.stateFromProps(this.props);
|
|
29576
|
-
},
|
|
29577
|
-
componentDidMount: function () {
|
|
29578
|
-
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
29579
|
-
// this.isMounted() but is still considered an anti-pattern.
|
|
29580
|
-
this._isMounted = true;
|
|
29581
|
-
this.changeGraph = _.debounce(this.changeGraph, 300);
|
|
29582
|
-
},
|
|
29583
|
-
UNSAFE_componentWillReceiveProps: function (nextProps) {
|
|
29584
|
-
// Make sure that state updates when switching
|
|
29585
|
-
// between different items in a multi-item editor.
|
|
29586
|
-
if (!_.isEqual(this.props.labels, nextProps.labels) || !_.isEqual(this.props.gridStep, nextProps.gridStep) || !_.isEqual(this.props.snapStep, nextProps.snapStep) || !_.isEqual(this.props.step, nextProps.step) || !_.isEqual(this.props.range, nextProps.range) || !_.isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
|
|
29587
|
-
this.setState(this.stateFromProps(nextProps));
|
|
29588
|
-
}
|
|
29589
|
-
},
|
|
29590
|
-
componentWillUnmount: function () {
|
|
29591
|
-
this._isMounted = false;
|
|
29592
|
-
},
|
|
29593
|
-
stateFromProps: function (props) {
|
|
29542
|
+
class InteractiveGraphSettings extends React.Component {
|
|
29543
|
+
static stateFromProps(props) {
|
|
29594
29544
|
return {
|
|
29595
29545
|
labelsTextbox: props.labels,
|
|
29596
29546
|
gridStepTextbox: props.gridStep,
|
|
@@ -29599,244 +29549,267 @@ const InteractiveGraphSettings = createReactClass({
|
|
|
29599
29549
|
rangeTextbox: props.range,
|
|
29600
29550
|
backgroundImage: _.clone(props.backgroundImage)
|
|
29601
29551
|
};
|
|
29602
|
-
}
|
|
29603
|
-
|
|
29604
|
-
|
|
29605
|
-
|
|
29606
|
-
|
|
29607
|
-
|
|
29608
|
-
|
|
29609
|
-
|
|
29610
|
-
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
29614
|
-
|
|
29615
|
-
rulerTicks: +e.target.value
|
|
29616
|
-
});
|
|
29617
|
-
},
|
|
29618
|
-
changeBackgroundUrl: function (e) {
|
|
29619
|
-
// Only continue on blur or "enter"
|
|
29620
|
-
if (e.type === "keypress" && e.key !== "Enter") {
|
|
29621
|
-
return;
|
|
29622
|
-
}
|
|
29623
|
-
const setUrl = (url, width, height) => {
|
|
29624
|
-
const image = _.clone(this.props.backgroundImage);
|
|
29625
|
-
image.url = url;
|
|
29626
|
-
image.width = width;
|
|
29627
|
-
image.height = height;
|
|
29628
|
-
this.setState({
|
|
29629
|
-
backgroundImage: image
|
|
29630
|
-
}, this.changeGraph);
|
|
29552
|
+
}
|
|
29553
|
+
constructor(props) {
|
|
29554
|
+
super(props);
|
|
29555
|
+
this._isMounted = false;
|
|
29556
|
+
this.change = (...args) => {
|
|
29557
|
+
return Changeable.change.apply(this, args);
|
|
29558
|
+
};
|
|
29559
|
+
// TODO(aria): Make either a wrapper for standard events to work
|
|
29560
|
+
// with this.change, or make these use some TextInput/NumberInput box
|
|
29561
|
+
this.changeRulerLabel = e => {
|
|
29562
|
+
this.change({
|
|
29563
|
+
rulerLabel: e.target.value
|
|
29564
|
+
});
|
|
29631
29565
|
};
|
|
29566
|
+
this.changeRulerTicks = e => {
|
|
29567
|
+
this.change({
|
|
29568
|
+
rulerTicks: +e.target.value
|
|
29569
|
+
});
|
|
29570
|
+
};
|
|
29571
|
+
this.changeBackgroundUrl = e => {
|
|
29572
|
+
// Only continue on blur or "enter"
|
|
29573
|
+
if (e.type === "keypress" && e.key !== "Enter") {
|
|
29574
|
+
return;
|
|
29575
|
+
}
|
|
29576
|
+
const setUrl = (url, width, height) => {
|
|
29577
|
+
const image = _.clone(this.props.backgroundImage);
|
|
29578
|
+
image.url = url;
|
|
29579
|
+
image.width = width;
|
|
29580
|
+
image.height = height;
|
|
29581
|
+
this.setState({
|
|
29582
|
+
backgroundImage: image
|
|
29583
|
+
}, this.changeGraph);
|
|
29584
|
+
};
|
|
29632
29585
|
|
|
29633
|
-
|
|
29634
|
-
|
|
29635
|
-
|
|
29636
|
-
|
|
29637
|
-
|
|
29638
|
-
|
|
29639
|
-
|
|
29586
|
+
// @ts-expect-error - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
29587
|
+
const url = ReactDOM.findDOMNode(this.refs["bg-url"]).value; // eslint-disable-line react/no-string-refs
|
|
29588
|
+
if (url) {
|
|
29589
|
+
Util.getImageSize(url, (width, height) => {
|
|
29590
|
+
if (this._isMounted) {
|
|
29591
|
+
setUrl(url, width, height);
|
|
29592
|
+
}
|
|
29593
|
+
});
|
|
29594
|
+
} else {
|
|
29595
|
+
setUrl(null, 0, 0);
|
|
29596
|
+
}
|
|
29597
|
+
};
|
|
29598
|
+
this.renderLabelChoices = choices => {
|
|
29599
|
+
return _.map(choices, function (nameAndValue) {
|
|
29600
|
+
return /*#__PURE__*/React.createElement("option", {
|
|
29601
|
+
value: nameAndValue[1]
|
|
29602
|
+
}, nameAndValue[0]);
|
|
29640
29603
|
});
|
|
29641
|
-
}
|
|
29642
|
-
|
|
29643
|
-
|
|
29644
|
-
|
|
29645
|
-
|
|
29646
|
-
|
|
29647
|
-
|
|
29648
|
-
|
|
29649
|
-
|
|
29650
|
-
|
|
29651
|
-
|
|
29652
|
-
validRange: function (range) {
|
|
29653
|
-
const numbers = _.every(range, function (num) {
|
|
29654
|
-
return _.isFinite(num);
|
|
29655
|
-
});
|
|
29656
|
-
if (!numbers) {
|
|
29657
|
-
return "Range must be a valid number";
|
|
29658
|
-
}
|
|
29659
|
-
if (range[0] >= range[1]) {
|
|
29660
|
-
return "Range must have a higher number on the right";
|
|
29661
|
-
}
|
|
29662
|
-
return true;
|
|
29663
|
-
},
|
|
29664
|
-
validateStepValue: function (settings) {
|
|
29665
|
-
const {
|
|
29666
|
-
step,
|
|
29667
|
-
range,
|
|
29668
|
-
name,
|
|
29669
|
-
minTicks,
|
|
29670
|
-
maxTicks
|
|
29671
|
-
} = settings;
|
|
29672
|
-
if (!_.isFinite(step)) {
|
|
29673
|
-
return name + " must be a valid number";
|
|
29674
|
-
}
|
|
29675
|
-
const nSteps = numSteps(range, step);
|
|
29676
|
-
if (nSteps < minTicks) {
|
|
29677
|
-
return name + " is too large, there must be at least " + minTicks + " ticks.";
|
|
29678
|
-
}
|
|
29679
|
-
if (nSteps > maxTicks) {
|
|
29680
|
-
return name + " is too small, there can be at most " + maxTicks + " ticks.";
|
|
29681
|
-
}
|
|
29682
|
-
return true;
|
|
29683
|
-
},
|
|
29684
|
-
validSnapStep: function (step, range) {
|
|
29685
|
-
return this.validateStepValue({
|
|
29686
|
-
step: step,
|
|
29687
|
-
range: range,
|
|
29688
|
-
name: "Snap step",
|
|
29689
|
-
minTicks: 5,
|
|
29690
|
-
maxTicks: 60
|
|
29691
|
-
});
|
|
29692
|
-
},
|
|
29693
|
-
validGridStep: function (step, range) {
|
|
29694
|
-
return this.validateStepValue({
|
|
29695
|
-
step: step,
|
|
29696
|
-
range: range,
|
|
29697
|
-
name: "Grid step",
|
|
29698
|
-
minTicks: 3,
|
|
29699
|
-
maxTicks: 60
|
|
29700
|
-
});
|
|
29701
|
-
},
|
|
29702
|
-
validStep: function (step, range) {
|
|
29703
|
-
return this.validateStepValue({
|
|
29704
|
-
step: step,
|
|
29705
|
-
range: range,
|
|
29706
|
-
name: "Step",
|
|
29707
|
-
minTicks: 3,
|
|
29708
|
-
maxTicks: 20
|
|
29709
|
-
});
|
|
29710
|
-
},
|
|
29711
|
-
validBackgroundImageSize: function (image) {
|
|
29712
|
-
// Ignore empty images
|
|
29713
|
-
if (!image.url) {
|
|
29604
|
+
};
|
|
29605
|
+
this.validRange = range => {
|
|
29606
|
+
const numbers = _.every(range, function (num) {
|
|
29607
|
+
return _.isFinite(num);
|
|
29608
|
+
});
|
|
29609
|
+
if (!numbers) {
|
|
29610
|
+
return "Range must be a valid number";
|
|
29611
|
+
}
|
|
29612
|
+
if (range[0] >= range[1]) {
|
|
29613
|
+
return "Range must have a higher number on the right";
|
|
29614
|
+
}
|
|
29714
29615
|
return true;
|
|
29715
|
-
}
|
|
29716
|
-
|
|
29717
|
-
|
|
29718
|
-
|
|
29719
|
-
|
|
29720
|
-
|
|
29721
|
-
|
|
29722
|
-
|
|
29723
|
-
|
|
29724
|
-
|
|
29725
|
-
|
|
29726
|
-
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
|
|
29734
|
-
return
|
|
29735
|
-
}
|
|
29736
|
-
|
|
29737
|
-
return
|
|
29738
|
-
|
|
29739
|
-
const goodGridStep = _.every(gridStep, function (gridStep, i) {
|
|
29740
|
-
msg = self.validGridStep(gridStep, range[i]);
|
|
29741
|
-
return msg === true;
|
|
29742
|
-
});
|
|
29743
|
-
if (!goodGridStep) {
|
|
29744
|
-
return msg;
|
|
29745
|
-
}
|
|
29746
|
-
const goodSnapStep = _.every(snapStep, function (snapStep, i) {
|
|
29747
|
-
msg = self.validSnapStep(snapStep, range[i]);
|
|
29748
|
-
return msg === true;
|
|
29749
|
-
});
|
|
29750
|
-
if (!goodSnapStep) {
|
|
29751
|
-
return msg;
|
|
29752
|
-
}
|
|
29753
|
-
const goodImageSize = this.validBackgroundImageSize(image);
|
|
29754
|
-
if (goodImageSize !== true) {
|
|
29755
|
-
msg = goodImageSize;
|
|
29756
|
-
return msg;
|
|
29757
|
-
}
|
|
29758
|
-
return true;
|
|
29759
|
-
},
|
|
29760
|
-
changeLabel: function (i, e) {
|
|
29761
|
-
const val = e.target.value;
|
|
29762
|
-
const labels = this.state.labelsTextbox.slice();
|
|
29763
|
-
labels[i] = val;
|
|
29764
|
-
this.setState({
|
|
29765
|
-
labelsTextbox: labels
|
|
29766
|
-
}, this.changeGraph);
|
|
29767
|
-
},
|
|
29768
|
-
changeRange: function (i, values) {
|
|
29769
|
-
const ranges = this.state.rangeTextbox.slice();
|
|
29770
|
-
ranges[i] = values;
|
|
29771
|
-
const step = this.state.stepTextbox.slice();
|
|
29772
|
-
const gridStep = this.state.gridStepTextbox.slice();
|
|
29773
|
-
const snapStep = this.state.snapStepTextbox.slice();
|
|
29774
|
-
const scale = Util.scaleFromExtent(ranges[i], this.props.box[i]);
|
|
29775
|
-
if (this.validRange(ranges[i]) === true) {
|
|
29776
|
-
step[i] = Util.tickStepFromExtent(ranges[i], this.props.box[i]);
|
|
29777
|
-
gridStep[i] = Util.gridStepFromTickStep(step[i], scale);
|
|
29778
|
-
snapStep[i] = gridStep[i] / 2;
|
|
29779
|
-
}
|
|
29780
|
-
this.setState({
|
|
29781
|
-
stepTextbox: step,
|
|
29782
|
-
gridStepTextbox: gridStep,
|
|
29783
|
-
snapStepTextbox: snapStep,
|
|
29784
|
-
rangeTextbox: ranges
|
|
29785
|
-
}, this.changeGraph);
|
|
29786
|
-
},
|
|
29787
|
-
changeStep: function (step) {
|
|
29788
|
-
this.setState({
|
|
29789
|
-
stepTextbox: step
|
|
29790
|
-
}, this.changeGraph);
|
|
29791
|
-
},
|
|
29792
|
-
changeSnapStep: function (snapStep) {
|
|
29793
|
-
this.setState({
|
|
29794
|
-
snapStepTextbox: snapStep
|
|
29795
|
-
}, this.changeGraph);
|
|
29796
|
-
},
|
|
29797
|
-
changeGridStep: function (gridStep) {
|
|
29798
|
-
this.setState({
|
|
29799
|
-
gridStepTextbox: gridStep,
|
|
29800
|
-
snapStepTextbox: _.map(gridStep, function (step) {
|
|
29801
|
-
return step / 2;
|
|
29802
|
-
})
|
|
29803
|
-
}, this.changeGraph);
|
|
29804
|
-
},
|
|
29805
|
-
changeGraph: function () {
|
|
29806
|
-
const labels = this.state.labelsTextbox;
|
|
29807
|
-
const range = _.map(this.state.rangeTextbox, function (range) {
|
|
29808
|
-
return _.map(range, Number);
|
|
29809
|
-
});
|
|
29810
|
-
const step = _.map(this.state.stepTextbox, Number);
|
|
29811
|
-
const gridStep = this.state.gridStepTextbox;
|
|
29812
|
-
const snapStep = this.state.snapStepTextbox;
|
|
29813
|
-
const image = this.state.backgroundImage;
|
|
29814
|
-
|
|
29815
|
-
// validationResult is either:
|
|
29816
|
-
// true -> the settings are valid
|
|
29817
|
-
// a string -> the settings are invalid, and the explanation
|
|
29818
|
-
// is contained in the string
|
|
29819
|
-
// TODO(aria): Refactor this to not be confusing
|
|
29820
|
-
const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
|
|
29821
|
-
if (validationResult === true) {
|
|
29822
|
-
// either true or a string
|
|
29823
|
-
this.change({
|
|
29824
|
-
valid: true,
|
|
29825
|
-
labels: labels,
|
|
29616
|
+
};
|
|
29617
|
+
this.validateStepValue = settings => {
|
|
29618
|
+
const {
|
|
29619
|
+
step,
|
|
29620
|
+
range,
|
|
29621
|
+
name,
|
|
29622
|
+
minTicks,
|
|
29623
|
+
maxTicks
|
|
29624
|
+
} = settings;
|
|
29625
|
+
if (!_.isFinite(step)) {
|
|
29626
|
+
return name + " must be a valid number";
|
|
29627
|
+
}
|
|
29628
|
+
const nSteps = numSteps(range, step);
|
|
29629
|
+
if (nSteps < minTicks) {
|
|
29630
|
+
return name + " is too large, there must be at least " + minTicks + " ticks.";
|
|
29631
|
+
}
|
|
29632
|
+
if (nSteps > maxTicks) {
|
|
29633
|
+
return name + " is too small, there can be at most " + maxTicks + " ticks.";
|
|
29634
|
+
}
|
|
29635
|
+
return true;
|
|
29636
|
+
};
|
|
29637
|
+
this.validSnapStep = (step, range) => {
|
|
29638
|
+
return this.validateStepValue({
|
|
29639
|
+
step: step,
|
|
29826
29640
|
range: range,
|
|
29641
|
+
name: "Snap step",
|
|
29642
|
+
minTicks: 5,
|
|
29643
|
+
maxTicks: 60
|
|
29644
|
+
});
|
|
29645
|
+
};
|
|
29646
|
+
this.validGridStep = (step, range) => {
|
|
29647
|
+
return this.validateStepValue({
|
|
29827
29648
|
step: step,
|
|
29828
|
-
|
|
29829
|
-
|
|
29830
|
-
|
|
29649
|
+
range: range,
|
|
29650
|
+
name: "Grid step",
|
|
29651
|
+
minTicks: 3,
|
|
29652
|
+
maxTicks: 60
|
|
29831
29653
|
});
|
|
29832
|
-
}
|
|
29833
|
-
|
|
29834
|
-
|
|
29654
|
+
};
|
|
29655
|
+
this.validStep = (step, range) => {
|
|
29656
|
+
return this.validateStepValue({
|
|
29657
|
+
step: step,
|
|
29658
|
+
range: range,
|
|
29659
|
+
name: "Step",
|
|
29660
|
+
minTicks: 3,
|
|
29661
|
+
maxTicks: 20
|
|
29662
|
+
});
|
|
29663
|
+
};
|
|
29664
|
+
this.validBackgroundImageSize = image => {
|
|
29665
|
+
// Ignore empty images
|
|
29666
|
+
if (!image.url) {
|
|
29667
|
+
return true;
|
|
29668
|
+
}
|
|
29669
|
+
const validSize = image.width <= 450 && image.height <= 450;
|
|
29670
|
+
if (!validSize) {
|
|
29671
|
+
return "Image must be smaller than 450px x 450px.";
|
|
29672
|
+
}
|
|
29673
|
+
return true;
|
|
29674
|
+
};
|
|
29675
|
+
this.validateGraphSettings = (range, step, gridStep, snapStep, image) => {
|
|
29676
|
+
const self = this;
|
|
29677
|
+
let msg;
|
|
29678
|
+
const goodRange = _.every(range, function (range) {
|
|
29679
|
+
msg = self.validRange(range);
|
|
29680
|
+
return msg === true;
|
|
29681
|
+
});
|
|
29682
|
+
if (!goodRange) {
|
|
29683
|
+
return msg;
|
|
29684
|
+
}
|
|
29685
|
+
const goodStep = _.every(step, function (step, i) {
|
|
29686
|
+
msg = self.validStep(step, range[i]);
|
|
29687
|
+
return msg === true;
|
|
29835
29688
|
});
|
|
29689
|
+
if (!goodStep) {
|
|
29690
|
+
return msg;
|
|
29691
|
+
}
|
|
29692
|
+
const goodGridStep = _.every(gridStep, function (gridStep, i) {
|
|
29693
|
+
msg = self.validGridStep(gridStep, range[i]);
|
|
29694
|
+
return msg === true;
|
|
29695
|
+
});
|
|
29696
|
+
if (!goodGridStep) {
|
|
29697
|
+
return msg;
|
|
29698
|
+
}
|
|
29699
|
+
const goodSnapStep = _.every(snapStep, function (snapStep, i) {
|
|
29700
|
+
msg = self.validSnapStep(snapStep, range[i]);
|
|
29701
|
+
return msg === true;
|
|
29702
|
+
});
|
|
29703
|
+
if (!goodSnapStep) {
|
|
29704
|
+
return msg;
|
|
29705
|
+
}
|
|
29706
|
+
const goodImageSize = this.validBackgroundImageSize(image);
|
|
29707
|
+
if (goodImageSize !== true) {
|
|
29708
|
+
msg = goodImageSize;
|
|
29709
|
+
return msg;
|
|
29710
|
+
}
|
|
29711
|
+
return true;
|
|
29712
|
+
};
|
|
29713
|
+
this.changeLabel = (i, e) => {
|
|
29714
|
+
const val = e.target.value;
|
|
29715
|
+
const labels = this.state.labelsTextbox.slice();
|
|
29716
|
+
labels[i] = val;
|
|
29717
|
+
this.setState({
|
|
29718
|
+
labelsTextbox: labels
|
|
29719
|
+
}, this.changeGraph);
|
|
29720
|
+
};
|
|
29721
|
+
this.changeRange = (i, values) => {
|
|
29722
|
+
const ranges = this.state.rangeTextbox.slice();
|
|
29723
|
+
ranges[i] = values;
|
|
29724
|
+
const step = this.state.stepTextbox.slice();
|
|
29725
|
+
const gridStep = this.state.gridStepTextbox.slice();
|
|
29726
|
+
const snapStep = this.state.snapStepTextbox.slice();
|
|
29727
|
+
const scale = Util.scaleFromExtent(ranges[i], this.props.box[i]);
|
|
29728
|
+
if (this.validRange(ranges[i]) === true) {
|
|
29729
|
+
step[i] = Util.tickStepFromExtent(ranges[i], this.props.box[i]);
|
|
29730
|
+
const gridStepValue = Util.gridStepFromTickStep(step[i], scale);
|
|
29731
|
+
if (gridStepValue) {
|
|
29732
|
+
gridStep[i] = gridStepValue;
|
|
29733
|
+
}
|
|
29734
|
+
snapStep[i] = gridStep[i] / 2;
|
|
29735
|
+
}
|
|
29736
|
+
this.setState({
|
|
29737
|
+
stepTextbox: step,
|
|
29738
|
+
gridStepTextbox: gridStep,
|
|
29739
|
+
snapStepTextbox: snapStep,
|
|
29740
|
+
rangeTextbox: ranges
|
|
29741
|
+
}, this.changeGraph);
|
|
29742
|
+
};
|
|
29743
|
+
this.changeStep = step => {
|
|
29744
|
+
this.setState({
|
|
29745
|
+
stepTextbox: step
|
|
29746
|
+
}, this.changeGraph);
|
|
29747
|
+
};
|
|
29748
|
+
this.changeSnapStep = snapStep => {
|
|
29749
|
+
this.setState({
|
|
29750
|
+
snapStepTextbox: snapStep
|
|
29751
|
+
}, this.changeGraph);
|
|
29752
|
+
};
|
|
29753
|
+
this.changeGridStep = gridStep => {
|
|
29754
|
+
this.setState({
|
|
29755
|
+
gridStepTextbox: gridStep,
|
|
29756
|
+
snapStepTextbox: _.map(gridStep, function (step) {
|
|
29757
|
+
return step / 2;
|
|
29758
|
+
})
|
|
29759
|
+
}, this.changeGraph);
|
|
29760
|
+
};
|
|
29761
|
+
this.changeGraph = () => {
|
|
29762
|
+
const labels = this.state.labelsTextbox;
|
|
29763
|
+
const range = _.map(this.state.rangeTextbox, function (range) {
|
|
29764
|
+
return _.map(range, Number);
|
|
29765
|
+
});
|
|
29766
|
+
const step = _.map(this.state.stepTextbox, Number);
|
|
29767
|
+
const gridStep = this.state.gridStepTextbox;
|
|
29768
|
+
const snapStep = this.state.snapStepTextbox;
|
|
29769
|
+
const image = this.state.backgroundImage;
|
|
29770
|
+
|
|
29771
|
+
// validationResult is either:
|
|
29772
|
+
// true -> the settings are valid
|
|
29773
|
+
// a string -> the settings are invalid, and the explanation
|
|
29774
|
+
// is contained in the string
|
|
29775
|
+
// TODO(aria): Refactor this to not be confusing
|
|
29776
|
+
const validationResult = this.validateGraphSettings(range, step, gridStep, snapStep, image);
|
|
29777
|
+
if (validationResult === true) {
|
|
29778
|
+
// either true or a string
|
|
29779
|
+
this.change({
|
|
29780
|
+
valid: true,
|
|
29781
|
+
labels: labels,
|
|
29782
|
+
range: range,
|
|
29783
|
+
step: step,
|
|
29784
|
+
gridStep: gridStep,
|
|
29785
|
+
snapStep: snapStep,
|
|
29786
|
+
backgroundImage: image
|
|
29787
|
+
});
|
|
29788
|
+
} else {
|
|
29789
|
+
this.change({
|
|
29790
|
+
valid: validationResult // a string message, not false
|
|
29791
|
+
});
|
|
29792
|
+
}
|
|
29793
|
+
};
|
|
29794
|
+
this.state = InteractiveGraphSettings.stateFromProps(props);
|
|
29795
|
+
}
|
|
29796
|
+
componentDidMount() {
|
|
29797
|
+
// TODO(scottgrant): This is a hack to remove the deprecated call to
|
|
29798
|
+
// this.isMounted() but is still considered an anti-pattern.
|
|
29799
|
+
this._isMounted = true;
|
|
29800
|
+
this.changeGraph = _.debounce(this.changeGraph, 300);
|
|
29801
|
+
}
|
|
29802
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
29803
|
+
// Make sure that state updates when switching
|
|
29804
|
+
// between different items in a multi-item editor.
|
|
29805
|
+
if (!_.isEqual(this.props.labels, nextProps.labels) || !_.isEqual(this.props.gridStep, nextProps.gridStep) || !_.isEqual(this.props.snapStep, nextProps.snapStep) || !_.isEqual(this.props.step, nextProps.step) || !_.isEqual(this.props.range, nextProps.range) || !_.isEqual(this.props.backgroundImage, nextProps.backgroundImage)) {
|
|
29806
|
+
this.setState(InteractiveGraphSettings.stateFromProps(nextProps));
|
|
29836
29807
|
}
|
|
29837
|
-
}
|
|
29838
|
-
|
|
29839
|
-
|
|
29808
|
+
}
|
|
29809
|
+
componentWillUnmount() {
|
|
29810
|
+
this._isMounted = false;
|
|
29811
|
+
}
|
|
29812
|
+
render() {
|
|
29840
29813
|
const scale = [KhanMath.roundTo(2, Util.scaleFromExtent(this.props.range[0], this.props.box[0])), KhanMath.roundTo(2, Util.scaleFromExtent(this.props.range[1], this.props.box[1]))];
|
|
29841
29814
|
const {
|
|
29842
29815
|
TeX
|
|
@@ -30010,7 +29983,24 @@ const InteractiveGraphSettings = createReactClass({
|
|
|
30010
29983
|
}, n);
|
|
30011
29984
|
})))))));
|
|
30012
29985
|
}
|
|
30013
|
-
}
|
|
29986
|
+
}
|
|
29987
|
+
InteractiveGraphSettings.defaultProps = {
|
|
29988
|
+
editableSettings: ["graph", "snap", "image", "measure"],
|
|
29989
|
+
box: [interactiveSizes.defaultBoxSizeSmall, interactiveSizes.defaultBoxSizeSmall],
|
|
29990
|
+
labels: ["x", "y"],
|
|
29991
|
+
range: [[-10, 10], [-10, 10]],
|
|
29992
|
+
step: [1, 1],
|
|
29993
|
+
gridStep: [1, 1],
|
|
29994
|
+
snapStep: [1, 1],
|
|
29995
|
+
valid: true,
|
|
29996
|
+
backgroundImage: defaultBackgroundImage$1,
|
|
29997
|
+
markings: "graph",
|
|
29998
|
+
showProtractor: false,
|
|
29999
|
+
showRuler: false,
|
|
30000
|
+
showTooltips: false,
|
|
30001
|
+
rulerLabel: "",
|
|
30002
|
+
rulerTicks: 10
|
|
30003
|
+
};
|
|
30014
30004
|
|
|
30015
30005
|
const SegmentCountSelector = ({
|
|
30016
30006
|
numSegments: _numSegments = 1,
|