因工作原因,学习相关ZedGraph源码来解决一些问题。刚看到这个开源图表控件时,感觉还是短小精悍的。
结合ZedGraph控件的例子大致看了下对应的源码,写下点感悟。
这里先大致说一些ZedGraph里的元素。
1.Panel:ZedGraph控件是如何画出来的,就是这这个上面画出来,后面的元素如坐标轴,线条,饼图。
2.Axis:轴线,任何二维线型、条型、饼型图表都需要一个坐标轴,至少有X轴,Y轴,然后我们才能在上面画相应的线条,饼型等元素。
3.CurveItem:我们刚说到在有坐标轴后,那么需要画我们的线条,条型,饼型什么的,CurveItem就是存储我们的数据然后画出对应的图形。
4.GraphObj:我们在整个Panel里可能要标出一些信息,如某点要添加相应描述,或是我们要标示有一部分是警告区域,都可以由这个来完成。
5.MajorTic与MinorTic:这二个对象都是针对Axis来说的,主要是描述上面的轴线上的主高刻度与副刻度。
6.Scale:这个和上面的对象一样是Axis来说的,主要是描述轴线上的刻度显示的对应的数字与标识。
7.PointPair:这个就是针对CurveItem来说的,CurveItem里保存着相应的数据,而这些数据就放在PointPair队例里。
这些其实就是构成统计图一些主要元素了,当然还有一些用于辅助的如:Legend(简单来说就是对应CurvItem图形的缩微图),Fill(用于填充对象的),Border(描述元素边界的),Symbol(点上的图形).
上面的1-7中,除5,6外都是有对应的集合类。
它们之间的关系如下。
Panel可以包含Axis,CurveItem,GraphObj这些元素的集合,而在其中一个CurveItem可以对应一个X轴和Y轴,也可以多个CurveItem对应一个X轴,而GraphObj与Axis和CurveItem没有直接关系。
CurveItem里包含着PointPair的集合,而Axis包含着Tic与Scale信息。
这里我先给出一些PaneBase相关的源码。
在这个类里,有个属性叫BaseDimension。
public float BaseDimension { get { return _baseDimension; } set { _baseDimension = value; } }
在源代码里给出一段说明,如果BaseDimension=8英寸,在chart图有8英寸宽的时候,如果标题为14像素那么高,那么在chart图缩小到4英寸宽的时候,标题也会缩小到7个像素那么高。
是不是有点湖里湖涂的,在这里我先解释一下英寸与像素的关系,这个还关系到另外一值,DPI(点每英寸),这个和显示器有关,现在的显示器一般是96DPI吧,老一点的一般是72DPI,在这里面也是用的72DPI,在这里8英寸用96DPI就是768像素。
这里先到这里,我们看下,它是如何用达到伸缩Chart图而引起相应Title跟着伸缩的。先看如下一段代码。
public float CalcScaleFactor() { float scaleFactor; //, xInch, yInch; const float ASPECTLIMIT = 1.5F; // if font scaling is turned off, then always return a 1.0 scale factor if ( !_isFontsScaled ) return 1.0f; if ( _rect.Height <= 0 ) return 1.0F; float length = _rect.Width; float aspect = _rect.Width / _rect.Height; if ( aspect > ASPECTLIMIT ) length = _rect.Height * ASPECTLIMIT; if ( aspect < 1.0F / ASPECTLIMIT ) length = _rect.Width * ASPECTLIMIT; scaleFactor = length / ( _baseDimension * 72F ); // Don't let the scaleFactor get ridiculous if ( scaleFactor < 0.1F ) scaleFactor = 0.1F; return scaleFactor; }
这段上有说明,得到一个比例因子,用于绘制元素,这段代码很简单,它首先会得到判断有没设置字体可以缩放,如不可以直接返回1,然后取panel自身的宽度,然后取宽与长的比例,如果宽大于1.5倍的长,那么取1.5倍的长,如果长大于宽1.5倍的长,则取宽的1.5倍长,如果不在这范围,就取其宽度。而这个比例因子就是这个前面所说的BaseDimension所点的像素点(不过是老机器上的),也就是576,就是说长宽适合,宽为576的话,是不会发生任何缩放的。
得到这个比例因子后能做什么了?绘图,能绘你伸缩chart图成任何比例都还能显示比例适合的图,看如下一段代码。
public RectangleF CalcClientRect( Graphics g, float scaleFactor ) { float charHeight = _title._fontSpec.GetHeight( scaleFactor ); RectangleF innerRect = new RectangleF( _rect.Left + _margin.Left * scaleFactor, _rect.Top + _margin.Top * scaleFactor, _rect.Width - scaleFactor * (_margin.Left + _margin.Right), _rect.Height - scaleFactor * (_margin.Top + _margin.Bottom)); if ( _title._isVisible && _title._text != string.Empty ) { SizeF titleSize = _title._fontSpec.BoundingBox( g, _title._text, scaleFactor ); // Leave room for the title height, plus a line spacing of charHeight * _titleGap innerRect.Y += titleSize.Height + charHeight * _titleGap; innerRect.Height -= titleSize.Height + charHeight * _titleGap; } // Calculate the legend rect, and back it out of the current ChartRect //this.legend.CalcRect( g, this, scaleFactor, ref innerRect ); return innerRect; }
这一段代码是为了得到Chart图除标题外的可用面积,这里我只看中间得到中间那段,我用如下图来说明。
这里可以看到我们伸缩外面如何通过比例因子来影响里面元素大小了。
其实在PaneBase里的Draw()函数里就看到,首先是得到比例因子,然后再把比例因子当做各个绘制元素的参数。