Пример #1
0
        /// <summary>
        /// Draws 3D border.
        /// </summary>
        /// <param name="graph">Graphics to draw the border on.</param>
        /// <param name="borderSkin">Border skin object.</param>
        /// <param name="rect">Rectangle of the border.</param>
        /// <param name="backColor">Color of rectangle</param>
        /// <param name="backHatchStyle">Hatch style</param>
        /// <param name="backImage">Back Image</param>
        /// <param name="backImageWrapMode">Image mode</param>
        /// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
        /// <param name="backGradientStyle">Gradient type</param>
        /// <param name="backSecondaryColor">Gradient End Color</param>
        /// <param name="borderColor">Border Color</param>
        /// <param name="borderWidth">Border Width</param>
        /// <param name="borderDashStyle">Border Style</param>
        public virtual void DrawBorder(
            ChartGraphics graph,
            BorderSkin borderSkin,
            SKRect rect,
            SKColor backColor,
            ChartHatchStyle backHatchStyle,
            string backImage,
            ChartImageWrapMode backImageWrapMode,
            SKColor backImageTransparentColor,
            ChartImageAlignmentStyle backImageAlign,
            GradientStyle backGradientStyle,
            SKColor backSecondaryColor,
            SKColor borderColor,
            int borderWidth,
            ChartDashStyle borderDashStyle)
        {
            SKRect absolute = ChartGraphics.Round(rect);

            // Calculate shadow colors (0.2 - 0.6)
            float   colorDarkeningIndex = 0.2f + (0.4f * (borderSkin.PageColor.Red + borderSkin.PageColor.Green + borderSkin.PageColor.Blue) / 765f);
            SKColor shadowColor         = new(
                (byte)(borderSkin.PageColor.Red * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Green * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Blue * colorDarkeningIndex));

            if (borderSkin.PageColor == SKColors.Transparent)
            {
                shadowColor = new(0, 0, 0, 60);
            }

            colorDarkeningIndex += 0.2f;
            SKColor shadowLightColor = new(
                (byte)(borderSkin.PageColor.Red * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Green * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Blue * colorDarkeningIndex));

            // Calculate rounded rect radius
            float radius = defaultRadiusSize;

            radius = Math.Max(radius, 2f * resolution / 96.0f);
            radius = Math.Min(radius, rect.Width / 2f);
            radius = Math.Min(radius, rect.Height / 2f);
            radius = (float)Math.Ceiling(radius);

            // Fill page background color
            using (SKPaint brush = new() { Style = SKPaintStyle.Fill, Color = borderSkin.PageColor })
            {
                graph.FillRectangle(brush, rect);
            }

            // Top/Left shadow
            SKRect shadowRect = absolute;

            shadowRect.Right  -= radius * .3f;
            shadowRect.Bottom -= radius * .3f;
            graph.DrawRoundedRectShadowAbs(shadowRect, cornerRadius, radius + 1 * resolution / 96.0f, shadowLightColor, borderSkin.PageColor, 1.4f);

            // Bottom/Right shadow
            shadowRect         = absolute;
            shadowRect.Left    = absolute.Left + radius / 3f;
            shadowRect.Top     = absolute.Top + radius / 3f;
            shadowRect.Right  -= radius / 3.5f;
            shadowRect.Bottom -= radius / 3.5f;
            graph.DrawRoundedRectShadowAbs(shadowRect, cornerRadius, radius, shadowColor, borderSkin.PageColor, 1.3f);

            // Draw Background
            shadowRect         = absolute;
            shadowRect.Left    = absolute.Left + 3f * resolution / 96.0f;
            shadowRect.Top     = absolute.Top + 3f * resolution / 96.0f;
            shadowRect.Right  -= radius * .75f;
            shadowRect.Bottom -= radius * .75f;
            SKPath path = ChartGraphics.CreateRoundedRectPath(shadowRect, cornerRadius);

            graph.DrawPathAbs(
                path,
                backColor,
                backHatchStyle,
                backImage,
                backImageWrapMode,
                backImageTransparentColor,
                backImageAlign,
                backGradientStyle,
                backSecondaryColor,
                borderColor,
                borderWidth,
                borderDashStyle,
                PenAlignment.Inset);

            // Dispose Graphic path
            if (path != null)
            {
                path.Dispose();
            }

            // Bottom/Right inner shadow
            SKRegion innerShadowRegion = new(
                ChartGraphics.CreateRoundedRectPath(
                    new SKRect(
                        shadowRect.Left - radius,
                        shadowRect.Top - radius,
                        shadowRect.Width + radius - radius * 0.25f,
                        shadowRect.Height + radius - radius * 0.25f),
                    cornerRadius));

            innerShadowRegion.Op(ChartGraphics.CreateRoundedRectPath(shadowRect, cornerRadius), SKRegionOperation.Difference);
            graph.Clip = innerShadowRegion;
            graph.DrawRoundedRectShadowAbs(
                shadowRect,
                cornerRadius,
                radius,
                SKColors.Transparent,
                new(SKColors.Gray.Red, SKColors.Gray.Green, SKColors.Gray.Blue, 128),
                .5f);
            graph.Clip = new();
        }
Пример #2
0
        /// <summary>
        /// Paints annotation object on specified graphics.
        /// </summary>
        /// <param name="graphics">
        /// A <see cref="ChartGraphics"/> used to paint annotation object.
        /// </param>
        /// <param name="chart">
        /// Reference to the <see cref="ChartService"/> control.
        /// </param>
        override internal void Paint(ChartService chart, ChartGraphics graphics)
        {
            // Get annotation position in relative coordinates
            GetRelativePosition(out SKPoint firstPoint, out SKSize size, out _);
            SKPoint secondPoint = new(firstPoint.X + size.Width, firstPoint.Y + size.Height);

            // Create selection rectangle
            SKRect selectionRect = new(firstPoint.X, firstPoint.Y, secondPoint.X, secondPoint.Y);

            // Check if text position is valid
            if (float.IsNaN(firstPoint.X) ||
                float.IsNaN(firstPoint.Y) ||
                float.IsNaN(secondPoint.X) ||
                float.IsNaN(secondPoint.Y))
            {
                return;
            }

            // Get arrow shape path
            using SKPath arrowPathAbs = GetArrowPath(graphics, selectionRect);

            // Draw arrow shape
            if (Common.ProcessModePaint)
            {
                graphics.DrawPathAbs(
                    arrowPathAbs,
                    (BackColor == SKColor.Empty) ? SKColors.White : BackColor,
                    BackHatchStyle,
                    String.Empty,
                    ChartImageWrapMode.Scaled,
                    SKColor.Empty,
                    ChartImageAlignmentStyle.Center,
                    BackGradientStyle,
                    BackSecondaryColor,
                    LineColor,
                    LineWidth,
                    LineDashStyle,
                    PenAlignment.Center,
                    ShadowOffset,
                    ShadowColor);
            }

            // Process hot region
            if (Common.ProcessModeRegions)
            {
                // Use callout defined hot region
                Common.HotRegionsList.AddHotRegion(
                    graphics,
                    arrowPathAbs,
                    false,
                    ReplaceKeywords(ToolTip),
                    String.Empty,
                    String.Empty,
                    String.Empty,
                    this,
                    ChartElementType.Annotation);
            }

            // Paint selection handles
            PaintSelectionHandles(graphics, selectionRect, null);
        }
