Merge branch 'develop' of bitbucket.org:iterativ/vbv_lernwelt into develop
This commit is contained in:
commit
ab10c38346
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import {computed, onMounted} from "vue";
|
import {computed, onMounted} from "vue";
|
||||||
import * as _ from 'underscore'
|
import * as _ from 'lodash'
|
||||||
import {useCircleStore} from '@/stores/circle';
|
import {useCircleStore} from '@/stores/circle';
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
|
|
@ -14,6 +14,13 @@ function someFinished(learningSequence) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function allFinished(learningSequence) {
|
||||||
|
if (circleStore.circle) {
|
||||||
|
return circleStore.circle.allFinishedInLearningSequence(learningSequence.translation_key);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.info('CircleDiagram mounted');
|
log.info('CircleDiagram mounted');
|
||||||
render();
|
render();
|
||||||
|
|
@ -39,7 +46,8 @@ const pieData = computed(() => {
|
||||||
pie.arrowStartAngle = pie.endAngle + (pie.startAngle - pie.endAngle) / 2
|
pie.arrowStartAngle = pie.endAngle + (pie.startAngle - pie.endAngle) / 2
|
||||||
pie.arrowEndAngle = pie.startAngle + (pie.startAngle - pie.endAngle) / 2
|
pie.arrowEndAngle = pie.startAngle + (pie.startAngle - pie.endAngle) / 2
|
||||||
pie.translation_key = thisLearningSequence.translation_key
|
pie.translation_key = thisLearningSequence.translation_key
|
||||||
pie.done = someFinished(thisLearningSequence)
|
pie.someFinished = someFinished(thisLearningSequence)
|
||||||
|
pie.allFinished = allFinished(thisLearningSequence)
|
||||||
})
|
})
|
||||||
angles = angles.reverse()
|
angles = angles.reverse()
|
||||||
return angles
|
return angles
|
||||||
|
|
@ -54,7 +62,9 @@ const blue900 = '#00224D',
|
||||||
gray300 = '#E0E5EC',
|
gray300 = '#E0E5EC',
|
||||||
gray500 = '#B1C1CA',
|
gray500 = '#B1C1CA',
|
||||||
sky400 = '#72CAFF',
|
sky400 = '#72CAFF',
|
||||||
sky500 = '#41B5FA'
|
sky500 = '#41B5FA',
|
||||||
|
green500 = '#54CE8B',
|
||||||
|
green400 = '#78DEA3'
|
||||||
|
|
||||||
const width = 450
|
const width = 450
|
||||||
const height = 450
|
const height = 450
|
||||||
|
|
@ -84,6 +94,28 @@ function render() {
|
||||||
const g = svg.append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
|
const g = svg.append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
|
||||||
|
|
||||||
|
|
||||||
|
function getColor(d) {
|
||||||
|
let color = gray300
|
||||||
|
if (d.someFinished) {
|
||||||
|
color = sky500
|
||||||
|
}
|
||||||
|
if (d.allFinished) {
|
||||||
|
color = green500
|
||||||
|
}
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHoverColor(d) {
|
||||||
|
let color = gray100
|
||||||
|
if (d.someFinished) {
|
||||||
|
color = sky400
|
||||||
|
}
|
||||||
|
if (d.allFinished) {
|
||||||
|
color = green400
|
||||||
|
}
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the pie diagram wede
|
// Generate the pie diagram wede
|
||||||
const wedgeGenerator = d3
|
const wedgeGenerator = d3
|
||||||
.arc()
|
.arc()
|
||||||
|
|
@ -108,16 +140,17 @@ function render() {
|
||||||
.transition()
|
.transition()
|
||||||
.duration('200')
|
.duration('200')
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky400 : gray100
|
return getHoverColor(d)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
.on('mouseout', function (d, i) {
|
.on('mouseout', function (d, i) {
|
||||||
d3.select(this)
|
d3.select(this)
|
||||||
.transition()
|
.transition()
|
||||||
.duration('200')
|
.duration('200')
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky500 : gray300
|
return getColor(d)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('click', function (d, elm) {
|
.on('click', function (d, elm) {
|
||||||
|
|
@ -125,11 +158,12 @@ function render() {
|
||||||
document.getElementById(elm.translation_key)?.scrollIntoView({behavior: 'smooth'})
|
document.getElementById(elm.translation_key)?.scrollIntoView({behavior: 'smooth'})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
learningSequences
|
learningSequences
|
||||||
.transition()
|
.transition()
|
||||||
.duration('1')
|
.duration(1)
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky500 : gray300
|
return getColor(d)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -193,7 +227,6 @@ function render() {
|
||||||
return d3.select(this.nodes()[last]);
|
return d3.select(this.nodes()[last]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const all_arows = g.selectAll('.arrow')
|
const all_arows = g.selectAll('.arrow')
|
||||||
all_arows.last().remove()
|
all_arows.last().remove()
|
||||||
|
|
||||||
|
|
@ -208,7 +241,7 @@ function render() {
|
||||||
<template>
|
<template>
|
||||||
<div class="svg-container h-full content-center">
|
<div class="svg-container h-full content-center">
|
||||||
<pre hidden>{{ pieData }}</pre>
|
<pre hidden>{{ pieData }}</pre>
|
||||||
<pre hidden>{{render()}}</pre>
|
<pre hidden>{{ render() }}</pre>
|
||||||
<svg class="circle-visualization h-full">
|
<svg class="circle-visualization h-full">
|
||||||
<circle v-if="!circleStore.circle" :cx="width / 2" :cy="height / 2" :r="radius" :color="gray300"/>
|
<circle v-if="!circleStore.circle" :cx="width / 2" :cy="height / 2" :r="radius" :color="gray300"/>
|
||||||
<circle v-if="!circleStore.circle" :cx="width / 2" :cy="height / 2" :r="radius / 2.5" color="white"/>
|
<circle v-if="!circleStore.circle" :cx="width / 2" :cy="height / 2" :r="radius / 2.5" color="white"/>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import {useLearningPathStore} from '../../stores/learningPath';
|
import {useLearningPathStore} from '../../stores/learningPath';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
width: {
|
width: {
|
||||||
|
|
@ -25,22 +26,41 @@ export default {
|
||||||
const learningPathStore = useLearningPathStore()
|
const learningPathStore = useLearningPathStore()
|
||||||
return {learningPathStore}
|
return {learningPathStore}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
viewBox() {
|
viewBox() {
|
||||||
return `0 0 ${this.width} ${this.height * 1.5}`
|
return `0 0 ${this.width} ${this.height * 1.5}`
|
||||||
},
|
},
|
||||||
circles() {
|
circles() {
|
||||||
|
|
||||||
|
function someFinished(circle, learningSequence) {
|
||||||
|
if (circle) {
|
||||||
|
return circle.someFinishedInLearningSequence(learningSequence.translation_key);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function allFinished(circle, learningSequence) {
|
||||||
|
if (circle) {
|
||||||
|
return circle.allFinishedInLearningSequence(learningSequence.translation_key);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.learningPathStore.learningPath) {
|
if (this.learningPathStore.learningPath) {
|
||||||
let internalCircles = []
|
let internalCircles = []
|
||||||
this.learningPathStore.learningPath.circles.forEach((circle) => {
|
this.learningPathStore.learningPath.circles.forEach((circle) => {
|
||||||
let pieWeights = new Array(Math.max(circle.learningSequences.length, 1)).fill(1)
|
const pieWeights = new Array(Math.max(circle.learningSequences.length, 1)).fill(1)
|
||||||
let pieGenerator = d3.pie()
|
const pieGenerator = d3.pie()
|
||||||
let pieData = pieGenerator(pieWeights)
|
let pieData = pieGenerator(pieWeights)
|
||||||
pieData.forEach((pie) => {
|
pieData.forEach((pie) => {
|
||||||
|
const thisLearningSequence = circle.learningSequences[parseInt(pie.index)]
|
||||||
pie.startAngle = pie.startAngle + Math.PI
|
pie.startAngle = pie.startAngle + Math.PI
|
||||||
pie.endAngle = pie.endAngle + Math.PI
|
pie.endAngle = pie.endAngle + Math.PI
|
||||||
const lp = circle.learningSequences[parseInt(pie.index)];
|
pie.done = circle.someFinishedInLearningSequence(thisLearningSequence.translation_key);
|
||||||
pie.done = circle.someFinishedInLearningSequence(lp.translation_key);
|
pie.someFinished = someFinished(circle, thisLearningSequence)
|
||||||
|
pie.allFinished = allFinished(circle, thisLearningSequence)
|
||||||
});
|
});
|
||||||
let newCircle = {}
|
let newCircle = {}
|
||||||
newCircle.pieData = pieData.reverse()
|
newCircle.pieData = pieData.reverse()
|
||||||
|
|
@ -72,7 +92,32 @@ export default {
|
||||||
gray300 = '#E0E5EC',
|
gray300 = '#E0E5EC',
|
||||||
gray500 = '#B1C1CA',
|
gray500 = '#B1C1CA',
|
||||||
sky400 = '#72CAFF',
|
sky400 = '#72CAFF',
|
||||||
sky500 = '#41B5FA'
|
sky500 = '#41B5FA',
|
||||||
|
green500 = '#54CE8B',
|
||||||
|
green400 = '#78DEA3'
|
||||||
|
|
||||||
|
|
||||||
|
function getColor(d) {
|
||||||
|
let color = gray300
|
||||||
|
if (d.someFinished) {
|
||||||
|
color = sky500
|
||||||
|
}
|
||||||
|
if (d.allFinished) {
|
||||||
|
color = green500
|
||||||
|
}
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHoverColor(d) {
|
||||||
|
let color = gray100
|
||||||
|
if (d.someFinished) {
|
||||||
|
color = sky400
|
||||||
|
}
|
||||||
|
if (d.allFinished) {
|
||||||
|
color = green400
|
||||||
|
}
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
|
||||||
let vueRouter = this.$router
|
let vueRouter = this.$router
|
||||||
|
|
||||||
|
|
@ -90,7 +135,7 @@ export default {
|
||||||
.transition()
|
.transition()
|
||||||
.duration(200)
|
.duration(200)
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky400 : gray100
|
return getHoverColor(d)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('mouseout', function (d, i) {
|
.on('mouseout', function (d, i) {
|
||||||
|
|
@ -99,7 +144,7 @@ export default {
|
||||||
.transition()
|
.transition()
|
||||||
.duration(200)
|
.duration(200)
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky500 : gray300
|
return getColor(d)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('click', function (d, i) {
|
.on('click', function (d, i) {
|
||||||
|
|
@ -130,7 +175,7 @@ export default {
|
||||||
.transition()
|
.transition()
|
||||||
.duration(1000)
|
.duration(1000)
|
||||||
.attr('fill', (d) => {
|
.attr('fill', (d) => {
|
||||||
return d.done ? sky500 : gray300
|
return getColor(d)
|
||||||
})
|
})
|
||||||
|
|
||||||
//Draw arc paths
|
//Draw arc paths
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,14 @@ const someFinished = computed(() => {
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const allFinished = computed(() => {
|
||||||
|
if (props.learningSequence && circleStore.circle) {
|
||||||
|
return circleStore.circle.allFinishedInLearningSequence(props.learningSequence.translation_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -37,6 +45,7 @@ const someFinished = computed(() => {
|
||||||
<div
|
<div
|
||||||
class="bg-white px-4 border border-gray-500 border-l-4"
|
class="bg-white px-4 border border-gray-500 border-l-4"
|
||||||
:class="{
|
:class="{
|
||||||
|
'border-l-green-500': allFinished,
|
||||||
'border-l-sky-500': someFinished,
|
'border-l-sky-500': someFinished,
|
||||||
'border-l-gray-500': !someFinished,
|
'border-l-gray-500': !someFinished,
|
||||||
}"
|
}"
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,21 @@ export class Circle implements LearningWagtailPage {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public allFinishedInLearningSequence(translationKey: string): boolean {
|
||||||
|
if (translationKey) {
|
||||||
|
const finishedContents = this.flatChildren.filter((lc) => {
|
||||||
|
return lc.completed && lc.parentLearningSequence?.translation_key === translationKey;
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
const totalContents = this.flatChildren.filter((lc) => {
|
||||||
|
return lc.parentLearningSequence?.translation_key === translationKey;
|
||||||
|
}).length;
|
||||||
|
return finishedContents === totalContents
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public parseCompletionData(completionData: CircleCompletion[]) {
|
public parseCompletionData(completionData: CircleCompletion[]) {
|
||||||
this.flatChildren.forEach((page) => {
|
this.flatChildren.forEach((page) => {
|
||||||
const pageIndex = completionData.findIndex((e) => {
|
const pageIndex = completionData.findIndex((e) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue