Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix timing distribution graph sometimes not displaying correctly #24191

Merged
merged 5 commits into from
Jul 13, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 109 additions & 123 deletions osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Layout;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
Expand Down Expand Up @@ -113,94 +115,95 @@ private void updateDisplay()
}
}

if (barDrawables != null)
if (barDrawables == null)
createBarDrawables();
else
{
for (int i = 0; i < barDrawables.Length; i++)
{
barDrawables[i].UpdateOffset(bins[i].Sum(b => b.Value));
}
}
else
{
int maxCount = bins.Max(b => b.Values.Sum());
barDrawables = bins.Select((bin, i) => new Bar(bins[i], maxCount, i == timing_distribution_centre_bin_index)).ToArray();
}

private void createBarDrawables()
{
int maxCount = bins.Max(b => b.Values.Sum());
barDrawables = bins.Select((_, i) => new Bar(bins[i], maxCount, i == timing_distribution_centre_bin_index)).ToArray();

Container axisFlow;
Container axisFlow;

const float axis_font_size = 12;
const float axis_font_size = 12;

InternalChild = new GridContainer
InternalChild = new GridContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
Content = new[]
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
Content = new[]
new Drawable[]
{
new Drawable[]
new GridContainer
{
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[] { barDrawables }
}
},
new Drawable[]
{
axisFlow = new Container
{
RelativeSizeAxes = Axes.X,
Height = axis_font_size,
}
},
RelativeSizeAxes = Axes.Both,
Content = new[] { barDrawables }
}
},
RowDimensions = new[]
new Drawable[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
}
};
axisFlow = new Container
{
RelativeSizeAxes = Axes.X,
Height = axis_font_size,
}
},
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
}
};

// Our axis will contain one centre element + 5 points on each side, each with a value depending on the number of bins * bin size.
double maxValue = timing_distribution_bins * binSize;
double axisValueStep = maxValue / axis_points;
// Our axis will contain one centre element + 5 points on each side, each with a value depending on the number of bins * bin size.
double maxValue = timing_distribution_bins * binSize;
double axisValueStep = maxValue / axis_points;

axisFlow.Add(new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "0",
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});

for (int i = 1; i <= axis_points; i++)
{
double axisValue = i * axisValueStep;
float position = (float)(axisValue / maxValue);
float alpha = 1f - position * 0.8f;

axisFlow.Add(new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "0",
RelativePositionAxes = Axes.X,
X = -position / 2,
Alpha = alpha,
Text = axisValue.ToString("-0"),
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});

for (int i = 1; i <= axis_points; i++)
axisFlow.Add(new OsuSpriteText
{
double axisValue = i * axisValueStep;
float position = (float)(axisValue / maxValue);
float alpha = 1f - position * 0.8f;

axisFlow.Add(new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
X = -position / 2,
Alpha = alpha,
Text = axisValue.ToString("-0"),
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});

axisFlow.Add(new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
X = position / 2,
Alpha = alpha,
Text = axisValue.ToString("+0"),
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});
}
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
X = position / 2,
Alpha = alpha,
Text = axisValue.ToString("+0"),
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});
}
}

Expand All @@ -211,13 +214,16 @@ private partial class Bar : CompositeDrawable
private readonly bool isCentre;
private readonly float totalValue;

private float basalHeight;
private const float minimum_height = 0.02f;

private float offsetAdjustment;

private Circle[] boxOriginals = null!;

private Circle? boxAdjustment;

private float? lastDrawHeight;

[Resolved]
private OsuColour colours { get; set; } = null!;

Expand Down Expand Up @@ -256,47 +262,36 @@ private void load()
else
{
// A bin with no value draws a grey dot instead.
Circle dot = new Circle
InternalChildren = boxOriginals = new[]
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Colour = isCentre ? Color4.White : Color4.Gray,
Height = 0,
new Circle
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Colour = isCentre ? Color4.White : Color4.Gray,
Height = 0,
}
};
InternalChildren = boxOriginals = new[] { dot };
}
}

protected override void LoadComplete()
{
base.LoadComplete();

if (!values.Any())
return;

updateBasalHeight();

foreach (var boxOriginal in boxOriginals)
{
boxOriginal.Y = 0;
boxOriginal.Height = basalHeight;
}

float offsetValue = 0;
Scheduler.AddOnce(updateMetrics, true);
}

for (int i = 0; i < values.Count; i++)
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
{
if (invalidation.HasFlagFast(Invalidation.DrawSize))
{
boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint);
boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint);
offsetValue -= values[i].Value;
if (lastDrawHeight != null && lastDrawHeight != DrawHeight)
Scheduler.AddOnce(updateMetrics, false);
}
}

protected override void Update()
{
base.Update();
updateBasalHeight();
return base.OnInvalidate(invalidation, source);
}

public void UpdateOffset(float adjustment)
Expand All @@ -321,45 +316,32 @@ public void UpdateOffset(float adjustment)
}

offsetAdjustment = adjustment;
drawAdjustmentBar();

Scheduler.AddOnce(updateMetrics, true);
}

private void updateBasalHeight()
private void updateMetrics(bool animate = true)
{
float newBasalHeight = DrawHeight > DrawWidth ? DrawWidth / DrawHeight : 1;

if (newBasalHeight == basalHeight)
return;

basalHeight = newBasalHeight;
foreach (var dot in boxOriginals)
dot.Height = basalHeight;

draw();
}
float offsetValue = 0;

private float offsetForValue(float value) => (1 - basalHeight) * value / maxValue;
for (int i = 0; i < boxOriginals.Length; i++)
{
int value = i < values.Count ? values[i].Value : 0;

private float heightForValue(float value) => MathF.Max(basalHeight + offsetForValue(value), 0);
var box = boxOriginals[i];

private void draw()
{
resizeBars();
box.MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint);
box.ResizeHeightTo(heightForValue(value), duration, Easing.OutQuint);
offsetValue -= value;
}

if (boxAdjustment != null)
drawAdjustmentBar();
}

private void resizeBars()
{
float offsetValue = 0;
if (!animate)
FinishTransforms(true);

for (int i = 0; i < values.Count; i++)
{
boxOriginals[i].Y = offsetForValue(offsetValue) * DrawHeight;
boxOriginals[i].Height = heightForValue(values[i].Value);
offsetValue -= values[i].Value;
}
lastDrawHeight = DrawHeight;
}

private void drawAdjustmentBar()
Expand All @@ -369,6 +351,10 @@ private void drawAdjustmentBar()
boxAdjustment.ResizeHeightTo(heightForValue(offsetAdjustment), duration, Easing.OutQuint);
boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint);
}

private float offsetForValue(float value) => (1 - minimum_height) * value / maxValue;

private float heightForValue(float value) => minimum_height + offsetForValue(value);
}
}
}