您的位置:首页 > Web前端 > JavaScript

D3.js中的Calendar View详解

2017-12-05 11:28 267 查看

Calendar View

今天我们来聊一聊绚丽多彩的Calendar View。d3.js官网中Calendar View展示的是从1990.01.01到2010.10.01日 Yahoo! Finance的股票情况。

先来张Calendar View的靓照,如图所示(由于图片较大,只截取了部分):



接下来详细解读实现这张图的源码

index.html文件解读—— [ 源码 ]

<!DOCTYPE html>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var width = 960,
height = 136,
cellSize = 17;   //定义每个方格的大小

var formatPercent = d3.format(".1%"); //定义一个百分数格式函数,规定百分数精确度小数点后1位

// 定义颜色函数,使用量化比例尺映射,即定义域为连续的,从-0.05到0.05,而值域是离散的颜色值
var color = d3.scaleQuantize()
.domain([-0.05, 0.05])
.range(["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"]);

// 定义10个svg组,分别用来展示从1990年到2010年的数据
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(1990, 2011))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");

// 定义每个年份对应的group旁边的标签
svg.append("text")
//定义标签文字(年份)的位置以及文字的旋转角度、文字内容
.attr("transform", "translate(-6," + cellSize * 3.5 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.text(function(d) { return d; });

// 定义每个年份中代表天的小方格
var rect = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#ccc")
.selectAll("rect")
//计算一组小方格的数量,调用d3的timeDays方法,获取两个时间之间的天数,例如,计算从1999年的第一天到2000年的第一天,则参数为new Date(1999,0,1)到 new Date(2000,0,1),timeDays返回天序列
.data(function(d) { return d3.timeDays(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
// 返回一年有多少个周,确定一组小方格的横向位置
.attr("x", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize; })
// 返回天,确定一组小方格的纵向位置
.attr("y", function(d) { return d.getDay() * cellSize; })
// 定义当前小方格上对应的日期的格式
.datum(d3.timeFormat("%Y-%m-%d"));

// 勾勒月份的分割线
svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll("path")
.data(function(d) { return d3.timeMonths(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("d", pathMonth);

d3.csv("dji.csv", function(error, csv) {
if (error) throw error;

// 这里的d3.nest可以参考http://blog.csdn.net/gdp12315_gu/article/details/51721988
var data = d3.nest()
// 以d.Date来对数据进行分组
.key(function(d) { return d.Date; })
// rollup函数用来获取每个组的values,因为一组为一天,只有一行数据,因此这里定义每个组的values 用d[0],即d[0].Close - d[0].Open) / d[0].Open来计算产生数值values
.rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
// 个人理解,这里的.object()函数类似于call()函数,用来将定义的分组机制应用到csv数据上,返回分组后的对象,官网对nest().object()的解释:Applies the nest operator to the specified array, returning a nested object.有没有醍醐灌顶的感觉,哈哈
.object(csv);
// 过滤操作,挑出日期在data中的小方格(因为周六、周日没有在data中,周六周日小方格填充色为默认白色)
rect.filter(function(d) { return d in data; })
// 定义小方格的填充色,通过每个小方格中的values值来映射颜色函数
.attr("fill", function(d) { return color(data[d]); })
.append("title")
// 定义小方格的title属性文本为 日期后面加小方格value对应的的百分比格式
.text(function(d) { return d + ": " + formatPercent(data[d]); });
});

// 定义月份分割线路径
function pathMonth(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = t0.getDay(), w0 = d3.timeWeek.count(d3.timeYear(t0), t0),
d1 = t1.getDay(), w1 = d3.timeWeek.count(d3.timeYear(t1), t1);
return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize
+ "H" + w0 * cellSize + "V" + 7 * cellSize
+ "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize
+ "H" + (w1 + 1) * cellSize + "V" + 0
+ "H" + (w0 + 1) * cellSize + "Z";
}

</script>


至此,Calendar View的实现讲解完毕,自我感觉现在挖的不够深,只懂得实现的大体思路,深入的细节所涉及的某些API和逻辑算法,还是有点模糊,有待好好提高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  d3 d3.js Calendar