Even Simpler Tooltip with D3.js and AngularJS
Using $compile to apply an angularjs tooltip directive to a d3 visualization.
HTML
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.6.0/ui-bootstrap-tpls.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<div ng-app="myApp" ng-controller="myCtrl">
<div my-nodes></div>
<button ng-click="moveDots()">Move the dots</button>
</div>
JavaScript
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)
}
}
};
}]);