Пример #1
0
        /// <summary>
        /// Check if any series is indexed. IsXValueIndexed flag is set or all X values are zeros.
        /// </summary>
        /// <param name="common">Reference to common chart classes.</param>
        /// <param name="series">Data series names.</param>
        /// <returns>True if any series is indexed.</returns>
        static internal bool IndexedSeries(CommonElements common, params string[] series)
        {
            // Data series loop
            bool zeroXValues = true;

            foreach (string ser in series)
            {
                Series localSeries = common.DataManager.Series[ser];

                // Check series indexed flag
                if (localSeries.IsXValueIndexed)
                {
                    // If flag set in at least one series - all series are indexed
                    return(true);
                }

                // Check if series has all X values set to zero
                if (zeroXValues && !IndexedSeries(localSeries))
                {
                    zeroXValues = false;
                }
            }

            return(zeroXValues);
        }
Пример #2
0
        /// <summary>
        /// Returns marker size.
        /// </summary>
        /// <param name="graph">The Chart Graphics object.</param>
        /// <param name="common">The Common elements object.</param>
        /// <param name="area">Chart area for this chart.</param>
        /// <param name="point">Data point.</param>
        /// <param name="markerSize">Marker size.</param>
        /// <param name="markerImage">Marker image.</param>
        /// <returns>Marker width and height.</returns>
        override protected SKSize GetMarkerSize(
            ChartGraphics graph,
            CommonElements common,
            ChartArea area,
            DataPoint point,
            int markerSize,
            string markerImage)
        {
            // Check required Y values number
            if (point.YValues.Length < YValuesPerPoint)
            {
                throw(new InvalidOperationException(SR.ExceptionChartTypeRequiresYValues(Name, YValuesPerPoint.ToString(CultureInfo.InvariantCulture))));
            }

            // Marker size
            SKSize size = new(markerSize, markerSize);

            if (graph != null && graph.Graphics != null)
            {
                // Marker size is in pixels and we do the mapping for higher DPIs
                size.Width  = markerSize;
                size.Height = markerSize;
            }

            // Check number of Y values for non empty points
            if (point.series.YValuesPerPoint > 1 && !point.IsEmpty)
            {
                // Scale Y values
                size.Width  = ScaleBubbleSize(graph, common, area, point.YValues[1]);
                size.Height = ScaleBubbleSize(graph, common, area, point.YValues[1]);
            }

            return(size);
        }
Пример #3
0
 /// <summary>
 /// Paint event arguments constructor.
 /// </summary>
 /// <param name="chartElement">Chart element.</param>
 /// <param name="chartGraph">Chart graphics.</param>
 /// <param name="common">Common elements.</param>
 /// <param name="position">Position.</param>
 internal ChartPaintEventArgs(object chartElement, ChartGraphics chartGraph, CommonElements common, ElementPosition position)
 {
     _chartElement = chartElement;
     _chartGraph   = chartGraph;
     _common       = common;
     _position     = position;
 }
Пример #4
0
 /// <summary>
 /// This method recalculates size of the bars. This method is used
 /// from Paint or Select method.
 /// </summary>
 /// <param name="selection">If True selection mode is active, otherwise paint mode is active</param>
 /// <param name="graph">The Chart Graphics object</param>
 /// <param name="common">The Common elements object</param>
 /// <param name="area">Chart area for this chart</param>
 /// <param name="seriesToDraw">Chart series to draw.</param>
 override protected void ProcessChartType(
     bool selection,
     ChartGraphics graph,
     CommonElements common,
     ChartArea area,
     Series seriesToDraw)
 {
     _scaleDetected = false;
     base.ProcessChartType(selection, graph, common, area, seriesToDraw);
 }
Пример #5
0
 /// <summary>
 /// Helper function, which returns the Y value of the point.
 /// </summary>
 /// <param name="common">Chart common elements.</param>
 /// <param name="area">Chart area the series belongs to.</param>
 /// <param name="series">Sereis of the point.</param>
 /// <param name="point">Point object.</param>
 /// <param name="pointIndex">Index of the point.</param>
 /// <param name="yValueIndex">Index of the Y value to get.</param>
 /// <returns>Y value of the point.</returns>
 virtual public double GetYValue(
     CommonElements common,
     ChartArea area,
     Series series,
     DataPoint point,
     int pointIndex,
     int yValueIndex)
 {
     return(point.YValues[yValueIndex]);
 }
Пример #6
0
 /// <summary>
 /// Check if all data points in many series have X value set to 0.
 /// </summary>
 /// <param name="common">Reference to common chart classes.</param>
 /// <param name="series">Data series.</param>
 /// <returns>True if all data points have value 0.</returns>
 static internal bool SeriesXValuesZeros(CommonElements common, params string[] series)
 {
     // Data series loop
     foreach (string ser in series)
     {
         // Check one series X values
         if (!SeriesXValuesZeros(common.DataManager.Series[ser]))
         {
             return(false);
         }
     }
     return(true);
 }
