随着社会的发展、科学的进步,地理信息系统(GIS)技术在社会的各个领域中的应用越来越广泛。其中专题图在地理信息系统应用中具有非常重要的作用、专题图的应用大大增强信息表达的直观性。目前在GIS软件领域各种GIS软件平台以及GIS开发组件都提供了丰富的专题图设置功能。
ESRI公司的GIS开发组件MapObjects中也提供了丰富的专题图功能,如:图表专题(包括直方图和饼图)、独立值、点密度、分类分级等。使用过MapObjects进行专题开发的人会发现:其中图表专题中MapObjects提供的图表显示是平面二维的,显示效果极其平淡,没有ArcMap中图表专题里的那种三维立体效果。有没有办法使这些图表象ArcMap中那样显示为三维立体的效果呢?MapObjects的ChartRenderer中提供了自定义图表的方法,也就是把ChartType设置为ChartTypeConstants中的moCustom,然后把ChartRenderer的CustomChart属性设置为我们自定义图表对象就可以了。
话是如此,但是如何创建这个自定义图表对象呢,MapObjects 提供了ICustomChart接口,我们要做的就是实现这个接口。在一般的开发语言中我们需要通过底层的API绘图函数来实现其中图形方面的操作,不过在.NET中我们可以使用强大的GDI+来实现这些操作,下面我们以C#.Net为例使用GDI+实现ICustomChart接口,创建美观、大方、直观、立体感强的三维直方图统计专题。
第一步:新建一个C#类库项目CustomChartRenderer(图一)
![](/Article/UploadFiles/200607/20060703164311157.gif)
|
图一 新建类库项目CustomChartRenderer |
第二步:添加程序集的应用。ESRI.MapObjects2.Core 和 ESRI.MapObjects2.Custom并继承 ESRI.MapObjects2.Custom.ICustomChart(图二、三)
![](/Article/UploadFiles/200607/20060703164311410.gif)
|
图二 添加程序集的应用 |
![](/Article/UploadFiles/200607/20060703164311146.gif)
|
图三 对我们创建的类添加对ICustomChart的继承 |
第三步:添加对ICustomChart继承接口的实现。在.NET开发界面的类似图中找到ICustomChart接口,点击右键菜单中的“添加”——>“实现接口”(图四)
![](/Article/UploadFiles/200607/20060703164312780.gif)
|
图四 添加对ICustomChart接口的实现 |
“实现接口”后我们的代码中会多了如下三个函数,我们要做的也就是完成这三个函数在渲染的过程中执行的顺序为SetupDC——> Draw——> ResetDC。
#region ICustomChart 成员 public void ResetDC(int hDC) { // TODO: 添加 Custom3DBarRenderer.ResetDC 实现 } public void SetupDC(object Map, object MapLayer, object ChartRenderer, int hDC, double dpi) { // TODO: 添加 Custom3DBarRenderer.SetupDC 实现 } public void Draw(int hDC, int x, int y, ref double[] values, double normValue, double sizeValue) { // TODO: 添加 Custom3DBarRenderer.Draw 实现 } #endregion |
第四步:添加成员变量、属性和自定义函数,自定义函数Setup3DBarRenderer主要负责对数据进行预处理和统计计算,计算图表渲染中的最大值,以便根据数值的大小分配直方图柱子的高度。
private int[] m_iColors; //记录直方条的颜色 private float m_MaxBarHeight = 50; //直方图的最大高度 private float m_MinBarHeight = 1; //直方图的最小高度 private float m_BarWidth = 10; //直方图的宽度 private float m_fTotal = 0; //用于记录统计字段中的最大直 private bool m_blDrawOutline = true; //是否绘制边框 private System.Drawing.Color m_OutlineColor = System.Drawing.Color.Black; //边框的颜色
public void Setup3DBarRenderer(ESRI.MapObjects2.Core.MapLayer lyr,ESRI.MapObjects2.Core.ChartRenderer cr) { if(lyr != null && cr != null) { //初始化颜色数组根据FieldCount动态创建 this.m_iColors = new int[cr.FieldCount]; for(short i=0;i<cr.FieldCount;i++) { this.m_iColors[i] = int.Parse(cr.get_Color(i).ToString()); } ESRI.MapObjects2.Core.Recordset rec; float fTotal = 0; rec = lyr.Records; while (!rec.EOF) { for(short i = 0 ; i < cr.FieldCount - 1;i++) { float fTemp = float.Parse(rec.Fields.Item(cr.get_Field(i)).ValueAsString); if(fTotal < fTemp) {//保存最大的值 以便计算绘制直方图的高 fTotal = fTemp; } } rec.MoveNext(); } this.m_fTotal = fTotal; } } // 公开一些属性以便根据需要进行修改 public float BarWidth { get; set; } public bool DrawOutline { get; set; } public float MaxBarHeight { get; set; } public float MinBarHeight { get; set; } public Color OutlineColor { get; set; } |
第五步:实现继承的接口ESRI.MapObjects2.Custom.ICustomChart中的方法Draw()。
public void Draw(int hDC, int x, int y, ref double[] values, double normValue, double sizeValue) { // TODO: 添加 Custom3DBarRenderer.Draw 实现 float iBarHeight = 0; float iBarWidth = 0; System.Drawing.Graphics g = System.Drawing.Graphics.FromHdc(new System.IntPtr(hDC)); //创建Graphics对象 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; //消除图形的锯齿 System.Drawing.SolidBrush tempBrush = null; System.Drawing.Pen pOutLine = new System.Drawing.Pen(new System.Drawing.SolidBrush(this.m_OutlineColor),0.2f); iBarWidth = this.m_BarWidth; float CurrentX,CurrentY; CurrentX = x - this.m_BarWidth * values.Length / 2; CurrentY = y; for(int i=0;i<values.Length;i++) { //创建画刷 并计算矩形的高度 tempBrush = new System.Drawing.SolidBrush(System.Drawing.ColorTranslator.FromWin32(this.m_iColors[i])); iBarHeight = System.Convert.ToSingle((values[i] * this.m_MaxBarHeight/this.m_fTotal).ToString()); if(iBarHeight < this.m_MinBarHeight) { iBarHeight = this.m_MinBarHeight; } if(iBarHeight > this.m_MaxBarHeight) { iBarHeight = this.m_MaxBarHeight; } //绘制矩形 System.Drawing.PointF[] pRect = new System.Drawing.PointF[4]; pRect[0].X = CurrentX; pRect[0].Y = CurrentY; pRect[1].X = CurrentX + iBarWidth ; pRect[1].Y = CurrentY; pRect[2].X = CurrentX + iBarWidth ; pRect[2].Y = CurrentY - iBarHeight; pRect[3].X = CurrentX; pRect[3].Y = CurrentY - iBarHeight; //绘制矩形顶部的阴影 System.Drawing.PointF[] pTopFill = new System.Drawing.PointF[4]; pTopFill[0].X = CurrentX; pTopFill[0].Y = CurrentY - iBarHeight; pTopFill[1].X = CurrentX + iBarWidth ; pTopFill[1].Y = CurrentY - iBarHeight; pTopFill[2].X = CurrentX + iBarWidth * 3/2 ; pTopFill[2].Y = CurrentY - iBarHeight - iBarWidth * 1/2; pTopFill[3].X = CurrentX + iBarWidth * 1/2 ; pTopFill[3].Y = CurrentY - iBarHeight - iBarWidth * 1/2;
CurrentX = CurrentX +iBarWidth; //斜面阴影部分 System.Drawing.PointF[] pShadow= new System.Drawing.PointF[4]; pShadow[0].X = CurrentX; pShadow[0].Y = CurrentY; pShadow[1].X = CurrentX + iBarWidth/2 ; pShadow[1].Y = CurrentY - iBarWidth/2; pShadow[2].X = CurrentX + iBarWidth/2 ; pShadow[2].Y = CurrentY - iBarHeight - iBarWidth * 1/2; pShadow[3].X = CurrentX ; pShadow[3].Y = CurrentY - iBarHeight;
//绘制3D图形 包括正面、斜面、顶部 g.FillPolygon(tempBrush,pRect); g.FillPolygon(new HatchBrush(HatchStyle.Percent50,tempBrush.Color),pTopFill); g.FillPolygon(tempBrush,pShadow); //如果设置了绘制边界线 则绘制边界 if(this.m_blDrawOutline) { g.DrawPolygon(pOutLine,pRect); g.DrawPolygon(pOutLine,pTopFill); g.DrawPolygon(pOutLine,pShadow); } } } |
最后,建立测试工程应用我们创建的三维直方图统计专题(点击按扭为地图设上此专题),看看设置完成后的效果,是不是比普通的二维直方图更好呢?。关键代码如下:
prprivate void button1_Click(object sender, System.EventArgs e) { //取得图层 ESRI.MapObjects2.Core.MapLayer lyr = this.axMap1.Layers.Item(0) as ESRI.MapObjects2.Core.MapLayer; //创建ChartRenderer对象 并使用moCustom类型 ESRI.MapObjects2.Core.ChartRenderer pChartRenderer = new ESRI.MapObjects2.Core.ChartRendererClass(); pChartRenderer.FieldCount = 3; pChartRenderer.set_Field(0, "GDP"); pChartRenderer.set_Color(0,(uint)ESRI.MapObjects2.Core.ColorConstants.moRed); pChartRenderer.set_Field(1,"AGRICULTUR"); pChartRenderer.set_Color(1,(uint)ESRI.MapObjects2.Core.ColorConstants.moYellow); pChartRenderer.set_Field(2,"Industry"); pChartRenderer.set_Color(2,(uint)ESRI.MapObjects2.Core.ColorConstants.moGreen); pChartRenderer.ChartType = ESRI.MapObjects2.Core.ChartTypeConstants.moCustom; //创建Custom3dBarRenderer对象并赋值给pChartRenderer Gissky.Common.Mo.CustomChartRenderer.Custom3DBarRenderer r = new Gissky.Common.Mo.CustomChartRenderer.Custom3DBarRenderer(); r.Setup3DBarRenderer(lyr,pChartRenderer); pChartRenderer.CustomChart = r; lyr.Renderer = pChartRenderer; this.axMap1.CtlRefresh(); } |
![](/Article/UploadFiles/200607/20060703164312900.gif)
|
图五 示例程序运行效果 |