Commit 515ef993 authored by Jan Dillenberger's avatar Jan Dillenberger

Implement bar_chart. Reimplement radarchart

parent 139ff413
Pipeline #21971 failed with stage
in 139 minutes and 32 seconds
......@@ -48,7 +48,13 @@ class UserResult extends Model
$answerConstructors = $evaluable->getAnswerConstructors($userId);
if (sizeof($answerConstructors) > 0) {
$result += $answerConstructors[$entryId]()->getUserScore();
if (array_key_exists($entryId, $answerConstructors)) {
$result += $answerConstructors[$entryId]()->getUserScore();
} else {
$answerConstructorReversed = array_reverse($answerConstructors);
$constructor = array_pop($answerConstructorReversed);
$result += $constructor()->getUserScore();
}
}
}
return $result;
......
......@@ -31,3 +31,35 @@
.green_bulb.traffic_light__bulb--active {
background-color: green;
}
/* D3JS Tooltio */
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
import { select } from 'd3-selection'
import { scaleLinear, scalePoint } from 'd3-scale'
import { scaleOrdinal, scaleLinear, scalePoint } from 'd3-scale'
import { line } from 'd3-shape'
import tip from 'd3-tip'
import { axisBottom } from 'd3-axis'
import hookChart from './lib/hook.js'
......@@ -10,9 +11,11 @@ let drawUntilMinMax = true
const d3 = Object.assign({}, {
select,
scaleLinear,
scaleOrdinal,
scalePoint,
line,
axisBottom,
tip,
})
......@@ -24,20 +27,48 @@ let margins = {
}
function drawBarChart(htmlElement, params, baseSize) {
function drawBarChart(htmlElement, params, baseSize, groupName) {
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)
let tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-5-baseSize/50, 0])
.html( d => {
if (d.isUser) {
return 'Dein Ergebnis für ' + d.subScaleName
} else {
return 'Durchschnitt der Vergleichsgruppe <br /> für ' + d.subScaleName
}
} )
svg.call(tip)
var x = d3.scalePoint()
.domain(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])
.range([ 0, baseSize ]);
svg.selectAll('.axisBottom')
.enter(params)
.append('g')
.attr("transform", "translate(0," + maxBarHeight + ")")
.call(d3.axisBottom(x))
svg.selectAll('.groupBar')
.data(params)
.data(params.map(data => {
let datacopy = JSON.parse(JSON.stringify(data))
datacopy.isUser = false
return datacopy
}))
.enter()
.append('rect')
.attr('class', 'groupBar')
......@@ -51,30 +82,23 @@ function drawBarChart(htmlElement, params, baseSize) {
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)
.on("mouseout", tip.hide)
.on("mouseover", function(d) {
tip.show(d, this)
d3.select(this).style('fill', '#76C6F5')
})
.on("mouseout", function(d) {
tip.hide(d, this)
d3.select(this).style('fill', '#4393c3')
});
svg.selectAll('.userBar')
.data(params)
.data(params.map(data => {
let datacopy = JSON.parse(JSON.stringify(data))
datacopy.isUser = true
return datacopy
}))
.enter()
.append('rect')
.attr('class', 'userBar')
......@@ -87,17 +111,26 @@ function drawBarChart(htmlElement, params, baseSize) {
svg.selectAll(".userBar")
.attr("y", d => maxBarHeight - (maxBarHeight * d.userScore / d.max) )
.attr("height", d => maxBarHeight * d.userScore / d.max )
.attr("height", d => maxBarHeight * d.userScore / d.max )
.on("mouseover", function(d) {
tip.show(d, this)
d3.select(this).style('fill', '#33FF33')
})
.on("mouseout", function(d) {
tip.hide(d, this)
d3.select(this).style('fill', 'green')
})
}
// HANDLE REQUEST
let initializeBarChart = (htmlElement, response, params, groupName) => {
console.log(params)
let baseSize = htmlElement.offsetWidth
htmlElement.innerHTML = ''
drawBarChart(htmlElement, params.data, baseSize)
drawBarChart(htmlElement, params.data, baseSize, groupName)
}
let filename = document.currentScript.src.split('/').reverse()[0]
......
......@@ -63,6 +63,10 @@ function drawButtons(htmlElement, response, drawGroupChart, options={}) {
groupButton = document.createElement("button")
groupButton.innerText = group.group
groupButton.addEventListener("click", () => makeChart(htmlElement, response, group.group, drawGroupChart), false)
if (subScale.groupResults.length <= 1) {
groupButton.style.display = "none"
}
buttonBox.appendChild(groupButton)
}
})
......
import { select } from 'd3-selection'
import { scaleOrdinal, scaleLinear, scalePoint } from 'd3-scale'
import { range } from 'd3-array'
import { format } from 'd3-format'
import { line } from 'd3-shape'
import tip from 'd3-tip'
import { axisBottom } from 'd3-axis'
import { curveLinearClosed, lineRadial, curveCardinalClosed } from 'd3-shape'
import hookChart from './lib/hook.js'
let drawUntilMinMax = true
const d3 = Object.assign({}, {
select,
scaleLinear,
scaleOrdinal,
scalePoint,
line,
axisBottom,
tip,
range,
format,
curveLinearClosed,
lineRadial,
curveCardinalClosed,
})
let margins = {
top: 20,
right: 10,
bottom: 35,
left: 10
}
function computeData(params, baseSize) {
// PREPARE STUFF
let computedData = {}
let maxGroup = params.reduce((subscale1, subscale2) => subscale1.max/subscale1.questionCount > subscale2.max/subscale2.questionCount ? subscale1 : subscale2)
let minGroup = params.reduce((subscale1, subscale2) => subscale1.max/subscale1.questionCount < subscale2.max/subscale2.questionCount ? subscale1 : subscale2)
// COMPUTE DATA
computedData.chartMax = maxGroup.max / maxGroup.questionCount
computedData.chartMin = minGroup.min / minGroup.questionCount
computedData.rScale = d3.scaleLinear()
.range([0, baseSize/2 - (margins.top + margins.bottom) ])
.domain([0, computedData.chartMax])
return computedData
}
function drawRadarAxis(g, params, baseSize) {
let computedData = computeData(params, baseSize)
let chartMin = computedData.chartMin
let chartMax = computedData.chartMax
let rScale = computedData.rScale
// DRAW AXIS
let axisGrid = g.append('g').attr('class', 'axisWrapper')
axisGrid.selectAll('.levels')
.data(d3.range(0, chartMax + 1).reverse())
.enter()
.append('circle')
.attr('class', 'gridCircle')
.attr('r', d => rScale(1) * d)
.style('stroke', '#5b5959')
.style('fill-opacity', 0)
axisGrid.selectAll('.axisLabel')
.data(d3.range(chartMin, chartMax + 1).reverse())
.enter().append('text')
.attr('class', 'axisLabel')
.attr('x', rScale(1/3))
.attr('y', d => - (rScale(1) * d) - rScale(1/chartMax))
.attr('dy', '0.4em')
.style('font-size', baseSize/40)
.attr('fill', 'black')
.text(d => d)
let axis = axisGrid.selectAll('.axis')
.data(params)
.enter()
.append('g')
.attr('class', 'axis')
// Append the lines
axis.append('line')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', (d, i) => rScale(chartMax * 1.05) * Math.cos((Math.PI * 2 / params.length) * i - Math.PI / 2))
.attr('y2', (d, i) => rScale(chartMax * 1.05) * Math.sin((Math.PI *2 / params.length) * i - Math.PI / 2))
.attr('class', 'line')
.style('stroke', '#504d4d')
.style('stroke-width', '2px')
}
function drawRadarGroup(g, params, baseSize, groupName) {
let computedData = computeData(params, baseSize)
let chartMin = computedData.chartMin
let chartMax = computedData.chartMax
let rScale = computedData.rScale
let entityScoreKey = groupName === 'user' ? 'userScore' : 'average'
let color = groupName === 'user' ? 'green' : 'red'
let scoreCircleWrapper = g.selectAll('.scoreCircleWrapper')
.data([params])
.enter().append('g')
.attr('class', 'radarCircleWrapper')
.attr('fill', 'red')
let tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-5-baseSize/50, 0])
.html( d => (Math.round(100 * d[entityScoreKey] / d.questionCount) ) / 100 )
g.call(tip)
let scoreCircle = scoreCircleWrapper.selectAll('.radarScoreCircle')
.data(d => d)
.enter().append('circle')
.attr('class', 'scoreCircle')
.attr('r', 7)
.attr('cx', (d, i) => rScale((d[entityScoreKey] / d.questionCount) ) * Math.cos((Math.PI * 2 / params.length) * i - Math.PI / 2))
.attr('cy', (d, i) => rScale((d[entityScoreKey] / d.questionCount) ) * Math.sin((Math.PI * 2 / params.length) * i - Math.PI / 2))
.style('fill', color)
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
// ToDo: Do everything missing
let legend = g.append('g')
.attr('class', 'legend')
/*.attr('transform', function (d, i) {
return 'translate(-50,0)'
})*/
.attr('height', 300)
.attr('width', 500)
// add legend texts
legend.selectAll('text')
.data(params)
.enter()
.append('text')
.attr('x', (d, i) => rScale(chartMax * 1.17) * Math.cos((Math.PI * 2 / params.length) * i - Math.PI / 2))
.attr('y', function (d, i) {
return rScale(chartMax * 1.17) * Math.sin((Math.PI * 2 / params.length) * i - Math.PI / 2)
})
.text(function (d) {
var text = d.subScaleName
return text
})
.style('font-size', baseSize/40)
.style("text-anchor", "middle")
}
// HANDLE REQUEST
let initializeBarChart = (htmlElement, response, params, groupName) => {
let baseSize = htmlElement.offsetWidth
htmlElement.innerHTML = ''
let svg = d3.select(htmlElement).append('svg')
.attr('width', baseSize)
.attr('height', baseSize)
.style('overflow', 'visible')
let g = svg.append('g')
.attr('transform', 'translate(' + (baseSize / 2 + margins.left) + ',' + (baseSize / 2 + margins.top) + ')')
drawRadarAxis(g, params.data, baseSize)
drawRadarGroup(g, params.data, baseSize, groupName)
drawRadarGroup(g, params.data, baseSize, 'user')
}
let filename = document.currentScript.src.split('/').reverse()[0]
let chartName = filename.replace(/\.js\??.*$/, '')
hookChart(chartName, initializeBarChart, {'hide_buttons': false})
......@@ -33,6 +33,7 @@
"axios": "^0.19.2",
"d3": "^5.9.7",
"d3-queue": "^3.0.7",
"d3-tip": "^0.9.1",
"vue": "^2.6.11",
"webpack-shell-plugin": "^0.5.0"
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment