How do I use angularjs directives in generated d3 html?

后端 未结 5 1876
北荒
北荒 2020-12-05 00:26

I\'m trying to use the angularjs tooltip directive on my d3 visualisation, so I have something like

var node = svg.selectAll(\".node\")
    .data(nodes)
            


        
5条回答
  •  南方客
    南方客 (楼主)
    2020-12-05 01:00

    A pretty good answer from @jbll - But it will probably be best to chain the directive compilation onto the end of the enter phase. It is important to have an enter phase and an update phase so the graphic can respond to data updates without recreating every element. The previous answer would have every directive on every node compiled whenever the model was changed. This may be what is wanted, but probably not.

    The following code shows the d3 graphic updating whenever the $scope.nodes variable changes.

    This is also a little neater because it doesn't require the removal and recreation of the original directive, which seems like a bit of a hack.

    Here is the Fiddle

    Add the button to the html:

    
    

    And then change the JavaScript fie to:

    var myApp = angular.module('myApp', ['ui.bootstrap']);
    
    myApp.controller('myCtrl', ['$scope', function($scope){
        $scope.nodes = [
            {"name": "foo", x: 50, y: 50},
            {"name": "bar", x: 100, y: 100}
        ];
        $scope.moveDots = function(){
            for(var n = 0; n < $scope.nodes.length; n++){
                var node = $scope.nodes[n];
                node.x = Math.random() * 200 + 20;
                node.y = Math.random() * 200 + 20;
            }
        }
    }]);
    
    myApp.directive('myNodes', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
    
                var mySvg = d3.select(element[0])
                    .append("svg")
                    .attr("width", 250)
                    .attr("height", 250);
    
                renderDots();
    
                scope.$watch("nodes", renderDots, true);
    
                function renderDots(){
    
                    // ENTER PHASE
    
                    mySvg.selectAll("circle")
                        .data(scope.nodes)
                        .enter()
                        .append("circle")
                        .attr("tooltip-append-to-body", true)
                        .attr("tooltip", function(d){
                            return d.name;
                        })
                        .call(function(){
                            $compile(this[0].parentNode)(scope);
                        });
    
                    // UPDATE PHASE - no call to enter(nodes) so all circles are selected
    
                    mySvg.selectAll("circle")
                        .attr("cx", function(d,i){
                            return d.x;
                        })
                        .attr("cy", function(d,i){
                            return d.y;
                        })
                        .attr("r", 10);
    
                    // todo: EXIT PHASE (remove any elements with deleted data)
                }
            }
        };
    }]);
    

提交回复
热议问题