# 2、坐标轴绘制

 1 <Canvas Margin="5">
2     <Line x:Name="x_axis" Stroke="Black" StrokeThickness="3" X1="40" Y1="280" X2="480" Y2="280" StrokeStartLineCap="Round"/>
3     <Line x:Name="y_axis" Stroke="Black" StrokeThickness="3" X1="40" Y1="280" X2="40" Y2="30" StrokeStartLineCap="Round"/>
4     <Path x:Name="x_axisArrow" Fill="Black">
5         <Path.Data>
6             <PathGeometry>
7                 <PathFigure StartPoint="480,276" IsClosed="True">
8                     <LineSegment Point="480,284"/>
9                     <LineSegment Point="490,280"/>
10                 </PathFigure>
11             </PathGeometry>
12         </Path.Data>
13     </Path>
14     <Path x:Name="y_axisArrow" Fill="Black">
15         <Path.Data>
16             <PathGeometry>
17                 <PathFigure StartPoint="36,30" IsClosed="True">
18                     <LineSegment Point="44,30"/>
19                     <LineSegment Point="40,20"/>
20                 </PathFigure>
21             </PathGeometry>
22         </Path.Data>
23     </Path>
24 </Canvas>

C#作出两个小箭头的后台代码如下：

 1 /// <summary>
2 /// 作出箭头
3 /// </summary>
4 private void DrawArrow()
5 {
6     Path x_axisArrow = new Path();//x轴箭头
7     Path y_axisArrow = new Path();//y轴箭头
8
9     x_axisArrow.Fill = new SolidColorBrush(Color.FromRgb(0xff, 0, 0));
10     y_axisArrow.Fill = new SolidColorBrush(Color.FromRgb(0xff, 0, 0));
11
12     PathFigure x_axisFigure = new PathFigure();
13     x_axisFigure.IsClosed = true;
14     x_axisFigure.StartPoint = new Point(480, 276);                          //路径的起点
15     x_axisFigure.Segments.Add(new LineSegment(new Point(480, 284), false)); //第2个点
16     x_axisFigure.Segments.Add(new LineSegment(new Point(490, 280), false)); //第3个点
17
18     PathFigure y_axisFigure = new PathFigure();
19     y_axisFigure.IsClosed = true;
20     y_axisFigure.StartPoint = new Point(36, 30);                          //路径的起点
21     y_axisFigure.Segments.Add(new LineSegment(new Point(44, 30), false)); //第2个点
22     y_axisFigure.Segments.Add(new LineSegment(new Point(40, 20), false)); //第3个点
23
24     PathGeometry x_axisGeometry = new PathGeometry();
25     PathGeometry y_axisGeometry = new PathGeometry();
26
29
30     x_axisArrow.Data = x_axisGeometry;
31     y_axisArrow.Data = y_axisGeometry;
32
35 }

WPF中没有画带箭头直线的函数，这个必需要自己写了，最好的方法当然还是在XAML中，用Path来绘制出一个三角形在线的末端。当然这种用绝对坐标绘出来的小三角形，它不方便绘制到别的画布中，当前单纯为了做出效果，后面可以用C#动态生成箭头，在后台完成绘制。上述代码的效果如下所示。

1             <TextBlock x:Name="x_label" Text="x" Canvas.Left="477" Canvas.Top="279"
2                        FontFamily="Arial" FontStyle="Italic" FontSize="20"/>
3             <TextBlock x:Name="y_label" Text="y" Canvas.Left="20" Canvas.Top="20"
4                        FontFamily="Arial" FontStyle="Italic" FontSize="20"/>
5             <TextBlock x:Name="o_label" Text="o" Canvas.Left="20" Canvas.Top="272"
6                        FontFamily="Arial" FontStyle="Italic" FontSize="20"/>

# 3、坐标轴刻度和标签添加

1 <Line x:Name="x_scale1" Stroke="Black" StrokeThickness="1" X1="50" Y1="280" X2="50" Y2="276" StrokeEndLineCap="Triangle"/>
2 <Line x:Name="y_scale1" Stroke="Black" StrokeThickness="1" X1="40" Y1="270" X2="44" Y2="270" StrokeEndLineCap="Triangle"/>

