2015-12-01 11 views
7

グローバルD3オブジェクトだけを使用するディレクティブを見てきました。また、グローバルD3オブジェクトをサービスに戻すだけで挿入するディレクティブも見てきました。 D3スクリプトを追加し、D3オブジェクトを提供するスクリプトのロード時に解決される約束を返します。D3をAngularRJSに挿入するための適切な規約

注射可能なサービスでこれを使用すると、最も意味があるように見えます(例1と2を参照)。しかし、どちらの方が良いか分かりません。例2では、​​D3がコードを実行する前にロードされていることが保証されますが、他の人のようには見えません。それ以外の場合は、サービス内でディレクティブ全体をラップする必要があります。d3と生成されたsvgオブジェクトスコープまたは未定義である可能性が高い(例2を参照)が、私はいつも最初の解決と考えている、少なくともコンパイルの約束、例を参照してください。3.

例1:サービスは

.factory('D3Service', [, 
    function() { 

     // Declare locals or other D3.js 
     // specific configurations here. 

     return d3; 
    }]); 

D3グローバルオブジェクトを渡す例2:D3スクリプトをDOMに追加して約束してくれるサービス

.factory('D3Service', ['$window', '$document', '$q', '$rootScope', 
    function ($window, $document, $q, $rootScope) { 

     var defer = $q.defer(); 

     var scriptTag = $document[0].createElement('script'); 
     scriptTag.type = 'text/javascript'; 
     scriptTag.src = 'https://d3js.org/d3.v3.min.js'; 
     scriptTag.async = true; 
     scriptTag.onreadystatechange = function() { 

      if (this.readyState == 'complete') { 
       onScriptLoad(); 
      } 
     } 
     scriptTag.onload = onScriptLoad; 

     var script = $document[0].getElementsByTagName('body')[0]; 
     script.appendChild(scriptTag); 

     //--- 
     // PUBLIC API 
     //--- 

     return { 
      d3: function() { 
       return defer.promise; 
      } 
     }; 

     //--- 
     // PRIVATE METHODS. 
     //--- 

     // Load D3 in the browser 
     function onScriptLoad() { 
      $rootScope.$apply(function() { 
       defer.resolve($window.d3); 
      }); 
     } 
    }]); 

例3:SVGを追加するコンパイルを使用することに直面したとき、私は同様の質問があったSVGは、リンクで利用可能ですが、少なくとも、コンパイルの約束は、常に最初

 // Perform DOM and template manipulations 
     function compile ($element, $attrs, $transclude) { 

      var svg; 

      // Callback provides raw D3 object 
      D3Service.d3().then(function (d3) { 

       // Create a responsive SVG root element 
       svg = d3.select($element[0]) 
       .append('svg') 
       .style('width', '100%'); 
      }); 

      // Return the link function 
      return function($scope, $element, $attrs) { 

       // Is svg undefined? 

       // Maybe? so have to wrap everything again in service 
       D3Service.d3().then(function (d3) { 

        function render() { 
         // d3 and svg guaranteed to be available, but code gets really ugly looking and untestable 
        } 
       }); 

       function render() { 
        // d3 and svg have to be passed in as they may not be available, but code is cleaner 
       } 
      }; 
     } 
+1

うん。 d3.jsがウィンドウスコープ内に 'd3'を置く以外に何もしない限り、最終的に存在するかどうかをチェックするための' $ interval'の約束以上のものはありません。 [IE8で、とにかく] – Brian

+0

こんにちは@ブライアンので、各グラフのディレクティブの 'リンク'は$間隔の約束を待ってからD3のグローバル参照を使用しますか?解決策のように思えるかもしれませんが、DRYerでなければならないかもしれません... – mtpultz

+1

私は "d3が定義されていない場合、d3をロードして待ちます。誰かがIE8を含むブラウザのためのより良い解決策を持っているなら、@ me! – Brian

答えて

4

を解決するだろうという意味ではありません問題はd3Angularです。問題に近づくにはいくつかの方法があるようでした。それぞれは実行可能でしたが、滑らかで自然な感じはしませんでした。そのコアでは、d3Angularはまったく異なる2つの技術であるように見えますが、それらはすぐにすぐに一緒に再生されません。私は間違ったことをしないでください、彼らは素晴らしいと一緒に働くが、彼らはお互いに暖かくする必要があります。だからせいぜい、Angularフレームワーク内でd3に遊び場を与えることができます。そして私はこの遊び場がdirectiveであると信じています。

