misc performance graph display tweaks
This commit is contained in:
parent
b78c467539
commit
bef8c08d90
@ -7,8 +7,6 @@ namespace Data.Models.Client.Stats
|
||||
{
|
||||
public class EFClientRankingHistory: AuditFields
|
||||
{
|
||||
public const int MaxRankingCount = 1728;
|
||||
|
||||
[Key]
|
||||
public long ClientRankingHistoryId { get; set; }
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace Stats.Helpers
|
||||
.Where(r => r.ClientId == clientInfo.ClientId)
|
||||
.Where(r => r.ServerId == serverId)
|
||||
.Where(r => r.Ranking != null)
|
||||
.OrderByDescending(r => r.UpdatedDateTime)
|
||||
.OrderByDescending(r => r.CreatedDateTime)
|
||||
.Take(250)
|
||||
.ToListAsync();
|
||||
|
||||
|
@ -138,6 +138,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
.CountAsync();
|
||||
}
|
||||
|
||||
public class RankingSnapshot
|
||||
{
|
||||
public int ClientId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime LastConnection { get; set; }
|
||||
public double? PerformanceMetric { get; set; }
|
||||
public double? ZScore { get; set; }
|
||||
public int? Ranking { get; set; }
|
||||
public DateTime CreatedDateTime { get; set; }
|
||||
}
|
||||
|
||||
public async Task<List<TopStatsInfo>> GetNewTopStats(int start, int count, long? serverId = null)
|
||||
{
|
||||
await using var context = _contextFactory.CreateContext(false);
|
||||
@ -150,23 +161,28 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
.Take(count)
|
||||
.ToListAsync();
|
||||
|
||||
var rankings = await context.Set<EFClientRankingHistory>()
|
||||
.Where(ranking => clientIdsList.Contains(ranking.ClientId))
|
||||
.Where(ranking => ranking.ServerId == serverId)
|
||||
.Select(ranking => new
|
||||
{
|
||||
ranking.ClientId,
|
||||
ranking.Client.CurrentAlias.Name,
|
||||
ranking.Client.LastConnection,
|
||||
ranking.PerformanceMetric,
|
||||
ranking.ZScore,
|
||||
ranking.Ranking,
|
||||
ranking.CreatedDateTime
|
||||
})
|
||||
.ToListAsync();
|
||||
var rankingsDict = new Dictionary<int, List<RankingSnapshot>>();
|
||||
|
||||
var rankingsDict = rankings.GroupBy(rank => rank.ClientId)
|
||||
.ToDictionary(rank => rank.Key, rank => rank.OrderBy(r => r.CreatedDateTime).ToList());
|
||||
foreach (var clientId in clientIdsList)
|
||||
{
|
||||
var eachRank = await context.Set<EFClientRankingHistory>()
|
||||
.Where(ranking => ranking.ClientId == clientId)
|
||||
.Where(ranking => ranking.ServerId == serverId)
|
||||
.OrderByDescending(ranking => ranking.CreatedDateTime)
|
||||
.Select(ranking => new RankingSnapshot
|
||||
{
|
||||
ClientId = ranking.ClientId,
|
||||
Name = ranking.Client.CurrentAlias.Name,
|
||||
LastConnection = ranking.Client.LastConnection,
|
||||
PerformanceMetric = ranking.PerformanceMetric,
|
||||
ZScore = ranking.ZScore,
|
||||
Ranking = ranking.Ranking,
|
||||
CreatedDateTime = ranking.CreatedDateTime
|
||||
})
|
||||
.Take(60)
|
||||
.ToListAsync();
|
||||
rankingsDict.Add(clientId, eachRank);
|
||||
}
|
||||
|
||||
var statsInfo = await context.Set<EFClientStatistics>()
|
||||
.Where(stat => clientIdsList.Contains(stat.ClientId))
|
||||
@ -187,7 +203,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
.ToListAsync();
|
||||
|
||||
var finished = statsInfo
|
||||
.OrderByDescending(stat => rankingsDict[stat.ClientId].Last().PerformanceMetric)
|
||||
.OrderByDescending(stat => rankingsDict[stat.ClientId].First().PerformanceMetric)
|
||||
.Select((s, index) => new TopStatsInfo
|
||||
{
|
||||
ClientId = s.ClientId,
|
||||
@ -195,24 +211,23 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
Deaths = s.Deaths,
|
||||
Kills = s.Kills,
|
||||
KDR = Math.Round(s.KDR, 2),
|
||||
LastSeen = (DateTime.UtcNow - (s.UpdatedAt ?? rankingsDict[s.ClientId].Last().LastConnection))
|
||||
LastSeen = (DateTime.UtcNow - (s.UpdatedAt ?? rankingsDict[s.ClientId].First().LastConnection))
|
||||
.HumanizeForCurrentCulture(1, TimeUnit.Week, TimeUnit.Second, ",", false),
|
||||
LastSeenValue = DateTime.UtcNow - (s.UpdatedAt ?? rankingsDict[s.ClientId].Last().LastConnection),
|
||||
LastSeenValue = DateTime.UtcNow - (s.UpdatedAt ?? rankingsDict[s.ClientId].First().LastConnection),
|
||||
Name = rankingsDict[s.ClientId].First().Name,
|
||||
Performance = Math.Round(rankingsDict[s.ClientId].Last().PerformanceMetric ?? 0, 2),
|
||||
RatingChange = (rankingsDict[s.ClientId].First().Ranking -
|
||||
rankingsDict[s.ClientId].Last().Ranking) ?? 0,
|
||||
Performance = Math.Round(rankingsDict[s.ClientId].First().PerformanceMetric ?? 0, 2),
|
||||
RatingChange = (rankingsDict[s.ClientId].Last().Ranking -
|
||||
rankingsDict[s.ClientId].First().Ranking) ?? 0,
|
||||
PerformanceHistory = rankingsDict[s.ClientId].Select(ranking => new PerformanceHistory
|
||||
{ Performance = ranking.PerformanceMetric ?? 0, OccurredAt = ranking.CreatedDateTime })
|
||||
.ToList(),
|
||||
TimePlayed = Math.Round(s.TotalTimePlayed / 3600.0, 1).ToString("#,##0"),
|
||||
TimePlayedValue = TimeSpan.FromSeconds(s.TotalTimePlayed),
|
||||
Ranking = index + start + 1,
|
||||
ZScore = rankingsDict[s.ClientId].Last().ZScore,
|
||||
ZScore = rankingsDict[s.ClientId].First().ZScore,
|
||||
ServerId = serverId
|
||||
})
|
||||
.OrderBy(r => r.Ranking)
|
||||
.Take(60)
|
||||
.ToList();
|
||||
|
||||
return finished;
|
||||
@ -1322,16 +1337,22 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
context.Update(mostRecent);
|
||||
}
|
||||
|
||||
if (totalRankingEntries > EFClientRankingHistory.MaxRankingCount)
|
||||
const int maxRankingCount = 1728; // 60 / 2.5 * 24 * 3 ( 3 days at sample every 2.5 minutes)
|
||||
|
||||
if (totalRankingEntries > maxRankingCount)
|
||||
{
|
||||
var lastRating = await context.Set<EFClientRankingHistory>()
|
||||
.Where(r => r.ClientId == clientId)
|
||||
.Where(r => r.ServerId == serverId)
|
||||
.OrderBy(r => r.CreatedDateTime)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (lastRating is not null)
|
||||
{
|
||||
context.Remove(lastRating);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the incrementation of kills and deaths for client statistics
|
||||
|
@ -193,16 +193,6 @@ namespace SharedLibraryCore.Services
|
||||
return await activePenaltiesIds.Select(ids => ids.Penalty).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<EFPenalty>> GetActivePenaltiesByClientId(int clientId)
|
||||
{
|
||||
await using var context = _contextFactory.CreateContext(false);
|
||||
return await context.PenaltyIdentifiers
|
||||
.Where(identifier => identifier.Penalty.Offender.ClientId == clientId)
|
||||
.Select(identifier => identifier.Penalty)
|
||||
.Where(Filter)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<EFPenalty>> ActivePenaltiesByRecentIdentifiers(int linkId)
|
||||
{
|
||||
await using var context = _contextFactory.CreateContext(false);
|
||||
|
@ -124,11 +124,12 @@
|
||||
var spm = Model.ServerId != null ? serverLegacyStat?.SPM.ToNumericalString() : Model.LegacyStats.WeightValueByPlaytime(nameof(EFClientStatistics.SPM), 0).ToNumericalString();
|
||||
|
||||
var performanceHistory = Model.Ratings
|
||||
.OrderBy(rating => rating.CreatedDateTime)
|
||||
.Select(rating => new PerformanceHistory { Performance = rating.PerformanceMetric, OccurredAt = rating.CreatedDateTime });
|
||||
|
||||
if (performance != null)
|
||||
if (performance != null && performance != Model.Ratings.FirstOrDefault().PerformanceMetric)
|
||||
{
|
||||
performanceHistory = performanceHistory.Append(new PerformanceHistory { Performance = performance.Value, OccurredAt = DateTime.UtcNow });
|
||||
performanceHistory = performanceHistory.Append(new PerformanceHistory { Performance = performance.Value, OccurredAt = Model.Ratings.FirstOrDefault()?.CreatedDateTime ?? DateTime.UtcNow });
|
||||
}
|
||||
|
||||
var score = allPerServer.Any()
|
||||
@ -285,7 +286,7 @@
|
||||
<!-- history graph -->
|
||||
@if (performanceHistory.Count() > 5)
|
||||
{
|
||||
<div class="w-half m-auto ml-lg-auto " id="client_performance_history_container">
|
||||
<div class="w-full w-lg-half m-auto ml-lg-auto" id="client_performance_history_container">
|
||||
<canvas id="client_performance_history" data-history="@(JsonSerializer.Serialize(performanceHistory))"></canvas>
|
||||
</div>
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
@using IW4MAdmin.Plugins.Stats
|
||||
@using System.Text.Json.Serialization
|
||||
@using System.Text.Json
|
||||
@model List<IW4MAdmin.Plugins.Stats.Web.Dtos.TopStatsInfo>
|
||||
@{
|
||||
@ -86,7 +85,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full w-md-half client-rating-graph pt-10 pb-10">
|
||||
<canvas id="rating_history_@(stat.ClientId + "_" + stat.Id)" data-history="@(JsonSerializer.Serialize(stat.PerformanceHistory))"></canvas>
|
||||
<canvas id="rating_history_@(stat.ClientId + "_" + stat.Id)" data-history="@(JsonSerializer.Serialize(stat.PerformanceHistory.OrderBy(perf => perf.OccurredAt)))"></canvas>
|
||||
</div>
|
||||
<div class="w-quarter align-self-center d-flex justify-content-center">
|
||||
<img class="w-100 h-100" src="~/images/stats/ranks/rank_@(stat.ZScore.RankIconIndexForZScore()).png" alt="@stat.Performance"/>
|
||||
|
@ -26,7 +26,7 @@ function setupPerformanceGraph() {
|
||||
}
|
||||
const chart = $('#client_performance_history');
|
||||
const container = $('#client_performance_history_container');
|
||||
chart.attr('height', summary.height());
|
||||
chart.attr('height', summary.height() * 1.5);
|
||||
chart.attr('width', container.width());
|
||||
renderPerformanceChart();
|
||||
}
|
||||
@ -394,7 +394,7 @@ function renderPerformanceChart() {
|
||||
position: 'right',
|
||||
ticks: {
|
||||
precision: 0,
|
||||
stepSize: 3,
|
||||
stepSize: max - min / 2,
|
||||
callback: function (value, index, values) {
|
||||
if (index === values.length - 1) {
|
||||
return min;
|
||||
|
@ -88,7 +88,7 @@ function getStatsChart(id) {
|
||||
position: 'right',
|
||||
ticks: {
|
||||
precision: 0,
|
||||
stepSize: 3,
|
||||
stepSize: max - min / 2,
|
||||
callback: function (value, index, values) {
|
||||
if (index === values.length - 1) {
|
||||
return min;
|
||||
|
Loading…
Reference in New Issue
Block a user