165 lines
5.1 KiB
JavaScript
165 lines
5.1 KiB
JavaScript
Object.defineProperty(Array.prototype, 'shuffle', {
|
|
value: function() {
|
|
for (let i = this.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[this[i], this[j]] = [this[j], this[i]];
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
|
|
(() => {
|
|
const unit = 5
|
|
|
|
const testmeta = document.querySelector('#testmeta')
|
|
const chartmeta = document.querySelector('#chartmeta')
|
|
let questionData = undefined
|
|
|
|
const hide = (el) => {
|
|
el.style.display = "none"
|
|
return el
|
|
}
|
|
const show = (el) => {
|
|
el.style.display = "block"
|
|
return el
|
|
}
|
|
|
|
const questionTemplate = (tpl) => {
|
|
return `
|
|
<div class="question">
|
|
<h3>${tpl.i + 1}. ${tpl.q}</h3>
|
|
|
|
<div class="input" data-q="${tpl.q}">
|
|
<label><input type="radio" name="q-${tpl.i}" value="5"> ${window.radios[4]}</label>
|
|
<label><input type="radio" name="q-${tpl.i}" value="4"> ${window.radios[3]}</label>
|
|
<label><input type="radio" name="q-${tpl.i}" value="3"> ${window.radios[2]}</label>
|
|
<label><input type="radio" name="q-${tpl.i}" value="2"> ${window.radios[1]}</label>
|
|
<label><input type="radio" name="q-${tpl.i}" value="1"> ${window.radios[0]}</label>
|
|
</div>
|
|
</div>`
|
|
}
|
|
|
|
const downloadResults = () => {
|
|
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(window.results))
|
|
var dlAnchorElem = document.querySelector('#downloadAnchorElem')
|
|
dlAnchorElem.setAttribute("href", dataStr)
|
|
dlAnchorElem.setAttribute("download", "results.json")
|
|
dlAnchorElem.click()
|
|
}
|
|
|
|
const fillInRandomResults = () => {
|
|
document.querySelectorAll('.input').forEach(d => { const r = Math.round(Math.random() * 4) + 1; d.querySelector(`input[value="${r}"]`).click(); })
|
|
calculateResults()
|
|
}
|
|
|
|
const calculateResults = () => {
|
|
const addResultsInHtml = (data) => {
|
|
data.forEach(d => {
|
|
const attr = d.attribute.replace(/ /g, '-')
|
|
document.querySelector(`#result_${attr}`).innerHTML = d.score;
|
|
})
|
|
}
|
|
|
|
const generateAmChart = (data) => {
|
|
// expected data: [{attribute: "Curiosity", score: 5}]
|
|
am4core.useTheme(am4themes_animated)
|
|
const chart = am4core.create("chartdiv", am4charts.RadarChart)
|
|
chart.data = data
|
|
|
|
const categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis())
|
|
categoryAxis.dataFields.category = "attribute"
|
|
categoryAxis.cursorTooltipEnabled = false
|
|
|
|
const valueAxis = chart.yAxes.push(new am4charts.ValueAxis())
|
|
valueAxis.renderer.axisFills.template.fill = chart.colors.getIndex(2)
|
|
valueAxis.renderer.axisFills.template.fillOpacity = 0.05
|
|
valueAxis.min = 0
|
|
valueAxis.max = unit
|
|
|
|
const series = chart.series.push(new am4charts.RadarSeries())
|
|
series.dataFields.valueY = "score"
|
|
series.tooltipText = "[bold]{score}[/]"
|
|
//series.fill = am4core.color('black')
|
|
series.dataFields.categoryX = "attribute"
|
|
series.strokeWidth = 3
|
|
|
|
chart.cursor = new am4charts.RadarCursor()
|
|
chart.cursor.lineY.disabled = true
|
|
}
|
|
|
|
const vals = [0, 1, 2, 3, 4, 5]
|
|
const valsInverted = [0, 5, 4, 3, 2, 1]
|
|
|
|
const convertInputResultsToChartData = () => {
|
|
return questionData.attributes.map((attribute, i) => {
|
|
const calculatedQs = questionData.questions
|
|
.filter(q => q.v.find(v => v.attribute === attribute))
|
|
.map(q => {
|
|
const checked = document.querySelector(`.input[data-q="${q.q}"] input:checked`)
|
|
const value = checked ? parseInt(checked.value) : 0
|
|
const weight = q.v.find(v => v.attribute === attribute).weight
|
|
|
|
return {
|
|
weight,
|
|
question: q.q,
|
|
value: q.invert ? valsInverted[value] : vals[value]
|
|
}
|
|
})
|
|
const totalWeights = calculatedQs
|
|
.map(calc => calc.weight * unit)
|
|
.reduce((one, two) => one + two, 0)
|
|
const totalScore = calculatedQs
|
|
.map(calc => calc.weight * calc.value)
|
|
.reduce((one, two) => one + two, 0)
|
|
const theScore = (totalScore / (totalWeights == 0 ? 1 : totalWeights)) * unit
|
|
|
|
return {
|
|
attribute,
|
|
questions: calculatedQs,
|
|
score: (theScore === 0 ? 1 : theScore).toFixed(2)
|
|
}
|
|
})
|
|
}
|
|
|
|
if(document.querySelectorAll('input:checked').length < questionData.questions.length) {
|
|
alert("Plese answer all questions first!")
|
|
return
|
|
}
|
|
|
|
hide(testmeta)
|
|
show(chartmeta)
|
|
window.results = convertInputResultsToChartData()
|
|
generateAmChart(results)
|
|
addResultsInHtml(results)
|
|
window.scrollTo(0, 0)
|
|
}
|
|
|
|
const generateQuestions = (data) => {
|
|
questionData = data
|
|
/* data format:
|
|
attributes
|
|
questions { q, v [ weight, attrIndex ] } -> totals to 100 parts
|
|
*/
|
|
let html = ''
|
|
data.questions.slice().shuffle().forEach((q, i) => {
|
|
html += questionTemplate({
|
|
q: q.q,
|
|
i: i
|
|
})
|
|
})
|
|
|
|
document.querySelector('#test').innerHTML = html;
|
|
}
|
|
|
|
document.querySelector('#download').addEventListener('click', downloadResults)
|
|
document.querySelector('#random').addEventListener('click', fillInRandomResults)
|
|
document.querySelector('#calculate').addEventListener('click', calculateResults)
|
|
document.querySelector('#restart').addEventListener('click', () => {
|
|
location.reload()
|
|
})
|
|
|
|
fetch('data.json').then((res) => {
|
|
return res.json();
|
|
}).then(generateQuestions);
|
|
})()
|