原文:WPF 自定义的图表(适用大量数据绘制)下

上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标显示数据有明显的延迟。经过思考,我采用了以下两个办法解决这个问题:
1.将数据显示的文本与图表分离,作为一个单独的canvas,这样,显示文本数据的时候就不需要重画图表了
2.计算鼠标移动速度,当移动速度过快时,不绘制文本,减少数据文本的绘制频率
3.使用START_INDEX 和 END_INDEX来表示绘制数据的其实位置和结束位置,减少对整个数据的遍历

首先看前台代码
<UserControl x:Class="Zero_Gjy.UserControls.DrawChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Zero_Gjy.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ScrollViewer > <Grid x:Name="linechart" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> </Grid>
</ScrollViewer>
</UserControl>

在lineChart中分别加入图表的Canvas和文本数据的Canvas,修改之前的DrawingCanvas,把绘制数据文本的代码分离出来

DrawingCanvas.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading; namespace Zero_Gjy.UserControls
{
public class DrawingCanvas : Canvas
{
private List<Visual> visuals = new List<Visual>(); public const double YZero = 50;
public const double YMargin = 50;
private double YLabelLen = 5;
private double yHeight;
private Brush line1Color = Brushes.Black;
private Brush labelColor = Brushes.Black;
private Brush axisColor = Brushes.Black;
private Brush line2Color = Brushes.Black;
private double thinkness = 1;
private double canvasWidth = 0;
private double xWidth;
private const int yLinesCount = 12; List<LineDatas> allDatas;
private double canvasHeight;
int dataCount = 0;
int rtCount = 0;
public enum MouseMode
{
ZOOM,
VIEW
}
public MouseMode mMode = MouseMode.VIEW;
public DrawingCanvas()
{
this.Background = Brushes.Transparent;
this.HorizontalAlignment = HorizontalAlignment.Left;
this.VerticalAlignment = VerticalAlignment.Top;
this.Margin = new Thickness(0, 0, 0, YMargin);
AllDatas = new List<LineDatas>(); } //获取Visual的个数
protected override int VisualChildrenCount
{
get { return visuals.Count; }
} //获取Visual
protected override Visual GetVisualChild(int index)
{
return visuals[index];
} //添加Visual
public void AddVisual(Visual visual)
{
visuals.Add(visual); base.AddVisualChild(visual);
base.AddLogicalChild(visual);
} //删除Visual
public void RemoveVisual(Visual visual)
{
visuals.Remove(visual); base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
} //命中测试
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
return hitResult.VisualHit as DrawingVisual;
} //使用DrawVisual画Polyline
//DrawingVisual lineVisual;
public void addData(string title,double min,double max,DoubleCollection xData, DoubleCollection mData, DoubleCollection sData)
{
AllDatas.Add(new LineDatas(title, min, max, xData,mData, sData)); dataCount++;
rtCount = mData.Count;
}
public void removeFirst() {
for(int i = 0; i < AllDatas.Count; i++)
{
AllDatas[i].RtData.RemoveAt(0);
AllDatas[i].ThData.RemoveAt(0);
}
}
public void removeLast()
{
for (int i = 0; i < AllDatas.Count; i++)
{
AllDatas[i].RtData.RemoveAt(AllDatas[i].RtData.Count - 1);
AllDatas[i].ThData.RemoveAt(AllDatas[i].ThData.Count - 1);
}
}
/// <summary>
/// 添加数据点
/// </summary>
/// <param name="xdatas">x坐标</param>
/// <param name="rtdatas">实测数据</param>
/// <param name="thdatas">理论数据</param>
public void addPoint(double[] xdatas,double[] rtdatas,double[] thdatas)
{
if (rtdatas.Length != allDatas.Count)
throw new Exception() { Source="数据个数不匹配"};
for (int i = 0; i < allDatas.Count; i++)
{
AllDatas[i].XData.Insert(0, xdatas[i]);
AllDatas[i].RtData.Insert(0,rtdatas[i]);
AllDatas[i].ThData.Insert(0,thdatas[i]);
if (allDatas[i].Min > rtdatas[i])
allDatas[i].Min = rtdatas[i];
if (allDatas[i].Max < rtdatas[i])
allDatas[i].Max = rtdatas[i];
}
}
//清空所有数据
public void clearData()
{
AllDatas.Clear(); }
//将数据清零
public void cleanData()
{
foreach(LineDatas item in allDatas)
{
for(int i = 0; i < item.RtData.Count; i++)
{
item.RtData[i] = 0;
item.ThData[i] = 0;
}
item.Min = -1;
item.Max = 1;
}
}
public void Polyline()
{
//如果虚画布没有数据
if(this.visuals.Count == 0)
{
for(int i = 0; i < AllDatas.Count; i++)
{
this.visuals.Add(new DrawingVisual());
}
}
for(int count = 0; count < AllDatas.Count; count++){
//计算基础坐标系
double x0, y0;
x0 = YZero;
y0 = (count + 1) * YMargin + count * yHeight;
string title = AllDatas[count].Title; LineDatas datas = allDatas[count];
DrawingVisual lineVisual = (DrawingVisual)this.visuals[count];
DrawingContext dc = lineVisual.RenderOpen();
Pen penAxis = new Pen(AxisColor, Thinkness);
penAxis.Freeze(); int yLabelMax = (int)AllDatas[count].Max + 1;
int yLabelMin = (int)AllDatas[count].Min - 1;
//画标题
FormattedText fttitle = new FormattedText(title, new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 15, Brushes.Black);
dc.DrawText(fttitle, new Point(xWidth / 2+x0 - fttitle.Width / 2, y0 - fttitle.Height));
//画Y轴
dc.DrawLine(penAxis, new Point(x0, y0), new Point(x0, y0 + yHeight));
dc.DrawLine(penAxis, new Point(x0 - YLabelLen, y0), new Point(x0, y0));
dc.DrawLine(penAxis, new Point(x0 - YLabelLen, y0 + yHeight / 2), new Point(x0, y0 + yHeight / 2));
dc.DrawLine(penAxis, new Point(x0 - YLabelLen, y0 + yHeight), new Point(x0, y0 + yHeight));
//y轴文本
FormattedText ft1 = new FormattedText(yLabelMax.ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
dc.DrawText(ft1, new Point(x0 - YLabelLen - ft1.Width, y0 - ft1.Height / 2));
FormattedText ft2 = new FormattedText(((yLabelMax + yLabelMin) / 2).ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
dc.DrawText(ft2, new Point(x0 - YLabelLen - ft2.Width, y0 + YHeight / 2 - ft2.Height / 2));
FormattedText ft3 = new FormattedText(yLabelMin.ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
dc.DrawText(ft3, new Point(x0 - YLabelLen - ft3.Width, y0 + yHeight - ft3.Height / 2));
//画线
Pen linePen1 = new Pen(Line1Color, Thinkness);
linePen1.Freeze();
Pen linePen2 = new Pen(Line2Color, Thinkness);
linePen2.Freeze();
double ratio = (yLabelMax - yLabelMin) / yHeight;
double step = xWidth / (datas.EndIndex - datas.StartIndex +1);
//Console.WriteLine("=======datastep:" + step);
for (int i = datas.StartIndex; i < datas.EndIndex; i++)
{
//将数值转换成位置
//理论值
Point p3 = new Point(x0 + (i - datas.StartIndex)*step, y0 + (yLabelMax - datas.ThData[i]) / ratio);
Point p4 = new Point(x0 + (i - datas.StartIndex + 1)*step, y0 + (yLabelMax - datas.ThData[i + 1]) / ratio);
dc.DrawLine(linePen2, p3, p4);
//实测值
Point p1 = new Point(x0 +(i - datas.StartIndex) *step, y0 + (yLabelMax - datas.RtData[i]) / ratio);
Point p2 = new Point(x0 + (i - datas.StartIndex + 1)*step, y0 + (yLabelMax - datas.RtData[i + 1]) / ratio);
dc.DrawLine(linePen1, p1, p2);
}
//绘制纵向网格和x轴文本
Pen pen3 = new Pen(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#666666")), 1);
pen3.DashStyle = new DashStyle(new double[] { 2.5, 2.5 }, 0);
pen3.Freeze();
double stepX = xWidth / yLinesCount;
int stepData = (datas.EndIndex - datas.StartIndex + 1) / yLinesCount;
if (stepData < 1)
stepData = 1;
for (int i = 1; i < yLinesCount; i++)
{
//纵向网格
Point p1 = new Point(x0 + i * stepX, y0 + yHeight);
Point p2 = new Point(x0 + i * stepX, y0);
dc.DrawLine(pen3, p1, p2);
//x轴文本
FormattedText ftX = new FormattedText(datas.XData[i * stepData].ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
Point p3 = new Point(x0 + i * stepX - ftX.Width / 2, yHeight + y0);
dc.DrawText(ftX, p3);
}
dc.Close();
}
this.InvalidateVisual();
} public double YHeight
{
get
{
return yHeight;
} set
{
yHeight = value;
}
} public Brush LabelColor
{
get
{
return labelColor;
} set
{
labelColor = value;
}
} public Brush AxisColor
{
get
{
return axisColor;
} set
{
axisColor = value;
}
} public double Thinkness
{
get
{
return thinkness;
} set
{
thinkness = value;
}
} public static double YZero1
{
get
{
return YZero;
}
} public double CanvasWidth
{
get
{
return canvasWidth;
} set
{
canvasWidth = value;
this.Width = value;
xWidth = value - YMargin - YZero;
}
} public Brush Line2Color
{
get
{
return line2Color;
} set
{
line2Color = value;
}
} public Brush Line1Color
{
get
{
return line1Color;
} set
{
line1Color = value;
}
} public double CanvasHeight
{
get
{
return canvasHeight;
} set
{
canvasHeight = value;
}
} public int DataCount
{
get
{
return dataCount;
} set
{
dataCount = value;
}
} public int RtCount
{
get
{
return rtCount;
} set
{
rtCount = value;
}
} internal List<LineDatas> AllDatas
{
get
{
return allDatas;
} set
{
allDatas = value;
}
}
}
}

DrawingLine.CS

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading; namespace Zero_Gjy.UserControls
{
class DrawingLine : Canvas
{
private List<Visual> visuals = new List<Visual>();
DrawingCanvas drawingCanvas;
private double x0;
private double y0;
private double mWidth;
private double mHeight;
public enum MouseMode
{
ZOOM,
VIEW
}
public MouseMode mMode = MouseMode.VIEW;
private double canvasWidth;
public DrawingLine(DrawingCanvas _dc)
{
this.drawingCanvas = _dc;
this.Background = Brushes.Transparent;
this.HorizontalAlignment = HorizontalAlignment.Left;
this.VerticalAlignment = VerticalAlignment.Top;
this.Height = drawingCanvas.CanvasHeight;
this.Width = drawingCanvas.CanvasWidth; x0 = DrawingCanvas.YZero;
y0 = DrawingCanvas.YMargin; mHeight = _dc.AllDatas.Count * (DrawingCanvas.YMargin + _dc.YHeight); this.PreviewMouseLeftButtonDown += DrawingCanvas_MouseLeftButtonDown;
this.PreviewMouseLeftButtonUp += DrawingCanvas_MouseLeftButtonUp;
this.MouseMove += DrawingCanvas_MouseMove;
this.MouseLeave += DrawingCanvas_MouseLeave;
}
//鼠标离开画布
private void DrawingCanvas_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
if (mMode == MouseMode.VIEW)
{
this.RemoveVisual(textVisual);
this.InvalidateVisual();
}
}
//选中放大区域完成,显示放大区域
private void DrawingCanvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
isMouseDown = false;
mMode = MouseMode.VIEW;
endup = e.GetPosition(this).X;
if (endup < x0)
endup = x0;
if (endup > x0+mWidth)
endup = x0 + mWidth;
//重画 选中区域
int len = drawingCanvas.AllDatas[0].EndIndex - drawingCanvas.AllDatas[0].StartIndex+1;
if (drawingCanvas.AllDatas.Count < 1 || len < 1)
return;
double step = mWidth / len;
if (isMouseMoved && Math.Abs(endup - startDown) > step)
{
int startIndex = 0;
int endIndex = 0;
if (endup > startDown)
{
startIndex = (int)((startDown - x0) / step) + 1;
endIndex = (int)((endup - x0) / step);
}
else
{
startIndex = (int)((endup - x0) / step) + 1;
endIndex = (int)((startDown - x0) / step);
} foreach (LineDatas data in drawingCanvas.AllDatas)
{
data.EndIndex = data.StartIndex + endIndex;
data.StartIndex = data.StartIndex + startIndex;
}
drawingCanvas.Polyline();
this.RemoveVisual(rectVisual);
this.InvalidateVisual();
}
isMouseMoved = false;
}
double preMoved = DrawingCanvas.YZero;
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
//long preTime = 0;
private const long MIN_TIME= 15000;
private void DrawingCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{ double positionX = e.GetPosition(this).X;
if (mMode == MouseMode.VIEW)
{
int len = drawingCanvas.AllDatas[0].EndIndex - drawingCanvas.AllDatas[0].StartIndex+1;
if (positionX > x0 && positionX < x0+mWidth && Math.Abs(positionX - preMoved) >= mWidth / len)
{
//计算速度鼠标移动速度,如果速度过快 ,则不绘制
if (stopwatch.IsRunning)
{
stopwatch.Stop();
}
long curTime = stopwatch.ElapsedTicks;
//Console.WriteLine(curTime);
if(curTime > MIN_TIME)
{
this.PolyText(positionX);
}
stopwatch.Restart();
preMoved = positionX; }
}
else if (isMouseDown && startDown > x0 && startDown < mWidth+x0)
{
isMouseMoved = true;
this.PolyRect(startDown, positionX);
} //stopwatch.Start();
} private bool isMouseDown = false;
private bool isMouseMoved = false;
private double startDown;
private double endup;
private int clickTimes = 0;
private void DrawingCanvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{ isMouseDown = true;
mMode = MouseMode.ZOOM;
startDown = e.GetPosition(this).X;
this.RemoveVisual(textVisual);
this.InvalidateVisual();
//双击
clickTimes++;
DispatcherTimer timer = new DispatcherTimer(); timer.Interval = new TimeSpan(0, 0, 0, 0, 300); timer.Tick += (s, e1) => { timer.IsEnabled = false; clickTimes = 0; }; timer.IsEnabled = true; if (clickTimes % 2 == 0)
{
//Console.WriteLine("double");
timer.IsEnabled = false; clickTimes = 0;
foreach (LineDatas data in drawingCanvas.AllDatas)
{
data.StartIndex = 0;
data.EndIndex = data.RtData.Count - 1;
} drawingCanvas.Polyline();
drawingCanvas.InvalidateVisual();
//this.InvalidateVisual();
}
} //获取Visual的个数
protected override int VisualChildrenCount
{
get { return visuals.Count; }
} public double MWidth
{
get
{
return mWidth;
} set
{
mWidth = value;
}
} public double MHeight
{
get
{
return mHeight;
} set
{
mHeight = value;
}
} public double CanvasWidth
{
get
{
return canvasWidth;
} set
{
canvasWidth = value;
this.Width = value;
mWidth = value - x0 - y0;
}
} //获取Visual
protected override Visual GetVisualChild(int index)
{
return visuals[index];
} //添加Visual
public void AddVisual(Visual visual)
{
visuals.Add(visual); base.AddVisualChild(visual);
base.AddLogicalChild(visual);
} //删除Visual
public void RemoveVisual(Visual visual)
{
visuals.Remove(visual); base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
//visual = null;
} //命中测试
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
return hitResult.VisualHit as DrawingVisual;
} //绘制鼠标选择放大的矩形
DrawingVisual rectVisual;
public void PolyRect(double startx, double endx)
{
if (rectVisual != null)
{
this.RemoveVisual(rectVisual);
}
rectVisual = new DrawingVisual();
DrawingContext dc = rectVisual.RenderOpen(); Pen pen = new Pen(new SolidColorBrush(Color.FromArgb(100, 255, 200, 200)), 1);
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(100, 255, 200, 200)), pen, new Rect(new Point(startx, y0), new Point(endx, y0+mHeight)));
dc.Close();
this.AddVisual(rectVisual);
this.InvalidateVisual();
}
//绘制显示选中的数值
DrawingVisual textVisual;
public void PolyText(double xPosition)
{
if (drawingCanvas.AllDatas.Count < 1)
return;
if (textVisual != null)
{
this.RemoveVisual(textVisual);
}
textVisual = new DrawingVisual(); DrawingContext dc = textVisual.RenderOpen();
int len = drawingCanvas.AllDatas[0].EndIndex - drawingCanvas.AllDatas[0].StartIndex+1;
double step = mWidth / len;
// Console.WriteLine("*****linestep:" + step);
int index = (int)((xPosition - x0) / step);
double ax = x0 + index * step;
//竖线
Pen pen = new Pen(Brushes.Transparent, 3);
pen.Freeze();
FormattedText[] ftXs = new FormattedText[drawingCanvas.AllDatas.Count]; for (int i = 0; i < drawingCanvas.AllDatas.Count; i++)
{
int mIndex = index + drawingCanvas.AllDatas[i].StartIndex;
ftXs[i] = new FormattedText("X:" + drawingCanvas.AllDatas[i].XData[mIndex] + " 实测:" + drawingCanvas.AllDatas[i].RtData[mIndex] + " 设计:" + drawingCanvas.AllDatas[i].ThData[mIndex], new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 15, Brushes.White);
//计算是否超出范围
if (ax + ftXs[i].Width < x0+mWidth)
{
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), pen, new Rect(new Point(ax, (i+1)*y0+i*drawingCanvas.YHeight), new Point(ax + ftXs[i].Width, (i + 1) * y0 + i * drawingCanvas.YHeight + ftXs[i].Height)));
dc.DrawText(ftXs[i], new Point(ax, (i + 1) * y0 + i * drawingCanvas.YHeight));
}
else
{
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), pen, new Rect(new Point(ax - ftXs[i].Width, (i + 1) * y0 + i * drawingCanvas.YHeight), new Point(ax, (i + 1) * y0 + i * drawingCanvas.YHeight + ftXs[i].Height)));
dc.DrawText(ftXs[i], new Point(ax - ftXs[i].Width, (i + 1) * y0 + i * drawingCanvas.YHeight));
}
}
Pen penLine = new Pen(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), 3);
penLine.DashStyle = new DashStyle(new double[] { 2.5, 2.5 }, 0);
penLine.Freeze();
dc.DrawLine(penLine, new Point(ax,y0), new Point(ax, y0+mHeight));
dc.Close();
this.AddVisual(textVisual);
this.InvalidateVisual();
} }
}

