Enable dragging cursor inside chart
MODIFY
WalletWasabi.Fluent/Controls/LineChart.cs
WalletWasabi.Fluent/Controls/LineChart.cs
@@ -5,13 +5,15 @@ using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.Media;
namespace WalletWasabi.Fluent.Controls
{
public class LineChart : Control
{
- #region Properties
+ #region Avalonia Properties
#region Values
@@ -198,7 +200,9 @@ namespace WalletWasabi.Fluent.Controls
#endregion
- #region LineChart ctor
+ #endregion
+
+ #region static ctor
static LineChart()
{
@@ -220,6 +224,14 @@ namespace WalletWasabi.Fluent.Controls
#endregion
+ #region Fields
+
+ private bool _captured;
+
+ #endregion
+
+ #region Clr Properties
+
#region Values
public List<double>? Values
@@ -560,6 +572,11 @@ namespace WalletWasabi.Fluent.Controls
#endregion
+ private static double Clamp(double val, double min, double max)
+ {
+ return Math.Min(Math.Max(val, min), max);
+ }
+
private static double ScaleHorizontal(double value, double max, double range)
{
return value / max * range;
@@ -611,10 +628,54 @@ namespace WalletWasabi.Fluent.Controls
};
}
+ public LineChart()
+ {
+ AddHandler(PointerPressedEvent, PointerPressedHandler, RoutingStrategies.Tunnel);
+ AddHandler(PointerReleasedEvent, PointerReleasedHandler, RoutingStrategies.Tunnel);
+ AddHandler(PointerMovedEvent, PointerMovedHandler, RoutingStrategies.Tunnel);
+ }
+
+ private void UpdateCursorPosition(double x)
+ {
+ var rangeValues = MaxValue - MinValue;
+ var rangeArea = Bounds.Width - ValuesMargin.Left - ValuesMargin.Right;
+ var value = Clamp(x - ValuesMargin.Left, 0, rangeArea);
+ CursorValue = MaxValue - rangeValues / rangeArea * value;
+ }
+
+ private void PointerMovedHandler(object? sender, PointerEventArgs e)
+ {
+ if (_captured)
+ {
+ var position = e.GetPosition(this);
+ UpdateCursorPosition(position.X);
+ }
+ }
+
+ private void PointerReleasedHandler(object? sender, PointerReleasedEventArgs e)
+ {
+ if (_captured)
+ {
+ Cursor = new Cursor(StandardCursorType.Arrow);
+ _captured = false;
+ }
+ }
+
+ private void PointerPressedHandler(object? sender, PointerPressedEventArgs e)
+ {
+ var position = e.GetPosition(this);
+ UpdateCursorPosition(position.X);
+ Cursor = new Cursor(StandardCursorType.SizeWestEast);
+ _captured = true;
+ }
+
private LineChartState CreateChartState(double width, double height)
{
var state = new LineChartState();
+ state.Width = width;
+ state.Height = height;
+
state.AreaMargin = ValuesMargin;
state.AreaWidth = width - state.AreaMargin.Left - state.AreaMargin.Right;
state.AreaHeight = height - state.AreaMargin.Top - state.AreaMargin.Bottom;
@@ -656,22 +717,6 @@ namespace WalletWasabi.Fluent.Controls
return state;
}
- public override void Render(DrawingContext context)
- {
- base.Render(context);
-
- var state = CreateChartState(Bounds.Width, Bounds.Height);
-
- DrawAreaFill(context, state);
- DrawAreaStroke(context, state);
- DrawCursor(context, state);
- DrawXAxis(context, state);
- DrawYAxis(context, state);
- DrawYAxisTitle(context, state);
- DrawLabels(context, state);
- DrawBorder(context, state);
- }
-
private void DrawAreaFill(DrawingContext context, LineChartState state)
{
if (state.Points is null)
@@ -872,17 +917,29 @@ namespace WalletWasabi.Fluent.Controls
private void DrawBorder(DrawingContext context, LineChartState state)
{
var brush = BorderBrush;
- if (brush is null)
- {
- return;
- }
var thickness = BorderThickness;
var radiusX = BorderRadiusX;
var radiusY = BorderRadiusY;
var pen = new Pen(brush, thickness);
var rect = new Rect(0, 0, state.Width, state.Height);
var rectDeflate = rect.Deflate(thickness * 0.5);
- context.DrawRectangle(null, pen, rectDeflate, radiusX, radiusY);
+ context.DrawRectangle(Brushes.Transparent, pen, rectDeflate, radiusX, radiusY);
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ base.Render(context);
+
+ var state = CreateChartState(Bounds.Width, Bounds.Height);
+
+ DrawAreaFill(context, state);
+ DrawAreaStroke(context, state);
+ DrawCursor(context, state);
+ DrawXAxis(context, state);
+ DrawYAxis(context, state);
+ DrawYAxisTitle(context, state);
+ DrawLabels(context, state);
+ DrawBorder(context, state);
}
private class LineChartState

MODIFY
WalletWasabi.Fluent/Views/TestLineChartView.axaml
WalletWasabi.Fluent/Views/TestLineChartView.axaml
</Style>
<!-- LineChart Border -->
<Style Selector="c|LineChart.border">
- <Setter Property="BorderBrush" Value="Black" />
+ <Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderRadiusX" Value="4" />
<Setter Property="BorderRadiusY" Value="4" />
DockPanel.Dock="Left"/>
<Slider x:Name="CursorValue1"
Classes="cursor"
- Minimum="2"
- Maximum="1008"
- Value="36"
+ Minimum="{Binding #SolidLineChart.MinValue}"
+ Maximum="{Binding #SolidLineChart.MaxValue}"
+ Value="{Binding #SolidLineChart.CursorValue}"
Margin="0,0,30,0"/>
</DockPanel>
- <c:LineChart Classes="labels cursor border yAxis yAxisTitle"
+ <c:LineChart x:Name="SolidLineChart"
+ Classes="labels cursor border yAxis yAxisTitle"
Values="{Binding Values}"
+ CursorValue="36"
Labels="{Binding Labels}"
MinValue="2"
MaxValue="1008"
Fill="#C6DAFC"
Stroke="#4285F4"
StrokeThickness="2"
- CursorValue="{Binding #CursorValue1.Value}"
YAxisTitle="More Expensive">
</c:LineChart>
</DockPanel>
DockPanel.Dock="Left"/>
<Slider x:Name="CursorValue2"
Classes="cursor"
- Minimum="2"
- Maximum="1008"
- Value="36"
+ Minimum="{Binding #GradientLineChart.MinValue}"
+ Maximum="{Binding #GradientLineChart.MaxValue}"
+ Value="{Binding #GradientLineChart.CursorValue}"
Margin="0,0,30,0"/>
</DockPanel>
- <c:LineChart Classes="labels cursor border yAxis yAxisTitle"
+ <c:LineChart x:Name="GradientLineChart"
+ Classes="labels cursor border yAxis yAxisTitle"
Values="{Binding Values}"
Labels="{Binding Labels}"
+ CursorValue="36"
MinValue="2"
MaxValue="1008"
LogarithmicScale="False"
ValuesMargin="60,30,30,60"
StrokeThickness="2"
- CursorStroke="#72BD81"
- CursorThickness="2"
- CursorValue="{Binding #CursorValue2.Value}"
YAxisTitle="More Expensive">
<c:LineChart.Fill>
<LinearGradientBrush StartPoint="50%,0%" EndPoint="50%,100%">

Enable dragging cursor inside chart