MAUI.GoogleChartsView is a user-friendly charting control designed for .NET MAUI applications. By harnessing the capabilities of Google Charts, it offers customizable data visualizations to suit a wide range of data types. Supports chart events, PNG export, and platform-specific gallery saving.
$ dotnet add package Plugin.MAUI.GoogleChartsViewMAUI.GoogleChartsView is a user-friendly charting control designed for .NET MAUI applications. By harnessing the capabilities of Google Charts, it offers customizable data visualizations to suit a wide range of data types. This library is an ideal choice for developers who aim to create visually engaging and informative charts in their .NET MAUI applications while avoiding the complexities associated with building charting solutions from the ground up.
Install the Plugin.MAUI.GoogleChartsView NuGet package in your .NET MAUI project:
dotnet add package Plugin.MAUI.GoogleChartsViewAdd the GoogleChartsView control to your page:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:charts="clr-namespace:MAUI.GoogleChartsView;assembly=MAUI.GoogleChartsView"
x:Class="MyApp.MainPage">
<StackLayout>
<charts:GoogleChartsView x:Name="MyChart"
WidthRequest="400"
HeightRequest="300"
ChartReady="OnChartReady"
ChartSelected="OnChartSelected"
ChartError="OnChartError" />
<Button Text="Export to Gallery" Clicked="OnExportClicked" />
</StackLayout>
</ContentPage>using MAUI.GoogleChartsView;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SetupChart();
}
private void SetupChart()
{
// Use ChartDataBuilder for easy data construction
var data = ChartDataBuilder.Create()
.AddStringColumn("Year")
.AddNumberColumn("Sales")
.AddNumberColumn("Expenses")
.AddRow("2021", 1000, 400)
.AddRow("2022", 1170, 460)
.AddRow("2023", 660, 1120)
.AddRow("2024", 1030, 540)
.Build();
// Use ChartOptionsBuilder for easy options configuration
var options = ChartOptionsBuilder.Create()
.Title("Company Performance")
.SmoothLines()
.Legend("bottom")
.BackgroundColor("#f5f5f5")
.Colors("#2196F3", "#FF5722")
.HAxis(title: "Year")
.VAxis(title: "Amount")
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.LineChart); // Type-safe!
MyChart.Options = options;
MyChart.EnableAnimation = true;
MyChart.AnimationDuration = 1000;
}
private void OnChartReady(object sender, EventArgs e)
{
Console.WriteLine("Chart is ready!");
}
private void OnChartSelected(object sender, ChartSelectionEventArgs e)
{
Console.WriteLine($"Selected: Row {e.Row}, Column {e.Column}");
}
private void OnChartError(object sender, ChartErrorEventArgs e)
{
Console.WriteLine($"Error: {e.ErrorType} - {e.Message}");
}
private async void OnExportClicked(object sender, EventArgs e)
{
try
{
// Save to device gallery
var path = await ChartImageSaver.SaveToGalleryAsync(
await MyChart.GetChartImageAsync(),
"MyChart.png");
await DisplayAlert("Success", $"Chart saved to: {path}", "OK");
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.Message, "OK");
}
}
}// Method 1: Get image as data URI
var imageDataUri = await myChart.GetChartImageAsync();
// Method 2: Save to specific file path
await myChart.SaveChartImageAsync("/path/to/chart.png");
// Method 3: Save to device gallery (platform-specific)
var savedPath = await ChartImageSaver.SaveToGalleryAsync(imageDataUri, "chart.png");
// Method 4: Get raw bytes for custom handling
byte[] imageBytes = ChartImageSaver.GetImageBytes(imageDataUri);
// Method 5: Get as stream
Stream imageStream = ChartImageSaver.GetImageStream(imageDataUri);| Property | Type | Default | Description |
|---|---|---|---|
| ChartType | string | null | Google Charts type (LineChart, PieChart, BarChart, etc.) |
| Data | object | null | Chart data in Google Charts DataTable format |
| Options | object | null | Chart configuration options |
| EnableAnimation | bool | true | Enable chart animations |
| AnimationDuration | int | 1000 | Animation duration in milliseconds |
| ChartTitle | string | "Chart Title" | Chart title text |
| RefreshIntervalMinutes | int | 10 | Auto-refresh interval |
| ZoomEnabled | bool | true | Enable/disable zoom functionality |
| IsChartReady | bool | false | Read-only: indicates if chart has finished rendering |
| Event | EventArgs | Description |
|---|---|---|
| ChartReady | EventArgs | Fired when chart finishes rendering |
| ChartSelected | ChartSelectionEventArgs | Fired when user selects a chart element |
| ChartClicked | ChartClickEventArgs | Fired when user clicks on chart |
| ChartError | ChartErrorEventArgs | Fired when an error occurs |
| ChartImageReady | ChartImageEventArgs | Fired when image export completes |
Use the ChartType enum for type-safe chart selection with automatic package loading:
// Type-safe chart selection
myChart.SetChartType(ChartType.LineChart);
myChart.SetChartType(ChartType.Sankey); // Auto-loads sankey package
myChart.SetChartType(ChartType.Timeline); // Auto-loads timeline packageStandard chart types - all loaded with a single package:
| Chart Type | Description |
|---|---|
| LineChart | Line graphs with optional smooth curves |
| AreaChart | Filled area under lines |
| ColumnChart | Vertical bar charts |
| BarChart | Horizontal bar charts |
| PieChart | Pie/donut charts (use PieHole for donut) |
| ScatterChart | X-Y scatter plots |
| ComboChart | Mix of bars and lines |
| SteppedAreaChart | Stepped/staircase area charts |
| BubbleChart | Scatter with bubble sizes |
| Histogram | Distribution frequency charts |
| CandlestickChart | Financial OHLC charts |
Each loads its own package automatically:
| Chart Type | Package | Description |
|---|---|---|
| Gauge | gauge | Speedometer-style gauges |
| Sankey | sankey | Flow diagrams showing relationships |
| Table | table | Interactive sortable data tables |
| TreeMap | treemap | Hierarchical data as nested rectangles |
| Calendar | calendar | Heat map calendar visualization |
| Gantt | gantt | Project timeline with dependencies |
| OrgChart | orgchart | Organizational hierarchy diagrams |
| GeoChart | geochart | Geographic data on maps |
| Timeline | timeline | Event timelines |
| WordTree | wordtree | Word relationship trees |
| Option | Description | Supported Types |
|---|---|---|
| title | Chart title displayed above | All |
| curveType | Line curve style ("function" for smooth) | LineChart |
| legend | Legend configuration | All |
| backgroundColor | Chart background color | All |
| colors | Array of series colors | All |
| fontSize | Default font size | All |
| fontName | Default font family | All |
| lineWidth | Line width in pixels | LineChart, AreaChart |
| pointSize | Point diameter in pixels | LineChart, AreaChart |
| hAxis | Horizontal axis configuration | All |
| vAxis | Vertical axis configuration | All |
| chartArea | Drawing area size/position | All |
| tooltip | Tooltip configuration | All |
| animation | Animation settings | All |
| is3D | Enable 3D rendering | PieChart, BarChart |
| pieHole | Donut chart hole size (0-1) | PieChart |
| orientation | Chart orientation | BarChart |
| explorer | Pan/zoom configuration | LineChart, AreaChart |
| trendlines | Trendline configuration | ScatterChart, ColumnChart |
Add to AndroidManifest.xml for gallery saving:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />Add to Info.plist for photo library access:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app saves chart images to your photo library.</string>Use the fluent API builders for easy chart construction:
// Simple usage
var data = ChartDataBuilder.Create()
.AddStringColumn("Category")
.AddNumberColumn("Value")
.AddRow("A", 100)
.AddRow("B", 200)
.Build();
// With formatted values
var row = new ChartRow()
.AddCell(1000, "$1,000")
.AddCell(2000, "$2,000");
// From collection
var salesData = ChartDataBuilder.Create()
.AddStringColumn("Product")
.AddNumberColumn("Sales")
.AddRows(products, p => new object[] { p.Name, p.Sales })
.Build();var options = ChartOptionsBuilder.Create()
.Title("Sales Report")
.Subtitle("Q1 2024")
.BackgroundColor("#ffffff")
.Colors("#4285F4", "#EA4335", "#FBBC05", "#34A853")
.FontSize(14)
.FontName("Arial")
.Legend("bottom", "center")
.HAxis(title: "Month", minValue: 0, maxValue: 12)
.VAxis(title: "Revenue ($)")
.SmoothLines() // For line charts
.LineWidth(3)
.PointSize(5)
.PieHole(0.4) // For donut charts
.Is3D() // For 3D pie charts
.Stacked() // For stacked bar/column
.ChartArea("80%", "70%", "10%", "10%")
.Tooltip(showColorCode: true, trigger: "focus")
.Explorer() // Enable pan/zoom
.Build();Some chart types require specific data formats. Here are examples for each:
var data = ChartDataBuilder.Create()
.AddStringColumn("Label")
.AddNumberColumn("Value")
.AddRow("Memory", 80)
.AddRow("CPU", 55)
.AddRow("Network", 68)
.Build();
var options = ChartOptionsBuilder.Create()
.Set("width", 400)
.Set("height", 300)
.Set("redFrom", 90)
.Set("redTo", 100)
.Set("yellowFrom", 75)
.Set("yellowTo", 90)
.Set("minorTicks", 5)
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.Gauge);
MyChart.Options = options;var data = ChartDataBuilder.Create()
.AddStringColumn("From")
.AddStringColumn("To")
.AddNumberColumn("Weight")
.AddRow("A", "X", 5)
.AddRow("A", "Y", 7)
.AddRow("A", "Z", 6)
.AddRow("B", "X", 2)
.AddRow("B", "Y", 9)
.AddRow("B", "Z", 4)
.Build();
var options = ChartOptionsBuilder.Create()
.Set("width", 600)
.Set("height", 400)
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.Sankey);
MyChart.Options = options;var data = ChartDataBuilder.Create()
.AddStringColumn("Name")
.AddStringColumn("Manager")
.AddStringColumn("Tooltip")
.AddRow("Mike", "", "The President")
.AddRow("Jim", "Mike", "VP")
.AddRow("Alice", "Mike", "VP")
.AddRow("Bob", "Jim", "Manager")
.AddRow("Carol", "Alice", "Manager")
.Build();
var options = ChartOptionsBuilder.Create()
.Set("allowHtml", true)
.Set("size", "large")
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.OrgChart);
MyChart.Options = options;var data = ChartDataBuilder.Create()
.AddStringColumn("Location")
.AddStringColumn("Parent")
.AddNumberColumn("Size")
.AddNumberColumn("Color")
.AddRow("Global", null, 0, 0)
.AddRow("Americas", "Global", 0, 0)
.AddRow("Europe", "Global", 0, 0)
.AddRow("USA", "Americas", 52, 31)
.AddRow("Mexico", "Americas", 24, 12)
.AddRow("France", "Europe", 42, -11)
.AddRow("Germany", "Europe", 31, -2)
.Build();
var options = ChartOptionsBuilder.Create()
.Set("minColor", "#f00")
.Set("midColor", "#ddd")
.Set("maxColor", "#0d0")
.Set("headerHeight", 15)
.Set("showScale", true)
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.TreeMap);
MyChart.Options = options;var data = ChartDataBuilder.Create()
.AddStringColumn("Name")
.AddNumberColumn("Salary")
.AddBooleanColumn("Full Time")
.AddRow("Mike", 10000, true)
.AddRow("Jim", 8000, false)
.AddRow("Alice", 12500, true)
.Build();
var options = ChartOptionsBuilder.Create()
.Set("showRowNumber", true)
.Set("page", "enable")
.Set("pageSize", 10)
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.Table);
MyChart.Options = options;Calendar charts require JavaScript Date objects. Use anonymous objects for date handling:
var data = new
{
cols = new object[]
{
new { id = "", label = "Date", type = "date" },
new { id = "", label = "Value", type = "number" }
},
rows = new object[]
{
new { c = new object[] { new { v = "Date(2024, 0, 1)" }, new { v = 3 } } },
new { c = new object[] { new { v = "Date(2024, 0, 2)" }, new { v = 7 } } },
new { c = new object[] { new { v = "Date(2024, 0, 15)" }, new { v = 10 } } },
new { c = new object[] { new { v = "Date(2024, 1, 1)" }, new { v = 5 } } },
new { c = new object[] { new { v = "Date(2024, 1, 14)" }, new { v = 8 } } }
}
};
var options = ChartOptionsBuilder.Create()
.Title("Daily Activity")
.Set("height", 350)
.Set("calendar", new { cellSize = 15 })
.Set("colorAxis", new { minValue = 0, colors = new[] { "#ffffff", "#4285F4" } })
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.Calendar);
MyChart.Options = options;Gantt charts require a specific 7-column format with dates:
var data = new
{
cols = new object[]
{
new { id = "Task ID", label = "Task ID", type = "string" },
new { id = "Task Name", label = "Task Name", type = "string" },
new { id = "Start", label = "Start", type = "date" },
new { id = "End", label = "End", type = "date" },
new { id = "Duration", label = "Duration", type = "number" },
new { id = "Percent Complete", label = "Percent Complete", type = "number" },
new { id = "Dependencies", label = "Dependencies", type = "string" }
},
rows = new object[]
{
new { c = new object[] {
new { v = "Research" },
new { v = "Find sources" },
new { v = "Date(2024, 0, 1)" },
new { v = "Date(2024, 0, 5)" },
new { v = (object?)null },
new { v = 100 },
new { v = (object?)null }
}},
new { c = new object[] {
new { v = "Write" },
new { v = "Write paper" },
new { v = (object?)null },
new { v = "Date(2024, 0, 9)" },
new { v = 3 * 24 * 60 * 60 * 1000 }, // 3 days in milliseconds
new { v = 25 },
new { v = "Research" }
}},
new { c = new object[] {
new { v = "Complete" },
new { v = "Hand in paper" },
new { v = (object?)null },
new { v = "Date(2024, 0, 10)" },
new { v = 1 * 24 * 60 * 60 * 1000 },
new { v = 0 },
new { v = "Write" }
}}
}
};
var options = ChartOptionsBuilder.Create()
.Set("height", 300)
.Set("gantt", new
{
trackHeight = 30,
criticalPathEnabled = true,
criticalPathStyle = new { stroke = "#e64a19", strokeWidth = 2 }
})
.Build();
MyChart.Data = data;
MyChart.SetChartType(ChartType.Gantt);
MyChart.Options = options;// Start auto-refreshing every 5 minutes
myChart.RefreshIntervalMinutes = 5;
myChart.StartAutoRefresh();
// Stop auto-refresh
myChart.StopAutoRefresh();The control implements IDisposable. For proper cleanup:
// In your page's OnDisappearing or cleanup code
myChart.Dispose();Contributions are always welcome!
Plugin.MAUI.GoogleChartsView is licensed under the MIT license.