Skip to content

Commit 718a12f

Browse files
committed
Template graph scaffolding
This is still in progress, but just laying out a few more things as I want to keep the ball rolling here. I have the expression inside the new template graph class - next step is just to render it in the jsxgraph view.
1 parent 583468d commit 718a12f

10 files changed

+686
-355
lines changed

media/js/src/GraphEditor.jsx

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import NonLinearDemandSupplyEditor from './editors/NonLinearDemandSupplyEditor.j
77
import ConsumptionLeisureEditor from './editors/ConsumptionLeisureEditor.jsx';
88
import ConsumptionSavingEditor from './editors/ConsumptionSavingEditor.jsx';
99
import DemandSupplyEditor from './editors/DemandSupplyEditor.jsx';
10+
import TemplateGraphEditor from './editors/TemplateGraphEditor.jsx';
1011
import CommonGraphEditor from './editors/CommonGraphEditor.jsx';
1112
import CommonGraphSettings from './editors/CommonGraphSettings.jsx';
1213
import JXGBoard from './JXGBoard.jsx';
@@ -245,6 +246,13 @@ export default class GraphEditor extends React.Component {
245246
{...commonEditorProps}
246247
{...this.props}
247248
/>;
249+
} else if (this.props.gType === 16) {
250+
// Template Graph: free-form equations
251+
rightSide =
252+
<TemplateGraphEditor
253+
{...commonEditorProps}
254+
{...this.props}
255+
/>;
248256
}
249257

