Пример #1
0
        /// <summary>
        /// Add a <see cref="CurveItem"/> to the selection list.
        /// </summary>
        /// <param name="master">
        /// The <see cref="MasterPane"/> that is the "owner" of the <see cref="CurveItem"/>'s.
        /// </param>
        /// <param name="ci">
        /// The <see cref="CurveItem"/> to be added to the list.
        /// </param>
        public void AddToSelection(MasterPane master, CurveItem ci)
        {
            if (this.Contains(ci) == false)
            {
                this.Add(ci);
            }

            this.UpdateSelection(master);
        }
Пример #2
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;
        }
Пример #3
0
 /// <summary>
 /// Find the data point that lies closest to the specified mouse (screen) point.
 /// </summary>
 /// <remarks>
 /// This method will search through all curves in
 /// <see cref="GraphPane.CurveList"/> to find which point is nearest.  It will only consider points that are within
 /// <see cref="Default.NearestTol"/> pixels of the screen point.
 /// </remarks>
 /// <param name="mousePt">
 /// The screen point, in pixel coordinates.
 /// </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, out CurveItem nearestCurve, out int iNearest)
 {
     return this.FindNearestPoint(mousePt, this._curveList, out nearestCurve, out iNearest);
 }
Пример #4
0
        /// <summary>
        /// Remove the specified <see cref="CurveItem"/> from the selection list.
        /// </summary>
        /// <param name="master">
        /// The <see cref="MasterPane"/> that is the "owner" of the <see cref="CurveItem"/>'s.
        /// </param>
        /// <param name="ci">
        /// The <see cref="CurveItem"/> to be removed from the list.
        /// </param>
        public void RemoveFromSelection(MasterPane master, CurveItem ci)
        {
            if (this.Contains(ci))
            {
                this.Remove(ci);
            }

            this.UpdateSelection(master);
        }
Пример #5
0
        /// <summary>
        /// Do all rendering associated with this <see cref="Line"/> to the specified
        /// <see cref="Graphics"/> device.  This method is normally only called by the Draw method of the parent <see cref="LineItem"/> 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 Draw(Graphics g, GraphPane pane, CurveItem curve, float scaleFactor)
        {
            // If the line is being shown, draw it
            if (this.IsVisible)
            {
                // How to handle fill vs nofill?
                // if ( isSelected )
                // 	GraphPane.Default.SelectedLine.
                SmoothingMode sModeSave = g.SmoothingMode;
                if (this._isAntiAlias)
                {
                    g.SmoothingMode = SmoothingMode.HighQuality;
                }

                if (curve is StickItem)
                {
                    this.DrawSticks(g, pane, curve, scaleFactor);
                }
                else if (this.IsSmooth || this.Fill.IsVisible)
                {
                    this.DrawSmoothFilledCurve(g, pane, curve, scaleFactor);
                }
                else
                {
                    this.DrawCurve(g, pane, curve, scaleFactor);
                }

                g.SmoothingMode = sModeSave;
            }
        }
Пример #6
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;
        }
Пример #7
0
        /// <summary>
        /// The is first line.
        /// </summary>
        /// <param name="pane">
        /// The pane.
        /// </param>
        /// <param name="curve">
        /// The curve.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool IsFirstLine(GraphPane pane, CurveItem curve)
        {
            CurveList curveList = pane.CurveList;

            for (int j = 0; j < curveList.Count; j++)
            {
                CurveItem tCurve = curveList[j];

                if (tCurve is LineItem && tCurve.IsY2Axis == curve.IsY2Axis && tCurve.YAxisIndex == curve.YAxisIndex)
                {
                    return tCurve == curve;
                }
            }

            return false;
        }
