feat: add rating colors
This commit is contained in:
parent
dfe1bfb845
commit
3664ddf6d7
|
|
@ -28,10 +28,6 @@ defineProps<{
|
|||
<span>{{ $t("a.Durchführungen") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO Figure out where this link should go -->
|
||||
<!-- <router-link class="btn-secondary" to="#">-->
|
||||
<!-- {{ $t("a.Liste anzeigen") }}-->
|
||||
<!-- </router-link>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,29 @@
|
|||
<script setup lang="ts">
|
||||
import BaseBox from "@/components/dashboard/BaseBox.vue";
|
||||
import { getBlendedColorForRating } from "@/utils/ratingToColor";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
feedbackCount: number;
|
||||
statisfactionMax: number;
|
||||
statisfactionAvg: number;
|
||||
}>();
|
||||
|
||||
const satisfactionColor = computed(() => {
|
||||
return getBlendedColorForRating(props.statisfactionAvg);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseBox :details-link="'/statistic/feedback'">
|
||||
<template #title>{{ $t("a.Feedback Teilnehmer") }}</template>
|
||||
<template #content>
|
||||
<div class="flex">
|
||||
<div class="flex items-center">
|
||||
<!-- Left Pane -->
|
||||
<div class="flex h-16 w-32 items-center justify-center rounded bg-green-500">
|
||||
<div
|
||||
class="mr-3 flex items-center justify-center rounded p-4"
|
||||
:style="{ backgroundColor: satisfactionColor }"
|
||||
>
|
||||
<i18next :translation="$t('a.{AVG} von {MAX}')">
|
||||
<template #AVG>
|
||||
<span class="pr-2 text-4xl font-bold">
|
||||
|
|
@ -27,7 +36,7 @@ const props = defineProps<{
|
|||
</i18next>
|
||||
</div>
|
||||
<!-- Right Pane -->
|
||||
<div class="flex flex-col items-center space-y-1 p-2">
|
||||
<div class="flex flex-col items-center space-y-1">
|
||||
<span class="font-bold">{{ $t("a.Allgemeine Zufriedenheit") }}</span>
|
||||
<div class="self-start">
|
||||
<i18next :translation="$t('a.Total {NUMBER} Antworten')">
|
||||
|
|
|
|||
|
|
@ -77,15 +77,10 @@ import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue";
|
|||
import { computed } from "vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import log from "loglevel";
|
||||
import { getBlendedColorForRating } from "@/utils/ratingToColor";
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
type RGB = [number, number, number];
|
||||
const red: RGB = [221, 103, 81]; // red-600
|
||||
const yellow: RGB = [250, 200, 82]; // yellow-500
|
||||
const lightGreen: RGB = [120, 222, 163]; // green-500
|
||||
const darkGreen: RGB = [91, 183, 130]; // green-600
|
||||
|
||||
const legends = [
|
||||
{ index: 1, label: t("feedback.veryUnhappy") },
|
||||
{ index: 2, label: t("feedback.unhappy") },
|
||||
|
|
@ -101,19 +96,11 @@ const props = defineProps<{
|
|||
|
||||
log.debug("RatingScale created", props);
|
||||
|
||||
const rating = computed((): number => {
|
||||
const rating = computed(() => {
|
||||
const sum = props.ratings.reduce((a, b) => a + b, 0);
|
||||
return sum / props.ratings.length;
|
||||
});
|
||||
|
||||
const weight = computed(() => {
|
||||
return rating.value % 1;
|
||||
});
|
||||
|
||||
const scale = computed(() => {
|
||||
return Math.floor(rating.value);
|
||||
});
|
||||
|
||||
const answers = computed(() => props.ratings.length);
|
||||
|
||||
const numberOfRatings = computed(() => {
|
||||
|
|
@ -122,57 +109,14 @@ const numberOfRatings = computed(() => {
|
|||
);
|
||||
});
|
||||
|
||||
const colors = computed(() => {
|
||||
switch (scale.value) {
|
||||
case 1:
|
||||
return [red, yellow];
|
||||
case 2:
|
||||
return [yellow, lightGreen];
|
||||
case 3:
|
||||
default:
|
||||
return [lightGreen, darkGreen];
|
||||
}
|
||||
});
|
||||
|
||||
const blendColorValue = (v1: number, v2: number, weight: number) => {
|
||||
return v1 * (1 - weight) + v2 * weight;
|
||||
};
|
||||
|
||||
const blendColors = (c1: RGB, c2: RGB, weight: number): RGB => {
|
||||
const [r1, g1, b1] = c1;
|
||||
const [r2, g2, b2] = c2;
|
||||
return [
|
||||
blendColorValue(r1, r2, weight),
|
||||
blendColorValue(g1, g2, weight),
|
||||
blendColorValue(b1, b2, weight),
|
||||
];
|
||||
};
|
||||
|
||||
const getRGBString = ([r, g, b]: RGB) => {
|
||||
return `rgb(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)})`;
|
||||
};
|
||||
|
||||
// const getRGBStyle = (c1: RGB, c2: RGB, weight: number) => {
|
||||
// return getRGBString(blendColors(c1, c2, weight));
|
||||
// };
|
||||
|
||||
const percent = computed(() => {
|
||||
return (scale.value - 1) * 33.33 + weight.value * 33.33;
|
||||
return (Math.floor(rating.value) - 1) * 33.33 + (rating.value % 1) * 33.33;
|
||||
});
|
||||
|
||||
const leftPosition = computed(() => {
|
||||
return `${percent.value.toPrecision(3)}%`;
|
||||
});
|
||||
const leftPosition = computed(() => `${percent.value.toPrecision(3)}%`);
|
||||
const rightClip = computed(() => `${Math.round(100 - percent.value)}%`);
|
||||
|
||||
const rightClip = computed(() => {
|
||||
return `${Math.round(100 - percent.value)}%`;
|
||||
});
|
||||
|
||||
const blendedColor = computed(() => {
|
||||
return blendColors(colors.value[0], colors.value[1], weight.value);
|
||||
});
|
||||
|
||||
const backgroundColor = getRGBString(blendedColor.value);
|
||||
const backgroundColor = getBlendedColorForRating(rating.value);
|
||||
|
||||
const circleStyle = {
|
||||
backgroundColor,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type {
|
|||
} from "@/gql/graphql";
|
||||
import StatisticFilterList from "@/components/dashboard/StatisticFilterList.vue";
|
||||
import { useCourseStatistics } from "@/composables";
|
||||
import { getBlendedColorForRating } from "@/utils/ratingToColor";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
|
|
@ -50,15 +51,25 @@ const { courseSessionName, circleMeta } = useCourseStatistics();
|
|||
<div>
|
||||
<div class="mb-4 flex items-center space-x-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded bg-green-500 px-2 py-1"
|
||||
class="rounded px-2 py-1"
|
||||
:style="{ backgroundColor: getBlendedColorForRating((item as FeedbackStatisticsRecordType).satisfaction_average) }"
|
||||
>
|
||||
<span class="font-bold">
|
||||
{{ (item as FeedbackStatisticsRecordType).satisfaction_average }}
|
||||
</span>
|
||||
von
|
||||
<span>
|
||||
{{ (item as FeedbackStatisticsRecordType).satisfaction_max }}
|
||||
</span>
|
||||
<i18next :translation="$t('a.{AVG} von {MAX}')">
|
||||
<template #AVG>
|
||||
<span class="font-bold">
|
||||
{{
|
||||
(
|
||||
item as FeedbackStatisticsRecordType
|
||||
).satisfaction_average.toFixed(1)
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
<template #MAX>
|
||||
<span>
|
||||
{{ (item as FeedbackStatisticsRecordType).satisfaction_max }}
|
||||
</span>
|
||||
</template>
|
||||
</i18next>
|
||||
</div>
|
||||
<span>
|
||||
{{ $t("a.Allgemeine Zufriedenheit") }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
type RGB = [number, number, number];
|
||||
|
||||
const red: RGB = [221, 103, 81]; // red-600
|
||||
const yellow: RGB = [250, 200, 82]; // yellow-500
|
||||
const lightGreen: RGB = [120, 222, 163]; // green-500
|
||||
const darkGreen: RGB = [91, 183, 130]; // green-600
|
||||
|
||||
const blendColorValue = (v1: number, v2: number, weight: number): number => {
|
||||
return v1 * (1 - weight) + v2 * weight;
|
||||
};
|
||||
|
||||
const blendColors = (c1: RGB, c2: RGB, weight: number): RGB => {
|
||||
const [r1, g1, b1] = c1;
|
||||
const [r2, g2, b2] = c2;
|
||||
return [
|
||||
blendColorValue(r1, r2, weight),
|
||||
blendColorValue(g1, g2, weight),
|
||||
blendColorValue(b1, b2, weight),
|
||||
];
|
||||
};
|
||||
|
||||
const getRGBString = (color: RGB): string => {
|
||||
const [r, g, b] = color;
|
||||
return `rgb(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)})`;
|
||||
};
|
||||
|
||||
export const getBlendedColorForRating = (rating: number): string => {
|
||||
const scale = Math.floor(rating);
|
||||
const weight = rating % 1;
|
||||
let colors: [RGB, RGB];
|
||||
|
||||
switch (scale) {
|
||||
case 1:
|
||||
colors = [red, yellow];
|
||||
break;
|
||||
case 2:
|
||||
colors = [yellow, lightGreen];
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
colors = [lightGreen, darkGreen];
|
||||
break;
|
||||
}
|
||||
|
||||
const blendedColor = blendColors(colors[0], colors[1], weight);
|
||||
return getRGBString(blendedColor);
|
||||
};
|
||||
Loading…
Reference in New Issue