Exemple #1
0
        /// <summary>
        /// Protected internal routine that draws the specified single bar (an individual "point")
        /// of this series to the specified <see c_ref="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 c_ref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see c_ref="CurveItem"/> object representing the
        /// <see c_ref="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 c_ref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see c_ref="Bar"/></param>
        /// <param name="valueAxis">The <see c_ref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see c_ref="Bar"/></param>
        /// <param name="barWidth">
        /// The width of each bar, in pixels.
        /// </param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see c_ref="GraphPane"/> object using the
        /// <see c_ref="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 barWidth, 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.BarSettings.GetClusterWidth();
            //float barWidth = curve.GetBarWidth( pane );
            float clusterGap = pane._barSettings.MinClusterGap * barWidth;
            float barGap     = barWidth * pane._barSettings.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.Scale.Transform(curve.IsOverrideOrdinal, index, curLowVal);
                pixHiVal  = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, index, curHiVal);
                // calculate a pixel value for the center of the bar on the base axis
                pixBase = baseAxis.Scale.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._barSettings.Base == BarBase.X)
                {
                    Draw(g, pane, pixSide, pixSide + barWidth, pixLowVal,
                         pixHiVal, scaleFactor, true, curve.IsSelected,
                         curve.Points[index]);
                }
                else
                {
                    Draw(g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth,
                         scaleFactor, true, curve.IsSelected,
                         curve.Points[index]);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Draw all the <see c_ref="ErrorBar"/>'s to the specified <see c_ref="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 c_ref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see c_ref="CurveItem"/> object representing the
        /// <see c_ref="Bar"/>'s to be drawn.</param>
        /// <param name="baseAxis">The <see c_ref="Axis"/> class instance that defines the base (independent)
        /// axis for the <see c_ref="Bar"/></param>
        /// <param name="valueAxis">The <see c_ref="Axis"/> class instance that defines the value (dependent)
        /// axis for the <see c_ref="Bar"/></param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see c_ref="GraphPane"/> object using the
        /// <see c_ref="PaneBase.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, float scaleFactor)
        {
            ValueHandler valueHandler = new ValueHandler(pane, false);

            float  pixBase, pixValue, pixLowValue;
            double scaleBase, scaleValue, scaleLowValue;

            if (curve.Points != null && IsVisible)
            {
                using (Pen pen = !curve.IsSelected ? new Pen(_color, _penWidth) :
                                 new Pen(Selection.Border.Color, Selection.Border.Width))
                {
                    // Loop over each defined point
                    for (int i = 0; i < curve.Points.Count; i++)
                    {
                        valueHandler.GetValues(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._scale.IsLog) &&
                            ((scaleValue > 0 && scaleLowValue > 0) || !valueAxis._scale.IsLog))
                        {
                            pixBase     = baseAxis.Scale.Transform(curve.IsOverrideOrdinal, i, scaleBase);
                            pixValue    = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, scaleValue);
                            pixLowValue = valueAxis.Scale.Transform(curve.IsOverrideOrdinal, i, scaleLowValue);

                            //if ( this.fill.IsGradientValueType )
                            //	brush = fill.MakeBrush( _rect, _points[i] );

                            Draw(g, pane, baseAxis is XAxis || baseAxis is X2Axis, pixBase, pixValue,
                                 pixLowValue, scaleFactor, pen, curve.IsSelected,
                                 curve.Points[i]);
                        }
                    }
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Determine the coords for the rectangle associated with a specified point for
        /// this <see c_ref="CurveItem" />
        /// </summary>
        /// <param name="pane">The <see c_ref="GraphPane" /> to which this curve belongs</param>
        /// <param name="i">The index of the point of interest</param>
        /// <param name="coords">A list of coordinates that represents the "rect" for
        /// this point (used in an html AREA tag)</param>
        /// <returns>true if it's a valid point, false otherwise</returns>
        override public bool GetCoords(GraphPane pane, int i, out string coords)
        {
            coords = string.Empty;

            if (i < 0 || i >= _points.Count)
            {
                return(false);
            }

            PointPair pt = _points[i];

            if (pt.IsInvalid)
            {
                return(false);
            }

            double       x, y, z;
            ValueHandler valueHandler = new ValueHandler(pane, false);

            valueHandler.GetValues(this, i, out x, out z, out y);

            Axis yAxis = GetYAxis(pane);
            Axis xAxis = GetXAxis(pane);

            PointF pixPt = new PointF(xAxis.Scale.Transform(_isOverrideOrdinal, i, x),
                                      yAxis.Scale.Transform(_isOverrideOrdinal, i, y));

            if (!pane.Chart.Rect.Contains(pixPt))
            {
                return(false);
            }

            float halfSize = _symbol.Size * pane.CalcScaleFactor();

            coords = String.Format("{0:f0},{1:f0},{2:f0},{3:f0}",
                                   pixPt.X - halfSize, pixPt.Y - halfSize,
                                   pixPt.X + halfSize, pixPt.Y + halfSize);

            return(true);
        }
Exemple #4
0
		/// <summary>
		/// Create a <see c_ref="TextObj" /> for each bar in the <see c_ref="GraphPane" />.
		/// </summary>
		/// <remarks>
		/// This method will go through the bars, create a label that corresponds to the bar value,
		/// and place it on the graph depending on user preferences.  This works for horizontal or
		/// vertical bars in clusters or stacks, but only for <see c_ref="BarItem" /> types.  This method
		/// does not apply to <see c_ref="ErrorBarItem" /> or <see c_ref="HiLowBarItem" /> objects.
		/// Call this method only after calling <see c_ref="GraphPane.AxisChange()" />.
		/// </remarks>
		/// <param name="pane">The GraphPane in which to place the text labels.</param>
		/// <param name="isBarCenter">true to center the labels inside the bars, false to
		/// place the labels just above the top of the bar.</param>
		/// <param name="valueFormat">The double.ToString string format to use for creating
		/// the labels.
		/// </param>
		/// <param name="fontColor">The color in which to draw the labels</param>
		/// <param name="fontFamily">The string name of the font family to use for the labels</param>
		/// <param name="fontSize">The floating point size of the font, in scaled points</param>
		/// <param name="isBold">true for a bold font type, false otherwise</param>
		/// <param name="isItalic">true for an italic font type, false otherwise</param>
		/// <param name="isUnderline">true for an underline font type, false otherwise</param>
		public static void CreateBarLabels( GraphPane pane, bool isBarCenter, string valueFormat,
			string fontFamily, float fontSize, Color fontColor, bool isBold, bool isItalic,
			bool isUnderline )
		{
			bool isVertical = pane.BarSettings.Base == BarBase.X;

			// keep a count of the number of BarItems
			int curveIndex = 0;

			// Get a valuehandler to do some calculations for us
			ValueHandler valueHandler = new ValueHandler( pane, true );

			// Loop through each curve in the list
			foreach ( CurveItem curve in pane.CurveList )
			{
				// work with BarItems only
				BarItem bar = curve as BarItem;
				if ( bar != null )
				{
					IPointList points = curve.Points;

					// ADD JKB 9/21/07
					// The labelOffset should depend on whether the curve is YAxis or Y2Axis.
					// JHC - Generalize to any value axis
					// Make the gap between the bars and the labels = 1.5% of the axis range
					float labelOffset;

					Scale scale = curve.ValueAxis( pane ).Scale;
					labelOffset = (float)( scale._max - scale._min ) * 0.015f;

					// Loop through each point in the BarItem
					for ( int i = 0; i < points.Count; i++ )
					{
						// Get the high, low and base values for the current bar
						// note that this method will automatically calculate the "effective"
						// values if the bar is stacked
						double baseVal, lowVal, hiVal;
						valueHandler.GetValues( curve, i, out baseVal, out lowVal, out hiVal );

						// Get the value that corresponds to the center of the bar base
						// This method figures out how the bars are positioned within a cluster
						float centerVal = (float)valueHandler.BarCenterValue( bar,
							bar.GetBarWidth( pane ), i, baseVal, curveIndex );

						// Create a text label -- note that we have to go back to the original point
						// data for this, since hiVal and lowVal could be "effective" values from a bar stack
						string barLabelText = ( isVertical ? points[i].Y : points[i].X ).ToString( valueFormat );

						// Calculate the position of the label -- this is either the X or the Y coordinate
						// depending on whether they are horizontal or vertical bars, respectively
						float position;
						if ( isBarCenter )
							position = (float)( hiVal + lowVal ) / 2.0f;
						else if ( hiVal >= 0 )
							position = (float)hiVal + labelOffset;
						else
							position = (float)hiVal - labelOffset;

						// Create the new TextObj
						TextObj label;
						if ( isVertical )
							label = new TextObj( barLabelText, centerVal, position );
						else
							label = new TextObj( barLabelText, position, centerVal );

						label.FontSpec.Family = fontFamily;

						// Configure the TextObj

                  // CHANGE JKB 9/21/07
                  // CoordinateFrame should depend on whether curve is YAxis or Y2Axis.
						label.Location.CoordinateFrame =
							(isVertical && curve.IsY2Axis) ? CoordType.AxisXY2Scale : CoordType.AxisXYScale;

						label.FontSpec.Size = fontSize;
						label.FontSpec.FontColor = fontColor;
						label.FontSpec.IsItalic = isItalic;
						label.FontSpec.IsBold = isBold;
						label.FontSpec.IsUnderline = isUnderline;

						label.FontSpec.Angle = isVertical ? 90 : 0;
						label.Location.AlignH = isBarCenter ? AlignH.Center :
									( hiVal >= 0 ? AlignH.Left : AlignH.Right );
						label.Location.AlignV = AlignV.Center;
						label.FontSpec.Border.IsVisible = false;
						label.FontSpec.Fill.IsVisible = false;

						// Add the TextObj to the GraphPane
						pane.GraphObjList.Add( label );
					}
					curveIndex++;
				}
			}
		}
Exemple #5
0
		/// <summary>
		/// Protected internal routine that draws the specified single bar (an individual "point")
		/// of this series to the specified <see c_ref="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 c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="CurveItem"/> object representing the
		/// <see c_ref="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 c_ref="Axis"/> class instance that defines the base (independent)
		/// axis for the <see c_ref="Bar"/></param>
		/// <param name="valueAxis">The <see c_ref="Axis"/> class instance that defines the value (dependent)
		/// axis for the <see c_ref="Bar"/></param>
		/// <param name="barWidth">
		/// The width of each bar, in pixels.
		/// </param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="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 barWidth, 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.BarSettings.GetClusterWidth();
			//float barWidth = curve.GetBarWidth( pane );
			float clusterGap = pane._barSettings.MinClusterGap * barWidth;
			float barGap = barWidth * pane._barSettings.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.Scale.Transform( curve.IsOverrideOrdinal, index, curLowVal );
				pixHiVal = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, index, curHiVal );
				// calculate a pixel value for the center of the bar on the base axis
				pixBase = baseAxis.Scale.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._barSettings.Base == BarBase.X )
					Draw( g, pane, pixSide, pixSide + barWidth, pixLowVal,
							pixHiVal, scaleFactor, true, curve.IsSelected,
							curve.Points[index] );
				else
					Draw( g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth,
							scaleFactor, true, curve.IsSelected,
							curve.Points[index] );
			}
		}