250258
return (
@@ -380,6 +388,7 @@ GraphEditor.propTypes = {
380388
gNName: PropTypes.string,
381389

382390
gFunctionChoice: PropTypes.number,
391+
gExpression: PropTypes.string,
383392

384393
gAreaConfiguration: PropTypes.number,
385394
gIsAreaDisplayed: PropTypes.bool,

media/js/src/GraphMapping.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ const exportGraph = function(state) {
104104

105105
area_a_name: state.gAreaAName,
106106
area_b_name: state.gAreaBName,
107-
area_c_name: state.gAreaCName
107+
area_c_name: state.gAreaCName,
108+
109+
expression: state.gExpression
108110
};
109111

110112
if (state.gType === 3 || state.gType === 12) {
@@ -215,7 +217,9 @@ const convertGraph = function(json) {
215217

216218
gAreaAName: json.area_a_name,
217219
gAreaBName: json.area_b_name,
218-
gAreaCName: json.area_c_name
220+
gAreaCName: json.area_c_name,
221+
222+
gExpression: json.expression
219223
};
220224
};
221225

@@ -315,7 +319,10 @@ const importGraph = function(json, obj, callback=null) {
315319

316320
gAreaAName: json.area_a_name,
317321
gAreaBName: json.area_b_name,
318-
gAreaCName: json.area_c_name
322+
gAreaCName: json.area_c_name,
323+
324+
// TODO: enable this when expression back-end is in place.
325+
// gExpression: json.expression
319326
};
320327

321328
// When importing a graph for display, save the initial state of
@@ -572,6 +579,8 @@ const defaultGraph = {
572579
gAreaBName: 'B',
573580
gAreaCName: 'C',
574581

582+
gExpression: 'x',
583+
575584
// Use a hard-coded proof-of-concept assessment spreadsheet for
576585
// now. Eventually, this will be defined using a Google
577586
// Spreadsheet, or some react-spreadsheet component with its data
@@ -581,4 +590,8 @@ const defaultGraph = {
581590
assessment: []
582591
};
583592

584-
export { convertGraph, exportGraph, importGraph, defaultGraph, defaultEvaluation, defaultModificationEvaluation, defaultLabelEvaluation };
593+
export {
594+
convertGraph, exportGraph, importGraph, defaultGraph,
595+
defaultEvaluation, defaultModificationEvaluation,
596+
defaultLabelEvaluation
597+
};

media/js/src/GraphViewer.jsx

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ConsumptionLeisureEditor from './editors/ConsumptionLeisureEditor.jsx';
99
import ConsumptionSavingEditor from './editors/ConsumptionSavingEditor.jsx';
1010
import DemandSupplyEditor from './editors/DemandSupplyEditor.jsx';
1111
import NonLinearDemandSupplyEditor from './editors/NonLinearDemandSupplyEditor.jsx';
12+
import TemplateGraphEditor from './editors/TemplateGraphEditor.jsx';
1213
import ExportGraphButton from './buttons/ExportGraphButton.jsx';
1314
import ResetGraphButton from './buttons/ResetGraphButton.jsx';
1415
import SubmitButton from './buttons/SubmitButton.jsx';
@@ -187,6 +188,13 @@ export default class GraphViewer extends React.Component {
187188
{...commonViewerProps}
188189
{...this.props}
189190
/>;
191+
} else if (this.props.gType === 16) {
192+
// Template Graph: free-form equations
193+
rightSide =
194+
<TemplateGraphEditor
195+
{...commonViewerProps}
196+
{...this.props}
197+
/>;
190198
}
191199

192200
// Show side-by-side view here.
@@ -447,6 +455,7 @@ GraphViewer.propTypes = {
447455
gNName: PropTypes.string,
448456

449457
gFunctionChoice: PropTypes.number,
458+
gExpression: PropTypes.string,
450459

451460
assessment: PropTypes.array,
452461
submission: PropTypes.object,

media/js/src/JXGBoard.jsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,9 @@ export default class JXGBoard extends React.Component {
262262
'gCobbDouglasAlpha', 'gCobbDouglasAlphaInitial', 'gNName',
263263
'gFunctionChoice', 'gAreaConfiguration',
264264
'gAreaConfigurationInitial', 'gIsAreaDisplayed', 'gAreaAName',
265-
'gAreaBName', 'gAreaCName', 'gNeedsSubmit', 'submission',
265+
'gAreaBName', 'gAreaCName',
266+
'gExpression',
267+
'gNeedsSubmit', 'submission',
266268
'shadow'
267269
];
268270

@@ -704,6 +706,8 @@ JXGBoard.propTypes = {
704706
gAreaBName: PropTypes.string,
705707
gAreaCName: PropTypes.string,
706708

709+
gExpression: PropTypes.string,
710+
707711
id: PropTypes.string.isRequired,
708712
locked: PropTypes.bool
709713
};

media/js/src/Viewer.jsx

+4
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ class Viewer extends Component {
130130
gAreaBName={this.state.gAreaBName}
131131
gAreaCName={this.state.gAreaCName}
132132

133+
gExpression={this.state.gExpression}
134+
133135
updateDisplayIntersection={this.updateDisplayIntersection.bind(this)}
134136
updateGraph={this.handleGraphUpdate.bind(this)}
135137
saveGraph={this.handleSaveGraph.bind(this)}
@@ -268,6 +270,8 @@ class Viewer extends Component {
268270
gAreaBName={this.state.gAreaBName}
269271
gAreaCName={this.state.gAreaCName}
270272

273+
gExpression={this.state.gExpression}
274+
271275
assessment={this.state.assessment}
272276
submission={this.state.submission}
273277
updateGraph={this.handleGraphUpdate.bind(this)}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { MathComponent } from 'mathjax-react';
4+
5+
import EditableControl from '../form-components/EditableControl.js';
6+
import { handleFormUpdate } from '../utils.js';
7+
8+
export default class TemplateGraphEditor extends React.Component {
9+
render() {
10+
const func1 = String.raw`MP_N = (1 - \alpha)AK^\alpha N^{-\alpha}`;
11+
const func2 = String.raw`MP_K = \alpha AK^{\alpha - 1} N^{1 - \alpha}`;
12+
13+
return (
14+
<>
15+
<div className="d-flex flex-wrap">
16+
<div className="row">
17+
<div className="col">
18+
<label
19+
className="form-check-label me-2"
20+
htmlFor="gExpression">
21+
<MathComponent tex="y = " />
22+
</label>
23+
<EditableControl
24+
id="gExpression"
25+
name="Expression"
26+
value={this.props.gExpression}
27+
valueEditable={true}
28+
isInstructor={this.props.isInstructor}
29+
disabled={this.props.disabled}
30+
updateGraph={this.props.updateGraph} />
31+
</div>
32+
</div>
33+
</div>
34+
35+
<h3 className="mt-3">
36+
NLDS Function
37+
</h3>
38+
39+
<div className="row">
40+
<div className="form-check">
41+
<input
42+
className="form-check-input"
43+
aria-label={func1}
44+
type="radio"
45+
name="gFunctionChoice"
46+
id="gFunctionChoice1"
47+
onChange={handleFormUpdate.bind(this)}
48+
value={0}
49+
checked={this.props.gFunctionChoice === 0} />
50+
<label
51+
className="form-check-label"
52+
htmlFor="gFunctionChoice1">
53+
<MathComponent tex={func1} />
54+
</label>
55+
</div>
56+
</div>
57+
<div className="row">
58+
<div className="form-check">
59+
<input
60+
className="form-check-input"
61+
aria-label={func2}
62+
type="radio"
63+
name="gFunctionChoice"
64+
id="gFunctionChoice2"
65+
onChange={handleFormUpdate.bind(this)}
66+
value={1}
67+
checked={this.props.gFunctionChoice === 1} />
68+
<label
69+
className="form-check-label"
70+
htmlFor="gFunctionChoice2">
71+
<MathComponent tex={func2} />
72+
</label>
73+
</div>
74+
</div>
75+
</>
76+
);
77+
}
78+
}
79+
80+
TemplateGraphEditor.propTypes = {
81+
gType: PropTypes.number,
82+
updateGraph: PropTypes.func.isRequired,
83+
isInstructor: PropTypes.bool.isRequired,
84+
disabled: PropTypes.bool,
85+
86+
gExpression: PropTypes.string,
87+
gFunctionChoice: PropTypes.number
88+
};

media/js/src/form-components/EditableControl.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default class EditableControl extends React.Component {
2020
name={this.props.id}
2121
className="form-control"
2222
type="text"
23-
maxLength="60"
23+
maxLength={this.props.maxLength || 60}
2424
disabled={this.props.disabled}
2525
value={this.props.value}
2626
onChange={handleFormUpdate.bind(this)} />
@@ -37,5 +37,6 @@ EditableControl.propTypes = {
3737
isInstructor: PropTypes.bool.isRequired,
3838
value: PropTypes.string,
3939
valueEditable: PropTypes.bool.isRequired,
40-
disabled: PropTypes.bool
40+
disabled: PropTypes.bool,
41+
maxLength: PropTypes.number
4142
};

media/js/src/graphs/TemplateGraph.js

+28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
1+
import { create, all } from 'mathjs';
12
import {Graph} from './Graph.js';
23

4+
const math = create(all, {});
5+
36
export class TemplateGraph extends Graph {
47
make() {
8+
// TODO: parse and render this.options.gExpression
9+
console.log('expression is:', this.options.gExpression);
10+
11+
const me = this;
12+
const f = function(x) {
13+
const scope = {
14+
x: x
15+
};
16+
17+
console.log(
18+
math.evaluate(me.options.gExpression, scope));
19+
20+
return x;
21+
//return math.evaluate(me.options.gExpression, scope);
22+
};
23+
24+
this.board.create('functiongraph', [f], {
25+
name: 'expression',
26+
withLabel: true,
27+
strokeWidth: 2,
28+
strokeColor: this.options.gType === 12 ?
29+
this.l2Color : this.l1Color,
30+
recursionDepthLow: 8,
31+
recursionDepthHigh: 15
32+
});
533
}
634
}
735

0 commit comments

Comments
 (0)