Git Commit History

A playful visualization of 10 years of git commit history for this website.

Each line represents a file, which grows and shrinks as changes are made.

Source Code for this Sketch

const frameInterval = 10
let data
let filemap
let index = 0
let frames = 0
let previousAngle = 0

class Change {
	static fadeFrames = 15
	static lenMult = 30

	constructor(text) {
		this.value = 0
		this.delta = 0
		this.fade = 0
		this.text = text
	}

	update(delta) {
		this.delta = delta
		this.value += delta
		this.fade = Change.fadeFrames // frames
	}

	draw() {
		stroke(60, 100, 51)
		line(0, 0, 0, Math.log(this.value+1) * Change.lenMult)

		if (this.fade > 0) {
			// Growing the line
			if (this.delta > 0) {
				// gradually approach the new value
				let length = this.value - 10*this.delta*this.fade/Change.fadeFrames
				let dlength = 10*this.delta*this.fade/Change.fadeFrames

				stroke(60+this.fade*7, 100, 51-this.fade/2)
				line(0, Math.log(length+1)*Change.lenMult,
					0, Math.log(length+dlength+1) * Change.lenMult)
			}

			// Shrinking the line
			if (this.delta < 0) {
				// gradually approach the new value
				let length = this.value - this.delta*this.fade/Change.fadeFrames
				let dlength = this.delta*this.fade/Change.fadeFrames

				stroke(60-this.fade*4, 100, 51)
				line(0, Math.log(length+1)*Change.lenMult,
					0, Math.log(length+dlength+1) * Change.lenMult)
			}

			this.fade--
		}
	}
}

function preload() {
	loadJSON("/js/git-history.json", (result) => {
		 data = result
	}, (error) => {
		console.error(error)
	})
}

function setup() {
	createCanvas(600, 600, P2D, canvas)
	chrisDefaults()

	// filemap will be a map of string -> int where the string is
	// the path to the file and int value is the number of lines
	filemap = {}
	// frameRate(12)

	new NativeButton("Replay", (event) => {
		index = 0
		filemap = {}
	})

	strokeWeight(1)
}

function draw() {
	// background(217, 100, 26)
	background(0)
	translate(width / 2, height / 2)

	if (index < data.length) {
		// Consume empty commits so we do something interesting each frame
		while(index < data.length && data[index].Changes === null) {
			index++
		}
		for (let i = 0; i < data[index].Changes.length; i++) {
			let key = data[index].Changes[i].Name
			if (!filemap.hasOwnProperty(key)) {
				filemap[key] = new Change(key)
			}
			filemap[key].update(data[index].Changes[i].Addition-data[index].Changes[i].Deletion)
		}
	}

	let angle = 0
	if (Object.keys(filemap).length > 0 ) {
		angle = 360/Object.keys(filemap).length
	}

	let rotation = lerp(previousAngle, angle, frames/frameInterval)
	for (const key in filemap) {
		if (filemap.hasOwnProperty(key)) {
			rotate(rotation)
			filemap[key].draw()
		}
	}

	frames++
	if (frames %frameInterval===0) {
		index++
		previousAngle = angle
	}
	if (frames >= frameInterval) {
		frames = 0
	}
}

You may use all or part of the p5 code seen on this page for your own creations, without restriction. Attribution is appreciated but not required.

This sketch also includes the following sources: p5common.js . Sources are available under their respective licenses.

See all p5.js sketches