Backend endpoint makes it easier consume for graph.
New endpoint has the data aggregated so we don't need to do as much in js. Also added simple year select when we have data spanning multiple years.
This commit is contained in:
		| @@ -2,19 +2,95 @@ | |||||||
|   <div class="chart"> |   <div class="chart"> | ||||||
|     <canvas ref="purchase-chart" width="100" height="50"></canvas> |     <canvas ref="purchase-chart" width="100" height="50"></canvas> | ||||||
|     <div ref="chartjsLegend" class="chartjsLegend"></div> |     <div ref="chartjsLegend" class="chartjsLegend"></div> | ||||||
|  |     <div class="year-select" v-if="years.length"> | ||||||
|  |       <button | ||||||
|  |         class="vin-button small" | ||||||
|  |         v-for="year in years" | ||||||
|  |         :class="{ active: yearSelected == year }" | ||||||
|  |         @click="yearFilterClicked(year)" | ||||||
|  |       > | ||||||
|  |         {{ year }} | ||||||
|  |       </button> | ||||||
|  |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import Chartjs from "chart.js"; | import Chartjs from "chart.js"; | ||||||
| import { chartPurchaseByColor } from "@/api"; |  | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       lotteries: [], | ||||||
|  |       years: [], | ||||||
|  |       yearSelected: undefined, | ||||||
|  |       chart: undefined | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|   async mounted() { |   async mounted() { | ||||||
|     let canvas = this.$refs["purchase-chart"].getContext("2d"); |     let canvas = this.$refs["purchase-chart"].getContext("2d"); | ||||||
|  |  | ||||||
|     let response = await chartPurchaseByColor(); |     this.lotteries = await this.chartPurchaseByColor(); | ||||||
|     let labels = []; |     if (this.lotteries?.length) this.years = [...new Set(this.lotteries.map(lot => lot.date.slice(0, 4)))]; | ||||||
|  |  | ||||||
|  |     const dataset = this.calculateChartDatapoints(); | ||||||
|  |  | ||||||
|  |     let chartData = { | ||||||
|  |       labels: dataset.labels, | ||||||
|  |       datasets: [dataset.blue, dataset.green, dataset.red, dataset.yellow] | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     this.chart = new Chart(canvas, { | ||||||
|  |       type: "line", | ||||||
|  |       data: chartData, | ||||||
|  |       options: { | ||||||
|  |         maintainAspectRatio: false, | ||||||
|  |         animation: { | ||||||
|  |           duration: 0 // general animation time | ||||||
|  |         }, | ||||||
|  |         title: { | ||||||
|  |           display: true, | ||||||
|  |           text: "Antall kjøpt", | ||||||
|  |           fontSize: 20 | ||||||
|  |         }, | ||||||
|  |         legend: { | ||||||
|  |           display: true, | ||||||
|  |           boxWidth: 3, | ||||||
|  |           usePointStyle: true, | ||||||
|  |           borderRadius: 10, | ||||||
|  |           labels: { | ||||||
|  |             padding: 12, | ||||||
|  |             boxWidth: 20, | ||||||
|  |             usePointStyle: true | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         scales: { | ||||||
|  |           yAxes: [ | ||||||
|  |             { | ||||||
|  |               ticks: { | ||||||
|  |                 beginAtZero: true | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           ] | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     async yearFilterClicked(year) { | ||||||
|  |       this.yearSelected = this.yearSelected === year ? null : year; | ||||||
|  |  | ||||||
|  |       this.lotteries = await this.chartPurchaseByColor(); | ||||||
|  |       const dataset = this.calculateChartDatapoints(); | ||||||
|  |       let chartData = { | ||||||
|  |         labels: dataset.labels, | ||||||
|  |         datasets: [dataset.blue, dataset.green, dataset.red, dataset.yellow] | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       this.chart.data = chartData; | ||||||
|  |       this.chart.update(); | ||||||
|  |     }, | ||||||
|  |     setupDataset() { | ||||||
|       let blue = { |       let blue = { | ||||||
|         label: "Blå", |         label: "Blå", | ||||||
|         borderColor: "#57d2fb", |         borderColor: "#57d2fb", | ||||||
| @@ -44,86 +120,39 @@ export default { | |||||||
|         data: [] |         data: [] | ||||||
|       }; |       }; | ||||||
|  |  | ||||||
|     if (response.length == 1) { |       return { | ||||||
|       labels.push(""); |         labels: [""], | ||||||
|       blue.data.push(0); |         blue, | ||||||
|       yellow.data.push(0); |         green, | ||||||
|       red.data.push(0); |         red, | ||||||
|       green.data.push(0); |         yellow | ||||||
|     } |  | ||||||
|  |  | ||||||
|     let highestNumber = 0; |  | ||||||
|  |  | ||||||
|     for (let i = 0; i < response.length; i++) { |  | ||||||
|       let thisDate = response[i]; |  | ||||||
|       let dateObject = new Date(thisDate.date); |  | ||||||
|       labels.push(this.getPrettierDateString(dateObject)); |  | ||||||
|  |  | ||||||
|       blue.data.push(thisDate.blue); |  | ||||||
|       yellow.data.push(thisDate.yellow); |  | ||||||
|       red.data.push(thisDate.red); |  | ||||||
|       green.data.push(thisDate.green); |  | ||||||
|  |  | ||||||
|       if (thisDate.blue > highestNumber) { |  | ||||||
|         highestNumber = thisDate.blue; |  | ||||||
|       } |  | ||||||
|       if (thisDate.yellow > highestNumber) { |  | ||||||
|         highestNumber = thisDate.yellow; |  | ||||||
|       } |  | ||||||
|       if (thisDate.green > highestNumber) { |  | ||||||
|         highestNumber = thisDate.green; |  | ||||||
|       } |  | ||||||
|       if (thisDate.red > highestNumber) { |  | ||||||
|         highestNumber = thisDate.red; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     let datasets = [blue, yellow, green, red]; |  | ||||||
|     let chartdata = { |  | ||||||
|       labels: labels, |  | ||||||
|       datasets: datasets |  | ||||||
|       }; |       }; | ||||||
|     let chart = new Chart(canvas, { |  | ||||||
|       type: "line", |  | ||||||
|       data: chartdata, |  | ||||||
|       options: { |  | ||||||
|         maintainAspectRatio: false, |  | ||||||
|         animation: { |  | ||||||
|           duration: 0 // general animation time |  | ||||||
|     }, |     }, | ||||||
|         title: { |     calculateChartDatapoints() { | ||||||
|           display: true, |       let dataset = this.setupDataset(); | ||||||
|           text: "Antall kjøpt", |  | ||||||
|           fontSize: 20 |       this.lotteries.map(lottery => { | ||||||
|         }, |         const date = new Date(lottery.date); | ||||||
|         legend: { |         dataset.labels.push(this.getPrettierDateString(date)); | ||||||
|           display: true, |  | ||||||
|           boxWidth: 3, |         dataset.blue.data.push(lottery.blue); | ||||||
|           usePointStyle: true, |         dataset.green.data.push(lottery.green); | ||||||
|           borderRadius: 10, |         dataset.red.data.push(lottery.red); | ||||||
|           labels: { |         dataset.yellow.data.push(lottery.yellow); | ||||||
|             padding: 12, |  | ||||||
|             boxWidth: 20, |  | ||||||
|             usePointStyle: true |  | ||||||
|           } |  | ||||||
|         }, |  | ||||||
|         scales: { |  | ||||||
|           yAxes: [ |  | ||||||
|             { |  | ||||||
|               ticks: { |  | ||||||
|                 beginAtZero: true, |  | ||||||
|                 suggestedMax: highestNumber + 5 |  | ||||||
|               } |  | ||||||
|             } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  |       return dataset; | ||||||
|  |     }, | ||||||
|  |     chartPurchaseByColor() { | ||||||
|  |       const url = new URL("/api/lotteries", window.location); | ||||||
|  |       if (this.yearSelected != null) url.searchParams.set("year", this.yearSelected); | ||||||
|  |  | ||||||
|  |       return fetch(url.href) | ||||||
|  |         .then(resp => resp.json()) | ||||||
|  |         .then(response => response.lotteries); | ||||||
|     }, |     }, | ||||||
|   methods: { |  | ||||||
|     getPrettierDateString(date) { |     getPrettierDateString(date) { | ||||||
|       return `${this.pad(date.getDate())}.${this.pad( |       return `${this.pad(date.getDate())}.${this.pad(date.getMonth() + 1)}.${this.pad(date.getYear() - 100)}`; | ||||||
|         date.getMonth() + 1 |  | ||||||
|       )}.${this.pad(date.getYear() - 100)}`; |  | ||||||
|     }, |     }, | ||||||
|     pad(num) { |     pad(num) { | ||||||
|       if (num < 10) { |       if (num < 10) { | ||||||
| @@ -136,11 +165,19 @@ export default { | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
| @import "../styles/media-queries.scss"; | @import "@/styles/media-queries.scss"; | ||||||
|  |  | ||||||
| .chart { | .chart { | ||||||
|   height: 40vh; |   height: 40vh; | ||||||
|   max-height: 500px; |   max-height: 500px; | ||||||
|   width: 100%; |   width: 100%; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .year-select { | ||||||
|  |   margin-top: 1rem; | ||||||
|  |  | ||||||
|  |   button:not(:first-of-type) { | ||||||
|  |     margin-left: 0.5rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user