上面两段代码中,我把需要绘制的数据属性单独抽象出来

LineDatas.CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media; namespace Zero_Gjy.UserControls
{
class LineDatas
{
string title;
double min;
double max;
DoubleCollection xData;
DoubleCollection rtData;
DoubleCollection thData;
int startIndex;
int endIndex;
public double Min
{
get
{
return min;
} set
{
min = value;
}
} public double Max
{
get
{
return max;
} set
{
max = value;
}
} public string Title
{
get
{
return title;
} set
{
title = value;
}
} public DoubleCollection RtData
{
get
{
return rtData;
} set
{
rtData = value;
min = value.Min();
max = value.Max();
}
} public DoubleCollection ThData
{
get
{
return thData;
} set
{
thData = value; }
} public int StartIndex
{
get
{
return startIndex;
} set
{
startIndex = value;
}
} public int EndIndex
{
get
{
return endIndex;
} set
{
endIndex = value;
}
} public DoubleCollection XData
{
get
{
return xData;
} set
{
xData = value;
}
} public LineDatas()
{
this.title = "";
this.Max = 0;
this.Min = 0;
this.XData = new DoubleCollection();
this.RtData = new DoubleCollection();
this.ThData = new DoubleCollection(); }
/// <summary>
///
/// </summary>
/// <param name="_title">数据标题</param>
/// <param name="min">数据最小值</param>
/// <param name="max">数据最大值</param>
/// <param name="_xData">x坐标</param>
/// <param name="rtdata">实测数据</param>
/// <param name="thdata">理论数据</param>
public LineDatas(string _title,double min, double max, DoubleCollection _xData, DoubleCollection rtdata,DoubleCollection thdata)
{
this.title = _title;
this.Min = min;
this.Max = max;
this.XData = _xData;
this.RtData = rtdata ;
this.ThData = thdata;
this.StartIndex = 0;
this.EndIndex = rtData.Count - 1;
}
public void clear()
{
this.XData.Clear();
this.RtData.Clear();
this.ThData.Clear();
}
}
}

