Private/Console/Charts.psm1
|
using namespace System using namespace System.Collections.Generic using module ..\Enums.psm1 using module ..\Abstracts.psm1 using module .\Colors.psm1 using module .\Rendering.psm1 class BarChartItem { [string]$Label [double]$Value [Color]$Color BarChartItem([string]$label, [double]$value, [Color]$color) { $this.Label = $label $this.Value = $value $this.Color = if ($null -ne $color) { $color } else { [Color]::Default } } } class BarChart : IRenderable { [List[BarChartItem]]$Items = [List[BarChartItem]]::new() [int]$Width = 40 [string]$ValueFormat = '0.##' [BarChart] AddItem([string]$label, [double]$value, [Color]$color) { $this.Items.Add([BarChartItem]::new($label, $value, $color)) return $this } [Measurement] Measure([RenderOptions]$options, [int]$maxWidth) { return [Measurement]::new(0, [Math]::Min([Math]::Max(1, $this.Width + 20), $maxWidth)) } [object[]] Render([RenderOptions]$options, [int]$maxWidth) { if ($this.Items.Count -eq 0) { return [Segment[]]@([Segment]::new('(empty chart)')) } $max = ($this.Items | Measure-Object -Property Value -Maximum).Maximum if ($max -le 0) { $max = 1 } $labelWidth = ($this.Items | ForEach-Object { $_.Label.Length } | Measure-Object -Maximum).Maximum $barWidth = [Math]::Max(1, [Math]::Min($this.Width, $maxWidth - $labelWidth - 10)) $segments = [List[Segment]]::new() for ($i = 0; $i -lt $this.Items.Count; $i++) { $it = $this.Items[$i] $cells = [Math]::Round(($it.Value / $max) * $barWidth) $bar = ('█' * [Math]::Max(0, $cells)).PadRight($barWidth, ' ') $line = ('{0,-' + $labelWidth + '} {1} {2}') -f $it.Label, $bar, $it.Value.ToString($this.ValueFormat) $style = [Style]::new($it.Color) $segments.Add([Segment]::new($line, $style)) if ($i -lt $this.Items.Count - 1) { $segments.Add([Segment]::LineBreak) } } return $segments.ToArray() } } class BreakdownChartItem { [string]$Label [double]$Value [Color]$Color BreakdownChartItem([string]$label, [double]$value, [Color]$color) { $this.Label = $label $this.Value = $value $this.Color = if ($null -ne $color) { $color } else { [Color]::Default } } } class BreakdownChart : IRenderable { [List[BreakdownChartItem]]$Items = [List[BreakdownChartItem]]::new() [BreakdownChart] AddItem([string]$label, [double]$value, [Color]$color) { $this.Items.Add([BreakdownChartItem]::new($label, $value, $color)) return $this } [Measurement] Measure([RenderOptions]$options, [int]$maxWidth) { return [Measurement]::new(0, $maxWidth) } [object[]] Render([RenderOptions]$options, [int]$maxWidth) { if ($this.Items.Count -eq 0) { return [Segment[]]@([Segment]::new('(empty breakdown)')) } $total = ($this.Items | Measure-Object -Property Value -Sum).Sum if ($total -le 0) { $total = 1 } $segments = [List[Segment]]::new() for ($i = 0; $i -lt $this.Items.Count; $i++) { $it = $this.Items[$i] $percent = ($it.Value / $total) * 100 $line = '{0}: {1:0.##}% ({2:0.##})' -f $it.Label, $percent, $it.Value $segments.Add([Segment]::new($line, [Style]::new($it.Color))) if ($i -lt $this.Items.Count - 1) { $segments.Add([Segment]::LineBreak) } } return $segments.ToArray() } } |