XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
using Windows.UI;
using XFEEDToolBox.Core.Models;

namespace XFEEDToolBox.Controls;

public sealed class RouteMap : UserControl
{
    private readonly Canvas canvas = new() { MinHeight = 230 };
    public static readonly DependencyProperty PlanProperty = DependencyProperty.Register(nameof(Plan), typeof(RoutePlan), typeof(RouteMap), new PropertyMetadata(null, (d, _) => ((RouteMap)d).Draw()));
    public RoutePlan? Plan { get => (RoutePlan?)GetValue(PlanProperty); set => SetValue(PlanProperty, value); }
    public RouteMap() { Content = canvas; SizeChanged += (_, _) => Draw(); }
    private static SolidColorBrush Brush(byte r, byte g, byte b, byte alpha = 255) => new(Color.FromArgb(alpha, r, g, b));
    private void Draw()
    {
        canvas.Children.Clear();
        var width = Math.Max(100, ActualWidth); var height = Math.Max(230, ActualHeight);
        canvas.Clip = new RectangleGeometry { Rect = new(0, 0, width, height) };
        for (var i = 0; i < 65; i++)
        {
            var dot = new Ellipse { Width = i % 7 == 0 ? 2 : 1, Height = i % 7 == 0 ? 2 : 1, Fill = Brush(116, 151, 187, (byte)(50 + i % 6 * 15)) };
            Canvas.SetLeft(dot, (i * 127 + 17) % width); Canvas.SetTop(dot, (i * 73 + 29) % height); canvas.Children.Add(dot);
        }
        var stations = Plan?.Legs.SelectMany(l => new[] { l.From, l.To }).DistinctBy(s => s.MarketId).ToArray() ?? [];
        if (stations.Length == 0)
        {
            var ring = new Ellipse { Width = 135, Height = 135, Stroke = Brush(49, 79, 111), StrokeThickness = 1 };
            Canvas.SetLeft(ring, width / 2 - 67); Canvas.SetTop(ring, height / 2 - 87); canvas.Children.Add(ring);
            var icon = new GameIcon { IconKey = Core.Rendering.GameUiIcon.FeatureRoute, Width = 34, Height = 34 };
            Canvas.SetLeft(icon, width / 2 - 17); Canvas.SetTop(icon, height / 2 - 35); canvas.Children.Add(icon);
            var hint = new TextBlock { Text = "计算路线后,在这里预览站点与航段", Foreground = Brush(145, 163, 185), FontSize = 12 };
            Canvas.SetLeft(hint, Math.Max(16, width / 2 - 120)); Canvas.SetTop(hint, height / 2 + 70); canvas.Children.Add(hint);
            return;
        }
        var minX = stations.Min(s => s.Position?.X ?? 0); var maxX = stations.Max(s => s.Position?.X ?? 0);
        var minY = stations.Min(s => s.Position?.Z + s.Position?.Y ?? 0); var maxY = stations.Max(s => s.Position?.Z + s.Position?.Y ?? 0);
        var points = stations.ToDictionary(s => s.MarketId, s => new Windows.Foundation.Point(60 + ((s.Position?.X ?? 0) - minX) / Math.Max(1, maxX - minX) * Math.Max(50, width - 190), 48 + ((s.Position?.Z + s.Position?.Y ?? 0) - minY) / Math.Max(1, maxY - minY) * Math.Max(50, height - 115)));
        foreach (var leg in Plan!.Legs)
        {
            var a = points[leg.From.MarketId]; var b = points[leg.To.MarketId];
            var offset = leg.Number % 2 == 0 ? 15d : -15d;
            var geometry = new PathGeometry(); var figure = new PathFigure { StartPoint = a };
            figure.Segments.Add(new QuadraticBezierSegment { Point1 = new((a.X + b.X) / 2 + offset, (a.Y + b.Y) / 2 - offset), Point2 = b }); geometry.Figures.Add(figure);
            canvas.Children.Add(new Microsoft.UI.Xaml.Shapes.Path { Data = geometry, Stroke = leg.Number == 1 ? Brush(255, 174, 72) : Brush(84, 222, 200, 160), StrokeThickness = 2, StrokeDashArray = leg.Number == 1 ? [] : [4, 4] });
            var label = new TextBlock { Text = $"{leg.Number:00}", FontSize = 11, Foreground = Brush(255, 174, 72), FontWeight = Microsoft.UI.Text.FontWeights.SemiBold };
            Canvas.SetLeft(label, (a.X + b.X) / 2 + offset); Canvas.SetTop(label, (a.Y + b.Y) / 2 - offset); canvas.Children.Add(label);
        }
        foreach (var station in stations)
        {
            var p = points[station.MarketId]; var first = station.MarketId == stations[0].MarketId;
            var outer = new Ellipse { Width = 24, Height = 24, Fill = first ? Brush(255, 174, 72, 35) : Brush(84, 222, 200, 30), Stroke = first ? Brush(255, 174, 72) : Brush(84, 222, 200), StrokeThickness = 1 };
            Canvas.SetLeft(outer, p.X - 12); Canvas.SetTop(outer, p.Y - 12); canvas.Children.Add(outer);
            var dot = new Ellipse { Width = 7, Height = 7, Fill = first ? Brush(255, 174, 72) : Brush(84, 222, 200) };
            Canvas.SetLeft(dot, p.X - 3.5); Canvas.SetTop(dot, p.Y - 3.5); canvas.Children.Add(dot);
            var label = new StackPanel { Spacing = 3 };
            label.Children.Add(new TextBlock { Text = station.SystemName, FontSize = 13, FontWeight = Microsoft.UI.Text.FontWeights.SemiBold });
            label.Children.Add(new TextBlock { Text = station.Name, FontSize = 10, Foreground = Brush(145, 163, 185), MaxWidth = 140, TextTrimming = TextTrimming.CharacterEllipsis });
            Canvas.SetLeft(label, p.X + 18); Canvas.SetTop(label, p.Y - 5); canvas.Children.Add(label);
        }
    }
}