しかし、(d3.jsファイルの読み込みあたり)約束を返しモジュラーd3Serviceアプローチについて:これは非常によくngNewsletterで詳しく説明されたが

angular.module('myApp.directives', ['d3']) 
    .directive('barChart', ['d3Service', function(d3Service) { 
    return { 
     link: function(scope, element, attrs) { 
     d3Service.d3().then(function(d3) { 
      // d3 is the raw d3 object 
     }); 
     }} 
    }]); 

は、それだけでサービスを利用するためにやり過ぎ思われますindex.htmlに他のすべてのjavascriptファイルを含めるだけで、scriptというタグをDOMに直接書き込むことができます。私たちが知っているのはdirectiveなので、意図的に読み込まないのはなぜですか?ただそれはそうフープを介してジャンプする必要はあり、:

<script src="/js/third-party/d3js/d3.min.js"></script> 

しかし、このアプローチの約束は、モジュールが提供されていない - 非常に簡単に私たちを注入することができるという、はい、その後、我々は複数のアプリケーションを構築していると、それぞれがd3を必要としましょうアプリケーションレベルのd3モジュールは素晴らしいです。しかし、あなたはいつもその約束を待たなければなりません。たとえそれが最初の負荷の直後に解決されるとわかっていても、あなたはそれを解決する必要があります。それを使用する指示またはコントローラーで。常に。バマー。

index.htmld3.jsを含めることを選択したため、私は約束を解消する必要なしに自分の指示にアクセスできます。ここではおそらく平行です:FWIW、私は角度の約束を使用してJQueryの約束を使用するので、私はJQueryが必要なときに何をしますか?まあ、私はそれが($.Deferred())を必要とするときにそれを呼び出す、私のポイントは、同様のファッションでd3を呼び出すことはちょうど私に大変なようでした。

私はd3Serviceを利用していますが、他のものよりもヘルパー機能のほうが多いです。例えば、私が仕事をするために上のSVGを取得する場合、なぜ私だけ応答SVGを与える関数を呼び出していない:

指令(リンク)

var svg = d3Service.getResponsiveCanvas(scope.id, margin, height, width); 

サービス

app.service('d3Service', function() { 

    return { 
     getResponsiveCanvas: function(id, margin, height, width) { 
     return d3.select('#' + id) 
       .append('div') 
       .classed('svg-container', true) 
       .append('svg') 
       .attr('id', 'svg-' + id) 
       .attr('preserveAspectRatio', 'xMinYMin meet') 
       .attr('viewBox', '0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom)) 
       .classed('svg-content-responsive', true) 
       .append('g') 
       .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')'); 
     } 
    } 
}); 

私はSVGに軸を追加するための同様の機能を持っています。これにはコードの臭いがありますが、まさにその性質上、d3でDOMを直接操作していますので、私の経験はどこに置いても、醜くて角度のような感じはしません。あなたの人生を楽にするサービスを手掛けています。

+1

大変感謝しています。それをindex.htmlに追加してディレクティブでアクセスすると、d3が未定義の問題が発生しますか?コメントに@Brianのようなinit()メソッドを追加する必要があるようです。個々のチャートを読み込む前に$ interval.dをチェックして$ window.d3を実行します。両方の視点からの答えを高く評価してください。 – mtpultz

+1

@mtpultz HTMLファイルに 'd3'を直接インクルードすることで、Angularが初期化した時点でロードされ、使用準備が整うことが保証されます。そのような私は定義されていないd3を実行していません。このように考えると、HTMLに含まれるだけで、ブラウザによって読み込まれ、JSエンジンに提供される別のJSファイルです。 underscore.jsまたはjquery、または他のサードパーティのJSライブラリを使用する場合は、同じフローです。 @Brianは約束が読み込まれたことを参照しているようですが、正しくロードされていない場合は未定義です。しかし、私が指摘したアプローチは、約束を使用しないでください – lux

+0

さて、私はいつもスクリプトの読み込み方法を忘れています。したがって、非同期に設定しない限り、これらは順番にロードされます。ありがとう:) – mtpultz

関連する問題