From 0316761c10f0744165a7e9940db00bb82f77a80c Mon Sep 17 00:00:00 2001 From: legonzaur Date: Tue, 28 Mar 2023 16:52:39 +0200 Subject: [PATCH] add some design to the app --- package-lock.json | 9 +++ package.json | 1 + src/App.vue | 70 ++++++++++++++++--- src/components/PlayerChart.vue | 59 +++++++++++++--- src/components/PlayerList.vue | 124 ++++++++++++++++++++++++++++----- src/store/index.ts | 11 ++- src/views/PlayerView.vue | 47 ++++++++----- 7 files changed, 267 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56fc935..47d43ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "chart.js": "^4.2.1", "chartjs-plugin-annotation": "^2.2.1", + "chartjs-plugin-datalabels": "^2.2.0", "core-js": "^3.8.3", "vue": "^3.2.13", "vue-chartjs": "^5.2.0", @@ -4385,6 +4386,14 @@ "chart.js": ">=3.7.0" } }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", diff --git a/package.json b/package.json index f42025f..3aa0dc5 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "chart.js": "^4.2.1", "chartjs-plugin-annotation": "^2.2.1", + "chartjs-plugin-datalabels": "^2.2.0", "core-js": "^3.8.3", "vue": "^3.2.13", "vue-chartjs": "^5.2.0", diff --git a/src/App.vue b/src/App.vue index 38d6182..8b091fc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,31 +1,81 @@ diff --git a/src/components/PlayerChart.vue b/src/components/PlayerChart.vue index ce347e7..b994dfc 100644 --- a/src/components/PlayerChart.vue +++ b/src/components/PlayerChart.vue @@ -14,19 +14,22 @@ import { Legend } from 'chart.js' import annotationPlugin from 'chartjs-plugin-annotation' +import dataLabel from 'chartjs-plugin-datalabels' import { Store, useStore } from 'vuex' import { Player, Weapon } from '@/store/index' import { Scatter } from 'vue-chartjs' import { defineComponent } from 'vue' -ChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend, annotationPlugin) +ChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend, annotationPlugin, dataLabel) export default defineComponent({ name: 'PlayerChart', props: { - filters: Object + filters: Object, + playerHighlighted: String }, + emits: ['highlightPlayer'], components: { Scatter }, @@ -37,10 +40,11 @@ export default defineComponent({ { label: 'Players', labels: [] as string[], - borderColor: '#f87979', + borderColor: ['#f87979'], backgroundColor: '#f87979', pointRadius: [1], pointStyle: ['dot'], + hoverRadius: [4], data: [] as {x:number, y:number}[] } ] @@ -55,13 +59,24 @@ export default defineComponent({ } return { x: this.players[e].deaths, y: this.players[e].kills } }) - chartData.datasets[0].pointRadius = [1].fill(1, 0, chartData.datasets[0].labels.length) - chartData.datasets[0].pointStyle = ['dot'].fill('dot', 0, chartData.datasets[0].labels.length) + chartData.datasets[0].pointRadius = Array(chartData.datasets[0].labels.length).fill(1) + chartData.datasets[0].pointStyle = Array(chartData.datasets[0].labels.length).fill('dot') + chartData.datasets[0].borderColor = Array(chartData.datasets[0].labels.length).fill('darkblue') + chartData.datasets[0].hoverRadius = Array(chartData.datasets[0].labels.length).fill(4) + if (this.$props.playerHighlighted) { + const index = this.playerIdList.indexOf(this.$props.playerHighlighted) + chartData.datasets[0].pointRadius[index] = 20 + chartData.datasets[0].pointStyle[index] = 'crossRot' + chartData.datasets[0].borderColor[index] = 'red' + chartData.datasets[0].hoverRadius[index] = 30 + } return chartData }, chartOptions () { const options = { responsive: true, + maintainAspectRatio: true, + animation: { duration: 500 }, plugins: { tooltip: { callbacks: { @@ -77,7 +92,27 @@ export default defineComponent({ } } }, - annotation: {} + annotation: {}, + datalabels: { + formatter: (value:any, context:any) => { + return this.players[this.playerIdList[context.dataIndex]].username + }, + backgroundColor: Array(this.playerIdList.length).fill(null), + borderColor: 'black', + borderWidth: Array(this.playerIdList.length).fill(0), + borderRadius: 5, + display: Array(this.playerIdList.length).fill('auto'), + align: '-45', + anchor: 'end', + clamp: true + } + }, + onClick: (e:Event, element:any) => { + this.$emit('highlightPlayer', element.length > 0 ? this.playerIdList[element[0].index] : undefined) + }, + onHover: (e:any, element:any) => { + if (!e.native.target) return + (e.native.target as HTMLElement).style.cursor = element[0] ? 'pointer' : 'default' } } if (!this.players) { @@ -107,9 +142,16 @@ export default defineComponent({ } } } + + if (this.$props.playerHighlighted) { + const index = this.playerIdList.indexOf(this.$props.playerHighlighted) + options.plugins.datalabels.display[index] = true + options.plugins.datalabels.backgroundColor[index] = 'red' + options.plugins.datalabels.borderWidth[index] = 1 + } return options }, - players ():{[key:string]:Player} { return this.store.getters.getPlayerList(this.filters) }, + players ():{[key:string]:Player} { return this.store.getters.getPlayerList(this.filters) || {} }, playerIdList ():string[] { return Object.keys(this.players) } }, @@ -123,8 +165,5 @@ export default defineComponent({ diff --git a/src/components/PlayerList.vue b/src/components/PlayerList.vue index 9617735..79a26ba 100644 --- a/src/components/PlayerList.vue +++ b/src/components/PlayerList.vue @@ -1,6 +1,7 @@