Пример #1
0
        /// <summary>
        /// Draw the this <see cref="CurveItem"/> to the specified <see cref="Graphics"/>
        /// device.  The format (stair-step or line) of the curve is defined by the <see cref="StepType"/> property.  The routine only draws the line segments;
        /// the symbols are drawn by the
        /// <see cref="Symbol.Draw"/> method.  This method is normally only called by the Draw method of the
        /// <see cref="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 cref="GraphPane"/> object that is the parent or owner of this object.
        /// </param>
        /// <param name="curve">
        /// A <see cref="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 cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust font sizes, etc. according to the actual size of the graph.
        /// </param>
        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 && !this._color.IsEmpty && this.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 = PointPairBase.Missing;
                                curY = PointPairBase.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 == PointPairBase.Missing || curY == PointPairBase.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)
                                    {
                                        this.InterpolatePoint(g, pane, curve, lastPt, scaleFactor, pen, lastX, lastY, tmpX, tmpY);
                                    }
                                    else if (!isOut)
                                    {
                                        if (!curve.IsSelected && this._gradientFill.IsGradientValueType)
                                        {
                                            using (Pen tPen = this.GetPen(pane, scaleFactor, lastPt))
                                            {
                                                if (this.StepType == StepType.NonStep)
                                                {
                                                    g.DrawLine(tPen, lastX, lastY, tmpX, tmpY);
                                                }
                                                else if (this.StepType == StepType.ForwardStep)
                                                {
                                                    g.DrawLine(tPen, lastX, lastY, tmpX, lastY);
                                                    g.DrawLine(tPen, tmpX, lastY, tmpX, tmpY);
                                                }
                                                else if (this.StepType == StepType.RearwardStep)
                                                {
                                                    g.DrawLine(tPen, lastX, lastY, lastX, tmpY);
                                                    g.DrawLine(tPen, lastX, tmpY, tmpX, tmpY);
                                                }
                                                else if (this.StepType == StepType.ForwardSegment)
                                                {
                                                    g.DrawLine(tPen, lastX, lastY, tmpX, lastY);
                                                }
                                                else
                                                {
                                                    g.DrawLine(tPen, lastX, tmpY, tmpX, tmpY);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (this.StepType == StepType.NonStep)
                                            {
                                                g.DrawLine(pen, lastX, lastY, tmpX, tmpY);
                                            }
                                            else if (this.StepType == StepType.ForwardStep)
                                            {
                                                g.DrawLine(pen, lastX, lastY, tmpX, lastY);
                                                g.DrawLine(pen, tmpX, lastY, tmpX, tmpY);
                                            }
                                            else if (this.StepType == StepType.RearwardStep)
                                            {
                                                g.DrawLine(pen, lastX, lastY, lastX, tmpY);
                                                g.DrawLine(pen, lastX, tmpY, tmpX, tmpY);
                                            }
                                            else if (this.StepType == StepType.ForwardSegment)
                                            {
                                                g.DrawLine(pen, lastX, lastY, tmpX, lastY);
                                            }
                                            else if (this.StepType == StepType.RearwardSegment)
                                            {
                                                g.DrawLine(pen, lastX, tmpY, tmpX, tmpY);
                                            }
                                        }
                                    }
                                }
                                catch
                                {
                                    this.InterpolatePoint(g, pane, curve, lastPt, scaleFactor, pen, lastX, lastY, tmpX, tmpY);
                                }
                            }

                            lastPt = curPt;
                            lastX = tmpX;
                            lastY = tmpY;
                            lastBad = false;

                            // lastOut = isOut;
                        }
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Determine the coords for the rectangle associated with a specified point for this <see cref="CurveItem"/>
        /// </summary>
        /// <param name="pane">
        /// The <see cref="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>
        public override bool GetCoords(GraphPane pane, int i, out string coords)
        {
            coords = string.Empty;

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

            PointPair pt = this._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 = this.GetYAxis(pane);
            Axis xAxis = this.GetXAxis(pane);

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

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

            float halfSize = this._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;
        }
