/// <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(); } }
/// <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; }
/// <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); }