From 9901116860ec79f35b6398aefd393e54b1ab91e6 Mon Sep 17 00:00:00 2001 From: artemiusgreat Date: Sat, 10 Feb 2024 23:53:42 -0500 Subject: [PATCH] Update resize --- Libs/ScriptContainer.csproj | 4 +- Libs/ScriptControl.razor.js | 107 +++++++++++++++++----- Libs/ScriptService.cs | 15 ++- Samples/SampleClient/Pages/Index.razor | 2 +- Samples/SampleServer/Pages/Index.razor | 21 ++++- Samples/SampleServer/wwwroot/css/site.css | 1 - 6 files changed, 113 insertions(+), 37 deletions(-) diff --git a/Libs/ScriptContainer.csproj b/Libs/ScriptContainer.csproj index f9da778..5b64899 100644 --- a/Libs/ScriptContainer.csproj +++ b/Libs/ScriptContainer.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -8,7 +8,7 @@ True - 1.1.9 + 1.2.0 artemiusgreat indemos.com http://indemos.com diff --git a/Libs/ScriptControl.razor.js b/Libs/ScriptControl.razor.js index 0a0e84e..6016dea 100644 --- a/Libs/ScriptControl.razor.js +++ b/Libs/ScriptControl.razor.js @@ -1,44 +1,105 @@ function ScriptModule(instance, options) { this.events = []; - this.sizeScheduler = null; + this.sizeObservers = []; this.serviceInstance = instance; - this.getDocBounds = () => { + /// + /// Get window size + /// + this.getDocBounds = () => this.getElementBounds(document.body); + + /// + /// Get element size + /// + /// + this.getElementBounds = element => { + const bounds = element.getBoundingClientRect(); return { - X: document.body.clientWidth, - Y: document.body.clientHeight + X: element.clientWidth || element.scrollWidth || bounds.width, + Y: element.clientHeight || element.scrollHeight || bounds.height }; }; - this.getElementBounds = (element) => { - const bounds = element.getBoundingClientRect(); - return { - X: bounds.width, - Y: bounds.height + /// + /// Subscribe to custom event + /// + /// + /// + /// + this.subscribe = (element, event, action) => { + let scheduler = null; + let index = this.sizeObservers.length; + let change = e => { + clearTimeout(scheduler); + scheduler = setTimeout(() => { + this.serviceInstance && this + .serviceInstance + .invokeMethodAsync(action, e, index, event) + .catch(o => this.unsubscribe()); + }, options.interval || 100); }; + element.addEventListener(event, change, false); + this.events.push({ element, event, change }); + return this.events.length - 1; }; - this.onSize = () => { - clearTimeout(this.sizeScheduler); - this.sizeScheduler = setTimeout(() => { - this - .serviceInstance - .invokeMethodAsync("OnSizeChange", this.getDocBounds()) - .catch(o => this.unsubscribe()); - }, options.interval); + /// + /// Unsubscribe from custom event + /// + /// + this.unsubscribe = index => { + this.events.forEach((o, i) => { + if (this.events[index] || i === index) { + o.element.removeEventListener(o.event, o.change); + this.events[i] = null; + } + }); + this.events = this.events.filter(o => o); }; - this.subscribe = (element, e, done) => { - element.addEventListener(e, done, false); - this.events.push({ element, e, done }); + /// + /// Subscribe to element resize + /// + /// + /// + this.subscribeToSize = (element, action) => { + let scheduler = null; + let index = this.sizeObservers.length; + let change = e => { + clearTimeout(scheduler); + scheduler = setTimeout(() => { + this.serviceInstance && this + .serviceInstance + .invokeMethodAsync(action, e, index, "resize") + .catch(o => this.unsubscribeFromSize()); + }, options.interval || 100); + }; + this.sizeObservers.push(new ResizeObserver(change).observe(element)); + return this.sizeObservers.length - 1; }; - this.unsubscribe = () => { - this.events.forEach(o => o.element.removeEventListener(o.e, o.done)); + /// + /// Unsubscribe from size observer + /// + /// + this.unsubscribeFromSize = index => { + this.sizeObservers.forEach((o, i) => { + if (this.sizeObservers[index] || i === index) { + this.sizeObservers[i].disconnect(); + this.sizeObservers[i] = null; + } + }); + this.sizeObservers = this.sizeObservers.filter(o => o); }; - this.subscribe(window, "resize", this.onSize); + try { + this.unsubscribeFromSize(); + this.subscribeToSize(document.body, "OnChangeAction"); + } catch (e) { + this.unsubscribe(); + this.subscribe(window, "resize", "OnChangeAction"); + } }; export function getScriptModule(instance, options) { diff --git a/Libs/ScriptService.cs b/Libs/ScriptService.cs index e775a3f..9587494 100644 --- a/Libs/ScriptService.cs +++ b/Libs/ScriptService.cs @@ -2,7 +2,9 @@ using Microsoft.JSInterop; using System; using System.Collections.Generic; +using System.Reflection; using System.Threading.Tasks; +using static System.Collections.Specialized.BitVector32; namespace ScriptContainer { @@ -40,7 +42,7 @@ public class ScriptService : IAsyncDisposable /// /// On size event /// - public Action OnSize { get; set; } = o => { }; + public Action OnChange { get; set; } = (o, i, action) => { }; /// /// Get document bounds @@ -81,11 +83,6 @@ public async Task CreateModule(IDictionary option options ??= new Dictionary(); - if (options.TryGetValue("interval", out var interval) is false) - { - options["interval"] = 100; - } - _serviceInstance = DotNetObjectReference.Create(this); _scriptModule = await _runtime.InvokeAsync("import", "./_content/ScriptContainer/ScriptControl.razor.js"); _scriptInstance = await _scriptModule.InvokeAsync("getScriptModule", _serviceInstance, options); @@ -97,9 +94,11 @@ public async Task CreateModule(IDictionary option /// Script proxy /// /// + /// + /// /// [JSInvokable] - public void OnSizeChange(ScriptMessage message) => OnSize(message); + public void OnChangeAction(dynamic message, int index, string action) => OnChange(message, index, action); /// /// Dispose @@ -107,7 +106,7 @@ public async Task CreateModule(IDictionary option /// public async ValueTask DisposeAsync() { - OnSize = o => { }; + OnChange = (o, i, action) => { }; if (_scriptInstance is not null) { diff --git a/Samples/SampleClient/Pages/Index.razor b/Samples/SampleClient/Pages/Index.razor index 54294ab..3ba18eb 100644 --- a/Samples/SampleClient/Pages/Index.razor +++ b/Samples/SampleClient/Pages/Index.razor @@ -59,7 +59,7 @@ await ScaleService.CreateModule(); await GetBounds(); - ScaleService.OnSize = async message => await GetBounds(); + ScaleService.OnChange = async (message, index, action) => await GetBounds(); } protected async Task GetBounds() diff --git a/Samples/SampleServer/Pages/Index.razor b/Samples/SampleServer/Pages/Index.razor index b430446..94df77b 100644 --- a/Samples/SampleServer/Pages/Index.razor +++ b/Samples/SampleServer/Pages/Index.razor @@ -3,7 +3,7 @@ @inject IJSRuntime runtime
-
@@ -27,6 +27,15 @@
  • @ItemBH
  • + @if (Rows.Any()) + { +
      + @foreach (var row in Rows) + { +
    • @row
    • + } +
    + }
    @code @@ -42,6 +51,7 @@ public ElementReference ElementB { get; set; } public ElementReference CanvasA { get; set; } public ElementReference CanvasB { get; set; } + public IList Rows { get; set; } = new string[0]; protected override async Task OnAfterRenderAsync(bool setup) { @@ -53,6 +63,13 @@ await base.OnAfterRenderAsync(setup); } + protected void Increase() + { + Rows = Rows.Any() ? + new string[0] : + Enumerable.Range(0, 50).Select(o => $"{o}").ToList(); + } + protected async Task Setup() { ScaleService?.DisposeAsync(); @@ -61,7 +78,7 @@ await ScaleService.CreateModule(); await GetBounds(); - ScaleService.OnSize = async message => await GetBounds(); + ScaleService.OnChange = async (message, index, action) => await GetBounds(); } protected async Task GetBounds() diff --git a/Samples/SampleServer/wwwroot/css/site.css b/Samples/SampleServer/wwwroot/css/site.css index 15f4c28..ef29177 100644 --- a/Samples/SampleServer/wwwroot/css/site.css +++ b/Samples/SampleServer/wwwroot/css/site.css @@ -8,7 +8,6 @@ html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; height: 100%; overflow: auto; - display: grid; } main, article, .element-container {