经过这样的改进,鼠标在界面移动时显示数据明显顺畅了很多。



WPF 自定义的图表(适用大量数据绘制)下的更多相关文章

  1. WPF 自定义的图表(适用大量数据绘制)

    原文:WPF 自定义的图表(适用大量数据绘制) 在WPF中绘制图表比较简单,有很多的第三方控件,但是在绘制大量数据的时候,就显得有些吃力,即便是自己用StreamGeometry画也达不到理想的效果, ...

  2. Highcharts使用CSV格式数据绘制图表

    Highcharts使用CSV格式数据绘制图表 CSV(Comma-Separated Values,逗号分隔值文本格式)是採用逗号切割的纯文本数据.通常情况下.每一个数据之间使用逗号切割,几个相关数 ...

  3. linux环境安装nagiosgraph将nagios的性能数据绘制成动态图表?

    需求描述: 在安装完成nagios之后,比如有监控磁盘负载信息的,连接数的,进程数的,可以通过安装nagiosgraph软件, 将nagios的性能数据绘制成图表,可以看到一段时间内数据的变化 环境说 ...

  4. Highcharts使用表格数据绘制图表

    Highcharts使用表格数据绘制图表 在Highcharts中,同意用户使用网页中现有的表格数据作为数据来源,然后依据该数据来源绘制图表.对于一个典型的HTML表格.当中,第一列的数据会作为x轴刻 ...

  5. DevExpress WPF v19.2图表图形控件功能增强?速速种草

    通过DevExpress WPF Controls,你能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案. 无论是Office办公软件的衍 ...

  6. WPF 自定义柱状图 BarChart

    WPF 自定义柱状图 当前的Telerik控件.DevExpress控件在图表控件方面做得不错,但是有时项目中需要特定的样式,不是只通过修改图表的模板和样式就能实现的. 或者说,通过修改当前的第三方控 ...

  7. WPF 自定义雷达图

    自定义雷达图表如下: Git下载地址:https://github.com/Kybs0/RadarChartControl 1.创建UserControl,名为“RadarChartControl” ...

  8. WPF自定义LED风格数字显示控件

    原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...

  9. wpf 自定义圆形按钮

    wpf 自定义圆形按钮 效果图 默认样式 获取焦点样式 点击样式 下面是实现代码: 一个是自定义控件类,一个是控件类皮肤 using System; using System.Collections. ...

