应用GDI+生成3D柱图的程序

按照老板的要求做的生成3D柱图的程序

  1using System;
  2using System.Collections;
  3using System.Drawing;
  4using System.Drawing.Imaging;
  5using System.Drawing.Drawing2D;
  6using System.Drawing.Text;
  7
  8namespace 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)/210);
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 + 252);
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, 2010);
345                //画出矩形边框。
346                objGraphics.DrawRectangle(Pens.Black, symbolLeg.X, symbolLeg.Y, 2010);
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控件

 1private 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}

效果如图所示:


posted @ 2005-06-28 14:03  阿哲  阅读(1576)  评论(2编辑  收藏  举报