①坐标轴刻度线添加

 1 /// <summary>
2 /// 作出x轴和y轴的刻度线
3 /// </summary>
4 private void DrawScale()
5 {
6     for (int i = 0; i < 45; i += 1)//作480个刻度，因为当前x轴长 480px，每10px作一个小刻度，还预留了一些小空间
7     {
8         //原点 O=(40,280)
9         Line x_scale = new Line();
10         x_scale.StrokeEndLineCap = PenLineCap.Triangle;
11         x_scale.StrokeThickness = 1;
12         x_scale.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
13
14         x_scale.X1 = 40 + i * 10;   //原点x=40,每10px作1个刻度
15         x_scale.X2 = x_scale.X1;    //在x轴上的刻度线，起点和终点相同
16
17         x_scale.Y1 = 280;           //与原点坐标的y=280，相同
18         x_scale.Y2 = x_scale.Y1 - 4;//刻度线长度为4px
19
20         if (i < 25)//由于y轴短一些，所以在此作出判断，只作25个刻度
21         {
22             //作出Y轴的刻度
23             Line y_scale = new Line();
24             y_scale.StrokeEndLineCap = PenLineCap.Triangle;
25             y_scale.StrokeThickness = 1;
26             y_scale.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
27
28             y_scale.X1 = 40;            //原点x=40，在y轴上的刻度线的起点与原点相同
29             y_scale.X2 = y_scale.X1 + 4;//刻度线长度为4px
30
31             y_scale.Y1 = 280 - i * 10;  //每10px作一个刻度
32             y_scale.Y2 = y_scale.Y1;    //起点和终点y坐标相同
34         }
36     }
37 }

 1 /// <summary>
2 /// 作出x轴和y轴的标尺
3 /// </summary>
4 private void DrawScale()
5 {
6     for (int i = 0; i < 45; i += 1)//作480个刻度，因为当前x轴长 480px，每10px作一个小刻度，还预留了一些小空间
7     {
8         //原点 O=(40,280)
9         Line x_scale = new Line();
10         x_scale.StrokeEndLineCap = PenLineCap.Triangle;
11         x_scale.StrokeThickness = 1;
12         x_scale.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
13
14         x_scale.X1 = 40 + i * 10;   //原点x=40,每10px作1个刻度
15         x_scale.X2 = x_scale.X1;    //在x轴上的刻度线，起点和终点相同
16
17         x_scale.Y1 = 280;           //与原点坐标的y=280，相同
18         if (i % 5 == 0)//每5个刻度添加一个大刻度
19         {
20             x_scale.StrokeThickness = 3;//把刻度线加粗一点
21             x_scale.Y2 = x_scale.Y1 - 8;//刻度线长度为8px
22         }
23         else
24         {
25             x_scale.Y2 = x_scale.Y1 - 4;//刻度线长度为4px
26         }
27
28         if (i < 25)//由于y轴短一些，所以在此作出判断，只作25个刻度
29         {
30             //作出Y轴的刻度
31             Line y_scale = new Line();
32             y_scale.StrokeEndLineCap = PenLineCap.Triangle;
33             y_scale.StrokeThickness = 1;
34             y_scale.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
35
36             y_scale.X1 = 40;            //原点x=40，在y轴上的刻度线的起点与原点相同
37             if (i % 5 == 0)
38             {
39                 y_scale.StrokeThickness = 3;
40                 y_scale.X2 = y_scale.X1 + 8;//刻度线长度为4px
41             }
42             else
43             {
44                 y_scale.X2 = y_scale.X1 + 4;//刻度线长度为8px
45             }
46
47             y_scale.Y1 = 280 - i * 10;  //每10px作一个刻度
48             y_scale.Y2 = y_scale.Y1;    //起点和终点y坐标相同
50         }
52     }
53 }

②坐标轴标签添加

 1 /// <summary>
