Update charts only after render, avoid registering multiple timers. Format axes
parent
d24063b545
commit
d09ecb3efb
|
@ -1,45 +1,66 @@
|
||||||
@using System.Diagnostics;
|
@using System.Diagnostics;
|
||||||
@using LANCommander.Extensions;
|
@using LANCommander.Extensions;
|
||||||
@using AntDesign.Charts;
|
@using AntDesign.Charts;
|
||||||
<Line @ref="Chart" Config="Config" />
|
@using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
<Area @ref="Chart" Config="Config" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public int TimerHistory { get; set; }
|
[Parameter] public int TimerHistory { get; set; }
|
||||||
[Parameter] public int TimerInterval { get; set; }
|
[Parameter] public int TimerInterval { get; set; }
|
||||||
|
|
||||||
IChartComponent? Chart;
|
IChartComponent? Chart;
|
||||||
|
System.Timers.Timer Timer;
|
||||||
|
|
||||||
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
||||||
|
|
||||||
Dictionary<string, PerformanceCounter> PerformanceCounters = new Dictionary<string, PerformanceCounter>();
|
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
|
||||||
|
|
||||||
LineConfig Config = new LineConfig
|
string JsConfig = @"{
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
alias: 'Speed',
|
||||||
|
formatter: (v) => humanFileSize(v, true) + '/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
AreaConfig Config = new AreaConfig
|
||||||
{
|
{
|
||||||
Name = "Network Download Rate",
|
Name = "Network Download Rate",
|
||||||
Padding = "auto",
|
Padding = "auto",
|
||||||
SeriesField = "Series",
|
SeriesField = "series",
|
||||||
YField = "Value",
|
YField = "value",
|
||||||
XField = "Index",
|
XField = "index",
|
||||||
|
Animation = false,
|
||||||
XAxis = new ValueCatTimeAxis
|
XAxis = new ValueCatTimeAxis
|
||||||
{
|
{
|
||||||
Type = "dateTime",
|
Visible = false
|
||||||
TickCount = 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var timer = new System.Timers.Timer();
|
if (Timer == null)
|
||||||
|
{
|
||||||
|
Timer = new System.Timers.Timer();
|
||||||
|
|
||||||
timer.Interval = TimerInterval;
|
Timer.Interval = TimerInterval;
|
||||||
|
|
||||||
timer.Elapsed += async (s, e) =>
|
Timer.Elapsed += async (s, e) =>
|
||||||
{
|
{
|
||||||
await RefreshData();
|
await RefreshData();
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timer.Start();
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
await Chart.UpdateChart(Config, null, null, JsConfig);
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshData()
|
private async Task RefreshData()
|
||||||
|
@ -57,6 +78,6 @@
|
||||||
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { Value = y, Index = i, Series = x.Key })), true);
|
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,66 @@
|
||||||
@using System.Diagnostics;
|
@using System.Diagnostics;
|
||||||
@using LANCommander.Extensions;
|
@using LANCommander.Extensions;
|
||||||
@using AntDesign.Charts;
|
@using AntDesign.Charts;
|
||||||
<Line @ref="Chart" Config="Config" />
|
@using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
<Area @ref="Chart" Config="Config" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public int TimerHistory { get; set; }
|
[Parameter] public int TimerHistory { get; set; }
|
||||||
[Parameter] public int TimerInterval { get; set; }
|
[Parameter] public int TimerInterval { get; set; }
|
||||||
|
|
||||||
IChartComponent? Chart;
|
IChartComponent? Chart;
|
||||||
|
System.Timers.Timer Timer;
|
||||||
|
|
||||||
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
|
||||||
|
|
||||||
Dictionary<string, PerformanceCounter> PerformanceCounters = new Dictionary<string, PerformanceCounter>();
|
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
|
||||||
|
|
||||||
LineConfig Config = new LineConfig
|
string JsConfig = @"{
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
alias: 'Speed',
|
||||||
|
formatter: (v) => humanFileSize(v, true) + '/s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
AreaConfig Config = new AreaConfig
|
||||||
{
|
{
|
||||||
Name = "Network Upload Rate",
|
Name = "Network Upload Rate",
|
||||||
Padding = "auto",
|
Padding = "auto",
|
||||||
SeriesField = "Series",
|
SeriesField = "series",
|
||||||
YField = "Value",
|
YField = "value",
|
||||||
XField = "Index",
|
XField = "index",
|
||||||
|
Animation = false,
|
||||||
XAxis = new ValueCatTimeAxis
|
XAxis = new ValueCatTimeAxis
|
||||||
{
|
{
|
||||||
Type = "dateTime",
|
Visible = false
|
||||||
TickCount = 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var timer = new System.Timers.Timer();
|
if (Timer == null)
|
||||||
|
{
|
||||||
|
Timer = new System.Timers.Timer();
|
||||||
|
|
||||||
timer.Interval = TimerInterval;
|
Timer.Interval = TimerInterval;
|
||||||
|
|
||||||
timer.Elapsed += async (s, e) =>
|
Timer.Elapsed += async (s, e) =>
|
||||||
{
|
{
|
||||||
await RefreshData();
|
await RefreshData();
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timer.Start();
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
await Chart.UpdateChart(Config, null, null, JsConfig);
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshData()
|
private async Task RefreshData()
|
||||||
|
@ -57,6 +78,6 @@
|
||||||
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { Value = y, Index = i, Series = x.Key })), true);
|
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,75 @@
|
||||||
@using System.Diagnostics;
|
@using System.Diagnostics;
|
||||||
@using LANCommander.Extensions;
|
@using LANCommander.Extensions;
|
||||||
@using AntDesign.Charts;
|
@using AntDesign.Charts;
|
||||||
<Line @ref="Chart" Config="Config" />
|
|
||||||
|
<Area @ref="Chart" Config="Config" />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public int TimerHistory { get; set; }
|
[Parameter] public int TimerHistory { get; set; }
|
||||||
[Parameter] public int TimerInterval { get; set; }
|
[Parameter] public int TimerInterval { get; set; }
|
||||||
IChartComponent? Chart;
|
IChartComponent? Chart;
|
||||||
|
System.Timers.Timer Timer;
|
||||||
|
|
||||||
double[] Data;
|
double[] Data;
|
||||||
|
|
||||||
PerformanceCounter PerformanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
PerformanceCounter PerformanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
||||||
|
|
||||||
LineConfig Config = new LineConfig
|
string JsConfig = @"{
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
alias: '% Usage',
|
||||||
|
formatter: (v) => v + '%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
AreaConfig Config = new AreaConfig
|
||||||
{
|
{
|
||||||
Name = "Processor Utilization",
|
Name = "Processor Utilization",
|
||||||
Padding = "auto",
|
Padding = "auto",
|
||||||
YField = "Value",
|
YField = "value",
|
||||||
XField = "Index",
|
XField = "index",
|
||||||
|
Animation = false,
|
||||||
|
IsPercent = true,
|
||||||
|
YAxis = new ValueAxis
|
||||||
|
{
|
||||||
|
Min = 0,
|
||||||
|
Max = 100
|
||||||
|
},
|
||||||
XAxis = new ValueCatTimeAxis
|
XAxis = new ValueCatTimeAxis
|
||||||
{
|
{
|
||||||
Type = "dateTime",
|
Visible = false
|
||||||
TickCount = 1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var timer = new System.Timers.Timer();
|
if (Timer == null)
|
||||||
|
{
|
||||||
|
Timer = new System.Timers.Timer();
|
||||||
|
|
||||||
timer.Interval = TimerInterval;
|
Timer.Interval = TimerInterval;
|
||||||
|
|
||||||
timer.Elapsed += async (s, e) =>
|
Timer.Elapsed += async (s, e) =>
|
||||||
{
|
{
|
||||||
await RefreshData();
|
await RefreshData();
|
||||||
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
timer.Start();
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
await Chart.UpdateChart(Config, null, null, JsConfig);
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshData()
|
private async Task RefreshData()
|
||||||
{
|
{
|
||||||
Data = Data.ShiftArrayAndInsert((double)PerformanceCounter.NextValue(), TimerHistory);
|
Data = Data.ShiftArrayAndInsert((double)Math.Ceiling(PerformanceCounter.NextValue()), TimerHistory);
|
||||||
|
|
||||||
await Chart.ChangeData(Data.Select((x, i) => new { Value = x, Index = i }), true);
|
await Chart.ChangeData(Data.Select((x, i) => new { value = x, index = i }), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
@using AntDesign.Charts
|
||||||
|
@using ByteSizeLib
|
||||||
|
|
||||||
|
<Pie Data="Data" Config="Config" JsConfig="@JsConfig" />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
object[] Data;
|
||||||
|
|
||||||
|
string JsConfig = @"{
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
alias: 'Data Usage',
|
||||||
|
formatter: (v) => humanFileSize(v, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
visible: true,
|
||||||
|
type: 'outer-center'
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
PieConfig Config = new PieConfig
|
||||||
|
{
|
||||||
|
Radius = 0.8,
|
||||||
|
AngleField = "value",
|
||||||
|
ColorField = "type",
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var drives = DriveInfo.GetDrives();
|
||||||
|
var root = Path.GetPathRoot(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||||
|
|
||||||
|
var totalStorageSize = drives.Where(d => d.IsReady && d.Name == root).Sum(d => d.TotalSize);
|
||||||
|
var totalAvailableFreeSpace = drives.Where(d => d.IsReady && d.Name == root).Sum(d => d.AvailableFreeSpace);
|
||||||
|
var totalUploadDirectorySize = new DirectoryInfo("Upload").EnumerateFiles().Sum(f => f.Length);
|
||||||
|
var totalSaveDirectorySize = new DirectoryInfo("Save").EnumerateFiles().Sum(f => f.Length);
|
||||||
|
|
||||||
|
Data = new object[]
|
||||||
|
{
|
||||||
|
new {
|
||||||
|
type = "Free",
|
||||||
|
value = totalAvailableFreeSpace
|
||||||
|
},
|
||||||
|
new {
|
||||||
|
type = "Games",
|
||||||
|
value = totalUploadDirectorySize
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
type = "Saves",
|
||||||
|
value = totalSaveDirectorySize
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
type = "Other",
|
||||||
|
value = totalStorageSize - totalAvailableFreeSpace - totalUploadDirectorySize - totalSaveDirectorySize
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,39 @@
|
||||||
@page "/Dashboard"
|
@page "/"
|
||||||
|
@page "/Dashboard"
|
||||||
@using LANCommander.Pages.Dashboard.Charts
|
@using LANCommander.Pages.Dashboard.Charts
|
||||||
|
|
||||||
<NetworkDownloadRate TimerHistory="60" TimerInterval="1000" />
|
<PageHeader Title="Dashboard" Style="margin-bottom: 24px" />
|
||||||
<NetworkUploadRate TimerHistory="60" TimerInterval="1000" />
|
|
||||||
<ProcessorUtilization TimerHistory="60" TimerInterval="1000" />
|
|
||||||
|
|
||||||
@code {
|
<GridRow Gutter="(16, 16)">
|
||||||
|
<GridCol Sm="24" Md="12">
|
||||||
|
<Card Title="Network Upload Rate">
|
||||||
|
<Body>
|
||||||
|
<NetworkDownloadRate TimerHistory="60" TimerInterval="1000" />
|
||||||
|
</Body>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
|
||||||
}
|
<GridCol Sm="24" Md="12">
|
||||||
|
<Card Title="Network Download Rate">
|
||||||
|
<Body>
|
||||||
|
<NetworkUploadRate TimerHistory="60" TimerInterval="1000" />
|
||||||
|
</Body>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
|
||||||
|
<GridCol Sm="24" Md="12">
|
||||||
|
<Card Title="CPU Usage (%)">
|
||||||
|
<Body>
|
||||||
|
<ProcessorUtilization TimerHistory="60" TimerInterval="1000" />
|
||||||
|
</Body>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
|
||||||
|
<GridCol Sm="24" Md="12">
|
||||||
|
<Card Title="Storage Usage">
|
||||||
|
<Body>
|
||||||
|
<StorageUsage />
|
||||||
|
</Body>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
</GridRow>
|
|
@ -29,5 +29,6 @@
|
||||||
<script src="~/_content/BlazorMonaco/jsInterop.js"></script>
|
<script src="~/_content/BlazorMonaco/jsInterop.js"></script>
|
||||||
<script src="~/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script>
|
<script src="~/_content/BlazorMonaco/lib/monaco-editor/min/vs/loader.js"></script>
|
||||||
<script src="~/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
|
<script src="~/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.js"></script>
|
||||||
|
<script src="~/js/site.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,3 +2,24 @@
|
||||||
// for details on configuring this project to bundle and minify static web assets.
|
// for details on configuring this project to bundle and minify static web assets.
|
||||||
|
|
||||||
// Write your JavaScript code.
|
// Write your JavaScript code.
|
||||||
|
function humanFileSize(bytes, si = false, dp = 1) {
|
||||||
|
const thresh = si ? 1000 : 1024;
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < thresh) {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
let u = -1;
|
||||||
|
const r = 10 ** dp;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||||
|
|
||||||
|
|
||||||
|
return bytes.toFixed(dp) + ' ' + units[u];
|
||||||
|
}
|
Loading…
Reference in New Issue