Skip to content

Instantly share code, notes, and snippets.

@GeorgDangl
Created October 31, 2017 20:14
Show Gist options
  • Save GeorgDangl/4402f32b0dc0844f8d8c0f98fe072b7f to your computer and use it in GitHub Desktop.
Save GeorgDangl/4402f32b0dc0844f8d8c0f98fe072b7f to your computer and use it in GitHub Desktop.
Displaying graphs and charts in a Xamarin WebView with Chart.js
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="App.Mobile.Views.HackyReportPage"
Title="Hacky Chart.js Report">
<WebView VerticalOptions="FillAndExpand">
<WebView.Source>
<HtmlWebViewSource Html="{Binding ReportHtml}" />
</WebView.Source>
</WebView>
</ContentPage>
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Prism.AppModel;
using Prism.Navigation;
using Prism.Services;
namespace App.Mobile.ViewModels
{
public class HackyReportPageViewModel : ViewModelBase
{
public HackyReportPageViewModel(INavigationService navigationService,
IApplicationStore applicationStore,
IDeviceService deviceService)
: base(navigationService, applicationStore, deviceService)
{
BuildReportHtml();
}
public string ReportHtml { get; set; }
private void BuildReportHtml()
{
var chartConfigScript = GetChartScript();
var html = GetHtmlWithChartConfig(chartConfigScript);
ReportHtml = html;
}
private string GetHtmlWithChartConfig(string chartConfig)
{
var inlineStyle = "style=\"width:100%;height:100%;\"";
var chartJsScript = "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js\"></script>";
var chartConfigJsScript = $"<script>{chartConfig}</script>";
var chartContent = $@"<div id=""chart-container"" {inlineStyle}>
<canvas id=""chart"" />
</div>";
var document = $@"<html style=""width:97%;height:100%;"">
<head>{chartJsScript}</head>
<body {inlineStyle}>
{chartContent}
{chartConfigJsScript}
</body>
</html>";
return document;
}
private string GetChartScript()
{
var chartConfig = GetSpendingChartConfig();
var script = $@"var config = {chartConfig};
window.onload = function() {{
var canvasContext = document.getElementById(""chart"").getContext(""2d"");
new Chart(canvasContext, config);
}};";
return script;
}
private string GetSpendingChartConfig()
{
var config = new
{
type = "pie",
data = GetPieChartData(),
options = new
{
responsive = true,
maintainAspectRatio = false,
legend = new
{
position = "top"
},
animation = new
{
animateScale = true
}
}
};
var jsonConfig = JsonConvert.SerializeObject(config);
return jsonConfig;
}
private object GetPieChartData()
{
var colors = GetDefaultColors();
var labels = new[] {"Groceries", "Car", "Flat", "Electronics", "Entertainment", "Insurance"};
var randomGen = new Random();
var dataPoints = Enumerable.Range(0, labels.Length)
.Select(i => randomGen.Next(5, 25))
.ToList();
var data = new
{
datasets = new[]
{
new
{
label = "Spending",
data = dataPoints,
backgroundColor = dataPoints.Select((d, i) =>
{
var color = colors[i % colors.Count];
return $"rgb({color.Item1},{color.Item2},{color.Item3})";
})
}
},
labels
};
return data;
}
private List<Tuple<int, int, int>> GetDefaultColors()
{
return new List<Tuple<int, int, int>>
{
new Tuple<int, int, int>(255, 99, 132),
new Tuple<int, int, int>(255, 159, 64),
new Tuple<int, int, int>(255, 205, 86),
new Tuple<int, int, int>(75, 192, 192),
new Tuple<int, int, int>(54, 162, 235),
new Tuple<int, int, int>(153, 102, 255),
new Tuple<int, int, int>(201, 203, 207)
};
}
}
}
@ChristopherMWood
Copy link

Thanks for writing this! I took your idea and expanded it into a Nuget package since I have several projects that could use this functionality. https://github.com/ChristopherMWood/XamarinChartJSPlugin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment