【d3.js实战】git提交统计图

d3.js实战 git提交统计图

通过之前的多篇博文的详细介绍,我们已经对d3的开发过程有了相当深入的了解和熟悉。在这篇文章中,我们将利用这些知识,来开发一个展示git提交记录的效果。

首先,我们需要明确我们的目标:我们想要创建一个可视化的图表,能够清晰地展示出git的提交历史。这个图表应该包含每个提交的时间、作者、提交信息等基本信息,并且以一种直观的方式展示出来,使得我们可以一目了然地看到项目的发展历程。

为了实现这个目标,我们需要使用d3的各种功能。首先,我们需要使用d3的数据绑定功能,将我们的git提交数据绑定到图表上。这样,每当我们的数据发生变化时,图表也会自动更新。

接下来,我们需要使用d3的布局功能,来决定如何在我们的图表中放置每个提交。我们可以选择线性布局,使得最新的提交总是在图表的最右边;也可以选择径向布局,使得最早的提交位于图表的中心,而最新的提交位于边缘。

然后,我们需要使用d3的绘图功能,来绘制出每个提交的具体形状。我们可以使用矩形、圆形、箭头等各种形状来表示每个提交,使得我们的图表更加丰富和有趣。

最后,我们需要使用d3的交互功能,来增加我们的图表的互动性。我们可以添加鼠标悬停事件,当用户将鼠标移动到一个提交上时,显示出该提交的详细信息;也可以添加点击事件,当用户点击一个提交时,跳转到该提交的代码页面。

下图是d3作者之一mbostock的git实际提交图,很震撼吧。

设计和配色我们直接仿照github。

这段代码定义了一个名为Gitcommit的类,它继承自Coresource类。这个类主要用于绘制一个表示Git提交历史的矩形图。以下是代码的主要功能和结构:

  1. 构造函数:在构造函数中,首先调用父类的构造函数,然后创建一个SVG元素,并将其宽度和高度设置为传入的div的宽度和高度。接着,创建两个分组元素commitGinfoG,并将它们的位置设置为绝对定位。最后,调用drawRectsdrawInfo方法来绘制矩形和信息文本。

  2. updateData方法:这个方法接收一个参数s,用于更新矩形图中的数据。它调用drawRects方法来重新绘制矩形。

  3. drawRects方法:这个方法接收一个参数s,用于生成随机数据。首先,根据给定的参数生成一个包含53周(每周7天)加上2个特殊日期(新年和圣诞节)共366天的数据集。然后,使用D3.js库将数据绑定到矩形元素上,并设置矩形的属性,如宽度、高度、颜色等。最后,返回矩形的宽度和高度。

  4. drawInfo方法:这个方法用于绘制矩形图的相关信息。首先,创建一个矩形作为背景,并在其上方添加一些文本,如"Learn how we count contributions."、"Less"和"More"。接着,为每个月和每周创建文本元素,并设置它们的属性,如位置、颜色等。最后,为每个颜色创建一个矩形元素,并设置它们的属性,如位置、颜色等。

通过这个类的实例化和方法调用,可以生成一个表示Git提交历史的矩形图。

js 复制代码
class Gitcommit extends Coresource {
    private svg: any;
    private commitG: any;
    private infoG: any;
    private colors = ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39']; // 定义颜色数组
    private month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; // 定义月份数组
    private week = ["Mon", "Wed", "Fri"]; // 定义星期数组

    constructor(div, options) {
        super(div, options); // 调用父类构造函数
        console.log('object :>> ', this.divWidth, this.divHeight);

        // 创建 SVG 元素
        this.svg = d3.select(div)
            .append('svg')
            .attr('width', this.divWidth)
            .attr('height', this.divHeight)
            .style('position', 'absolute');

        // 创建 commitG 和 infoG 分组元素
        this.commitG = this.svg.append('g').attr('class', 'commitG')
            .attr('transform', 'translate(' + this.divWidth / 2 + ',' + 160 + ')');

        this.infoG = this.svg.append('g').attr('class', 'infoG')
            .attr('transform', 'translate(' + this.divWidth / 2 + ',' + (160) + ')');

        // 绘制矩形并返回矩形的宽度和高度
        let { boxw, boxh } = this.drawRects(5);
        
        // 绘制信息区域
        this.drawIonf(boxw, boxh);
    }

