git日历坐标系? 手动完成github活泼/贡献图
前言
在运用github或gitlab时,我们总能发现,我们一年内的活泼度能够经过一张图直观地展现出来,那么你是否猎奇它是怎么完成的,最近工作中也遇到这样相似的需求,刚开端计划运用echarts的日历坐标系,但demo测验下来成果不尽人意,除了装备费事,自定义自由度不够,以及关于业务需求支撑度也不够,因而,痛定思痛,决议动手手写一个自由度更高的组件。而且关于后端数据结构要求很低,除了能展现近一年数据,还能自定义时刻规模,有需求的小伙伴能够直接检查源码:gitee.com/fcli/vue-ca…
话不多说,先上完成效果图:
布局结构
本组件首要分为三个部分: (1)最左边展现周一至周日部分,每周开端时刻从周日或周一开端可自定义修正
<div class="weeks">
<div class="week">周一</div>
<div class="week">周二</div>
<div class="week">周三</div>
<div class="week">周四</div>
<div class="week">周五</div>
<div class="week">周六</div>
<div class="week">周日</div>
</div>
(2)每一列表示一周的始末时刻,运用el-tooltip悬浮展现具体时刻,需求的能够自定义修正展现内容和款式
<div class="column" v-for="(columnData, columnIndex) in allDateData" :key="columnIndex">
<div class="my-title">{{ columnData.title }}</div>
<div class="date-wrapper" v-for="(dateItem, dateIndex) in columnData.data" :key="dateIndex"
:style="{ background: getColor(dateItem.number).color }"
:class="{ hiddenDate: (columnIndex == 0 && dateIndex < prevTodayWeek - 1), active: getColor(dateItem.number).level == hoverLevel }">
<el-tooltip class="box-item" effect="dark" :content="dateItem.date" placement="top">
<div class="date"></div>
</el-tooltip>
</div>
</div>
(3)贡献图例,可自定义完成点击筛选等功能
<div class="operation">
<div class="legend">
<div class="level-desc">少</div>
<div class="level level-1" @mouseover="hoverLevel = i" @mouseout="hoverLevel = 0" v-for="i in 5" :key="i"
:class="['level-' + i]"></div>
<div class="level-desc">多</div>
</div>
</div>
具体完成
1、首先核算和获取上一年的时刻,以及是星期几,我这儿采用dayjs来获取。核算上年今天最接近的周一的时刻,该时刻为起始时刻。
// 上年今天
let prevToday = dayjs().subtract(1, 'year').format('YYYY-MM-DD')
// 上年今天的是星期几,dayjs获取的为0-6,0是星期日
let prevTodayWeekNum = dayjs(prevToday).format('d') || 7;
prevTodayWeek.value = prevTodayWeekNum;
// 初始日期(上年临近的星期一)
let firstMondayDate =
prevTodayWeekNum > 1
? dayjs().subtract(1, 'year')
.subtract(prevTodayWeekNum - 1, 'days')
.format('YYYY-MM-DD')
: prevToday;
2、核算从开端时刻到完毕时刻之间有多少个周,核算列数
// 初始日期至今天的天数,包括今天
let days = dayjs().diff(dayjs(firstMondayDate), 'days') + 1;
// 每周天数
let columns = 7;
// 最大列数(周数)
let lineNums = Math.ceil(days / columns);
3、制作图表数据,判断月份需求展现的方位,可往dateData中自定义添加需求的数据字段。第一列直接依据第一天的月份,之后的每列数依据上一周的最终一天减去第一天的月份,假如大于1代表月份产生了改变,下一列的title显示最新的月份。
// 制作图表的源数据
let dateData: any = [];
let monthCN = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
for (let i = 0; i < lineNums; i++) {
// 最近一星期不一定满的
let weekColumn = i === lineNums - 1 ? (days % columns ? days % columns : columns) : columns;
// 开端核算title(月份的图例)
let theWeekStartMonth = dayjs(firstMondayDate)
.add(i * 7, 'days')
.format('M');
let day = dayjs(firstMondayDate)
.add(i * 7, 'days')
.format('DD');
//避免开端时月份挤在一起
if (i == 0 && 30 - day < 15) {
theWeekStartMonth = theWeekStartMonth + 1;
}
let theWeekEndMonth = dayjs(firstMondayDate)
.add(i * 7 + weekColumn, 'days')
.format('M');
let title = i === 0 ? monthCN[theWeekStartMonth - 1] : '';
let isSwitchMonth = false;
if (theWeekEndMonth - theWeekStartMonth) {
isSwitchMonth = true;
}
if (i && dateData[i - 1].isSwitchMonth) {
title = monthCN[theWeekEndMonth - 1];
}
// 图表源数据格式:columns:列数,title:列标题,isSwitchMonth:月份是否产生改变,data:每格数据
dateData.push({
columns: weekColumn,
title: title,
isSwitchMonth: isSwitchMonth,
data: []
});
for (let j = 0; j < dateData[i].columns; j++) {
let date = dayjs(firstMondayDate)
.add(i * 7 + j, 'days')
.format('YYYY-MM-DD');
// 提交次数在slider规模内再进行次数赋值
let number = submissionRecord.value[date];
// number:提交次数,date:提交日期
dateData[i].data.push({
number: number,
date: date
});
}
}
(4)依据活泼度或数据量,展现不同节点的布景颜色
const getColor = (number: number) => {
let num = number / props.maxData;
let level = 1;
if (num == 0) {
num = 0.1;
level = 1
} else if (num > 0 && num < 0.3) {
num = 0.3;
level = 2
} else if (num > 0.3 && num < 0.6) {
num = 0.6;
level = 3
} else if (num < 0.9) {
num = 0.8;
level = 4
} else {
num = 1;
level = 5
}
if (props.maxData == 0) {
num = 0.1;
level = 1
}
return { color: 'rgba(55,126,259,' + num + ')', level };
}
(5)监听数据的变化,动态呼应,更新组件数据
watch(() => props.timeData, (newValue) => {
submissionRecord.value = newValue;
init();
}, { immediate: true, deep: true })
运用示例
现已打包上传npm,有需求的小伙伴能够直接装置运用,假如需求自定义修正组件内容,可访问git源码自行修正。git地址:gitee.com/fcli/vue-ca…
npm install @fcli/vue-calendar-map --save-dev 来装置
在项目中运用
import VueCalendarMap from '@fcli/vue-calendar-map';
const app=createApp(App)
app.use(VueCalendarMap);
测验demo
<template>
<div class="content">
<vue-calendar-map :timeData="timeData" :maxData="maxData"></vue-calendar-map>
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs';
import VueCalendarMap from './plugin/index.vue';
import {ref} from 'vue';
components:{
VueCalendarMap
}
const maxData=ref(190);
const timeData=ref<any>({})
let tempDate:any={}
for(let i=0;i<366;i++){
let date=dayjs().subtract(1, 'year').add(i, 'days').format('YYYY-MM-DD')
tempDate[date]=(Math.random() * 200).toFixed(0);
}
timeData.value=tempDate;
</script>
参数阐明
特点 | 特点名称 | 类型 | 可选值 |
---|---|---|---|
timeData | 日期和数量对应对象 | Object | {} |
maxData | 最大值 | Number | 0 |
最终
本人长时间分享一些实用干货和学习总结之类的开源技术文章,欢迎有需求的小伙伴点赞保藏和点个重视。