Пример #8
0
        /// <summary>
        /// Render the <see cref="Line"/>'s as vertical sticks (from a <see cref="StickItem"/>) 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"/> 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 DrawSticks(Graphics g, GraphPane pane, CurveItem curve, float scaleFactor)
        {
            Line source = this;
            if (curve.IsSelected)
            {
                source = Selection.Line;
            }

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

            float basePix = yAxis.Scale.Transform(0.0);
            using (Pen pen = source.GetPen(pane, scaleFactor))
            {
                for (int i = 0; i < curve.Points.Count; i++)
                {
                    PointPair pt = curve.Points[i];

                    if (pt.X != PointPairBase.Missing && pt.Y != PointPairBase.Missing && !double.IsNaN(pt.X) && !double.IsNaN(pt.Y)
                        && !double.IsInfinity(pt.X) && !double.IsInfinity(pt.Y) && (!xAxis._scale.IsLog || pt.X > 0.0)
                        && (!yAxis._scale.IsLog || pt.Y > 0.0))
                    {
                        float pixY = yAxis.Scale.Transform(curve.IsOverrideOrdinal, i, pt.Y);
                        float pixX = xAxis.Scale.Transform(curve.IsOverrideOrdinal, i, pt.X);

                        if (pixX >= pane.Chart._rect.Left && pixX <= pane.Chart._rect.Right)
                        {
                            if (pixY > pane.Chart._rect.Bottom)
                            {
                                pixY = pane.Chart._rect.Bottom;
                            }

                            if (pixY < pane.Chart._rect.Top)
                            {
                                pixY = pane.Chart._rect.Top;
                            }

                            if (!curve.IsSelected && this._gradientFill.IsGradientValueType)
                            {
                                using (Pen tPen = this.GetPen(pane, scaleFactor, pt)) g.DrawLine(tPen, pixX, pixY, pixX, basePix);
                            }
                            else
                            {
                                g.DrawLine(pen, pixX, pixY, pixX, basePix);
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Get the user scale values associate with a particular point of a particular curve.
        /// </summary>
        /// <remarks>
        /// The main purpose of this method is to handle stacked bars and lines, in which case the stacked values are returned rather than the individual data
        /// values.  However, this method works generically for any curve type.
        /// </remarks>
        /// <param name="pane">
        /// The parent <see cref="GraphPane"/> object.
        /// </param>
        /// <param name="curve">
        /// A <see cref="CurveItem"/> object of interest.
        /// </param>
        /// <param name="iPt">
        /// The zero-based point index for the point of interest.
        /// </param>
        /// <param name="baseVal">
        /// A <see cref="double"/> value representing the value for the independent axis.
        /// </param>
        /// <param name="lowVal">
        /// A <see cref="double"/> value representing the lower value for the dependent axis.
        /// </param>
        /// <param name="hiVal">
        /// A <see cref="double"/> value representing the upper value for the dependent axis.
        /// </param>
        /// <returns>
        /// true if the data point is value, false for
        /// <see cref="PointPairBase.Missing"/>, invalid, etc. data.
        /// </returns>
        public static bool GetValues(GraphPane pane, CurveItem curve, int iPt, out double baseVal, out double lowVal, out double hiVal)
        {
            hiVal = PointPairBase.Missing;
            lowVal = PointPairBase.Missing;
            baseVal = PointPairBase.Missing;

            if (curve == null || curve.Points.Count <= iPt || !curve.IsVisible)
            {
                return false;
            }

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

            if (baseAxis is XAxis || baseAxis is X2Axis)
            {
                baseVal = curve.Points[iPt].X;
            }
            else
            {
                baseVal = curve.Points[iPt].Y;
            }

            // is it a stacked bar type?
            if (curve is BarItem && (pane._barSettings.Type == BarType.Stack || pane._barSettings.Type == BarType.PercentStack))
            {
                double positiveStack = 0;
                double negativeStack = 0;
                double curVal;

                // loop through all the curves, summing up the values to get a total (only
                // for the current ordinal position iPt)
                foreach (CurveItem tmpCurve in pane.CurveList)
                {
                    // Sum the value for the current curve only if it is a bar
                    if (tmpCurve.IsBar && tmpCurve.IsVisible)
                    {
                        curVal = PointPairBase.Missing;

                        // For non-ordinal curves, find a matching base value (must match exactly)
                        if (curve.IsOverrideOrdinal || !baseAxis._scale.IsAnyOrdinal)
                        {
                            IPointList points = tmpCurve.Points;

                            for (int i = 0; i < points.Count; i++)
                            {
                                if ((baseAxis is XAxis || baseAxis is X2Axis) && points[i].X == baseVal)
                                {
                                    curVal = points[i].Y;
                                    break;
                                }

                                if (!(baseAxis is XAxis || baseAxis is X2Axis) && points[i].Y == baseVal)
                                {
                                    curVal = points[i].X;
                                    break;
                                }
                            }
                        }

                        // otherwise, it's an ordinal type so use the value at the same ordinal position
                        else if (iPt < tmpCurve.Points.Count)
                        {
                            // Get the value for the appropriate value axis
                            if (baseAxis is XAxis || baseAxis is X2Axis)
                            {
                                curVal = tmpCurve.Points[iPt].Y;
                            }
                            else
                            {
                                curVal = tmpCurve.Points[iPt].X;
                            }
                        }

                        // If it's a missing value, skip it
                        if (curVal == PointPairBase.Missing)
                        {
                            positiveStack = PointPairBase.Missing;
                            negativeStack = PointPairBase.Missing;
                        }

                        // the current curve is the target curve, save the summed values for later
                        if (tmpCurve == curve)
                        {
                            // if the value is positive, use the positive stack
                            if (curVal >= 0)
                            {
                                lowVal = positiveStack;
                                hiVal = (curVal == PointPairBase.Missing || positiveStack == PointPairBase.Missing)
                                            ? PointPairBase.Missing
                                            : positiveStack + curVal;
                            }

                            // otherwise, use the negative stack
                            else
                            {
                                hiVal = negativeStack;
                                lowVal = (curVal == PointPairBase.Missing || negativeStack == PointPairBase.Missing)
                                             ? PointPairBase.Missing
                                             : negativeStack + curVal;
                            }
                        }

                        // Add all positive values to the positive stack, and negative values to the
                        // negative stack
                        if (curVal >= 0)
                        {
                            positiveStack = (curVal == PointPairBase.Missing || positiveStack == PointPairBase.Missing)
                                                ? PointPairBase.Missing
                                                : positiveStack + curVal;
                        }
                        else
                        {
                            negativeStack = (curVal == PointPairBase.Missing || negativeStack == PointPairBase.Missing)
                                                ? PointPairBase.Missing
                                                : negativeStack + curVal;
                        }
                    }
                }

                // if the curve is a PercentStack type, then calculate the percent for this bar
                // based on the total height of the stack
                if (pane._barSettings.Type == BarType.PercentStack && hiVal != PointPairBase.Missing && lowVal != PointPairBase.Missing)
                {
                    // Use the total magnitude of the positive plus negative bar stacks to determine
                    // the percentage value
                    positiveStack += Math.Abs(negativeStack);

                    // just to avoid dividing by zero...
                    if (positiveStack != 0)
                    {
                        // calculate the percentage values
                        lowVal = lowVal / positiveStack * 100.0;
                        hiVal = hiVal / positiveStack * 100.0;
                    }
                    else
                    {
                        lowVal = 0;
                        hiVal = 0;
                    }
                }

                if (baseVal == PointPairBase.Missing || lowVal == PointPairBase.Missing || hiVal == PointPairBase.Missing)
                {
                    return false;
                }

                return true;
            }

                // If the curve is a stacked line type, then sum up the values similar to the stacked bar type
            if (curve is LineItem && pane.LineType == LineType.Stack)
            {
                double stack = 0;
                double curVal;

                // loop through all the curves, summing up the values to get a total (only
                // for the current ordinal position iPt)
                foreach (CurveItem tmpCurve in pane.CurveList)
                {
                    // make sure the curve is a Line type
                    if (tmpCurve is LineItem && tmpCurve.IsVisible)
                    {
                        curVal = PointPairBase.Missing;

                        // For non-ordinal curves, find a matching base value (must match exactly)
                        if (curve.IsOverrideOrdinal || !baseAxis._scale.IsAnyOrdinal)
                        {
                            IPointList points = tmpCurve.Points;

                            for (int i = 0; i < points.Count; i++)
                            {
                                if (points[i].X == baseVal)
                                {
                                    curVal = points[i].Y;
                                    break;
                                }
                            }
                        }

                        // otherwise, it's an ordinal type so use the value at the same ordinal position
                        else if (iPt < tmpCurve.Points.Count)
                        {
                            // For line types, the Y axis is always the value axis
                            curVal = tmpCurve.Points[iPt].Y;
                        }

                        // if the current value is missing, then the rest of the stack is missing
                        if (curVal == PointPairBase.Missing)
                        {
                            stack = PointPairBase.Missing;
                        }

                        // if the current curve is the target curve, save the values
                        if (tmpCurve == curve)
                        {
                            lowVal = stack;

                            // 							if ( curVal < 0 && stack == 0 )
                            // 							{
                            // 								stack = curVal;
                            // 								lowVal = curVal;
                            // 								hiVal = curVal;
                            // 							}
                            // 							else
                            hiVal = (curVal == PointPairBase.Missing || stack == PointPairBase.Missing) ? PointPairBase.Missing : stack + curVal;
                        }

                        // sum all the curves to a single total.  This includes both positive and
                        // negative values (unlike the bar stack type).
                        stack = (curVal == PointPairBase.Missing || stack == PointPairBase.Missing) ? PointPairBase.Missing : stack + curVal;
                    }
                }

                if (baseVal == PointPairBase.Missing || lowVal == PointPairBase.Missing || hiVal == PointPairBase.Missing)
                {
                    return false;
                }

                return true;
            }

                // otherwise, the curve is not a stacked type (not a stacked bar or stacked line)
            if ((!(curve is HiLowBarItem)) && (!(curve is ErrorBarItem)))
            {
                lowVal = 0;
            }
            else
            {
                lowVal = curve.Points[iPt].LowValue;
            }

            if (baseAxis is XAxis || baseAxis is X2Axis)
            {
                hiVal = curve.Points[iPt].Y;
            }
            else
            {
                hiVal = curve.Points[iPt].X;
            }

            // Special Exception: Bars on log scales should always plot from the Min value upwards,
            // since they can never be zero
            if (curve is BarItem && valueAxis._scale.IsLog && lowVal == 0)
            {
                lowVal = valueAxis._scale._min;
            }

            if (baseVal == PointPairBase.Missing || hiVal == PointPairBase.Missing
                || (lowVal == PointPairBase.Missing && (curve is ErrorBarItem || curve is HiLowBarItem)))
            {
                return false;
            }

            return true;
        }
Пример #10
0
 /// <summary>
 /// Get the user scale values associate with a particular point of a particular curve.
 /// </summary>
 /// <remarks>
 /// The main purpose of this method is to handle stacked bars, in which case the stacked values are returned rather than the individual data
 /// values.
 /// </remarks>
 /// <param name="curve">
 /// A <see cref="CurveItem"/> object of interest.
 /// </param>
 /// <param name="iPt">
 /// The zero-based point index for the point of interest.
 /// </param>
 /// <param name="baseVal">
 /// A <see cref="double"/> value representing the value for the independent axis.
 /// </param>
 /// <param name="lowVal">
 /// A <see cref="double"/> value representing the lower value for the dependent axis.
 /// </param>
 /// <param name="hiVal">
 /// A <see cref="double"/> value representing the upper value for the dependent axis.
 /// </param>
 /// <returns>
 /// true if the data point is value, false for
 /// <see cref="PointPairBase.Missing"/>, invalid, etc. data.
 /// </returns>
 public bool GetValues(CurveItem curve, int iPt, out double baseVal, out double lowVal, out double hiVal)
 {
     return GetValues(this._pane, curve, iPt, out baseVal, out lowVal, out hiVal);
 }
Пример #11
0
        /// <summary>
        /// Calculate the user scale position of the center of the specified bar, using the
        /// <see cref="Axis"/> as specified by <see cref="BarSettings.Base"/>.  This method is used primarily by the
        /// <see cref="GraphPane.FindNearestPoint(PointF,out CurveItem,out int)"/> method in order to determine the bar "location," which is defined as the
        /// center of the top of the individual bar.
        /// </summary>
        /// <param name="curve">
        /// The <see cref="CurveItem"/> representing the bar of interest.
        /// </param>
        /// <param name="barWidth">
        /// The width of each individual bar. This can be calculated using the <see cref="CurveItem.GetBarWidth"/> method.
        /// </param>
        /// <param name="iCluster">
        /// The cluster number for the bar of interest.  This is the ordinal position of the current point.  That is, if a particular <see cref="CurveItem"/>
        /// has 10 points, then a value of 3 would indicate the 4th point in the data array.
        /// </param>
        /// <param name="val">
        /// The actual independent axis value for the bar of interest.
        /// </param>
        /// <param name="iOrdinal">
        /// The ordinal position of the <see cref="CurveItem"/> of interest. That is, the first bar series is 0, the second is 1, etc.  Note that this applies
        /// only to the bars.  If a graph includes both bars and lines, then count only the bars.
        /// </param>
        /// <returns>
        /// A user scale value position of the center of the bar of interest.
        /// </returns>
        public double BarCenterValue(CurveItem curve, float barWidth, int iCluster, double val, int iOrdinal)
        {
            Axis baseAxis = curve.BaseAxis(this._pane);
            if (curve is ErrorBarItem || curve is HiLowBarItem || curve is OHLCBarItem || curve is JapaneseCandleStickItem)
            {
                if (baseAxis._scale.IsAnyOrdinal && iCluster >= 0 && !curve.IsOverrideOrdinal)
                {
                    return iCluster + 1.0;
                }

                return val;
            }

            float clusterWidth = this._pane._barSettings.GetClusterWidth();
            float clusterGap = this._pane._barSettings.MinClusterGap * barWidth;
            float barGap = barWidth * this._pane._barSettings.MinBarGap;

            if (curve.IsBar && this._pane._barSettings.Type != BarType.Cluster)
            {
                iOrdinal = 0;
            }

            float centerPix = baseAxis.Scale.Transform(curve.IsOverrideOrdinal, iCluster, val) - clusterWidth / 2.0F + clusterGap / 2.0F
                              + iOrdinal * (barWidth + barGap) + 0.5F * barWidth;
            return baseAxis.Scale.ReverseTransform(centerPix);
        }
Пример #12
0
        // public static Color SelectedSymbolColor = Color.Gray;

        #endregion Other

        #if ( DOTNET1 )

        // Define a "Contains" method so that this class works with .Net 1.1 or 2.0
        internal bool Contains( CurveItem item )
        {
            foreach ( CurveItem ci in this )
                if ( item == ci )
                    return true;

            return false;
        }
Пример #13
0
        /// <summary>
        /// Place a <see cref="CurveItem"/> in the selection list, removing all other items.
        /// </summary>
        /// <param name="master">
        /// The <see cref="MasterPane"/> that is the "owner" of the <see cref="CurveItem"/>'s.
        /// </param>
        /// <param name="ci">
        /// The <see cref="CurveItem"/> to be added to the list.
        /// </param>
        public void Select(MasterPane master, CurveItem ci)
        {
            // Clear the selection, but don't send the event,
            // the event will be sent in "AddToSelection" by calling "UpdateSelection"
            this.ClearSelection(master, false);

            this.AddToSelection(master, ci);
        }
Пример #14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CurveItem"/> class. 
        /// The Copy Constructor
        /// </summary>
        /// <param name="rhs">
        /// The CurveItem object from which to copy
        /// </param>
        public CurveItem(CurveItem rhs)
        {
            this._label = rhs._label.Clone();
            this._isY2Axis = rhs.IsY2Axis;
            this._isX2Axis = rhs.IsX2Axis;
            this._isVisible = rhs.IsVisible;
            this._isOverrideOrdinal = rhs._isOverrideOrdinal;
            this._yAxisIndex = rhs._yAxisIndex;

            if (rhs.Tag is ICloneable)
            {
                this.Tag = ((ICloneable)rhs.Tag).Clone();
            }
            else
            {
                this.Tag = rhs.Tag;
            }

            this._points = (IPointList)rhs.Points.Clone();

            this._link = rhs._link.Clone();
        }
Пример #15
0
        /// <summary>
        /// Draw the this <see cref="Bar"/> to the specified <see cref="Graphics"/>
        /// device as a bar at each defined point. This method is normally only called by the <see cref="BarItem.Draw"/> method of the
        /// <see cref="BarItem"/> 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="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="barWidth">
        /// The width of each bar, in pixels.
        /// </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="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 DrawBars(Graphics g, GraphPane pane, CurveItem curve, Axis baseAxis, Axis valueAxis, float barWidth, int pos, float scaleFactor)
        {
            // For non-cluster bar types, the position is always zero since the bars are on top
            // of eachother
            BarType barType = pane._barSettings.Type;
            if (barType == BarType.Overlay || barType == BarType.Stack || barType == BarType.PercentStack || barType == BarType.SortedOverlay)
            {
                pos = 0;
            }

            // Loop over each defined point and draw the corresponding bar
            for (int i = 0; i < curve.Points.Count; i++)
            {
                this.DrawSingleBar(g, pane, curve, i, pos, baseAxis, valueAxis, barWidth, scaleFactor);
            }
        }
Пример #16
0
        /// <summary>
        /// Draw the this <see cref="CurveItem"/> to the specified <see cref="Graphics"/>
        /// device using the specified smoothing property (<see cref="Line.SmoothTension"/>). The routine draws the line segments and the area fill (if any, see
        /// <see cref="FillType"/>; 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.  Note that the <see cref="StepType"/> property is ignored for smooth lines (e.g., when <see cref="Line.IsSmooth"/>
        /// is true).
        /// </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 DrawSmoothFilledCurve(Graphics g, GraphPane pane, CurveItem curve, float scaleFactor)
        {
            Line source = this;
            if (curve.IsSelected)
            {
                source = Selection.Line;
            }

            PointF[] arrPoints;
            int count;
            IPointList points = curve.Points;

            if (this.IsVisible && !this.Color.IsEmpty && points != null && this.BuildPointsArray(pane, curve, out arrPoints, out count) && count > 2)
            {
                float tension = this._isSmooth ? this._smoothTension : 0f;

                // Fill the curve if needed
                if (this.Fill.IsVisible)
                {
                    Axis yAxis = curve.GetYAxis(pane);

                    using (GraphicsPath path = new GraphicsPath(FillMode.Winding))
                    {
                        path.AddCurve(arrPoints, 0, count - 2, tension);

                        double yMin = yAxis._scale._min < 0 ? 0.0 : yAxis._scale._min;
                        this.CloseCurve(pane, curve, arrPoints, count, yMin, path);

                        RectangleF rect = path.GetBounds();
                        using (Brush brush = source._fill.MakeBrush(rect))
                        {
                            if (pane.LineType == LineType.Stack && yAxis.Scale._min < 0 && this.IsFirstLine(pane, curve))
                            {
                                float zeroPix = yAxis.Scale.Transform(0);
                                RectangleF tRect = pane.Chart._rect;
                                tRect.Height = zeroPix - tRect.Top;
                                if (tRect.Height > 0)
                                {
                                    Region reg = g.Clip;
                                    g.SetClip(tRect);
                                    g.FillPath(brush, path);
                                    g.SetClip(pane.Chart._rect);
                                }
                            }
                            else
                            {
                                g.FillPath(brush, path);
                            }

                            // brush.Dispose();
                        }

                        // restore the zero line if needed (since the fill tends to cover it up)
                        yAxis.FixZeroLine(g, pane, scaleFactor, rect.Left, rect.Right);
                    }
                }

                // If it's a smooth curve, go ahead and render the path.  Otherwise, use the
                // standard drawcurve method just in case there are missing values.
                if (this._isSmooth)
                {
                    using (Pen pen = this.GetPen(pane, scaleFactor))
                    {
                        // Stroke the curve
                        g.DrawCurve(pen, arrPoints, 0, count - 2, tension);

                        // pen.Dispose();
                    }
                }
                else
                {
                    this.DrawCurve(g, pane, curve, scaleFactor);
                }
            }
        }
Пример #17
0
        /// <summary>
        /// Draw the specified single bar (an individual "point") of this series to the specified
        /// <see cref="Graphics"/> device.  This method is not as efficient as
        /// <see cref="DrawBars"/>, which draws the bars for all points.  It is intended to be used only for <see cref="BarType.SortedOverlay"/>, which
        /// requires special handling of each bar.
        /// </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="pos">
        /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) in the cluster of bars.
        /// </param>
        /// <param name="index">
        /// The zero-based index number for the single bar to be drawn.
        /// </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>
        public void DrawSingleBar(
            Graphics g, 
            GraphPane pane, 
            CurveItem curve, 
            Axis baseAxis, 
            Axis valueAxis, 
            int pos, 
            int index, 
            float barWidth, 
            float scaleFactor)
        {
            // Make sure that a bar value exists for the current curve and current ordinal position
            if (index >= curve.Points.Count)
            {
                return;
            }

            // For Overlay and Stack bars, the position is always zero since the bars are on top
            // of eachother
            if (pane._barSettings.Type == BarType.Overlay || pane._barSettings.Type == BarType.Stack || pane._barSettings.Type == BarType.PercentStack)
            {
                pos = 0;
            }

            // Draw the specified bar
            this.DrawSingleBar(g, pane, curve, index, pos, baseAxis, valueAxis, barWidth, scaleFactor);
        }
Пример #18
0
        /// <summary>
        /// This method just handles the case where one or more of the coordinates are outrageous, or GDI+ threw an exception.  This method attempts to correct
        /// the outrageous coordinates by interpolating them to a point (along the original line) that lies at the edge of the ChartRect so that GDI+ will handle
        /// it properly.  GDI+ will throw an exception, or just plot the data incorrectly if the coordinates are too large (empirically, this appears to be when
        /// the coordinate value is greater than 5,000,000 or less than -5,000,000).  Although you typically would not see coordinates like this, if you
        /// repeatedly zoom in on a ZedGraphControl, eventually all your points will be way outside the bounds of the plot.
        /// </summary>
        /// <param name="g">
        /// The g.
        /// </param>
        /// <param name="pane">
        /// The pane.
        /// </param>
        /// <param name="curve">
        /// The curve.
        /// </param>
        /// <param name="lastPt">
        /// The last Pt.
        /// </param>
        /// <param name="scaleFactor">
        /// The scale Factor.
        /// </param>
        /// <param name="pen">
        /// The pen.
        /// </param>
        /// <param name="lastX">
        /// The last X.
        /// </param>
        /// <param name="lastY">
        /// The last Y.
        /// </param>
        /// <param name="tmpX">
        /// The tmp X.
        /// </param>
        /// <param name="tmpY">
        /// The tmp Y.
        /// </param>
        private void InterpolatePoint(
            Graphics g, 
            GraphPane pane, 
            CurveItem curve, 
            PointPair lastPt, 
            float scaleFactor, 
            Pen pen, 
            float lastX, 
            float lastY, 
            float tmpX, 
            float tmpY)
        {
            try
            {
                RectangleF chartRect = pane.Chart._rect;

                // try to interpolate values
                bool lastIn = chartRect.Contains(lastX, lastY);
                bool curIn = chartRect.Contains(tmpX, tmpY);

                // If both points are outside the ChartRect, make a new point that is on the LastX/Y
                // side of the ChartRect, and fall through to the code that handles lastIn == true
                if (!lastIn)
                {
                    float newX, newY;

                    if (Math.Abs(lastX) > Math.Abs(lastY))
                    {
                        newX = lastX < 0 ? chartRect.Left : chartRect.Right;
                        newY = lastY + (tmpY - lastY) * (newX - lastX) / (tmpX - lastX);
                    }
                    else
                    {
                        newY = lastY < 0 ? chartRect.Top : chartRect.Bottom;
                        newX = lastX + (tmpX - lastX) * (newY - lastY) / (tmpY - lastY);
                    }

                    lastX = newX;
                    lastY = newY;
                }

                if (!curIn)
                {
                    float newX, newY;

                    if (Math.Abs(tmpX) > Math.Abs(tmpY))
                    {
                        newX = tmpX < 0 ? chartRect.Left : chartRect.Right;
                        newY = tmpY + (lastY - tmpY) * (newX - tmpX) / (lastX - tmpX);
                    }
                    else
                    {
                        newY = tmpY < 0 ? chartRect.Top : chartRect.Bottom;
                        newX = tmpX + (lastX - tmpX) * (newY - tmpY) / (lastY - tmpY);
                    }

                    tmpX = newX;
                    tmpY = newY;
                }

                /*
                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 		// non-step
                    g.DrawLine( pen, lastX, lastY, tmpX, tmpY );
                */
                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
            {
            }
        }
Пример #19
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]);
                }
            }
        }
Пример #20
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;
        }
