programing

생성된 d3 html에서 angularjs directives를 어떻게 사용합니까?

css3 2023. 10. 2. 15:22

생성된 d3 html에서 angularjs directives를 어떻게 사용합니까?

나는 내 d3 시각화에 angularjs tooltip 지시를 사용하려고 노력하고 있어서, 나는 다음과 같은 것이 있습니다.

var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("circle")
        .attr("tooltip-append-to-body", true)
        .attr("tooltip", function(d) {
            return d.name;
        })
// ... attributes

그러나 툴팁이 표시되지 않습니다.필요한가요?$compile아니면 뭔가?포장해 봤습니다.$timeout그것도 효과가 없었어요

저도 비슷한 문제가 있었는데 네, 해결했습니다.$compile. 당신의 d3 코드가 사용자 정의 지침 안에 있다고 가정합니다.여기서 툴팁 속성을 추가하고, $compile이 한 번만 실행되도록 사용자 지정 지시 속성을 제거한 후 $compile을 호출할 수 있습니다.

    myApp.directive('myNodes', ['$compile', function ($compile) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var nodes = [{"name": "foo"}, {"name": "bar"}] 
            var mySvg = d3.select(element[0])
                  .append("svg")
                  .attr("width", 100)
                  .attr("height", 100);

            var node = mySvg.selectAll(".node")
             .data(nodes)
             .enter()
             .append("circle")
             .attr("cx", function(d,i){
                return 20+i*50;
             })
             .attr("cy", 50)
             .attr("r", 10)
             .attr("tooltip-append-to-body", true)
             .attr("tooltip", function(d){
                 return d.name;
             });

            element.removeAttr("my-nodes");
            $compile(element)(scope);
            }
        };
    }]);

$compile 서비스는 지시에 의해 추가된 속성을 사용하여 요소가 컴파일되도록 합니다.

여기 위 코드를 사용한 작동 피들이 있습니다.그게 당신이 찾고 있는 것이기를 바랍니다!

@jbll의 꽤 좋은 답변입니다. 그러나 지시 컴파일을 시작 단계의 끝으로 연결하는 것이 아마도 가장 좋을 것입니다.모든 요소를 다시 만들지 않고 그래픽이 데이터 업데이트에 응답할 수 있도록 시작 단계와 업데이트 단계가 중요합니다.이전의 답변은 모델이 변경될 때마다 모든 노드의 모든 지시를 컴파일하도록 했습니다.이것이 원하는 것일 수도 있지만, 아마 아닐 것입니다.

다음 코드는 $scope.nodes 변수가 변경될 때마다 d3 그래픽 업데이트를 보여줍니다.

이것 또한 원래의 지시를 삭제하고 다시 만들 필요가 없기 때문에 조금 더 깔끔합니다. 이것은 약간의 해킹처럼 보입니다.

여기 피들이 있습니다.

html에 단추를 추가합니다.

<button ng-click="moveDots()">Move the dots</button>

그런 다음 JavaScript fie를 다음과 같이 변경합니다.

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

html이 angularjs가 아닌 다른 것에 의해 생성되고 DOM에 삽입된다면, angular가 그것에 대해 알 수 있도록 DOM에 삽입하기 전에 당신의 지시 속성을 포함하는 html을 컴파일해야 할 것입니다.

removeAtr을 호출할 필요가 없기 때문에 이 방법이 훨씬 좋습니다(해크 같습니다).

myApp.directive('myNodes', ['$compile', function ($compile) {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var nodes = [{"name": "foo"}, {"name": "bar"}] 
        var mySvg = d3.select(element[0])
              .append("svg")
              .attr("width", 100)
              .attr("height", 100);

        var node = mySvg.selectAll(".node")
         .data(nodes)
         .enter()
         .append("circle")
         .attr("cx", function(d,i){
            return 20+i*50;
         })
         .attr("cy", 50)
         .attr("r", 10)
         .attr("tooltip-append-to-body", true)
         .attr("tooltip", function(d){
             return d.name;
         });

        $compile(svg[0])(scope);
        }
    };
}]);

@david004는 에 체인을 연결하는 것에 대해 좋은 점을 제공하므로 각 입력 요소에서 한 번만 호출됩니다.하지만 전화 대신에$compile에서parentNode, 제가 전화를 이용해서 하는 방법은 이렇습니다.$compile각 개별 입력 요소:

// Entering
myD3Selection.enter()
  .append( 'rect' )
  .attr( {foo: 'bar'} )
  .call( compile );

// Compile encapsulated in reusable function, so can be used on multiple enter() chains
function compile( d3Selection )
{
  d3Selection.each( function( d, i )
  {
    // this is the actual DOM element
    $compile( this )( scope );
  } );
}

언급URL : https://stackoverflow.com/questions/20399336/how-do-i-use-angularjs-directives-in-generated-d3-html