问题
I am searching how to display information about a bubble D3.js in AngularJS. I can show an alert with the desired information but I can't display informations on the page with AngularJS because I have no access to the $scope because my graphe is in a directive... How can I pass the informations without change the structure of the web app ? I can't put the formation the bubble chart outsite of this directive. This is my HTML :
<body ng-app="d3DemoApp">
<div id="graph1" ng-controller="controllerBubble">
The package name should appear here : {{packageName}}
<bubble-chart chart-data="chartData"></bubble-chart>
</div>
</body>
The service :
d3DemoApp.service('dataService', function AppCtrl($http, $q) {
this.getCommitData = function(param) {
var deferred = $q.defer();
$http({
method: 'GET',
url: param
}).
success(function(data) {
deferred.resolve({
chartData: data,
error: ''
});
}).
error(function(data, status) {
deferred.resolve({
error: status
});
});
return deferred.promise;
};
});
The controller :
var d3DemoApp = angular.module('d3DemoApp', []);
// controller business logic
d3DemoApp.controller('controllerBubble', function AppCtrl($rootScope, $scope, dataService) {
$scope.choice = 'data.json';
loadData($scope.choice);
function loadData(param) {
dataService.getCommitData(param).then(function(res) {
if (res.error) {
$scope.error = res.error;
return false;
}
$scope.chartData = res.chartData;
});
}
});
d3DemoApp.directive('bubbleChart', function() {
return {
restrict: 'EA',
transclude: true,
scope: {
chartData: '='
},
link: function(scope, elem, attrs) {
scope.$watch('chartData', function(newValue, oldValue) {
console.info('new data comes to directive');
console.info(newValue);
if (newValue) {
scope.drawChart(newValue);
}
});
scope.drawChart = function(rootData) {
var diameter = 900,
format = d3.format(",d"),
color = d3.scale.category20c();
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.value(function(d) {
return (d.numberOfLink + 1);
})
.padding(1.5);
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
var filt = svg.append("defs")
.append("filter")
.attr({
id: "f1",
x: 0,
y: 0,
width: "200%",
height: "200%"
});
filt.append("feOffset").attr({
result: "offOut",
"in": "sourceAlpha",
dx: 10,
dy: 10
});
filt.append("feGaussianBlur").attr({
result: "blurOut",
"in": "offOut",
stdDeviation: 10
});
var feMerge = filt.append("feMerge");
feMerge.append("feMergeNode").attr("in", "offsetBlur")
feMerge.append("feMergeNode").attr("in", "SourceGraphic");
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(rootData))
.filter(function(d) {
return !d.children;
}))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
node.append("title")
.text(function(d) {
return d.className + ": " + format(d.value);
});
node.append("circle")
.attr("r", function(d) {
return d.r;
})
.style("fill", function(d) {
return "red";
});
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) {
return d.className.substring(0, d.r / 3);
})
node.on("click", click);
function click(d) {
alert(d.packageName);
$scope.packageName = d.packageName; // How to access to the scope ?
}
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
var classes = [];
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) {
recurse(node.name, child);
});
else classes.push({
packageName: name,
className: node.name,
value: node.numberOfLink,
idProjet: node.projectId,
numberOfLink: node.numberOfLink,
priority: node.priority
});
}
recurse(null, root);
return {
children: classes
};
}
d3.select(self.frameElement).style("height", diameter + "px");
}
if (typeof scope.chartData != "undefined") {
scope.drawChart(scope.chartData);
}
}
};
});
This is an online example of the problem with Plunker : https://plnkr.co/edit/LUa7RHxjSaVe1KTzy33c?p=preview
Hope someone will can make works the Plunker ! Thanks.
回答1:
Here's the result: https://plnkr.co/edit/CnoTA0kyW7hWWjI6DspS?p=preview
You have to create a shared service/factory between your controllers in order to do that. There are lots of examples out there.
angular.module('d3DemoApp').factory('NotifyingService', function($rootScope) {
return {
subscribe: function(scope, callback) {
var handler = $rootScope.$on('notifying-service-event', callback);
scope.$on('$destroy', handler);
},
notify: function(msg) {
$rootScope.$emit('notifying-service-event', msg.packageName);
}
};
});
回答2:
I have implemented in a different way, passing a variable from the parent scope to the directive which is in isolated scope mode was a good and clean solution for me, most of the open source project I have seen implemented in the same way. In that case you can even call functions inside your directive if it's related to your component workflow here is a link to the project and let me know what do you think https://github.com/amgadfahmi/angular-bubbletree
来源:https://stackoverflow.com/questions/37294036/display-informations-about-a-bubble-chart-d3-js-in-angularjs