/// <summary> /// Calculate the user scale position of the center of the specified bar, using the /// <see cref="Axis"/> as specified by <see cref="GraphPane.BarBase"/>. This method is /// used primarily by the /// <see cref="GraphPane.FindNearestPoint(PointF,out CurveItem,out int)"/> method in order to /// determine the bar "location," which is defined as the center of the top of the individual bar. /// </summary> /// <param name="curve">The <see cref="CurveItem"/> representing the /// bar of interest.</param> /// <param name="barWidth">The width of each individual bar. This can be calculated using /// the <see cref="CurveItem.GetBarWidth"/> method.</param> /// <param name="iCluster">The cluster number for the bar of interest. This is the ordinal /// position of the current point. That is, if a particular <see cref="CurveItem"/> has /// 10 points, then a value of 3 would indicate the 4th point in the data array.</param> /// <param name="val">The actual independent axis value for the bar of interest.</param> /// <param name="iOrdinal">The ordinal position of the <see cref="CurveItem"/> of interest. /// That is, the first bar series is 0, the second is 1, etc. Note that this applies only /// to the bars. If a graph includes both bars and lines, then count only the bars.</param> /// <returns>A user scale value position of the center of the bar of interest.</returns> public double BarCenterValue(CurveItem curve, float barWidth, int iCluster, double val, int iOrdinal) { Axis baseAxis = curve.BaseAxis(pane); if (curve is ErrorBarItem || curve is HiLowBarItem) { if ((baseAxis.IsOrdinal || baseAxis.IsText) && iCluster >= 0 && !curve.IsOverrideOrdinal) { return((double)iCluster + 1.0); } else { return(val); } } else { float clusterWidth = pane.GetClusterWidth(); float clusterGap = pane.MinClusterGap * barWidth; float barGap = barWidth * pane.MinBarGap; if ((curve.IsBar && !(pane.BarType == BarType.Cluster || pane.BarType == BarType.ClusterHiLow))) { iOrdinal = 0; } float centerPix = baseAxis.Transform(curve.IsOverrideOrdinal, iCluster, val) - clusterWidth / 2.0F + clusterGap / 2.0F + iOrdinal * (barWidth + barGap) + 0.5F * barWidth; return(baseAxis.ReverseTransform(centerPix)); } }
/// <summary> /// Protected internal routine that draws the specified single bar (an individual "point") /// of this series to the specified <see cref="Graphics"/> device. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="GraphPane"/> object that is the parent or /// owner of this object. /// </param> /// <param name="curve">A <see cref="CurveItem"/> object representing the /// <see cref="Bar"/>'s to be drawn.</param> /// <param name="index"> /// The zero-based index number for the single bar to be drawn. /// </param> /// <param name="pos"> /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) /// in the cluster of bars. /// </param> /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent) /// axis for the <see cref="Bar"/></param> /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent) /// axis for the <see cref="Bar"/></param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> virtual protected void DrawSingleBar(Graphics g, GraphPane pane, CurveItem curve, int index, int pos, Axis baseAxis, Axis valueAxis, float scaleFactor) { // pixBase = pixel value for the bar center on the base axis // pixHiVal = pixel value for the bar top on the value axis // pixLowVal = pixel value for the bar bottom on the value axis float pixBase, pixHiVal, pixLowVal; float clusterWidth = pane.GetClusterWidth(); float barWidth = curve.GetBarWidth(pane); float clusterGap = pane.MinClusterGap * barWidth; float barGap = barWidth * pane.MinBarGap; // curBase = the scale value on the base axis of the current bar // curHiVal = the scale value on the value axis of the current bar // curLowVal = the scale value of the bottom of the bar double curBase, curLowVal, curHiVal; ValueHandler valueHandler = new ValueHandler(pane, false); valueHandler.GetValues(curve, index, out curBase, out curLowVal, out curHiVal); // 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 invalid if (!curve.Points[index].IsInvalid) { // calculate a pixel value for the top of the bar on value axis pixLowVal = valueAxis.Transform(curve.IsOverrideOrdinal, index, curLowVal); pixHiVal = valueAxis.Transform(curve.IsOverrideOrdinal, index, curHiVal); // calculate a pixel value for the center of the bar on the base axis pixBase = baseAxis.Transform(curve.IsOverrideOrdinal, index, curBase); // Calculate the pixel location for the side of the bar (on the base axis) float pixSide = pixBase - clusterWidth / 2.0F + clusterGap / 2.0F + pos * (barWidth + barGap); // Draw the bar if (pane.BarBase == BarBase.X) { this.Draw(g, pane, pixSide, pixSide + barWidth, pixLowVal, pixHiVal, scaleFactor, true, curve.Points[index]); } else { this.Draw(g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth, scaleFactor, true, curve.Points[index]); } } }
/// <summary> /// Calculate the width of each bar, depending on the actual bar type /// </summary> /// <returns>The width for an individual bar, in pixel units</returns> public float GetBarWidth(GraphPane pane) { // Total axis width = // npts * ( nbars * ( bar + bargap ) - bargap + clustgap ) // cg * bar = cluster gap // npts = max number of points in any curve // nbars = total number of curves that are of type IsBar // bar = bar width // bg * bar = bar gap // therefore: // totwidth = npts * ( nbars * (bar + bg*bar) - bg*bar + cg*bar ) // totwidth = bar * ( npts * ( nbars * ( 1 + bg ) - bg + cg ) ) // solve for bar float barWidth; if (this is ErrorBarItem) { barWidth = (float)(((ErrorBarItem)this).ErrorBar.Symbol.Size * pane.CalcScaleFactor()); } else if (this is HiLowBarItem) { barWidth = (float)(((HiLowBarItem)this).Bar.GetBarWidth(pane, ((HiLowBarItem)this).BaseAxis(pane), pane.CalcScaleFactor())); } else // BarItem or LineItem { // For stacked bar types, the bar width will be based on a single bar float numBars = 1.0F; if (pane.BarType == BarType.Cluster || pane.BarType == BarType.ClusterHiLow) { numBars = pane.CurveList.NumBars; } float denom = numBars * (1.0F + pane.MinBarGap) - pane.MinBarGap + pane.MinClusterGap; if (denom <= 0) { denom = 1; } barWidth = pane.GetClusterWidth() / denom; } if (barWidth <= 0) { return(1); } return(barWidth); }
/// <summary> /// Calculate the screen pixel position of the center of the specified bar, using the /// <see cref="Axis"/> as specified by <see cref="GraphPane.BarBase"/>. This method is /// used primarily by the /// <see cref="GraphPane.FindNearestPoint(PointF,out CurveItem,out int)"/> method in order to /// determine the bar "location," which is defined as the center of the top of the individual bar. /// </summary> /// <param name="curve">The <see cref="CurveItem"/> representing the /// bar of interest.</param> /// <param name="barWidth">The width of each individual bar. This can be calculated using /// the <see cref="CurveItem.GetBarWidth"/> method.</param> /// <param name="iCluster">The cluster number for the bar of interest. This is the ordinal /// position of the current point. That is, if a particular <see cref="CurveItem"/> has /// 10 points, then a value of 3 would indicate the 4th point in the data array.</param> /// <param name="val">The actual independent axis value for the bar of interest.</param> /// <param name="iOrdinal">The ordinal position of the <see cref="CurveItem"/> of interest. /// That is, the first bar series is 0, the second is 1, etc. Note that this applies only /// to the bars. If a graph includes both bars and lines, then count only the bars.</param> /// <returns>A screen pixel X position of the center of the bar of interest.</returns> public double BarCenterValue(CurveItem curve, float barWidth, int iCluster, double val, int iOrdinal) { float clusterWidth = pane.GetClusterWidth(); float clusterGap = pane.MinClusterGap * barWidth; float barGap = barWidth * pane.MinBarGap; if ((curve.IsBar && !(pane.BarType == BarType.Cluster)) || curve is ErrorBarItem || curve is HiLowBarItem) { iOrdinal = 0; } Axis baseAxis = curve.BaseAxis(pane); float centerPix = baseAxis.Transform(iCluster, val) - clusterWidth / 2.0F + clusterGap / 2.0F + iOrdinal * (barWidth + barGap) + 0.5F * barWidth; return(baseAxis.ReverseTransform(centerPix)); }
/// <summary> /// Protected internal routine that draws the specified single bar (an individual "point") /// of this series to the specified <see cref="Graphics"/> device. /// </summary> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="GraphPane"/> object that is the parent or /// owner of this object. /// </param> /// <param name="curve">A <see cref="CurveItem"/> object representing the /// <see cref="Bar"/>'s to be drawn.</param> /// <param name="index"> /// The zero-based index number for the single bar to be drawn. /// </param> /// <param name="pos"> /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) /// in the cluster of bars. /// </param> /// <param name="baseAxis">The <see cref="Axis"/> class instance that defines the base (independent) /// axis for the <see cref="Bar"/></param> /// <param name="valueAxis">The <see cref="Axis"/> class instance that defines the value (dependent) /// axis for the <see cref="Bar"/></param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="GraphPane.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> protected virtual void DrawSingleBar( Graphics g, GraphPane pane, CurveItem curve, int index, int pos, Axis baseAxis, Axis valueAxis, double scaleFactor ) { // pixBase = pixel value for the bar center on the base axis // pixHiVal = pixel value for the bar top on the value axis // pixLowVal = pixel value for the bar bottom on the value axis float pixBase, pixHiVal, pixLowVal; float clusterWidth = pane.GetClusterWidth(); float barWidth = curve.GetBarWidth( pane ); float clusterGap = pane.MinClusterGap * barWidth; float barGap = barWidth * pane.MinBarGap; // curBase = the scale value on the base axis of the current bar // curHiVal = the scale value on the value axis of the current bar // curLowVal = the scale value of the bottom of the bar double curBase, curLowVal, curHiVal; BarValueHandler valueHandler = new BarValueHandler( pane ); valueHandler.GetBarValues( curve, index, out curBase, out curLowVal, out curHiVal ); // 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 invalid if ( !curve.Points[index].IsInvalid ) { // calculate a pixel value for the top of the bar on value axis pixLowVal = valueAxis.Transform( index, curLowVal ); pixHiVal = valueAxis.Transform( index, curHiVal ); // calculate a pixel value for the center of the bar on the base axis pixBase = baseAxis.Transform( index, curBase ); // Calculate the pixel location for the side of the bar (on the base axis) float pixSide = pixBase - clusterWidth / 2.0F + clusterGap / 2.0F + pos * ( barWidth + barGap ); // Draw the bar if ( pane.BarBase == BarBase.X ) this.Draw( g, pane, pixSide, pixSide + barWidth, pixLowVal, pixHiVal, scaleFactor, true ); else this.Draw( g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth, scaleFactor, true ); } }
/// <summary> /// Calculate the width of each bar, depending on the actual bar type /// </summary> /// <returns>The width for an individual bar, in pixel units</returns> public float GetBarWidth( GraphPane pane ) { // Total axis width = // npts * ( nbars * ( bar + bargap ) - bargap + clustgap ) // cg * bar = cluster gap // npts = max number of points in any curve // nbars = total number of curves that are of type IsBar // bar = bar width // bg * bar = bar gap // therefore: // totwidth = npts * ( nbars * (bar + bg*bar) - bg*bar + cg*bar ) // totwidth = bar * ( npts * ( nbars * ( 1 + bg ) - bg + cg ) ) // solve for bar float barWidth; if ( this is ErrorBarItem ) barWidth = (float) ( ((ErrorBarItem)this).ErrorBar.Symbol.Size * pane.CalcScaleFactor() ); else if ( this is HiLowBarItem ) barWidth = (float) ( ((HiLowBarItem)this).Bar.GetBarWidth( pane, ((HiLowBarItem)this).BaseAxis(pane), pane.CalcScaleFactor() ) ); else // BarItem or LineItem { // For stacked bar types, the bar width will be based on a single bar float numBars = 1.0F; if ( pane.BarType == BarType.Cluster ) numBars = pane.CurveList.NumBars; float denom = numBars * ( 1.0F + pane.MinBarGap ) - pane.MinBarGap + pane.MinClusterGap; if ( denom <= 0 ) denom = 1; barWidth = pane.GetClusterWidth() / denom; } if ( barWidth <= 0 ) return 1; return barWidth; }