随机推荐

  1. Atitit &#160;&#160;图像处理&#160;平滑&#160;也称&#160;模糊,&#160;归一化块滤波、高斯滤波、中值滤波、双边滤波)

    Atitit   图像处理 平滑 也称 模糊, 归一化块滤波.高斯滤波.中值滤波.双边滤波) 是一项简单且使用频率很高的图像处理方法 用途 去噪 去雾 各种线性滤波器对图像进行平滑处理,相关OpenC ...

  2. [0x01 用Python讲解数据结构与算法] 关于数据结构和算法还有编程

    忍耐和坚持虽是痛苦的事情,但却能渐渐地为你带来好处. ——奥维德 一.学习目标 · 回顾在计算机科学.编程和问题解决过程中的基本知识: · 理解“抽象”在问题解决过程中的重要作用: · 理解并实现抽象 ...

  3. 博友的 编写高质量代码 改善java程序的151个建议

    编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html

  4. hdu 4115 Eliminate the Conflict ( 2-sat )

    Eliminate the Conflict Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...

  5. MyBatis学习总结1

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用 ...

  6. java面试入门总结

    最近正好有时间空下来,前一段时间本来打算呢,写一写阶段的总结,今天就来谈谈吧.作为一个java入门小白,之前就职于浙江大华,是通过大华10月份秋季招聘通过大华的面试. 浙江大华校招采用模式是先笔试.再 ...

  7. Teclast/台电 P98HD四核测评9.7寸台电P98HD 评测体验 (转载)

    自从苹果新iPad上市推出后,拥有Retina高清屏幕分辨率的平板让我们的视线一下子变得“清晰”起来,超高2048x1536分辨率也成为厂商们追捧的对象,在经历了双核时代配备高清分辨率对于硬件性能承载 ...

  8. 物流追踪 - -GPS和GPRS应用

    源码1: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<termios.h ...

  9. Apache服务器和tomcat服务器有什么区别(转)

    Apache与Tomcat都是Apache开源组织开发的用于处理HTTP服务的项目,两者都是免费的,都可以做为独立的Web服务器运行.Apache是Web服务器而Tomcat是Java应用服务器. A ...

  10. centos7.3安装MongoDB

    安装步骤: 1.配置包管理系统 vim /etc/yum.repos.d/mongodb.repo [mongodb] name=MongoDB Repository baseurl=http://d ...