Пример #3
0
        /// <summary>
        /// Get arrow path for the specified annotation position
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        private SKPath GetArrowPath(
            ChartGraphics graphics,
            SKRect position)
        {
            // Get absolute position
            SKRect  positionAbs = graphics.GetAbsoluteRectangle(position);
            SKPoint firstPoint  = positionAbs.Location;
            SKPoint secondPoint = new(positionAbs.Right, positionAbs.Bottom);

            // Calculate arrow length
            float deltaX      = secondPoint.X - firstPoint.X;
            float deltaY      = secondPoint.Y - firstPoint.Y;
            float arrowLength = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            // Create unrotated graphics path for the arrow started at the annotation location
            // and going to the right for the length of the rotated arrow.
            SKPath path         = new();
            float  pointerRatio = 2.1f;

            SKPoint[] points;
            if (ArrowStyle == ArrowStyle.Simple)
            {
                points = new SKPoint[] {
                    firstPoint,
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize * pointerRatio),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize),
                    new SKPoint(firstPoint.X + arrowLength, firstPoint.Y - ArrowSize),
                    new SKPoint(firstPoint.X + arrowLength, firstPoint.Y + ArrowSize),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize * pointerRatio)
                };
            }
            else if (ArrowStyle == ArrowStyle.DoubleArrow)
            {
                points = new SKPoint[] {
                    firstPoint,
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize * pointerRatio),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize),
                    new SKPoint(firstPoint.X + arrowLength - ArrowSize * pointerRatio, firstPoint.Y - ArrowSize),
                    new SKPoint(firstPoint.X + arrowLength - ArrowSize * pointerRatio, firstPoint.Y - ArrowSize * pointerRatio),
                    new SKPoint(firstPoint.X + arrowLength, firstPoint.Y),
                    new SKPoint(firstPoint.X + arrowLength - ArrowSize * pointerRatio, firstPoint.Y + ArrowSize * pointerRatio),
                    new SKPoint(firstPoint.X + arrowLength - ArrowSize * pointerRatio, firstPoint.Y + ArrowSize),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize * pointerRatio)
                };
            }
            else if (ArrowStyle == ArrowStyle.Tailed)
            {
                float tailRatio = 2.1f;
                points = new SKPoint[] {
                    firstPoint,
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize * pointerRatio),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y - ArrowSize),
                    new SKPoint(firstPoint.X + arrowLength, firstPoint.Y - ArrowSize * tailRatio),
                    new SKPoint(firstPoint.X + arrowLength - ArrowSize * tailRatio, firstPoint.Y),
                    new SKPoint(firstPoint.X + arrowLength, firstPoint.Y + ArrowSize * tailRatio),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize),
                    new SKPoint(firstPoint.X + ArrowSize * pointerRatio, firstPoint.Y + ArrowSize * pointerRatio)
                };
            }
            else
            {
                throw (new InvalidOperationException(SR.ExceptionAnnotationArrowStyleUnknown));
            }

            path.AddLines(points);
            path.Close();

            // Calculate arrow angle
            float angle = (float)(Math.Atan(deltaY / deltaX) * 180f / Math.PI);

            if (deltaX < 0)
            {
                angle += 180f;
            }

            // Rotate arrow path around the first point
            SKMatrix matrix = SKMatrix.CreateRotationDegrees(angle, firstPoint.X, firstPoint.Y);

            path.Transform(matrix);

            return(path);
        }
Пример #4
0
        /// <summary>
        /// Return intensity of lightStyle for Polygons. There are tree types of lights: None,
        /// Simplistic and Realistic. None Style have same lightStyle intensity on
        /// all polygons. Normal vector doesn’t have influence on this type
        /// of lighting. Simplistic style have lightStyle source, which is
        /// rotated together with scene. Realistic lighting have fixed lightStyle
        /// source and intensity of lightStyle is change when scene is rotated.
        /// </summary>
        /// <param name="points">Points of the polygon</param>
        /// <param name="surfaceColor">Color used for polygons without lighting</param>
        /// <param name="visiblePolygon">This flag gets information if  polygon is visible or not.</param>
        /// <param name="rotation">Y angle ( from -90 to 90 ) Should be used width switchSeriesOrder to get from -180 to 180</param>
        /// <param name="surfaceName">Used for lighting of front - back and left - right sides</param>
        /// <param name="switchSeriesOrder">Used to calculate real y angle</param>
        /// <returns>Color corrected with intensity of lightStyle</returns>
        internal SKColor GetPolygonLight(Point3D[] points, SKColor surfaceColor, bool visiblePolygon, float rotation, SurfaceNames surfaceName, bool switchSeriesOrder)
        {
            // Corrected color
            SKColor color = surfaceColor;

            // Direction of lightStyle source
            Point3D lightSource;

            lightSource = new Point3D(0F, 0F, 1F);

            // There are tree different lightStyle styles: None, Simplistic and realistic.
            switch (_lightStyle)
            {
            // LightStyle style is None
            case LightStyle.None:
            {
                // Use same color
                break;
            }

            // LightStyle style is Simplistic
            case LightStyle.Simplistic:
            {
                // Find two vectors of polygon
                Point3D firstVector = new();
                firstVector.X = points[0].X - points[1].X;
                firstVector.Y = points[0].Y - points[1].Y;
                firstVector.Z = points[0].Z - points[1].Z;

                Point3D secondVector = new();
                secondVector.X = points[2].X - points[1].X;
                secondVector.Y = points[2].Y - points[1].Y;
                secondVector.Z = points[2].Z - points[1].Z;

                // Find Normal vector for Polygon
                Point3D normalVector = new();
                normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y;
                normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z;
                normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X;

                // Polygon is left side ( like side of area chart )
                if (surfaceName == SurfaceNames.Left)
                {
                    color = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.15);
                }
                // Polygon is right side ( like side of area chart )
                else if (surfaceName == SurfaceNames.Right)
                {
                    color = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.15);
                }
                // Polygon is front side ( like side of area chart )
                else if (surfaceName == SurfaceNames.Front)
                {
                    color = surfaceColor;
                }
                // Polygon is back side ( like side of area chart )
                else if (surfaceName == SurfaceNames.Back)
                {
                    color = surfaceColor;
                }
                // Polygon has angle with bottom side ( Line chart or top of area chart )
                else
                {
                    float angleLeft;
                    float angleRight;

                    // Find angles between lightStyle and polygon for different y-axis angles.
                    if (switchSeriesOrder)
                    {
                        if (rotation > 0 && rotation <= 90)
                        {
                            angleLeft  = GetAngle(normalVector, _lightVectors[3]);
                            angleRight = GetAngle(normalVector, _lightVectors[4]);
                        }
                        else
                        {
                            angleLeft  = GetAngle(normalVector, _lightVectors[4]);
                            angleRight = GetAngle(normalVector, _lightVectors[3]);
                        }
                    }
                    else
                    {
                        if (rotation > 0 && rotation <= 90)
                        {
                            angleLeft  = GetAngle(normalVector, _lightVectors[4]);
                            angleRight = GetAngle(normalVector, _lightVectors[3]);
                        }
                        else
                        {
                            angleLeft  = GetAngle(normalVector, _lightVectors[3]);
                            angleRight = GetAngle(normalVector, _lightVectors[4]);
                        }
                    }

                    if (Math.Abs(angleLeft - angleRight) < 0.01)
                    {
                        color = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.25);
                    }
                    else if (angleLeft < angleRight)
                    {
                        color = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.25);
                    }
                    else
                    {
                        color = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.15);
                    }
                }

                break;
            }

            // LightStyle style is Realistic
            default:
            {
                // Find two vectors of polygon
                Point3D firstVector = new();
                firstVector.X = points[0].X - points[1].X;
                firstVector.Y = points[0].Y - points[1].Y;
                firstVector.Z = points[0].Z - points[1].Z;

                Point3D secondVector = new();
                secondVector.X = points[2].X - points[1].X;
                secondVector.Y = points[2].Y - points[1].Y;
                secondVector.Z = points[2].Z - points[1].Z;

                // Find Normal vector for Polygon
                Point3D normalVector = new();
                normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y;
                normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z;
                normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X;

                // ******************************************************************
                // Color correction. Angle between Normal vector of polygon and
                // vector of lightStyle source is used.
                // ******************************************************************
                if (surfaceName == SurfaceNames.Front)
                {
                    lightSource.Z *= -1;
                    color          = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI);
                }
                else if (surfaceName == SurfaceNames.Back)
                {
                    lightSource.Z *= -1;
                    color          = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI);
                }
                else
                {
                    if (visiblePolygon)
                    {
                        lightSource.Z *= -1;
                    }

                    color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, normalVector) / Math.PI);
                }

                break;
            }
            }
            return(color);
        }
