using Blazor.Extensions.Canvas.Canvas2D; using Blazor.Extensions; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.ComponentModel; using System.Reflection.Metadata.Ecma335; namespace BlazorCanvas.Server.Components.Data; // https://www.codeproject.com/Articles/5269947/Drawing-with-the-HTML-Canvas-Element-in-Blazor-Ser public class CanvasService { private Canvas2DContext? _currentCanvasContext; private IJSRuntime _jsRuntime; private IRedisService _redisService; private CanvasCommand _lastCommand = new(); private List _lsComms = new(); private bool _is_init = false, _is_started = false, _has_ended = false; public CanvasService(IJSRuntime jsRuntime, IRedisService redisService) { _jsRuntime = jsRuntime; _redisService = redisService; } ~CanvasService() { _has_ended = true; Task.Delay(100); } public string currentColor { get; set; } = "Black"; public int pointSize { get; set; } = 1; public bool snap { get; set; } public ElementReference divCanvas { get; set; } public BECanvasComponent myCanvas { get; set; } = new(); /// /// Version Pub/Sub /// public async void Subscribe() { CancellationToken cToken = new(); while (!cToken.IsCancellationRequested) { var comm = await _redisService.Subscribe(cToken); if (comm is not null) Draw(comm); } } public async void Consume() { while (!_has_ended) { if (_lsComms.Count > 0) _lsComms.Clear(); _lsComms.AddRange(await _redisService.Consume()); if (_lsComms.Count == 1) Draw(_lsComms[0]); else if (_lsComms.Count > 0) Draw(_lsComms); Task.Delay(10); } } public async void InitStreamer() { while (!_is_init) { _is_init = await _redisService.InitStreamer(); if (!_is_init) await Task.Delay(1000); } } public async void Draw(IEnumerable lsCommand) { if (_currentCanvasContext is null) { _currentCanvasContext = await myCanvas.CreateCanvas2DAsync(); await _currentCanvasContext.ClearRectAsync(0, 0, 1920, 1080); } await _currentCanvasContext.BeginBatchAsync(); foreach (CanvasCommand command in lsCommand) { await _currentCanvasContext.SetFillStyleAsync(command.Color); await _currentCanvasContext.FillRectAsync(command.X, command.Y, command.PointSize, command.PointSize); } await _currentCanvasContext.EndBatchAsync(); } public async void Draw(CanvasCommand command) { if (_currentCanvasContext is null) { _currentCanvasContext = await myCanvas.CreateCanvas2DAsync(); await _currentCanvasContext.ClearRectAsync(0, 0, 1920, 1080); } try { await _currentCanvasContext.SetFillStyleAsync(command.Color); } catch (JSDisconnectedException e) { Console.WriteLine(e.ToString()); return; // Welp. } await _currentCanvasContext.FillRectAsync(command.X, command.Y, command.PointSize, command.PointSize); } public async void HandleMouse(MouseEventArgs eventArgs) { double mouseX = 0, mouseY = 0; if (!_is_started) { if (!_is_init) InitStreamer(); if (_is_init) { Consume(); _is_started = true; } return; } if (eventArgs.Buttons == 0 || eventArgs.Buttons > 2) return; // Rien faire si aucun bouton est appuyé ou si les deux boutons/ d'autres boutons sont appuyés. if (divCanvas.Id?.Length > 0) { string data = await _jsRuntime.InvokeAsync("getDivCanvasOffsets", new object[] { divCanvas }); string color = "White"; CanvasCommand command = new(); JObject? offsets = (JObject?)JsonConvert.DeserializeObject(data); if (offsets is not null && offsets.HasValues) { // Translation entre le canvas et la souris. mouseX = eventArgs.PageX - offsets.Value("offsetLeft"); mouseY = eventArgs.PageY - offsets.Value("offsetTop"); } if (eventArgs.Buttons == 1) // Couleur si bouton gauche, blanc si bouton droit color = currentColor; if (snap) { // Magnétisme boboche. mouseX -= mouseX % pointSize; mouseY -= mouseY % pointSize; } command.X = mouseX; command.Y = mouseY; command.Color = color; command.PointSize = pointSize; if (command.Equals(_lastCommand)) return; // Pour pas spammer des commandes si c'est pas pertinent. _redisService.Produce(command); // Stream _lastCommand = command; } } }