5.5 HTML Questions - Maple T.A. 2016 Help
Maple T.A. Online Help

Select your version: Maple T.A. 2017 | Maple T.A. 2016 | Maple T.A. 10

5.5 HTML Questions


The HTML question is actually an extension of the Maple-graded question type, where the text or equation editor input area is replaced with an arbitrary HTML + Javascript application. You define a correct answer and grading code that use Maple syntax. The HTML and Javascript that you provide need to take a student’s input and return a representation of their answer to the grading code. In this way, the correct answer and randomization are hidden from the student and are not visible by simply inspecting the Javascript on the webpage.


To create an HTML question:

  1. From the Class Homepage, click Content Repository in the top menu.
  1. From the Create New drop-down menu, select Question/Text.
  1. This brings you to the Question Designer screen:

  • Enter a title for the question under the Question Name panel.
  • Enter the question in the Question Text.

  1. Click Response Area ().
  1. Under the menu option Choose Question Type, select HTML.
  1. (Optional) To add an Algorithm or Feedback to the question, see Adding and Editing Algorithms and Adding and Editing Information Fields, Hints, or Feedback.
  1. On the Edit Response Area screen,

  1. Weighting: specify the weight of this response area in the overall question. The default Weighting is set to 1.

  1. In the Answer field, you must enter the correct response to the question. Keep in mind the following details:
  • The last line of code must evaluate to an expression that is stored to the variable $ANSWER in the Grading Code, and the in the Javascript variable answer in the setFeedback() function.
  • Complete each line of code with a semicolon.
  • Add parentheses when appropriate, for example, (x + y) / 2.
  • Use the long form name for all package functions, for example, VectorCalculus[ArcLength].
  • Like a Maple-graded question, you must use valid Maple code to evaluate the answer.

  1. In the Grading Code region,
  • Like a Maple-graded question, you must use valid Maple code to evaluate the answer.
  • The last line of your question code must evaluate to a Boolean value (true or false) or a floating-point number between 0.0 and 1.0 for partial grading. By default, use the Maple command evalb(($ANSWER)-($RESPONSE)=0); as indicated, where $RESPONSE represents the student response and $ANSWER represents the correct answer.
  • Use the long form name for all package functions, for example, VectorCalculus[ArcLength].
  • Use $RESPONSE to represent the value of the student’s response in your code. Before your code is processed by Maple, $RESPONSE is replaced by the output of the Javascript getResponse() function.
  • Use $ANSWER to represent the correct answer, as you have provided in the previous field.

  1. In the Question HTML field, enter HTML needed to display the response area. The entire HTML response area will appear inside of an iframe, so other question text and HTML will not be directly accessible by the question’s Javascript.

  1. In the Question CSS field, enter any CSS need to display the response area. Because the response area will be displayed in an iframe, this CSS will not affect the rest of the question and vice versa.

  1. In the Question Javascript field, you must minimally fill out the stub functions: initialize(), setFeedback(), and getResponse().
  • initialize() is called whenever this response area is displayed, whether prompting the student for a response or showing the student’s response and the correct answer.
  • setFeedback(response, answer) is called when the student’s response and the correct answer are to be displayed next to each other. The variable response will receive the output of getResponse() and the variable answer will receive the value defined in the Answer field.
  • getResponse() is called whenever the question is graded. It should return the state of the response area such that is can be evaluated by the Grading Code.

  1. Click Save and then Preview to see the question.


  1. From the Class Homepage, click Content Repository in the top menu.
  1. From the Create New drop-down menu, select Question/Text.
  1. Enter the following title for the Question Name: Select the Red Ball
  1. Enter the following for the Question Text: Click to select the red ball from among the choices.
  1. At the bottom of the page, click the add icon () and enter the following Algorithm:

