实现方式一:
将数据(Point[])根据索引沿X轴使用虚拟画布进行绘制,每个数据绘制大小为1px * 1px;最终绘制出的宽度等于数据的总长度。标记并存储当前绘制的图为PreviousBitmap; 继续置顶绘制第二组数据,第二组数据绘制完后,将标记的PreviousBitmap作为Image在Y轴距离顶部距离为1px的地方用DrawingContext.DrawImage()方式绘制,以此类推。核心代码如下:
private void DoAddDataArray(Point[] arrPoints) { this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { double dPixelWidth = Pixel; double dContainerWidth = this.VbxContainer.ActualWidth; double dContainerHeight = this.VbxContainer.ActualHeight; double dPixelHeight = Pixel/2d; double dCellHeight = 1; double dCellWidth = 1; DrawingVisual drawingVisual = new DrawingVisual(); DrawingContext drawingContext = drawingVisual.RenderOpen(); drawingContext.DrawRectangle(new SolidColorBrush(Colors.Blue), new Pen(), new Rect(0, 0, dPixelWidth, dCellHeight)); // 绘制新数据 for (int i = 0; i < arrPoints.Length; i++) { double dCellX = Math.Round(((arrPoints[i].X - MinAxisX) / (MaxAxisX - MinAxisX)) * Pixel); double dY = arrPoints[i].Y; Color oColor = this.GetColor(dY); //drawingContext.DrawRectangle(new SolidColorBrush(oColor), // new Pen(), new Rect(dCellX, 0, dCellWidth, dCellHeight)); LinearGradientBrush lineBrush = new LinearGradientBrush(); lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 0)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.25)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.5)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.75)); lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1)); drawingContext.DrawRectangle(lineBrush, new Pen(), new Rect(dCellX-1, 0, dCellWidth + 2, dCellHeight)); } // 绘制历史数据 if (this.PreviousBitmap != null) drawingContext.DrawImage(this.PreviousBitmap, new Rect(0, dCellHeight, dPixelWidth, dPixelHeight)); drawingContext.Close(); // 生成图像处理 RenderTargetBitmap rtbCurrent = new RenderTargetBitmap((int)dPixelWidth, (int)dPixelHeight, 96, 96, PixelFormats.Pbgra32); rtbCurrent.Render(drawingVisual); this.PreviousBitmap = rtbCurrent; // 当前绘制的存为历史,下次绘制时直接调用 this.ImgMain.Source = rtbCurrent; // 显示绘制的图像 })); }
运行效果
实现方式二:
将数据(Point[])根据索引沿X轴使用虚拟画布进行绘制,每个数据绘制大小为1px * 1px;最终绘制出的宽度等于数据的总长度。创建一个Rectangle,将绘制的图赋值给Rectangle.Fill属性,将绘制过程中不断创建的Rectangle插入控件Stackpanel的首位。核心代码如下:
private void DoAddDataArray(Point[] arrPoints) { this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { double dPixelWidth = Pixel; double dContainerWidth = this.VbxContainer.ActualWidth; double dContainerHeight = this.VbxContainer.ActualHeight; double dPixelHeight = Pixel / 2d; DrawingVisual drawingVisual = new DrawingVisual(); DrawingContext drawingContext = drawingVisual.RenderOpen(); drawingContext.DrawRectangle(new SolidColorBrush(Colors.Blue), new Pen(), new Rect(0, 0, dPixelWidth, 1)); // 绘制新数据 double dCellHeight = 1; double dCellWidth = 1; for (int i = 0; i < arrPoints.Length; i++) { double dCellX = Math.Round(((arrPoints[i].X - MinAxisX) / (MaxAxisX - MinAxisX)) * Pixel); double dY = arrPoints[i].Y; Color oColor = this.GetColor(dY); //drawingContext.DrawRectangle(new SolidColorBrush(oColor), // new Pen(), new Rect(dCellX, 0, dCellWidth, dCellHeight)); LinearGradientBrush lineBrush = new LinearGradientBrush(); lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 0)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.25)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.5)); lineBrush.GradientStops.Add(new GradientStop(oColor, 0.75)); lineBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1)); drawingContext.DrawRectangle(lineBrush, new Pen(), new Rect(dCellX - 0.5, 0, dCellWidth + 1, dCellHeight)); } drawingContext.Close(); // 生成图像处理 RenderTargetBitmap rtbCurrent = new RenderTargetBitmap((int)dPixelWidth, (int)1, 96, 96, PixelFormats.Pbgra32); rtbCurrent.Render(drawingVisual); Rectangle rect = new Rectangle(); rect.Width = Pixel; rect.Height = 1; rect.Fill = new ImageBrush(rtbCurrent); // SpContainers ---- Stackpanel this.SpContainers.Children.Insert(0, rect); if (this.SpContainers.Children.Count > 500) this.SpContainers.Children.RemoveAt(500); })); }
运行效果:
相对而言,方式二由于不断插入新的Rectangle。下移效果为控件位置变化所呈现,不像方式一是一张完整图,故画质欠缺。
性能和测试:
采用Timer生成随机数据进行测试。10毫秒1组,每组1000个数据点。 相当于每秒绘制10万个点。
测试时在Release模式下,开启多个子模块,性能勉强能接受。
环境:
语言: C#
工程:WPF
工具:Visual Studio 2017
系统:Windows
第三方插件:无
微信扫码下载源代码: