Skip to content

Instantly share code, notes, and snippets.

@dtaylor-530
Created April 17, 2020 08:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dtaylor-530/c1236e1648ca6a577c17611080304817 to your computer and use it in GitHub Desktop.
Save dtaylor-530/c1236e1648ca6a577c17611080304817 to your computer and use it in GitHub Desktop.
Multi-line Tracker for OxyPlot
#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>
@dtaylor-530
Copy link
Author

dtaylor-530 commented Apr 17, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment