diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 6b1850002d94..e8d2eefd81fd 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -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; @@ -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) + }); } } @@ -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!; @@ -256,15 +262,17 @@ 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 }; } } @@ -272,31 +280,18 @@ 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) @@ -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() @@ -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); } } }