excubo-ag / Blazor.Canvas

https://excubo-ag.github.io/Blazor.Canvas/
MIT License
220 stars 23 forks source link

Issue with paths when used with batching #179

Closed technyon closed 4 months ago

technyon commented 4 months ago

Hi,

I have a strange issue that occurs when drawing paths using batching with MoveToAsync, LineToAsync nad StrokeAsync. As long as I draw a static image, everything is fine, but in my case the user can zoom and pan the content of the canvas. While this works for shapes like rectangles, paths have an issue: Paths from previous renders remain on the canvas, although it has been cleared using ClearRectAsync. Rectangles don't have this problem.

To reproduce:

Expected behavior: ClearRectAsync should clear the canvas and only the paths drawn after the last ClearRectAsync are visible

@page "/2D/DrawingRectangles"
@using System.Diagnostics
@using Excubo.Blazor.Canvas.Contexts

<SourceCodeLink Repository="Blazor.Canvas" Section="@nameof(Context2D)" Page="@nameof(DrawingRectangles)" />
<h3>DrawingRectangles</h3>

For more information, please visit <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">https://developer.mozilla.org/</a>.
<hr />
<Canvas @ref="canvas" onmousemove="@OnMove" width="400" height="400" style="border: 5px solid red" />
<hr />
<ol>
    @if (Messages != null)
    {
        foreach (var message in Messages)
        {
            <li>@message</li>
        }
    }
</ol>

@code {
    private async Task OnMove(MouseEventArgs e)
    {
        offsetX = offsetX + (int)e.MovementX;
        offsetY = offsetY + (int)e.MovementY;
        await UpdateCanvasAsync();
    }

    private Canvas canvas;
    private Context2D _context;

    private List<string> Messages = new List<string>();
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            _context = await canvas.GetContext2DAsync();
            await UpdateCanvasAsync();
        }
    }

    private int offsetX = 0;
    private int offsetY = 0;

    private async Task UpdateCanvasAsync()
    {
        var messages = new List<string>();
        await using (var batch = _context.CreateBatch())
        {
            await batch.ClearRectAsync(0, 0, 400, 400);
            await batch.FillRectAsync(offsetX + 100, offsetY + 100, 100, 100);
            await batch.StrokeRectAsync(offsetX + 210, offsetY + 100, 100, 100);
            await batch.StrokeStyleAsync("#000000");
            await batch.MoveToAsync(offsetX + 80, offsetY + 100);
            await batch.LineToAsync(offsetX + 80, offsetY + 100 + 100);
            await batch.StrokeAsync();

        }
    }
}
technyon commented 4 months ago

To answer my own issue, this can be fixed by putting

await batch.BeginPathAsync();

before any calls drawing paths.