Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate d3.js chart in C# application?

Tags:

c#

.net

d3.js

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?

like image 357
bobby Avatar asked Aug 26 '12 21:08

bobby


2 Answers

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.

like image 174
WiredPrairie Avatar answered Sep 28 '22 18:09

WiredPrairie


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.

like image 31
Stefan Steiger Avatar answered Sep 28 '22 17:09

Stefan Steiger