Exemple #6
0
		/// <summary>
		/// Draw the this <see c_ref="CurveItem"/> to the specified <see c_ref="Graphics"/>
		/// device.  The format (stair-step or line) of the curve is
		/// defined by the <see c_ref="StepType"/> property.  The routine
		/// only draws the line segments; the symbols are drawn by the
		/// <see c_ref="Symbol.Draw"/> method.  This method
		/// is normally only called by the Draw method of the
		/// <see c_ref="CurveItem"/> object
		/// </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="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		/// <param name="pane">
		/// A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		public void DrawCurveOriginal( Graphics g, GraphPane pane,
										  CurveItem curve, float scaleFactor )
		{
			Line source = this;
			if ( curve.IsSelected )
				source = Selection.Line;

			float tmpX, tmpY,
					lastX = float.MaxValue,
					lastY = float.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;

			float minX = pane.Chart.Rect.Left;
			float maxX = pane.Chart.Rect.Right;
			float minY = pane.Chart.Rect.Top;
			float maxY = pane.Chart.Rect.Bottom;

			using ( Pen pen = source.GetPen( pane, scaleFactor ) )
			{
				if ( points != null && !_color.IsEmpty && IsVisible )
				{
					//bool lastOut = false;
					bool isOut;

					// Loop over each point in the curve
					for ( 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 invalid
						if ( curX == PointPair.Missing ||
								curY == PointPair.Missing ||
								Double.IsNaN( curX ) ||
								Double.IsNaN( curY ) ||
								Double.IsInfinity( curX ) ||
								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 out
							lastBad = lastBad || !pane.IsIgnoreMissing;
							isOut = true;
						}
						else
						{
							// Transform the current point from user scale units to
							// screen coordinates
							tmpX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curX );
							tmpY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, curY );
							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 here
									if ( 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 && _gradientFill.IsGradientValueType )
										{
											using ( Pen tPen = GetPen( pane, scaleFactor, lastPt ) )
											{
												if ( StepType == StepType.NonStep )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, tmpY );
												}
												else if ( StepType == StepType.ForwardStep )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, lastY );
													g.DrawLine( tPen, tmpX, lastY, tmpX, tmpY );
												}
												else if ( StepType == StepType.RearwardStep )
												{
													g.DrawLine( tPen, lastX, lastY, lastX, tmpY );
													g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );
												}
												else if ( StepType == StepType.ForwardSegment )
												{
													g.DrawLine( tPen, lastX, lastY, tmpX, lastY );
												}
												else
												{
													g.DrawLine( tPen, lastX, tmpY, tmpX, tmpY );
												}
											}
										}
										else
										{
											if ( StepType == StepType.NonStep )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, tmpY );
											}
											else if ( StepType == StepType.ForwardStep )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, lastY );
												g.DrawLine( pen, tmpX, lastY, tmpX, tmpY );
											}
											else if ( StepType == StepType.RearwardStep )
											{
												g.DrawLine( pen, lastX, lastY, lastX, tmpY );
												g.DrawLine( pen, lastX, tmpY, tmpX, tmpY );
											}
											else if ( StepType == StepType.ForwardSegment )
											{
												g.DrawLine( pen, lastX, lastY, tmpX, lastY );
											}
											else if ( 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;
						}
					}
				}
			}
		}
