first viable version

This commit is contained in:
Lorenz Padberg 2022-06-30 11:02:52 +02:00
parent 20c85dc6fc
commit c9cc2c2cb6
2 changed files with 132 additions and 144 deletions

View File

@ -1,8 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import * as d3 from "d3"; import * as d3 from "d3";
import {computed, onMounted, reactive, ref} from "vue"; import {computed, onMounted} from "vue";
import * as _ from 'underscore' import * as _ from 'underscore'
import {useCircleStore} from "@/stores/circle";
const props = defineProps<{ const props = defineProps<{
circleStore: {}, circleStore: {},
@ -21,15 +20,15 @@ const props = defineProps<{
function someFinished(learningSequence) { function someFinished(learningSequence) {
return props.circleStore.flatChildren.filter((lc) => { return props.circleStore.flatChildren.filter((lc) => {
return lc.completed && lc.parentLearningSequence?.translation_key === learningSequence.translation_key; return lc.completed && lc.parentLearningSequence?.translation_key === learningSequence.translation_key;
}).length > 0; }).length > 0;
} }
const pieData = computed(() => { const pieData = computed(() => {
const circle = props.circleStore.circleData, completionData = props.circleStore.completionData const circle = props.circleStore.circleData, completionData = props.circleStore.completionData
console.log('initial of compute pie data ', circle, completionData) console.log('initial of compute pie data ', circle, completionData)
if (circle && completionData) { if (circle && completionData) {
console.log('initial of compute pie data ', circle, completionData) console.log('initial of compute pie data ', circle, completionData)
@ -38,7 +37,6 @@ const pieData = computed(() => {
}) })
const completionDataByPageId = _.object(_.map(completionData, function (item) { const completionDataByPageId = _.object(_.map(completionData, function (item) {
console.log(item)
return [item.page_key, item] return [item.page_key, item]
})) }))
@ -53,7 +51,6 @@ const pieData = computed(() => {
pie.endAngle = pie.endAngle + Math.PI pie.endAngle = pie.endAngle + Math.PI
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
console.log(someFinished(thisLearningSequence))
pie.done = someFinished(thisLearningSequence) pie.done = someFinished(thisLearningSequence)
}) })
angles = angles.reverse() angles = angles.reverse()
@ -64,169 +61,158 @@ const pieData = computed(() => {
const blue900 = '#00224D', const blue900 = '#00224D',
blue700 = '#1A5197', blue700 = '#1A5197',
gray100 = '#EDF2F6', gray100 = '#EDF2F6',
gray300 = '#E0E5EC', gray300 = '#E0E5EC',
gray500 = '#B1C1CA', gray500 = '#B1C1CA',
sky400 = '#72CAFF', sky400 = '#72CAFF',
sky500 = '#41B5FA' sky500 = '#41B5FA'
const svg = computed(() => { const render = computed(() => {
})
const render = computed( () => {
const width = 450, //props.width, const width = 450, //props.width,
height = 450, //props.height, height = 450, //props.height,
radius: number = Math.min(width, height) / 2.4, radius: number = Math.min(width, height) / 2.4,
arrowStrokeWidth = 2 arrowStrokeWidth = 2
const svg = d3.select('.circle-visualization')
.attr('width', width)
.attr('height', height)
// Append markter as definition to the svg
svg.append("svg:defs").append("svg:marker")
.attr("id", "triangle")
.attr("refX", 11)
.attr("refY", 11)
.attr("markerWidth", 20)
.attr("markerHeight", 20)
.attr("markerUnits", "userSpaceOnUse")
.attr("orient", "auto")
.append("path")
.attr("d", "M -1 0 l 10 0 M 0 -1 l 0 10")
.attr('transform', 'rotate(-90, 10, 0)')
.attr('stroke-width', arrowStrokeWidth)
.attr('stroke', gray500)
const g = svg.append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
const svg = d3.select('.circle-visualization') // Generate the pie diagram wede
.attr('width', width) const wedgeGenerator = d3
.attr('height', height) .arc()
.innerRadius(radius / 2.5)
// Append markter as definition to the svg .padAngle(12 / 360)
svg.append("svg:defs").append("svg:marker") .outerRadius(radius)
.attr("id", "triangle")
.attr("refX", 11)
.attr("refY", 11)
.attr("markerWidth", 20)
.attr("markerHeight", 20)
.attr("markerUnits", "userSpaceOnUse")
.attr("orient", "auto")
.append("path")
.attr("d", "M -1 0 l 10 0 M 0 -1 l 0 10")
.attr('transform', 'rotate(-90, 10, 0)')
.attr('stroke-width', arrowStrokeWidth)
.attr('stroke', gray500)
const g = svg.append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
// Generate the arrows
const arrowRadius = radius * 1.1
// Generate the pie diagram wede const learningSequences = g.selectAll('.learningSegmentArc').data(pieData.value).enter().append('g')
const wedgeGenerator = d3 .attr('class', 'learningSegmentArc')
.arc() .attr('role', 'button')
.innerRadius(radius / 2.5) .attr('fill', gray300)
.padAngle(12 / 360)
.outerRadius(radius)
// Generate the arrows learningSequences
const arrowRadius = radius * 1.1 .on('mouseover', function (d, i) {
d3.select(this)
.transition()
.duration('200')
.attr('fill', (d) => {
return d.done ? sky400 : gray100
})
})
.on('mouseout', function (d, i) {
d3.select(this)
.transition()
.duration('200')
.attr('fill', (d) => {
return d.done ? sky500 : gray300
})
})
learningSequences
.transition()
.duration('1')
.attr('fill', (d) => {
return d.done ? sky500 : gray300
})
const learningSequences = g.selectAll('.learningSegmentArc').data(pieData.value).enter().append('g') learningSequences.append('path').attr('d', wedgeGenerator)
.attr('class', 'learningSegmentArc')
.attr('role', 'button')
.attr('fill', gray300)
learningSequences const learningSequenceText = learningSequences
.on('mouseover', function (d, i) { .append('text')
d3.select(this) .attr('fill', blue900)
.transition() .style('font-size', 15)
.duration('200') .text((d) => {
.attr('fill', (d) => { return d.title
return d.done ? sky400 : gray100 })
}) .attr("transform", function (d) {
let translate = wedgeGenerator.centroid(d)
translate = [translate[0], translate[1] + 20]
return "translate(" + translate + ")";
})
.attr('class', 'circlesText text-xl font-bold')
.style('text-anchor', 'middle')
}) const iconWidth = 25
.on('mouseout', function (d, i) {
d3.select(this)
.transition()
.duration('200')
.attr('fill', (d) => {
return d.done ? sky500 : gray300
})
})
learningSequences const learningSequenceIcon = learningSequences.append("svg:image")
.transition() .attr("xlink:href", (d) => {
.duration('1000') return "/static/icons/" + d.icon.replace("it-", "") + ".svg"
.attr('fill', (d) => { })
return d.done ? sky500 : gray300 .attr("width", iconWidth)
}) .attr("height", iconWidth)
.attr("transform", function (d) {
let translate = wedgeGenerator.centroid(d)
translate = [translate[0] - iconWidth / 2, translate[1] - iconWidth]
return "translate(" + translate + ")";
})
learningSequences.append('path').attr('d', wedgeGenerator) // Create Arrows
const arrow = d3
.arc()
.innerRadius(arrowRadius)
.outerRadius(arrowRadius + arrowStrokeWidth)
.padAngle(20 / 360)
.startAngle(d => {
return d.arrowStartAngle
})
.endAngle(d => {
return d.arrowEndAngle
})
const learningSequenceText = learningSequences const arrows = g
.append('text') .selectAll('.arrow')
.attr('fill', blue900) .data(pieData.value)
.style('font-size', 15) .join('g')
.text((d) => { .attr('class', 'arrow')
return d.title .attr('marker-end', 'url(#triangle)')
})
.attr("transform", function (d) {
let translate = wedgeGenerator.centroid(d)
translate = [translate[0], translate[1] + 20]
return "translate(" + translate + ")";
})
.attr('class', 'circlesText text-xl font-bold')
.style('text-anchor', 'middle')
const iconWidth = 25 // remove last arrow
d3.selection.prototype.last = function () {
const learningSequenceIcon = learningSequences.append("svg:image") let last = this.size() - 1;
.attr("xlink:href", (d) => { return d3.select(this.nodes()[last]);
return "/static/icons/" + d.icon.replace("it-", "") + ".svg" };
})
.attr("width", iconWidth)
.attr("height", iconWidth)
.attr("transform", function (d) {
let translate = wedgeGenerator.centroid(d)
translate = [translate[0] - iconWidth / 2, translate[1] - iconWidth]
return "translate(" + translate + ")";
})
// Create Arrows const all_arows = g.selectAll('.arrow')
const arrow = d3 all_arows.last().remove()
.arc()
.innerRadius(arrowRadius)
.outerRadius(arrowRadius + arrowStrokeWidth)
.padAngle(20 / 360)
.startAngle(d => {
return d.arrowStartAngle
})
.endAngle(d => {
return d.arrowEndAngle
})
//Draw arrow paths
const arrows = g arrows.append('path').attr('fill', gray500).attr('d', arrow)
.selectAll('.arrow')
.data(pieData.value)
.join('g')
.attr('class', 'arrow')
.attr('marker-end', 'url(#triangle)')
// remove last arrow
d3.selection.prototype.last = function () {
let last = this.size() - 1;
return d3.select(this.nodes()[last]);
};
const all_arows = g.selectAll('.arrow')
all_arows.last().remove()
//Draw arrow paths
arrows.append('path').attr('fill', gray500).attr('d', arrow)
return svg return svg
}) })
onMounted(async () => {
}
);
function viewBox() { function viewBox() {
@ -239,10 +225,12 @@ function viewBox() {
<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>
<pre> </pre> <pre> </pre>
<svg class="circle-visualization h-full" :viewBox="viewBox"> <svg class="circle-visualization h-full" :viewBox="viewBox">
<circle v-if="! pieData" cx="50" cy="50" r="50"/>
</svg> </svg>
</div> </div>
</template> </template>

View File

@ -45,7 +45,7 @@ onMounted(async () => {
{{ circleStore.circleData.title }} {{ circleStore.circleData.title }}
</h1> </h1>
<div v-if="circleStore.circleData.learningSequences && circleStore.completionData" class="w-full mt-8"> <div v-if="circleStore.circleData.learningSequences && circleStore.flatChildren" class="w-full mt-8">
<CircleDiagram :circle-store="circleStore"></CircleDiagram> <CircleDiagram :circle-store="circleStore"></CircleDiagram>
</div> </div>