/// <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> virtual protected 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> /// Draw all the <see cref="ErrorBar"/>'s to the specified <see cref="Graphics"/> /// device as a an error bar at each defined point. /// </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="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> public void Draw(Graphics g, GraphPane pane, ErrorBarItem curve, Axis baseAxis, Axis valueAxis, double scaleFactor) { BarValueHandler valueHandler = new BarValueHandler(pane); float pixBase, pixValue, pixLowValue; double scaleBase, scaleValue, scaleLowValue; if (curve.Points != null && this.IsVisible) { Pen pen = new Pen(color, penWidth); // Loop over each defined point for (int i = 0; i < curve.Points.Count; i++) { valueHandler.GetBarValues(curve, i, out scaleBase, out scaleLowValue, out scaleValue); // 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[i].IsInvalid3D && (scaleBase > 0 || !baseAxis.IsLog) && ((scaleValue > 0 && scaleLowValue > 0) || !valueAxis.IsLog)) { pixBase = baseAxis.Transform(scaleBase); pixValue = valueAxis.Transform(scaleValue); pixLowValue = valueAxis.Transform(scaleLowValue); //if ( this.fill.IsGradientValueType ) // brush = fill.MakeBrush( rect, points[i] ); this.Draw(g, pane, baseAxis is XAxis, pixBase, pixValue, pixLowValue, scaleFactor, pen); } } } }
/// <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> /// Draw all the <see cref="ErrorBar"/>'s to the specified <see cref="Graphics"/> /// device as a an error bar at each defined point. /// </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="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> public void Draw( Graphics g, GraphPane pane, ErrorBarItem curve, Axis baseAxis, Axis valueAxis, double scaleFactor ) { BarValueHandler valueHandler = new BarValueHandler( pane ); float pixBase, pixValue, pixLowValue; double scaleBase, scaleValue, scaleLowValue; if ( curve.Points != null && this.IsVisible ) { Pen pen = new Pen( color, penWidth ); // Loop over each defined point for ( int i=0; i<curve.Points.Count; i++ ) { valueHandler.GetBarValues( curve, i, out scaleBase, out scaleLowValue, out scaleValue ); // 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[i].IsInvalid3D && ( scaleBase > 0 || !baseAxis.IsLog ) && ( ( scaleValue > 0 && scaleLowValue > 0 ) || !valueAxis.IsLog ) ) { pixBase = baseAxis.Transform( scaleBase ); pixValue = valueAxis.Transform( scaleValue ); pixLowValue = valueAxis.Transform( scaleLowValue ); //if ( this.fill.IsGradientValueType ) // brush = fill.MakeBrush( rect, points[i] ); this.Draw( g, pane, baseAxis is XAxis, pixBase, pixValue, pixLowValue, scaleFactor, pen ); } } } }
/// <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 override void DrawSingleBar( Graphics g, GraphPane pane, CurveItem curve, int index, int pos, Axis baseAxis, Axis valueAxis, double scaleFactor ) { float scaledSize = GetBarWidth( pane, baseAxis, scaleFactor ); // pixBase = pixel value for the bar center on the base axis // pixValue = pixel value for the bar top on the value axis // pixLow = pixel value for the bar bottom on the value axis float pixBase, pixHiVal, pixLowVal; // curBase = the scale value on the base axis of the current bar // curValue = the scale value on the value axis of the current bar // double curBase = ( baseAxis is XAxis ) ? points[index].X : points[index].Y; // double curValue = ( baseAxis is XAxis ) ? points[index].Y : points[index].X; double curBase, curLowVal, curHiVal; BarValueHandler valueHandler = new BarValueHandler( pane ); valueHandler.GetBarValues( curve, index, out curBase, out curLowVal, out curHiVal ); // curLow = the scale value on the value axis for the bottom of the current bar // Get a "low" value for the bottom of the bar and verify validity //double curLow = points[index].LowValue; if ( curLowVal == PointPair.Missing || System.Double.IsNaN( curLowVal ) || System.Double.IsInfinity( curLowVal ) ) curLowVal = 0; // 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 pixHiVal = valueAxis.Transform( index, curHiVal ); // calculate a pixel value for the center of the bar on the base axis pixBase = baseAxis.Transform( index, curBase ); pixLowVal = valueAxis.Transform( index, curLowVal ); // Calculate the pixel location for the side of the bar (on the base axis) float pixSide = pixBase - scaledSize / 2.0F; // Draw the bar if ( baseAxis is XAxis ) this.Draw( g, pane, pixSide, pixSide + scaledSize, pixLowVal, pixHiVal, scaleFactor, true ); else this.Draw( g, pane, pixLowVal, pixHiVal, pixSide, pixSide + scaledSize, scaleFactor, true ); } }
/// <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> override protected void DrawSingleBar(Graphics g, GraphPane pane, CurveItem curve, int index, int pos, Axis baseAxis, Axis valueAxis, double scaleFactor) { float scaledSize = GetBarWidth(pane, baseAxis, scaleFactor); // pixBase = pixel value for the bar center on the base axis // pixValue = pixel value for the bar top on the value axis // pixLow = pixel value for the bar bottom on the value axis float pixBase, pixHiVal, pixLowVal; // curBase = the scale value on the base axis of the current bar // curValue = the scale value on the value axis of the current bar // double curBase = ( baseAxis is XAxis ) ? points[index].X : points[index].Y; // double curValue = ( baseAxis is XAxis ) ? points[index].Y : points[index].X; double curBase, curLowVal, curHiVal; BarValueHandler valueHandler = new BarValueHandler(pane); valueHandler.GetBarValues(curve, index, out curBase, out curLowVal, out curHiVal); // curLow = the scale value on the value axis for the bottom of the current bar // Get a "low" value for the bottom of the bar and verify validity //double curLow = points[index].LowValue; if (curLowVal == PointPair.Missing || System.Double.IsNaN(curLowVal) || System.Double.IsInfinity(curLowVal)) { curLowVal = 0; } // 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 pixHiVal = valueAxis.Transform(index, curHiVal); // calculate a pixel value for the center of the bar on the base axis pixBase = baseAxis.Transform(index, curBase); pixLowVal = valueAxis.Transform(index, curLowVal); // Calculate the pixel location for the side of the bar (on the base axis) float pixSide = pixBase - scaledSize / 2.0F; // Draw the bar if (baseAxis is XAxis) { this.Draw(g, pane, pixSide, pixSide + scaledSize, pixLowVal, pixHiVal, scaleFactor, true); } else { this.Draw(g, pane, pixLowVal, pixHiVal, pixSide, pixSide + scaledSize, scaleFactor, true); } } }
/// <summary> /// Find the data point that lies closest to the specified mouse (screen) /// point. /// </summary> /// <remarks> /// This method will search through the specified list of curves to find which point is /// nearest. It will only consider points that are within /// <see cref="Default.NearestTol"/> pixels of the screen point, and it will /// only consider <see cref="CurveItem"/>'s that are in /// <paramref name="targetCurveList"/>. /// </remarks> /// <param name="mousePt">The screen point, in pixel coordinates.</param> /// <param name="targetCurveList">A <see cref="CurveList"/> object containing /// a subset of <see cref="CurveItem"/>'s to be searched.</param> /// <param name="nearestCurve">A reference to the <see cref="CurveItem"/> /// instance that contains the closest point. nearestCurve will be null if /// no data points are available.</param> /// <param name="iNearest">The index number of the closest point. The /// actual data vpoint will then be <see cref="CurveItem.Points">CurveItem.Points[iNearest]</see> /// . iNearest will /// be -1 if no data points are available.</param> /// <returns>true if a point was found and that point lies within /// <see cref="Default.NearestTol"/> pixels /// of the screen point, false otherwise.</returns> public bool FindNearestPoint( PointF mousePt, CurveList targetCurveList, out CurveItem nearestCurve, out int iNearest ) { CurveItem nearestBar = null; int iNearestBar = -1; nearestCurve = null; iNearest = -1; // If the point is outside the axisRect, always return false if ( ! axisRect.Contains( mousePt ) ) return false; double x, y, y2; ReverseTransform( mousePt, out x, out y, out y2 ); if ( xAxis.Min == xAxis.Max || yAxis.Min == yAxis.Max || y2Axis.Min == y2Axis.Max ) return false; BarValueHandler valueHandler = new BarValueHandler( this ); double xPixPerUnit = axisRect.Width / ( xAxis.Max - xAxis.Min ); double yPixPerUnit = axisRect.Height / ( yAxis.Max - yAxis.Min ); double y2PixPerUnit = axisRect.Height / ( y2Axis.Max - y2Axis.Min ); double yPixPerUnitAct, yAct, yMinAct, yMaxAct; double minDist = 1e20; double xVal, yVal, dist=99999, distX, distY; double tolSquared = Default.NearestTol * Default.NearestTol; int iBar = 0; foreach ( CurveItem curve in targetCurveList ) { if ( curve.IsY2Axis ) { yAct = y2; yMinAct = y2Axis.Min; yMaxAct = y2Axis.Max; yPixPerUnitAct = y2PixPerUnit; } else { yAct = y; yMinAct = yAxis.Min; yMaxAct = yAxis.Max; yPixPerUnitAct = yPixPerUnit; } PointPairList points = curve.Points; float barWidth = curve.GetBarWidth( this ); double barWidthUserHalf; bool isXBaseAxis = ( curve.BaseAxis( this ) == XAxis ); if ( isXBaseAxis ) barWidthUserHalf = barWidth / xPixPerUnit / 2.0; else barWidthUserHalf = barWidth / yPixPerUnit / 2.0; if ( points != null ) { for ( int iPt=0; iPt<curve.NPts; iPt++ ) { if ( xAxis.IsOrdinal ) xVal = (double) iPt + 1.0; else xVal = points[iPt].X; if ( yAxis.IsOrdinal ) yVal = (double) iPt + 1.0; else yVal = points[iPt].Y; if ( xVal != PointPair.Missing && xVal >= xAxis.Min && xVal <= xAxis.Max && yVal != PointPair.Missing && yVal >= yMinAct && yVal <= yMaxAct ) { if ( curve.IsBar || curve is ErrorBarItem || curve is HiLowBarItem ) { double baseVal, lowVal, hiVal; valueHandler.GetBarValues( curve, iPt, out baseVal, out lowVal, out hiVal ); if ( lowVal > hiVal ) { double tmpVal = lowVal; lowVal = hiVal; hiVal = tmpVal; } if ( isXBaseAxis ) { double centerVal = valueHandler.BarCenterValue( curve, barWidth, iPt, xVal, iBar ); if ( x < centerVal - barWidthUserHalf || x > centerVal + barWidthUserHalf || y < lowVal || y > hiVal ) continue; } else { double centerVal = valueHandler.BarCenterValue( curve, barWidth, iPt, yVal, iBar ); if ( y < centerVal - barWidthUserHalf || y > centerVal + barWidthUserHalf || x < lowVal || x > hiVal ) continue; } if ( nearestBar == null ) { iNearestBar = iPt; nearestBar = curve; } } else { distX = (xVal - x) * xPixPerUnit; distY = (yVal - yAct) * yPixPerUnitAct; dist = distX * distX + distY * distY; if ( dist >= minDist ) continue; minDist = dist; iNearest = iPt; nearestCurve = curve; } } } if ( curve.IsBar ) iBar++; } } if ( nearestCurve is LineItem ) { float halfSymbol = (float) ( ((LineItem)nearestCurve).Symbol.Size * CalcScaleFactor() / 2 ); minDist -= halfSymbol * halfSymbol; if ( minDist < 0 ) minDist = 0; } if ( minDist >= tolSquared && nearestBar != null ) { // if no point met the tolerance, but a bar was found, use it nearestCurve = nearestBar; iNearest = iNearestBar; return true; } else if ( minDist < tolSquared ) { // Did we find a close point, and is it within the tolerance? // (minDist is the square of the distance in pixel units) return true; } else // otherwise, no valid point found return false; }