2

私は最近d3.jsのプラグインを書き込もうとしていて、おそらく些細なことと混同されています。再利用可能なチャートの作成方法については、 d3のWebサイトに説明があります。パターンは次のようになります(最も重要な詳細のみ、完全なコードはここにあります):

デザインパターン1:d3Webサイトから

function timeSeriesChart() {
  var margin = {top: 20, right: 20, bottom: 20, left: 20},
      ...
      area = d3.svg.area().x(X).y1(Y),
      line = d3.svg.line().x(X).y(Y);

  function chart(selection) {
    selection.each(function(data) {

      // Convert data to standard representation greedily;
      // this is needed for nondeterministic accessors.
      data = data.map(function(d, i) {
        return [xValue.call(data, d, i), yValue.call(data, d, i)];
      });

      // Update the x-scale.
      ...

      // Update the y-scale.
      ...

      // Select the svg element, if it exists.
      var svg = d3.select(this).selectAll("svg").data([data]);
      ...

      // Otherwise, create the skeletal chart.
      var gEnter = svg.enter().append("svg").append("g");
      ...    
  }

  // The x-accessor for the path generator; xScale ∘ xValue.
  function X(d) {      }

  // The x-accessor for the path generator; yScale ∘ yValue.
  function Y(d) {      }

  chart.margin = function(_) {
    if (!arguments.length) return margin;
    margin = _;
    return chart;
  };

  chart.width = function(_) {
    if (!arguments.length) return width;
    width = _;
    return chart;
  };

  chart.height = function(_) {
    if (!arguments.length) return height;
    height = _;
    return chart;
  };

  chart.x = function(_) {
    if (!arguments.length) return xValue;
    xValue = _;
    return chart;
  };

  chart.y = function(_) {
    if (!arguments.length) return yValue;
    yValue = _;
    return chart;
  };

  return chart;
}

特にd3の作成者自身が提案したため、このパターンが堅牢であることは間違いありません。ただし、その投稿に出くわす前は、次のパターンを問題なく使用してきました(プラグインの一般的な作成方法と同様)。

デザインパターン2:プラグインを作成する一般的な方法

(function() {
    var kg = {
        version: '0.1a'
    };

    window.kg = kg;

    kg.chart = {};

    // ==========================================================
    // CHART::SAMPLE CHART TYPE
    // ==========================================================
    kg.chart.samplechart = {

        // ----------------------------------------------------------
        // CONFIGURATION PARAMETERS
        // ----------------------------------------------------------
        WIDTH: 900,
        HEIGHT: 500,
        MARGINS: {
            top: 20,
            right: 20,
            bottom: 20,
            left: 60,
            padding: 40
        },
        xRange: d3.time.scale(),
        yRange: d3.scale.linear(),
        xAxis: d3.svg.axis(),
        yAxis: d3.svg.axis(),
        data: {},

        // ----------------------------------------------------------
        // INIT FUNCTION
        // ----------------------------------------------------------
        init: function() {
            // Initialize and add graph to the given div
            this.update();
        },

        // ----------------------------------------------------------
        // Redraws the graph
        // ----------------------------------------------------------
        update: function() {
            var parentThis = this;
            var newData = parentThis.data;

            // Continue with adding points/lines to the chart


        },
        // ----------------------------------------------------------
        // Gets random data for graph demonstration
        // ----------------------------------------------------------
        getRandomData: function() {
            // Useful for demo purposes  

        }
    };

    // ==========================================================
    // HELPER FUNCTIONS
    // ==========================================================

}());


// EXAMPLE: This renders the chart. 
kg.chart.samplechart.vis = d3.select("#visualization");
kg.chart.samplechart.data = kg.chart.samplechart.getRandomData();
kg.chart.samplechart.init();​    

私はしばらくの間デザインパターン2を問題なく使用しています(私はそれがあまりきれいではないことに同意しますが、私はそれに取り組んでいます)。デザインパターン1を見た後、冗長性が高すぎると感じました。たとえば、内部変数にアクセスできるようにするコードの最後のブロック(chart.margin = function(_) {}など)を見てください。

おそらくこれは良い習慣ですが、これはさまざまなチャートタイプごとに繰り返す必要があり(現在開発中のNVD3と呼ばれるライブラリで見られるように)、開発作業とバグのリスクの両方が増加するため、メンテナンスが面倒になります。

パターンを続けた場合にどのような深刻な問題に直面するのか、またはパターンをどのように改善したり、デザインパターン1の精神に近づけることができるのかを知りたいです。完全な書き直しが必要になり、やや安定したミニライブラリに新しいバグが発生するため、この時点でパターンを変更しないようにしています。助言がありますか?

4

1 に答える 1

4

実際、2番目のパターンはd3ソースコードで見つけることができます。

(function(){
...
d3 = {version: "2.9.6"}; // semver
...

d3.svg = {};
d3.svg.arc = function() {
  var innerRadius = d3_svg_arcInnerRadius,
      outerRadius = d3_svg_arcOuterRadius,
...

ただし、スケール、軸、面積、レイアウトなどのコンポーネントとジェネレーターは、「ゲッターセッターメソッドを使用したクロージャーとしてのチャート」または「構成可能な関数による高次プログラミング」と呼ぶことができるパターンを使用する傾向があります。理論的根拠については、 Googleグループスレッドでこのディスカッションをフォローできます。

個人的には、この冗長性は便利でかなり読みやすいものであっても、好きではありません。そこで、カスタム関数を使用して、これらのゲッターとセッターを自動的に生成します。

d3.helper.createAccessors = function(visExport) {
    for (var n in visExport.opts) {
        if (!visExport.opts.hasOwnProperty(n)) continue;
        visExport[n] = (function(n) {
            return function(v) {
                return arguments.length ? (visExport.opts[n] = v, this) : visExport.opts[n];
            }
        })(n);
    }
};

チャートモジュールの最後にこのように使用します。

d3.helper.createAccessors(chart, opts);

optsは、すべてのパブリック関数の名前です。

var opts = {
            width: 200,
            margin: [5, 0, 20, 0],
            height: 200,
            showPoints: true,
            showAreas: false,
            enableTooltips: true,
            dotSize: 4
        };

完全な例を次に示します。http://jsfiddle.net/christopheviau/YPAYz/

于 2012-07-31T14:51:22.403 に答える