贡献图

前言

这次要做的 Web 前端实战是一个 Gitee 个人主页下的贡献图。整体来说这个案例并不难,主要是控制第一个节点以及最后一个节点处于星期几,且必须保持365个节点。

效果演示

title:(贡献图源码) cover:(https://img2020.cnblogs.com/blog/1957096/202005/1957096-20200527110106198-1974765350.jpg) link:(https://github.com/Himmeltala/learnplace/tree/main/Web%20%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/ECMAScript/01-practice)

布局设计

整体的布局是上下,顶部一个 div、下面一个 div。下面的 div 是左右布局,左边是星期、右边是贡献节点。一列贡献节点一共有7个(不一定每一列都是7个)。星期要与每一行贡献节点保持平行。左右布局的高度保持一致,因此,每一个贡献节点的宽和高就取自布局的高/7

<div id="cb-chart">
  <div class="top-bar">
    <div class="occupation"></div>
    <div class="months"></div>
  </div>
  <div class="bottom">
    <div class="left-side">
      <div class="week">周一</div>
      <div class="week">周四</div>
      <div class="week">周日</div>
    </div>
    <div class="right-side"></div>
  </div>
</div>

CSS 样式

div#cb-chart

div.top-bardiv.bottom两个容器内的元素都是水平方向排列。div.top-bar的高度占整个div#cb-chart的 20%;div.bottom自然就是 80%。

顶部所占比例 20%

#cb-chart {
  width: 940px;
  height: 140px;
}

#cb-chart .top-bar {
  display: flex;
  height: 20%;
  width: 100%;
}

#cb-chart .bottom {
  display: flex;
  height: 80%;
  width: 100%;
}

div.bottom

星期与贡献节点是左右排列在整个容器的,且星期占整个容器的 8%:

#cb-chart .bottom .left-side {
  width: 8%;
  height: 100%;
}

#cb-chart .bottom .right-side {
  width: 92%;
  height: 100%;
}

星期下的所有元素要均匀分配整个div.left-side的纵向空间:

#cb-chart .bottom .left-side {
  /* ...... */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

div.right-side中的所有元素(贡献节点)都是从上到下排列,若超出容器的空间时自动换行,左右之间的元素要保持垂直水平对齐:

#cb-chart .bottom .right-side {
  /* ...... */
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  flex-direction: column;
  align-content: center;
  align-items: center;
}

div.top-bar

下面两张图显示了顶部容器最左边有一个不显示的且占了空间的元素,主要目的是用来隔开星期剩余的空间,使顶部容器的每一个月份能够完美对齐下面的贡献节点。

顶部右侧所占比率 92%

顶部左侧所占比率 8%

因此在div.top-bar中加了一个空元素<div class="occupation"></div>

#cb-chart .top-bar .occupation {
  width: 8%;
}

div.left-side的宽度 8%,所以它也是 8%;而div.months自然就占整个容器的 92%。

#cb-chart .top-bar .months {
  font-size: 12px;
  height: 100%;
  width: 92%;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: center;
}

div.point

这个就是每一个贡献节点元素的样式,宽高必须要经过计算之后才可以给出来,节点的宽和高取自div.bottom 的高/7。使用 CSS var() 函数代替固定的值:

#cb-chart .bottom .right-side .point {
  width: var(--point-size);
  height: var(--point-size);
  border: 1px solid #fff;
  box-sizing: border-box;
  background-color: white;
}

JS 部分

绘制节点图

在开始之前要给div.right-side处添加大于365个的贡献节点的 div 元素:

function drawChartGrid() {
  let $el = $("#cb-chart .bottom .right-side");
  $el.css("--point-size", `${$el.height() / 7}px`);
  for (let h = 0; h < 54; h++) {
    for (let v = 0; v < 7; v++) {
      $el.append(`<div class="point"></div>`);
    }
  }
}

函数绘制的空白节点图,待用数据填充

定位起始节点和结束节点

这些贡献度节点的数量是大于365个的,并且每一天的星期数都是有变化的,所以要计算今天是星期几,以及去年的今天是星期几,这样才可以定位起始节点和结束节点。

从起始节点开始,循环到结束节点,这之间就是准确的节点数量,一共365个。使用 $().slice(start, end)函数循环,循环对象是div.right-side下的所有div.point

函数需要两个变量来控制循环,起始和结束。起始就是去年的今天的星期是几?在 JS Date() 对象中,索引值 1 代表星期一;索引值 0 代表星期日。由于贡献节点的索引值是从 0 开始的,所以,索引值 0 代表星期一,6 代表星期日。所以,要进行计算:

星期 Date 中的索引值 贡献节点索引值
星期一 1 0
星期二 2 1
星期三 3 2
星期四 4 3
星期五 5 4
星期六 6 5
星期日 0 6

查找规律,除星期日以外,Date 中的索引值与贡献节点的索引值总是相差 1。所以,只需要 Date 中的索引值(weekIndex)减去 1 就知道slice()函数从哪里开始。

特殊情况星期日:当weekIndex - 1 < 0时,说明是星期日,函数要从索引值 6 开始。

function drawPoints() {
  let nowDate = new Date();
  let oldDate = new Date(`${nowDate.getFullYear() - 1}-${nowDate.getMonth() + 1}-${nowDate.getDate()}`);

  let weekIndex = oldDate.getDay();

  let start = weekIndex - 1 < 0 ? 6 : weekIndex - 1;
  let end = start === 6 ? 372 : 365 + weekIndex;

  $(`#cb-chart .bottom .right-side .point`)
    .slice(start, end)
    .each((i, el) => {
      // ......
    });
}

绘制节点颜色

节点的颜色根据贡献的数量来设置:

function setPointColor(el, number) {
  if (number > 0 && number <= 5) {
    $(el).addClass("a-type-point");
  } else if (number > 5 && number <= 10) {
    $(el).addClass("b-type-point");
  } else if (number > 10 && number <= 15) {
    $(el).addClass("c-type-point");
  } else if (number > 15) {
    $(el).addClass("d-type-point");
  } else {
    $(el).addClass("e-type-point");
  }
}

函数要获取当前循环的贡献节点的 DOM 对象,以及这个节点对应的贡献数量。函数在下面进行调用:

function drawPoints() {
  // ......
  let data = getPointsData(oldDate);
  $(`#cb-chart .bottom .right-side .point`)
    .slice(start, end)
    .each((i, el) => {
      setPointColor(el, data[i].number);
    });
}

这里出现了一个 getPointsData 函数,暂时不用管,它是随机生成数据的函数。

posted @   Himmelbleu  阅读(139)  评论(0编辑  收藏  举报
首页
随笔
博客园
我的
标签
管理
贡献图
发表于 2022-07-24 00:53
|
已有 139 人阅读
|
留下 0 条评论
|
全文字数 ≈ 813字

前言

这次要做的 Web 前端实战是一个 Gitee 个人主页下的贡献图。整体来说这个案例并不难,主要是控制第一个节点以及最后一个节点处于星期几,且必须保持365个节点。

效果演示

布局设计

整体的布局是上下,顶部一个 div、下面一个 div。下面的 div 是左右布局,左边是星期、右边是贡献节点。一列贡献节点一共有7个(不一定每一列都是7个)。星期要与每一行贡献节点保持平行。左右布局的高度保持一致,因此,每一个贡献节点的宽和高就取自布局的高/7

HTML
<div id="cb-chart">
  <div class="top-bar">
    <div class="occupation"></div>
    <div class="months"></div>
  </div>
  <div class="bottom">
    <div class="left-side">
      <div class="week">周一</div>
      <div class="week">周四</div>
      <div class="week">周日</div>
    </div>
    <div class="right-side"></div>
  </div>
</div>

CSS 样式

div#cb-chart

div.top-bardiv.bottom两个容器内的元素都是水平方向排列。div.top-bar的高度占整个div#cb-chart的 20%;div.bottom自然就是 80%。

顶部所占比例 20%

CSS
#cb-chart {
  width: 940px;
  height: 140px;
}

#cb-chart .top-bar {
  display: flex;
  height: 20%;
  width: 100%;
}

#cb-chart .bottom {
  display: flex;
  height: 80%;
  width: 100%;
}

div.bottom

星期与贡献节点是左右排列在整个容器的,且星期占整个容器的 8%:

CSS
#cb-chart .bottom .left-side {
  width: 8%;
  height: 100%;
}

#cb-chart .bottom .right-side {
  width: 92%;
  height: 100%;
}

星期下的所有元素要均匀分配整个div.left-side的纵向空间:

CSS
#cb-chart .bottom .left-side {
  /* ...... */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

div.right-side中的所有元素(贡献节点)都是从上到下排列,若超出容器的空间时自动换行,左右之间的元素要保持垂直水平对齐:

CSS
#cb-chart .bottom .right-side {
  /* ...... */
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  flex-direction: column;
  align-content: center;
  align-items: center;
}

div.top-bar

下面两张图显示了顶部容器最左边有一个不显示的且占了空间的元素,主要目的是用来隔开星期剩余的空间,使顶部容器的每一个月份能够完美对齐下面的贡献节点。

