如何在.NET MAUI 中绘制饼图

问题描述 投票:0回答:2

我需要创建一个如下所示的进度条。

我现在所做的是:

public void Draw(ICanvas canvas, RectF dirtyRect)
{
    float effectiveSize = Size - Thickness;
    float x = Thickness / 2;
    float y = Thickness / 2;

    if (Progress < 0)
    {
        Progress = 0;
    }
    else if (Progress > 100)
    {
        Progress = 100;
    }

    if (Progress < 100)
    {
        float angle = GetAngle(Progress);

        canvas.StrokeColor = ProgressLeftColor;
        canvas.StrokeSize = Thickness;
        canvas.DrawEllipse(x, y, effectiveSize, effectiveSize);

        // Draw arc
        canvas.StrokeColor = ProgressColor;
        canvas.StrokeSize = Thickness;
        canvas.DrawArc(x, y, effectiveSize, effectiveSize, 90, angle, true, false);
    }
    else
    {
        // Draw circle
        canvas.StrokeColor = ProgressColor;
        canvas.StrokeSize = Thickness;
        canvas.DrawEllipse(x, y, effectiveSize, effectiveSize);
    }

    float fontSize = effectiveSize / 2.86f;
    canvas.FontSize = fontSize;
    canvas.FontColor = TextColor;

    float verticalPosition = ((Size / 2) - (fontSize / 2)) * 1.15f;
    canvas.DrawString($"{Progress}%", x, verticalPosition, effectiveSize, effectiveSize / 4, HorizontalAlignment.Center, VerticalAlignment.Center);
}

这会画出一个带有弧线的漂亮圆圈。我正在努力解决内部馅饼部分(浅灰色部分)。我需要那个部分填充一些颜色。

我的想法之一是创建两条线,然后用弧线连接它们,并填充对象。 像这样的东西。

canvas.FillColor = Colors.Teal;

var center = new Point(effectiveSize / 2, effectiveSize / 2);
var startPoint = new Point(x, y);
var endPoint = new Point();
canvas.DrawLine(center, startPoint);
canvas.DrawLine(center, endPoint);
canvas.DrawArc((float)startPoint.X, (float)startPoint.Y,float)endPoint.X, (float)endPoint.Y, 0, angle, true, false);

如何计算终点。 或者有什么更好的解决办法吗

谢谢

math canvas maui draw
2个回答
1
投票

您可以尝试使用SkiaSharp来绘制这个饼图。我在这里分享一个解决方案。有关更多信息,您可以参考SkiaSharp曲线和路径。它也适用于毛伊岛。

使用滑块控制角度:

<VerticalStackLayout
    Spacing="25"
    Padding="30,0"
    VerticalOptions="Center">

    
    <Slider Maximum="360" ValueChanged="Slider_ValueChanged" />

    <skia:SKCanvasView x:Name="mycanvas" WidthRequest="400" HeightRequest="400" PaintSurface="SKCanvasView_PaintSurface"/>


</VerticalStackLayout>

在后面的代码中:

void Slider_ValueChanged(System.Object sender, Microsoft.Maui.Controls.ValueChangedEventArgs e)
{
    if (e.NewValue >= 360)
    {
        // the value cannnot be equal to 360
        SweepAngle = (float)359.99;
    }
    else
    {
        SweepAngle = (float)e.NewValue;
    }
    mycanvas.InvalidateSurface();
}

void SKCanvasView_PaintSurface(System.Object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{
    SKImageInfo info = e.Info;
    SKSurface surface = e.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();


    // draw the default background circle ring
    SKPaint cPaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.LightGray,
        StrokeWidth = 50
    };
    SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
    canvas.DrawCircle(center, 200, cPaint);

    cPaint.Color = SKColors.AliceBlue;
    cPaint.Style = SKPaintStyle.Fill;
    canvas.DrawCircle(center, 200, cPaint);


    //draw the progress bar outer ring
    SKRect rect = new SKRect(center.X-200, center.Y-200, center.X + 200, center.Y + 200);

    SKPaint aPaint = new SKPaint()
    {

        StrokeWidth = 50,
        Color = SKColors.Green,
        IsStroke = true
    };

    canvas.DrawArc(rect, -90, SweepAngle, false,aPaint);
    
    // draw the inner circle of the progress bar
    using (SKPath path = new SKPath())
    using (SKPaint fillPaint = new SKPaint())
    using (SKPaint outlinePaint = new SKPaint())
    {
        SKRect rect1 = new SKRect(center.X - 200, center.Y - 200, center.X + 200, center.Y + 200);

        path.MoveTo(e.Info.Width / 2, e.Info.Height / 2);
        path.ArcTo(rect1, -90, SweepAngle, false);

        fillPaint.Style = SKPaintStyle.Fill;
        fillPaint.Color = SKColors.LightGreen;

        canvas.DrawPath(path, fillPaint);
    }
    SKPaint textPaint = new SKPaint
    {
        Color = SKColors.LightSeaGreen,
        StrokeWidth = 1,
    };

    // draw the text
    string text = (Math.Round(SweepAngle/360*100,0)).ToString() + "%";
    float textWidth = textPaint.MeasureText(text);
    textPaint.TextSize = 0.2f * info.Width * textPaint.TextSize / textWidth;

    SKRect textBounds = new SKRect();
    textPaint.MeasureText(text, ref textBounds);

    float xText = info.Width / 2 - textBounds.MidX;
    float yText = info.Height / 2 - textBounds.MidY;

    canvas.DrawText(text, xText, yText, textPaint);
}

希望有帮助!


0
投票

您已经使用 Skia 得到了一个很好的答案,但如果您想使用 Microsoft.Maui.Graphics,这里是一个替代方案。没有文本,因为即使可以将其添加到可绘制对象中,如果您正在执行控件,那么在封装所有这些内容的 ContentView 中也更好。从那里您可以添加 BindableProperty 和所有此类机制。

public class ProgressbarDrawable : IDrawable
{
    public double Progress { get; set; } = 100;

    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        canvas.SaveState();
        var startAngle = 90;
        var _progressAngle = Progress / 100;
        var endAngle = startAngle - (int)Math.Round(_progressAngle * 360, MidpointRounding.AwayFromZero);
        var isFullCircle = Progress == 100;

        var centerX = dirtyRect.Width / 2;
        var centerY = dirtyRect.Height / 2;
        var radius = dirtyRect.Width / 2;

        canvas.StrokeColor = new Color(243, 242, 238);
        canvas.StrokeSize = 10;
        canvas.DrawCircle(centerX, centerY, radius);

        if (isFullCircle)
        {
            canvas.FillColor = new Color(235, 243, 231);
            canvas.FillCircle(centerX, centerY, radius);
            canvas.StrokeColor = new Color(132, 189, 137);
            canvas.StrokeSize = 10;
            canvas.DrawCircle(centerX, centerY, radius);
        }
        else
        {

            var path = new PathF();
            path.MoveTo(centerX, centerY);
            path.AddArc(centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle, endAngle, true);
            path.LineTo(centerX, centerY);
            canvas.FillColor = new Color(235, 243, 231);
            canvas.FillPath(path);

            canvas.StrokeColor = new Color(132, 189, 137);
            canvas.StrokeSize = 10;
            canvas.DrawArc(centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle, endAngle, true, false);
        }

        canvas.RestoreState();
    }
}

实施

<ContentPage.Resources>
    <drawables:ProgressbarDrawable x:Key="ProgressbarDrawable" />
</ContentPage.Resources>

<GraphicsView
    x:Name="ProgressbarDrawable"
    Drawable="{StaticResource ProgressbarDrawable}"
    HeightRequest="200"
    WidthRequest="200" />
© www.soinside.com 2019 - 2024. All rights reserved.