#Randomly choose a ball to be the correct answer $which=rint(20)+1; #Use a single Maple call to generate initial positions, speeds, masses and radii for the choices $maple=maple("randomize(): vx:=RandomTools:-Generate(list(float(range=-0.20..0.20),20)): vy:=RandomTools:-Generate(list(float(range=-0.20..0.20),20)): x:=RandomTools:-Generate(list(integer(range=1..499),20)): y:=RandomTools:-Generate(list(integer(range=1..299),20)): m:=RandomTools:-Generate(list(integer(range=10..50),20)): r:=RandomTools:-Generate(list(integer(range=10..20),20)): convert(vx,string),convert(vy,string),convert(x,string),convert(y,string),convert(m,string),convert(r,string);"); #The array of initial horizontal speeds $vx=switch(0,$maple); #The array of initial vertical speeds $vy=switch(1,$maple); #The array of initial horizontal positions $x=switch(2,$maple); #The array of initial vertical positions $y=switch(3,$maple); #The array of masses $m=switch(4,$maple); #The array of radii $r=switch(5,$maple);

  1. Under Question Text, click the Response Area () icon.
  1. Select HTML.
  1. Set the Answer to $which
  1. Set the Question HTML to the following:

<div id="canvasContainer"> <canvas id="collisionsCanvas" width="500" height="300"></canvas> </div>

  1. Set the Question CSS to the following:

#canvasContainer{ width: 500px; height: 300px; }

  1. In the Question Javascript field, do the following:
  1. Add the following global variables above the initialize function:

var theBalls; var context; var correct = false; var feedbackMode = false;

  1. Add the following functions in the Additional functions section at the bottom:

function newBall(options){ var thisBall = {}; thisBall.pos = options.pos || {x:0, y:0}; thisBall.v = options.v || {x:0, y:0}; thisBall.m = options.m || 50; thisBall.r = options.r || 10; thisBall.color = options.color || "#000000"; thisBall.selectColor = options.selectColor || "#000000"; thisBall.context = options.thecontext; thisBall.lasttime = options.lasttime || 0; thisBall.selected = options.selected || false; thisBall.draw = options.draw || function(){ thisBall.context.beginPath(); thisBall.context.arc(thisBall.pos.x, thisBall.pos.y, thisBall.r, 0, 2 * Math.PI); thisBall.context.fillStyle = thisBall.color; thisBall.context.fill(); if (thisBall.selected){ thisBall.context.beginPath(); thisBall.context.arc(thisBall.pos.x, thisBall.pos.y, thisBall.r + 10, 0, 2 * Math.PI); thisBall.context.strokeStyle = thisBall.selectColor; thisBall.context.stroke(); } }; thisBall.update = options.update || function(newTime){ thisBall.pos.x = thisBall.pos.x + thisBall.v.x*(newTime-thisBall.lasttime); thisBall.pos.y = thisBall.pos.y + thisBall.v.y*(newTime-thisBall.lasttime); if (((thisBall.pos.x + thisBall.r >= window.innerWidth-10) && (thisBall.v.x >0)) || ((thisBall.pos.x - thisBall.r <= 0) && (thisBall.v.x <0))){ thisBall.v.x = (-1)*thisBall.v.x; thisBall.pos.x = thisBall.pos.x + thisBall.v.x*(newTime-thisBall.lasttime); } if (((thisBall.pos.y + thisBall.r >= window.innerHeight-10) && (thisBall.v.y >0)) || ((thisBall.pos.y - thisBall.r <= 0) && (thisBall.v.y <0))){ thisBall.v.y = (-1)*thisBall.v.y; thisBall.pos.y = thisBall.pos.y + thisBall.v.y*(newTime-thisBall.lasttime); } }; return thisBall; } function vecDiff(v1,v2){ var temp = {x: v1.x-v2.x ,y: v1.y-v2.y}; return temp; } function dotProd(v1,v2){ var temp = v1.x*v2.x + v1.y*v2.y; return temp ; } function vecMag(v1){ var temp = Math.sqrt(Math.pow(v1.x,2)+Math.pow(v1.y,2)); return temp; } function scalMult(a,v1){ var temp = {x: a*v1.x ,y: a*v1.y}; return temp; } function checkForCollisions(theBalls,newTime){ for(var i=0; i<theBalls.length; i++){ for(var j=0; j<i; j++){ if (Math.sqrt(Math.pow(theBalls[i].pos.x - theBalls[j].pos.x,2)+Math.pow(theBalls[i].pos.y - theBalls[j].pos.y,2)) <= (theBalls[i].r + theBalls[j].r)){ temp1 = vecDiff(theBalls[i].v,scalMult((2*theBalls[j].m/(theBalls[i].m+theBalls[j].m))*(dotProd(vecDiff(theBalls[i].v,theBalls[j].v),vecDiff(theBalls[i].pos,theBalls[j].pos))/Math.pow(vecMag(vecDiff(theBalls[i].pos,theBalls[j].pos)),2)),vecDiff(theBalls[i].pos,theBalls[j].pos))); temp2 = vecDiff(theBalls[j].v,scalMult((2*theBalls[i].m/(theBalls[i].m+theBalls[j].m))*(dotProd(vecDiff(theBalls[j].v,theBalls[i].v),vecDiff(theBalls[j].pos,theBalls[i].pos))/Math.pow(vecMag(vecDiff(theBalls[j].pos,theBalls[i].pos)),2)),vecDiff(theBalls[j].pos,theBalls[i].pos))); theBalls[i].v = temp1; theBalls[j].v = temp2; theBalls[i].pos.x = theBalls[i].pos.x + 1*theBalls[i].v.x*(newTime-theBalls[i].lasttime); theBalls[i].pos.y = theBalls[i].pos.y + 1*theBalls[i].v.y*(newTime-theBalls[i].lasttime); theBalls[j].pos.x = theBalls[j].pos.x + 1*theBalls[j].v.x*(newTime-theBalls[j].lasttime); theBalls[j].pos.y = theBalls[j].pos.y + 1*theBalls[j].v.y*(newTime-theBalls[j].lasttime); } } } } function newBallSystem() { var thisBS = []; thisBS.addBall = function (newBall) { thisBS[thisBS.length] = newBall; thisBS[thisBS.length - 1].id = thisBS.length - 1; }; return thisBS; } function animate(context, theBalls) { var time = (new Date()).getTime(); context.canvas.width = window.innerWidth; context.canvas.height = window.innerHeight; context.clearRect(0, 0, context.canvas.width, context.canvas.height); for(var i=0; i<theBalls.length; i++){ theBalls[i].update(time); } time = (new Date()).getTime(); checkForCollisions(theBalls,time); for(i=0; i<theBalls.length; i++){ theBalls[i].draw(); theBalls[i].lasttime = time; } requestAnimFrame(function () { animate(context, theBalls); }); } function handleClick(pos,context,theBalls){ var selected = null; for(var i=0; i<theBalls.length; i++){ theBalls[i].selected = false; if (Math.sqrt(Math.pow(theBalls[i].pos.x - pos.x,2)+Math.pow(theBalls[i].pos.y - pos.y,2)) <= (theBalls[i].r+10)){ selected = i; } } if (selected !== null){ theBalls[selected].selected = true; } }

  1. Replace the placeholder initialize function with:

function initialize(interactiveMode){ if (!interactiveMode){ feedbackMode = true; } window.requestAnimFrame = (function (callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 120); }; })(); jQuery(document).ready(function(){ var canvas = document.getElementById("collisionsCanvas"); context = canvas.getContext("2d"); var startTime = (new Date()).getTime(); theBalls = newBallSystem(); var initX = $x; var initY = $y; var initVX = $vx; var initVY = $vy; var initM = $m; var initR = $r; for (var i=0; i < 20; i++){ theBalls.addBall(newBall({pos: {x:initX[i],y:initY[i]},v: {x:initVX[i],y:initVY[i]}, m: initM[i], r: initR[i], thecontext: context,lasttime: startTime,color:"rgb(50,50,200)"})); } theBalls[$which].color="rgb(200,50,50)"; animate(context,theBalls); context.canvas.addEventListener('click',function(e){ var x; var y; if (e.pageX || e.pageY) { x = e.pageX; y = e.pageY; } else { x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } x -= context.canvas.offsetLeft; y -= context.canvas.offsetTop; if (interactiveMode){ handleClick({x: x, y: y},context,theBalls); } }); }); };

  1. Replace the placeholder setFeedback function with:

function setFeedback(response, answer){ if (response > 0 && response < theBalls.length){ theBalls[response].selected = true; } if (answer > 0 && answer < theBalls.length){ theBalls[answer].selected = true; theBalls[answer].selectColor = "#00FF00"; if (answer != response){ theBalls[response].selectColor = "#FF0000"; } } };

  1. Replace the placeholder getResponse function with:

function getResponse(){ for(var i=0; i<theBalls.length; i++){ if(theBalls[i].selected){ return i; } } return -1; };

  1. Click OK.
  1. Click Save to save the question.
  1. Click Preview to test the question. You can click on any of the balls to select your response, then click Grade or How did I do? to check your response.

Next Steps

To edit further details in the Content Repository, see Editing Question Details.