D3.js中的Calendar View详解

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和逻辑算法,还是有点模糊,有待好好提高。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值