Пример #3
0
        /// <summary>
        /// Build an array of <see cref="PointF"/> values (pixel coordinates) that represents the low values for the current curve.
        /// </summary>
        /// <remarks>
        /// Note that this drawing routine ignores <see cref="PointPairBase.Missing"/>
        /// values, but it does not "break" the line to indicate values are missing.
        /// </remarks>
        /// <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="LineItem"/> representing this curve.
        /// </param>
        /// <param name="arrPoints">
        /// An array of <see cref="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 (this.IsVisible && !this.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[(this._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 == PointPairBase.Missing || y == PointPairBase.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 (this._isSmooth || index == 0 || this.StepType == StepType.NonStep)
                        {
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = curY;
                        }
                        else if (this.StepType == StepType.ForwardStep)
                        {
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = lastY;
                            index++;
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = curY;
                        }
                        else if (this.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;
        }
Пример #4
0
        /// <summary>
        /// Build an array of <see cref="PointF"/> values (pixel coordinates) that represents the current curve.  Note that this drawing routine ignores
        /// <see cref="PointPairBase.Missing"/>
        /// values, but it does not "break" the line to indicate values are missing.
        /// </summary>
        /// <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="LineItem"/> representing this curve.
        /// </param>
        /// <param name="arrPoints">
        /// An array of <see cref="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 (this.IsVisible && !this.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[(this._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 == PointPairBase.Missing || y == PointPairBase.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 (this._isSmooth || index == 0 || this.StepType == StepType.NonStep)
                        {
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = curY;
                        }
                        else if (this.StepType == StepType.ForwardStep || this.StepType == StepType.ForwardSegment)
                        {
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = lastY;
                            index++;
                            arrPoints[index].X = curX;
                            arrPoints[index].Y = curY;
                        }
                        else if (this.StepType == StepType.RearwardStep || this.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;
        }
Пример #5
0
        /// <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="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 cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust font sizes, etc. according to the actual size of the graph.
        /// </param>
        protected virtual 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)
                {
                    this.Draw(g, pane, pixSide, pixSide + barWidth, pixLowVal, pixHiVal, scaleFactor, true, curve.IsSelected, curve.Points[index]);
                }
                else
                {
                    this.Draw(g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth, scaleFactor, true, curve.IsSelected, curve.Points[index]);
                }
            }
        }
Пример #6
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 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 ChartRect, always return false
            if (!this._chart._rect.Contains(mousePt))
            {
                return false;
            }

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

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

            if (!this.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 = this._y2AxisList[yIndex]._scale._min;
                        yMaxAct = this._y2AxisList[yIndex]._scale._max;
                    }
                    else
                    {
                        yAct = y[yIndex];
                        yMinAct = this._yAxisList[yIndex]._scale._min;
                        yMaxAct = this._yAxisList[yIndex]._scale._max;
                    }

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

                    double xPixPerUnit = this._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 != PointPairBase.Missing && yVal != PointPairBase.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 && this._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 * this.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;
        }