Exemple #7
0
		/// <summary>
		/// Build an array of <see c_ref="PointF"/> values (pixel coordinates) that represents
		/// the low values for the current curve.
		/// </summary>
		/// <remarks>Note that this drawing routine ignores <see c_ref="PointPairBase.Missing"/>
		/// values, but it does not "break" the line to indicate values are missing.
		/// </remarks>
		/// <param name="pane">A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.</param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="arrPoints">An array of <see c_ref="PointF"/> values in pixel
		/// coordinates representing the current curve.</param>
		/// <param name="count">The number of points contained in the "arrPoints"
		/// parameter.</param>
		/// <returns>true for a successful points array build, false for data problems</returns>
		public bool BuildLowPointsArray( GraphPane pane, CurveItem curve,
						out PointF[] arrPoints, out int count )
		{
			arrPoints = null;
			count = 0;
			IPointList points = curve.Points;

			if ( IsVisible && !Color.IsEmpty && points != null )
			{
				int index = 0;
				float curX, curY,
						lastX = 0,
						lastY = 0;
				double x, y, hiVal;
				ValueHandler valueHandler = new ValueHandler( pane, false );

				// Step type plots get twice as many points.  Always add three points so there is
				// room to close out the curve for area fills.
                arrPoints = new PointF[(_stepType == StepType.NonStep ? 1 : 2) *
					( pane.LineType == LineType.Stack ? 2 : 1 ) *
					points.Count + 1];

				// Loop backwards over all points in the curve
				// In this case an array of points was already built forward by BuildPointsArray().
				// This time we build backwards to complete a loop around the area between two curves.
				for ( int i = points.Count - 1; i >= 0; i-- )
				{
					// Make sure the current point is valid
					if ( !points[i].IsInvalid )
					{
						// Get the user scale values for the current point
						valueHandler.GetValues( curve, i, out x, out y, out hiVal );

						if ( x == PointPair.Missing || y == PointPair.Missing )
							continue;

						// Transform the user scale values to pixel locations
						Axis xAxis = curve.GetXAxis( pane );
						curX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, x );
						Axis yAxis = curve.GetYAxis( pane );
						curY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, y );

						// Add the pixel value pair into the points array
						// Two points are added for step type curves
						// ignore step-type setting for smooth curves
						if ( _isSmooth || index == 0 || StepType == StepType.NonStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.ForwardStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = lastY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.RearwardStep )
						{
							arrPoints[index].X = lastX;
							arrPoints[index].Y = curY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}

						lastX = curX;
						lastY = curY;
						index++;

					}

				}

				// Make sure there is at least one valid point
				if ( index == 0 )
					return false;

				// Add an extra point at the end, since the smoothing algorithm requires it
				arrPoints[index] = arrPoints[index - 1];
				index++;

				count = index;
				return true;
			}
		    return false;
		}
Exemple #8
0
		/// <summary>
		/// Build an array of <see c_ref="PointF"/> values (pixel coordinates) that represents
		/// the current curve.  Note that this drawing routine ignores <see c_ref="PointPairBase.Missing"/>
		/// values, but it does not "break" the line to indicate values are missing.
		/// </summary>
		/// <param name="pane">A reference to the <see c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.</param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="arrPoints">An array of <see c_ref="PointF"/> values in pixel
		/// coordinates representing the current curve.</param>
		/// <param name="count">The number of points contained in the "arrPoints"
		/// parameter.</param>
		/// <returns>true for a successful points array build, false for data problems</returns>
		public bool BuildPointsArray( GraphPane pane, CurveItem curve,
			out PointF[] arrPoints, out int count )
		{
			arrPoints = null;
			count = 0;
			IPointList points = curve.Points;

			if ( IsVisible && !Color.IsEmpty && points != null )
			{
				int index = 0;
				float curX, curY,
							lastX = 0,
							lastY = 0;
				double x, y, lowVal;
				ValueHandler valueHandler = new ValueHandler( pane, false );

				// Step type plots get twice as many points.  Always add three points so there is
				// room to close out the curve for area fills.
                arrPoints = new PointF[(_stepType == StepType.NonStep ? 1 : 2) *
											points.Count + 1];

				// Loop over all points in the curve
				for ( int i = 0; i < points.Count; i++ )
				{
					// make sure that the current point is valid
					if ( !points[i].IsInvalid )
					{
						// Get the user scale values for the current point
						// use the valueHandler only for stacked types
						if ( pane.LineType == LineType.Stack )
						{
							valueHandler.GetValues( curve, i, out x, out lowVal, out y );
						}
						// otherwise, just access the values directly.  Avoiding the valueHandler for
						// non-stacked types is an optimization to minimize overhead in case there are
						// a large number of points.
						else
						{
							x = points[i].X;
							y = points[i].Y;
						}

						if ( x == PointPair.Missing || y == PointPair.Missing )
							continue;

						// Transform the user scale values to pixel locations
						Axis xAxis = curve.GetXAxis( pane );
						curX = xAxis.Scale.Transform( curve.IsOverrideOrdinal, i, x );
						Axis yAxis = curve.GetYAxis( pane );
						curY = yAxis.Scale.Transform( curve.IsOverrideOrdinal, i, y );

						if ( curX < -1000000 || curY < -1000000 || curX > 1000000 || curY > 1000000 )
							continue;

						// Add the pixel value pair into the points array
						// Two points are added for step type curves
						// ignore step-type setting for smooth curves
						if ( _isSmooth || index == 0 || StepType == StepType.NonStep )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.ForwardStep ||
										StepType == StepType.ForwardSegment )
						{
							arrPoints[index].X = curX;
							arrPoints[index].Y = lastY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}
						else if ( StepType == StepType.RearwardStep ||
										StepType == StepType.RearwardSegment )
						{
							arrPoints[index].X = lastX;
							arrPoints[index].Y = curY;
							index++;
							arrPoints[index].X = curX;
							arrPoints[index].Y = curY;
						}

						lastX = curX;
						lastY = curY;
						index++;

					}

				}

				// Make sure there is at least one valid point
				if ( index == 0 )
					return false;

				// Add an extra point at the end, since the smoothing algorithm requires it
				arrPoints[index] = arrPoints[index - 1];
				index++;

				count = index;
				return true;
			}
		    return false;
		}
