I believe you're after something like this:
// Your code (unchanged)
timer = new Timer(400);
ds = new ObservableDataSource<VoltagePoint>();
ds.SetXMapping(x => dateAxis.ConvertToDouble(x.Date));
ds.SetYMapping(y => y.Voltage);
plotter.AddLineGraph(ds, 2, "Sample");
timer.Start();
// Make the Viewport not move when items are added.
plotter.Viewport.AutoFitToView = false;
// Put in your initial viewing dimensions
var xMin = dateAxis.ConvertToDouble(DateTime.Now);
var startXMax = dateAxis.ConvertToDouble(DateTime.Now.AddMinutes(1));
var startYMin = -20;
var startYMax = 520;
// Set the initial visible area.
plotter.Visible = new Rect { X = xMin, Width = startXMax - xMin, Y = startYMin, Height = startYMax - startYMin };
// If you wish, you can also restrict where the user can scroll:
plotter.Viewport.Restrictions.Add(new CustomAxisRestriction(xMin));
Where the restriction is another way of controlling what the user sees, a very basic example is below:
public class CustomAxisRestriction : ViewportRestrictionBase
{
private double xMin;
public CustomAxisRestriction(double xMin)
{
this.xMin = xMin;
}
public override Rect Apply(Rect oldDataRect, Rect newDataRect, Viewport2D viewport)
{
newDataRect.X = Math.Max(newDataRect.X, xMin);
return newDataRect;
}
}
Basically, all you need in a restriction is an override of the Apply
method, with the above signature.
In your case, you might also want to add restrictions on newDataRect.Y
and newDataRect.Height
, if you wish to constrain them in -20 <-> 520 (or however), but I'll leave that up to you - the basic idea is above.
Hope this helps! Let me know if any of the above doesn't make sense :).
A (not necessarily fantastic) method for smooth scrolling:
Add another timer, eg, on initializing:
animationTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) };
animationTimer.Tick += animationTimer_Tick;
animationTimer.Start();
I use a DispatcherTimer
instead of a Timer
because the moving of the ViewPort
needs to be done on the UI Thread. Then just have:
private void animationTimer_Tick(object sender, EventArgs e)
{
var oldRect = plotter.Visible;
oldRect.X = Math.Max(oldRect.X, dateAxis.ConvertToDouble(DateTime.Now.AddMinutes(-0.1)));
plotter.Visible = oldRect;
}
Of course, you need to think carefully from a UX perspective on how / whether the user should be able to interrupt this scrolling, and re-enable it. But I'll leave that down to you..!
But all the code I've given above should work (or at least was working locally!) Let me know if you have any problems with it.
I did have a few problems with the axis behaving oddly during animation, I think this is basically a bit of a bug with the axis TicksProvider
, so if necessary, you might need to implement your own: dateAxis.TicksProvider = new CustomTicksProvider();
, with CustomTicksProvider
inheriting from TimeTicksProviderBase<DateTime>
, but that should be relatively straightforward to implement with a google search.
Good luck!