1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 16:32:54 +08:00

Add the ability to set and show an offset value on timing distribution graph

This commit is contained in:
Dean Herbert 2022-03-04 14:34:33 +09:00
parent d3e04fe594
commit 540d7d0e2c
2 changed files with 126 additions and 84 deletions

View File

@ -17,10 +17,13 @@ namespace osu.Game.Tests.Visual.Ranking
{ {
public class TestSceneHitEventTimingDistributionGraph : OsuTestScene public class TestSceneHitEventTimingDistributionGraph : OsuTestScene
{ {
private HitEventTimingDistributionGraph graph;
[Test] [Test]
public void TestManyDistributedEvents() public void TestManyDistributedEvents()
{ {
createTest(CreateDistributedHitEvents()); createTest(CreateDistributedHitEvents());
AddStep("add adjustment", () => graph.UpdateOffset(10));
} }
[Test] [Test]
@ -68,7 +71,7 @@ namespace osu.Game.Tests.Visual.Ranking
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#333") Colour = Color4Extensions.FromHex("#333")
}, },
new HitEventTimingDistributionGraph(events) graph = new HitEventTimingDistributionGraph(events)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
namespace osu.Game.Screens.Ranking.Statistics namespace osu.Game.Screens.Ranking.Statistics
{ {
@ -58,6 +59,8 @@ namespace osu.Game.Screens.Ranking.Statistics
private double binSize; private double binSize;
private double hitOffset; private double hitOffset;
private Bar[] barDrawables;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
@ -108,115 +111,151 @@ namespace osu.Game.Screens.Ranking.Statistics
bins[index]++; bins[index]++;
} }
int maxCount = bins.Max(); if (barDrawables != null)
var bars = new Drawable[total_timing_distribution_bins];
for (int i = 0; i < bars.Length; i++)
{ {
bars[i] = new Bar(i == timing_distribution_centre_bin_index) for (int i = 0; i < barDrawables.Length; i++)
{ {
Height = Math.Max(0.05f, (float)bins[i] / maxCount) barDrawables[i].UpdateOffset(bins[i]);
};
}
Container axisFlow;
const float axis_font_size = 12;
InternalChild = new GridContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
Content = new[]
{
new Drawable[]
{
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[] { bars }
}
},
new Drawable[]
{
axisFlow = new Container
{
RelativeSizeAxes = Axes.X,
Height = axis_font_size,
}
},
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
} }
}; }
else
// 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, int maxCount = bins.Max();
Origin = Anchor.Centre, barDrawables = new Bar[total_timing_distribution_bins];
Text = "0",
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
});
for (int i = 1; i <= axis_points; i++) for (int i = 0; i < barDrawables.Length; i++)
{ barDrawables[i] = new Bar(bins[i], maxCount, i == timing_distribution_centre_bin_index);
double axisValue = i * axisValueStep;
float position = (float)(axisValue / maxValue); Container axisFlow;
float alpha = 1f - position * 0.8f;
const float axis_font_size = 12;
InternalChild = new GridContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
Content = new[]
{
new Drawable[]
{
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[] { barDrawables }
}
},
new Drawable[]
{
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;
axisFlow.Add(new OsuSpriteText axisFlow.Add(new OsuSpriteText
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativePositionAxes = Axes.X, Text = "0",
X = -position / 2,
Alpha = alpha,
Text = axisValue.ToString("-0"),
Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold) Font = OsuFont.GetFont(size: axis_font_size, weight: FontWeight.SemiBold)
}); });
axisFlow.Add(new OsuSpriteText for (int i = 1; i <= axis_points; i++)
{ {
Anchor = Anchor.Centre, double axisValue = i * axisValueStep;
Origin = Anchor.Centre, float position = (float)(axisValue / maxValue);
RelativePositionAxes = Axes.X, float alpha = 1f - position * 0.8f;
X = position / 2,
Alpha = alpha, axisFlow.Add(new OsuSpriteText
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)
});
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)
});
}
} }
} }
private class Bar : CompositeDrawable private class Bar : CompositeDrawable
{ {
public Bar(bool isCentre) private readonly float value;
private readonly float maxValue;
private readonly Circle boxOriginal;
private readonly Circle boxAdjustment;
public Bar(float value, float maxValue, bool isCentre)
{ {
Anchor = Anchor.BottomCentre; this.value = value;
Origin = Anchor.BottomCentre; this.maxValue = maxValue;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Masking = true;
var colour = Color4Extensions.FromHex("#66FFCC"); InternalChildren = new Drawable[]
if (isCentre)
colour = colour.Lighten(1);
InternalChild = new Circle
{ {
RelativeSizeAxes = Axes.Both, boxOriginal = new Circle
Colour = colour {
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Colour = isCentre ? Color4.White : Color4Extensions.FromHex("#66FFCC"),
Height = 0,
},
boxAdjustment = new Circle
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Colour = Color4.Yellow,
Blending = BlendingParameters.Additive,
Alpha = 0.6f,
Height = 0,
},
}; };
} }
private const double duration = 300;
protected override void LoadComplete()
{
base.LoadComplete();
boxOriginal.ResizeHeightTo(Math.Clamp(value / maxValue, 0.05f, 1), duration, Easing.OutQuint);
}
public void UpdateOffset(float adjustment)
{
boxAdjustment.ResizeHeightTo(Math.Clamp(adjustment / maxValue, 0.05f, 1), duration, Easing.OutQuint);
}
} }
} }
} }