Пример #21
0
        /// <summary>
        /// Create a URL for a <see cref="CurveItem"/> that includes the index of the point that was selected.
        /// </summary>
        /// <remarks>
        /// An "index" parameter is added to the <see cref="Url"/> property for this link to indicate which point was selected.  Further, if the X or Y axes
        /// that correspond to this <see cref="CurveItem"/> are of
        /// <see cref="AxisType.Text"/>, then an additional parameter will be added containing the text value that corresponds to the <paramref name="index"/>
        /// of the selected point. The <see cref="XAxis"/> text parameter will be labeled "xtext", and the <see cref="YAxis"/> text parameter will be labeled
        /// "ytext".
        /// </remarks>
        /// <param name="pane">
        /// The <see cref="GraphPane"/> of interest
        /// </param>
        /// <param name="curve">
        /// The <see cref="CurveItem"/> for which to make the url string.
        /// </param>
        /// <param name="index">
        /// The zero-based index of the selected point
        /// </param>
        /// <returns>
        /// A string containing the url with an index parameter added.
        /// </returns>
        public virtual string MakeCurveItemUrl(GraphPane pane, CurveItem curve, int index)
        {
            string url = this._url;

            if (url.IndexOf('?') >= 0)
            {
                url += "&index=" + index;
            }
            else
            {
                url += "?index=" + index;
            }

            Axis xAxis = curve.GetXAxis(pane);
            if (xAxis.Type == AxisType.Text && index >= 0 && xAxis.Scale.TextLabels != null && index <= xAxis.Scale.TextLabels.Length)
            {
                url += "&xtext=" + xAxis.Scale.TextLabels[index];
            }

            Axis yAxis = curve.GetYAxis(pane);
            if (yAxis != null && yAxis.Type == AxisType.Text && index >= 0 && yAxis.Scale.TextLabels != null && index <= yAxis.Scale.TextLabels.Length)
            {
                url += "&ytext=" + yAxis.Scale.TextLabels[index];
            }

            return url;
        }
