...
 
Commits (28)
......@@ -19,6 +19,7 @@ class Evaluations extends ShortCodeController
{
$evaluation = Evaluation::where('id', $data["shortCodeAtts"]["visualize"])->first();
if ($evaluation !== null) {
wp_enqueue_style('evaluation_styles', GS_PLUGIN_DIR_URL . "/Public/css/Evaluations/style.css");
$visualizationName = $evaluation->getVisualization()['name'];
$this->templateRenderer->putVariable('EvaluationExists', true);
$this->templateRenderer->putVariable('chart_js', GS_PLUGIN_DIR_URL . "/Public/js/dist/visualizations/" . $visualizationName . ".js");
......
.traffic_light__hull {
width: unset;
background-color: #333333;
border-radius: 20px;
margin: 30px 0;
padding: 5%;
display: block;
}
.traffic_light__bulb,
.traffic_light__bulb--active {
min-height: 30px;
min-width: 30px;
max-height: 80px;
max-width: 80px;
background-color: #111111;
border-radius: 50%;
margin: 20px auto;
transition: background 500ms
}
.red_bulb.traffic_light__bulb--active {
background-color: red;
}
.yellow_bulb.traffic_light__bulb--active {
background-color: yellow;
}
.green_bulb.traffic_light__bulb--active {
background-color: green;
}
import { select } from 'd3-selection'
import { scaleLinear, scalePoint } from 'd3-scale'
import { line } from 'd3-shape'
import { axisBottom } from 'd3-axis'
import hookChart from './lib/hook.js'
let drawUntilMinMax = true
const d3 = Object.assign({}, {
select,
scaleLinear,
scalePoint,
line,
axisBottom,
})
let margins = {
top: 20,
right: 10,
bottom: 35,
left: 10
}
function drawBarChart(htmlElement, params, baseSize) {
let barDistance = 10
let barWidth = (baseSize / params.length) - barDistance
let maxBarHeight = baseSize / 3
console.log(params)
let svg = d3.select(htmlElement).append('svg')
.attr('width', baseSize)
.attr('height', baseSize / 3)
svg.selectAll('.groupBar')
.data(params)
.enter()
.append('rect')
.attr('class', 'groupBar')
.attr('x', (d, i) => (barWidth + barDistance) * i)
.attr('y', maxBarHeight)
.attr('width', 0.95*barWidth / 2)
.attr('height', 0)
.style('fill', '#4393c3')
//.style('opacity', '0.85')
svg.selectAll(".groupBar")
.attr("y", d => maxBarHeight - (maxBarHeight * d.average / d.max) )
.attr("height", d => maxBarHeight * d.average / d.max )
const xScale = d3.scalePoint();
const xAxis = d3.axisBottom()
.scale(xScale)
.tickPadding(15)
.tickSize(-maxBarHeight)
const yAxisG = svg.append('g');
yAxisG.append('text')
.attr('class', 'axis-label')
.attr('x', -maxBarHeight / 2)
.attr('y', -100)
.attr('transform', `rotate(-90)`)
.style('text-anchor', 'middle')
.text(yLabel);
xAxisG.call(xAxis)
svg.selectAll('.userBar')
.data(params)
.enter()
.append('rect')
.attr('class', 'userBar')
.attr('x', (d, i) => (barWidth/2) + (barWidth + + barDistance) * i)
.attr('y', maxBarHeight)
.attr('width', 0.95*barWidth / 2)
.attr('height', 0)
.style('fill', 'green')
.style('opacity', '0.85')
svg.selectAll(".userBar")
.attr("y", d => maxBarHeight - (maxBarHeight * d.userScore / d.max) )
.attr("height", d => maxBarHeight * d.userScore / d.max )
}
// HANDLE REQUEST
let initializeBarChart = (htmlElement, response, params, groupName) => {
console.log(params)
let baseSize = htmlElement.offsetWidth
htmlElement.innerHTML = ''
drawBarChart(htmlElement, params.data, baseSize)
}
let filename = document.currentScript.src.split('/').reverse()[0]
let chartName = filename.substring(0, filename.length - 3)
hookChart(chartName, initializeBarChart, {'hide_buttons': false})
// Config file for radarChart///////
/* global d3 */
import { scaleOrdinal } from 'd3-scale'
const margin = { top: 150, right: 150, bottom: 150, left: 150 }
const margin = { top: 150, right: 150, bottom: 150, left: 150 } // was before 120 for each
const width = Math.min(800, window.innerWidth - 10) - margin.left - margin.right
const height = Math.min(800, window.innerHeight - 10) - margin.top - margin.bottom
......
import { select } from 'd3-selection'
import Fetcher from './fetcher.js'
function getStatisticalGroupParameters(response, group, options = {}) {
let data = {}
data['meta'] = {
'groupName': group
}
response.subScales.forEach( (subScale, i) => {
if ('max_subscales' in options && i >= options.max_subscales) {
return
}
data['data'] = []
response.subScales.forEach( (subScale, i) => {
let currentGroup = response['subScales'][i]['groupResults'].filter( groupResult => {
return groupResult.group == group
})[0]
data['data'].push({
'subScaleName': subScale.name,
'questionCount': currentGroup.questionCount,
'average': currentGroup.average,
'standardDeviation': currentGroup.standardDeviation,
'min': currentGroup.min,
'max': currentGroup.max,
'minValue': currentGroup.minValue,
'maxValue': currentGroup.maxValue,
'userScore': subScale.userResult.score
})
})
})
return data
}
function makeChart(htmlElement, response, groupName, drawGroupChart) {
let params = getStatisticalGroupParameters(response, groupName)
drawGroupChart(htmlElement, response, params, groupName)
}
function drawButtons(htmlElement, response, drawGroupChart, options={}) {
let buttonBox = htmlElement.nextSibling.nextSibling
let groupNames = []
let groupButton
response.subScales.forEach( (subScale, i) => {
if ("max_subscales" in options && i >= options.max_subscales) {
return
}
subScale.groupResults.forEach(group => {
if (!groupNames.includes(group.group)) {
groupNames.push(group.group)
groupButton = document.createElement("button")
groupButton.innerText = group.group
groupButton.addEventListener("click", () => makeChart(htmlElement, response, group.group, drawGroupChart), false)
buttonBox.appendChild(groupButton)
}
})
})
return buttonBox
}
function hookChart(elementClass, drawGroupChart, options = {}) {
let elements = document.getElementsByClassName(elementClass)
let url, buttonBox, i = 0
Array.prototype.forEach.call(elements, htmlElement => {
htmlElement.innerHTML = ''
url = Fetcher.buildURL(select(htmlElement).attr('evaluation_id'))
Fetcher.getJSON(url).then(response => {
if ( !("hide_buttons" in options && options.hide_buttons) ) {
buttonBox = drawButtons(htmlElement, response, drawGroupChart, options)
buttonBox.firstChild.click()
} else {
makeChart(htmlElement, response, response.subScales[0].groupResults[0].group, drawGroupChart)
}
}, error => console.log(error))
})
}
export default hookChart
import { select } from 'd3-selection'
import { scaleLinear } from 'd3-scale'
import { line } from 'd3-shape'
import { axisBottom } from 'd3-axis'
import hookChart from './lib/hook.js'
let drawUntilMinMax = true
const d3 = Object.assign({}, {
select,
scaleLinear,
line,
axisBottom,
})
let margins = {
top: 20,
right: 10,
bottom: 35,
left: 10
}
// MATH FUNCTIONSGaussian probability function
function gaussian (x, mean, sigma) {
const gaussianConstant = 1 / (Math.sqrt(2 * Math.PI) * sigma)
x = (x - mean) / sigma
return gaussianConstant * (Math.exp(-0.5 * (x * x)))
}
function clipMinMax(min, max, value) {
return value < min ? min : value > max ? max : value
}
// DATA FUNCTIONS
function makeGroupDistributionData(params) {
let p=0, q=0, data = []
let sampleSize = 1000;
data.push({'q': params.minValue, 'p': 0})
for (var i = 0; i < (sampleSize); i++) {
q = (params.min + ((params.max - params.min) / sampleSize * i))
p = gaussian(q, params.mean, params.sigma)
data.push({
'q': clipMinMax(params.minValue, params.maxValue, q),
'p': p
})
}
data[0].q = data[1].q
data.push({'q': params.maxValue, 'p': data[data.length-1].p})
data.push({'q': params.maxValue, 'p': 0})
return data
}
// DRAW FUNCTIONS
function makeCanvasGroup(element, baseSize) {
element.innerHTML = ''
let svg = d3.select(element).append('svg')
.attr('width', baseSize)
.attr('height', baseSize/2)
let chart = svg.append('g')
.attr('transform', `translate(${margins.left},${margins.top})`)
return chart
}
function draw_normal_distribution(chart, params, baseSize) {
let data = makeGroupDistributionData(params)
let xScale = d3.scaleLinear()
.range([0, baseSize - margins.left - margins.right])
.domain([params.min, params.max])
let yScale = d3.scaleLinear()
.range([(baseSize/2) - margins.top - margins.bottom, 0])
.domain([0, 1])//gaussian(params.mean, params.mean, params.sigma)])
let plotLine = d3.line()
.x( data => xScale(data.q) )
.y( data => yScale(data.p) )
chart.append('path')
.datum(data)
.attr('class', 'line')
.attr('d', plotLine)
.attr('stroke-width', 1)
.style('fill', '#4393c3')
.style('opacity', '0.45')
.style('stroke', 'black')
let axis_position_y = yScale(0)
chart.append('g')
.attr('class', 'x axis')
.attr('transform', "translate(0," + axis_position_y + ")")
.call(d3.axisBottom(xScale))
}
function drawUser(chart, params, baseSize) {
let xScale = d3.scaleLinear()
.range([params.min, baseSize - margins.left - margins.right])
.domain([1, params.max])
let yScale = d3.scaleLinear()
.range([(baseSize/2) - margins.top - margins.bottom, 0])
.domain([0, 1])
let data = [{'x': params.userScore, 'y':0},{'x':params.userScore, 'y': 0.8}]
let plotLine = d3.line()
.x( data => xScale(data.x) )
.y( data => yScale(data.y) )
chart.append('path')
.datum(data)
.attr('class', 'line')
.attr('d', plotLine)
.attr('stroke-width', 6)
.style('opacity', '0.75')
.style('stroke', 'green')
}
// HANDLE REQUEST
let drawNormalDistribution = (htmlElement, response, params, groupName) => {
let baseSize = htmlElement.offsetWidth
let subScaleOffset = 0
let data = params.data
let groupAvgParams = {
'mean': params.data[0].average / params.data[0].questionCount,
'min': params.data[0].min / params.data[0].questionCount,
'max': params.data[0].max / params.data[0].questionCount,
'minValue': ( drawUntilMinMax ? params.data[0].min : params.data[0].minValue) / params.data[0].questionCount,
'maxValue': ( drawUntilMinMax ? params.data[0].max : params.data[0].maxValue) / params.data[0].questionCount,
'sigma': data[Object.keys(data)[subScaleOffset]].standardDeviation / params.data[0].questionCount,
'userScore': params.data[0].userScore / params.data[0].questionCount
}
let canvasGroup = makeCanvasGroup(htmlElement, baseSize)
draw_normal_distribution(canvasGroup, groupAvgParams, baseSize)
drawUser(canvasGroup, groupAvgParams, baseSize)
}
let filename = document.currentScript.src.split('/').reverse()[0]
let chartName = filename.substring(0, filename.length - 3)
hookChart(chartName, drawNormalDistribution, {'hide_buttons': true})
......@@ -503,9 +503,21 @@ function parseData (response) {
}
// API Call
let domElementId = '.radarchart'
let evaluationId = d3.select(domElementId).attr('evaluation_id')
let url = Fetcher.buildURL(evaluationId)
// let domElementClass = '.radarchart'
// let evaluationId = d3.select(domElementClass).attr('evaluation_id')
// let url = Fetcher.buildURL(evaluationId)
// let data
let data
let url
let elements = document.getElementsByClassName('radarchart')
Array.prototype.forEach.call(elements, function(element){
url = Fetcher.buildURL(d3.select(element).attr('evaluation_id'))
Fetcher.getJSON(url).then(response => { data = parseData(response); RadarChart(element, data, radarOptions)}, error => console.log(error))
})
Fetcher.getJSON(url).then(response => { data = parseData(response); RadarChart(domElementId, data, radarOptions) }, error => console.error('Failed!', error))
// Fetcher.getJSON(url).then(response => { data = parseData(response); RadarChart(domElementClass, data, radarOptions) }, error => console.error('Failed!', error))
import hookChart from './lib/hook.js'
let draw_traffic_light = (htmlElement, response, params, groupName) => {
let data = params.data[0]
let traffic_light = document.createElement('div')
traffic_light.classList.add('traffic_light__hull')
let active_conditions = {
'red_bulb': data.userScore < data.average - data.standardDeviation,
'yellow_bulb': data.userScore > data.average - data.standardDeviation && data.userScore < data.average - data.standardDeviation,
'green_bulb': data.userScore > data.average + data.standardDeviation,
}
let light_bulbs = {
'red_bulb': document.createElement('div'),
'yellow_bulb': document.createElement('div'),
'green_bulb': document.createElement('div')
}
Object.keys(light_bulbs).forEach(bulbName => {
light_bulbs[bulbName].classList.add(bulbName)
light_bulbs[bulbName].classList.add(active_conditions[bulbName] ? 'traffic_light__bulb--active' : 'traffic_light__bulb')
traffic_light.appendChild(light_bulbs[bulbName])
})
htmlElement.appendChild(traffic_light)
}
let filename = document.currentScript.src.split('/').reverse()[0]
let chartName = filename.substring(0, filename.length - 3)
hookChart(chartName, draw_traffic_light, {'hide_buttons': true})
......@@ -73,7 +73,7 @@ $evaluables_per_subscale = [
$evaluables_per_subscale[$subscale_names[8]] = call_user_func_array('array_merge', array_values($evaluables_per_subscale));
$visualisation_config = [
'name' => 'normal_distribution',
'name' => 'traffic_light',
'minSubScales' => 1,
'maxSubScales' => 1,
'type' => $eval_type
......