Пример #5
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);
        }
Пример #6
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();
            }
        }
Пример #7
0
        /// <summary>
        /// Return intensity of lightStyle for 3D Cube. There are tree types of lights: None,
        /// Simplistic and Realistic. None Style have same lightStyle intensity on
        /// all polygons. Normal vector doesn’t have influence on this type
        /// of lighting. Simplistic style have lightStyle source, which is
        /// rotated together with scene. Realistic lighting have fixed lightStyle
        /// source and intensity of lightStyle is change when scene is rotated.
        /// </summary>
        /// <param name="surfaceColor">Color used for polygons without lighting</param>
        /// <param name="front">Color corrected with intensity of lightStyle for Front side of the 3D Rectangle</param>
        /// <param name="back">Color corrected with intensity of lightStyle for Back side of the 3D Rectangle</param>
        /// <param name="left">Color corrected with intensity of lightStyle for Left side of the 3D Rectangle</param>
        /// <param name="right">Color corrected with intensity of lightStyle for Right side of the 3D Rectangle</param>
        /// <param name="top">Color corrected with intensity of lightStyle for Top side of the 3D Rectangle</param>
        /// <param name="bottom">Color corrected with intensity of lightStyle for Bottom side of the 3D Rectangle</param>
        internal void GetLight(SKColor surfaceColor, out SKColor front, out SKColor back, out SKColor left, out SKColor right, out SKColor top, out SKColor bottom)
        {
            switch (_lightStyle)
            {
            // LightStyle style is None
            case LightStyle.None:
            {
                front  = surfaceColor;
                left   = surfaceColor;
                top    = surfaceColor;
                back   = surfaceColor;
                right  = surfaceColor;
                bottom = surfaceColor;
                break;
            }

            // LightStyle style is Simplistic
            case LightStyle.Simplistic:
            {
                front  = surfaceColor;
                left   = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.25);
                top    = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.15);
                back   = surfaceColor;
                right  = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.25);
                bottom = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0.15);
                break;
            }

            // LightStyle style is Realistic
            default:
            {
                // For Right Axis angle Realistic lightStyle should be different
                if (_rightAngleAxis)
                {
                    // LightStyle source Vector
                    Point3D   lightSource   = new(0F, 0F, -1F);
                    Point3D[] rightPRpoints = new Point3D[1];
                    rightPRpoints[0] = lightSource;
                    RightAngleProjection(rightPRpoints);

                    // ******************************************************************
                    // Color correction. Angle between Normal vector of polygon and
                    // vector of lightStyle source is used.
                    // ******************************************************************
                    if (_angleY >= 45 || _angleY <= -45)
                    {
                        front = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[1]) / Math.PI);

                        back = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[2]) / Math.PI);

                        left = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0);

                        right = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0);
                    }
                    else
                    {
                        front = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 0);

                        back = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, 1);

                        left = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[3]) / Math.PI);

                        right = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[4]) / Math.PI);
                    }

                    top = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[5]) / Math.PI);

                    bottom = ChartGraphics.GetGradientColor(surfaceColor, SKColors.Black, GetAngle(lightSource, _lightVectors[6]) / Math.PI);
                }
                else
                {
                    // LightStyle source Vector
                    Point3D lightSource = new(0F, 0F, 1F);

                    // ******************************************************************
                    // Color correction. Angle between Normal vector of polygon and
                    // vector of lightStyle source is used.
                    // ******************************************************************
                    front = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI);

                    back = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI);

                    left = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[3]) / Math.PI);

                    right = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[4]) / Math.PI);

                    top = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[5]) / Math.PI);

                    bottom = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[6]) / Math.PI);
                }

                break;
            }
            }
        }
Пример #8
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();
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Draws a marker that represents a data point in FastPoint series.
        /// </summary>
        /// <param name="graph">Chart graphics used to draw the marker.</param>
        /// <param name="point">Series data point drawn.</param>
        /// <param name="pointIndex">Data point index in the series.</param>
        /// <param name="location">Marker location in pixels.</param>
        /// <param name="markerStyle">Marker style.</param>
        /// <param name="markerSize">Marker size in pixels.</param>
        /// <param name="brush">Brush used to fill marker shape.</param>
        /// <param name="borderPen">Marker border pen.</param>
        virtual protected void DrawMarker(
            ChartGraphics graph,
            DataPoint point,
            int pointIndex,
            SKPoint location,
            MarkerStyle markerStyle,
            int markerSize,
            SKPaint brush,
            SKPaint borderPen)
        {
            // Transform 3D coordinates
            if (chartArea3DEnabled)
            {
                Point3D[] points = new Point3D[1];
                location  = graph.GetRelativePoint(location);
                points[0] = new Point3D(location.X, location.Y, seriesZCoordinate);
                matrix3D.TransformPoints(points);
                location.X = points[0].X;
                location.Y = points[0].Y;
                location   = graph.GetAbsolutePoint(location);
            }

            // Create marker bounding rectangle in pixels
            SKRect markerBounds = new(
                location.X - markerSize / 2f, location.Y - markerSize / 2f, markerSize, markerSize);

            // Draw Marker
            switch (markerStyle)
            {
            case (MarkerStyle.Star4):
            case (MarkerStyle.Star5):
            case (MarkerStyle.Star6):
            case (MarkerStyle.Star10):
            {
                // Set number of corners
                int cornerNumber = 4;
                if (markerStyle == MarkerStyle.Star5)
                {
                    cornerNumber = 5;
                }
                else if (markerStyle == MarkerStyle.Star6)
                {
                    cornerNumber = 6;
                }
                else if (markerStyle == MarkerStyle.Star10)
                {
                    cornerNumber = 10;
                }

                // Get star polygon
                SKPoint[] points = ChartGraphics.CreateStarPolygon(markerBounds, cornerNumber);

                // Fill shape
                graph.FillPolygon(brush, points);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawPolygon(borderPen, points);
                }
                break;
            }

            case (MarkerStyle.Circle):
            {
                graph.FillEllipse(brush, markerBounds);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawEllipse(borderPen, markerBounds);
                }

                break;
            }

            case (MarkerStyle.Square):
            {
                graph.FillRectangle(brush, markerBounds);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawRectangle(
                        borderPen,
                        (int)Math.Round(markerBounds.Left, 0),
                        (int)Math.Round(markerBounds.Top, 0),
                        (int)Math.Round(markerBounds.Width, 0),
                        (int)Math.Round(markerBounds.Height, 0));
                }

                break;
            }

            case (MarkerStyle.Cross):
            {
                // Calculate cross line width and size
                float crossLineWidth = (float)Math.Ceiling(markerSize / 4F);
                float crossSize      = markerSize;      // * (float)Math.Sin(45f/180f*Math.PI)

                // Calculate cross coordinates
                SKPoint[] points = new SKPoint[12];
                points[0].X = location.X - crossSize / 2F;
                points[0].Y = location.Y + crossLineWidth / 2F;
                points[1].X = location.X - crossSize / 2F;
                points[1].Y = location.Y - crossLineWidth / 2F;

                points[2].X = location.X - crossLineWidth / 2F;
                points[2].Y = location.Y - crossLineWidth / 2F;
                points[3].X = location.X - crossLineWidth / 2F;
                points[3].Y = location.Y - crossSize / 2F;
                points[4].X = location.X + crossLineWidth / 2F;
                points[4].Y = location.Y - crossSize / 2F;

                points[5].X = location.X + crossLineWidth / 2F;
                points[5].Y = location.Y - crossLineWidth / 2F;
                points[6].X = location.X + crossSize / 2F;
                points[6].Y = location.Y - crossLineWidth / 2F;
                points[7].X = location.X + crossSize / 2F;
                points[7].Y = location.Y + crossLineWidth / 2F;

                points[8].X  = location.X + crossLineWidth / 2F;
                points[8].Y  = location.Y + crossLineWidth / 2F;
                points[9].X  = location.X + crossLineWidth / 2F;
                points[9].Y  = location.Y + crossSize / 2F;
                points[10].X = location.X - crossLineWidth / 2F;
                points[10].Y = location.Y + crossSize / 2F;
                points[11].X = location.X - crossLineWidth / 2F;
                points[11].Y = location.Y + crossLineWidth / 2F;

                // Rotate cross coordinates 45 degrees
                SKMatrix rotationMatrix = SKMatrix.CreateRotationDegrees(45, location.X, location.Y);
                rotationMatrix.TransformPoints(points);

                // Fill shape
                graph.FillPolygon(brush, points);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawPolygon(borderPen, points);
                }
                break;
            }

            case (MarkerStyle.Diamond):
            {
                SKPoint[] points = new SKPoint[4];
                points[0].X = markerBounds.Left;
                points[0].Y = markerBounds.Top + markerBounds.Height / 2F;
                points[1].X = markerBounds.Left + markerBounds.Width / 2F;
                points[1].Y = markerBounds.Top;
                points[2].X = markerBounds.Right;
                points[2].Y = markerBounds.Top + markerBounds.Height / 2F;
                points[3].X = markerBounds.Left + markerBounds.Width / 2F;
                points[3].Y = markerBounds.Bottom;

                graph.FillPolygon(brush, points);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawPolygon(borderPen, points);
                }
                break;
            }

            case (MarkerStyle.Triangle):
            {
                SKPoint[] points = new SKPoint[3];
                points[0].X = markerBounds.Left;
                points[0].Y = markerBounds.Bottom;
                points[1].X = markerBounds.Top + markerBounds.Width / 2F;
                points[1].Y = markerBounds.Top;
                points[2].X = markerBounds.Right;
                points[2].Y = markerBounds.Bottom;

                graph.FillPolygon(brush, points);

                // Draw border
                if (borderPen != null)
                {
                    graph.DrawPolygon(borderPen, points);
                }
                break;
            }

            default:
            {
                throw (new InvalidOperationException(SR.ExceptionFastPointMarkerStyleUnknown));
            }
            }

            // Process selection regions
            if (Common.ProcessModeRegions)
            {
                Common.HotRegionsList.AddHotRegion(
                    graph.GetRelativeRectangle(markerBounds),
                    point,
                    point.series.Name,
                    pointIndex);
            }
        }
