diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index 3bc4556a27..02e8a8329a 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -23,6 +23,9 @@ namespace osu.Game.Graphics.UserInterface /// public float? MinValue { get; set; } + public float? ActualMaxValue { get; private set; } + public float? ActualMinValue { get; private set; } + private const double transform_duration = 500; /// @@ -40,6 +43,7 @@ namespace osu.Game.Graphics.UserInterface /// public IEnumerable Values { + get { return values; } set { values = value.ToArray(); @@ -77,6 +81,9 @@ namespace osu.Game.Graphics.UserInterface if (MaxValue > max) max = MaxValue.Value; if (MinValue < min) min = MinValue.Value; + ActualMaxValue = max; + ActualMinValue = min; + for (int i = 0; i < values.Length; i++) { float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1; diff --git a/osu.Game/Users/Profile/RankChart.cs b/osu.Game/Users/Profile/RankChart.cs index 9cb11623da..49f67efbdc 100644 --- a/osu.Game/Users/Profile/RankChart.cs +++ b/osu.Game/Users/Profile/RankChart.cs @@ -2,12 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using OpenTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -16,24 +19,28 @@ namespace osu.Game.Users.Profile { public class RankChart : Container { - private readonly SpriteText rank, performance, relative; - private readonly LineGraph graph; + private readonly SpriteText rankText, performanceText, relativeText; + private readonly RankChartLineGraph graph; - private readonly int[] ranks, performances; + private int[] ranks, performances; + private int rank, performance, countryRank; + + private readonly User user; public RankChart(User user) { + this.user = user; Padding = new MarginPadding { Vertical = 10 }; Children = new Drawable[] { - rank = new OsuSpriteText + rankText = new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Font = @"Exo2.0-RegularItalic", TextSize = 25 }, - relative = new OsuSpriteText + relativeText = new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -41,29 +48,35 @@ namespace osu.Game.Users.Profile Y = 25, TextSize = 13 }, - performance = new OsuSpriteText + performanceText = new OsuSpriteText { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Font = @"Exo2.0-RegularItalic", TextSize = 13 }, - graph = new LineGraph + graph = new RankChartLineGraph { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -13, - DefaultValueCount = 90 + DefaultValueCount = 90, + BallRelease = () => + { + rankText.Text = $"#{rank:#,#}"; + performanceText.Text = $"{performance:#,#}pp"; + relativeText.Text = $"{this.user.Country?.FullName} #{countryRank:#,#}"; + }, + BallMove = index => + { + rankText.Text = $"#{ranks[index]:#,#}"; + performanceText.Text = $"{performances[index]:#,#}pp"; + relativeText.Text = index == ranks.Length ? "Now" : $"{ranks.Length - index} days ago"; + //plural should be handled in a general way + } } }; - - //placeholder text - rank.Text = "#12,345"; - relative.Text = $"{user.Country?.FullName} #678"; - performance.Text = "4,567pp"; - ranks = Enumerable.Range(1234, 80).ToArray(); - performances = ranks.Select(x => 6000 - x).ToArray(); } [BackgroundDependencyLoader] @@ -73,10 +86,16 @@ namespace osu.Game.Users.Profile Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); - // put placeholder data here to show the transform + // put placeholder data here to show the transform + rank = 12345; + countryRank = 678; + performance = 4567; + ranks = Enumerable.Range(1234, 80).ToArray(); + performances = ranks.Select(x => 6000 - x).ToArray(); // use logarithmic coordinates graph.Values = ranks.Select(x => -(float)Math.Log(x)); + graph.ResetBall(); }); } @@ -89,5 +108,70 @@ namespace osu.Game.Users.Profile return base.Invalidate(invalidation, source, shallPropagate); } + + private class RankChartLineGraph : LineGraph + { + private readonly CircularContainer ball; + private bool ballShown; + + private const double transform_duration = 100; + + public Action BallMove; + public Action BallRelease; + + public RankChartLineGraph() + { + Add(ball = new CircularContainer + { + Size = new Vector2(8), + Masking = true, + Origin = Anchor.Centre, + Alpha = 0, + RelativePositionAxes = Axes.Both, + Children = new Drawable[] + { + new Box { RelativeSizeAxes = Axes.Both } + } + }); + } + + public void ResetBall() + { + ball.MoveTo(new Vector2(1, ((ActualMaxValue - Values.Last()) / (ActualMaxValue - ActualMinValue)).Value), ballShown ? transform_duration : 0, EasingTypes.OutQuint); + ball.Show(); + BallRelease(); + ballShown = true; + } + + protected override bool OnMouseMove(InputState state) + { + if (ballShown) + { + var values = Values as IList; + var position = ToLocalSpace(state.Mouse.NativeState.Position); + int count = Math.Max(values.Count, DefaultValueCount); + int index = (int)Math.Round(position.X / DrawWidth * (count - 1)); + if (index >= count - values.Count) + { + int i = index + values.Count - count; + float value = values[i]; + float y = ((ActualMaxValue - value) / (ActualMaxValue - ActualMinValue)).Value; + if (Math.Abs(y * DrawHeight - position.Y) <= 8f) + { + ball.MoveTo(new Vector2(index / (float)(count - 1), y), transform_duration, EasingTypes.OutQuint); + BallMove(i); + } + } + } + return base.OnMouseMove(state); + } + + protected override void OnHoverLost(InputState state) + { + if (ballShown) + ResetBall(); + base.OnHoverLost(state); + } + } } }