Reputation: 147
I would like to report a rather strange behaviour when using jointly angularjs and d3js. The following plunker illustrates it: Plunker
Here is the directive that does most of the job:
.directive('element1', function() {
return {
restrict: 'E',
replace: true,
template: '<svg></svg>',
link: function (scope, element, attrs) {
var rootElmt = d3.select(element[0]);
rootElmt.append("g")
.selectAll("text")
.data(["Hello World"])
.enter()
.append("text")
.attr("x", 20)
.attr("y", 20)
.text(function(d) {
return d;
});
rootElmt.selectAll("text")[0]
.forEach(function(d) {
console.log("text length: ", d.getComputedTextLength());
});
}
}
});
You will certainly notice that the custom element directive element1 does lots of unnecessary work on the sole basis of the obtained result - actually, I isolated the core of a problem occuring in a much more complex piece of software, where this apparatus is needed to some extent.
The plunker produces the expected result, i.e. showing a SVG text string, and logging the result of getComputedTextLength() applied on the latter. The plunker uses angularjs v1.2.0rc3.
Now, if you comment the 1.2.0rc3 script loading clause, and uncomment that of the 1.2.17 (i.e. a fairly recent version), the code runs into an error, caused by getComputedTextLength being undefined.
This error can be traced back to the properties of the text object: while older versions of angular provided with SVGTextElement objects (i.e. from the SVG prototype chain), newer versions bring HTMLUnknownElement objects - causing the notable absence of the getComputedTextLength method.
Can this be the cause of some intricate interaction between angularjs and d3? Maybe my directive code does not comply to recent angularjs best practices?
Thanks by advance for your keen help!
Upvotes: 1
Views: 304
Reputation: 19377
The root of the problem is that you're creating your SVG node in the Angular template rather than deferring to the D3 code to create it inside the directive:
template: '<svg></svg>',
This appears to be related to Angular issue #7383, which seems to have been introduced in version 1.2.16.
I see the 1.3 branch (not yet released) has an upcoming feature #7265 to restore this support:
Previously, templates would always be assumed to be valid HTML nodes. In some cases, it is desirable to use SVG or MathML or some other language.
To work around this in Angular 1.2.x, you can simply remove the template property from your directive and create the SVG node from the D3 code instead:
// create it here instead:
var rootElmt = d3.select(element[0]).append('svg');
Upvotes: 1