Пример #10
0
        /// <summary>
        /// Draws chart area cursor and selection.
        /// </summary>
        /// <param name="graph">Reference to the ChartGraphics object.</param>
        internal void Paint(ChartGraphics graph)
        {
            //***************************************************
            //** Prepare for drawing
            //***************************************************

            // Do not proceed with painting if cursor is not attached to the axis
            if (GetAxis() == null ||
                _chartArea == null ||
                _chartArea.Common == null ||
                _chartArea.Common.ChartPicture == null ||
                _chartArea.Common.ChartPicture.isPrinting)
            {
                return;
            }

            // Get plot area position
            SKRect plotAreaPosition = _chartArea.PlotAreaPosition.ToSKRect();

            // Detect if cursor is horizontal or vertical
            bool horizontal = true;

            if (GetAxis().AxisPosition == AxisPosition.Bottom || GetAxis().AxisPosition == AxisPosition.Top)
            {
                horizontal = false;
            }

            //***************************************************
            //** Draw selection
            //***************************************************

            // Check if selection need to be drawn
            if (_drawSelection &&
                !double.IsNaN(SelectionStart) &&
                !double.IsNaN(SelectionEnd) &&
                SelectionColor != SKColor.Empty)
            {
                // Calculate selection rectangle
                SKRect rectSelection = GetSelectionRect(plotAreaPosition);
                rectSelection.Intersect(plotAreaPosition);

                // Get opposite axis selection rectangle
                SKRect rectOppositeSelection = GetOppositeSelectionRect(plotAreaPosition);

                // Draw selection if rectangle is not empty
                if (!rectSelection.IsEmpty && rectSelection.Width > 0 && rectSelection.Height > 0)
                {
                    // Limit selection rectangle to the area of the opposite selection
                    if (!rectOppositeSelection.IsEmpty && rectOppositeSelection.Width > 0 && rectOppositeSelection.Height > 0)
                    {
                        rectSelection.Intersect(rectOppositeSelection);

                        // We do not need to draw selection in the opposite axis
                        Cursor oppositeCursor =
                            (_attachedToXAxis == AxisName.X || _attachedToXAxis == AxisName.X2) ?
                            _chartArea.CursorY : _chartArea.CursorX;
                        oppositeCursor._drawSelection = false;
                    }

                    // Make sure selection is inside plotting area
                    rectSelection.Intersect(plotAreaPosition);

                    // If selection rectangle is not empty
                    if (rectSelection.Width > 0 && rectSelection.Height > 0)
                    {
                        // Add transparency to solid colors
                        var rangeSelectionColor = SelectionColor;
                        if (rangeSelectionColor.Alpha == 255)
                        {
                            rangeSelectionColor = new(rangeSelectionColor.Red, rangeSelectionColor.Green, rangeSelectionColor.Blue, 120);
                        }

                        // Draw selection
                        graph.FillRectangleRel(rectSelection,
                                               rangeSelectionColor,
                                               ChartHatchStyle.None,
                                               "",
                                               ChartImageWrapMode.Tile,
                                               SKColor.Empty,
                                               ChartImageAlignmentStyle.Center,
                                               GradientStyle.None,
                                               SKColor.Empty,
                                               SKColor.Empty,
                                               0,
                                               ChartDashStyle.NotSet,
                                               SKColor.Empty,
                                               0,
                                               PenAlignment.Inset);
                    }
                }
            }

            //***************************************************
            //** Draw cursor
            //***************************************************

            // Check if cursor need to be drawn
            if (!double.IsNaN(Position) &&
                LineColor != SKColor.Empty &&
                LineWidth > 0 &&
                LineDashStyle != ChartDashStyle.NotSet)
            {
                // Calculate line position
                bool    insideArea = false;
                SKPoint point1     = SKPoint.Empty;
                SKPoint point2     = SKPoint.Empty;
                if (horizontal)
                {
                    // Set cursor coordinates
                    point1.X = plotAreaPosition.Left;
                    point1.Y = (float)GetAxis().GetLinearPosition(Position);
                    point2.X = plotAreaPosition.Right;
                    point2.Y = point1.Y;

                    // Check if cursor is inside plotting rect
                    if (point1.Y >= plotAreaPosition.Top && point1.Y <= plotAreaPosition.Bottom)
                    {
                        insideArea = true;
                    }
                }
                else
                {
                    // Set cursor coordinates
                    point1.X = (float)GetAxis().GetLinearPosition(Position);
                    point1.Y = plotAreaPosition.Top;
                    point2.X = point1.X;
                    point2.Y = plotAreaPosition.Bottom;

                    // Check if cursor is inside plotting rect
                    if (point1.X >= plotAreaPosition.Left && point1.X <= plotAreaPosition.Right)
                    {
                        insideArea = true;
                    }
                }

                // Draw cursor if it's inside the chart area plotting rectangle
                if (insideArea)
                {
                    graph.DrawLineRel(LineColor, LineWidth, LineDashStyle, point1, point2);
                }
            }
            // Reset draw selection flag
            _drawSelection = true;
        }
