Skip to content

Instantly share code, notes, and snippets.

@moxak
Last active October 9, 2022 03:41
Show Gist options
  • Save moxak/e7fa3e99a90ded2645c13b7a9f574ea1 to your computer and use it in GitHub Desktop.
Save moxak/e7fa3e99a90ded2645c13b7a9f574ea1 to your computer and use it in GitHub Desktop.
div.js-calendar-graph {
margin-top: 1rem;
display: flex !important;
flex-direction: column !important;
align-items: flex-end !important;
overflow: hidden !important;
margin-right: 8px !important;
margin-left: 8px !important;
}
text {
font-family:"Gill Sans", sans-serif;
font-size:11px;
fill:var(--tw-prose-links);
}
[data-level="0"]{
fill:#eeeeee;
}
[data-level="1"]{
fill: #d6e685;
}
[data-level="2"]{
fill:#8cc665;
}
[data-level="3"]{
fill:#44a340;
}
[data-level="4"]{
fill:#1e6823;
}
.dark [data-level="0"]{
fill:#2D333B;
}
.dark [data-level="1"]{
fill: #1A4E34;
}
.dark [data-level="2"]{
fill:#006D32;
}
.dark [data-level="3"]{
fill:#26A641;
}
.dark [data-level="4"]{
fill:#39D353;
}
.svg-tip {
position: absolute;
z-index: 99999;
padding: 8px 16px;
font-size: 11px;
text-align: center;
border-radius: 6px;
color:#ffffff;
background: #24292f;
}
.dark .svg-tip {
background: #6e7681;
}
.svg-tip:after {
position: absolute;
bottom: -10px;
left: 50%;
width: 5px;
height: 5px;
box-sizing: border-box;
margin: 0 0 0 -4px;
content: " ";
border: 5px solid transparent;
border-top-color: #24292f;
}
.dark .svg-tip:after {
border-top-color: #6e7681;
}
.svg-tip.left::after {
left: 10%
}
.svg-tip.right::after {
left: 90%
}
function hideTooltip() {
if (currentTooltip) {
currentTooltip.hidden = true
}
}
function showTooltip(el) {
hideTooltip()
const date = new Date(el.getAttribute('data-date'))
const count = parseInt(el.getAttribute('data-count') || '')
const formatted = new Intl.DateTimeFormat('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
timeZone: 'UTC'
}).format(date)
const label = count === 0 ? 'No' : new Intl.NumberFormat('en-US').format(count)
const strong = document.createElement('strong')
strong.textContent = `${label} ${count === 1 ? 'contribution' : 'contributions'}`
currentTooltip.innerHTML = ''
currentTooltip.append(strong, ` on ${formatted}`)
// We have to show the tooltip before calculating it's position.
currentTooltip.hidden = false
const bounds = el.getBoundingClientRect()
const x = bounds.left + window.pageXOffset - currentTooltip.offsetWidth / 2 + bounds.width / 2
const y = bounds.bottom + window.pageYOffset - currentTooltip.offsetHeight - bounds.height * 2
const graphContainer = document.querySelector('.js-calendar-graph')
const graphContainerBounds = graphContainer.getBoundingClientRect()
currentTooltip.style.top = `${y}px`
if (isTooFarLeft(graphContainerBounds, x)) {
currentTooltip.style.left = `${southwestTooltip(bounds)}px`
currentTooltip.classList.add('left')
currentTooltip.classList.remove('right')
} else if (isTooFarRight(graphContainerBounds, x)) {
currentTooltip.style.left = `${southeastTooltip(bounds)}px`
currentTooltip.classList.add('right')
currentTooltip.classList.remove('left')
} else {
currentTooltip.style.left = `${x}px`
currentTooltip.classList.remove('left')
currentTooltip.classList.remove('right')
}
}
function isTooFarLeft(graphContainerBounds, tooltipX) {
return graphContainerBounds.x > tooltipX
}
function isTooFarRight(graphContainerBounds, tooltipX) {
return graphContainerBounds.x + graphContainerBounds.width < tooltipX + currentTooltip.offsetWidth
}
function southwestTooltip(bounds) {
return bounds.left + window.pageXOffset - currentTooltip.offsetWidth * 0.1 + bounds.width / 2
}
function southeastTooltip(bounds) {
return bounds.left + window.pageXOffset - currentTooltip.offsetWidth * 0.9 + bounds.width / 2
}
const currentTooltip = document.createElement('div')
currentTooltip.classList.add('svg-tip', 'svg-tip-one-line')
// Remove pointer events to prevent tooltip flickering
currentTooltip.style.pointerEvents = 'none'
currentTooltip.hidden = true
// Add the tooltip to
document.body.appendChild(currentTooltip)
const el = document.getElementsByClassName('js-calendar-graph-svg')[0];
const container = document.getElementsByClassName('js-calendar-graph')[0];
container.addEventListener('mouseover', function (event) {
const target = event.target
if (target.matches('rect[data-count]')) {
showTooltip(target)
}
})
container.addEventListener('mouseout', hideTooltip)
const fromStr = container.getAttribute('data-from')
if (fromStr) {
previousDay = new Date(fromStr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment