/// <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"/> control. /// </param> override internal void Paint(ChartService chart, ChartGraphics graphics) { // Get annotation position in relative coordinates GetRelativePosition(out SKPoint firstPoint, out _, out _); SKPoint secondPoint = new(firstPoint.X + SKSize.Empty.Width, firstPoint.Y + SKSize.Empty.Height); // Create selection rectangle SKRect selectionRect = new(firstPoint.X, firstPoint.Y, secondPoint.X, secondPoint.Y); // Get text position SKRect rectanglePosition = new(selectionRect.Left, selectionRect.Top, selectionRect.Right, selectionRect.Bottom); if (rectanglePosition.Width < 0 || rectanglePosition.Height < 0) { rectanglePosition = rectanglePosition.Standardized; } // Check if position is valid if (float.IsNaN(rectanglePosition.Left) || float.IsNaN(rectanglePosition.Top) || float.IsNaN(rectanglePosition.Right) || float.IsNaN(rectanglePosition.Bottom)) { return; } if (isRectVisible && Common.ProcessModePaint) { // Draw rectangle graphics.FillRectangleRel( rectanglePosition, BackColor, BackHatchStyle, String.Empty, ChartImageWrapMode.Scaled, SKColor.Empty, ChartImageAlignmentStyle.Center, BackGradientStyle, BackSecondaryColor, LineColor, LineWidth, LineDashStyle, ShadowColor, ShadowOffset, PenAlignment.Center, isEllipse, 1, false); } // Call base class to paint text, selection handles and process hot regions base.Paint(chart, graphics); }
/// <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); } }
/// <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; }