Пример #7
0
        /// <summary>
        /// Get value from custom attribute BubbleMaxSize
        /// </summary>
        /// <param name="area">Chart Area</param>
        /// <returns>Bubble Max size</returns>
        static internal double GetBubbleMaxSize(ChartArea area)
        {
            double maxPossibleBubbleSize = 15;

            // Try to find bubble size scale in the custom series properties
            foreach (Series ser in area.Common.DataManager.Series)
            {
                if (string.Compare(ser.ChartTypeName, ChartTypeNames.Bubble, StringComparison.OrdinalIgnoreCase) == 0 &&
                    ser.ChartArea == area.Name &&
                    ser.IsVisible() && ser.IsCustomPropertySet(CustomPropertyName.BubbleMaxSize))
                {
                    maxPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMaxSize]);
                    if (maxPossibleBubbleSize < 0 || maxPossibleBubbleSize > 100)
                    {
                        throw (new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMaxSize")));
                    }
                }
            }

            return(maxPossibleBubbleSize / 100);
        }
Пример #8
0
 /// <summary>
 /// Data manager public constructor
 /// </summary>
 /// <param name="container">Service container object.</param>
 public DataManager(CommonElements common)
 {
     Common  = common;
     _series = new SeriesCollection(this);
 }
Пример #9
0
        /// <summary>
        /// Scales the value used to determine the size of the Bubble.
        /// </summary>
        /// <param name="common">The Common elements object</param>
        /// <param name="area">Chart area for this chart</param>
        /// <param name="value">Value to scale.</param>
        /// <param name="yValue">True if Y value is calculated, false if X.</param>
        /// <returns>Scaled values.</returns>
        static internal double AxisScaleBubbleSize(CommonElements common, ChartArea area, double value, bool yValue)
        {
            // Try to find bubble size scale in the custom series properties
            double minAll = double.MaxValue;
            double maxAll = double.MinValue;
            double maxPossibleBubbleSize = 15F;
            double minPossibleBubbleSize = 3F;
            float  maxBubleSize;
            float  minBubleSize;
            double valueScale;
            double valueDiff;

            foreach (Series ser in common.DataManager.Series)
            {
                if (String.Compare(ser.ChartTypeName, ChartTypeNames.Bubble, StringComparison.OrdinalIgnoreCase) == 0 &&
                    ser.ChartArea == area.Name &&
                    ser.IsVisible())
                {
                    // Check if custom properties are set to specify scale
                    if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMin))
                    {
                        minAll = Math.Min(minAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMin]));
                    }
                    if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMax))
                    {
                        maxAll = Math.Max(maxAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMax]));
                    }

                    // Check if attribute for max. size is set
                    if (ser.IsCustomPropertySet(CustomPropertyName.BubbleMaxSize))
                    {
                        maxPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMaxSize]);
                        if (maxPossibleBubbleSize < 0 || maxPossibleBubbleSize > 100)
                        {
                            throw(new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMaxSize")));
                        }
                    }

                    // Check if custom properties set to use second Y value (bubble size) as label text
                    if (ser.IsCustomPropertySet(CustomPropertyName.BubbleUseSKSizeorLabel) && String.Compare(ser[CustomPropertyName.BubbleUseSKSizeorLabel], "true", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        break;
                    }
                }
            }

            // Scale values are not specified - auto detect
            double minimum = double.MaxValue;
            double maximum = double.MinValue;
            double minSer  = double.MaxValue;
            double maxSer  = double.MinValue;

            foreach (Series ser in common.DataManager.Series)
            {
                if (String.Compare(ser.ChartTypeName, ChartTypeNames.Bubble, StringComparison.OrdinalIgnoreCase) == 0 &&
                    ser.ChartArea == area.Name &&
                    ser.IsVisible())
                {
                    foreach (DataPoint point in ser.Points)
                    {
                        if (!point.IsEmpty)
                        {
                            minSer = Math.Min(minSer, point.YValues[1]);
                            maxSer = Math.Max(maxSer, point.YValues[1]);

                            if (yValue)
                            {
                                minimum = Math.Min(minimum, point.YValues[0]);
                                maximum = Math.Max(maximum, point.YValues[0]);
                            }
                            else
                            {
                                minimum = Math.Min(minimum, point.XValue);
                                maximum = Math.Max(maximum, point.XValue);
                            }
                        }
                    }
                }
            }
            if (minAll == double.MaxValue)
            {
                minAll = minSer;
            }
            if (maxAll == double.MinValue)
            {
                maxAll = maxSer;
            }

            // Calculate maximum bubble size
            maxBubleSize = (float)((maximum - minimum) / (100.0 / maxPossibleBubbleSize));
            minBubleSize = (float)((maximum - minimum) / (100.0 / minPossibleBubbleSize));

            // Calculate scaling variables depending on the Min/Max values
            if (maxAll == minAll)
            {
                valueScale = 1;
                valueDiff  = minAll - (maxBubleSize - minBubleSize) / 2f;
            }
            else
            {
                valueScale = (maxBubleSize - minBubleSize) / (maxAll - minAll);
                valueDiff  = minAll;
            }


            // Check if value do not exceed Min&Max
            if (value > maxAll)
            {
                return(0F);
            }
            if (value < minAll)
            {
                return(0F);
            }

            // Return scaled value
            return((float)((value - valueDiff) * valueScale) + minBubleSize);
        }