Пример #22
0
        /// <summary>
        /// Close off a <see cref="GraphicsPath"/> that defines a curve
        /// </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 screen pixel coordinates representing the current curve.
        /// </param>
        /// <param name="count">
        /// The number of points contained in the "arrPoints" parameter.
        /// </param>
        /// <param name="yMin">
        /// The Y axis value location where the X axis crosses.
        /// </param>
        /// <param name="path">
        /// The <see cref="GraphicsPath"/> class that represents the curve.
        /// </param>
        public void CloseCurve(GraphPane pane, CurveItem curve, PointF[] arrPoints, int count, double yMin, GraphicsPath path)
        {
            // For non-stacked lines, the fill area is just the area between the curve and the X axis
            if (pane.LineType != LineType.Stack)
            {
                // Determine the current value for the bottom of the curve (usually the Y value where
                // the X axis crosses)
                float yBase;
                Axis yAxis = curve.GetYAxis(pane);
                yBase = yAxis.Scale.Transform(yMin);

                // Add three points to the path to move from the end of the curve (as defined by
                // arrPoints) to the X axis, from there to the start of the curve at the X axis,
                // and from there back up to the beginning of the curve.
                path.AddLine(arrPoints[count - 1].X, arrPoints[count - 1].Y, arrPoints[count - 1].X, yBase);
                path.AddLine(arrPoints[count - 1].X, yBase, arrPoints[0].X, yBase);
                path.AddLine(arrPoints[0].X, yBase, arrPoints[0].X, arrPoints[0].Y);
            }

            // For stacked line types, the fill area is the area between this curve and the curve below it
            else
            {
                PointF[] arrPoints2;
                int count2;

                float tension = this._isSmooth ? this._smoothTension : 0f;

                // Find the next lower curve in the curveList that is also a LineItem type, and use
                // its smoothing properties for the lower side of the filled area.
                int index = pane.CurveList.IndexOf(curve);
                if (index > 0)
                {
                    CurveItem tmpCurve;
                    for (int i = index - 1; i >= 0; i--)
                    {
                        tmpCurve = pane.CurveList[i];
                        if (tmpCurve is LineItem)
                        {
                            tension = ((LineItem)tmpCurve).Line.IsSmooth ? ((LineItem)tmpCurve).Line.SmoothTension : 0f;
                            break;
                        }
                    }
                }

                // Build another points array consisting of the low points (which are actually the points for
                // the curve below the current curve)
                this.BuildLowPointsArray(pane, curve, out arrPoints2, out count2);

                // Add the new points to the GraphicsPath
                path.AddCurve(arrPoints2, 0, count2 - 2, tension);
            }
        }
