mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 17:02:51 +08:00
parent
1cf30f62fc
commit
7dccb310f3
BIN
docs/input/assets/images/barchart.png
Normal file
BIN
docs/input/assets/images/barchart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
75
docs/input/widgets/barchart.md
Normal file
75
docs/input/widgets/barchart.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
Title: Bar Chart
|
||||||
|
Order: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
Use `BarChart` to render bar charts to the console.
|
||||||
|
|
||||||
|
<img src="../assets/images/barchart.png" style="width: 100%;" />
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
## Basic usage
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
AnsiConsole.Render(new BarChart()
|
||||||
|
.Width(60)
|
||||||
|
.Label("[green bold underline]Number of fruits[/]")
|
||||||
|
.CenterLabel()
|
||||||
|
.AddItem("Apple", 12, Color.Yellow)
|
||||||
|
.AddItem("Orange", 54, Color.Green)
|
||||||
|
.AddItem("Banana", 33, Color.Red));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add items with converter
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Create a list of fruits
|
||||||
|
var items = new List<(string Label, double Value)>
|
||||||
|
{
|
||||||
|
("Apple", 12),
|
||||||
|
("Orange", 54),
|
||||||
|
("Banana", 33),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render bar chart
|
||||||
|
AnsiConsole.Render(new BarChart()
|
||||||
|
.Width(60)
|
||||||
|
.Label("[green bold underline]Number of fruits[/]")
|
||||||
|
.CenterLabel()
|
||||||
|
.AddItems(items, (item) => new BarChartItem(
|
||||||
|
item.Label, item.Value, Color.Yellow)));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add items implementing IBarChartItem
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed class Fruit : IBarChartItem
|
||||||
|
{
|
||||||
|
public string Label { get; set; }
|
||||||
|
public double Value { get; set; }
|
||||||
|
public Color? Color { get; set; }
|
||||||
|
|
||||||
|
public Fruit(string label, double value, Color? color = null)
|
||||||
|
{
|
||||||
|
Label = label;
|
||||||
|
Value = value;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a list of fruits
|
||||||
|
var items = new List<Fruit>
|
||||||
|
{
|
||||||
|
new Fruit("Apple", 12, Color.Yellow),
|
||||||
|
new Fruit("Orange", 54, Color.Red),
|
||||||
|
new Fruit("Banana", 33, Color.Green),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render bar chart
|
||||||
|
AnsiConsole.Render(new BarChart()
|
||||||
|
.Width(60)
|
||||||
|
.Label("[green bold underline]Number of fruits[/]")
|
||||||
|
.CenterLabel()
|
||||||
|
.AddItem(new Fruit("Mango", 3))
|
||||||
|
.AddItems(items));
|
||||||
|
```
|
@ -1,5 +1,5 @@
|
|||||||
Title: Calendar
|
Title: Calendar
|
||||||
Order: 2
|
Order: 3
|
||||||
RedirectFrom: calendar
|
RedirectFrom: calendar
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Title: Canvas Image
|
Title: Canvas Image
|
||||||
Order: 5
|
Order: 6
|
||||||
---
|
---
|
||||||
|
|
||||||
To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to
|
To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Title: Canvas
|
Title: Canvas
|
||||||
Order: 4
|
Order: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
`Canvas` is a widget that allows you to render arbitrary "pixels"
|
`Canvas` is a widget that allows you to render arbitrary "pixels"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Title: Figlet
|
Title: Figlet
|
||||||
Order: 3
|
Order: 4
|
||||||
RedirectFrom: figlet
|
RedirectFrom: figlet
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Title: Rule
|
Title: Rule
|
||||||
Order: 1
|
Order: 2
|
||||||
RedirectFrom: rule
|
RedirectFrom: rule
|
||||||
---
|
---
|
||||||
|
|
||||||
|
15
examples/Charts/Charts.csproj
Normal file
15
examples/Charts/Charts.csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<Title>Charts</Title>
|
||||||
|
<Description>Demonstrates how to render charts in a console.</Description>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
21
examples/Charts/Program.cs
Normal file
21
examples/Charts/Program.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace InfoExample
|
||||||
|
{
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
|
public static void Main()
|
||||||
|
{
|
||||||
|
var chart = new BarChart()
|
||||||
|
.Width(60)
|
||||||
|
.Label("[green bold underline]Number of fruits[/]")
|
||||||
|
.CenterLabel()
|
||||||
|
.AddItem("Apple", 12, Color.Yellow)
|
||||||
|
.AddItem("Orange", 54, Color.Green)
|
||||||
|
.AddItem("Banana", 33, Color.Red);
|
||||||
|
|
||||||
|
AnsiConsole.WriteLine();
|
||||||
|
AnsiConsole.Render(chart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
Number of fruits
|
||||||
|
Apple ████████ 12
|
||||||
|
Orange █████████████████████████████████████████████████ 54
|
||||||
|
Banana ████████████████████████████ 33
|
28
src/Spectre.Console.Tests/Unit/BarChartTests.cs
Normal file
28
src/Spectre.Console.Tests/Unit/BarChartTests.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using VerifyXunit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Spectre.Console.Tests.Unit
|
||||||
|
{
|
||||||
|
[UsesVerify]
|
||||||
|
public sealed class BarChartTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Should_Render_Correctly()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new PlainConsole(width: 80);
|
||||||
|
|
||||||
|
// When
|
||||||
|
console.Render(new BarChart()
|
||||||
|
.Width(60)
|
||||||
|
.Label("Number of fruits")
|
||||||
|
.AddItem("Apple", 12)
|
||||||
|
.AddItem("Orange", 54)
|
||||||
|
.AddItem("Banana", 33));
|
||||||
|
|
||||||
|
// Then
|
||||||
|
await Verifier.Verify(console.Output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -62,6 +62,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Progress", "..\examples\Pro
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Status", "..\examples\Status\Status.csproj", "{3716AFDF-0904-4635-8422-86E6B9356840}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Status", "..\examples\Status\Status.csproj", "{3716AFDF-0904-4635-8422-86E6B9356840}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Charts", "..\examples\Charts\Charts.csproj", "{0A1AFD26-86A0-4060-B277-D380172C7070}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -324,6 +326,18 @@ Global
|
|||||||
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x64.Build.0 = Release|Any CPU
|
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.ActiveCfg = Release|Any CPU
|
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.Build.0 = Release|Any CPU
|
{3716AFDF-0904-4635-8422-86E6B9356840}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -348,6 +362,7 @@ Global
|
|||||||
{5693761A-754A-40A8-9144-36510D6A4D69} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
{5693761A-754A-40A8-9144-36510D6A4D69} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||||
{2B712A52-40F1-4C1C-833E-7C869ACA91F3} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
{2B712A52-40F1-4C1C-833E-7C869ACA91F3} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||||
{3716AFDF-0904-4635-8422-86E6B9356840} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
{3716AFDF-0904-4635-8422-86E6B9356840} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||||
|
{0A1AFD26-86A0-4060-B277-D380172C7070} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
|
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
|
||||||
|
234
src/Spectre.Console/Extensions/BarGraphExtensions.cs
Normal file
234
src/Spectre.Console/Extensions/BarGraphExtensions.cs
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains extension methods for <see cref="BarChart"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class BarGraphExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an item to the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="label">The item label.</param>
|
||||||
|
/// <param name="value">The item value.</param>
|
||||||
|
/// <param name="color">The item color.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart AddItem(this BarChart chart, string label, double value, Color? color = null)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.Data.Add(new BarChartItem(label, value, color));
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an item to the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">A type that implements <see cref="IBarChartItem"/>.</typeparam>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart AddItem<T>(this BarChart chart, T item)
|
||||||
|
where T : IBarChartItem
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.Data.Add(new BarChartItem(
|
||||||
|
item.Label,
|
||||||
|
item.Value,
|
||||||
|
item.Color));
|
||||||
|
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds multiple items to the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">A type that implements <see cref="IBarChartItem"/>.</typeparam>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart AddItems<T>(this BarChart chart, IEnumerable<T> items)
|
||||||
|
where T : IBarChartItem
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
AddItem<T>(chart, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds multiple items to the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">A type that implements <see cref="IBarChartItem"/>.</typeparam>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="items">The items.</param>
|
||||||
|
/// <param name="converter">The converter that converts instances of <c>T</c> to <see cref="BarChartItem"/>.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart AddItems<T>(this BarChart chart, IEnumerable<T> items, Func<T, BarChartItem> converter)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (converter is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(converter));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
chart.Data.Add(converter(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the width of the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="width">The bar chart width.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart Width(this BarChart chart, int? width)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.Width = width;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the label of the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="label">The bar chart label.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart Label(this BarChart chart, string? label)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.Label = label;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows values next to each bar in the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart ShowValues(this BarChart chart)
|
||||||
|
{
|
||||||
|
return ShowValues(chart, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hides values next to each bar in the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart HideValues(this BarChart chart)
|
||||||
|
{
|
||||||
|
return ShowValues(chart, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not values should be shown
|
||||||
|
/// next to each bar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <param name="show">Whether or not values should be shown next to each bar.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart ShowValues(this BarChart chart, bool show)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.ShowValues = show;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aligns the label to the left.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart LeftAlignLabel(this BarChart chart)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.LabelAlignment = Justify.Left;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Centers the label.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart CenterLabel(this BarChart chart)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.LabelAlignment = Justify.Center;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aligns the label to the right.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chart">The bar chart.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static BarChart RightAlignLabel(this BarChart chart)
|
||||||
|
{
|
||||||
|
if (chart is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(chart));
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.LabelAlignment = Justify.Right;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -97,5 +97,22 @@ namespace Spectre.Console
|
|||||||
grid.AddRow(columns.Select(column => new Markup(column)).ToArray());
|
grid.AddRow(columns.Select(column => new Markup(column)).ToArray());
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the grid width.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid">The grid.</param>
|
||||||
|
/// <param name="width">The width.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static Grid Width(this Grid grid, int? width)
|
||||||
|
{
|
||||||
|
if (grid is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(grid));
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.Width = width;
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ namespace Spectre.Console
|
|||||||
/// <param name="table">The table.</param>
|
/// <param name="table">The table.</param>
|
||||||
/// <param name="width">The width.</param>
|
/// <param name="width">The width.</param>
|
||||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
public static Table Width(this Table table, int width)
|
public static Table Width(this Table table, int? width)
|
||||||
{
|
{
|
||||||
if (table is null)
|
if (table is null)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Spectre.Console.Rendering
|
namespace Spectre.Console.Rendering
|
||||||
{
|
{
|
||||||
@ -8,12 +9,14 @@ namespace Spectre.Console.Rendering
|
|||||||
public abstract class Renderable : IRenderable
|
public abstract class Renderable : IRenderable
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
[DebuggerStepThrough]
|
||||||
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
Measurement IRenderable.Measure(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
return Measure(context, maxWidth);
|
return Measure(context, maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
[DebuggerStepThrough]
|
||||||
IEnumerable<Segment> IRenderable.Render(RenderContext context, int maxWidth)
|
IEnumerable<Segment> IRenderable.Render(RenderContext context, int maxWidth)
|
||||||
{
|
{
|
||||||
return Render(context, maxWidth);
|
return Render(context, maxWidth);
|
||||||
|
82
src/Spectre.Console/Widgets/BarChart.cs
Normal file
82
src/Spectre.Console/Widgets/BarChart.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A renderable (horizontal) bar chart.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BarChart : Renderable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bar chart data.
|
||||||
|
/// </summary>
|
||||||
|
public List<BarChartItem> Data { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of the bar chart.
|
||||||
|
/// </summary>
|
||||||
|
public int? Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the bar chart label.
|
||||||
|
/// </summary>
|
||||||
|
public string? Label { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the bar chart label alignment.
|
||||||
|
/// </summary>
|
||||||
|
public Justify? LabelAlignment { get; set; } = Justify.Center;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not
|
||||||
|
/// values should be shown next to each bar.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowValues { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BarChart"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BarChart()
|
||||||
|
{
|
||||||
|
Data = new List<BarChartItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||||
|
{
|
||||||
|
var maxValue = Data.Max(item => item.Value);
|
||||||
|
|
||||||
|
var table = new Grid();
|
||||||
|
table.Collapse();
|
||||||
|
table.AddColumn(new GridColumn().PadRight(2).RightAligned());
|
||||||
|
table.AddColumn(new GridColumn().PadLeft(0));
|
||||||
|
table.Width = Width;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Label))
|
||||||
|
{
|
||||||
|
table.AddRow(Text.Empty, new Markup(Label).Alignment(LabelAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in Data)
|
||||||
|
{
|
||||||
|
table.AddRow(
|
||||||
|
new Markup(item.Label),
|
||||||
|
new ProgressBar()
|
||||||
|
{
|
||||||
|
Value = item.Value,
|
||||||
|
MaxValue = maxValue,
|
||||||
|
ShowRemaining = false,
|
||||||
|
CompletedStyle = new Style().Foreground(item.Color ?? Color.Default),
|
||||||
|
FinishedStyle = new Style().Foreground(item.Color ?? Color.Default),
|
||||||
|
UnicodeBar = '█',
|
||||||
|
AsciiBar = '█',
|
||||||
|
ShowValue = ShowValues,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((IRenderable)table).Render(context, maxWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
src/Spectre.Console/Widgets/BarChartItem.cs
Normal file
38
src/Spectre.Console/Widgets/BarChartItem.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An item that's shown in a bar chart.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BarChartItem : IBarChartItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item label.
|
||||||
|
/// </summary>
|
||||||
|
public string Label { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item value.
|
||||||
|
/// </summary>
|
||||||
|
public double Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item color.
|
||||||
|
/// </summary>
|
||||||
|
public Color? Color { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BarChartItem"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="label">The item label.</param>
|
||||||
|
/// <param name="value">The item value.</param>
|
||||||
|
/// <param name="color">The item color.</param>
|
||||||
|
public BarChartItem(string label, double value, Color? color = null)
|
||||||
|
{
|
||||||
|
Label = label ?? throw new ArgumentNullException(nameof(label));
|
||||||
|
Value = value;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,11 @@ namespace Spectre.Console
|
|||||||
set => MarkAsDirty(() => _alignment = value);
|
set => MarkAsDirty(() => _alignment = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of the grid.
|
||||||
|
/// </summary>
|
||||||
|
public int? Width { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Grid"/> class.
|
/// Initializes a new instance of the <see cref="Grid"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -124,6 +129,7 @@ namespace Spectre.Console
|
|||||||
ShowHeaders = false,
|
ShowHeaders = false,
|
||||||
IsGrid = true,
|
IsGrid = true,
|
||||||
PadRightCell = _padRightCell,
|
PadRightCell = _padRightCell,
|
||||||
|
Width = Width,
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var column in _columns)
|
foreach (var column in _columns)
|
||||||
|
23
src/Spectre.Console/Widgets/IBarGraphItem.cs
Normal file
23
src/Spectre.Console/Widgets/IBarGraphItem.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
namespace Spectre.Console
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a bar chart item.
|
||||||
|
/// </summary>
|
||||||
|
public interface IBarChartItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item label.
|
||||||
|
/// </summary>
|
||||||
|
string Label { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item value.
|
||||||
|
/// </summary>
|
||||||
|
double Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the item color.
|
||||||
|
/// </summary>
|
||||||
|
Color? Color { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
@ -10,6 +11,10 @@ namespace Spectre.Console
|
|||||||
public double MaxValue { get; set; } = 100;
|
public double MaxValue { get; set; } = 100;
|
||||||
|
|
||||||
public int? Width { get; set; }
|
public int? Width { get; set; }
|
||||||
|
public bool ShowRemaining { get; set; } = true;
|
||||||
|
public char UnicodeBar { get; set; } = '━';
|
||||||
|
public char AsciiBar { get; set; } = '-';
|
||||||
|
public bool ShowValue { get; set; }
|
||||||
|
|
||||||
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow);
|
public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow);
|
||||||
public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green);
|
public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green);
|
||||||
@ -26,15 +31,38 @@ namespace Spectre.Console
|
|||||||
var width = Math.Min(Width ?? maxWidth, maxWidth);
|
var width = Math.Min(Width ?? maxWidth, maxWidth);
|
||||||
var completed = Math.Min(MaxValue, Math.Max(0, Value));
|
var completed = Math.Min(MaxValue, Math.Max(0, Value));
|
||||||
|
|
||||||
var token = !context.Unicode || context.LegacyConsole ? '-' : '━';
|
var token = !context.Unicode || context.LegacyConsole ? AsciiBar : UnicodeBar;
|
||||||
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
|
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
|
||||||
|
|
||||||
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));
|
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));
|
||||||
|
|
||||||
|
var value = completed.ToString(CultureInfo.InvariantCulture);
|
||||||
|
if (ShowValue)
|
||||||
|
{
|
||||||
|
bars = bars - value.Length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
yield return new Segment(new string(token, bars), style);
|
yield return new Segment(new string(token, bars), style);
|
||||||
|
|
||||||
|
if (ShowValue)
|
||||||
|
{
|
||||||
|
yield return new Segment(" " + value, style);
|
||||||
|
}
|
||||||
|
|
||||||
if (bars < width)
|
if (bars < width)
|
||||||
{
|
{
|
||||||
yield return new Segment(new string(token, width - bars), RemainingStyle);
|
var diff = width - bars;
|
||||||
|
if (ShowValue)
|
||||||
|
{
|
||||||
|
diff = diff - value.Length - 1;
|
||||||
|
if (diff <= 0)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var remainingToken = ShowRemaining ? token : ' ';
|
||||||
|
yield return new Segment(new string(remainingToken, diff), RemainingStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user