Add-XLChart.ps1
function Add-XLChart { [OutputType([XLChart])] [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline=$true)] [XLSheet]$Sheet, [string]$Header, [OfficeOpenXml.Drawing.Chart.eChartType]$Type, [string]$XSeries, [int]$Row = 1, [int]$Column = 1, [int]$Width = 800, [int]$Height = 480, [System.Collections.IDictionary]$Options = @{}, [Switch]$PassThru = $false, [Scriptblock]$With = $null ); begin {} process { $worksheet = $Sheet.Worksheet $chart = $worksheet.Drawings.AddChart("Chart" + [Guid]::NewGuid().ToString('n'), $Type) $chart.Title.Text = $Header $chart.SetPosition($Row, 0, $Column, 0) $chart.SetSize($Width, $Height) # TODO this kinda sucks if ([bool]$Options['ShowPercent']) { $chart.DataLabel.ShowPercent= $true } if ([bool]$Options['ShowValue']) { $chart.DataLabel.ShowValue = $true } if ([bool]$Options['NoLegend']) { $chart.Legend.Remove(); } if ([bool]$Options['HideYAxis']) { $chart.YAxis.Deleted = $true; $chart.YAxis.MajorTickMark = [OfficeOpenXml.Drawing.Chart.eAxisTickMark]::None; $chart.YAxis.MinorTickMark = [OfficeOpenXml.Drawing.Chart.eAxisTickMark]::None; # TODO this deletes all majorGridLines which I'm pretty sure is not correct $chartXml = $chart.ChartXml; $nsuri = $chartXml.DocumentElement.NamespaceURI; $nsm = [System.Xml.XmlNamespaceManager]::new($chartXml.NameTable); $nsm.AddNamespace("c", $nsuri); $gridLines = $chartXml.SelectNodes('//c:majorGridlines', $nsm) $null = $gridLines | ForEach-Object -Process {$_.ParentNode.RemoveChild($_);} } if (-not [bool]$Options['XAxisBetweenTicks'] -and $chart.YAxis -is [OfficeOpenXml.Drawing.Chart.ExcelChartAxis]) { # TODO not sure why this has to be set on the YAxis, makes little sense $chart.YAxis.CrossBetween = [OfficeOpenXml.Drawing.Chart.eCrossBetween]::MidCat } $xlChart = [XLChart]::new($Sheet.Owner, $chart) if (-not [string]::IsNullOrEmpty($XSeries)) { $xlChart.XSeries = $XSeries } if ($With -ne $null) { $null = $xlChart | ForEach-Object -Process $With } if ($PassThru.IsPresent) { $Sheet; } elseif ($With -eq $null) { $xlChart; } } end {} } #TODO add parameter sets so Type can be typed but still optional function Add-XLChartSeries { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline=$true)] [XLChart]$Chart, [object]$Header = $null, [string]$XSeries, [Parameter(Mandatory = $true)] [string]$YSeries, [switch]$Secondary = $false, [object]$Type = $null, [switch]$PassThru = $false ) begin{} process{ $excelChart = $Chart.Chart; if ($XSeries -eq '') { $XSeries = $Chart.XSeries; } if ($XSeries -eq '') { throw "XSeries was not provided and the chart doesn't have one specified." } $currentChart = $null if ($Type -eq $null) { if ($excelChart.UseSecondaryAxis -eq $Secondary.IsPresent) { $currentChart = $excelChart } else { # no type is defined, and the base chart doesn't match, we don't have a suitable chart to operate on throw "Type is not specified and the XLChart provided settings incompatible with the current series." } } else { # find matching subchart $currentChart = @($excelChart.PlotArea.ChartTypes | Where-Object -FilterScript { $_.ChartType -eq [OfficeOpenXml.Drawing.Chart.eChartType]$Type -and $_.UseSecondaryAxis -eq $Secondary.IsPresent}) if ($currentChart.Count -gt 0) { if ($currentChart.Count -gt 1) { Write-Warning "Multiple matching charts found, picking the first one. Request new feature if you need to be able specify an explicit sub-chart." } $currentChart = $currentChart[0] } else { $currentChart = $excelChart.PlotArea.ChartTypes.Add([OfficeOpenXml.Drawing.Chart.eChartType]$Type) } } $series = $currentChart.Series.Add($YSeries, $XSeries) if ($Header -ne $null) { $series.Header = [string]$Header } if ($Secondary.IsPresent) { $currentChart.UseSecondaryAxis = $true } if ($PassThru.IsPresent) { $Chart } } end{} } |