Built with blockbuilder.org
forked from vjwilson's block: pie chart browser usage
license: mit |
Built with blockbuilder.org
forked from vjwilson's block: pie chart browser usage
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
<link rel="stylesheet" href="styles.css"> | |
</head> | |
<body> | |
<div class="search-block"> | |
<label for="username">GitHub Username</label> | |
<input name="username" id="username" value="vjwilson"> | |
<button type="button" id="search">Graph Repos</button> | |
</div> | |
<div class="github-link" id="github-link"> | |
</div> | |
<div class="container"> | |
</div> | |
<script> | |
const container = d3.select('.container') | |
const svg = container.append("svg") | |
.attr("width", 960) | |
.attr("height", 500); | |
const width = svg.attr("width"); | |
const height = svg.attr("height"); | |
const radius = Math.min(width, height) / 2; | |
const searchBox = document.getElementById('username'); | |
const triggerBtn = document.getElementById('search'); | |
let username = searchBox.value; | |
const githubLink = document.getElementById('github-link'); | |
triggerBtn.addEventListener('click', function(e) { | |
username = searchBox.value.trim(); | |
graphRepos(username); | |
}); | |
searchBox.addEventListener('keypress', function(e) { | |
const code = e.which; | |
if (code === 13) { | |
username = searchBox.value.trim(); | |
graphRepos(username); | |
} | |
}); | |
graphRepos(username); | |
function graphRepos(user) { | |
svg.selectAll("*").remove(); | |
while (githubLink.firstChild) { | |
githubLink.removeChild(githubLink.firstChild); | |
} | |
fetch(`https://api.github.com/users/${user}/repos?per_page=100`) | |
.then(function(response) { | |
if (!response.ok) { | |
throw new Error("HTTP error, status = " + response.status); | |
} | |
return response.json(); | |
}) | |
.then(function(repos) { | |
if (!repos.length) { | |
throw new Error(`No public repos for user ${user}`); | |
} | |
const g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); | |
const totals = repos.reduce((sums, repo) => { | |
sums[repo.language] = (sums[repo.language] || 0) + 1; | |
return sums; | |
}, {}); | |
const int = Object.entries(totals); | |
const newData = int.map((sum) => { | |
return { | |
language: sum[0], | |
count: sum[1] | |
}; | |
}); | |
const color = d3.scaleOrdinal(['#4daf4a','#377eb8','#ff7f00','#984ea3','#e41a1c']); | |
// Generate the pie | |
const pie = d3.pie().value(function(d) { | |
return d.count; | |
}); | |
// Generate the arcs | |
const arc = d3.arc() | |
.innerRadius(0) | |
.outerRadius(radius - 50); | |
const label = d3.arc() | |
.outerRadius(radius - 5) | |
.innerRadius(radius - 35); | |
//Generate groups | |
const arcs = g.selectAll(".arc") | |
.data(pie(newData)) | |
.enter() | |
.append("g") | |
.attr("class", "arc") | |
//Draw arc paths | |
arcs.append("path") | |
.attr("fill", function(d) { | |
return color(d.data.language); | |
}) | |
.attr('stroke', 'white') | |
.attr("d", arc); | |
arcs.append("text") | |
.attr("transform", function(d) { | |
return "translate(" + label.centroid(d) + ")"; | |
}) | |
.attr('text-anchor', 'middle') | |
.attr('font-size', '14px') | |
.text(function(d) { | |
return d.data.language + ' (' + d.data.count + ')'; | |
}); | |
const newLink = document.createElement('a'); | |
newLink.setAttribute('href', `https://github.com/${user}?tab=repositories`); | |
newLink.setAttribute('target', '_blank'); | |
newLink.setAttribute('rel', 'noopener noreferrer'); | |
newLink.setAttribute('target', '_top'); | |
const newContent = document.createTextNode(`View repos for ${user}`); | |
newLink.appendChild(newContent); | |
githubLink.append(newLink); | |
svg.append("g") | |
.attr("transform", "translate(" + 40 + "," + (height / 2) + ")rotate(270)") | |
.append("text") | |
.text("Public Repos by Language") | |
.attr("class", "title") | |
.attr('font-size', '24px') | |
.attr('text-anchor', 'middle'); | |
}) | |
.catch(function(error) { | |
var p = document.createElement('p'); | |
p.classList.add('error') | |
p.appendChild( | |
document.createTextNode('Error: ' + error.message) | |
); | |
document.body.insertBefore(p, container.node()); | |
}); | |
} | |
</script> | |
</body> |
*:focus { | |
outline: thin rebeccapurple dotted; | |
} | |
.search-block { | |
border: 1px solid rebeccapurple; | |
border-radius: 4px; | |
padding: .5rem; | |
position: absolute; | |
width: 200px; | |
} | |
.search-block label { | |
color: grey; | |
display: block; | |
margin-bottom: .125rem; | |
} | |
.search-block input { | |
color: rebeccapurple; | |
font-size: 1rem; | |
margin-bottom: .75rem; | |
width: 100% | |
} | |
.search-block button { | |
background-color: rebeccapurple; | |
color: white; | |
display: block; | |
font-size: 1rem; | |
font-weight: bold; | |
width: 100%; | |
} | |
.github-link { | |
padding: 1rem; | |
position: absolute; | |
right: 0; | |
} | |
.error { | |
color: red; | |
position: absolute; | |
left: 0; | |
text-align: center; | |
top: 50%; | |
width: 100%; | |
z-index: 1; | |
} |