Exemple #9
0
		/// <summary>
		/// Draw all the <see c_ref="ErrorBar"/>'s to the specified <see c_ref="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 c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="CurveItem"/> object representing the
		/// <see c_ref="Bar"/>'s to be drawn.</param>
		/// <param name="baseAxis">The <see c_ref="Axis"/> class instance that defines the base (independent)
		/// axis for the <see c_ref="Bar"/></param>
		/// <param name="valueAxis">The <see c_ref="Axis"/> class instance that defines the value (dependent)
		/// axis for the <see c_ref="Bar"/></param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.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, float scaleFactor )
		{
			ValueHandler valueHandler = new ValueHandler( pane, false );

			float	pixBase, pixValue, pixLowValue;
			double	scaleBase, scaleValue, scaleLowValue;
		
			if ( curve.Points != null && IsVisible )
			{
				using ( Pen pen = !curve.IsSelected ? new Pen( _color, _penWidth ) :
						new Pen( Selection.Border.Color, Selection.Border.Width ) )
				{
					// Loop over each defined point							
					for ( int i = 0; i < curve.Points.Count; i++ )
					{
						valueHandler.GetValues( 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._scale.IsLog ) &&
								( ( scaleValue > 0 && scaleLowValue > 0 ) || !valueAxis._scale.IsLog ) )
						{
							pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, i, scaleBase );
							pixValue = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, scaleValue );
							pixLowValue = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, i, scaleLowValue );

							//if ( this.fill.IsGradientValueType )
							//	brush = fill.MakeBrush( _rect, _points[i] );

							Draw( g, pane, baseAxis is XAxis || baseAxis is X2Axis, pixBase, pixValue,
											pixLowValue, scaleFactor, pen, curve.IsSelected,
											curve.Points[i] );
						}
					}
				}
			}
		}
