按照老板的要求做的生成3D柱图的程序
1
using
System;
2
using
System.Collections;
3
using
System.Drawing;
4
using
System.Drawing.Imaging;
5
using
System.Drawing.Drawing2D;
6
using
System.Drawing.Text;
7

8
namespace
Chart
9

{
10
/**//// <summary>
11
/// ColumnChart 的摘要说明。
12
/// </summary>
13
public class ColumnChart
14
{
15
public int Width = 420; //图形的宽
16
public int Height = 200; //图形的高
17
public int iLeftTopX = 35; //数据区左上角的X
18
public int iLeftTopY = 35; //数据区左上角的Y
19
public float iSectY = 100; //数据
20
public Color BackColor = Color.White;
21
public int iBottomHeight = 10;
22
public float iLegWidth = 80;
23
public int iGroupNum = 1;
24
25
public Color[] ColorArray
26
= new Color[]
{Color.Blue,Color.Red,Color.Yellow,Color.Purple,Color.Orange,
27
Color.Brown,Color.Gray,Color.Maroon,Color.AliceBlue,
28
Color.AntiqueWhite,Color.Aquamarine, Color.Azure,
29
Color.YellowGreen,Color.Bisque,Color.Black,Color.BlanchedAlmond,
30
Color.BlueViolet,Color.BurlyWood,Color.CadetBlue,Color.Chartreuse,Color.Chocolate};
31
32
private ArrayList chartValues = new ArrayList(); //点数组
33
private float iYdivs = 10; //y轴分成iYdivs等份
34
private string strUnit = "";
35
private string strTitle = "";
36
private float iBottom; //最小点的在Y轴上的位置
37
private float iSymbolLeg; //标记的x轴开始位置
38
private float iValueWidth; // 数据区的宽
39
private float iValueHeight; // 数据区的高
40
private float iValueMaxY = 0; //Y轴最大值
41
private float iValueMinY = 0; //Y轴最小值
42
private float iPointZeroX = 0;
43
private float iPointZeroY = 0; //坐标零点,如果没有负值,就是最小点的坐标
44
private float iDeep = 10; //柱子的深度
45
private int iWidth = 40; //每个柱占据的宽度,包括它右边的空格在内
46
47
private Graphics objGraphics;
48
/**//// <summary>
49
/// 标题
50
/// </summary>
51
public string Title
52
{
53
get
54
{
55
return strTitle;
56
}
57
set
58
{
59
strTitle = value;
60
}
61
}
62
63
64
/**//// <summary>
65
/// Y轴的数值的单位
66
/// </summary>
67
public string Unit
68
{
69
get
70
{
71
return strUnit;
72
}
73
set
74
{
75
strUnit = value;
76
}
77
}
78
79
80
class dataPole
81
{
82
public float Value;
83
public string Name;
84
public string Type;
85
public float ValuePoint;
86
}
87
88
/**//// <summary>
89
/// 向图中添加一个值
90
/// </summary>
91
/// <param name="myValue">值的大小</param>
92
/// <param name="myName">值的名称</param>
93
public void AddValue(float myValue, string myName)
94
{
95
dataPole myData = new dataPole();
96
myData.Value = myValue;
97
myData.Name = myName;
98
myData.Type = myName;
99
myData.ValuePoint = 0;
100
101
chartValues.Add(myData);
102
}
103
104
/**//// <summary>
105
/// 向图中添加一个值
106
/// </summary>
107
/// <param name="myValue">值的大小</param>
108
/// <param name="myName">值的名称,写在右方</param>
109
/// <param name="myType">值的类型,如一月二月,写在下方</param>
110
public void AddValue(float myValue, string myName, string myType)
111
{
112
dataPole myData = new dataPole();
113
myData.Value = myValue;
114
myData.Name = myName;
115
myData.Type = myType;
116
myData.ValuePoint = 0;
117
118
chartValues.Add(myData);
119
}
120
121
/**//// <summary>
122
///
123
/// </summary>
124
public ColumnChart(int myWidth, int myHeight, Graphics myGraphics ,string myUnit,string myTitle)
125
{
126
strTitle = myTitle;
127
strUnit = myUnit;
128
129
Width = myWidth;
130
Height = myHeight;
131
132
objGraphics = myGraphics;
133
}
134
135
/**//// <summary>
136
/// 计算一些需要用到的值
137
/// </summary>
138
protected void CalculateValue()
139
{
140
float iRightLegWidth = 5;
141
foreach(dataPole myPole in chartValues)
142
{
143
SizeF size = objGraphics.MeasureString(myPole.Name,new Font("宋体", 9));
144
if(iRightLegWidth < size.Width + 5 )
145
{
146
iRightLegWidth = size.Width + 5;
147
}
148
}
149
iLegWidth = iRightLegWidth + 25;
150
iSymbolLeg = Width - iLegWidth;
151
152
if(this.iGroupNum ==1)
153
{
154
iBottomHeight = 10;
155
}
156
else
157
{
158
iBottomHeight = 25;
159
}
160
iBottom = Height - iBottomHeight;
161
162
iValueWidth = iSymbolLeg - iLeftTopX - iDeep - 10;
163
iValueHeight = iBottom - iLeftTopY;
164
//-------------------------------------------------------------------------------------
165
//算最大值
166
foreach(dataPole myPole in chartValues)
167
{
168
for(;iValueMaxY < myPole.Value;iValueMaxY = iValueMaxY + iSectY);
169
}
170
//算最小值iValueMinY
171
iValueMinY = iValueMaxY;
172
foreach(dataPole myPole in chartValues)
173
{
174
for(;iValueMinY > myPole.Value;iValueMinY = iValueMinY - iSectY);
175
}
176
//以上两个最大最小值是用来计算iYdivs的
177
178
iYdivs = (iValueMaxY - iValueMinY)/iSectY;
179
float fltemp = iSectY;
180
for(;iYdivs > 10;iSectY += fltemp)
181
{
182
iYdivs = (iValueMaxY - iValueMinY)/iSectY;
183
}
184
185
//因为iSectY的值发生变化,所以要重新计算最大最小值。
186
iValueMaxY = 0;
187
//算最大值
188
foreach(dataPole myPole in chartValues)
189
{
190
for(;iValueMaxY < myPole.Value;iValueMaxY = iValueMaxY + iSectY);
191
}
192
//算最小值iValueMinY
193
iValueMinY = iValueMaxY;
194
foreach(dataPole myPole in chartValues)
195
{
196
for(;iValueMinY > myPole.Value;iValueMinY = iValueMinY - iSectY);
197
}
198
//--------------------------------------------------------------------------------------------
199
200
//最大值加上一段,这样不会顶在上面,留有一点余地
201
iValueMaxY += iSectY;
202
iPointZeroX = iLeftTopX;
203
if(iValueMinY < 0 )
204
{ //最小值减去一段,这样最短的不会只有一点,稍长一点,好看一些,
205
//而且如果有负数,这样不会顶到下面
206
iValueMinY -= iSectY;
207
iPointZeroY = iLeftTopY + iValueHeight*(iValueMaxY/(iValueMaxY - iValueMinY));
208
}
209
210
else if(iValueMinY > 0 )
211
{
212
iValueMinY -= iSectY;
213
iPointZeroY = iBottom;
214
}
215
else
216
{ //如果iSectY大于所有值中的最小值,就会出现iValueMinY等于0的情况,
217
//这个时候如果再将iValueMinY减去iSectY
218
//就会得到iValueMinY为负数,应该屏蔽这种情况
219
iPointZeroY = iBottom;
220
}
221
222
iYdivs = (iValueMaxY - iValueMinY)/iSectY;
223
224
//iWidth是每个数值的宽度
225
if(chartValues.Count!=0)
226
{
227
iWidth = (int)(iValueWidth - 40)/chartValues.Count;
228
}
229
230
if(iWidth > 40)
231
{
232
iWidth = 40;
233
}
234
else if(iWidth < 5)
235
{
236
iWidth = 5;
237
}
238
239
if(iDeep > (iWidth-iDeep)*7/10)
240
{
241
iDeep = (iWidth-iDeep)*7/10;
242
}
243
244
245
//得到相对应的值需要在图上画出的点数。画图的时候用ValuePoint,
246
//取值的时候用Value,取名字的时候用Name
247
if(iValueMinY >= 0)
248
{
249
foreach(dataPole myPole in chartValues)
250
{
251
myPole.ValuePoint = System.Convert.ToInt32(iValueHeight * (myPole.Value - iValueMinY) / (iValueMaxY - iValueMinY));
252
}
253
}
254
else
255
{
256
foreach(dataPole myPole in chartValues)
257
{
258
myPole.ValuePoint = System.Convert.ToInt32((iPointZeroY- iLeftTopY) * (myPole.Value) / (iValueMaxY));
259
}
260
}
261
262
}
263
264
/**//// <summary>
265
/// 画图;
266
/// </summary>
267
public void Draw()
268
{
269
CalculateValue();
270
271
int i;
272
273
//objGraphics.ScaleTransform(1,1);
274
//设定平滑为无锯齿
275
//objGraphics.SmoothingMode = SmoothingMode.AntiAlias;
276
objGraphics.CompositingQuality = CompositingQuality.GammaCorrected;
277
objGraphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
278
279
//清除整个绘图面并以指定White为背景色进行填充。
280
objGraphics.Clear(BackColor);
281
282
//----------绘制统计图标题--------------------------------------------------------------------------------------------
283
//在画布(objBitMap对象),用指定的Brush(画笔)对象和Font(字体)对象绘制统计图标题。
284
SizeF size = objGraphics.MeasureString(strTitle,new Font("宋体", 12, FontStyle.Bold));
285
objGraphics.DrawString(strTitle, new Font("宋体", 12, FontStyle.Bold), Brushes.Black, (iSymbolLeg - size.Width)/2, 10);
286
287
//------------画横线,方便用户查看-----------------------------------------------------------------------------------------------
288
float x = iLeftTopX,y=0;
289
string myLabel;
290
Pen SilverPen = new Pen(Color.Silver, 1);
291
Pen BlackPen = new Pen(Color.Black, 1);
292
for(i = 0;i<=iYdivs;i++)
293
{
294
y = iBottom - (i * iValueHeight / iYdivs);
295
myLabel = System.Convert.ToString(Math.Round(iValueMinY + ((iValueMaxY - iValueMinY) * i / iYdivs),2));
296
//写左边的坐标的值
297
objGraphics.DrawString(myLabel, new Font("宋体", 9), new SolidBrush(Color.Black), 5, y - 6);
298
299
//画线
300
objGraphics.DrawLine(SilverPen, x, y, x+iDeep , y -iDeep);
301
objGraphics.DrawLine(SilverPen, x +iDeep , y -iDeep , x + iValueWidth +iDeep, y -iDeep);
302
objGraphics.DrawLine(BlackPen, x-2, y, x, y);
303
}
304
//写出y轴的单位
305
myLabel = "单位:" + strUnit;
306
objGraphics.DrawString(myLabel, new Font("宋体", 9), new SolidBrush(Color.Black), 3, y - iDeep -13);
307
//-----------------------------------------------------------------------------------------------------------------------------------
308
309
//--------画图形区域---------------------------------------------------------------------------------------------------------
310
//这四个点是左边的坐标面
311
PointF p1 = new PointF(iLeftTopX,iLeftTopY);
312
PointF p2 = new PointF(iLeftTopX+ iDeep, iLeftTopY - iDeep);
313
PointF p3 = new PointF(iLeftTopX,iLeftTopY + iValueHeight);
314
PointF p4 = new PointF(iLeftTopX +iDeep,iLeftTopY + iValueHeight -iDeep);
315
//这四个点是0点的横的坐标面
316
PointF p5 = new PointF(iPointZeroX,iPointZeroY);
317
PointF p6 = new PointF(iPointZeroX + iDeep,iPointZeroY - iDeep);
318
PointF p7 = new PointF(iPointZeroX + iValueWidth,iPointZeroY);
319
PointF p8 = new PointF(iPointZeroX + iValueWidth + iDeep,iPointZeroY -iDeep);
320
321
PointF[] ptsArray1 =
{p1, p3, p4, p2};
322
PointF[] ptsArray2 =
{p5, p7, p8, p6};
323
324
//左边的坐标面
325
objGraphics.DrawPolygon(BlackPen,ptsArray1);
326
//0点的横的坐标面
327
objGraphics.DrawPolygon(BlackPen,ptsArray2);
328
//数据区
329
objGraphics.DrawRectangle(BlackPen, iLeftTopX+ iDeep, iLeftTopY - iDeep, iValueWidth, iValueHeight);
330
//----------------------------------------------------------------------------------------------------------------------------------
331
332
//----------创建图例文字--------------------------------------------------------------------------------------------------------
333
PointF symbolLeg = new PointF(iSymbolLeg, 5);
334
PointF descLeg = new PointF(iSymbolLeg + 25, 2);
335
//画出图例。
336
//当iGroupNum!=1的时候,只用画出iGroupNum个图例就可以了。
337
//利用objGraphics图形对象的三个方法画出图例:
338
//FillRectangle()方法画出填充矩形,DrawRectangle()方法画出矩形的边框,
339
//DrawString()方法画出说明文字。这三个图形对象的方法在 .NET 框架类库类库中均已重载,
340
//可以很方便根据不同的参数来画出图形。
341
i = 0;
342
foreach(dataPole myPole in chartValues)
343
{ //画出填充矩形。
344
objGraphics.FillRectangle(new SolidBrush(GetColor(i,iGroupNum)), symbolLeg.X, symbolLeg.Y, 20, 10);
345
//画出矩形边框。
346
objGraphics.DrawRectangle(Pens.Black, symbolLeg.X, symbolLeg.Y, 20, 10);
347
//画出图例说明文字。
348
//objGraphics.DrawString(arrValueNames[i].ToString(), new Font("宋体", 10), Brushes.Black, descLeg);
349
objGraphics.DrawString(myPole.Name.ToString(), new Font("宋体", 9), Brushes.Black, descLeg);
350
//移动坐标位置,只移动Y方向的值即可。
351
symbolLeg.Y += 15;
352
descLeg.Y += 15;
353
//-------
354
i++;
355
if(iGroupNum ==1)
356
{
357
continue;
358
}
359
else if(iGroupNum !=1 &&
360
i>=iGroupNum)
361
{
362
break;
363
}
364
}
365
366
367
//----------遍历数据源的每一项数据,并根据数据的大小画出矩形图(即柱形图的柱)----------------------------------------------------------
368
//画出三维柱图
369
i=0;
370
foreach(dataPole myPole in chartValues)
371
{
372
if(myPole.Value>=0)
373
{
374
DrawCell(GetColor(i,iGroupNum),(i * iWidth) + iLeftTopX + 20, iPointZeroY - myPole.ValuePoint, iWidth-4, myPole.ValuePoint,iDeep);
375
}
376
else
377
{
378
DrawCell(GetColor(i,iGroupNum),(i * iWidth) + iLeftTopX + 20, iPointZeroY, iWidth-4, Math.Abs(myPole.ValuePoint),iDeep);
379
}
380
i++;
381
}
382
i=0;
383
foreach(dataPole myPole in chartValues)
384
{
385
//在每个柱的上方显示大小 因为怕被前面的矩形挡住,所以分开来画
386
if(myPole.Value>=0)
387
{
388
objGraphics.DrawString(myPole.Value.ToString(), new Font("宋体", 9), Brushes.Black, (i * iWidth) + iLeftTopX + 20 + 6, iPointZeroY - myPole.ValuePoint-iDeep-15);
389
if(iGroupNum != 1 && i%iGroupNum ==0)
390
{
391
objGraphics.DrawString(myPole.Type.ToString(), new Font("宋体", 9), Brushes.Black, (i * iWidth) + iLeftTopX + 20, iPointZeroY -iDeep+15);
392
}
393
}
394
else
395
{
396
objGraphics.DrawString(myPole.Value.ToString(), new Font("宋体", 9), Brushes.Black, (i * iWidth) + iLeftTopX + 20 + 6, iPointZeroY - myPole.ValuePoint-iDeep+15);
397
if(iGroupNum != 1&& i%iGroupNum ==0)
398
{
399
objGraphics.DrawString(myPole.Type.ToString(), new Font("宋体", 9), Brushes.Black, (i * iWidth) + iLeftTopX + 20, iPointZeroY -iDeep-15);
400
}
401
}
402
i++;
403
}
404
}
405
406
/**//// <summary>
407
///
408
/// </summary>
409
/// <param name="itemIndex"></param>
410
/// <returns></returns>
411
private Color GetColor(int itemIndex,int iGroupNum)
412
{
413
Color objColor = Color.White;
414
int j = 0;
415
if(iGroupNum == 1)
416
{
417
j = itemIndex%ColorArray.Length;
418
}
419
else
420
{
421
j = itemIndex%iGroupNum;
422
}
423
objColor = ColorArray[j];
424
425
return objColor;
426
}
427
428
429
/**//// <summary>
430
/// 画三维柱图
431
/// </summary>
432
/// <param name="myColor">颜色,不透明之前</param>
433
/// <param name="x">长方体的前面一个面的左上角的坐标x点</param>
434
/// <param name="y">长方体的前面一个面的左上角的坐标y点</param>
435
/// <param name="width">长方体的前面一个面的宽</param>
436
/// <param name="height">长方体的前面一个面的高</param>
437
/// <param name="iDeep">长方体的深,后面一个面的X坐标为 前面一个面的x + iDeep </param>
438
private void DrawCell(Color myColor,float x,float y,float width,float height,float iDeep)
439
{
440
Rectangle Frect =
441
new Rectangle((int)x, (int)y, (int)width, (int)height);
442
Rectangle Brect =
443
new Rectangle(Frect.X + (int)iDeep, Frect.Y -(int)iDeep, Frect.Width, Frect.Height);
444
445
PointF p1 = new PointF((float)Frect.X, (float)Frect.Y);
446
PointF p2 = new PointF((float)Frect.X, (float)(Frect.Y + Frect.Height));
447
PointF p3 = new PointF((float)(Frect.X + Frect.Width), (float)(Frect.Y + Frect.Height));
448
PointF p4 = new PointF((float)(Frect.X + Frect.Width), (float)Frect.Y);
449
450
PointF p5 = new PointF((float)Brect.X, (float)Brect.Y);
451
PointF p6 = new PointF((float)Brect.X, (float)(Brect.Y + Brect.Height));
452
PointF p7 = new PointF((float)(Brect.X + Brect.Width), (float)(Brect.Y + Brect.Height));
453
PointF p8 = new PointF((float)(Brect.X + Brect.Width), (float)Brect.Y);
454
455
// Create points for polygon.
456
PointF[] ptsArray1 = //left
457
{
458
p1, p2, p6, p5
459
};
460
461
PointF[] ptsArray2 = //bottom
462
{
463
p2, p3, p7, p6
464
};
465
466
PointF[] ptsArray3 = //right
467
{
468
p4, p3, p7, p8
469
};
470
471
PointF[] ptsArray4 = //top
472
{
473
p1, p4, p8, p5
474
};
475
//
476
//myColor = Color.FromArgb(164,164,251);
477
//颜色的问题正在测试中。。。。。颜色太难看了。。。。:(
478
479
SolidBrush defaultBrush = //164,164,251
480
new SolidBrush(Color.FromArgb(128,myColor.R,myColor.G,myColor.B));
481
int r,g,b;
482
r = myColor.R - 37;
483
g = myColor.G - 37;
484
b = myColor.B - 45;
485
if (r<0) r=0;
486
if (g<0) g=0;
487
if (b<0) b=0;
488
SolidBrush topBrush = // 127,127,206 37,37,45
489
new SolidBrush(Color.FromArgb(188,r,g,b));
490
int r1,g1,b1;
491
492
493
r1 = myColor.R - 52;
494
g1 = myColor.G - 52;
495
b1 = myColor.B - 88;
496
if (r1<0) r1=0;
497
if (g1<0) g1=0;
498
if (b1<0) b1=0;
499
SolidBrush rightBrush = //112,112,163 52,52,88
500
new SolidBrush(Color.FromArgb(220,r1,g1,b1));
501
502
503
SolidBrush invisibleBrush =
504
new SolidBrush(Color.FromArgb(111,myColor.R,myColor.G,myColor.B));
505
SolidBrush visibleBrush =
506
new SolidBrush(Color.FromArgb(188,myColor.R,myColor.G,myColor.B));
507
SolidBrush FrectBrush =
508
new SolidBrush(Color.FromArgb(220,myColor.R,myColor.G,myColor.B));
509
510
511
// Fill recntagle1
512
//objGraphics.FillRectangle(invisibleBrush, Brect);
513
objGraphics.FillRectangle(defaultBrush, Brect);
514
objGraphics.DrawRectangle(Pens.Black, Brect);
515
516
// Fill Polygon1
517
//objGraphics.FillPolygon(invisibleBrush, ptsArray1);
518
objGraphics.FillPolygon(defaultBrush, ptsArray1);
519
objGraphics.DrawPolygon(Pens.Black, ptsArray1);
520
// Fill Polygon2
521
//objGraphics.FillPolygon(invisibleBrush, ptsArray2);
522
objGraphics.FillPolygon(defaultBrush, ptsArray2);
523
objGraphics.DrawPolygon(Pens.Black, ptsArray2);
524
// Fill Polygon3
525
//objGraphics.FillPolygon(visibleBrush, ptsArray3);
526
objGraphics.FillPolygon(rightBrush, ptsArray3);
527
objGraphics.DrawPolygon(Pens.Black, ptsArray3);
528
// Fill Polygon4
529
//objGraphics.FillPolygon(visibleBrush, ptsArray4);
530
objGraphics.FillPolygon(topBrush, ptsArray4);
531
objGraphics.DrawPolygon(Pens.Black, ptsArray4);
532
533
// Fill recntagle2
534
objGraphics.FillRectangle(FrectBrush, Frect);
535
objGraphics.DrawRectangle(Pens.Black, Frect);
536
537
invisibleBrush.Dispose();
538
visibleBrush.Dispose();
539
FrectBrush.Dispose();
540
}
541
}
542
}
使用方法如下:
如:在窗口Form1加上一个pictureBox1控件
1
private
void
pictureBox1_Paint(
object
sender, System.Windows.Forms.PaintEventArgs e)
2

{
3
Chart.ColumnChart myChart = new Chart.ColumnChart(this.pictureBox1.Width,this.pictureBox1.Height
4
,e.Graphics ,"分","高一(二)班各科成绩统计");
5
myChart.iLeftTopX = 45; //数据区左上角的X
6
myChart.iLeftTopY = 50; //数据区左上角的Y
7
myChart.iSectY = 2; //数据段大小
8
myChart.iGroupNum = 5; //分组数
9
10
myChart.AddValue(69,"语文","男生");
11
myChart.AddValue(82,"数学","男生");
12
myChart.AddValue(78,"英语","男生");
13
myChart.AddValue(80,"物理","男生");
14
myChart.AddValue(74,"化学","男生");
15
16
myChart.AddValue(77,"语文","女生");
17
myChart.AddValue(78,"数学","女生");
18
myChart.AddValue(80,"英语","女生");
19
myChart.AddValue(76,"物理","女生");
20
myChart.AddValue(69,"化学","女生");
21
22
myChart.Draw();
23
}
效果如图所示: