我正在将基于D3的网站迁移到有角度的图表。每个单独的图表仍将由D3绘制,但每个图表都将在角色directive
上绘制图表。
其中一个图表元素由图表(SVG)和充当其图例的HTML表组成。
[ svg (chart) ][ table (legend) ]
D3绘制图表,我使用ng-repeat
绘制图例。在这种情况下,图例和图表都需要是交互式的:需要有DOM事件监视器。然而,指令的控制器在 ng-repeat绘制图例之前运行(因此DOM元素尚不存在)。
视图:
<div ng-transclude></div>
<div class="wrapper">
<svg></svg>
<div class="valign">
<table>
<tr>
<th>#</th>
<th>Name</th>
<th>BTC</th>
<th>USD</th>
</tr>
<tr ng-repeat="item in items" class="legend item-{{item.title}}" title="{{item.title}}">
<th>{{$index + 1}}</th>
<td>{{item.title}}</td>
<td>{{item.btc | bitcoin}}</td>
<td>{{item.usd | currency}}</td>
</tr>
</table>
</div>
</div>
指令:
angular
.module('d3.charts', [])
.directive('volumeElement', function() {
return {
restrict: 'E',
scope: {
data: '='
},
transclude: true,
link: function(scope, element, attrs) {
// todo: this needs to be changed upstream in the volume controller
scope.mode = '24h';
// the d3 chart function
var chart = new window.WZB.VolumeChart(
element.find('svg')[0],
scope.data
);
var $paths, $legend;
var render = function() {
chart.mode = scope.mode;
chart.render();
$paths = element.find('.interactive');
addHovers();
}
var addHovers = function() {
// PROBLEM: at this point the ng-repeat has not populated the legend yet
$legend = element.find('.legend')
$paths.hover(function(e) {
var $path = $(e.target);
var title = $path.attr('title');
var legend = $legend
.filter(function() {
var nonActive = $(this).attr('title') !== title;
if(!nonActive)
$(this).removeClass('blur')
return nonActive;
})
$paths
.not($path)
.add(legend)
.addClass('blur');
}, function() {
$paths.add($legend)
.removeClass('blur');
})
}
render();
},
templateUrl: '/volume-element.html'
}
})
我正在使用jQuery来获得更高级的DOM manips,我不仅可以依赖angular ng-mouseover
指令,因为我需要角度生成表和D3生成SVG的事件监听器。
如果ng-repeat
填充了图例,我该如何执行代码?
Hacky解决方案:
// todo: proper fix
// see @link https://stackoverflow.com/questions/24035289/angularjs-add-jquery-dom-eventlisteners-after-ng-repeat
setTimeout(addHovers, 0);
答案 0 :(得分:0)
我重构了代码,我并没有以有棱角的方式思考。包含新指令,d3也创建表,而不是混合角度和d3用于相同的可视化。这样我就不再需要jQuery了。