ZedGraph源碼學習(三)

來源:互聯網
上載者:User

我們先看下一段代碼,這行代碼是說在軸上對應的值轉化成它對應的像素值。

public float Transform( double x ){// Must take into account Log, and Reverse Axesdouble denom = ( _maxLinTemp - _minLinTemp );double ratio;if ( denom > 1e-100 )ratio = ( Linearize( x ) - _minLinTemp ) / denom;elseratio = 0;if ( _isReverse == ( _ownerAxis is XAxis || _ownerAxis is X2Axis ) )return (float) ( _maxPix - ( _maxPix - _minPix ) * ratio );elsereturn (float) ( _minPix + ( _maxPix - _minPix ) * ratio );}

這段代碼很好理解,我們假設這是X軸,軸沒有反轉,X軸上的座標最小值minLinTemp,對應像素是minpix,座標最大值是maxLinTemp,對應像素是maxpix,現有一點在x軸的座標是xlin,那麼它對應的像素是xpix,它們滿足這樣一個關係,(xlin-minLinTemp)/(maxLinTemp-minLinTemp)=(xpix-minpix)/(maxpix-minpix),根據這個關係我們能得到對應的xpix的關係。如果是Y軸,因為我們座標繫上的Y軸和在裝置上的座標系是反著來的,那麼它們的關係要改著這樣了,(xlin-minLinTemp)/(maxLinTemp-minLinTemp)=(maxpix-xpix)/(maxpix-minpix).

然後我們查看一下Chart圖上的元素是如何繪製的,我們這裡看線條的繪製過程。線條的元素LineItem裡會封裝一個Line的對象,這個對象主要是負責具體畫什麼樣的線,如直線,基數樣條等,我們看一下普通的基數樣條的繪製代碼。

public void DrawCurve( Graphics g, GraphPane pane,                                CurveItem curve, float scaleFactor ){Line source = this;if ( curve.IsSelected )source = Selection.Line;// switch to int to optimize drawing speed (per Dale-a-b)inttmpX, tmpY,lastX = int.MaxValue,lastY = int.MaxValue;double curX, curY, lowVal;PointPair curPt, lastPt = new PointPair();bool lastBad = true;IPointList points = curve.Points;ValueHandler valueHandler = new ValueHandler( pane, false );Axis yAxis = curve.GetYAxis( pane );Axis xAxis = curve.GetXAxis( pane );bool xIsLog = xAxis._scale.IsLog;bool yIsLog = yAxis._scale.IsLog;// switch to int to optimize drawing speed (per Dale-a-b)int minX = (int)pane.Chart.Rect.Left;int maxX = (int)pane.Chart.Rect.Right;int minY = (int)pane.Chart.Rect.Top;int maxY = (int)pane.Chart.Rect.Bottom;using ( Pen pen = source.GetPen( pane, scaleFactor ) ){if ( points != null && !_color.IsEmpty && this.IsVisible ){//bool lastOut = false;bool isOut;bool isOptDraw = _isOptimizedDraw && points.Count > 1000;// (Dale-a-b) we'll set an element to true when it has been drawnbool[,] isPixelDrawn = null;if ( isOptDraw )isPixelDrawn = new bool[maxX + 1, maxY + 1]; // Loop over each point in the curvefor ( int i = 0; i < points.Count; i++ ){curPt = points[i];if ( pane.LineType == LineType.Stack ){if ( !valueHandler.GetValues( curve, i, out curX, out lowVal, out curY ) ){curX = PointPair.Missing;curY = PointPair.Missing;}}else{curX = curPt.X;curY = curPt.Y;}// Any value set to double max is invalid and should be skipped// This is used for calculated values that are out of range, divide//   by zero, etc.// Also, any value <= zero on a log scale is invalidif ( curX == PointPair.Missing ||curY == PointPair.Missing ||System.Double.IsNaN( curX ) ||System.Double.IsNaN( curY ) ||System.Double.IsInfinity( curX ) ||System.Double.IsInfinity( curY ) ||( xIsLog && curX <= 0.0 ) ||( yIsLog && curY <= 0.0 ) ){// If the point is invalid, then make a linebreak only if IsIgnoreMissing is false// LastX and LastY are always the last valid point, so this works outlastBad = lastBad || !pane.IsIgnoreMissing;isOut = true;}else{// Transform the current point from user scale units to// screen coordinatestmpX = (int) xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curX );tmpY = (int) yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curY );// Maintain an array of "used" pixel locations to avoid duplicate drawing operations// contributed by Dale-a-bif ( isOptDraw && tmpX >= minX && tmpX <= maxX &&tmpY >= minY && tmpY <= maxY ) // guard against the zoom-in case{if ( isPixelDrawn[tmpX, tmpY] )continue;isPixelDrawn[tmpX, tmpY] = true;}isOut = ( tmpX < minX && lastX < minX ) || ( tmpX > maxX && lastX > maxX ) ||( tmpY < minY && lastY < minY ) || ( tmpY > maxY && lastY > maxY );if ( !lastBad ){try{// GDI+ plots the data wrong and/or throws an exception for// outrageous coordinates, so we do a sanity check hereif ( lastX > 5000000 || lastX < -5000000 ||lastY > 5000000 || lastY < -5000000 ||tmpX > 5000000 || tmpX < -5000000 ||tmpY > 5000000 || tmpY < -5000000 )InterpolatePoint( g, pane, curve, lastPt, scaleFactor, pen,lastX, lastY, tmpX, tmpY );else if ( !isOut ){if ( !curve.IsSelected && this._gradientFill.IsGradientValueType ){using ( Pen tPen = GetPen( pane, scaleFactor, lastPt ) ){if ( this.StepType == StepType.NonStep ){g.DrawLine( tPen, lastX, lastY, tmpX, tmpY );}else if ( this.StepType == StepType.ForwardStep ){g.DrawLine( tPen, lastX, lastY, tmpX, lastY );g.DrawLine( tPen, tmpX, lastY, tmpX, tmpY );}else if ( this.StepType == StepType.RearwardStep ){g.DrawLine( tPen, lastX, lastY, lastX, tmpY );g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );}else if ( this.StepType == StepType.ForwardSegment ){g.DrawLine( tPen, lastX, lastY, tmpX, lastY );}else{g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );}}}else{if ( this.StepType == StepType.NonStep ){g.DrawLine( pen, lastX, lastY, tmpX, tmpY );}else if ( this.StepType == StepType.ForwardStep ){g.DrawLine( pen, lastX, lastY, tmpX, lastY );g.DrawLine( pen, tmpX, lastY, tmpX, tmpY );}else if ( this.StepType == StepType.RearwardStep ){g.DrawLine( pen, lastX, lastY, lastX, tmpY );g.DrawLine( pen, lastX, tmpY, tmpX, tmpY );}else if ( this.StepType == StepType.ForwardSegment ){g.DrawLine( pen, lastX, lastY, tmpX, lastY );}else if ( this.StepType == StepType.RearwardSegment ){g.DrawLine( pen, lastX, tmpY, tmpX, tmpY );}}}}catch{InterpolatePoint( g, pane, curve, lastPt, scaleFactor, pen,lastX, lastY, tmpX, tmpY );}}lastPt = curPt;lastX = tmpX;lastY = tmpY;lastBad = false;//lastOut = isOut;}}}}}

代碼有些多,但是過程還是很清晰的,前面一部分代碼都是來擷取相關資料,然後遍曆對應CurveItem裡的IPointList資料,把每個Point資料(是我們看到的資料)對應當前CurveItem裡的X軸與Y軸上的像素值(給機器來看的),這裡用到的轉換就是上面所說的那部分代碼,根據我們選擇StepType不同來繪製每二點決定的線。這樣就繪製出了我們要的線條,別的元素具體上不同,但是都是這種邏輯。其實如果要多瞭解這一方面的邏輯,可以看下有關座標系統和轉換的知識。

PS:讀源碼有個地方要注意,不要只是跟著代碼往下來,看一會不是分支過多就是跑題了,看的時候你要自己跟著想,如果是我來實現這一功能,應該怎麼來實現,然後和看的代碼比對。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.