ng-repeat を使用し、AngularJS ディレクティブを使用して構築された D3 ダイヤルを使用して動的ダッシュボードを構築しています。
1 つのディレクティブ タグを実行すると、正常に動作します。ng-repeat に 2 つ以上のディレクティブ タグがある場合、ディレクティブが同じ変数を使用している奇妙な競合状態が発生しているように見えます。ディレクティブ インスタンスのスコープが完全に分離されていることを保証するにはどうすればよいですか?
プログレス変数の分離に問題があるようです。2 つのダイヤル (ディレクティブ インスタンス) が同じ進捗値を補間しており、めちゃくちゃになっています。プログレス変数をディレクティブ内の別のスコープに移動しようとしましたが、解決策が見つかりません。
HTML:
<div ng-controller="DashboardCtrl" ng-init="init();">
<div ng-repeat="item in metrics">
<div ng-switch on="item.type">
<div ng-switch-when="dial">
<gh-dial val="item.data" data-format="item.data-format" metric-title="item.title" gh-target="item.target"></gh-dial>
</div>
<div ng-switch-when="meter">
<gh-meter val="item.data" data-format="item.data-format" metric-title="item.title" gh-target="item.target"></gh-meter>
</div>
</div>
</div>
</div>
指令:
directives.directive('ghDial', function () {
var width = 370,
height = 370,
twoPi = 2 * Math.PI,
progress = 0;
return {
restrict: 'E',
scope: {
val: '=',
dataFormat: '=',
metricTitle: '=',
ghTarget: '='
},
link: function (scope, element, attrs) {
console.debug(scope.dataFormat);
var formatPercent = d3.format(scope.dataFormat);
var total = scope.ghTarget.valueOf() ;
var prepend = "" ;
if (scope.dataFormat === "$") scope.prepend = "$" ;
console.debug("prepend: "+scope.prepend);
console.debug("data format: "+scope.dataFormat );
// set up initial svg object
var vis = d3.select(element[0]).append("svg")
.attr("width", width)
.attr("height", height)
.attr('fill', '#2E7AF9')
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
scope.$watch('val', function (newVal, oldVal) {
vis.selectAll('*').remove();
// if 'val' is undefined, exit
if (!newVal) {
return;
}
var arc = d3.svg.arc()
.startAngle(0)
.innerRadius(140)
.outerRadius(170)
;
var meter = vis.append("g")
.attr("class", "progress-meter");
meter.append("path")
.attr("class", "background")
.attr("d", arc.endAngle(twoPi));
var foreground = meter.append("path")
.attr("class", "foreground");
var text = meter.append("text")
.attr("text-anchor", "middle")
.style("font-size","14px");
var text2 = meter.append("text")
.attr("y", 40)
.attr("text-anchor", "middle")
.attr("class", "text2");
console.debug(scope.metricTitle);
text2.text(scope.metricTitle);
var animate = function(percentage) {
var i = d3.interpolate(progress, percentage/total);
d3.transition().duration(800).tween("progress", function () {
return function (t) {
progress = i(t);
foreground.attr("d", arc.endAngle(twoPi * progress));
console.debug("progress:"+progress);
text.text(prepend+''+percentage);
};
});
};
setTimeout(function () {
console.debug(newVal);
animate(newVal.expr0.valueOf());
}, 500);
});
}
}
});