web-dev-qa-db-fra.com

D3 dans une application AngularJS

J'essaie de créer ma première application avec AngularJS. Cela semble soigné, mais il y a beaucoup d'abstraction, et je suis juste curieux de savoir si quelqu'un a des conseils sur la façon la plus idiomatique d'utiliser la méthodologie angular pour mettre à jour les visuels créés avec d3js.

Merci, bp

42
BHP

Afin de faire angular et les autres frameworks jouent Nice, c'est pour envelopper les "autres" frameworks en utilisant des directives.

http://docs.angularjs.org/guide/directive

La chose que vous voulez faire est de dire angular lorsque les données ont été mises à jour par les "autres" frameworks. Si angular n'a pas besoin de savoir, alors votre tâche est plus simple.

Voici un exemple qui fonctionne avec SVG, c'est génial

http://sullerandras.github.com/SVG-Sequence-Diagram/

Voici un exemple qui enveloppe TinyMCE

http://jsfiddle.net/programmieraffe/kjsEV/

34
Dan Doyon

Il y a aussi la possibilité d'insérer la syntaxe du guidon AngularJS directement dans les éléments générés par d3:

var containerDiv = d3.select(targetCSSSelectorForADiv);
var svgG = containerDiv
                                .append("svg")
                                .attr("width", width + margin.left + margin.right)
                                .attr("height", height + margin.top + margin.bottom)
                                .append("g")
                                .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

 svgG.selectAll(".tempclass").data(scope.circles).enter()
                                .append("circle")
                                .attr("class", "tempclass")
                                .attr("cx", function (d, i) { return "{{circles[" + i + "].cx}}" })
                                .attr("cy", function (d, i) { return "{{circles[" + i + "].cy}}" })
                                .attr("r", function (d, i) { return "{{circles[" + i + "].radius}}" })
                                .attr("ng-style", function (d, i)
                                {
                                    return "{fill: circles[" + i + "].circolor"
                                        + ", opacity: circles[" + i + "].opa"
                                        + ", 'stroke-width': 4*circles[" + i + "].opa"
                                        + ", stroke: 'red' }";
                                });

Veuillez noter les choses suivantes: la portée est en fait l'objet angular scope transmis de la directive à la fonction de rendu. Définir le style d'un élément sur un "{{... ...} } "l'expression ne fonctionnera pas, j'utilise donc l'attribut" ng-style "ici.

Cependant, il y a une autre astuce: vous devez dire Angular pour regarder les éléments DOM générés dynamiquement et câbler la liaison de données, je connais maintenant deux façons de faire:

//the target div is the one with the angular ng-controller attribute 
//this you can call at the end of the d3 rendering call from within the render function
angular.bootstrap(document.getElementById("d3ContainerDivID"), ['d3App']);

l'autre façon est la suivante:

//and this could be called from the directive that triggered the rendering or
//some other place that could have the angular $compile service injected
$compile(document.getElementById("d3ContainerDivID"))(scope);

Vous pouvez maintenant modifier les membres de votre portée et ils seront directement mis à jour vers vos éléments d3, dans ce cas les cercles svg. Dans le angular (qui est instancié avant que la directive ne se déclenche qui dessine les objets d3).

    $scope.circles = [];
    for (var i = 0; i < 50; i++)
    {
        $scope.circles.Push(new Circle());
    }
    setInterval(function ()
    {
        $scope.circles.forEach(function (d, i) { $scope.circles[i] = new Circle(); });
        $scope.$digest();
    }, 2000);

Veuillez noter l'appel $ digest, qui indique angular pour digérer la portée modifiée; cela changera les valeurs sur les éléments du cercle svg. Pour tout ce qui ressemble aux animations et autres, d3 n'est plus responsable et il faudrait implémenter manuellement ou utiliser un modèle différent.

3
hans

Si nous utilisons d3 à l'intérieur d'une directive pour générer des éléments avec d'autres Angular (comme je pense que vous trouverez que c'est une exigence assez courante), vous pouvez appeler $compile À la fin de la Mettre à jour la phase du processus de rendu avec la méthode call(). Comme ceci (en supposant que nous rendons un tas de cercles):

mySvg.selectAll("circle")
                .data(scope.nodes)
                .enter()
                .append("circle")
                .attr("someDirective")
                .call(function(){
                    $compile(this[0].parentNode)(scope);
                });
0
david004

Vous pouvez également suivre ce tutoriel/screencast pour voir comment utiliser D3 avec angular. C'est un peu différent, car il utilise une bibliothèque d'encapsuleurs autour de d3 appelée rickshaw, qui fournit des trucs spécifiques à la représentation graphique, mais l'approche est exactement la même:

http://tagtree.tv/d3-with-rickshaw-and-angular

0
hendrikswan