I am a big fan of Mike Bostock's d3.js chart library: d3js.org.
I would like to use it to display charts in a C# .Net application, but I don't know if it is possible.
It may be possible by generating HTM+JS codes and rendering it in a webbrowser window. However, I understood d3.js library cannot be used locally without a webserver (However I did not understood what works without a webserver and what requires a webserver), therefore a simple solution does not work.
Has anybody tried to develop that kind of deployment of d3.js charts? Do you have an idea on where to start in order to have the most simple solution?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With