Exemple #10
0
        /// <summary>
        /// Determine the coords for the rectangle associated with a specified point for
        /// this <see c_ref="CurveItem" />
        /// </summary>
        /// <param name="pane">The <see c_ref="GraphPane" /> to which this curve belongs</param>
        /// <param name="i">The index of the point of interest</param>
        /// <param name="coords">A list of coordinates that represents the "rect" for
        /// this point (used in an html AREA tag)</param>
        /// <returns>true if it's a valid point, false otherwise</returns>
        override public bool GetCoords(GraphPane pane, int i, out string coords)
        {
            coords = string.Empty;

            if (i < 0 || i >= _points.Count)
            {
                return(false);
            }

            Axis valueAxis = ValueAxis(pane);
            Axis baseAxis  = BaseAxis(pane);

            float scaledSize = _bar.Symbol.Size * pane.CalcScaleFactor();

            // 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.BarSettings.GetClusterWidth();
            float barWidth     = GetBarWidth(pane);
            float clusterGap   = pane._barSettings.MinClusterGap * barWidth;
            float barGap       = barWidth * pane._barSettings.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(this, i, 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 (!_points[i].IsInvalid3D)
            {
                // calculate a pixel value for the top of the bar on value axis
                pixLowVal = valueAxis.Scale.Transform(_isOverrideOrdinal, i, curLowVal);
                pixHiVal  = valueAxis.Scale.Transform(_isOverrideOrdinal, i, curHiVal);
                // calculate a pixel value for the center of the bar on the base axis
                pixBase = baseAxis.Scale.Transform(_isOverrideOrdinal, i, curBase);

                // 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 || baseAxis is X2Axis)
                {
                    coords = String.Format("{0:f0},{1:f0},{2:f0},{3:f0}",
                                           pixSide, pixLowVal,
                                           pixSide + scaledSize, pixHiVal);
                }
                else
                {
                    coords = String.Format("{0:f0},{1:f0},{2:f0},{3:f0}",
                                           pixLowVal, pixSide,
                                           pixHiVal, pixSide + scaledSize);
                }

                return(true);
            }

            return(false);
        }
Exemple #11
0
		private Point HandlePointValues( Point mousePt )
		{
			int iPt;
			GraphPane pane;
			object nearestObj;

			using ( Graphics g = CreateGraphics() )
			{

				if ( _masterPane.FindNearestPaneObject( mousePt,
					g, out pane, out nearestObj, out iPt ) )
				{
					if ( nearestObj is CurveItem && iPt >= 0 )
					{
						CurveItem curve = (CurveItem)nearestObj;
						// Provide Callback for User to customize the tooltips
						if ( PointValueEvent != null )
						{
							string label = PointValueEvent( this, pane, curve, iPt );
							if ( label != null && label.Length > 0 )
							{
								pointToolTip.SetToolTip( this, label );
								pointToolTip.Active = true;
							}
							else
								pointToolTip.Active = false;
						}
						else
						{

							if ( curve is PieItem )
							{
								pointToolTip.SetToolTip( this,
									( (PieItem)curve ).Value.ToString( _pointValueFormat ) );
							}
							//							else if ( curve is OHLCBarItem || curve is JapaneseCandleStickItem )
							//							{
							//								StockPt spt = (StockPt)curve.Points[iPt];
							//								this.pointToolTip.SetToolTip( this, ( (XDate) spt.Date ).ToString( "MM/dd/yyyy" ) + "\nOpen: $" +
							//								spt.Open.ToString( "N2" ) +
							//								"\nHigh: $" +
							//								spt.High.ToString( "N2" ) + "\nLow: $" +
							//								spt.Low.ToString( "N2" ) + "\nClose: $" +
							//								spt.Close.ToString
							//								( "N2" ) );
							//							}
							else
							{
								PointPair pt = curve.Points[iPt];

								if ( pt.Tag is string )
									pointToolTip.SetToolTip( this, (string)pt.Tag );
								else
								{
									double xVal, yVal, lowVal;
									ValueHandler valueHandler = new ValueHandler( pane, false );
									if ( ( curve is BarItem || curve is ErrorBarItem || curve is HiLowBarItem )
											&& pane.BarSettings.Base != BarBase.X )
										valueHandler.GetValues( curve, iPt, out yVal, out lowVal, out xVal );
									else
										valueHandler.GetValues( curve, iPt, out xVal, out lowVal, out yVal );

									string xStr = MakeValueLabel( curve.GetXAxis( pane ), xVal, iPt,
										curve.IsOverrideOrdinal );
									string yStr = MakeValueLabel( curve.GetYAxis( pane ), yVal, iPt,
										curve.IsOverrideOrdinal );

									pointToolTip.SetToolTip( this, "( " + xStr + ", " + yStr + " )" );

									//this.pointToolTip.SetToolTip( this,
									//	curve.Points[iPt].ToString( this.pointValueFormat ) );
								}
							}

							pointToolTip.Active = true;
						}
					}
					else
						pointToolTip.Active = false;
				}
				else
					pointToolTip.Active = false;

				//g.Dispose();
			}
			return mousePt;
		}
Exemple #12
0
        /// <summary>
        /// Create a <see c_ref="TextObj" /> for each bar in the <see c_ref="GraphPane" />.
        /// </summary>
        /// <remarks>
        /// This method will go through the bars, create a label that corresponds to the bar value,
        /// and place it on the graph depending on user preferences.  This works for horizontal or
        /// vertical bars in clusters or stacks, but only for <see c_ref="BarItem" /> types.  This method
        /// does not apply to <see c_ref="ErrorBarItem" /> or <see c_ref="HiLowBarItem" /> objects.
        /// Call this method only after calling <see c_ref="GraphPane.AxisChange()" />.
        /// </remarks>
        /// <param name="pane">The GraphPane in which to place the text labels.</param>
        /// <param name="isBarCenter">true to center the labels inside the bars, false to
        /// place the labels just above the top of the bar.</param>
        /// <param name="valueFormat">The double.ToString string format to use for creating
        /// the labels.
        /// </param>
        /// <param name="fontColor">The color in which to draw the labels</param>
        /// <param name="fontFamily">The string name of the font family to use for the labels</param>
        /// <param name="fontSize">The floating point size of the font, in scaled points</param>
        /// <param name="isBold">true for a bold font type, false otherwise</param>
        /// <param name="isItalic">true for an italic font type, false otherwise</param>
        /// <param name="isUnderline">true for an underline font type, false otherwise</param>
        public static void CreateBarLabels(GraphPane pane, bool isBarCenter, string valueFormat,
                                           string fontFamily, float fontSize, Color fontColor, bool isBold, bool isItalic,
                                           bool isUnderline)
        {
            bool isVertical = pane.BarSettings.Base == BarBase.X;

            // keep a count of the number of BarItems
            int curveIndex = 0;

            // Get a valuehandler to do some calculations for us
            ValueHandler valueHandler = new ValueHandler(pane, true);

            // Loop through each curve in the list
            foreach (CurveItem curve in pane.CurveList)
            {
                // work with BarItems only
                BarItem bar = curve as BarItem;
                if (bar != null)
                {
                    IPointList points = curve.Points;

                    // ADD JKB 9/21/07
                    // The labelOffset should depend on whether the curve is YAxis or Y2Axis.
                    // JHC - Generalize to any value axis
                    // Make the gap between the bars and the labels = 1.5% of the axis range
                    float labelOffset;

                    Scale scale = curve.ValueAxis(pane).Scale;
                    labelOffset = (float)(scale._max - scale._min) * 0.015f;

                    // Loop through each point in the BarItem
                    for (int i = 0; i < points.Count; i++)
                    {
                        // Get the high, low and base values for the current bar
                        // note that this method will automatically calculate the "effective"
                        // values if the bar is stacked
                        double baseVal, lowVal, hiVal;
                        valueHandler.GetValues(curve, i, out baseVal, out lowVal, out hiVal);

                        // Get the value that corresponds to the center of the bar base
                        // This method figures out how the bars are positioned within a cluster
                        float centerVal = (float)valueHandler.BarCenterValue(bar,
                                                                             bar.GetBarWidth(pane), i, baseVal, curveIndex);

                        // Create a text label -- note that we have to go back to the original point
                        // data for this, since hiVal and lowVal could be "effective" values from a bar stack
                        string barLabelText = (isVertical ? points[i].Y : points[i].X).ToString(valueFormat);

                        // Calculate the position of the label -- this is either the X or the Y coordinate
                        // depending on whether they are horizontal or vertical bars, respectively
                        float position;
                        if (isBarCenter)
                        {
                            position = (float)(hiVal + lowVal) / 2.0f;
                        }
                        else if (hiVal >= 0)
                        {
                            position = (float)hiVal + labelOffset;
                        }
                        else
                        {
                            position = (float)hiVal - labelOffset;
                        }

                        // Create the new TextObj
                        TextObj label;
                        if (isVertical)
                        {
                            label = new TextObj(barLabelText, centerVal, position);
                        }
                        else
                        {
                            label = new TextObj(barLabelText, position, centerVal);
                        }

                        label.FontSpec.Family = fontFamily;

                        // Configure the TextObj

                        // CHANGE JKB 9/21/07
                        // CoordinateFrame should depend on whether curve is YAxis or Y2Axis.
                        label.Location.CoordinateFrame =
                            (isVertical && curve.IsY2Axis) ? CoordType.AxisXY2Scale : CoordType.AxisXYScale;

                        label.FontSpec.Size        = fontSize;
                        label.FontSpec.FontColor   = fontColor;
                        label.FontSpec.IsItalic    = isItalic;
                        label.FontSpec.IsBold      = isBold;
                        label.FontSpec.IsUnderline = isUnderline;

                        label.FontSpec.Angle  = isVertical ? 90 : 0;
                        label.Location.AlignH = isBarCenter ? AlignH.Center :
                                                (hiVal >= 0 ? AlignH.Left : AlignH.Right);
                        label.Location.AlignV           = AlignV.Center;
                        label.FontSpec.Border.IsVisible = false;
                        label.FontSpec.Fill.IsVisible   = false;

                        // Add the TextObj to the GraphPane
                        pane.GraphObjList.Add(label);
                    }
                    curveIndex++;
                }
            }
        }
Exemple #13
0
		/// <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 c_ref="Default.NearestTol"/> pixels of the screen point, and it will
		/// only consider <see c_ref="CurveItem"/>'s that are in 
		/// <paramref name="targetCurveList"/>.
		/// </remarks>
		/// <param name="mousePt">The screen point, in pixel coordinates.</param>
		/// <param name="targetCurveList">A <see c_ref="CurveList"/> object containing
		/// a subset of <see c_ref="CurveItem"/>'s to be searched.</param>
		/// <param name="nearestCurve">A reference to the <see c_ref="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 c_ref="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 c_ref="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 ChartRect, always return false
			if ( !_chart._rect.Contains( mousePt ) )
				return false;

			double x, x2;
			double[] y;
			double[] y2;

			//ReverseTransform( mousePt, out x, out y, out y2 );
			ReverseTransform( mousePt, out x, out x2, out y, out y2 );

			if ( !AxisRangesValid() )
				return false;

			ValueHandler valueHandler = new ValueHandler( this, false );

			//double	yPixPerUnit = chartRect.Height / ( yAxis.Max - yAxis.Min );
			//double	y2PixPerUnit; // = chartRect.Height / ( y2Axis.Max - y2Axis.Min );

			double yPixPerUnitAct, yAct, yMinAct, yMaxAct, xAct;
			double minDist = 1e20;
			double xVal, yVal, dist = 99999, distX, distY;
			double tolSquared = Default.NearestTol * Default.NearestTol;

			int iBar = 0;

			foreach ( CurveItem curve in targetCurveList )
			{
				//test for pie first...if it's a pie rest of method superfluous
				if ( curve is PieItem && curve.IsVisible )
				{
					if ( ( (PieItem)curve ).SlicePath != null &&
							( (PieItem)curve ).SlicePath.IsVisible( mousePt ) )
					{
						nearestBar = curve;
						iNearestBar = 0;
					}
				}
				else if ( curve.IsVisible )
				{
					int yIndex = curve.GetYAxisIndex( this );
					Axis yAxis = curve.GetYAxis( this );
					Axis xAxis = curve.GetXAxis( this );

					if ( curve.IsY2Axis )
					{
						yAct = y2[yIndex];
						yMinAct = _y2AxisList[yIndex]._scale._min;
						yMaxAct = _y2AxisList[yIndex]._scale._max;
					}
					else
					{
						yAct = y[yIndex];
						yMinAct = _yAxisList[yIndex]._scale._min;
						yMaxAct = _yAxisList[yIndex]._scale._max;
					}

					yPixPerUnitAct = _chart._rect.Height / ( yMaxAct - yMinAct );

					double xPixPerUnit = _chart._rect.Width / ( xAxis._scale._max - xAxis._scale._min );
					xAct = xAxis is XAxis ? x : x2;

					IPointList points = curve.Points;
					float barWidth = curve.GetBarWidth( this );
					double barWidthUserHalf;
					Axis baseAxis = curve.BaseAxis( this );
					bool isXBaseAxis = ( baseAxis is XAxis || baseAxis is X2Axis );
					if ( isXBaseAxis )
						barWidthUserHalf = barWidth / xPixPerUnit / 2.0;
					else
						barWidthUserHalf = barWidth / yPixPerUnitAct / 2.0;

					if ( points != null )
					{
						for ( int iPt = 0; iPt < curve.NPts; iPt++ )
						{
							// xVal is the user scale X value of the current point
							if ( xAxis._scale.IsAnyOrdinal && !curve.IsOverrideOrdinal )
								xVal = iPt + 1.0;
							else
								xVal = points[iPt].X;

							// yVal is the user scale Y value of the current point
							if ( yAxis._scale.IsAnyOrdinal && !curve.IsOverrideOrdinal )
								yVal = iPt + 1.0;
							else
								yVal = points[iPt].Y;

							if ( xVal != PointPair.Missing &&
									yVal != PointPair.Missing )
							{

								if ( curve.IsBar || curve is ErrorBarItem ||
									curve is HiLowBarItem || curve is OHLCBarItem ||
									curve is JapaneseCandleStickItem )
								{
									double baseVal, lowVal, hiVal;
									valueHandler.GetValues( 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 ( xAct < centerVal - barWidthUserHalf ||
												xAct > centerVal + barWidthUserHalf ||
												yAct < lowVal || yAct > hiVal )
											continue;
									}
									else
									{
										double centerVal = valueHandler.BarCenterValue( curve, barWidth, iPt, yVal, iBar );

										if ( yAct < centerVal - barWidthUserHalf ||
												yAct > centerVal + barWidthUserHalf ||
												xAct < lowVal || xAct > hiVal )
											continue;
									}

									if ( nearestBar == null )
									{
										iNearestBar = iPt;
										nearestBar = curve;
									}
								}
								else if ( xVal >= xAxis._scale._min && xVal <= xAxis._scale._max &&
											yVal >= yMinAct && yVal <= yMaxAct )
								{
									if ( curve is LineItem && _lineType == LineType.Stack )
									{
										double zVal;
										valueHandler.GetValues( curve, iPt, out xVal, out zVal, out yVal );
									}

									distX = ( xVal - xAct ) * 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 = ( (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;
			}
		    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;
		    }
		    return false;
		}
Exemple #14
0
		/// <summary>
		/// Determine the coords for the rectangle associated with a specified point for 
		/// this <see c_ref="CurveItem" />
		/// </summary>
		/// <param name="pane">The <see c_ref="GraphPane" /> to which this curve belongs</param>
		/// <param name="i">The index of the point of interest</param>
		/// <param name="coords">A list of coordinates that represents the "rect" for
		/// this point (used in an html AREA tag)</param>
		/// <returns>true if it's a valid point, false otherwise</returns>
		override public bool GetCoords( GraphPane pane, int i, out string coords )
		{
			coords = string.Empty;

			if ( i < 0 || i >= _points.Count )
				return false;

			PointPair pt = _points[i];
			if ( pt.IsInvalid )
				return false;

			double x, y, z;
			ValueHandler valueHandler = new ValueHandler( pane, false );
			valueHandler.GetValues( this, i, out x, out z, out y );

			Axis yAxis = GetYAxis( pane );
			Axis xAxis = GetXAxis( pane );

			PointF pixPt = new PointF( xAxis.Scale.Transform( _isOverrideOrdinal, i, x ),
							yAxis.Scale.Transform( _isOverrideOrdinal, i, y ) );
			
			if ( !pane.Chart.Rect.Contains( pixPt ) )
				return false;

			float halfSize = _symbol.Size * pane.CalcScaleFactor();

			coords = String.Format( "{0:f0},{1:f0},{2:f0},{3:f0}",
					pixPt.X - halfSize, pixPt.Y - halfSize,
					pixPt.X + halfSize, pixPt.Y + halfSize );

			return true;
		}
Exemple #15
0
		/// <summary>
		/// Draw this <see c_ref="CurveItem"/> to the specified <see c_ref="Graphics"/>
		/// device as a symbol at each defined point.  The routine
		/// only draws the symbols; the lines are draw by the
		/// <see c_ref="Line.DrawCurve"/> method.  This method
		/// is normally only called by the Draw method of the
		/// <see c_ref="CurveItem"/> object
		/// </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 c_ref="GraphPane"/> object that is the parent or
		/// owner of this object.
		/// </param>
		/// <param name="curve">A <see c_ref="LineItem"/> representing this
		/// curve.</param>
		/// <param name="scaleFactor">
		/// The scaling factor to be used for rendering objects.  This is calculated and
		/// passed down by the parent <see c_ref="GraphPane"/> object using the
		/// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
		/// font sizes, etc. according to the actual size of the graph.
		/// </param>
		/// <param name="isSelected">Indicates that the <see c_ref="Symbol" /> should be drawn
		/// with attributes from the <see c_ref="Selection" /> class.
		/// </param>
		public void Draw( Graphics g, GraphPane pane, LineItem curve, float scaleFactor,
			bool isSelected )
		{
			Symbol source = this;
			if ( isSelected )
				source = Selection.Symbol;

			int tmpX, tmpY;

			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;

			// (Dale-a-b) we'll set an element to true when it has been drawn	
			bool[,] isPixelDrawn = new bool[maxX + 1, maxY + 1];

			double curX, curY, lowVal;
			IPointList points = curve.Points;

			if ( points != null && ( _border.IsVisible || _fill.IsVisible ) )
			{
				SmoothingMode sModeSave = g.SmoothingMode;
				if ( _isAntiAlias )
					g.SmoothingMode = SmoothingMode.HighQuality;

				// For the sake of speed, go ahead and create a solid brush and a pen
				// If it's a gradient fill, it will be created on the fly for each symbol
				//SolidBrush	brush = new SolidBrush( this.fill.Color );

				using ( Pen pen = source._border.GetPen( pane, scaleFactor ) )
				using ( GraphicsPath path = MakePath( g, scaleFactor ) )
				{
					RectangleF rect = path.GetBounds();

					using ( Brush brush = source.Fill.MakeBrush( rect ) )
					{
						ValueHandler valueHandler = new ValueHandler( pane, false );
						Scale xScale = curve.GetXAxis( pane ).Scale;
						Scale yScale = curve.GetYAxis( pane ).Scale;

						bool xIsLog = xScale.IsLog;
						bool yIsLog = yScale.IsLog;
						bool xIsOrdinal = xScale.IsAnyOrdinal;

						double xMin = xScale.Min;
						double xMax = xScale.Max;

						// Loop over each defined point							
						for ( int i = 0; i < points.Count; i++ )
						{
							// Get the user scale values for the current point
							// use the valueHandler only for stacked types
							if ( pane.LineType == LineType.Stack )
							{
								valueHandler.GetValues( curve, i, out curX, out lowVal, out curY );
							}
							// otherwise, just access the values directly.  Avoiding the valueHandler for
							// non-stacked types is an optimization to minimize overhead in case there are
							// a large number of points.
							else
							{
								curX = points[i].X;
								if ( curve is StickItem )
									curY = points[i].Z;
								else
									curY = points[i].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 invalid

							if ( curX != PointPair.Missing &&
									curY != PointPair.Missing &&
									!Double.IsNaN( curX ) &&
									!Double.IsNaN( curY ) &&
									!Double.IsInfinity( curX ) &&
									!Double.IsInfinity( curY ) &&
									( curX > 0 || !xIsLog ) &&
									( !yIsLog || curY > 0.0 ) &&
									( xIsOrdinal || ( curX >= xMin && curX <= xMax ) ) )
							{
								// Transform the user scale values to pixel locations
								tmpX = (int) xScale.Transform( curve.IsOverrideOrdinal, i, curX );
								tmpY = (int) yScale.Transform( curve.IsOverrideOrdinal, i, curY );

								// Maintain an array of "used" pixel locations to avoid duplicate drawing operations
								if ( tmpX >= minX && tmpX <= maxX && tmpY >= minY && tmpY <= maxY ) // guard against the zoom-in case
								{
									if ( isPixelDrawn[tmpX, tmpY] )
										continue;
									isPixelDrawn[tmpX, tmpY] = true;
								}

								// If the fill type for this symbol is a Gradient by value type,
								// the make a brush corresponding to the appropriate current value
								if ( _fill.IsGradientValueType || _border._gradientFill.IsGradientValueType )
								{
									using ( Brush tBrush = _fill.MakeBrush( rect, points[i] ) )
									using ( Pen tPen = _border.GetPen( pane, scaleFactor, points[i] ) )
										DrawSymbol( g, tmpX, tmpY, path, tPen, tBrush );
								}
								else
								{
									// Otherwise, the brush is already defined
									// Draw the symbol at the specified pixel location
									DrawSymbol( g, tmpX, tmpY, path, pen, brush );
								}
							}
						}
					}
				}

				g.SmoothingMode = sModeSave;
			}
		}
Exemple #16
0
		/// <summary>
		/// Determine the coords for the rectangle associated with a specified point for 
		/// this <see c_ref="CurveItem" />
		/// </summary>
		/// <param name="pane">The <see c_ref="GraphPane" /> to which this curve belongs</param>
		/// <param name="i">The index of the point of interest</param>
		/// <param name="coords">A list of coordinates that represents the "rect" for
		/// this point (used in an html AREA tag)</param>
		/// <returns>true if it's a valid point, false otherwise</returns>
		override public bool GetCoords( GraphPane pane, int i, out string coords )
		{
			coords = string.Empty;

			if ( i < 0 || i >= _points.Count )
				return false;

			Axis valueAxis = ValueAxis( pane );
			Axis baseAxis = BaseAxis( pane );

			// 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.BarSettings.GetClusterWidth();
			float barWidth = GetBarWidth( pane );
			float clusterGap = pane._barSettings.MinClusterGap * barWidth;
			float barGap = barWidth * pane._barSettings.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( this, i, 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 ( !_points[i].IsInvalid3D )
			{
				// calculate a pixel value for the top of the bar on value axis
				pixLowVal = valueAxis.Scale.Transform( _isOverrideOrdinal, i, curLowVal );
				pixHiVal = valueAxis.Scale.Transform( _isOverrideOrdinal, i, curHiVal );
				// calculate a pixel value for the center of the bar on the base axis
				pixBase = baseAxis.Scale.Transform( _isOverrideOrdinal, i, curBase );

				// Calculate the pixel location for the side of the bar (on the base axis)
				float pixSide = pixBase - clusterWidth / 2.0F + clusterGap / 2.0F +
								pane.CurveList.GetBarItemPos( pane, this ) * ( barWidth + barGap );

				// Draw the bar
				if ( baseAxis is XAxis || baseAxis is X2Axis )
					coords = String.Format( "{0:f0},{1:f0},{2:f0},{3:f0}",
								pixSide, pixLowVal,
								pixSide + barWidth, pixHiVal );
				else
					coords = String.Format( "{0:f0},{1:f0},{2:f0},{3:f0}",
								pixLowVal, pixSide,
								pixHiVal, pixSide + barWidth );

				return true;
			}

			return false;
		}
Exemple #17
0
        /// <summary>
        /// Draw this <see c_ref="CurveItem"/> to the specified <see c_ref="Graphics"/>
        /// device as a symbol at each defined point.  The routine
        /// only draws the symbols; the lines are draw by the
        /// <see c_ref="Line.DrawCurve"/> method.  This method
        /// is normally only called by the Draw method of the
        /// <see c_ref="CurveItem"/> object
        /// </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 c_ref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">A <see c_ref="LineItem"/> representing this
        /// curve.</param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see c_ref="GraphPane"/> object using the
        /// <see c_ref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <param name="isSelected">Indicates that the <see c_ref="Symbol" /> should be drawn
        /// with attributes from the <see c_ref="Selection" /> class.
        /// </param>
        public void Draw(Graphics g, GraphPane pane, LineItem curve, float scaleFactor,
                         bool isSelected)
        {
            Symbol source = this;

            if (isSelected)
            {
                source = Selection.Symbol;
            }

            int tmpX, tmpY;

            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;

            // (Dale-a-b) we'll set an element to true when it has been drawn
            bool[,] isPixelDrawn = new bool[maxX + 1, maxY + 1];

            double     curX, curY, lowVal;
            IPointList points = curve.Points;

            if (points != null && (_border.IsVisible || _fill.IsVisible))
            {
                SmoothingMode sModeSave = g.SmoothingMode;
                if (_isAntiAlias)
                {
                    g.SmoothingMode = SmoothingMode.HighQuality;
                }

                // For the sake of speed, go ahead and create a solid brush and a pen
                // If it's a gradient fill, it will be created on the fly for each symbol
                //SolidBrush	brush = new SolidBrush( this.fill.Color );

                using (Pen pen = source._border.GetPen(pane, scaleFactor))
                    using (GraphicsPath path = MakePath(g, scaleFactor))
                    {
                        RectangleF rect = path.GetBounds();

                        using (Brush brush = source.Fill.MakeBrush(rect))
                        {
                            ValueHandler valueHandler = new ValueHandler(pane, false);
                            Scale        xScale       = curve.GetXAxis(pane).Scale;
                            Scale        yScale       = curve.GetYAxis(pane).Scale;

                            bool xIsLog     = xScale.IsLog;
                            bool yIsLog     = yScale.IsLog;
                            bool xIsOrdinal = xScale.IsAnyOrdinal;

                            double xMin = xScale.Min;
                            double xMax = xScale.Max;

                            // Loop over each defined point
                            for (int i = 0; i < points.Count; i++)
                            {
                                // Get the user scale values for the current point
                                // use the valueHandler only for stacked types
                                if (pane.LineType == LineType.Stack)
                                {
                                    valueHandler.GetValues(curve, i, out curX, out lowVal, out curY);
                                }
                                // otherwise, just access the values directly.  Avoiding the valueHandler for
                                // non-stacked types is an optimization to minimize overhead in case there are
                                // a large number of points.
                                else
                                {
                                    curX = points[i].X;
                                    if (curve is StickItem)
                                    {
                                        curY = points[i].Z;
                                    }
                                    else
                                    {
                                        curY = points[i].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 invalid

                                if (curX != PointPair.Missing &&
                                    curY != PointPair.Missing &&
                                    !Double.IsNaN(curX) &&
                                    !Double.IsNaN(curY) &&
                                    !Double.IsInfinity(curX) &&
                                    !Double.IsInfinity(curY) &&
                                    (curX > 0 || !xIsLog) &&
                                    (!yIsLog || curY > 0.0) &&
                                    (xIsOrdinal || (curX >= xMin && curX <= xMax)))
                                {
                                    // Transform the user scale values to pixel locations
                                    tmpX = (int)xScale.Transform(curve.IsOverrideOrdinal, i, curX);
                                    tmpY = (int)yScale.Transform(curve.IsOverrideOrdinal, i, curY);

                                    // Maintain an array of "used" pixel locations to avoid duplicate drawing operations
                                    if (tmpX >= minX && tmpX <= maxX && tmpY >= minY && tmpY <= maxY)                               // guard against the zoom-in case
                                    {
                                        if (isPixelDrawn[tmpX, tmpY])
                                        {
                                            continue;
                                        }
                                        isPixelDrawn[tmpX, tmpY] = true;
                                    }

                                    // If the fill type for this symbol is a Gradient by value type,
                                    // the make a brush corresponding to the appropriate current value
                                    if (_fill.IsGradientValueType || _border._gradientFill.IsGradientValueType)
                                    {
                                        using (Brush tBrush = _fill.MakeBrush(rect, points[i]))
                                            using (Pen tPen = _border.GetPen(pane, scaleFactor, points[i]))
                                                DrawSymbol(g, tmpX, tmpY, path, tPen, tBrush);
                                    }
                                    else
                                    {
                                        // Otherwise, the brush is already defined
                                        // Draw the symbol at the specified pixel location
                                        DrawSymbol(g, tmpX, tmpY, path, pen, brush);
                                    }
                                }
                            }
                        }
                    }

                g.SmoothingMode = sModeSave;
            }
        }
Exemple #18
0
        /// <summary>
        /// Calculate the range for stacked bars and lines.
        /// </summary>
        /// <remarks>This method is required for the stacked
        /// types because (for bars), the negative values are a separate stack than the positive
        /// values.  If you just sum up the bars, you will get the sum of the positive plus negative,
        /// which is less than the maximum positive value and greater than the maximum negative value.
        /// </remarks>
        /// <param name="pane">
        /// A reference to the <see c_ref="GraphPane"/> object that is the parent or
        /// owner of this object.
        /// </param>
        /// <param name="curve">The <see c_ref="CurveItem"/> for which to calculate the range</param>
        /// <param name="tXMinVal">The minimum X value so far</param>
        /// <param name="tYMinVal">The minimum Y value so far</param>
        /// <param name="tXMaxVal">The maximum X value so far</param>
        /// <param name="tYMaxVal">The maximum Y value so far</param>
        /// <seealso c_ref="GraphPane.IsBoundedRanges"/>
        private void GetStackRange(GraphPane pane, CurveItem curve, out double tXMinVal,
                                   out double tYMinVal, out double tXMaxVal, out double tYMaxVal)
        {
            // initialize the values to outrageous ones to start
            tXMinVal = tYMinVal = Double.MaxValue;
            tXMaxVal = tYMaxVal = Double.MinValue;

            ValueHandler valueHandler = new ValueHandler(pane, false);
            Axis         baseAxis     = curve.BaseAxis(pane);
            bool         isXBase      = baseAxis is XAxis || baseAxis is X2Axis;

            double lowVal, baseVal, hiVal;

            for (int i = 0; i < curve.Points.Count; i++)
            {
                valueHandler.GetValues(curve, i, out baseVal, out lowVal, out hiVal);
                double x = isXBase ? baseVal : hiVal;
                double y = isXBase ? hiVal : baseVal;

                if (x != PointPair.Missing && y != PointPair.Missing && lowVal != PointPair.Missing)
                {
                    if (x < tXMinVal)
                    {
                        tXMinVal = x;
                    }
                    if (x > tXMaxVal)
                    {
                        tXMaxVal = x;
                    }
                    if (y < tYMinVal)
                    {
                        tYMinVal = y;
                    }
                    if (y > tYMaxVal)
                    {
                        tYMaxVal = y;
                    }

                    if (!isXBase)
                    {
                        if (lowVal < tXMinVal)
                        {
                            tXMinVal = lowVal;
                        }
                        if (lowVal > tXMaxVal)
                        {
                            tXMaxVal = lowVal;
                        }
                    }
                    else
                    {
                        if (lowVal < tYMinVal)
                        {
                            tYMinVal = lowVal;
                        }
                        if (lowVal > tYMaxVal)
                        {
                            tYMaxVal = lowVal;
                        }
                    }
                }
            }
        }