Пример #11
0
        /// <summary>
        /// Draws 3D button in the scroll bar
        /// </summary>
        /// <param name="graph">Chart graphics.</param>
        /// <param name="buttonRect">Button position.</param>
        /// <param name="pressedState">Indicates that button is pressed.</param>
        /// <param name="buttonType">Button type to draw.</param>
        internal void PaintScrollBar3DButton(
            ChartGraphics graph,
            SKRect buttonRect,
            bool pressedState,
            ScrollBarButtonType buttonType)
        {
            // Page Up/Down buttons do not require drawing
            if (buttonType == ScrollBarButtonType.LargeIncrement || buttonType == ScrollBarButtonType.LargeDecrement)
            {
                return;
            }

            // Get 3 levels of colors for button drawing
            var darkerColor  = ChartGraphics.GetGradientColor(_buttonCurrentColor, SKColors.Black, 0.5);
            var darkestColor = ChartGraphics.GetGradientColor(_buttonCurrentColor, SKColors.Black, 0.8);
            var lighterColor = ChartGraphics.GetGradientColor(_buttonCurrentColor, SKColors.White, 0.5);

            // Fill button rectangle background
            graph.FillRectangleRel(
                buttonRect,
                _buttonCurrentColor,
                ChartHatchStyle.None,
                "",
                ChartImageWrapMode.Tile,
                SKColor.Empty,
                ChartImageAlignmentStyle.Center,
                GradientStyle.None,
                SKColor.Empty,
                darkerColor,
                (pressedState) ? 1 : 0,
                ChartDashStyle.Solid,
                SKColor.Empty,
                0,
                PenAlignment.Outset);

            // Check if 2 or 1 pixel border will be drawn (if size too small)
            bool singlePixelBorder = Size <= 12;

            // Draw 3D effect around the button when not pressed
            if (!pressedState)
            {
                // Get relative size of 1 pixel
                SKSize pixelRelativeSize = new(1, 1);
                pixelRelativeSize = graph.GetRelativeSize(pixelRelativeSize);

                // Draw top/left border with button color
                graph.DrawLineRel(
                    (singlePixelBorder) ? lighterColor : _buttonCurrentColor, 1, ChartDashStyle.Solid,
                    new SKPoint(buttonRect.Left, buttonRect.Bottom),
                    new SKPoint(buttonRect.Left, buttonRect.Top));
                graph.DrawLineRel(
                    (singlePixelBorder) ? lighterColor : _buttonCurrentColor, 1, ChartDashStyle.Solid,
                    new SKPoint(buttonRect.Left, buttonRect.Top),
                    new SKPoint(buttonRect.Right, buttonRect.Top));

                // Draw right/bottom border with the darkest color
                graph.DrawLineRel(
                    (singlePixelBorder) ? darkerColor : darkestColor, 1, ChartDashStyle.Solid,
                    new SKPoint(buttonRect.Right, buttonRect.Bottom),
                    new SKPoint(buttonRect.Right, buttonRect.Top));
                graph.DrawLineRel(
                    (singlePixelBorder) ? darkerColor : darkestColor, 1, ChartDashStyle.Solid,
                    new SKPoint(buttonRect.Left, buttonRect.Bottom),
                    new SKPoint(buttonRect.Right, buttonRect.Bottom));

                if (!singlePixelBorder)
                {
                    // Draw right/bottom border (offset 1) with the dark color
                    graph.DrawLineRel(
                        darkerColor, 1, ChartDashStyle.Solid,
                        new SKPoint(buttonRect.Right - pixelRelativeSize.Width, buttonRect.Bottom - pixelRelativeSize.Height),
                        new SKPoint(buttonRect.Right - pixelRelativeSize.Width, buttonRect.Top + pixelRelativeSize.Height));
                    graph.DrawLineRel(
                        darkerColor, 1, ChartDashStyle.Solid,
                        new SKPoint(buttonRect.Left + pixelRelativeSize.Width, buttonRect.Bottom - pixelRelativeSize.Height),
                        new SKPoint(buttonRect.Right - pixelRelativeSize.Width, buttonRect.Bottom - pixelRelativeSize.Height));

                    // Draw top/left border (offset 1) with lighter color
                    graph.DrawLineRel(
                        lighterColor, 1, ChartDashStyle.Solid,
                        new SKPoint(buttonRect.Left + pixelRelativeSize.Width, buttonRect.Bottom - pixelRelativeSize.Height),
                        new SKPoint(buttonRect.Left + pixelRelativeSize.Width, buttonRect.Top + pixelRelativeSize.Height));
                    graph.DrawLineRel(
                        lighterColor, 1, ChartDashStyle.Solid,
                        new SKPoint(buttonRect.Left + pixelRelativeSize.Width, buttonRect.Left + pixelRelativeSize.Height),
                        new SKPoint(buttonRect.Right - pixelRelativeSize.Width, buttonRect.Left + pixelRelativeSize.Height));
                }
            }

            // Check axis orientation
            bool verticalAxis = (axis.AxisPosition == AxisPosition.Left ||
                                 axis.AxisPosition == AxisPosition.Right);

            // Set graphics transformation for button pressed mode
            float pressedShifting = (singlePixelBorder) ? 0.5f : 1f;

            if (pressedState)
            {
                graph.TranslateTransform(pressedShifting, pressedShifting);
            }

            // Draw button image
            SKRect buttonAbsRect = graph.GetAbsoluteRectangle(buttonRect);
            float  imageOffset   = (singlePixelBorder) ? 2 : 3;

            switch (buttonType)
            {
            case (ScrollBarButtonType.SmallDecrement):
            {
                // Calculate triangal points position
                SKPoint[] points = new SKPoint[3];
                if (verticalAxis)
                {
                    points[0].X = buttonAbsRect.Left + imageOffset;
                    points[0].Y = buttonAbsRect.Top + (imageOffset + 1f);
                    points[1].X = buttonAbsRect.Left + buttonAbsRect.Width / 2f;
                    points[1].Y = buttonAbsRect.Bottom - imageOffset;
                    points[2].X = buttonAbsRect.Right - imageOffset;
                    points[2].Y = buttonAbsRect.Top + (imageOffset + 1f);
                }
                else
                {
                    points[0].X = buttonAbsRect.Left + imageOffset;
                    points[0].Y = buttonAbsRect.Top + buttonAbsRect.Height / 2f;
                    points[1].X = buttonAbsRect.Right - (imageOffset + 1f);
                    points[1].Y = buttonAbsRect.Top + imageOffset;
                    points[2].X = buttonAbsRect.Right - (imageOffset + 1f);
                    points[2].Y = buttonAbsRect.Bottom - imageOffset;
                }

                using var brush = new SKPaint { Style = SKPaintStyle.Fill, Color = _lineCurrentColor };

                graph.FillPolygon(brush, points);

                break;
            }

            case (ScrollBarButtonType.SmallIncrement):
            {
                // Calculate triangal points position
                SKPoint[] points = new SKPoint[3];
                if (verticalAxis)
                {
                    points[0].X = buttonAbsRect.Left + imageOffset;
                    points[0].Y = buttonAbsRect.Bottom - (imageOffset + 1f);
                    points[1].X = buttonAbsRect.Left + buttonAbsRect.Width / 2f;
                    points[1].Y = buttonAbsRect.Top + imageOffset;
                    points[2].X = buttonAbsRect.Right - imageOffset;
                    points[2].Y = buttonAbsRect.Bottom - (imageOffset + 1f);
                }
                else
                {
                    points[0].X = buttonAbsRect.Right - imageOffset;
                    points[0].Y = buttonAbsRect.Top + buttonAbsRect.Height / 2f;
                    points[1].X = buttonAbsRect.Left + (imageOffset + 1f);
                    points[1].Y = buttonAbsRect.Top + imageOffset;
                    points[2].X = buttonAbsRect.Left + (imageOffset + 1f);
                    points[2].Y = buttonAbsRect.Bottom - imageOffset;
                }

                using var brush = new SKPaint { Style = SKPaintStyle.Fill, Color = _lineCurrentColor };
                graph.FillPolygon(brush, points);

                break;
            }

            case (ScrollBarButtonType.ZoomReset):
            {
                // Draw circule with a minus sign

                using var pen = new SKPaint { Style = SKPaintStyle.Fill, Color = _lineCurrentColor };

                graph.DrawEllipse(pen, buttonAbsRect.Left + imageOffset - 0.5f, buttonAbsRect.Top + imageOffset - 0.5f, buttonAbsRect.Width - 2f * imageOffset, buttonAbsRect.Height - 2f * imageOffset);
                graph.DrawLine(pen, buttonAbsRect.Left + imageOffset + 1.5f, buttonAbsRect.Top + buttonAbsRect.Height / 2f - 0.5f, buttonAbsRect.Right - imageOffset - 2.5f, buttonAbsRect.Top + buttonAbsRect.Height / 2f - 0.5f);

                break;
            }
            }

            // Reset graphics transformation for button pressed mode
            if (pressedState)
            {
                graph.TranslateTransform(-pressedShifting, -pressedShifting);
            }
        }
