diff --git a/EgwCoreLib.BlazorTest/Pages/TestLoading.razor b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor new file mode 100644 index 0000000..9e66ea2 --- /dev/null +++ b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor @@ -0,0 +1,14 @@ +@page "/TestLoading" + +

TestLoading

+
+ + +
+
+ + +
+ + + diff --git a/EgwCoreLib.BlazorTest/Pages/TestLoading.razor.cs b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor.cs new file mode 100644 index 0000000..eaaecf0 --- /dev/null +++ b/EgwCoreLib.BlazorTest/Pages/TestLoading.razor.cs @@ -0,0 +1,58 @@ +namespace EgwCoreLib.BlazorTest.Pages +{ + public partial class TestLoading + { + #region Protected Properties + + protected double expTime { get; set; } = 6; + protected int numSteps { get; set; } = 4; + + #endregion Protected Properties + + #region Protected Methods + + protected async Task StartLongTimer() + { + double stdWait = expTime / numSteps; + int nextWait = 1000; + int stepVal = maxVal / numSteps; + // imposto i valori x progress.. + maxVal = 100; + expTimeMSec = (int)(stdWait * 1000); + //nextVal = stepVal; + //currVal = 0; + for (int currStep = 1; currStep <= numSteps; currStep++) + { + // aggiorno valori + currVal = (currStep - 1) * stepVal; + nextVal = currStep * stepVal; + // se max mi fermo... + if (nextVal > maxVal) + { + nextVal = maxVal; + } + await InvokeAsync(StateHasChanged); + // simulo ritardo importante (da 2 a 3 volte + nextWait = (int)(rnd.Next(2000, 3000) * stdWait); + // attendo step successivi... + await Task.Delay(nextWait); + } + await Task.Delay(1); + currVal = maxVal; + await InvokeAsync(StateHasChanged); + } + + #endregion Protected Methods + + #region Private Fields + + private int currVal = 100; + private int expTimeMSec = 10000; + private int maxVal = 100; + private int nextVal = 100; + private Random rnd = new Random(); + private string titleMsg = "SIM Progress"; + + #endregion Private Fields + } +} \ No newline at end of file diff --git a/EgwCoreLib.BlazorTest/Pages/TestMultiLine.razor b/EgwCoreLib.BlazorTest/Pages/TestMultiLine.razor index e3d24db..f734c50 100644 --- a/EgwCoreLib.BlazorTest/Pages/TestMultiLine.razor +++ b/EgwCoreLib.BlazorTest/Pages/TestMultiLine.razor @@ -17,3 +17,37 @@ else } +
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
diff --git a/EgwCoreLib.Razor/LoadingData.razor b/EgwCoreLib.Razor/LoadingData.razor index 354d765..40de504 100644 --- a/EgwCoreLib.Razor/LoadingData.razor +++ b/EgwCoreLib.Razor/LoadingData.razor @@ -1,6 +1,84 @@ -
-
-

loading data

- +@if (DisplaySize == CtrlSize.Small) +{ +
+
+
+
+ loading data +
+ @if (DisplayMode == SpinMode.Normal) + { + + } + else if (DisplayMode == SpinMode.Growl) + { +
+ Loading... +
+ } + else + { +
+
+ +
+
+ } +
+
-
\ No newline at end of file +} +else if (DisplaySize == CtrlSize.Normal) +{ +
+
+

loading data

+ @if (DisplayMode == SpinMode.Normal) + { + + } + else if (DisplayMode == SpinMode.Growl) + { +
+ Loading... +
+ } + else + { +
+
+ +
+
+ } +
+
+} +else if (DisplaySize == CtrlSize.Large) +{ +
+
+
+

loading data

+ @if (DisplayMode == SpinMode.Normal) + { + + } + else if (DisplayMode == SpinMode.Growl) + { +
+ Loading... +
+ } + else + { +
+
+ +
+
+ } +
+
+
+} \ No newline at end of file diff --git a/EgwCoreLib.Razor/LoadingData.razor.cs b/EgwCoreLib.Razor/LoadingData.razor.cs new file mode 100644 index 0000000..60b8647 --- /dev/null +++ b/EgwCoreLib.Razor/LoadingData.razor.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Components; + +namespace EgwCoreLib.Razor +{ + public partial class LoadingData + { + #region Public Enums + + public enum CtrlSize + { + Normal, + Small, + Large + } + + public enum SpinMode + { + Normal, + Growl, + BounceLine + } + + #endregion Public Enums + + #region Public Properties + + /// + /// Modalità display principale + /// default: alert alert-primary + /// + [Parameter] + public string DisplayCss { get; set; } = "alert alert-primary"; + + /// + /// Modalità animazione + /// default: Normal + /// + [Parameter] + public SpinMode DisplayMode { get; set; } = SpinMode.Normal; + + /// + /// Dimensione display + /// default: Normal + /// + [Parameter] + public CtrlSize DisplaySize { get; set; } = CtrlSize.Normal; + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/EgwCoreLib.Razor/LoadingData.razor.css b/EgwCoreLib.Razor/LoadingData.razor.css new file mode 100644 index 0000000..5530d10 --- /dev/null +++ b/EgwCoreLib.Razor/LoadingData.razor.css @@ -0,0 +1,126 @@ +.modalOrd { + position: relative; + z-index: 9999; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: #000000; + background-color: rgba(0, 0, 0, 0.6); +} +.loader { + width: 5rem; + position: relative; +} +.loader-text { + position: relative; + top: 0; + padding: 0; + margin: 0; + color: #C8B6FF; + animation: text_713 3.5s ease both infinite; + font-size: 0.8rem; + letter-spacing: 1px; +} +.load { + background-color: #9A79FF; + border-radius: 3rem; + display: block; + height: 1rem; + width: 1rem; + bottom: 0; + position: relative; + transform: translateX(64px); + animation: loading_713 3.5s ease both infinite; +} +.load::before { + position: relative; + content: ""; + width: 100%; + height: 100%; + background-color: #D1C2FF; + border-radius: inherit; + animation: loading2_713 3.5s ease both infinite; +} +@keyframes text_713 { + 0% { + letter-spacing: 1px; + transform: translateX(0px); + } + 40% { + letter-spacing: 2px; + transform: translateX(26px); + } + 80% { + letter-spacing: 1px; + transform: translateX(32px); + } + 90% { + letter-spacing: 2px; + transform: translateX(0px); + } + 100% { + letter-spacing: 1px; + transform: translateX(0px); + } +} +@keyframes loading_713 { + 0% { + width: 16px; + transform: translateX(0px); + } + 40% { + width: 100%; + transform: translateX(0px); + } + 80% { + width: 16px; + transform: translateX(64px); + } + 90% { + width: 100%; + transform: translateX(0px); + } + 100% { + width: 16px; + transform: translateX(0px); + } +} +@keyframes loading2_713 { + 0% { + transform: translateX(0px); + width: 16px; + } + 40% { + transform: translateX(0%); + width: 80%; + } + 80% { + width: 100%; + transform: translateX(0px); + } + 90% { + width: 80%; + transform: translateX(15px); + } + 100% { + transform: translateX(0px); + width: 16px; + } +} +/* Modal Content/Box */ +.modalOrd-content-small { + margin: 0.4rem auto; + width: 50%; +} +.modalOrd-content { + margin: 1.4rem auto; + padding-left: 20%; + width: 50%; +} +.modalOrd-content-large { + margin: 2.4rem auto; + padding-left: 20%; + width: 50%; +} \ No newline at end of file diff --git a/EgwCoreLib.Razor/LoadingData.razor.less b/EgwCoreLib.Razor/LoadingData.razor.less new file mode 100644 index 0000000..018a6f2 --- /dev/null +++ b/EgwCoreLib.Razor/LoadingData.razor.less @@ -0,0 +1,147 @@ +.modalOrd { + position: relative; + z-index: 9999; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.6); +} + + +.loader { + width: 5rem; + position: relative; +} + +.loader-text { + position: relative; + top: 0; + padding: 0; + margin: 0; + color: #C8B6FF; + animation: text_713 3.5s ease both infinite; + font-size: .8rem; + letter-spacing: 1px; +} + +.load { + background-color: #9A79FF; + border-radius: 3rem; + display: block; + height: 1rem; + width: 1rem; + bottom: 0; + position: relative; + transform: translateX(64px); + animation: loading_713 3.5s ease both infinite; +} + +.load::before { + position: relative; + content: ""; + width: 100%; + height: 100%; + background-color: #D1C2FF; + border-radius: inherit; + animation: loading2_713 3.5s ease both infinite; +} + +@keyframes text_713 { + 0% { + letter-spacing: 1px; + transform: translateX(0px); + } + + 40% { + letter-spacing: 2px; + transform: translateX(26px); + } + + 80% { + letter-spacing: 1px; + transform: translateX(32px); + } + + 90% { + letter-spacing: 2px; + transform: translateX(0px); + } + + 100% { + letter-spacing: 1px; + transform: translateX(0px); + } +} + +@keyframes loading_713 { + 0% { + width: 16px; + transform: translateX(0px); + } + + 40% { + width: 100%; + transform: translateX(0px); + } + + 80% { + width: 16px; + transform: translateX(64px); + } + + 90% { + width: 100%; + transform: translateX(0px); + } + + 100% { + width: 16px; + transform: translateX(0px); + } +} + +@keyframes loading2_713 { + 0% { + transform: translateX(0px); + width: 16px; + } + + 40% { + transform: translateX(0%); + width: 80%; + } + + 80% { + width: 100%; + transform: translateX(0px); + } + + 90% { + width: 80%; + transform: translateX(15px); + } + + 100% { + transform: translateX(0px); + width: 16px; + } +} + +/* Modal Content/Box */ +.modalOrd-content-small { + margin: 0.4rem auto; + width: 50%; +} +.modalOrd-content { + margin: 1.4rem auto; + padding-left: 20%; + width: 50%; +} +.modalOrd-content-large { + margin: 2.4rem auto; + padding-left: 20%; + width: 50%; +} diff --git a/EgwCoreLib.Razor/LoadingData.razor.min.css b/EgwCoreLib.Razor/LoadingData.razor.min.css new file mode 100644 index 0000000..ce1a088 --- /dev/null +++ b/EgwCoreLib.Razor/LoadingData.razor.min.css @@ -0,0 +1 @@ +.modalOrd{position:relative;z-index:9999;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,.6);}.loader{width:5rem;position:relative;}.loader-text{position:relative;top:0;padding:0;margin:0;color:#c8b6ff;animation:text_713 3.5s ease both infinite;font-size:.8rem;letter-spacing:1px;}.load{background-color:#9a79ff;border-radius:3rem;display:block;height:1rem;width:1rem;bottom:0;position:relative;transform:translateX(64px);animation:loading_713 3.5s ease both infinite;}.load::before{position:relative;content:"";width:100%;height:100%;background-color:#d1c2ff;border-radius:inherit;animation:loading2_713 3.5s ease both infinite;}@keyframes text_713{0%{letter-spacing:1px;transform:translateX(0);}40%{letter-spacing:2px;transform:translateX(26px);}80%{letter-spacing:1px;transform:translateX(32px);}90%{letter-spacing:2px;transform:translateX(0);}100%{letter-spacing:1px;transform:translateX(0);}}@keyframes loading_713{0%{width:16px;transform:translateX(0);}40%{width:100%;transform:translateX(0);}80%{width:16px;transform:translateX(64px);}90%{width:100%;transform:translateX(0);}100%{width:16px;transform:translateX(0);}}@keyframes loading2_713{0%{transform:translateX(0);width:16px;}40%{transform:translateX(0%);width:80%;}80%{width:100%;transform:translateX(0);}90%{width:80%;transform:translateX(15px);}100%{transform:translateX(0);width:16px;}}.modalOrd-content-small{margin:.4rem auto;width:50%;}.modalOrd-content{margin:1.4rem auto;padding-left:20%;width:50%;}.modalOrd-content-large{margin:2.4rem auto;padding-left:20%;width:50%;} \ No newline at end of file diff --git a/EgwCoreLib.Razor/ProgressDisplay.razor b/EgwCoreLib.Razor/ProgressDisplay.razor new file mode 100644 index 0000000..988f338 --- /dev/null +++ b/EgwCoreLib.Razor/ProgressDisplay.razor @@ -0,0 +1,32 @@ +@if (isLoading) +{ + +
+ +
+
+} \ No newline at end of file diff --git a/EgwCoreLib.Razor/ProgressDisplay.razor.cs b/EgwCoreLib.Razor/ProgressDisplay.razor.cs new file mode 100644 index 0000000..db4435b --- /dev/null +++ b/EgwCoreLib.Razor/ProgressDisplay.razor.cs @@ -0,0 +1,223 @@ +using Microsoft.AspNetCore.Components; + +namespace EgwCoreLib.Razor +{ + public partial class ProgressDisplay : IDisposable + { + #region Public Enums + + public enum ModalSize + { + Small, + Medium, + Large + } + + #endregion Public Enums + + #region Public Properties + + /// + /// Valore corrente + /// + [Parameter] + public double CurrVal + { + get => actVal; + set + { + actVal = value; + startVal = value; + isLoading = actVal < MaxVal; + } + } + + /// + /// Dimensioni attese modale + /// default: ModalSize.Medium + /// + [Parameter] + public ModalSize DisplaySize { get; set; } = ModalSize.Medium; + + /// + /// Tempo atteso per prossimo step + /// default: 10000 + /// + [Parameter] + public int ExpTimeMSec { get; set; } = 10000; + + /// + /// Valore massimo ammesso + /// default: 100 + /// + [Parameter] + public double MaxVal { get; set; } = 100; + + /// + /// Style modale + /// default: card + /// alternative: card alert-primary + /// + [Parameter] + public string ModalCss { get; set; } = "card"; + + /// + /// Prossimo valore ammesso (fino al max) + /// default: 100 + /// + [Parameter] + public double NextVal { get; set; } = 100; + + /// + /// Style progressbar + /// default: progress-bar progress-bar-striped progress-bar-animated + /// + [Parameter] + public string ProgressCss { get; set; } = "progress-bar progress-bar-striped progress-bar-animated"; + + /// + /// Intervallo interno per refresh percentuale avanzamento + /// default: 100ms + /// + [Parameter] + public int RefreshInterval { get; set; } = 100; + + /// + /// Indica se mostrare la percentuale vanzamento + /// default: true + /// + [Parameter] + public bool ShowPercent { get; set; } = true; + + /// + /// Numero di secondi prima (rispetto valore ExpTimeMsec) da cui iniziare rallentamento + /// + [Parameter] + public int SlowWindowMSec { get; set; } = 3000; + + //Titolo da mostrare (se "" NON lo mostra) + [Parameter] + public string Title { get; set; } = "Progress"; + + #endregion Public Properties + + #region Public Methods + + public void Dispose() + { + uiTimer?.Dispose(); + } + + #endregion Public Methods + + #region Protected Properties + + protected string modalDialogCss + { + get + { + string answ = "modal-dialog"; + switch (DisplaySize) + { + case ModalSize.Small: + answ = "modal-dialog modal-sm"; + break; + + case ModalSize.Large: + answ = "modal-dialog modal-xl"; + break; + + case ModalSize.Medium: + default: + break; + } + return answ; + } + } + + #endregion Protected Properties + + #region Protected Methods + + protected override async Task OnParametersSetAsync() + { + // salvo valori aggiornamento... + if (ExpTimeMSec > 0) + { + lastUpdate = DateTime.Now; + nextUpdate = lastUpdate.AddMilliseconds(ExpTimeMSec); + await RefreshDisplay(); + } + if (isLoading) + { + uiTimer?.Dispose(); + uiTimer = new PeriodicTimer(TimeSpan.FromMilliseconds(RefreshInterval)); + RunTimer(); + } + else + { + uiTimer = null; + } + } + + #endregion Protected Methods + + #region Private Fields + + private PeriodicTimer? uiTimer = null; + + #endregion Private Fields + + #region Private Properties + + private double actVal { get; set; } = 100; + private string currWidth { get; set; } = ""; + private string displayMsg { get; set; } = "Loading..."; + + private bool isLoading { get; set; } = false; + + private DateTime lastUpdate { get; set; } = DateTime.Now.AddMinutes(-1); + + private DateTime nextUpdate { get; set; } = DateTime.Now; + + private double startVal { get; set; } = 100; + + #endregion Private Properties + + #region Private Methods + + private async Task RefreshDisplay() + { + currWidth = $"{(double)actVal / MaxVal:P0}"; + if (ShowPercent) + { + displayMsg = $"{actVal / MaxVal:P2}"; + } + await InvokeAsync(StateHasChanged); + } + + private async void RunTimer() + { + while (uiTimer != null && await uiTimer.WaitForNextTickAsync()) + { + if (isLoading) + { + DateTime adesso = DateTime.Now; + if (nextUpdate <= adesso.AddMilliseconds(SlowWindowMSec)) + { + nextUpdate = adesso.AddMilliseconds(RefreshInterval); + } + // calcolo delta ms... + var numMs = adesso.Subtract(lastUpdate).TotalMilliseconds; + var denMs = nextUpdate.Subtract(lastUpdate).TotalMilliseconds; + denMs = denMs > 0 ? denMs : 1; + // aggiorno display... + actVal = startVal + (NextVal - startVal) * (numMs / denMs); + await RefreshDisplay(); + } + } + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/EgwCoreLib.Razor/compilerconfig.json b/EgwCoreLib.Razor/compilerconfig.json index 3aa4469..47adeac 100644 --- a/EgwCoreLib.Razor/compilerconfig.json +++ b/EgwCoreLib.Razor/compilerconfig.json @@ -22,5 +22,9 @@ { "outputFile": "CalWeekColumn.razor.css", "inputFile": "CalWeekColumn.razor.less" + }, + { + "outputFile": "LoadingData.razor.css", + "inputFile": "LoadingData.razor.less" } ] \ No newline at end of file