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.