Пример #10
0
        /// <summary>
        /// Scales the value used to determine the size of the Bubble.
        /// </summary>
        /// <param name="graph">The Chart Graphics object</param>
        /// <param name="common">The Common elements object</param>
        /// <param name="area">Chart area for this chart</param>
        /// <param name="value">Value to scale.</param>
        /// <returns>Scaled values.</returns>
        private float ScaleBubbleSize(ChartGraphics graph, CommonElements common, ChartArea area, double value)
        {
            // Check if scaling numbers are detected
            if (!_scaleDetected)
            {
                // Try to find bubble size scale in the custom series properties
                _minAll = double.MaxValue;
                _maxAll = double.MinValue;
                foreach (Series ser in common.DataManager.Series)
                {
                    if (String.Compare(ser.ChartTypeName, Name, true, System.Globalization.CultureInfo.CurrentCulture) == 0 &&
                        ser.ChartArea == area.Name &&
                        ser.IsVisible())
                    {
                        // Check if custom properties are set to specify scale
                        if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMin))
                        {
                            _minAll = Math.Min(_minAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMin]));
                        }
                        if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMax))
                        {
                            _maxAll = Math.Max(_maxAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMax]));
                        }

                        // Check if attribute for max. size is set
                        if (ser.IsCustomPropertySet(CustomPropertyName.BubbleMaxSize))
                        {
                            _maxPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMaxSize]);
                            if (_maxPossibleBubbleSize < 0 || _maxPossibleBubbleSize > 100)
                            {
                                throw(new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMaxSize")));
                            }
                        }

                        // Check if attribute for min. size is set
                        if (ser.IsCustomPropertySet(CustomPropertyName.BubbleMinSize))
                        {
                            _minPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMinSize]);
                            if (_minPossibleBubbleSize < 0 || _minPossibleBubbleSize > 100)
                            {
                                throw(new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMinSize")));
                            }
                        }


                        // Check if custom properties set to use second Y value (bubble size) as label text
                        labelYValueIndex = 0;
                        if (ser.IsCustomPropertySet(CustomPropertyName.BubbleUseSKSizeorLabel) && String.Compare(ser[CustomPropertyName.BubbleUseSKSizeorLabel], "true", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            labelYValueIndex = 1;
                            break;
                        }
                    }
                }

                // Scale values are not specified - auto detect
                if (_minAll == double.MaxValue || _maxAll == double.MinValue)
                {
                    double minSer = double.MaxValue;
                    double maxSer = double.MinValue;
                    foreach (Series ser in common.DataManager.Series)
                    {
                        if (ser.ChartTypeName == Name && ser.ChartArea == area.Name && ser.IsVisible())
                        {
                            foreach (DataPoint point in ser.Points)
                            {
                                if (!point.IsEmpty)
                                {
                                    // Check required Y values number
                                    if (point.YValues.Length < YValuesPerPoint)
                                    {
                                        throw (new InvalidOperationException(SR.ExceptionChartTypeRequiresYValues(Name, YValuesPerPoint.ToString(CultureInfo.InvariantCulture))));
                                    }

                                    minSer = Math.Min(minSer, point.YValues[1]);
                                    maxSer = Math.Max(maxSer, point.YValues[1]);
                                }
                            }
                        }
                    }
                    if (_minAll == double.MaxValue)
                    {
                        _minAll = minSer;
                    }
                    if (_maxAll == double.MinValue)
                    {
                        _maxAll = maxSer;
                    }
                }

                // Calculate maximum bubble size
                SKSize areaSize = graph.GetAbsoluteSize(area.PlotAreaPosition.Size);
                _maxBubleSize = (float)(Math.Min(areaSize.Width, areaSize.Height) / (100.0 / _maxPossibleBubbleSize));
                _minBubleSize = (float)(Math.Min(areaSize.Width, areaSize.Height) / (100.0 / _minPossibleBubbleSize));

                // Calculate scaling variables depending on the Min/Max values
                if (_maxAll == _minAll)
                {
                    _valueScale = 1;
                    _valueDiff  = _minAll - (_maxBubleSize - _minBubleSize) / 2f;
                }
                else
                {
                    _valueScale = (_maxBubleSize - _minBubleSize) / (_maxAll - _minAll);
                    _valueDiff  = _minAll;
                }

                _scaleDetected = true;
            }

            // Check if value do not exceed Min&Max
            if (value > _maxAll)
            {
                return(0F);
            }
            if (value < _minAll)
            {
                return(0F);
            }

            // Return scaled value
            return((float)((value - _valueDiff) * _valueScale) + _minBubleSize);
        }
