使用angular-nvd3构造圆形分数
目标简介
一个漂亮的分数显示,从0-100,就像下面几个图那样:



所用到的技术
angularjs [1] 是非常著名的前端MVC框架,由google支持的开源项目。
d3 [2] 是基于SVG的数据可视化技术,是教底层的可扩展的库。
nvd3 [3] 是对d3的封装,实现了柱状图、折线图、饼图等常用的统计图形的定制库,增加了d3的易用性。
angular-nvd3 [4] 是nvd3在angular框架中的进一步封装,使得其在angular用户中更加易用。
要使用angular-nvd3,html页面中需要包含如下片段(假设各个模块已经下载到本地,使用cdn的读者自行替换):
<link href="bower_components/nvd3/build/nv.d3.min.css" rel="stylesheet">
<script src="bower_components/d3/d3.min.js"></script>
<script src="bower_components/nvd3/build/nv.d3.min.js"></script>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-nvd3/dist/angular-nvd3.min.js"></script>
实现思路
在nvd3中,由于饼图(pieChart)可以定制成中间掏空环形图(donut),我们可以以此为基础来构造整个图形:
- 外圈绿色和灰色构成的环形图;
- 中圈白色和黄色构成的环形图;
- 内圈直接使用div
外圈环形图需要两个值, score和100-score; 中圈一样; 内圈通过css设置border-radius为50%来构成一个整圆形,使用line-height来居中。
不过,怎么使这两个环与中间的圆都是同心圆呢?这需要如下两个条件:
- 容器为正方形,绝对定位
- 两个nvd3图的选项,四边的border都是0
参考源代码
index.html
<html>
<head>
<title>漂亮的分数</title>
<link href="bower_components/nvd3/build/nv.d3.min.css" rel="stylesheet">
<script src="bower_components/d3/d3.min.js"></script>
<script src="bower_components/nvd3/build/nv.d3.min.js"></script>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-nvd3/dist/angular-nvd3.min.js"></script>
<link href="index.css" rel="stylesheet" >
</head>
<body ng-app="demoApp">
<h1>漂亮的分数</h1>
<div style="width: 400px; height: 400px; position:absolute;" ng-controller="DemoCtrl" >
<nvd3 options="chart.options" data="scoreData" class="full" ></nvd3>
<div style="width: 75%; height: 75%; margin-left: 12.5%; margin-top: 12.5%; position:absolute;">
<nvd3 options="chart.options_inner" data="scoreData" class="full" ></nvd3>
</div>
<div style="width: 80%; height: 80%; margin-left: 10%; margin-top: 10%; position:absolute;">
<div style="position:absolute; width: 50%; height: 50%; left: 25%; top: 25%; background: black; border-radius: 50%; text-align: center; color: white; line-height: 45px;">
<span style="font-size:2.5em; line-height: 160px;" >{{score}}分</span>
</div>
</div>
</div>
<script type="text/javascript">
angular.module("demoApp", ['nvd3'])
.controller("DemoCtrl", function($scope){
$scope.xFunction = function(){
return function(d){
return d.key;
};
};
$scope.yFunction = function(){
return function(d){
return d.value;
};
};
function init(){
$scope.score = 95;
$scope.chart = {};
$scope.chart.options = {
chart:{
type: 'pieChart',
margin: { left: 0, top: 0, right: 0, bottom: 0},
donut: true,
donutRatio: 0.60,
x: $scope.xFunction(),
y: $scope.yFunction(),
showLabels: false,
showLegend: false,
color: ['rgb(130,201,63)', 'lightgray']
}
};
$scope.chart.options_inner = {
chart:{
type: 'pieChart',
margin: { left: 0, top: 0, right: 0, bottom: 0},
donut: true,
donutRatio: 0.5,
x: $scope.xFunction(),
y: $scope.yFunction(),
showLabels: false,
showLegend: false,
color: ['transparent', 'rgb(252,225,11)']
}
};
}
init();
$scope.$watch('score', function(nv, ov){
if( nv ){
$scope.scoreData = [
{key: 'score', value: nv },
{key: 'other', value: 100-nv }
];
$scope.chart.data = {
key: 'thekey',
data: $scope.scoreData
};
}
});
});
</script>
</body>
</html>
index.css
.full{
position:absolute;
width: 100%;
height: 100%;
}