动态创建的d3图表中的角度ng-click不起作用

时间:2022-10-22 09:15:55

I'm trying to create a d3 chart using an Angular directive. I manage to create it, but the problem is that I want some ng-click events on the chart elements and I'm not really sure how this should be done.

我正在尝试使用Angular指令创建d3图表。我设法创建它,但问题是我想在图表元素上有一些ng-click事件,我不确定应该怎么做。

Here is my directive:

这是我的指示:

.directive('circleChart', function($parse, $window, $compile) {
        return {
            restrict: 'A',
            scope: {
                datajson: '='
            },
            link: function(scope, elem, attrs) {

                var circleChart = new CircleChart(scope.datajson);
                circleChart.initialise(scope);
                var svg = circleChart.generateGraph();
                svg = angular.element(svg);

                console.log(svg);
                //scope.$apply(function() {
                  var content = $compile(svg)(scope);
                  elem.append(content);
                //});
            }
        }
    });

The CircleChart object creates my d3 chart and there is the place I attach an ng-click attribute to the chart elements (doesn't seem to be a proper Angular way of doing it):

CircleChart对象创建我的d3图表,并且有一个地方我将ng-click属性附加到图表元素(似乎不是一个正确的Angular方式):

var CircleChart = Class.create({
    initialise: function(scope) {
        this.datajson = scope.datajson;
    },

    generateGraph: function() {

    .............

    var chartContent = d3.select("div#chart-content");

    var svg = chartContent.append("svg")
        .attr("id", "circle")
        .attr("width", diameter)
        .attr("height", diameter)
        .style("border-radius", "50px")
        .append("g")
        .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

      ...............

           var circle = svg.selectAll("circle")
                .data(nodes)
                .enter().append("circle")
                .attr("class", function(d) {
                    return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
                })
                .attr("id", function(d) {
                    return d.id;
                })
                .attr("value", function(d) {
                    return d.name
                })
                .attr("parent", function(d) {
                    if (d.parent) return d.parent['id']
                })
                .attr("ng-click", function(d) {
                    return "getEgs('" + d.id + "')";
                })

    ...............

The d3 code is working fine because if I remove the compile code from the directive, the chart gets drawn, but the ng-clicks don't fire.

d3代码工作正常,因为如果我从指令中删除编译代码,则会绘制图表,但不会触发ng-clicks。

If I leave the compile code there, it goes into an infinite loop and the browser is building up memory until I have to kill it.

如果我把编译代码留在那里,它会进入一个无限循环,浏览器正在构建内存,直到我必须杀死它。

Obviously, my method is not working and it will be awesome if someone can help me out

显然,我的方法不起作用,如果有人可以帮助我,那将是很棒的

1 个解决方案

#1


5  

Since you are modifying the DOM from inside the CircleChart.generateGraph and re-appending the contents of the element in you directive: elem.append(content) after compilation, you (probably) end up in an infinite loop.

由于您正在从CircleChart.generateGraph内部修改DOM并在编译后重新附加元素的内容:elem.append(content),您(可能)最终会进入无限循环。

If you do want to compile the template thus produced, you can simple call $compile(elem.contents())(scope); without having to clear and append the content again. $compile will work Angular magic on the DOM in-place.

如果你想编译这样生成的模板,你可以简单地调用$ compile(elem.contents())(scope);无需再次清除和附加内容。 $ compile将在DOM上就地使用Angular魔法。


However, as I suggested in the comments, since you have access to the whole scope in CircleChart (which in my opinion is probably an overkill), you should capture the click event in d3 and invoke the getErgs function from code instead of $compile-ing the code and delegating the task to Angular.

但是,正如我在评论中所建议的那样,因为你可以访问CircleChart中的整个范围(我认为这可能是一种矫枉过正),你应该在d3中捕获click事件并从代码而不是$ compile-调用getErgs函数。代码并将任务委托给Angular。

#1


5  

Since you are modifying the DOM from inside the CircleChart.generateGraph and re-appending the contents of the element in you directive: elem.append(content) after compilation, you (probably) end up in an infinite loop.

由于您正在从CircleChart.generateGraph内部修改DOM并在编译后重新附加元素的内容:elem.append(content),您(可能)最终会进入无限循环。

If you do want to compile the template thus produced, you can simple call $compile(elem.contents())(scope); without having to clear and append the content again. $compile will work Angular magic on the DOM in-place.

如果你想编译这样生成的模板,你可以简单地调用$ compile(elem.contents())(scope);无需再次清除和附加内容。 $ compile将在DOM上就地使用Angular魔法。


However, as I suggested in the comments, since you have access to the whole scope in CircleChart (which in my opinion is probably an overkill), you should capture the click event in d3 and invoke the getErgs function from code instead of $compile-ing the code and delegating the task to Angular.

但是,正如我在评论中所建议的那样,因为你可以访问CircleChart中的整个范围(我认为这可能是一种矫枉过正),你应该在d3中捕获click事件并从代码而不是$ compile-调用getErgs函数。代码并将任务委托给Angular。