Пример #12
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();
            }
        }
Пример #13
0
        /// <summary>
        /// Draws a 3D surface connecting the two specified points in 2D space.
        /// Used to draw Line based charts.
        /// </summary>
        /// <param name="area">Chart area reference.</param>
        /// <param name="graph">Chart graphics.</param>
        /// <param name="matrix">Coordinates transformation matrix.</param>
        /// <param name="lightStyle">LightStyle style (None, Simplistic, Realistic).</param>
        /// <param name="prevDataPointEx">Previous data point object.</param>
        /// <param name="positionZ">Z position of the back side of the 3D surface.</param>
        /// <param name="depth">Depth of the 3D surface.</param>
        /// <param name="points">Array of points.</param>
        /// <param name="pointIndex">Index of point to draw.</param>
        /// <param name="pointLoopIndex">Index of points loop.</param>
        /// <param name="tension">Line tension.</param>
        /// <param name="operationType">AxisName of operation Drawing, Calculating Path or Both</param>
        /// <param name="topDarkening">Darkenning scale for top surface. 0 - None.</param>
        /// <param name="bottomDarkening">Darkenning scale for bottom surface. 0 - None.</param>
        /// <param name="thirdPointPosition">Position where the third point is actually located or float.NaN if same as in "firstPoint".</param>
        /// <param name="fourthPointPosition">Position where the fourth point is actually located or float.NaN if same as in "secondPoint".</param>
        /// <param name="clippedSegment">Indicates that drawn segment is 3D clipped. Only top/bottom should be drawn.</param>
        /// <returns>Returns elemnt shape path if operationType parameter is set to CalcElementPath, otherwise Null.</returns>
        protected override SKPath Draw3DSurface(
            ChartArea area,
            ChartGraphics graph,
            Matrix3D matrix,
            LightStyle lightStyle,
            DataPoint3D prevDataPointEx,
            float positionZ,
            float depth,
            ArrayList points,
            int pointIndex,
            int pointLoopIndex,
            float tension,
            DrawingOperationTypes operationType,
            float topDarkening,
            float bottomDarkening,
            SKPoint thirdPointPosition,
            SKPoint fourthPointPosition,
            bool clippedSegment)
        {
            // Create graphics path for selection
            SKPath resultPath = ((operationType & DrawingOperationTypes.CalcElementPath) == DrawingOperationTypes.CalcElementPath)
                ? new SKPath() : null;

            // Check if points are drawn from sides to center (do only once)
            if (centerPointIndex == int.MaxValue)
            {
                centerPointIndex = GetCenterPointIndex(points);
            }

            //************************************************************
            //** Find line first & second points
            //************************************************************
            DataPoint3D secondPoint     = (DataPoint3D)points[pointIndex];
            int         pointArrayIndex = pointIndex;
            DataPoint3D firstPoint      = ChartGraphics.FindPointByIndex(
                points,
                secondPoint.index - 1,
                (multiSeries) ? secondPoint : null,
                ref pointArrayIndex);

            // Fint point with line properties
            DataPoint3D pointAttr = secondPoint;

            if (prevDataPointEx.dataPoint.IsEmpty)
            {
                pointAttr = prevDataPointEx;
            }
            else if (firstPoint.index > secondPoint.index)
            {
                pointAttr = firstPoint;
            }

            // Adjust point visual properties
            SKColor        color     = (useBorderColor) ? pointAttr.dataPoint.BorderColor : pointAttr.dataPoint.Color;
            ChartDashStyle dashStyle = pointAttr.dataPoint.BorderDashStyle;

            if (pointAttr.dataPoint.IsEmpty && pointAttr.dataPoint.Color == SKColor.Empty)
            {
                color = SKColors.Gray;
            }
            if (pointAttr.dataPoint.IsEmpty && pointAttr.dataPoint.BorderDashStyle == ChartDashStyle.NotSet)
            {
                dashStyle = ChartDashStyle.Solid;
            }

            //************************************************************
            //** Create "middle" point
            //************************************************************
            DataPoint3D middlePoint = new();

            middlePoint.xPosition = secondPoint.xPosition;
            middlePoint.yPosition = firstPoint.yPosition;

            // Check if reversed drawing order required
            bool originalDrawOrder = true;

            if ((pointIndex + 1) < points.Count)
            {
                DataPoint3D p = (DataPoint3D)points[pointIndex + 1];
                if (p.index == firstPoint.index)
                {
                    originalDrawOrder = false;
                }
            }

            // Check in which order vertical & horizontal lines segments should be drawn
            if (centerPointIndex != int.MaxValue && pointIndex >= centerPointIndex)
            {
                originalDrawOrder = false;
            }

            // Draw two segments of the step line
            SKPath resultPathLine1, resultPathLine2;

            if (originalDrawOrder)
            {
                // Draw first line
                middlePoint.dataPoint = secondPoint.dataPoint;
                resultPathLine1       = graph.Draw3DSurface(
                    area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
                    pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
                    firstPoint, middlePoint,
                    points, pointIndex, 0f, operationType, LineSegmentType.First,
                    showPointLines, false,
                    area.ReverseSeriesOrder,
                    multiSeries, 0, true);

                // No second draw of the prev. front line required
                graph.frontLinePen = null;

                // Draw second line
                middlePoint.dataPoint = firstPoint.dataPoint;
                resultPathLine2       = graph.Draw3DSurface(
                    area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
                    pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
                    middlePoint, secondPoint,
                    points, pointIndex, 0f, operationType, LineSegmentType.Last,
                    showPointLines, false,
                    area.ReverseSeriesOrder,
                    multiSeries, 0, true);

                // No second draw of the prev. front line required
                graph.frontLinePen = null;
            }
            else
            {
                // Draw second line
                middlePoint.dataPoint = firstPoint.dataPoint;
                resultPathLine2       = graph.Draw3DSurface(
                    area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
                    pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
                    middlePoint, secondPoint,
                    points, pointIndex, 0f, operationType, LineSegmentType.Last,
                    showPointLines, false,
                    area.ReverseSeriesOrder,
                    multiSeries, 0, true);

                // No second draw of the prev. front line required
                graph.frontLinePen = null;

                // Draw first line
                middlePoint.dataPoint = secondPoint.dataPoint;
                resultPathLine1       = graph.Draw3DSurface(
                    area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, color,
                    pointAttr.dataPoint.BorderColor, pointAttr.dataPoint.BorderWidth, dashStyle,
                    firstPoint, middlePoint,
                    points, pointIndex, 0f, operationType, LineSegmentType.First,
                    showPointLines, false,
                    area.ReverseSeriesOrder,
                    multiSeries, 0, true);

                // No second draw of the prev. front line required
                graph.frontLinePen = null;
            }

            if (resultPath != null)
            {
                if (area.Common.ProcessModeRegions && resultPathLine1 != null && resultPathLine1.PointCount > 0)
                {
                    area.Common.HotRegionsList.AddHotRegion(
                        resultPathLine1,
                        false,
                        prevDataPointEx.dataPoint,
                        prevDataPointEx.dataPoint.series.Name,
                        prevDataPointEx.index - 1);
                }

                if (resultPathLine2 != null && resultPathLine2.PointCount > 0)
                {
                    resultPath.AddPath(resultPathLine2);
                }
            }
            return(resultPath);
        }