Пример #11
0
 /// <summary>
 /// Adds markers position to the list. Used to check SmartLabelStyle overlapping.
 /// </summary>
 /// <param name="common">Common chart elements.</param>
 /// <param name="area">Chart area.</param>
 /// <param name="series">Series values to be used.</param>
 /// <param name="list">List to add to.</param>
 public void AddSmartLabelMarkerPositions(CommonElements common, ChartArea area, Series series, ArrayList list)
 {
     // Fast Line chart type do not support labels
 }
Пример #12
0
        /// <summary>
        /// Paint FastLine Chart.
        /// </summary>
        /// <param name="graph">The Chart Graphics object.</param>
        /// <param name="common">The Common elements object.</param>
        /// <param name="area">Chart area for this chart.</param>
        /// <param name="seriesToDraw">Chart series to draw.</param>
        virtual public void Paint(
            ChartGraphics graph,
            CommonElements common,
            ChartArea area,
            Series seriesToDraw)
        {
            Common = common;
            Graph  = graph;
            bool clipRegionSet = false;

            if (area.Area3DStyle.Enable3D)
            {
                // Initialize variables
                chartArea3DEnabled = true;
                matrix3D           = area.matrix3D;
            }
            else
            {
                chartArea3DEnabled = false;
            }

            //************************************************************
            //** Loop through all series
            //************************************************************
            foreach (Series series in common.DataManager.Series)
            {
                // Process non empty series of the area with FastLine chart type
                if (string.Compare(series.ChartTypeName, Name, true, System.Globalization.CultureInfo.CurrentCulture) != 0 ||
                    series.ChartArea != area.Name ||
                    !series.IsVisible())
                {
                    continue;
                }

                // Get 3D series depth and Z position
                if (chartArea3DEnabled)
                {
                    area.GetSeriesZPositionAndDepth(series, out float seriesDepth, out seriesZCoordinate);
                    seriesZCoordinate += seriesDepth / 2.0f;
                }

                // Set active horizontal/vertical axis
                Axis   hAxis    = area.GetAxis(AxisName.X, series.XAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : Series.XSubAxisName);
                Axis   vAxis    = area.GetAxis(AxisName.Y, series.YAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : Series.YSubAxisName);
                double hAxisMin = hAxis.ViewMinimum;
                double hAxisMax = hAxis.ViewMaximum;
                double vAxisMin = vAxis.ViewMinimum;
                double vAxisMax = vAxis.ViewMaximum;

                // Get "PermittedPixelError" attribute
                float permittedPixelError = 1.0f;
                if (series.IsCustomPropertySet(CustomPropertyName.PermittedPixelError))
                {
                    string attrValue = series[CustomPropertyName.PermittedPixelError];

                    bool parseSucceed = float.TryParse(attrValue, NumberStyles.Any, CultureInfo.CurrentCulture, out float pixelError);

                    if (parseSucceed)
                    {
                        permittedPixelError = pixelError;
                    }
                    else
                    {
                        throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PermittedPixelError")));
                    }

                    // "PermittedPixelError" attribute value should be in range from zero to 1
                    if (permittedPixelError < 0f || permittedPixelError > 1f)
                    {
                        throw (new InvalidOperationException(SR.ExceptionCustomAttributeIsNotInRange0to1("PermittedPixelError")));
                    }
                }

                // Get pixel size in axes coordinates
                SKSize pixelSize            = graph.GetRelativeSize(new SKSize(permittedPixelError, permittedPixelError));
                SKSize axesMin              = graph.GetRelativeSize(new SKSize((float)hAxisMin, (float)vAxisMin));
                double axesValuesPixelSizeX = Math.Abs(hAxis.PositionToValue(axesMin.Width + pixelSize.Width, false) - hAxis.PositionToValue(axesMin.Width, false));

                // Create line pen
                SKPaint linePen = new() { Color = series.Color, StrokeWidth = series.BorderWidth };
                linePen.PathEffect = ChartGraphics.GetPenStyle(series.BorderDashStyle, series.BorderWidth);
                linePen.StrokeCap  = SKStrokeCap.Round;

                // Create empty line pen
                SKPaint emptyLinePen = new() { Style = SKPaintStyle.Stroke, Color = series.EmptyPointStyle.Color, StrokeWidth = series.EmptyPointStyle.BorderWidth };
                emptyLinePen.PathEffect = ChartGraphics.GetPenStyle(series.EmptyPointStyle.BorderDashStyle, series.EmptyPointStyle.BorderWidth);
                emptyLinePen.StrokeCap  = SKStrokeCap.Round;

                // Check if series is indexed
                bool indexedSeries = ChartHelper.IndexedSeries(Common, series.Name);

                // Loop through all ponts in the series
                int       index                      = 0;
                double    yValueRangeMin             = double.NaN;
                double    yValueRangeMax             = double.NaN;
                DataPoint pointRangeMin              = null;
                DataPoint pointRangeMax              = null;
                double    xValue                     = 0;
                double    yValue                     = 0;
                double    xValuePrev                 = 0;
                double    yValuePrev                 = 0;
                DataPoint prevDataPoint              = null;
                SKPoint   lastVerticalSegmentPoint   = SKPoint.Empty;
                SKPoint   prevPoint                  = SKPoint.Empty;
                SKPoint   currentPoint               = SKPoint.Empty;
                bool      prevPointInAxesCoordinates = false;
                bool      verticalLineDetected       = false;
                bool      prevPointIsEmpty           = false;
                bool      currentPointIsEmpty        = false;
                bool      firstNonEmptyPoint         = false;
                double    xPixelConverter            = (graph.Common.ChartPicture.Width - 1.0) / 100.0;
                double    yPixelConverter            = (graph.Common.ChartPicture.Height - 1.0) / 100.0;
                foreach (DataPoint point in series.Points)
                {
                    // Get point X and Y values
                    xValue = (indexedSeries) ? index + 1 : point.XValue;
                    xValue = hAxis.GetLogValue(xValue);
                    yValue = vAxis.GetLogValue(point.YValues[0]);
                    currentPointIsEmpty = point.IsEmpty;

                    // NOTE: Fixes issue #7094
                    // If current point is non-empty but the previous one was,
                    // use empty point style properties to draw it.
                    if (prevPointIsEmpty && !currentPointIsEmpty && !firstNonEmptyPoint)
                    {
                        firstNonEmptyPoint  = true;
                        currentPointIsEmpty = true;
                    }
                    else
                    {
                        firstNonEmptyPoint = false;
                    }

                    // Check if line is completly out of the data scaleView
                    if (!verticalLineDetected &&
                        ((xValue < hAxisMin && xValuePrev < hAxisMin) ||
                         (xValue > hAxisMax && xValuePrev > hAxisMax) ||
                         (yValue < vAxisMin && yValuePrev < vAxisMin) ||
                         (yValue > vAxisMax && yValuePrev > vAxisMax)))
                    {
                        xValuePrev = xValue;
                        yValuePrev = yValue;
                        prevPointInAxesCoordinates = true;
                        ++index;
                        continue;
                    }
                    else if (!clipRegionSet && (xValuePrev < hAxisMin || xValuePrev > hAxisMax ||
                                                xValue > hAxisMax || xValue < hAxisMin ||
                                                yValuePrev < vAxisMin || yValuePrev > vAxisMax ||
                                                yValue < vAxisMin || yValue > vAxisMax))
                    {
                        // Set clipping region for line drawing
                        graph.SetClip(area.PlotAreaPosition.ToSKRect());
                        clipRegionSet = true;
                    }

                    // Check if point may be skipped
                    // Check if points X value in acceptable error boundary
                    if (index > 0 &&
                        currentPointIsEmpty == prevPointIsEmpty && Math.Abs(xValue - xValuePrev) < axesValuesPixelSizeX)
                    {
                        if (!verticalLineDetected)
                        {
                            verticalLineDetected = true;
                            if (yValue > yValuePrev)
                            {
                                yValueRangeMax = yValue;
                                yValueRangeMin = yValuePrev;
                                pointRangeMax  = point;
                                pointRangeMin  = prevDataPoint;
                            }
                            else
                            {
                                yValueRangeMax = yValuePrev;
                                yValueRangeMin = yValue;
                                pointRangeMax  = prevDataPoint;
                                pointRangeMin  = point;
                            }
                        }
                        else
                        {
                            if (yValue > yValueRangeMax)
                            {
                                yValueRangeMax = yValue;
                                pointRangeMax  = point;
                            }
                            else if (yValue < yValueRangeMin)
                            {
                                yValueRangeMin = yValue;
                                pointRangeMin  = point;
                            }
                        }

                        // Remember last point
                        prevDataPoint = point;

                        // Remember last vertical range point
                        // Note! Point is in axes coordinate.
                        lastVerticalSegmentPoint.Y = (float)yValue;

                        // Increase counter and proceed to next data point
                        ++index;
                        continue;
                    }

                    // Get point pixel position
                    currentPoint.X = (float)
                                     (hAxis.GetLinearPosition(xValue) * xPixelConverter);
                    currentPoint.Y = (float)
                                     (vAxis.GetLinearPosition(yValue) * yPixelConverter);

                    // Check if previous point must be converted from axes values to pixels
                    if (prevPointInAxesCoordinates)
                    {
                        prevPoint.X = (float)
                                      (hAxis.GetLinearPosition(xValuePrev) * xPixelConverter);
                        prevPoint.Y = (float)
                                      (vAxis.GetLinearPosition(yValuePrev) * yPixelConverter);
                    }

                    // Draw accumulated vertical line (with minimal X values differences)
                    if (verticalLineDetected)
                    {
                        // Convert Y coordinates to pixels
                        yValueRangeMin = (vAxis.GetLinearPosition(yValueRangeMin) * yPixelConverter);
                        yValueRangeMax = (vAxis.GetLinearPosition(yValueRangeMax) * yPixelConverter);

                        // Draw accumulated vertical line
                        DrawLine(
                            series,
                            prevDataPoint,
                            pointRangeMin,
                            pointRangeMax,
                            index,
                            (prevPointIsEmpty) ? emptyLinePen : linePen,
                            prevPoint.X,
                            (float)yValueRangeMin,
                            prevPoint.X,
                            (float)yValueRangeMax);

                        // Reset vertical line detected flag
                        verticalLineDetected = false;

                        // Convert last point of the vertical line segment to pixel coordinates
                        prevPoint.Y = (float)
                                      (vAxis.GetLinearPosition(lastVerticalSegmentPoint.Y) * yPixelConverter);
                    }

                    // Draw line from previous to current point
                    if (index > 0)
                    {
                        DrawLine(
                            series,
                            point,
                            pointRangeMin,
                            pointRangeMax,
                            index,
                            (currentPointIsEmpty) ? emptyLinePen : linePen,
                            prevPoint.X,
                            prevPoint.Y,
                            currentPoint.X,
                            currentPoint.Y);
                    }

                    // Remember last point coordinates
                    xValuePrev    = xValue;
                    yValuePrev    = yValue;
                    prevDataPoint = point;
                    prevPoint     = currentPoint;
                    prevPointInAxesCoordinates = false;
                    prevPointIsEmpty           = currentPointIsEmpty;
                    ++index;
                }

                // Draw last accumulated line segment
                if (verticalLineDetected)
                {
                    // Check if previous point must be converted from axes values to pixels
                    if (prevPointInAxesCoordinates)
                    {
                        prevPoint.X = (float)
                                      (hAxis.GetLinearPosition(xValuePrev) * xPixelConverter);
                        prevPoint.Y = (float)
                                      (vAxis.GetLinearPosition(yValuePrev) * yPixelConverter);
                    }

                    // Convert Y coordinates to pixels
                    yValueRangeMin = (vAxis.GetLinearPosition(yValueRangeMin) * yPixelConverter);
                    yValueRangeMax = (vAxis.GetLinearPosition(yValueRangeMax) * yPixelConverter);

                    // Draw accumulated vertical line
                    DrawLine(
                        series,
                        prevDataPoint,
                        pointRangeMin,
                        pointRangeMax,
                        index - 1,
                        prevPointIsEmpty ? emptyLinePen : linePen,
                        prevPoint.X,
                        (float)yValueRangeMin,
                        prevPoint.X,
                        (float)yValueRangeMax);
                }
            }

            // Reset Clip Region
            if (clipRegionSet)
            {
                graph.ResetClip();
            }
        }
