How to integrate d3.js chart in C# application?
A web server definitely isn't required to use a client side JavaScript library like d3.js.
For C#, you'll need to embed a web browser control (in either WindowsForms or WPF).
You'll need to make sure that the browser is working in IE9 Standards mode as shown here.
Create your web pages as you would normally. Navigate to them using webbrowser.navigate (as just files on the file system.)
This should work.
Necromancing.
You can do this with C# and .NET-Core on all operating systems using nodeJS.
Absolutely no browser-control required.
Just install JavaScript-Services with nuget, then install d3, jsdom and svg2png in nodejs:
npm install –save svg2png
npm install –save jsdom
npm install –save d3
then in Startup.cs, add NodeServices in ConfigureServices
using Microsoft.AspNetCore.NodeServices;
public void ConfigureServices(IServiceCollection services)
{
// services.AddMvc();
// https://geeks.ms/clanderas/2016/10/18/asp-net-core-node-services-to-execute-your-nodejs-scripts/
// https://blogs.msdn.microsoft.com/webdev/2017/02/14/building-single-page-applications-on-asp-net-core-with-javascriptservices/
services.AddNodeServices( options => {
// options.DebuggingPort
});
}
Add an output handler:
public class AgeInfo
{
public string age;
public int population;
public AgeInfo(string prmAge, int prmPop)
{
this.age = prmAge;
this.population = prmPop;
}
}
// http://gunnarpeipman.com/2017/10/aspnet-core-node-d3js/
public async Task<IActionResult> Chart([FromServices] INodeServices nodeServices)
{
var options = new { width = 400, height = 200 };
var data = new[] {
new { label = "Abulia", count = 10 },
new { label = "Betelgeuse", count = 20 },
new { label = "Cantaloupe", count = 30 },
new { label = "Dijkstra", count = 40 }
};
List<AgeInfo> ls = new List<AgeInfo>();
ls.Add( new AgeInfo("<5", 2704659));
ls.Add( new AgeInfo("5-13", 4499890));
ls.Add( new AgeInfo("14-17", 2159981));
ls.Add( new AgeInfo("18-24", 3853788));
ls.Add( new AgeInfo("25-44", 14106543));
ls.Add( new AgeInfo("45-64", 8819342));
ls.Add( new AgeInfo("≥65", 612463));
// string markup = await nodeServices.InvokeAsync<string>("Node/d3Pie.js", options, data);
string markup = await nodeServices.InvokeAsync<string>("Node/d3chart.js", options, ls);
string html = @"<!DOCTYPE html>
<html>
<head><meta charset=""utf-8"" />
<style type=""text/css"">
.arc text
{
font: 10px sans-serif;
text-anchor: middle;
}
.arc path
{
stroke: #fff;
}
</style>
</head>
<body>
<img src=""" + markup + @""" />
</body>
</html>";
return Content(html, "text/html");
}
And then add the JavaScript
// Include all modules we need
const svg2png = require("svg2png");
const { JSDOM } = require("jsdom");
const d3 = require('d3');
// https://bl.ocks.org/mbostock/3887235
module.exports = function (callback, options, data) {
var dom = new JSDOM('<!DOCTYPE html><html><head><meta charset="utf-8" /></head><body><svg width="960" height="500"></svg></body></html>');
var document = dom.window.document;
dom.window.d3 = d3.select(dom.window.document);
// callback(null, dom.window.document.body.innerHTML);
var svg = dom.window.d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var pie = d3.pie()
.sort(null)
.value(function (d) {
return d.population;
});
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
/*
var dataaa =
[
{
age: "<5",
population: 2704659
},
{
age: "5-13",
population: 4499890
},
{
age: "14-17",
population: 2159981
},
{
age: "18-24",
population: 3853788
},
{
age: "25-44",
population: 14106543
}
,
{
age: "45-64",
population: 8819342
}
,
{
age: "≥65",
population: 612463
}
];
*/
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function (d) {
return color(d.data.age);
});
arc.append("text")
.attr("transform", function (d) {
return "translate(" + label.centroid(d) + ")";
})
.attr("dy", "0.35em")
.text(function (d) {
return d.data.age;
});
//});
// var svgText = dom.window.document.body.outerHTML;
// var svgText = dom.window.document.body.innerHTML;
var svgText = dom.window.document.body.querySelector("svg").outerHTML
// callback(null, svgText);
// var svgText = dom.window.d3.select("svg").html();
// svgText=process.version; // v8.6.0
// svgText= JSON.stringify(process.versions); //
// var pjson = require('./package.json'); svgText = pjson.version;
// callback(null, svgText);
// callback(null, JSON.stringify( { width: width, height: height } ));
// var buf = Buffer.from(svgText);
// callback(null, JSON.stringify( buf ));
// var output = svg2png.sync(buf, { width: width, height: height } );
// callback(null, JSON.stringify( output ));
//callback(null, svgText);
// callback(null, 'data:image/svg+xml;base64,' + Buffer.from(svgText).toString('base64'));
svg2png(Buffer.from(svgText), { width: width, height: height })
.then(buffer => 'data:image/png;base64,' + buffer.toString('base64') )
.then(buffer => callback(null, buffer));
}
That should give you a the required d3-chart without needing a svg-compatible browser.
You might need to update npm before you can (successfully) install any nodeJS modules.
npm install -g npm
You can also do this in a command-line application, just that then you need to set up your own DI contrainer.