Added pie chart showing counts of categories with a rating of 3 or below

This commit is contained in:
neviyn 2018-12-13 12:50:28 +00:00
parent cbfddfe8c1
commit 39de14caf6
4 changed files with 89 additions and 9 deletions

View File

@ -49,3 +49,17 @@ data class ChartDataset(
) { ) {
constructor(label: String, color: String, data: List<Double>) : this(label, color, color, data) constructor(label: String, color: String, data: List<Double>) : this(label, color, color, data)
} }
data class AfiPieChart(
val labels: List<String> = listOf("Monitoring", "Knowledge", "Control", "Conservatism", "Teamwork"),
val datasets: List<AfiPieChartDataset>
) {
constructor(afiPieChartDataset: AfiPieChartDataset) : this(datasets = listOf(afiPieChartDataset))
}
data class AfiPieChartDataset(
val data: List<Int>,
val backgroundColor: List<String> = listOf("#F90", "#000", "#00FF00", "#33F", "#FF0")
) {
constructor(monitoring: Int, knowledge: Int, control: Int, conservatism: Int, teamwork: Int) : this(data = listOf(monitoring, knowledge, control, conservatism, teamwork))
}

View File

@ -190,6 +190,39 @@ class Controller {
} }
return builder.toString() return builder.toString()
} }
val afiPieThreshold = 3
@PostMapping("/observations/afipie")
fun getObservationsAfiPieChartData(@Valid @RequestBody observationsRequest: ObservationsRequest): AfiPieChart? {
val data = getObservations(observationsRequest)
var monitoring = 0
var knowledge = 0
var control = 0
var conservatism = 0
var teamwork = 0
for (x in data) {
for (y in x.scenarios) {
if (y.monitoring.rating <= afiPieThreshold)
monitoring++
if (y.knowledge.rating <= afiPieThreshold)
knowledge++
if (y.control.rating <= afiPieThreshold)
control++
if (y.controlProcedural.rating <= afiPieThreshold)
control++
if (y.conservatism.rating <= afiPieThreshold)
conservatism++
if (y.teamworkCommunications.rating <= afiPieThreshold)
teamwork++
if (y.teamworkLeadership.rating <= afiPieThreshold)
teamwork++
if (y.teamworkWorkload.rating <= afiPieThreshold)
teamwork++
}
}
return AfiPieChart(AfiPieChartDataset(monitoring, knowledge, control, conservatism, teamwork))
}
} }
data class AverageData( data class AverageData(

View File

@ -0,0 +1,12 @@
<script>
import { Pie, mixins } from "vue-chartjs";
export default {
extends: Pie,
mixins: [mixins.reactiveProp],
props: ["chartData", "options"],
mounted() {
this.renderChart(this.chartData, this.options);
}
};
</script>

View File

@ -13,6 +13,10 @@
</button> </button>
</div> </div>
</b-modal> </b-modal>
<b-row>
<b-col><b-button @click="chartMode = 0; getFilteredAverage()">Trends</b-button></b-col>
<b-col><b-button @click="chartMode = 1; getFilteredAverage()">AFIs</b-button></b-col>
</b-row>
<b-row> <b-row>
<b-col> <b-col>
<b-form-group label="Site"> <b-form-group label="Site">
@ -49,12 +53,20 @@
<b-button v-on:click="getFilteredAverage()">Refresh</b-button> <b-button v-on:click="getFilteredAverage()">Refresh</b-button>
</b-col> </b-col>
</b-row> </b-row>
<b-row> <b-row v-if="chartData != null && chartData.labels.length > 0 && !loading">
<b-col v-if="chartData != null && chartData.labels.length > 0"> <b-col v-if="chartMode == 0">
<stats-view v-bind:chartData="chartData" <stats-view v-bind:chartData="chartData"
style="position: relative; height:80vh" :options="options"/> style="position: relative; height:80vh" :options="options"/>
</b-col> </b-col>
<b-col v-else> <b-col v-else-if="chartMode == 1">
<afi-pie :chartData="chartData" :options="pieOptions"/>
</b-col>
</b-row>
<b-row v-else-if="loading">
Loading...
</b-row>
<b-row v-else>
<b-col>
<v-icon name="search"></v-icon> <v-icon name="search"></v-icon>
<p>No data found with the given search parameters.</p> <p>No data found with the given search parameters.</p>
</b-col> </b-col>
@ -65,6 +77,7 @@
<script> <script>
import Vue from "vue"; import Vue from "vue";
import StatsView from "../components/StatsView"; import StatsView from "../components/StatsView";
import AfiPie from "../components/AfiPie"
import "vue-awesome/icons/exclamation-circle"; import "vue-awesome/icons/exclamation-circle";
import "vue-awesome/icons/search"; import "vue-awesome/icons/search";
@ -73,9 +86,12 @@ var moment = require("moment");
export default { export default {
name: "stats", name: "stats",
title: "Statistics", title: "Statistics",
components: { StatsView }, components: { StatsView, AfiPie },
data: function() { data: function() {
return { return {
chartMode: 0,
endpoints: ["/observations/chartdata", "/observations/afipie"],
loading: false,
chartData: null, chartData: null,
options: { options: {
responsive: true, responsive: true,
@ -110,6 +126,9 @@ export default {
] ]
} }
}, },
pieOptions:{
maintainAspectRatio: false
},
errorStatus: null, errorStatus: null,
errorMessage: null, errorMessage: null,
dateOptions: { dateOptions: {
@ -172,8 +191,9 @@ export default {
}, },
methods: { methods: {
getFilteredAverage: function() { getFilteredAverage: function() {
this.loading = true;
Vue.axios Vue.axios
.post("/observations/chartdata", { .post(this.endpoints[this.chartMode], {
site: this.siteSelection, site: this.siteSelection,
tutor: this.tutorSelection, tutor: this.tutorSelection,
startDate: moment(this.startDate).format("YYYY-MM-DD"), startDate: moment(this.startDate).format("YYYY-MM-DD"),
@ -183,11 +203,13 @@ export default {
}) })
.then(response => { .then(response => {
this.chartData = response.data; this.chartData = response.data;
this.loading = false;
}) })
.catch(error => { .catch(error => {
this.errorStatus = error.response.status; this.errorStatus = error.response.status;
this.errorMessage = error.response.data; this.errorMessage = error.response.data;
this.$refs.errorModal.show(); this.$refs.errorModal.show();
this.loading = false;
}); });
}, },
getTutors: function() { getTutors: function() {
@ -216,7 +238,6 @@ export default {
} }
}, },
mounted() { mounted() {
this.getFilteredAverage();
Vue.axios Vue.axios
.get("/site") .get("/site")
.then(response => { .then(response => {