Пример #13
0
        /// <summary>
        /// Paint FastPoint Chart.
        /// </summary>
        /// <param name="graph">The Chart Graphics object.</param>
        /// <param name="common">The Common elements object.</param>
        /// <param name="area">Chart area for this chart.</param>
        /// <param name="seriesToDraw">Chart series to draw.</param>
        virtual public void Paint(
            ChartGraphics graph,
            CommonElements common,
            ChartArea area,
            Series seriesToDraw)
        {
            Common = common;
            Graph  = graph;
            if (area.Area3DStyle.Enable3D)
            {
                // Initialize variables
                chartArea3DEnabled = true;
                matrix3D           = area.matrix3D;
            }
            else
            {
                chartArea3DEnabled = false;
            }

            //************************************************************
            //** Loop through all series
            //************************************************************
            foreach (Series series in common.DataManager.Series)
            {
                // Process non empty series of the area with FastPoint chart type
                if (String.Compare(series.ChartTypeName, Name, true, System.Globalization.CultureInfo.CurrentCulture) != 0 ||
                    series.ChartArea != area.Name ||
                    !series.IsVisible())
                {
                    continue;
                }

                // Get 3D series depth and Z position
                if (chartArea3DEnabled)
                {
                    area.GetSeriesZPositionAndDepth(series, out float seriesDepth, out seriesZCoordinate);
                    seriesZCoordinate += seriesDepth / 2.0f;
                }

                // Set active horizontal/vertical axis
                Axis   hAxis    = area.GetAxis(AxisName.X, series.XAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : Series.XSubAxisName);
                Axis   vAxis    = area.GetAxis(AxisName.Y, series.YAxisType, (area.Area3DStyle.Enable3D) ? string.Empty : Series.YSubAxisName);
                double hAxisMin = hAxis.ViewMinimum;
                double hAxisMax = hAxis.ViewMaximum;
                double vAxisMin = vAxis.ViewMinimum;
                double vAxisMax = vAxis.ViewMaximum;

                // Get "PermittedPixelError" attribute.
                // By default use 1/3 of the marker size.
                float permittedPixelError = series.MarkerSize / 3f;
                if (series.IsCustomPropertySet(CustomPropertyName.PermittedPixelError))
                {
                    string attrValue = series[CustomPropertyName.PermittedPixelError];

                    bool parseSucceed = float.TryParse(attrValue, NumberStyles.Any, CultureInfo.CurrentCulture, out float pixelError);

                    if (parseSucceed)
                    {
                        permittedPixelError = pixelError;
                    }
                    else
                    {
                        throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid2("PermittedPixelError")));
                    }

                    // "PermittedPixelError" attribute value should be in range from zero to 1
                    if (permittedPixelError < 0f || permittedPixelError > 1f)
                    {
                        throw (new InvalidOperationException(SR.ExceptionCustomAttributeIsNotInRange0to1("PermittedPixelError")));
                    }
                }

                // Get pixel size in axes coordinates
                SKSize pixelSize            = graph.GetRelativeSize(new SKSize(permittedPixelError, permittedPixelError));
                SKSize axesMin              = graph.GetRelativeSize(new SKSize((float)hAxisMin, (float)vAxisMin));
                double axesValuesPixelSizeX = Math.Abs(hAxis.PositionToValue(axesMin.Width + pixelSize.Width, false) - hAxis.PositionToValue(axesMin.Width, false));
                double axesValuesPixelSizeY = Math.Abs(vAxis.PositionToValue(axesMin.Height + pixelSize.Height, false) - vAxis.PositionToValue(axesMin.Height, false));

                // Create point marker brush
                SKPaint markerBrush      = new() { Color = (series.MarkerColor == SKColor.Empty) ? series.Color : series.MarkerColor, Style = SKPaintStyle.Fill };
                SKPaint emptyMarkerBrush = new() { Color = (series.EmptyPointStyle.MarkerColor == SKColor.Empty) ? series.EmptyPointStyle.Color : series.EmptyPointStyle.MarkerColor, Style = SKPaintStyle.Fill };

                // Create point marker border pen
                SKPaint borderPen      = null;
                SKPaint emptyBorderPen = null;
                if (series.MarkerBorderColor != SKColor.Empty && series.MarkerBorderWidth > 0)
                {
                    borderPen = new SKPaint()
                    {
                        Style = SKPaintStyle.Stroke, Color = series.MarkerBorderColor, StrokeWidth = series.MarkerBorderWidth
                    };
                }
                if (series.EmptyPointStyle.MarkerBorderColor != SKColor.Empty && series.EmptyPointStyle.MarkerBorderWidth > 0)
                {
                    emptyBorderPen = new SKPaint()
                    {
                        Style = SKPaintStyle.Stroke, Color = series.EmptyPointStyle.MarkerBorderColor, StrokeWidth = series.EmptyPointStyle.MarkerBorderWidth
                    };
                }

                // Check if series is indexed
                bool indexedSeries = ChartHelper.IndexedSeries(Common, series.Name);

                // Get marker size taking in consideration current DPIs
                int markerSize = series.MarkerSize;
                if (graph != null && graph.Graphics != null)
                {
                    // Marker size is in pixels and we do the mapping for higher DPIs
                    markerSize = Math.Max(markerSize, markerSize);
                }

                // Loop through all ponts in the series
                int         index            = 0;
                double      xValuePrev       = 0.0;
                double      yValuePrev       = 0.0;
                SKPoint     currentPoint     = SKPoint.Empty;
                double      xPixelConverter  = (graph.Common.ChartPicture.Width - 1.0) / 100.0;
                double      yPixelConverter  = (graph.Common.ChartPicture.Height - 1.0) / 100.0;
                MarkerStyle markerStyle      = series.MarkerStyle;
                MarkerStyle emptyMarkerStyle = series.EmptyPointStyle.MarkerStyle;
                foreach (DataPoint point in series.Points)
                {
                    // Get point X and Y values
                    double xValue = (indexedSeries) ? index + 1 : point.XValue;
                    xValue = hAxis.GetLogValue(xValue);
                    double yValue = vAxis.GetLogValue(point.YValues[0]);
                    bool   currentPointIsEmpty = point.IsEmpty;

                    // Check if point is completly out of the data scaleView
                    if (xValue < hAxisMin ||
                        xValue > hAxisMax ||
                        yValue < vAxisMin ||
                        yValue > vAxisMax)
                    {
                        xValuePrev = xValue;
                        yValuePrev = yValue;
                        ++index;
                        continue;
                    }

                    // Check if point may be skipped
                    if (index > 0 && Math.Abs(xValue - xValuePrev) < axesValuesPixelSizeX &&
                        Math.Abs(yValue - yValuePrev) < axesValuesPixelSizeY)
                    {
                        // Increase counter and proceed to the next data point
                        ++index;
                        continue;
                    }

                    // Get point pixel position
                    currentPoint.X = (float)
                                     (hAxis.GetLinearPosition(xValue) * xPixelConverter);
                    currentPoint.Y = (float)
                                     (vAxis.GetLinearPosition(yValue) * yPixelConverter);

                    // Draw point marker
                    MarkerStyle currentMarkerStyle = (currentPointIsEmpty) ? emptyMarkerStyle : markerStyle;
                    if (currentMarkerStyle != MarkerStyle.None)
                    {
                        this.DrawMarker(
                            graph,
                            point,
                            index,
                            currentPoint,
                            currentMarkerStyle,
                            markerSize,
                            (currentPointIsEmpty) ? emptyMarkerBrush : markerBrush,
                            (currentPointIsEmpty) ? emptyBorderPen : borderPen);
                    }

                    // Remember last point coordinates
                    xValuePrev = xValue;
                    yValuePrev = yValue;
                    ++index;
                }

                // Dispose used brushes and pens
                markerBrush.Dispose();
                emptyMarkerBrush.Dispose();
                if (borderPen != null)
                {
                    borderPen.Dispose();
                }
                if (emptyBorderPen != null)
                {
                    emptyBorderPen.Dispose();
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Draw chart line using horisontal and vertical lines.
        /// </summary>
        /// <param name="graph">Graphics object.</param>
        /// <param name="common">The Common elements object</param>
        /// <param name="point">Point to draw the line for.</param>
        /// <param name="series">Point series.</param>
        /// <param name="points">Array of points coordinates.</param>
        /// <param name="pointIndex">Index of point to draw.</param>
        /// <param name="tension">Line tension</param>
        override protected void DrawLine(
            ChartGraphics graph,
            CommonElements common,
            DataPoint point,
            Series series,
            SKPoint[] points,
            int pointIndex,
            float tension)
        {
            // Start drawing from the second point
            if (pointIndex <= 0)
            {
                return;
            }

            // Darw two lines
            SKPoint point1 = points[pointIndex - 1];
            SKPoint point2 = new(points[pointIndex].X, points[pointIndex - 1].Y);
            SKPoint point3 = points[pointIndex];

            graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(point1), graph.GetRelativePoint(point2), series.ShadowColor, series.ShadowOffset);
            graph.DrawLineRel(point.Color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(point2), graph.GetRelativePoint(point3), series.ShadowColor, series.ShadowOffset);

            if (common.ProcessModeRegions)
            {
                // Create grapics path object for the line
                // Split line into 2 segments.
                SKPath path = new();
                try
                {
                    path.AddLine(point2, point3);
                    if (!point2.Equals(point3))
                    {
                        // path.Widen(new Pen(point.Color, point.BorderWidth + 2));
                    }
                }
                catch (OutOfMemoryException)
                {
                    // SKPath.Widen incorrectly throws OutOfMemoryException
                    // catching here and reacting by not widening
                }
                catch (ArgumentException)
                {
                    // Ignore
                }

                float[]   coord      = new float[path.PointCount * 2];
                SKPoint[] pathPoints = path.Points;

                // Allocate array of floats
                SKPoint pointNew;
                for (int i = 0; i < path.PointCount; i++)
                {
                    pointNew         = graph.GetRelativePoint(pathPoints[i]);
                    coord[2 * i]     = pointNew.X;
                    coord[2 * i + 1] = pointNew.Y;
                }

                common.HotRegionsList.AddHotRegion(
                    path,
                    false,
                    coord,
                    point,
                    series.Name,
                    pointIndex);
                path.Dispose();
                // Create grapics path object for the line
                path = new SKPath();
                try
                {
                    path.AddLine(point1, point2);
                    //path.Widen(new Pen(point.Color, point.BorderWidth + 2));
                }
                catch (OutOfMemoryException)
                {
                    // SKPath.Widen incorrectly throws OutOfMemoryException
                    // catching here and reacting by not widening
                }
                catch (ArgumentException)
                {
                    // Ignore
                }

                // Allocate array of floats
                coord      = new float[path.PointCount * 2];
                pathPoints = path.Points;
                for (int i = 0; i < path.PointCount; i++)
                {
                    pointNew         = graph.GetRelativePoint(pathPoints[i]);
                    coord[2 * i]     = pointNew.X;
                    coord[2 * i + 1] = pointNew.Y;
                }

                common.HotRegionsList.AddHotRegion(
                    path,
                    false,
                    coord,
                    series.Points[pointIndex - 1],
                    series.Name,
                    pointIndex - 1);
                path.Dispose();
            }
        }
Пример #15
0
 public ImageLoader(CommonElements common)
 {
     _common = common;
 }