You-draw-it lets you configure a quiz with questions. This quiz supports answers for a single value, sequence of values and multiple choice. The user can specify the numeric answers (single number or sequence of values, e.g. time series) by drawing interactively.
- This you-draw-it implementation is adapted from the great work at https://github.com/wdr-data/you-draw-it
- Original idea developed by the New York Times
- The visualization and interaction features were implemented using the amazing library d3.js
- fun facts
- datasketches
- minecraft
- minecraft - custom font
- newspaper article in rtbf in French
- example with reference values
- example with individually styled reference values
- example with multiple choice questions
The easiest way to start off is to create an html file with the following content:
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>My quiz</title>
<meta name="viewport" content="width=device-width,user-scalable=yes,initial-scale=1,minimum-scale=1">
<link rel="stylesheet" href="https://ee2dev.github.io/ydi/css/style.css">
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://ee2dev.github.io/ydi/js/youdrawit.min.js"></script>
<script>
var questions = [];
var question = {};
var globals = {
default: "en"
};
// ----- for additional questions, copy FROM here
question = {
heading: "Question 1",
data: [
{2015: 1503451},
{2016: -1491897},
{2017: 1495333},
{2018: 1453203},
{2019: 1458438},
{2020: 1442801}
]
};
questions.push(question);
// ----- for additional questions, copy TO here
// ----- for additional questions, copy FROM here
question = {
heading: "Question 2",
data: 17.1,
};
questions.push(question);
// ----- for additional questions, copy TO here
var myChart = youdrawit
.chart()
.globals(globals)
.questions(questions);
d3.select("body")
.append("div")
.attr("class", "chart")
.call(myChart);
</script>
</body>
</html>
All you need to do is
- download the zipped repository by clicking on the green button at the top part of the repository page and select
- unzip the downloaded repository
- navigate to the dist directory
- open one of the three templates in a browser (e.g. templateEnglish.html) to see it running locally
- make a copy of the template and adjust/add/remove the questions and answers in a text editor
In the javascript portion three variables are defined:
questions
which is an array ofquestion
objects.question
which is an object containing all infos about that questionglobals
which is an object containing global settings, mainly text or html strings, which are displayed during the course of the quiz.
All you need to do is
- to adjust the two properties of each
question
heading
refering to a string with one particular quiz question. This string can contain text or html (in case want to format your question in a certain way).data
refering to the value or values of the correct answer.- In case a single value is the answer (which is represented by a bar chart),
data
has to be initialized with the correct number. - In case a sequence of values is the answer (which is represented by a line chart),
data
has to be initialized by an array of objects. Each object is a point in the sequence and has to be initialized by a key (which will be the x coordinate) and its value (which will be the y coordinate) - In case multiple choice (of text) is the answer,
data
has to be initialized by an array of objects. Each object is a possible answer and has to be initialized by a key (which will be the possible answer) and a boolean value (which indicates if the answer is correct)
- In case a single value is the answer (which is represented by a bar chart),
- to add more
question
's you can simply copy the block commented with ...copy FROM here
until ...copy TO here
, adjust the properties and you are ready to go!
For specific adjustments take a look at tips & tricks and the API reference.
-
number of digits It is recommended using at most 4 digits for any value. The value is displayed with all thousands as well as the decimal separator. The number of displayed digits after the decimal spearator can be specified with
question.precision
-
text vs html The following options can be set with either text or html:
-
final score You can add a text or html after the final score is shown. In addition you can show a different text or html based on the final score. See
globals.scoreHtml
for details. -
using a different font See section Using a different font
-
template You can use this template which lists all
globals
andquestion
options.
Click here to the see the visual reference to the configuration options.
# globals.default
Sets the several undefined properties of globals
to default values. If a property is already defined, it is not overridden.
Three values are currently supported:
- globals.default = "en".
Initialization with English defaults. In addition, the thousands separator is set to
,
(comma) and the decimal separator to.
(dot). The English default is also applied if no default is specified.
// globals.default = "en" applies the following initialization:
var globals = {
default: "en",
resultButtonText: "Show me the result!",
resultButtonTooltip: "Draw your guess. Upon clicking here, you see if you're right.",
scoreTitle: "Your result:",
scoreButtonText: "Show me how good I am!",
scoreButtonTooltip: "Click here to see your result",
drawAreaTitle: "Your\nguess",
drawLine: "draw the graph\nfrom here to the end",
drawBar: "drag the bar\nto the estimated height",
};
- globals.default = "de".
Initialization with German defaults. In addition, the thousands separator is set to
.
(dot) and the decimal separator to,
(comma).
// globals.default = "de" applies the following initialization:
var globals = {
default: "de",
resultButtonText: "Zeig mir die Lösung!",
resultButtonTooltip: "Zeichnen Sie Ihre Einschätzung. Der Klick verrät, ob sie stimmt.",
scoreTitle: "Ihr Ergebnis:",
scoreButtonText: "Zeig mir, wie gut ich war!",
scoreButtonTooltip: "Klicken Sie hier, um Ihr Gesamtergebnis zu sehen"",
drawAreaTitle: "Ihre\nEinschätzung",
drawLine: "Zeichnen Sie von hier\nden Verlauf zu Ende",
drawBar: "Ziehen Sie den Balken\nauf die entsprechende Höhe",
};
- globals.default = "fr".
Initialization with French defaults. In addition, the thousands separator is set to
,
(comma). Shout-out to Ambroise Carton for the translation!
// globals.default = "fr" applies the following initialization:
var globals = {
default: "fr",
resultButtonText: "Montrez-moi le résultat",
resultButtonTooltip: "A vous de dessiner la courbe. Pour voir la bonne réponse, cliquez ici",
scoreTitle: "Votre résultat:",
scoreButtonText: "Montrez-moi la bonne réponse",
scoreButtonTooltip: "Cliquez ici pour obtenir des explications",
drawAreaTitle: "Votre supposition",
drawLine: "Placez votre doigt ou votre souris ici et dessinez la courbe",
drawBar: "Montez la barre jusqu’à la hauteur supposée",
};
# globals.header
Sets the text or html containing the header (= first line of the quiz).
# globals.subHeader
Sets the text or html containing the subHeader (= second line of the quiz).
# globals.drawAreaTitle
Sets the text denoting the area to be drawn by the user.
# globals.drawLine
Sets the text denoting the call to action for the user to continue drawing the line chart.
# globals.drawBar
Sets the text denoting the call to action for the user to adjusting the bar chart.
# globals.resultButtonText
Sets the text denoting the button to reveal the correct answer.
# globals.resultButtonTooltip
Sets the text denoting the tooltip of the button to reveal the correct answer.
# globals.showScore
Determines if the score evaluation should be displayed or not. Default is true.
# globals.scoreButtonText
Sets the text denoting the button to reveal the total score.
# globals.scoreButtonTooltip
Sets the text denoting the tooltip of the button to reveal the total score.
# globals.scoreTitle
Sets the text denoting the the headline on top of the score evaluation.
# globals.scoreHtml
There are two ways to specify that property:
- specify a text or html for any score:
var globals = {
...
scoreHtml: "Next time you can do better!",
};
Sets the text or html shown after the total score is revealed.
- specify a text or html depending on the score:
var globals = {
...
scoreHtml: [{lower: 0, upper: 50, html: "<b>That wasn't much, was it??</b>"},
{lower: 50, upper: 101, html: "<b>Excellent!!</b>"}],
};
Sets the text or html based on the score. In this case, globals.scoreHtml
is an array
of objects
. The array contains as many objects as there are intervalls. Each object
defines the intervall with its lower and upper bound. It also contains an html property for the text or html to be displayed in this case.
# question.data
Sets the value/ values which is/are the correct response for the question.
- In case a single value is the answer (which is re presented by a bar chart),
data
has to be initialized with the correct number. - In case a sequence of values is the answer (which is represented by a line chart),
data
has to be initialized by an array of objects. Each object is a point in the sequence and has to be initialized by a key (which will be the x coordinate) and its value (which will be the y coordinate) - In case multiple choice (of text) is the answer,
data
has to be initialized by an array of objects. Each object is a possible answer and has to be initialized by a key (which will be the possible answer) and a boolean value (which indicates if the answer is correct)
Note that the decimal separator has to denoted by a .
(dot). The display, however, can be modified with globals.default
(.
(dot) vs ,
(comma))
// examples for setting question.data
question = {
...
// data for single value looks like this:
data: 385, // or
data: 2.545, // or
// data for a sequence of values looks like this:
data: [
{"1998 (JP)": 32000},
{"2002 (US)": 22000},
{"2006 (IT)": 18000},
{"2010 (CA)": 18500},
{"2014 (RU)": 25000},
{"2018 (CN)": 22400},
], // or
data: [
{"Mon": 32.0},
{"Tue": 20.2},
{"Wed": 18.7},
{"Thu": 18.3},
{"Fri": 25.2},
{"Sat": 22.1},
{"Son": 22.9},
], //or
// data for multiple choice questions look like this:
data: [
{"San Francisco": false},
{"Boston": false},
{"New York": false},
{"Paris": true},
], // or
data: [
{"Mike Bostock": false},
{"Jim Vallandingham": true},
{"Amanda Cox": false},
],
...};
# question.heading
Sets the text or html containing the question.
# question.subHeading
Sets the text or html below the heading
.
# question.resultHtml
Sets the text or html after the user has drawn his guess and the correct result is shown.
# question.unit
Sets a string which is attached to the values of the y axis and the label of the tooltip when the user makes.
// examples for setting question.unit
question = {
...
unit: "sec", // or
unit: "Mio", // or
unit: "US$", // or
unit: "€",
...};
# question.precision
Sets the number of decimal places. The default is 1.
# question.lastPointShownAt
Determines the last point shown for the line chart. The user guesses start from the next point. Default value is the next to last point in the sequence. This leaves the user to guess just the last point. Any point but the last can be specified. Is irrelevant for the bar chart.
# question.yAxisMin
Sets the lowest value for the y axis. Default value is:
- 0, if all values are positive numbers
- Min(value) - random number * Min(value), if min(values) is a negative number. random number is a number between 0.4 and 1.0.
# question.yAxisMax
Sets the highest value for the y axis. Default value is:
- Max(value) + random number * Max(value). random number is a number between 0.4 and 1.0.
# question.referenceValues
Sets reference values to be shown before the interaction starts.
For the bar chart: referenceValues
has to be initialized by an array of objects. Each object has two properties:
text
(containing the label)value
(which contains the y coordinate).
E.g.:
question = {
...
referenceValues: [
{text: "right-handers (12.0 sec)", value: 12},
{text: "right-handers2 (12.5 sec)", value: 12.5},
{text: "right-handers3 (13 sec)", value: 13},
],
referenceValues
for the bar chart can be styled as follows:
<style>
.question-referenceValue {
color: red;
stroke: red;
}
</style>
For the line chart: referenceValues
has to be initialized by an array of objects. Each object has three properties:
text
(containing the label)textPosition
optional (which contains the offset on the path. Possible values are:start
,middle
andend
. The default ismiddle
)value
(which contains an array with the data for the line)
E.g.:
question = {
...
referenceValues: [
{text: "myLine", textPosition: "end", value: [
{"1998": 12000},
{"2002": 12000},
{"2006": 8000},
{"2010": 8500},
{"2014": 15000},
{"2018": 2400},
]
},
{text: "your Line", textPosition: "start", value: [
{"2010": 28500},
{"2014": 5000},
{"2018": 16400},
]
},
],
referenceValues
for the line chart can be styled as follows:
<style>
.question-referenceValues.referenceLine.line-myLine {
fill: deeppink;
stroke: deeppink;
}
</style>
The selector for referenceValues
for the line chart is .question-referenceValues.referenceLine
.
In case you want to style each line separately you the class .line-
the name of your line. Any whitespaces in your name (= the text property) will be trimmed.
# question.referenceShape
Sets the shape of the reference for the bar chart (single value). Default value is "line", only alternative is "tick" which prevents overlapping.
The font of the quiz can be changed in the <head>
of the html document by
- importing the new font
- assigning the font to the desired text elements
Three possible choices are:
<head>
...
<link href="https://fonts.googleapis.com/css?family=Indie+Flower" rel="stylesheet">
<style>
.update-font, .tick text {
font-family: 'Indie Flower', cursive;
font-size: 1.5em;
}
</style>
</head>
<head>
...
<link href="https://fonts.googleapis.com/css?family=Indie+Flower" rel="stylesheet">
<style>
.update-font {
font-family: 'Indie Flower', cursive;
font-size: 1.5em;
}
</style>
</head>
<head>
...
<link href="https://fonts.googleapis.com/css?family=Indie+Flower" rel="stylesheet">
<style>
.globals-drawLine, .globals-drawBar {
font-family: 'Indie Flower', cursive;
font-size: 1.5em;
}
</style>
</head>
You can CSS style any text element by applying class selectors as referenced below:
object key | class1 | class2 |
---|---|---|
globals.header | globals-header | update-font |
globals.subHeader | globals-subHeader | update-font |
globals.resultButtonText | globals-resultButtonText | update-font |
globals.resultButtonTooltip | globals-resultButtonTooltip | update-font |
globals.drawAreaTitle | globals-drawAreaTitle | update-font |
globals.drawLine | globals-drawLine | update-font |
globals.drawBar | globals-drawBar | update-font |
globals.scoreButtonText | globals-scoreButtonText | update-font |
globals.scoreButtonTooltip | globals-scoreButtonTooltip | update-font |
globals.scoreTitle | globals-scoreTitle | update-font |
globals.scoreHtml | globals-scoreHtml | update-font |
() → .scoreText | globals-scoreText | update-font |
question.heading | question-heading | update-font |
question.subHeading | question-subHeading | update-font |
question.resultHtml | question-resultHtml | update-font |
question.referenceValues | question-referenceValues | update-font |
(question.unit) → label | question-label | update-font |
(multiple choice question) → label | question-multipleChoice | update-font |
The final score is calculated as follows:
- for each question a score is calculated by
- (if line chart)
- compute the max possible distance for all points
- give score (0 - 100) for this question based on absolute distances
- (if bar chart)
- compute the max possible distance
- give score (0 - 100) for this question based on absolute distance
- (if line chart)
- final score is mean of all individual scores
This code is released under the BSD license.