D3js 与 Angular
将 D3js 与 Angular 一起使用可以开辟新的可能性前沿,例如一旦更新数据就可以实时更新图表。我们可以在 Angular 指令中封装完整的图表功能,这使其易于重复使用。
index.html >>
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script data-require="angular.js@1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<script src="app.js"></script>
<script src="bar-chart.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<!-- reusable d3js bar-chart directive, data is sent using isolated scope -->
<bar-chart data="data"></bar-chart>
</div>
</body>
</html>
我们可以使用控制器将数据传递到图表,并监视数据中的任何更改,以便在指令中实现图表的实时更新:
app.js >>
angular.module('myApp', [])
.controller('MyCtrl', function($scope) {
$scope.data = [50, 40, 30];
$scope.$watch('data', function(newVal, oldVal) {
$scope.data = newVal;
}, true);
});
最后,指令定义。我们编写的用于创建和操作图表的代码将位于指令的 link 函数中。
请注意,我们在指令中也放置了一个范围。$ watch,以便在控制器传递新数据后立即更新。如果有任何数据更改,我们正在为数据变量重新分配新数据,然后调用 repaintChart()
函数,该函数执行图表重新呈现。
bar-chart.js >>
angular.module('myApp').directive('barChart', function($window) {
return {
restrict: 'E',
replace: true,
scope: {
data: '='
},
template: '<div id="bar-chart"></div>',
link: function(scope, element, attrs, fn) {
var data = scope.data;
var d3 = $window.d3;
var rawSvg = element;
var colors = d3.scale.category10();
var canvas = d3.select(rawSvg[0])
.append('svg')
.attr("width", 300)
.attr("height", 150);
// watching for any changes in the data
// if new data is detected, the chart repaint code is run
scope.$watch('data', function(newVal, oldVal) {
data = newVal;
repaintChart();
}, true);
var xscale = d3.scale.linear()
.domain([0, 100])
.range([0, 240]);
var yscale = d3.scale.linear()
.domain([0, data.length])
.range([0, 120]);
var bar = canvas.append('g')
.attr("id", "bar-group")
.attr("transform", "translate(10,20)")
.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr("class", "bar")
.attr("height", 15)
.attr("x", 0)
.attr("y", function(d, i) {
return yscale(i);
})
.style("fill", function(d, i) {
return colors(i);
})
.attr("width", function(d) {
return xscale(d);
});
// changing the bar widths according to the changes in data
function repaintChart() {
canvas.selectAll('rect')
.data(data)
.transition()
.duration(800)
.attr("width", function(d) {
return xscale(d);
})
}
}
}
});