Пример #23
0
 /// <summary>
 /// Find the data point that lies closest to the specified mouse (screen) point for the specified curve.
 /// </summary>
 /// <remarks>
 /// This method will search only through the points for the specified curve to determine which point is nearest the mouse point.  It will only consider
 /// points that are within
 /// <see cref="Default.NearestTol"/> pixels of the screen point.
 /// </remarks>
 /// <param name="mousePt">
 /// The screen point, in pixel coordinates.
 /// </param>
 /// <param name="targetCurve">
 /// A <see cref="CurveItem"/> object containing the data points 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, CurveItem targetCurve, out CurveItem nearestCurve, out int iNearest)
 {
     CurveList targetCurveList = new CurveList();
     targetCurveList.Add(targetCurve);
     return this.FindNearestPoint(mousePt, targetCurveList, out nearestCurve, out iNearest);
 }
Пример #24
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;
                        }
                    }
                }
            }
        }
Пример #25
0
        /// <summary>
        /// The graph_ point value event.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="pane">
        /// The pane.
        /// </param>
        /// <param name="curve">
        /// The curve.
        /// </param>
        /// <param name="iPt">
        /// The i pt.
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        private string graph_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt)
        {
            PointPair point = curve[iPt];
            var flight = point.Tag as Flight;
            if (flight != null)
            {
                return flight.SummaryString;
            }

            return string.Empty;
        }