web-dev-qa-db-ja.com

C#アプリケーションにd3.jsチャートを統合する方法は?

私はマイクボストックのd3.jsチャートライブラリd3js.orgの大ファンです。

C#.Netアプリケーションでグラフを表示するためにそれを使用したいのですが、それが可能かどうかわかりません。

HTM + JSコードを生成し、それをWebブラウザーウィンドウに表示することで可能になる場合があります。ただし、d3.jsライブラリはWebサーバーなしではローカルで使用できないことを理解しました(ただし、Webサーバーなしで機能するものとWebサーバーを必要とするものは理解していません)。したがって、単純なソリューションは機能しません。

そのようなd3.jsチャートの配置を開発しようとした人はいますか?最も簡単な解決策を得るためにどこから始めればよいか考えていますか?

31
bobby

Webサーバーは、d3.jsのようなクライアント側のJavaScriptライブラリを使用する必要はありません。

C#の場合は、Webブラウザーコントロールを(WindowsFormsまたはWPFに)埋め込む必要があります。

here のように、ブラウザがIE9標準モードで動作していることを確認する必要があります。

通常どおりにWebページを作成します。 webbrowser.navigateを使用してそれらに移動します(ファイルシステム上のファイルと同様)。

これは動作するはずです。

14
WiredPrairie

ネクロマンシング。

これは、nodeJSを使用するすべてのオペレーティングシステムでC#および.NET-Coreを使用して行うことができます。
ブラウザ制御はまったく必要ありません。
インストール JavaScript-Services とnugetを使用し、d3、jsdom、svg2pngをnodejsにインストールします。

npm install –save svg2png
npm install –save jsdom
npm install –save d3

次に、Startup.csで、ConfigureServicesにNodeServicesを追加します。

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 
      });
}

出力ハンドラを追加します。

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");
}

そして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));

}

これにより、svg互換のブラウザーを必要とせずに、必要なd3-chartが提供されます。

NodeJSモジュールを(正常に)インストールする前に、npmを更新する必要がある場合があります。

npm install -g npm

コマンドラインアプリケーションでこれを行うこともできます。その場合は、独自のDIコントレイナーを設定する必要があります。

8
Stefan Steiger

同じソリューションを探していて、偶然 Edge.js に遭遇しました。任意の.NET 4.5アプリケーションから実行でき、Nugetを介してインストールできます。 node.jsのインストールは必要ありませんが、NPMを使用してD3をインストールするにはnodeが必要です。 package-lock.jsonおよびnode_modulesフォルダーが実行時にEdge.jsファイルと同じディレクトリにあるか、グローバルにインストールされていることを確認してください。 npm i d3-arrayフォルダー内から\Edgeを実行し、*。jsonファイルと* .jsファイルを含めて、それらをコンテンツに設定し、出力ディレクトリにコピーしました。次に、次のように単純です:

class Program {
    public static async Task Start(int[] someArray) {
        var func = Edge.Func(@"
            var d3 = require('d3-array')
            return function (data, callback) {
                callback(null, 'D3 says: ' + d3.min(data));
            }
        ");
        Console.WriteLine(await func(someArray));
    }

    static void Main(string[] args) {
        Start(new int[] { 1, 2, 3, 4 }).Wait();
    }
} 

出力:D3 says: 1

注:.Net7.2では、プロジェクトルートにEdgeフォルダをインストールするには、Edge.Js.Binaries NuGetパッケージをインストールする必要がありました。 Edge.Jsパッケージはこれを行いませんでしたが、4.5ではそれを行いました。

0
maeneak