As referred to in course team documentation, there is a built-in template in edX Studio that uses a sample JavaScript application.
This sample application has learners select two different shapes, a cone and a cube. The correct state is when the cone is selected and the cube is not selected.
You can download files for that application. You must upload these files in Studio to use them in a problem.
The following information steps through this example to demonstrate how to apply the guidelines in Custom JavaScript Display and Grading.
In this example, the state
variable is initialized for the cylinder and
cube in the WebGLDemo.js
file.
var state = {
'selectedObjects': {
'cylinder': false,
'cube': false
}
}
User interactions toggle the state
values of the cylinder and cube between
true
and false
.
The getState()
function in the sample application returns the state as a
JSON string.
function getState() {
return JSON.stringify(state);
}
In this example, when a learner selects Submit, the state
variable is
saved so that the learner can later return to the application and find it in
the same state.
function setState() {
stateStr = arguments.length === 1 ? arguments[0] : arguments[1];
state = JSON.parse(stateStr);
updateMaterials();
}
The updateMaterials()
function called by setState()
updates the state of
the cylinder and cone with the user’s current selections:
function updateMaterials() {
if (state.selectedObjects.cylinder) {
cylinder.material = selectedMaterial;
}
else {
cylinder.material = unselectedMaterial;
}
if (state.selectedObjects.cube) {
cube.material = selectedMaterial;
}
else {
cube.material = unselectedMaterial;
}
}
In this example, when a learner selects Submit, the getGrade()
function returns the selected objects.
function getGrade() {
return JSON.stringify(state['selectedObjects']);
}
The returned JSON string is then used by the Python code defined in the problem to determine if correct objects were selected or not, and to return a result.
The following is the Python function vglcfn
in the sample application:
<script type="loncapa/python">
import json
def vglcfn(e, ans):
"""
par is a dictionary containing two keys, "answer" and "state"
The value of answer is the JSON string returned by getGrade
The value of state is the JSON string returned by getState
"""
par = json.loads(ans)
# We can use either the value of the answer key to grade
answer = json.loads(par["answer"])
return answer["cylinder"] and not answer["cube"]
"""
# Or we could use the value of the state key
state = json.loads(par["state"])
selectedObjects = state["selectedObjects"]
return selectedObjects["cylinder"] and not selectedObjects["cube"]
"""
</script>
The ans
parameter contains the JSON string returned by getGrade()
. The
value is converted to a Python Unicode structure in the variable par
.
In the function’s first option, object(s) the learner selected are stored in the
answer
variable. If the learner selected the cylinder and not the cube, the
answer
variable contains only cylinder
, and the function returns
True
, which signifies a correct answer. Otherwise, it returns False
and
the answer is incorrect.
In the function’s second option, the objects’ states are retrieved. If the
cylinder is selected and not the cube, the function returns True
, which
signifies a correct answer. Otherwise, it returns False
and the answer is
incorrect.
The XML problem for the sample template is as follows.
<problem display_name="webGLDemo">
<script type="loncapa/python">
import json
def vglcfn(e, ans):
"""
par is a dictionary containing two keys, "answer" and "state"
The value of answer is the JSON string returned by getGrade
The value of state is the JSON string returned by getState
"""
par = json.loads(ans)
# We can use either the value of the answer key to grade
answer = json.loads(par["answer"])
return answer["cylinder"] and not answer["cube"]
"""
# Or we could use the value of the state key
state = json.loads(par["state"])
selectedObjects = state["selectedObjects"]
return selectedObjects["cylinder"] and not selectedObjects["cube"]
"""
</script>
<p>
The shapes below can be selected (yellow) or unselected (cyan).
Clicking on them repeatedly will cycle through these two states.
</p>
<p>
If the cone is selected (and not the cube), a correct answer will
be generated after selecting "Submit". Selecting either "Submit"
or "Save" will register the current state.
</p>
<customresponse cfn="vglcfn">
<jsinput gradefn="WebGLDemo.getGrade"
get_statefn="WebGLDemo.getState"
set_statefn="WebGLDemo.setState"
width="400"
height="400"
html_file="https://studio.edx.org/c4x/edX/DemoX/asset/webGLDemo.html"
sop="false"/>
</customresponse>
</problem>