Пример #14
0
        /// <summary>
        /// Paints an annotation object on the specified graphics.
        /// </summary>
        /// <param name="graphics">
        /// A <see cref="ChartGraphics"/> object, used to paint an annotation object.
        /// </param>
        /// <param name="chart">
        /// Reference to the <see cref="ChartService"/> owner control.
        /// </param>
        override internal void Paint(ChartService chart, ChartGraphics graphics)
        {
            // Get annotation position in relative coordinates
            GetRelativePosition(out SKPoint firstPoint, out SKSize size, out SKPoint anchorPoint);
            SKPoint secondPoint = new(firstPoint.X + size.Width, firstPoint.Y + size.Height);

            // Create selection rectangle
            SKRect selectionRect = new(firstPoint.X, firstPoint.Y, secondPoint.X, secondPoint.Y);

            // Adjust coordinates
            AdjustLineCoordinates(ref firstPoint, ref secondPoint, ref selectionRect);

            // Check if text position is valid
            if (float.IsNaN(firstPoint.X) ||
                float.IsNaN(firstPoint.Y) ||
                float.IsNaN(secondPoint.X) ||
                float.IsNaN(secondPoint.Y))
            {
                return;
            }

            // TODO: this
#if false
            // Set line caps
            bool        capChanged = false;
            SKStrokeCap oldCap     = SKStrokeCap.Butt;
            if (_startCap != LineAnchorCapStyle.None ||
                _endCap != LineAnchorCapStyle.None)
            {
                capChanged = true;
                oldCap     = graphics.Pen.StrokeCap;

                // Apply anchor cap settings
                if (_startCap == LineAnchorCapStyle.Arrow)
                {
                    // Adjust arrow size for small line width
                    if (LineWidth < 4)
                    {
                        int adjustment = 3 - LineWidth;
                        graphics.Pen.StrokeCap      = LineCap.Custom;
                        graphics.Pen.CustomStartCap = new AdjustableArrowCap(
                            LineWidth + adjustment,
                            LineWidth + adjustment,
                            true);
                    }
                    else
                    {
                        graphics.Pen.StartCap = LineCap.ArrowAnchor;
                    }
                }
                else if (_startCap == LineAnchorCapStyle.Diamond)
                {
                    graphics.Pen.StartCap = LineCap.DiamondAnchor;
                }
                else if (_startCap == LineAnchorCapStyle.Round)
                {
                    graphics.Pen.StartCap = LineCap.RoundAnchor;
                }
                else if (_startCap == LineAnchorCapStyle.Square)
                {
                    graphics.Pen.StartCap = LineCap.SquareAnchor;
                }
                if (_endCap == LineAnchorCapStyle.Arrow)
                {
                    // Adjust arrow size for small line width
                    if (LineWidth < 4)
                    {
                        int adjustment = 3 - LineWidth;
                        graphics.Pen.StrokeCap = SKStrokeCap.Round;
                        //    graphics.Pen.EndCap = LineCap.Custom;
                        //    graphics.Pen.CustomEndCap = new AdjustableArrowCap(
                        //        this.LineWidth + adjustment,
                        //        this.LineWidth + adjustment,
                        //        true);
                    }
                    else
                    {
                        graphics.Pen.StrokeCap = SKStrokeCap.Round;//LineCap.ArrowAnchor;
                    }
                }
                else if (_endCap == LineAnchorCapStyle.Diamond)
                {
                    graphics.Pen.EndCap = LineCap.DiamondAnchor;
                }
                else if (_endCap == LineAnchorCapStyle.Round)
                {
                    graphics.Pen.EndCap = LineCap.RoundAnchor;
                }
                else if (_endCap == LineAnchorCapStyle.Square)
                {
                    graphics.Pen.EndCap = LineCap.SquareAnchor;
                }
            }

            if (Common.ProcessModePaint)
            {
                // Draw line
                graphics.DrawLineRel(
                    LineColor,
                    LineWidth,
                    LineDashStyle,
                    firstPoint,
                    secondPoint,
                    ShadowColor,
                    ShadowOffset);
            }

            // Restore line caps
            if (capChanged)
            {
                graphics.Pen.StartCap = oldStartCap;
                graphics.Pen.EndCap   = oldEndCap;
            }
#endif
            // Paint selection handles
            PaintSelectionHandles(graphics, selectionRect, null);
        }