顶部右侧所占比率 92%

顶部左侧所占比率 8%

因此在div.top-bar中加了一个空元素<div class="occupation"></div>

CSS
#cb-chart .top-bar .occupation {
  width: 8%;
}

div.left-side的宽度 8%,所以它也是 8%;而div.months自然就占整个容器的 92%。

CSS
#cb-chart .top-bar .months {
  font-size: 12px;
  height: 100%;
  width: 92%;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: center;
}

div.point

这个就是每一个贡献节点元素的样式,宽高必须要经过计算之后才可以给出来,节点的宽和高取自div.bottom 的高/7。使用 CSS var() 函数代替固定的值:

CSS
#cb-chart .bottom .right-side .point {
  width: var(--point-size);
  height: var(--point-size);
  border: 1px solid #fff;
  box-sizing: border-box;
  background-color: white;
}

JS 部分

绘制节点图

在开始之前要给div.right-side处添加大于365个的贡献节点的 div 元素:

JS
function drawChartGrid() {
  let $el = $("#cb-chart .bottom .right-side");
  $el.css("--point-size", `${$el.height() / 7}px`);
  for (let h = 0; h < 54; h++) {
    for (let v = 0; v < 7; v++) {
      $el.append(`<div class="point"></div>`);
    }
  }
}

函数绘制的空白节点图,待用数据填充

定位起始节点和结束节点

这些贡献度节点的数量是大于365个的,并且每一天的星期数都是有变化的,所以要计算今天是星期几,以及去年的今天是星期几,这样才可以定位起始节点和结束节点。

从起始节点开始,循环到结束节点,这之间就是准确的节点数量,一共365个。使用 $().slice(start, end)函数循环,循环对象是div.right-side下的所有div.point

函数需要两个变量来控制循环,起始和结束。起始就是去年的今天的星期是几?在 JS Date() 对象中,索引值 1 代表星期一;索引值 0 代表星期日。由于贡献节点的索引值是从 0 开始的,所以,索引值 0 代表星期一,6 代表星期日。所以,要进行计算:

星期 Date 中的索引值 贡献节点索引值
星期一 1 0
星期二 2 1
星期三 3 2
星期四 4 3
星期五 5 4
星期六 6 5
星期日 0 6

查找规律,除星期日以外,Date 中的索引值与贡献节点的索引值总是相差 1。所以,只需要 Date 中的索引值(weekIndex)减去 1 就知道slice()函数从哪里开始。

特殊情况星期日:当weekIndex - 1 < 0时,说明是星期日,函数要从索引值 6 开始。

JS
function drawPoints() {
  let nowDate = new Date();
  let oldDate = new Date(`${nowDate.getFullYear() - 1}-${nowDate.getMonth() + 1}-${nowDate.getDate()}`);

  let weekIndex = oldDate.getDay();

  let start = weekIndex - 1 < 0 ? 6 : weekIndex - 1;
  let end = start === 6 ? 372 : 365 + weekIndex;

  $(`#cb-chart .bottom .right-side .point`)
    .slice(start, end)
    .each((i, el) => {
      // ......
    });
}

绘制节点颜色

节点的颜色根据贡献的数量来设置:

JS
function setPointColor(el, number) {
  if (number > 0 && number <= 5) {
    $(el).addClass("a-type-point");
  } else if (number > 5 && number <= 10) {
    $(el).addClass("b-type-point");
  } else if (number > 10 && number <= 15) {
    $(el).addClass("c-type-point");
  } else if (number > 15) {
    $(el).addClass("d-type-point");
  } else {
    $(el).addClass("e-type-point");
  }
}

函数要获取当前循环的贡献节点的 DOM 对象,以及这个节点对应的贡献数量。函数在下面进行调用:

JS
function drawPoints() {
  // ......
  let data = getPointsData(oldDate);
  $(`#cb-chart .bottom .right-side .point`)
    .slice(start, end)
    .each((i, el) => {
      setPointColor(el, data[i].number);
    });
}

这里出现了一个 getPointsData 函数,暂时不用管,它是随机生成数据的函数。

作者:Himmelbleu
出处: https://www.cnblogs.com/Himmelbleu/#/p/16508381
版权:本作品采用「 署名-非商业性使用-相同方式共享 4.0 国际 」许可协议进行许可。
文章目录
前言
布局设计
CSS 样式
div#cb-chart
div.bottom
div.top-bar
div.point
JS 部分
绘制节点图
定位起始节点和结束节点
绘制节点颜色
点击右上角即可分享
微信分享提示