在ng repeat中隔离AngularJS指令中多个d3组件的作用域
我正在使用ng repeat和使用AngularJS指令构建的D3拨号盘构建一个动态仪表板 当我运行1指令标记时,它工作正常。当我在ng repeat中有2+个指令标记时,它看起来像是一个奇怪的竞争条件,其中指令使用相同的变量。如何保证指令实例具有完全隔离的作用域 看起来我在隔离进度变量时遇到了问题。2个刻度盘(指令实例)插入了相同的进度值,结果搞砸了。我尝试将progress变量移动到指令中的不同范围,但找不到解决方案 HTML:在ng repeat中隔离AngularJS指令中多个d3组件的作用域,angularjs,d3.js,angularjs-directive,Angularjs,D3.js,Angularjs Directive,我正在使用ng repeat和使用AngularJS指令构建的D3拨号盘构建一个动态仪表板 当我运行1指令标记时,它工作正常。当我在ng repeat中有2+个指令标记时,它看起来像是一个奇怪的竞争条件,其中指令使用相同的变量。如何保证指令实例具有完全隔离的作用域 看起来我在隔离进度变量时遇到了问题。2个刻度盘(指令实例)插入了相同的进度值,结果搞砸了。我尝试将progress变量移动到指令中的不同范围,但找不到解决方案 HTML: 我把这个修好了。我认为主要的问题是在转换线上添加一个D3 se
我把这个修好了。我认为主要的问题是在转换线上添加一个D3 select(),以便D3知道它正在转换哪个拨号盘。我还从指令中删除了append SVG,现在文档中只有一个SVG。该指令正在SVG标记下追加组。看起来棒极了 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);
});
}
}
});
<div ng-controller="DashboardCtrl" ng-init="init();">
<svg id="d3Parent" width="1000" height="1000" fill="#2E7AF9">
</svg>
<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.00001;
return {
restrict: 'E',
transclude: true,
scope: {
val: '=',
dataFormat: '=',
metricTitle: '=',
ghTarget: '='
},
link: function (scope, element, attrs) {
console.debug(attrs['data-format']);
var formatPercent = d3.format(scope.dataFormat);
var total = scope.ghTarget.valueOf() ;
var prepend = "" ;
if (scope.dataFormat === "$") prepend = "$" ;
console.debug("prepend: "+scope.prepend);
console.debug("data format: "+scope.dataFormat );
var index = document.querySelector("#d3Parent").childNodes.length-1 ;
var column = [200, 600];
var row = [200, 500, 750]
// set up initial svg object
var vis = d3.select("#d3Parent")
.append("g")
.attr("transform", "translate(" + column[index%2] + "," + row[0] + ")");
scope.$watch('val', function (newVal, oldVal) {
console.debug("directive watch fired:"+scope.metricTitle);
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","24px");
var text2 = meter.append("text")
.attr("y", 40)
.attr("text-anchor", "middle")
.attr("class", "text2");
console.debug(scope.metricTitle);
text2.text(scope.metricTitle);
var percentage = newVal.expr0.valueOf() ;
console.debug("animate progress: "+progress+" percentage:"+percentage+" total:"+total);
var i = d3.interpolateNumber(progress, percentage/total);
d3.select(vis).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);
};
});
});
}
}
});