diff --git a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoLayout.razor b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoLayout.razor index 46bfa0b..81356f6 100644 --- a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoLayout.razor +++ b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoLayout.razor @@ -26,7 +26,7 @@ - + diff --git a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor index daf1538..4ef6793 100644 --- a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor +++ b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor @@ -1,3 +1,8 @@ @inherits PlayerInfoStatisticsBase -
\ No newline at end of file +
+
+
+
+
+ @*
*@ \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor.css b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor.css new file mode 100644 index 0000000..eb47927 --- /dev/null +++ b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatistics.razor.css @@ -0,0 +1,6 @@ +.chartsRow { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-around; +} diff --git a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatisticsBase.cs b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatisticsBase.cs index 74ad5f2..46efe38 100644 --- a/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatisticsBase.cs +++ b/WotBlitzStatisticsPro.Blazor/Pages/PlayerInfoStatisticsBase.cs @@ -1,5 +1,7 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.AspNetCore.Components; +using WotBlitzStatisticsPro.Blazor.GraphQl; using WotBlitzStatisticsPro.Blazor.Services; namespace WotBlitzStatisticsPro.Blazor.Pages @@ -9,11 +11,19 @@ namespace WotBlitzStatisticsPro.Blazor.Pages [Inject] public IChartsService ChartsService { get; set; } + + [Parameter] + public IEnumerable TanksList { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - await ChartsService.BuildBarChart("main"); + await ChartsService.BuildBarChartBattlesByTankType("battlesByTankType", TanksList); + await ChartsService.BuildBarChartWinRatesByTankType("winRateByTankType", TanksList); + await ChartsService.BuildBarChartAvgDmgByTankType("avgDmgByTankType", TanksList); + //await ChartsService.BuildStackedBarChart("stacked"); } } } diff --git a/WotBlitzStatisticsPro.Blazor/Resources/App.de.resx b/WotBlitzStatisticsPro.Blazor/Resources/App.de.resx index e57f177..f8a4425 100644 --- a/WotBlitzStatisticsPro.Blazor/Resources/App.de.resx +++ b/WotBlitzStatisticsPro.Blazor/Resources/App.de.resx @@ -123,9 +123,15 @@ Mittlere EP + + Mittlerer Schaden dem Panzertype + Gefechte + + Gefechte dem Panzertype + Abbrechen @@ -216,6 +222,9 @@ Sieg + + Panzertypensieg + vor Jahren diff --git a/WotBlitzStatisticsPro.Blazor/Resources/App.ru.resx b/WotBlitzStatisticsPro.Blazor/Resources/App.ru.resx index a2c451a..d35deb5 100644 --- a/WotBlitzStatisticsPro.Blazor/Resources/App.ru.resx +++ b/WotBlitzStatisticsPro.Blazor/Resources/App.ru.resx @@ -123,9 +123,15 @@ Средний опыт + + Средний урон по типу танка + Количество боёв + + Количество боёв по типу танка + Отмена @@ -216,6 +222,9 @@ Процент побед + + Процент побед по типу танка + лет назад diff --git a/WotBlitzStatisticsPro.Blazor/Services/ChartService.cs b/WotBlitzStatisticsPro.Blazor/Services/ChartService.cs index 844362c..3022639 100644 --- a/WotBlitzStatisticsPro.Blazor/Services/ChartService.cs +++ b/WotBlitzStatisticsPro.Blazor/Services/ChartService.cs @@ -1,20 +1,209 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; using Microsoft.JSInterop; +using WotBlitzStatisticsPro.Blazor.GraphQl; +using WotBlitzStatisticsPro.Blazor.Helpers; namespace WotBlitzStatisticsPro.Blazor.Services { public class ChartService: IChartsService { private readonly IJSRuntime _jsRuntime; + private readonly IStringLocalizer _localize; - public ChartService(IJSRuntime jsRuntime) + public ChartService(IJSRuntime jsRuntime, IStringLocalizer localize) { _jsRuntime = jsRuntime; + _localize = localize; } - public async Task BuildBarChart(string elementId) + public async Task BuildBarChartBattlesByTankType(string elementId, IEnumerable tanks) { - await _jsRuntime.InvokeVoidAsync("eChartsInterop.BuildBarChart", elementId); + var battlesCountByTankType = new Dictionary(); + + foreach (var tank in tanks) + { + if (tank.TankTypeId == null) + { + continue; + } + if (battlesCountByTankType.ContainsKey(tank.TankTypeId)) + { + battlesCountByTankType[tank.TankTypeId] += tank.Battles; + } + else + { + battlesCountByTankType.Add(tank.TankTypeId, tank.Battles); + } + } + + int mediumValue = 0; + int lightValue = 0; + int heavyValue = 0; + int atValue = 0; + if (battlesCountByTankType.ContainsKey(Constants.MediumTank)) + { + mediumValue = Convert.ToInt32(battlesCountByTankType[Constants.MediumTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.LightTank)) + { + lightValue = Convert.ToInt32(battlesCountByTankType[Constants.LightTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.HeavyTank)) + { + heavyValue = Convert.ToInt32(battlesCountByTankType[Constants.HeavyTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.AtSpg)) + { + atValue = Convert.ToInt32(battlesCountByTankType[Constants.AtSpg]); + } + + var chartData = new[] + { + new {tankType = Constants.MediumTank, value = mediumValue, color = "#9FE3CE"}, + new {tankType = Constants.LightTank, value = lightValue, color = "#9FE3CE"}, + new {tankType = Constants.HeavyTank, value = heavyValue, color = "#9FE3CE"}, + new {tankType = Constants.AtSpg, value = atValue, color = "#9FE3CE"}, + }; + + await _jsRuntime.InvokeVoidAsync("eChartsInterop.BuildBarChartByTankType", elementId, _localize.GetString("Battles by tank types").Value, chartData); + } + + public async Task BuildBarChartWinRatesByTankType(string elementId, IEnumerable tanks) + { + var battlesCountByTankType = new Dictionary(); + var winsCountByTankType = new Dictionary(); + + foreach (var tank in tanks) + { + if(tank.TankTypeId == null) + { + continue; + } + if(battlesCountByTankType.ContainsKey(tank.TankTypeId)) + { + battlesCountByTankType[tank.TankTypeId] += tank.Battles; + } + else + { + battlesCountByTankType.Add(tank.TankTypeId, tank.Battles); + } + if(winsCountByTankType.ContainsKey(tank.TankTypeId)) + { + winsCountByTankType[tank.TankTypeId] += tank.Wins; + } + else + { + winsCountByTankType.Add(tank.TankTypeId, tank.Wins); + } + } + + int mediumValue = 0; + int lightValue = 0; + int heavyValue = 0; + int atValue = 0; + if (battlesCountByTankType.ContainsKey(Constants.MediumTank)) + { + mediumValue = Convert.ToInt32(100 * winsCountByTankType[Constants.MediumTank] / + battlesCountByTankType[Constants.MediumTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.LightTank)) + { + lightValue = Convert.ToInt32(100 * winsCountByTankType[Constants.LightTank] / + battlesCountByTankType[Constants.LightTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.HeavyTank)) + { + heavyValue = Convert.ToInt32(100 * winsCountByTankType[Constants.HeavyTank] / + battlesCountByTankType[Constants.HeavyTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.AtSpg)) + { + atValue = Convert.ToInt32(100 * winsCountByTankType[Constants.AtSpg] / + battlesCountByTankType[Constants.AtSpg]); + } + + var chartData = new[] + { + new {tankType = Constants.MediumTank, value = mediumValue, color = mediumValue.ScaleColor()}, + new {tankType = Constants.LightTank, value = lightValue, color = lightValue.ScaleColor()}, + new {tankType = Constants.HeavyTank, value = heavyValue, color = heavyValue.ScaleColor()}, + new {tankType = Constants.AtSpg, value = atValue, color = atValue.ScaleColor()}, + }; + + await _jsRuntime.InvokeVoidAsync("eChartsInterop.BuildBarChartByTankType", elementId, _localize.GetString("Win rate by tank types").Value, chartData); + } + + public async Task BuildBarChartAvgDmgByTankType(string elementId, IEnumerable tanks) + { + var battlesCountByTankType = new Dictionary(); + var damageSumByTankType = new Dictionary(); + + foreach (var tank in tanks) + { + if (tank.TankTypeId == null) + { + continue; + } + if (battlesCountByTankType.ContainsKey(tank.TankTypeId)) + { + battlesCountByTankType[tank.TankTypeId] += tank.Battles; + } + else + { + battlesCountByTankType.Add(tank.TankTypeId, tank.Battles); + } + if (damageSumByTankType.ContainsKey(tank.TankTypeId)) + { + damageSumByTankType[tank.TankTypeId] += tank.DamageDealt; + } + else + { + damageSumByTankType.Add(tank.TankTypeId, tank.DamageDealt); + } + } + + int mediumValue = 0; + int lightValue = 0; + int heavyValue = 0; + int atValue = 0; + if (battlesCountByTankType.ContainsKey(Constants.MediumTank)) + { + mediumValue = Convert.ToInt32(damageSumByTankType[Constants.MediumTank] / + battlesCountByTankType[Constants.MediumTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.LightTank)) + { + lightValue = Convert.ToInt32(damageSumByTankType[Constants.LightTank] / + battlesCountByTankType[Constants.LightTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.HeavyTank)) + { + heavyValue = Convert.ToInt32(damageSumByTankType[Constants.HeavyTank] / + battlesCountByTankType[Constants.HeavyTank]); + } + if (battlesCountByTankType.ContainsKey(Constants.AtSpg)) + { + atValue = Convert.ToInt32(damageSumByTankType[Constants.AtSpg] / + battlesCountByTankType[Constants.AtSpg]); + } + + var chartData = new[] + { + new {tankType = Constants.MediumTank, value = mediumValue, color = "#D98D8B"}, + new {tankType = Constants.LightTank, value = lightValue, color = "#D98D8B"}, + new {tankType = Constants.HeavyTank, value = heavyValue, color = "#D98D8B"}, + new {tankType = Constants.AtSpg, value = atValue, color = "#D98D8B"}, + }; + + await _jsRuntime.InvokeVoidAsync("eChartsInterop.BuildBarChartByTankType", elementId, _localize.GetString("Avg damage by tank types").Value, chartData); + } + + public async Task BuildStackedBarChart(string elementId) + { + await _jsRuntime.InvokeVoidAsync("eChartsInterop.BuildStackedBarChart", elementId); } } } \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor/Services/IChartsService.cs b/WotBlitzStatisticsPro.Blazor/Services/IChartsService.cs index 927f753..7687285 100644 --- a/WotBlitzStatisticsPro.Blazor/Services/IChartsService.cs +++ b/WotBlitzStatisticsPro.Blazor/Services/IChartsService.cs @@ -1,9 +1,14 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; +using WotBlitzStatisticsPro.Blazor.GraphQl; namespace WotBlitzStatisticsPro.Blazor.Services { public interface IChartsService { - Task BuildBarChart(string elementId); + Task BuildBarChartBattlesByTankType(string elementId, IEnumerable tanks); + Task BuildBarChartWinRatesByTankType(string elementId, IEnumerable tanks); + Task BuildBarChartAvgDmgByTankType(string elementId, IEnumerable tanks); + Task BuildStackedBarChart(string elementId); } } \ No newline at end of file diff --git a/WotBlitzStatisticsPro.Blazor/wwwroot/echarts/echarts-interop.js b/WotBlitzStatisticsPro.Blazor/wwwroot/echarts/echarts-interop.js index a847152..6686831 100644 --- a/WotBlitzStatisticsPro.Blazor/wwwroot/echarts/echarts-interop.js +++ b/WotBlitzStatisticsPro.Blazor/wwwroot/echarts/echarts-interop.js @@ -1,29 +1,272 @@ var eChartsInterop = eChartsInterop || {}; -eChartsInterop.BuildBarChart = function (elementId) { +eChartsInterop.BuildBarChartByTankType = function (elementId, chartTitle, chartData) { + var tankTypes = { + 'HeavyTank': '/tank-type/vehicle.class.heavy.small.scale-200.png', + 'AtSpg': '/tank-type/vehicle.class.atspg.small.scale-200.png', + 'MediumTank': '/tank-type/vehicle.class.medium.small.scale-200.png', + 'LightTank': '/tank-type/vehicle.class.light.small.scale-200.png' + }; + + var seriesLabel = { + show: true + } + // based on prepared DOM, initialize echarts instance - var myChart = echarts.init(document.getElementById(elementId)); + var myChart = echarts.init(document.getElementById(elementId), 'dark'); + + var lightData = chartData.find(d => d.tankType === 'lightTank'); + var mediumData = chartData.find(d => d.tankType === 'mediumTank'); + var heavyData = chartData.find(d => d.tankType === 'heavyTank'); + var atData = chartData.find(d => d.tankType === 'AT-SPG'); // specify chart configuration item and data var option = { title: { - text: 'ECharts entry example' + text: chartTitle }, - tooltip: {}, - legend: { - data: ['Sales'] + toolbox: { + show: true, + feature: { + saveAsImage: {} + } }, xAxis: { - data: ["shirt", "cardign", "chiffon shirt", "pants", "heels", "socks"] + type: 'value', + name: '', + axisLabel: { + formatter: '{value}' + } }, - yAxis: {}, - series: [{ - name: 'Sales', - type: 'bar', - data: [5, 20, 36, 10, 10, 20] - }] + yAxis: { + type: 'category', + data: ['HeavyTank', 'AtSpg', 'MediumTank', 'LightTank'], + axisTick: { + alignWithLabel: true + }, + axisLabel: { + formatter: function (value) { + return '{' + value + '| }'; + }, + rich: { + value: { + lineHeight: 10, + align: 'center' + }, + HeavyTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.HeavyTank + } + }, + AtSpg: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.AtSpg + } + }, + MediumTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.MediumTank + } + }, + LightTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.LightTank + } + } + } + } + }, + series: [ + { + type: 'bar', + label: seriesLabel, + barWidth: '30px', + data: [ + { + value: heavyData.value, + itemStyle: { + color: heavyData.color + } + }, + { + value: atData.value, + itemStyle: { + color: atData.color + } + }, + { + value: mediumData.value, + itemStyle: { + color: mediumData.color + } + }, + { + value: lightData.value, + itemStyle: { + color: lightData.color + } + }] + }] }; // use configuration item and data specified to show chart myChart.setOption(option); + window.addEventListener('resize', + function() { + myChart.resize(); + }); +}; + +eChartsInterop.BuildStackedBarChart = function (elementId) { + var tankTypes = { + 'HeavyTank': '/tank-type/vehicle.class.heavy.small.scale-200.png', + 'AtSpg': '/tank-type/vehicle.class.atspg.small.scale-200.png', + 'MediumTank': '/tank-type/vehicle.class.medium.small.scale-200.png', + 'LightTank': '/tank-type/vehicle.class.light.small.scale-200.png' + }; + + var seriesLabel = { + show: true + } + + // based on prepared DOM, initialize echarts instance + var myChart = echarts.init(document.getElementById(elementId), 'dark'); + + // specify chart configuration item and data + var option = { + + title: { + text: 'Statistics by tank types' + }, + tooltip: { + trigger: 'axis', + axisPointer: { // Use axis to trigger tooltip + type: 'shadow' // 'shadow' as default; can also be 'line' or 'shadow' + } + }, + legend: { + data: ['Battles', '% Побед', 'Avg Dmg'] + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: { + type: 'value' + }, + toolbox: { + show: true, + feature: { + saveAsImage: {} + } + }, + yAxis: { + type: 'category', + data: ['HeavyTank', 'AtSpg', 'MediumTank', 'LightTank'], + axisTick: { + alignWithLabel: true + }, + axisLabel: { + formatter: function (value) { + return '{' + value + '| }'; + }, + rich: { + value: { + lineHeight: 10, + align: 'center' + }, + HeavyTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.HeavyTank + } + }, + AtSpg: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.AtSpg + } + }, + MediumTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.MediumTank + } + }, + LightTank: { + height: 20, + width: 20, + align: 'center', + backgroundColor: { + image: tankTypes.LightTank + } + } + } + } + }, + series: [ + { + name: 'Battles', + type: 'bar', + stack: 'total', + label: { + show: true + }, + emphasis: { + focus: 'series' + }, + data: [830, 1300, 50, 5000] + }, + { + name: '% Побед', + type: 'bar', + stack: 'total', + label: { + show: true + }, + emphasis: { + focus: 'series' + }, + data: [35, 56, 48, 60] + }, + { + name: 'Avg Dmg', + type: 'bar', + stack: 'total', + label: { + show: true + }, + emphasis: { + focus: 'series' + }, + data: [600, 2500, 1700, 1300] + } + ] + }; + + // use configuration item and data specified to show chart + myChart.setOption(option); + window.onresize = function () { + myChart.resize(); + }; }; \ No newline at end of file