using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; using Brush = System.Windows.Media.Brush; using Brushes = System.Windows.Media.Brushes; using Pen = System.Windows.Media.Pen; using Point = System.Windows.Point; namespace PulseDock.App.Controls { public class SparklineControl : FrameworkElement { public static readonly DependencyProperty ValuesProperty = DependencyProperty.Register( nameof(Values), typeof(IEnumerable), typeof(SparklineControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); public static readonly DependencyProperty LineColorProperty = DependencyProperty.Register( nameof(LineColor), typeof(Brush), typeof(SparklineControl), new FrameworkPropertyMetadata(Brushes.Cyan, FrameworkPropertyMetadataOptions.AffectsRender)); public static readonly DependencyProperty LineThicknessProperty = DependencyProperty.Register( nameof(LineThickness), typeof(double), typeof(SparklineControl), new FrameworkPropertyMetadata(1.5, FrameworkPropertyMetadataOptions.AffectsRender)); public IEnumerable? Values { get => (IEnumerable?)GetValue(ValuesProperty); set => SetValue(ValuesProperty, value); } public Brush LineColor { get => (Brush)GetValue(LineColorProperty); set => SetValue(LineColorProperty, value); } public double LineThickness { get => (double)GetValue(LineThicknessProperty); set => SetValue(LineThicknessProperty, value); } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); var values = Values?.ToArray(); if (values == null || values.Length < 2 || ActualWidth <= 0 || ActualHeight <= 0) return; double width = ActualWidth; double height = ActualHeight; float min = 0f; float max = 100f; // Scale percentage or range dynamically float actualMax = values.Max(); if (actualMax > 100f) max = actualMax; var geometry = new StreamGeometry(); using (var ctx = geometry.Open()) { double stepX = width / (values.Length - 1); for (int i = 0; i < values.Length; i++) { double x = i * stepX; float val = Math.Clamp(values[i], min, max); double normY = (val - min) / (max - min); double y = height - (normY * (height - 4)) - 2; var point = new Point(x, y); if (i == 0) ctx.BeginFigure(point, isFilled: false, isClosed: false); else ctx.LineTo(point, isStroked: true, isSmoothJoin: true); } } geometry.Freeze(); var pen = new Pen(LineColor, LineThickness); pen.Freeze(); drawingContext.DrawGeometry(null, pen, geometry); } } }