Пример #15
0
        /// <summary>
        /// Draws 3D border
        /// </summary>
        /// <param name="graph">Graphics to draw the border on.</param>
        /// <param name="borderSkin">Border skin object.</param>
        /// <param name="rect">Rectangle of the border.</param>
        /// <param name="backColor">Color of rectangle</param>
        /// <param name="backHatchStyle">Hatch style</param>
        /// <param name="backImage">Back Image</param>
        /// <param name="backImageWrapMode">Image mode</param>
        /// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
        /// <param name="backGradientStyle">Gradient type</param>
        /// <param name="backSecondaryColor">Gradient End Color</param>
        /// <param name="borderColor">Border Color</param>
        /// <param name="borderWidth">Border Width</param>
        /// <param name="borderDashStyle">Border Style</param>
        public virtual void DrawBorder(
            ChartGraphics graph,
            BorderSkin borderSkin,
            SKRect rect,
            SKColor backColor,
            ChartHatchStyle backHatchStyle,
            string backImage,
            ChartImageWrapMode backImageWrapMode,
            SKColor backImageTransparentColor,
            ChartImageAlignmentStyle backImageAlign,
            GradientStyle backGradientStyle,
            SKColor backSecondaryColor,
            SKColor borderColor,
            int borderWidth,
            ChartDashStyle borderDashStyle)
        {
            SKRect absolute = ChartGraphics.Round(rect);

            // Calculate shadow colors (0.2 - 0.6)
            float   colorDarkeningIndex = 0.3f + (0.4f * (borderSkin.PageColor.Red + borderSkin.PageColor.Green + borderSkin.PageColor.Blue) / 765f);
            SKColor shadowColor         = new(
                (byte)(backColor.Red * colorDarkeningIndex),
                (byte)(backColor.Green * colorDarkeningIndex),
                (byte)(backColor.Blue * colorDarkeningIndex));

            colorDarkeningIndex += 0.2f;
            SKColor shadowLightColor = new(
                (byte)(borderSkin.PageColor.Red * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Green * colorDarkeningIndex),
                (byte)(borderSkin.PageColor.Blue * colorDarkeningIndex));

            if (borderSkin.PageColor == SKColors.Transparent)
            {
                shadowLightColor = new SKColor(0, 0, 0, 60);
            }

            // Calculate rounded rect radius
            float radius = defaultRadiusSize;

            radius = Math.Max(radius, 2f * resolution / 96.0f);
            radius = Math.Min(radius, rect.Width / 2f);
            radius = Math.Min(radius, rect.Height / 2f);
            radius = (float)Math.Ceiling(radius);

            // Fill page background color
            using (SKPaint brush = new() { Color = borderSkin.PageColor, Style = SKPaintStyle.Fill })
            {
                graph.FillRectangle(brush, rect);
            }

            SKRect shadowRect;

            if (drawOutsideTopLeftShadow)
            {
                // Top/Left outside shadow
                shadowRect         = absolute;
                shadowRect.Left   -= radius * 0.3f;
                shadowRect.Top    -= radius * 0.3f;
                shadowRect.Right  -= radius * .3f;
                shadowRect.Bottom -= radius * .3f;
                graph.DrawRoundedRectShadowAbs(shadowRect, cornerRadius, radius, Color.FromArgb(128, SKColors.Black), borderSkin.PageColor, outsideShadowRate);
            }

            // Bottom/Right outside shadow
            shadowRect         = absolute;
            shadowRect.Left   += radius * 0.3f;
            shadowRect.Top    += radius * 0.3f;
            shadowRect.Right  -= radius * .3f;
            shadowRect.Bottom -= radius * .3f;
            graph.DrawRoundedRectShadowAbs(shadowRect, cornerRadius, radius, shadowLightColor, borderSkin.PageColor, outsideShadowRate);

            // Background
            shadowRect         = absolute;
            shadowRect.Right  -= radius * .3f;
            shadowRect.Bottom -= radius * .3f;
            SKPath path = ChartGraphics.CreateRoundedRectPath(shadowRect, cornerRadius);

            graph.DrawPathAbs(
                path,
                backColor,
                backHatchStyle,
                backImage,
                backImageWrapMode,
                backImageTransparentColor,
                backImageAlign,
                backGradientStyle,
                backSecondaryColor,
                borderColor,
                borderWidth,
                borderDashStyle,
                PenAlignment.Inset);

            // Dispose Graphic path
            if (path != null)
            {
                path.Dispose();
            }

            // Draw screws imitation in the corners of the farame
            if (drawScrews)
            {
                // Left/Top screw
                SKRect screwRect = SKRect.Empty;
                float  offset    = radius * 0.4f;
                screwRect.Left = shadowRect.Left + offset;
                screwRect.Top  = shadowRect.Top + offset;
                screwRect.Size = new(radius * 0.55f, screwRect.Width);
                DrawScrew(graph, screwRect);

                // Right/Top screw
                screwRect.Left = shadowRect.Right - offset - screwRect.Width;
                DrawScrew(graph, screwRect);

                // Right/Bottom screw
                screwRect.Left = shadowRect.Right - offset - screwRect.Width;
                screwRect.Top  = shadowRect.Bottom - offset - screwRect.Height;
                DrawScrew(graph, screwRect);

                // Left/Bottom screw
                screwRect.Left = shadowRect.Left + offset;
                screwRect.Top  = shadowRect.Bottom - offset - screwRect.Height;
                DrawScrew(graph, screwRect);
            }

            // Bottom/Right inner shadow
            SKRegion innerShadowRegion;

            if (drawBottomShadow)
            {
                shadowRect         = absolute;
                shadowRect.Right  -= radius * .3f;
                shadowRect.Bottom -= radius * .3f;
                innerShadowRegion  = new SKRegion(
                    ChartGraphics.CreateRoundedRectPath(
                        new SKRect(
                            shadowRect.Left - radius,
                            shadowRect.Top - radius,
                            shadowRect.Width + 0.5f * radius,
                            shadowRect.Height + 0.5f * radius),
                        cornerRadius));

                // TODO: innerShadowRegion.Complement(graph.CreateRoundedRectPath(shadowRect, cornerRadius));

                graph.Clip = innerShadowRegion;

                shadowRect.Left   -= 0.5f * radius;
                shadowRect.Top    -= 0.5f * radius;
                shadowRect.Right  += 0.5f * radius;
                shadowRect.Bottom += 0.5f * radius;

                graph.DrawRoundedRectShadowAbs(
                    shadowRect,
                    cornerRadius,
                    radius,
                    SKColors.Transparent,
                    Color.FromArgb(175, (sunken) ? SKColors.White : shadowColor),
                    1.0f);
                graph.Clip = new SKRegion();
            }

            // Top/Left inner shadow
            shadowRect         = absolute;
            shadowRect.Right  -= radius * .3f;
            shadowRect.Bottom -= radius * .3f;
            innerShadowRegion  = new(
                ChartGraphics.CreateRoundedRectPath(
                    new SKRect(
                        shadowRect.Left + radius * .5f,
                        shadowRect.Top + radius * .5f,
                        shadowRect.Width - .2f * radius,
                        shadowRect.Height - .2f * radius),
                    cornerRadius));

            SKRect shadowWithOffset = shadowRect;

            shadowWithOffset.Right  += radius;
            shadowWithOffset.Bottom += radius;
            // TODO: innerShadowRegion.Complement(graph.CreateRoundedRectPath(shadowWithOffset, cornerRadius));

            innerShadowRegion.SetPath(ChartGraphics.CreateRoundedRectPath(shadowRect, cornerRadius), innerShadowRegion);
            graph.Clip = innerShadowRegion;
            graph.DrawRoundedRectShadowAbs(
                shadowWithOffset,
                cornerRadius,
                radius,
                SKColors.Transparent,
                Color.FromArgb(175, (sunken) ? shadowColor : SKColors.White),
                1.0f);
            graph.Clip = new();
        }
Пример #16
0
        /// <summary>
        /// Draws 3D border.
        /// </summary>
        /// <param name="graph">Graphics to draw the border on.</param>
        /// <param name="borderSkin">Border skin object.</param>
        /// <param name="rect">Rectangle of the border.</param>
        /// <param name="backColor">Color of rectangle</param>
        /// <param name="backHatchStyle">Hatch style</param>
        /// <param name="backImage">Back Image</param>
        /// <param name="backImageWrapMode">Image mode</param>
        /// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
        /// <param name="backGradientStyle">Gradient type</param>
        /// <param name="backSecondaryColor">Gradient End Color</param>
        /// <param name="borderColor">Border Color</param>
        /// <param name="borderWidth">Border Width</param>
        /// <param name="borderDashStyle">Border Style</param>
        public override void DrawBorder(
            ChartGraphics graph,
            BorderSkin borderSkin,
            SKRect rect,
            SKColor backColor,
            ChartHatchStyle backHatchStyle,
            string backImage,
            ChartImageWrapMode backImageWrapMode,
            SKColor backImageTransparentColor,
            ChartImageAlignmentStyle backImageAlign,
            GradientStyle backGradientStyle,
            SKColor backSecondaryColor,
            SKColor borderColor,
            int borderWidth,
            ChartDashStyle borderDashStyle)
        {
            drawBottomShadow         = true;
            sunken                   = false;
            outsideShadowRate        = .9f;
            drawOutsideTopLeftShadow = false;
            bool oldScrewsFlag = drawScrews;

            drawScrews = false;
            base.DrawBorder(
                graph,
                borderSkin,
                rect,
                borderSkin.BackColor,
                borderSkin.BackHatchStyle,
                borderSkin.BackImage,
                borderSkin.BackImageWrapMode,
                borderSkin.BackImageTransparentColor,
                borderSkin.BackImageAlignment,
                borderSkin.BackGradientStyle,
                borderSkin.BackSecondaryColor,
                borderSkin.BorderColor,
                borderSkin.BorderWidth,
                borderSkin.BorderDashStyle);

            drawScrews   = oldScrewsFlag;
            rect.Left   += sizeLeftTop.Width;
            rect.Top    += sizeLeftTop.Height;
            rect.Right  -= sizeRightBottom.Width + sizeLeftTop.Width;
            rect.Bottom -= sizeRightBottom.Height + sizeLeftTop.Height;
            if (rect.Width > 0 && rect.Height > 0)
            {
                float[] oldCorners = (float[])cornerRadius.Clone();
                cornerRadius             = innerCorners;
                drawBottomShadow         = false;
                sunken                   = true;
                drawOutsideTopLeftShadow = true;
                outsideShadowRate        = 1.4f;
                SKColor oldPageColor = borderSkin.PageColor;
                borderSkin.PageColor = SKColors.Transparent;
                base.DrawBorder(
                    graph,
                    borderSkin,
                    rect,
                    backColor,
                    backHatchStyle,
                    backImage,
                    backImageWrapMode,
                    backImageTransparentColor,
                    backImageAlign,
                    backGradientStyle,
                    backSecondaryColor,
                    borderColor,
                    borderWidth,
                    borderDashStyle);
                borderSkin.PageColor = oldPageColor;
                cornerRadius         = oldCorners;
            }
        }