Created
April 17, 2020 08:37
-
-
Save dtaylor-530/c1236e1648ca6a577c17611080304817 to your computer and use it in GitHub Desktop.
Multi-line Tracker for OxyPlot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#nullable enable | |
using OxyPlot; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reactive.Linq; | |
using OxyPlot.Series; | |
namespace OxyPlotEx | |
{ | |
/// <summary> | |
/// Provides a plot manipulator for tracker functionality. | |
/// </summary> | |
public class TrackerManipulator1 : TrackerManipulator | |
{ | |
/// <summary> | |
/// The current series. | |
/// </summary> | |
private Series? currentSeries; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="TrackerManipulator" /> class. | |
/// </summary> | |
/// <param name="plotView">The plot view.</param> | |
public TrackerManipulator1(IPlotView plotView) | |
: base(plotView) | |
{ | |
} | |
/// <summary> | |
/// Occurs when the input device changes position during a manipulation. | |
/// </summary> | |
/// <param name="e">The <see cref="OxyPlot.OxyMouseEventArgs" /> instance containing the event data.</param> | |
public override void Delta(OxyMouseEventArgs e) | |
{ | |
base.Delta(e); | |
e.Handled = true; | |
if (Return()) return; | |
var results = SelectResults().ToArray(); | |
var first = results.FirstOrDefault(); | |
if (first != null) | |
{ | |
var htr = new TrackerHitResult1(results.Where(a => a != null).ToDictionary(a => a.Text.Split('\n').First(), a => a.DataPoint.Y), first); | |
this.PlotView.ShowTracker(htr); | |
this.PlotView.ActualModel.RaiseTrackerChanged(htr); | |
} | |
IEnumerable<TrackerHitResult?> SelectResults() | |
=> | |
from series in PlotView.ActualModel.Series.OfType<XYAxisSeries>() | |
orderby series.Title == currentSeries?.Title descending | |
select GetNearestHit(series, e.Position, this.Snap, this.PointsOnly); | |
bool Return() | |
{ | |
var actualModel = this.PlotView.ActualModel; | |
if (actualModel == null || !actualModel.PlotArea.Contains(e.Position.X, e.Position.Y)) | |
{ | |
return true; | |
} | |
if (this.currentSeries == null || !this.LockToInitialSeries) | |
{ | |
// get the nearest | |
this.currentSeries = actualModel.GetSeriesFromPoint(e.Position, 20); | |
if (this.currentSeries == null) | |
{ | |
if (!this.LockToInitialSeries) | |
{ | |
this.PlotView.HideTracker(); | |
} | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
/// <summary> | |
/// Gets the nearest tracker hit. | |
/// </summary> | |
/// <param name="series">The series.</param> | |
/// <param name="point">The point.</param> | |
/// <param name="snap">Snap to points.</param> | |
/// <param name="pointsOnly">Check points only (no interpolation).</param> | |
/// <returns>A tracker hit result.</returns> | |
private static TrackerHitResult? GetNearestHit(Series series, ScreenPoint point, bool snap, bool pointsOnly) | |
{ | |
// Check data points only | |
if (snap || pointsOnly) | |
{ | |
var result = series?.GetNearestPoint(point, false); | |
if (result != null && result.Position.DistanceTo(point) < 20) | |
{ | |
return result; | |
} | |
} | |
// Check between data points (if possible) | |
if (!pointsOnly) | |
{ | |
return series?.GetNearestPoint(point, true); | |
} | |
return null; | |
} | |
} | |
public class TrackerHitResult1 : TrackerHitResult | |
{ | |
public Dictionary<string, double> Values { get; private set; } | |
public TrackerHitResult1(Dictionary<string, double> values, TrackerHitResult trackerHitResult) | |
{ | |
this.Values = values; | |
this.Index = trackerHitResult.Index; | |
this.DataPoint = trackerHitResult.DataPoint; | |
this.Item = trackerHitResult.Item; | |
this.LineExtents = trackerHitResult.LineExtents; | |
this.PlotModel = trackerHitResult.PlotModel; | |
this.Position = trackerHitResult.Position; | |
this.Series = trackerHitResult.Series; | |
this.Text = trackerHitResult.Text; | |
} | |
} | |
} | |
<oxy:PlotView x:Name="plotView" > | |
<oxy:PlotView.DefaultTrackerTemplate> | |
<ControlTemplate> | |
<oxy:TrackerControl Position="{Binding Position}" | |
BorderThickness="2" BorderBrush="LightSteelBlue" LineStroke="SteelBlue" | |
LineExtents="{Binding PlotModel.PlotArea}"> | |
<oxy:TrackerControl.Content> | |
<ItemsControl ItemsSource="{Binding Values}"></ItemsControl> | |
</oxy:TrackerControl.Content> | |
</oxy:TrackerControl> | |
</ControlTemplate> | |
</oxy:PlotView.DefaultTrackerTemplate> | |
</oxy:PlotView> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on idea from the article Multi-line Tracker for OxyPlot @
https://www.codeproject.com/Tips/1075272/Multi-line-Tracker-for-OxyPlot
for a tracker that has information on all lines in plot