【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版地铁站都比你努力

相关推荐
C语言魔术师13 分钟前
【小游戏篇】三子棋游戏
前端·算法·游戏
匹马夕阳1 小时前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?1 小时前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二8 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062069 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb9 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角9 小时前
CSS 颜色
前端·css
九酒9 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔10 小时前
HTML5 新表单属性详解
前端·html·html5
lee57610 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm