我正试图使用绘制DateTime
和Integer
值的动态数据显示创建一个实时图表。我需要的是用固定的轴值平滑滚动X轴。就像平移一样,即当您从中心拖动绘图时,它会随着鼠标光标流畅地移动。我希望有一个类似的行为自动。
当前,当更改计时器中的数据源时,轴范围会动态变化,滚动不平滑。有可能改变这种行为吗。有什么想法,请帮忙。
我尝试在400毫秒的计时器中动态更新日期和整数数据源,这会产生一个基于数据源的轴范围变化的实时图。
这是测试代码:
窗口加载
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();
计时器勾选
Random rnd = new Random();
TestPoint pt = new TestPoint (rnd.Next(1, 500), DateTime.Now);
ds.AppendAsync(plotter.Viewport.Dispatcher, pt);
我相信你在追求这样的东西:
// 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));
在限制是控制用户所见内容的另一种方式的情况下,下面是一个非常基本的例子:
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;
}
}
基本上,在一个限制中,您所需要的只是用上面的签名重写Apply
方法。
在您的情况下,如果您希望在-20<->中对newDataRect.Y
和newDataRect.Height
进行约束,您可能还希望添加对它们的限制520(或者无论如何),但我将把这件事留给你——基本想法在上面。
希望这能有所帮助!如果以上任何一项都没有意义,请告诉我:)。
一种(不一定很神奇)平滑滚动的方法:
添加另一个计时器,例如,在初始化时:
animationTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(20) };
animationTimer.Tick += animationTimer_Tick;
animationTimer.Start();
我使用DispatcherTimer
而不是Timer
,因为ViewPort
的移动需要在UI线程上完成。然后只需:
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;
}
当然,你需要从用户体验的角度仔细考虑用户应该如何/是否能够中断滚动并重新启用它。但我将把这件事留给你。。!
但是我上面给出的所有代码都应该可以工作(或者至少在本地工作!)如果你有任何问题,请告诉我。
我确实遇到了一些轴在动画过程中表现奇怪的问题,我认为这基本上是轴TicksProvider
的一个错误,所以如果有必要,你可能需要实现自己的:dateAxis.TicksProvider = new CustomTicksProvider();
,CustomTicksProvider
继承自TimeTicksProviderBase<DateTime>
,但用谷歌搜索实现应该相对简单。
祝你好运!