Can you show storyline quiz score as a percentage?
Oct 03, 2023
We've build a game show quiz with Articulate Storyline with 3 stages, 5 question in each stage with a total of 15 questions. For every correct answer, the user gets 100 point and the aim of the course is to get as much of a high score as possible. We are having issue reporting the course/quiz on the LMS we are using. We tried to run a report on our LMS to report on percentage using the field 'SCORM 2004 Quiz Data - Quiz score' but its not showing the correct percentage score. For example, one result was 1400 points (14/15) so the percentage score should show 93% but its shows 33%. Below is a screenshot showing this:
All the relevant quiz setting have been selected to score on, we have a 'submit score' trigger on the final slide when the timeline starts. Is there anything we are missing that is causing the score to show incorrectly.
2 Replies
Hi Nathan,
Happy to help!
Can I ask if you've tested the behavior on a different LMS to see if the scoring issue is specific to your LMS? If you haven't yet, here's a helpful article on testing courses in SCORM Cloud.
If you are able to replicate the scoring issue in SCORM Cloud, would you be willing to share a copy of your project file here or in private by opening a support case so we can take a closer look at what's happening? We'll delete it when we're done testing!
You can do this using JavaScript and xAPI statements and queries.
I'll show you the code I use.
function sendAnswered(object, objectId, responseVar, success) {
const player = GetPlayer();
const uNamejs = player.GetVar("uName");
const uEmailjs = player.GetVar("uEmail");
const userResponse = player.GetVar(responseVar);
const uScorejs = player.GetVar("uScore");
const maxScorejs = player.GetVar("maxScore");
const scaledScore = uScorejs / maxScorejs;
let finalDuration = convertToIso(slideSeconds);
const statement = {
"actor": {
"name": uNamejs,
"mbox": "mailto:" + uEmailjs
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/answered",
"display": {"en-us": "answered"}
},
"object": {
"id": objectId,
"definition": {
"name": {"en-us": object},
"description": {"en-us": "Question in the Quiz"},
"type": "http://adlnet.gov/expapi/activities/question"
},
"objectType": "Activity"
},
"result": {
"duration": finalDuration,
"response": userResponse,
"score": {
"min": 0,
"max": maxScorejs,
"raw": uScorejs,
"scaled": scaledScore
},
"success": success
}
}
const result = ADL.XAPIWrapper.sendStatement(statement);
}
// Function to send passed result and user score to the LRS (Learning Record Store)
function sendPassed(object, objectId) {
// Get references to Storyline variables
const player = GetPlayer();
const uNamejs = player.GetVar("uName");
const uEmailjs = player.GetVar("uEmail");
const uScorejs = player.GetVar("uScore");
const maxScorejs = player.GetVar("maxScore");
const scaledScore = uScorejs / maxScorejs;
let finalDuration = convertToIso(courseSeconds);
const statement = {
"actor": {
"name": uNamejs,
"mbox": "mailto:" + uEmailjs
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/passed",
"display": {"en-us": "passed"}
},
"object": {
"id": objectId,
"definition": {
"name": {"en-us": object},
"description": {"en-us": "NGTS Network Overview"},
"type": "http://adlnet.gov/expapi/activities/assessment"
},
"objectType": "Activity"
},
"result": {
"duration": finalDuration,
"score": {
"min": 0,
"max": maxScorejs,
"raw": uScorejs,
"scaled": scaledScore
},
"success": true
}
};
// Converts the time to ISO standard readable in JavaScriptfunction convertToIso(secondsVar) {
let seconds = secondsVar;
if (seconds > 60) {
if (seconds > 3600) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
seconds = (seconds % 3600) % 60;
return `PT${hours}H${minutes}M${seconds}S`;
} else {
const minutes = Math.floor(seconds / 60);
seconds %= 60;
return `PT${minutes}M${seconds}S`;
}
} else {
return `PT${seconds}S`;
}
}
Then you would want some placeholders within your storyline file for the usernames and scores.
firsUser and firstScore
These are pretty typically used placeholders after Devlin Peck published how to develop a leaderboard using xAPI. So, I'll use his example in this reference so you can follow along with his instructions if you get stuck.
I have added to the code to include debugging to help you find any errors when viewing the console log (F12 when you are viewing the exported html).
function populateLeaderboard() {
// Create parameters for querying xAPI statements
const parameters = ADL.XAPIWrapper.searchParams();
parameters["verb"] = "http://adlnet.gov/expapi/verbs/passed";
parameters["activity"] = "http://example.com/NGTSNetworkOverview";
const queryData = ADL.XAPIWrapper.getStatements(parameters);
const statements = queryData.statements;
statements.sort(function(a, b) {
return b.result.score.scaled - a.result.score.scaled;
});
const player = GetPlayer();
player.SetVar("firstUser", statements[0].actor.name);
player.SetVar("secondUser", statements[1].actor.name);
player.SetVar("thirdUser", statements[2].actor.name);
player.SetVar("fourthUser", statements[3].actor.name);
player.SetVar("fifthUser", statements[4].actor.name);
console.log("Scaled Scores:", statements.map((stmt) => stmt.result.score.scaled));
console.log("User Scores (Percentages):", statements.map((stmt) => stmt.result.score.scaled * 100 + "%"));
player.SetVar("firstScore", statements[0].result.score.scaled * 100 + "%");
player.SetVar("secondScore", statements[1].result.score.scaled * 100 + "%");
player.SetVar("thirdScore", statements[2].result.score.scaled * 100 + "%");
player.SetVar("fourthScore", statements[3].result.score.scaled * 100 + "%");
player.SetVar("fifthScore", statements[4].result.score.scaled * 100 + "%");
}
Please let me know if this helped you or not. Happy to chat about it via LinkedIn when you have time.
Scott