Пример #7
0
        /// <summary>
        /// The handle point values.
        /// </summary>
        /// <param name="mousePt">
        /// The mouse pt.
        /// </param>
        /// <returns>
        /// The <see cref="Point"/>.
        /// </returns>
        private Point HandlePointValues(Point mousePt)
        {
            int iPt;
            GraphPane pane;
            object nearestObj;

            using (Graphics g = this.CreateGraphics())
            {
                if (this._masterPane.FindNearestPaneObject(mousePt, g, out pane, out nearestObj, out iPt))
                {
                    if (nearestObj is CurveItem && iPt >= 0)
                    {
                        CurveItem curve = (CurveItem)nearestObj;
                        if (this.PointValueEvent != null)
                        {
                            string label = this.PointValueEvent(this, pane, curve, iPt);
                            if (label != null && label.Length > 0)
                            {
                                if (this.pointToolTip.GetToolTip(this) != label)
                                {
                                    this.pointToolTip.Show(label, this);
                                }
                            }
                            else
                            {
                                this.pointToolTip.Hide(this);
                            }
                        }
                        else
                        {
                            if (curve is PieItem)
                            {
                                string label = ((PieItem)curve).Value.ToString(this._pointValueFormat);
                                if (this.pointToolTip.GetToolTip(this) != label)
                                {
                                    this.pointToolTip.Show(label, this);
                                }
                            }
                            else
                            {
                                PointPair pt = curve.Points[iPt];

                                if (pt.Tag is string)
                                {
                                    this.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 = this.MakeValueLabel(curve.GetXAxis(pane), xVal, iPt, curve.IsOverrideOrdinal);
                                    string yStr = this.MakeValueLabel(curve.GetYAxis(pane), yVal, iPt, curve.IsOverrideOrdinal);

                                    string label = "( " + xStr + ", " + yStr + " )";
                                    if (this.pointToolTip.GetToolTip(this) != label)
                                    {
                                        this.pointToolTip.Show(label, this);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        this.pointToolTip.Hide(this);
                    }
                }
                else
                {
                    this.pointToolTip.Hide(this);
                }
            }

            return mousePt;
        }
Пример #8
0
        /// <summary>
        /// Draw this <see cref="CurveItem"/> to the specified <see cref="Graphics"/>
        /// device as a symbol at each defined point.  The routine only draws the symbols; the lines are draw by the
        /// <see cref="Line.DrawCurve"/> method.  This method is normally only called by the Draw method of the
        /// <see cref="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 cref="GraphPane"/> object that is the parent or owner of this object.
        /// </param>
        /// <param name="curve">
        /// A <see cref="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 cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <param name="isSelected">
        /// Indicates that the <see cref="Symbol"/> should be drawn with attributes from the <see cref="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 && (this._border.IsVisible || this._fill.IsVisible))
            {
                SmoothingMode sModeSave = g.SmoothingMode;
                if (this._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 = this.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 != PointPairBase.Missing && curY != PointPairBase.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 (this._fill.IsGradientValueType || this._border._gradientFill.IsGradientValueType)
                                {
                                    using (Brush tBrush = this._fill.MakeBrush(rect, points[i])) using (Pen tPen = this._border.GetPen(pane, scaleFactor, points[i])) this.DrawSymbol(g, tmpX, tmpY, path, tPen, tBrush);
                                }
                                else
                                {
                                    // Otherwise, the brush is already defined
                                    // Draw the symbol at the specified pixel location
                                    this.DrawSymbol(g, tmpX, tmpY, path, pen, brush);
                                }
                            }
                        }
                    }
                }

                g.SmoothingMode = sModeSave;
            }
        }
Пример #9
0
        /// <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="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 && this.IsVisible)
            {
                using (Pen pen = !curve.IsSelected ? new Pen(this._color, this._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] );
                            this.Draw(
                                g,
                                pane,
                                baseAxis is XAxis || baseAxis is X2Axis,
                                pixBase,
                                pixValue,
                                pixLowValue,
                                scaleFactor,
                                pen,
                                curve.IsSelected,
                                curve.Points[i]);
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Determine the coords for the rectangle associated with a specified point for this <see cref="CurveItem"/>
        /// </summary>
        /// <param name="pane">
        /// The <see cref="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>
        public override bool GetCoords(GraphPane pane, int i, out string coords)
        {
            coords = string.Empty;

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

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

            float scaledSize = this._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 = this.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 (!this._points[i].IsInvalid3D)
            {
                // calculate a pixel value for the top of the bar on value axis
                pixLowVal = valueAxis.Scale.Transform(this._isOverrideOrdinal, i, curLowVal);
                pixHiVal = valueAxis.Scale.Transform(this._isOverrideOrdinal, i, curHiVal);

                // calculate a pixel value for the center of the bar on the base axis
                pixBase = baseAxis.Scale.Transform(this._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;
        }
Пример #11
0
        /// <summary>
        /// Create a <see cref="TextObj"/> for each bar in the <see cref="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 cref="BarItem"/> types.  This method does not apply to
        /// <see cref="ErrorBarItem"/> or <see cref="HiLowBarItem"/> objects. Call this method only after calling <see cref="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="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="fontColor">
        /// The color in which to draw the labels
        /// </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++;
                }
            }
        }