2 /// 添加刻度标签
3 /// </summary>
4 private void DrawScaleLabel()
5 {
6     for (int i = 1; i < 7; i++)//7 个标签，一共
7     {
8         TextBlock x_ScaleLabel = new TextBlock();
9         TextBlock y_ScaleLabel = new TextBlock();
10
11         x_ScaleLabel.Text = (i * 50).ToString();//只给大刻度添加标签，每50px添加一个标签
12
13         Canvas.SetLeft(x_ScaleLabel, 40 + 5 * 10 * i - 12);//40是原点的坐标，-12是为了让标签看的位置剧中一点
14         Canvas.SetTop(x_ScaleLabel, 280 + 2);//让标签字往下移一点
15
16         y_ScaleLabel.Text = (i * 50).ToString();
17         Canvas.SetLeft(y_ScaleLabel, 40 - 25);              //-25px是字体大小的偏移
18         Canvas.SetTop(y_ScaleLabel, 280 - 5 * 10 * i - 6);  //280px是原点的坐标，同样-6是为了让标签不要上坐标轴叠上
19
22     }
23 }

运行此代码后，效果如下：

# 4、数据点添加和曲线绘制

①数据点添加显示

1 <Ellipse Fill="Blue" Height="8" Width="8" Canvas.Left="100" Canvas.Top="200"/>
2 <Ellipse Fill="Blue" Height="8" Width="8" Canvas.Left="220" Canvas.Top="180"/>

 1 private void DrawPoint()
2 {
3     //随机生成8个点
4     Random rPoint = new Random();
5     for (int i = 0; i < 8; i++)
6     {
7         int x_point = i * 50;
8         int y_point = rPoint.Next(250);
10     }
11
12     for (int i = 0; i < dataPoints.Count; i++)
13     {
14         Ellipse dataEllipse = new Ellipse();
15         dataEllipse.Fill = new SolidColorBrush(Color.FromRgb(0, 0, 0xff));
16         dataEllipse.Width = 8;
17         dataEllipse.Height = 8;
18
19         Canvas.SetLeft(dataEllipse, 40 + dataPoints[i].X - 4);//-4是为了补偿圆点的大小，到精确的位置
20         Canvas.SetTop(dataEllipse, 280 - dataPoints[i].Y - 4);
21
23     }
24 }

数据点集合声明如下

private List<Point> dataPoints = new List<Point>();

上述代码的运行效果如下（左图）：

②曲线绘制

将所有点用折线描绘出来，C#代码如下，效果如上图（右图）。由于前后两次的代码是不同时间运行的，生成的点是随机的，不一样，所以两副图点不相同。

 1 private void DrawCurve()
2 {
3     Polyline curvePolyline = new Polyline();
4
5     curvePolyline.Stroke = Brushes.Green;
6     curvePolyline.StrokeThickness = 2;
7
8     curvePolyline.Points = coordinatePoints;
10 }

对coordinatePoints的定义和初始化如下。

//这行代码在程序的开始部分private PointCollection coordinatePoints = new PointCollection();----------------------------------------------------------------------------
//将数据点在画布中的位置保存下来
coordinatePoints.Add(new Point(40 + dataPoints[i].X, 280 - dataPoints[i].Y));

# 5、让图表动起来

 1 private void AddCurvePoint(Point dataPoint)
2 {
3     dataPoints.RemoveAt(0);
5     for (int i = 0; i < dataPoints.Count; i++)
6     {
7         //每一个点的X数据都要向左移动50px
8         dataPoints[i] = new Point(dataPoints[i].X - 50, dataPoints[i].Y);
9         coordinatePoints[i] = new Point(40 + dataPoints[i].X, 280 - dataPoints[i].Y);
10
11         Canvas.SetLeft(pointEllipses[i], 40 + dataPoints[i].X - 4);//-4是为了补偿圆点的大小，到精确的位置
12         Canvas.SetTop(pointEllipses[i], 280 - dataPoints[i].Y - 4);
13     }
14 }

1 private void chartCanvas_MouseDown(object sender, MouseButtonEventArgs e)
2 {
3     //随机生成Y坐标
4     Point dataPoint = new Point(400, (new Random()).Next(250));
5
7 }

private List<Point> dataPoints = new List<Point>();
private PointCollection coordinatePoints = new PointCollection();
private List<Ellipse> pointEllipses = new List<Ellipse>();

# 心得体会

posted @ 2017-04-05 21:31 EndlessCoding 阅读(...) 评论(...) 编辑 收藏