问题
Given the following use-case:
I use D3js to render objects which are managed by AngularJS. I would like to add interactivity to the D3 chart. When clicking on a svg element I would like to have a kind of popup menu allowing to modify the object properties. These properties are required by AngularJS but are not rendered by D3.
The D3-Angular integration is derived from http://bl.ocks.org/biovisualize/5372077 which uses a closure.
Current implementation:
As of today I am using the $modal service from angular-ui bootstrap to create the popup menu. From a functionnality point of view it works pretty well: When clicking on a svg element, D3 dispatches an event That event is catched by Angular which calls the $modal service Within the modal window I modify the object properties
However I am not satisfied with the rendering. I would like the popup menu to look like a popover. It should be placed close to the svg element which was clicked.
As far as I understand, I have two options:
- Continue to use the $modal service and modify its look. What approach should be taken? Using the windowClass option?
- Stop using the $modal service and start hacking on the popover directive. The problem is that I do not think it is possible to add such a directive to an svg element. The solution would be to create a popover service close to the $modal service.
Which option should be chosen? and how to implement it?
EDIT:
Working plunker using a custom my-popover directive: http://plnkr.co/edit/5KYvxi?p=preview
回答1:
It is possible to add a directives to code generated by d3
, only thing you need to ensure is that you call the $compile service on the content after it has been rendered.
For the given example, it would look something like this:
.directive('barChart', function($compile){ // inject $compile
var chart = d3.custom.barChart();
return {
restrict: 'E',
replace: true,
template: '<div class="chart"></div>',
scope:{
height: '=height',
data: '=data',
hovered: '&hovered'
},
link: function(scope, element, attrs) {
var chartEl = d3.select(element[0]);
chart.on('customHover', function(d, i){
scope.hovered({args:d});
});
scope.$watch('data', function (newVal, oldVal) {
chartEl.datum(newVal).call(chart);
$compile(element.contents())(scope); // <-- call to $compile
});
scope.$watch('height', function(d, i){
chartEl.call(chart.height(scope.height));
$compile(element.contents())(scope); // <-- call to $compile
})
}
}
And in the d3
's drawing function:
bars.enter().append('rect')
.classed('bar', true)
.attr('myPopover', 'Text to show') // <-- Adding an attribute here.
.attr({x: chartW,
width: barW,
y: function(d, i) { return y1(d); },
height: function(d, i) { return chartH - y1(d); }
})
.on('mouseover', dispatch.customHover);
Demo
来源:https://stackoverflow.com/questions/19656365/angular-ui-d3-how-to-implement-contextual-menu-popover-vs-modal