|
const ContributionsDraw = { |
|
colors: [ |
|
'#eeeeee', |
|
'#d6e685', |
|
'#8cc665', |
|
'#44a340', |
|
'#1e6823', |
|
], |
|
container: document.querySelector('.js-calendar-graph-svg'), |
|
clearButton: null, |
|
weeksOfTheYear: null, |
|
isLeftClickDown: false, |
|
isRightClickDown: false, |
|
|
|
init() { |
|
this._addClearButton(); |
|
|
|
this.addEventListeners(); |
|
|
|
[...this.container.querySelectorAll('.day')].forEach((el) => { |
|
el.style.cursor = 'pointer'; |
|
}); |
|
|
|
// disable dragging and selection |
|
this.container.style.cssText = '-webkit-user-select: none; -webkit-user-drag: none;'; |
|
|
|
// cache the contribution columns |
|
this.weeksOfTheYear = [...this.container.querySelector('g').childNodes].filter((el) => el.nodeName === 'g'); |
|
}, |
|
|
|
addEventListeners() { |
|
this.container.addEventListener('mousedown', (e) => { |
|
switch (event.which) { |
|
case 1: |
|
this.isLeftClickDown = true; |
|
break; |
|
case 3: |
|
this.isRightClickDown = true; |
|
break; |
|
} |
|
|
|
if (e.target.classList.contains('day')) { |
|
this._increaseColour(e.target); |
|
} |
|
}); |
|
|
|
this.container.addEventListener('mouseup', (e) => { |
|
this.isLeftClickDown = false; |
|
this.isRightClickDown = false; |
|
}); |
|
|
|
this.container.addEventListener('mouseover', (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
|
|
if (this.isLeftClickDown) { |
|
this._increaseColour(e.target); |
|
} |
|
if (this.isRightClickDown) { |
|
this._clearCell(e.target); |
|
} |
|
}); |
|
|
|
// prevent github default behaviour |
|
this.container.addEventListener('click', (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
}); |
|
|
|
this.container.addEventListener('contextmenu', (e) => { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
|
|
if(e.target.classList.contains('day')) { |
|
this._clearCell(e.target); |
|
} |
|
}); |
|
|
|
this.clearButton.addEventListener('click', this.clear.bind(this)); |
|
}, |
|
|
|
_increaseColour(el) { |
|
const currentColor = el.getAttribute('fill'); |
|
const index = this.colors.indexOf(currentColor); |
|
const nextIndex = index === this.colors.length - 1 ? this.colors.length - 1 : index + 1; |
|
|
|
el.setAttribute('fill', this.colors[nextIndex]); |
|
}, |
|
|
|
_clearCell(el) { |
|
el.setAttribute('fill', this.colors[0]); |
|
}, |
|
|
|
_addClearButton() { |
|
this.clearButton = document.createElement("button"); |
|
this.clearButton.textContent = 'Clear'; |
|
this.clearButton.className = 'btn btn-sm'; |
|
this.clearButton.style.float = 'right'; |
|
this.clearButton.style.marginLeft = '10px'; |
|
|
|
const buttonContainer = this.container.parentNode.nextElementSibling; |
|
|
|
buttonContainer.insertBefore(this.clearButton, buttonContainer.firstChild); |
|
}, |
|
|
|
clear() { |
|
[...this.container.querySelectorAll('.day')].forEach((el) => { |
|
el.setAttribute('fill', this.colors[0]); |
|
}); |
|
}, |
|
|
|
import(data) { |
|
data.forEach((el, dayOfTheWeek) => { |
|
el.forEach((value, week) => { |
|
const cell = [...this.weeksOfTheYear[week].querySelectorAll('.day')][dayOfTheWeek]; |
|
|
|
if(cell) { |
|
cell.setAttribute('fill', this.colors[value]); |
|
} |
|
}); |
|
}); |
|
}, |
|
|
|
export() { |
|
const daysOfTheWeek = [...this.weeksOfTheYear[0].querySelectorAll('.day')]; |
|
|
|
const data = daysOfTheWeek.map((el, i) => { |
|
return [...this.weeksOfTheYear].map((week) => { |
|
// check if it might be one of the remaining days of the current week |
|
if (i >= week.children.length) { |
|
return 0; |
|
} |
|
|
|
const color = week.children[i].getAttribute('fill'); |
|
return this.colors.indexOf(color); |
|
}); |
|
}); |
|
|
|
console.log(JSON.stringify(data)); |
|
}, |
|
}; |
|
|
|
ContributionsDraw.init(); |
Sorry if this is an old or dead tool but I was trying to use this and found that the code wasn't working with Firefox. A quick scan and I found the issue to be with the event.which, which should be e.which. here's the fixed code if anyone’s having trouble getting this to work