    // 更新数据
    public updateData(s) {
        this.drawRects(s);
    }

    // 绘制矩形
    private drawRects(s) {
        let num = 53 * 7 + 2 + 3; // 计算总共需要绘制的矩形数量
        let data = [];
        
        // 生成随机数据
        for (let i = 0; i < num; i++) {
            let k = Math.round(Math.random() * 4);
            if (s < Math.random() * 10) {
                k = 0;
            }
            data.push(k);
        }

        // 选择并绑定数据
        let g = this.commitG.selectAll('g').filter('.rects')
            .data([1])
            .join('g')
            .attr('class', 'rects');

        // 绘制矩形
        g.selectAll('rect')
            .data(data)
            .join('rect')
            .attr('width', 10)
            .attr('height', 10)
            .attr('x', (d, i) => Math.floor(i / 7) * 13)
            .attr('y', (d, i) => Math.floor(i % 7) * 13)
            .attr('rx', 2)
            .attr('ry', 2)
            .attr('fill', d => this.colors[d])
            .attr('stroke', '#1b1f230f')
            .attr('stroke-width', 1)
            .attr('opacity', (d, i) => i < 3 ? 0 : 1);

        // 计算并返回矩形的宽度和高度
        let boxw = 10, boxh = 10;
        g.each(function () {
            let box = this.getBBox();
            boxw = box.width;
            boxh = box.height;
            d3.select(this).attr('transform', 'translate(' + (-boxw / 2) + ',' + (-boxh / 2) + ')');
        });

        return { "boxw": boxw, "boxh": boxh };
    }

    // 绘制信息区域
    private drawIonf(boxw, boxh) {
        let backw = boxw + 70;
        let backh = boxh + 80;

        // 绘制背景矩形
        this.infoG.append('rect')
            .attr('width', backw)
            .attr('height', backh)
            .attr('x', -backw / 2 - 10)
            .attr('y', -backh / 2)
            .attr('rx', 8)
            .attr('ry', 8)
            .attr('stroke', '#e1e4e8')
            .attr('fill', 'none')
            .attr('stroke-width', 1);

        // 添加文本信息
        this.infoG.append('text')
            .text('Learn how we count contributions.')
            .attr('fill', '#586069')
            .attr('font-size', '0.75em')
            .attr('x', -boxw / 2)
            .attr('y', boxh / 2 + 20)
            .attr('font-size', '12px');

        // 添加更多文本信息和颜色示例矩形
        // 省略部分代码...

        // 添加月份标签
        this.infoG.selectAll('text').filter('month')
            .data(this.month)
            .join('text')
            .attr('class', 'month')
            .text(d => d)
            .attr('x', (d, i) => i * 59 - boxw / 2)
            .attr('y', -boxh / 2 - 10)
            .attr('fill', '#24292e')
            .attr('font-size', '9px');

        // 添加星期标签
        this.infoG.selectAll('text').filter('week')
            .attr('class', 'week')
            .data(this.week)
            .join('text')
            .text(d => d)
            .attr('x', -boxw / 2 - 30)
            .attr('y', (d, i) => i * 25 + 22 - boxh / 2)
            .attr('fill', '#24292e')
            .attr('font-size', '9px');
    }
}

运行效果

2D版本:可视化100天-2 GitHub之地铁站都比你努力

3D版本:可视化100天-3 three.js之3D版地铁站都比你努力

相关推荐
迷雾漫步者44 分钟前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-1 小时前
验证码机制
前端·后端
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖3 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235243 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240254 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar4 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人5 小时前
前端知识补充—CSS
前端·css
GISer_Jing5 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试