|
@@ -1,11 +1,186 @@
|
|
|
-using Avalonia.Controls;
|
|
|
+using Avalonia;
|
|
|
+using Avalonia.Controls;
|
|
|
+using Avalonia.Data;
|
|
|
+using Avalonia.Media;
|
|
|
+using Mapsui;
|
|
|
+using Mapsui.Layers;
|
|
|
+using Mapsui.Projections;
|
|
|
+using Mapsui.Styles;
|
|
|
+using ReactiveUI;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Collections.ObjectModel;
|
|
|
+using System.Collections.Specialized;
|
|
|
+using System.Linq;
|
|
|
+using Color = Mapsui.Styles.Color;
|
|
|
|
|
|
namespace PRS.Avalonia.Modules;
|
|
|
|
|
|
public partial class EquipmentMapsView : UserControl
|
|
|
{
|
|
|
+ public static readonly StyledProperty<ObservableCollection<Marker>> JobMarkersProperty
|
|
|
+ = AvaloniaProperty.Register<EquipmentMapsView, ObservableCollection<Marker>>(nameof(JobMarkers), new());
|
|
|
+
|
|
|
+ public static readonly StyledProperty<ObservableCollection<Marker>> EquipmentMarkersProperty
|
|
|
+ = AvaloniaProperty.Register<EquipmentMapsView, ObservableCollection<Marker>>(nameof(EquipmentMarkers), new());
|
|
|
+
|
|
|
+ public static readonly StyledProperty<Point> CoordinatesProperty
|
|
|
+ = AvaloniaProperty.Register<EquipmentMapsView, Point>(nameof(JobMarkers), new());
|
|
|
+
|
|
|
+ public static readonly StyledProperty<int> ZoomLevelProperty
|
|
|
+ = AvaloniaProperty.Register<EquipmentMapsView, int>(nameof(EquipmentMarkers), new());
|
|
|
+
|
|
|
+ private readonly MemoryLayer _jobLayer;
|
|
|
+ private readonly MemoryLayer _equipmentLayer;
|
|
|
+
|
|
|
+ public ObservableCollection<Marker> JobMarkers
|
|
|
+ {
|
|
|
+ get => GetValue(JobMarkersProperty);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ObservableCollection<Marker> EquipmentMarkers
|
|
|
+ {
|
|
|
+ get => GetValue(EquipmentMarkersProperty);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Point Coordinates
|
|
|
+ {
|
|
|
+ get => GetValue(CoordinatesProperty);
|
|
|
+ }
|
|
|
+
|
|
|
+ public int ZoomLevel
|
|
|
+ {
|
|
|
+ get => GetValue(ZoomLevelProperty);
|
|
|
+ }
|
|
|
+
|
|
|
+ static EquipmentMapsView()
|
|
|
+ {
|
|
|
+ JobMarkersProperty.Changed.AddClassHandler<EquipmentMapsView>(JobMarkersChanged);
|
|
|
+ EquipmentMarkersProperty.Changed.AddClassHandler<EquipmentMapsView>(EquipmentMarkersChanged);
|
|
|
+ CoordinatesProperty.Changed.AddClassHandler<EquipmentMapsView>(CoordinatesChanged);
|
|
|
+ ZoomLevelProperty.Changed.AddClassHandler<EquipmentMapsView>(ZoomLevelChanged);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ZoomLevelChanged(EquipmentMapsView view, AvaloniaPropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ view.Map.Map.Navigator.ZoomToLevel(view.ZoomLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void CoordinatesChanged(EquipmentMapsView view, AvaloniaPropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ var point = SphericalMercator.FromLonLat(view.Coordinates.Y, view.Coordinates.X);
|
|
|
+ view.Map.Map.Navigator.CenterOn(point.x, point.y);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void JobMarkersChanged(EquipmentMapsView view, AvaloniaPropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ if(args.OldValue is INotifyCollectionChanged changed)
|
|
|
+ {
|
|
|
+ changed.CollectionChanged -= view.JobMarkers_CollectionChanged;
|
|
|
+ }
|
|
|
+ view.JobMarkers.CollectionChanged += view.JobMarkers_CollectionChanged;
|
|
|
+ view._jobLayer.Features = view.JobMarkers.Select(x => x.ToFeature(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void EquipmentMarkersChanged(EquipmentMapsView view, AvaloniaPropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ if(args.OldValue is INotifyCollectionChanged changed)
|
|
|
+ {
|
|
|
+ changed.CollectionChanged -= view.EquipmentMarkers_CollectionChanged;
|
|
|
+ }
|
|
|
+ view.EquipmentMarkers.CollectionChanged += view.EquipmentMarkers_CollectionChanged;
|
|
|
+ view._equipmentLayer.Features = view.EquipmentMarkers.Select(x => x.ToFeature(false));
|
|
|
+ }
|
|
|
+
|
|
|
public EquipmentMapsView()
|
|
|
{
|
|
|
InitializeComponent();
|
|
|
+
|
|
|
+ Bind(JobMarkersProperty, new Binding(nameof(EquipmentMapsViewModel.JobMarkers)));
|
|
|
+ Bind(EquipmentMarkersProperty, new Binding(nameof(EquipmentMapsViewModel.EquipmentMarkers)));
|
|
|
+ Bind(CoordinatesProperty, new Binding(nameof(EquipmentMapsViewModel.Coordinates)));
|
|
|
+ Bind(ZoomLevelProperty, new Binding(nameof(EquipmentMapsViewModel.ZoomLevel)));
|
|
|
+
|
|
|
+ _jobLayer = CreateJobLayer();
|
|
|
+ _equipmentLayer = CreateEquipmentLayer();
|
|
|
+
|
|
|
+ Map.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer());
|
|
|
+ Map.Map.Layers.Add(_jobLayer);
|
|
|
+ Map.Map.Layers.Add(_equipmentLayer);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void EquipmentMarkers_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ _equipmentLayer.Features = EquipmentMarkers.Select(x => x.ToFeature(false));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void JobMarkers_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ _jobLayer.Features = JobMarkers.Select(x => x.ToFeature(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ private MemoryLayer CreateJobLayer()
|
|
|
+ {
|
|
|
+ var layer = new MemoryLayer
|
|
|
+ {
|
|
|
+ Name = "Job Layer",
|
|
|
+ Features = JobMarkers.Select(x => x.ToFeature(true)),
|
|
|
+ Style = new SymbolStyle
|
|
|
+ {
|
|
|
+ SymbolScale = 0.2,
|
|
|
+ SymbolOffset = new(),
|
|
|
+ SymbolRotation = 45,
|
|
|
+ SymbolType = SymbolType.Rectangle,
|
|
|
+ Fill = new Mapsui.Styles.Brush(Color.Red),
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return layer;
|
|
|
+ }
|
|
|
+
|
|
|
+ private MemoryLayer CreateEquipmentLayer()
|
|
|
+ {
|
|
|
+ var layer = new MemoryLayer
|
|
|
+ {
|
|
|
+ Name = "Equipment Layer",
|
|
|
+ Features = EquipmentMarkers.Select(x => x.ToFeature(false)),
|
|
|
+ Style = new SymbolStyle
|
|
|
+ {
|
|
|
+ SymbolScale = 0.25,
|
|
|
+ SymbolOffset = new(),
|
|
|
+ SymbolType = SymbolType.Ellipse,
|
|
|
+ Fill = new Mapsui.Styles.Brush(Color.Blue),
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return layer;
|
|
|
+ }
|
|
|
+
|
|
|
+ public class Marker(string code, double latitude, double longitude)
|
|
|
+ {
|
|
|
+ public string Code { get; set; } = code;
|
|
|
+
|
|
|
+ public Point Coordinates { get; set; } = new(longitude, latitude);
|
|
|
+
|
|
|
+ public IFeature ToFeature(bool isJob)
|
|
|
+ {
|
|
|
+ var point = SphericalMercator.FromLonLat(Coordinates.X, Coordinates.Y);
|
|
|
+ var feature = new PointFeature(point.x, point.y)
|
|
|
+ {
|
|
|
+ ["Label"] = Code,
|
|
|
+ Styles =
|
|
|
+ {
|
|
|
+ new LabelStyle
|
|
|
+ {
|
|
|
+ Text = Code,
|
|
|
+ Offset = new(8, 0),
|
|
|
+ HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Left,
|
|
|
+ ForeColor = isJob ? Color.Red : Color.Blue,
|
|
|
+ BackColor = new(Color.Transparent)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return feature;
|
|
|
+ }
|
|
|
}
|
|
|
}
|