98 lines
3.3 KiB
C#
98 lines
3.3 KiB
C#
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<float>),
|
|
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<float>? Values
|
|
{
|
|
get => (IEnumerable<float>?)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);
|
|
}
|
|
}
|
|
}
|