Skip to content

Instantly share code, notes, and snippets.

@umbrae
Forked from danse/.block
Last active August 19, 2019 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save umbrae/a0b9548d7e1bf295578efa66c23ac0d8 to your computer and use it in GitHub Desktop.
Save umbrae/a0b9548d7e1bf295578efa66c23ac0d8 to your computer and use it in GitHub Desktop.
Polar Clock (Duration Mode)
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #FFF;
margin: auto;
width: 960px;
color: #EEE;
}
.arc-text {
font: 16px sans-serif;
}
.arc-center {
fill: none;
}
#credit {
display: none;
position: absolute;
font: 10px sans-serif;
right: 10px;
bottom: 10px;
color: #ddd;
}
#credit a {
color: inherit;
}
.attention {
margin-top: 120px;
font-size: 9px;
font-weight: bold;
width: 100%;
color: #999;
text-align: center;
font-family: sans-serif;
}
#num_viewers_display {
font-size: 120%;
}
#humanDescription {
display: block;
width: 100%;
margin-top: 60px;
font-family: sans-serif;
color: #444;
font-weight: 900;
font-size: 47px;
line-height: 1.4;
text-align: center;
}
</style>
<!--
<input type="range" min="1" max="300" step="1" name="num_viewers" id="num_viewers" value="2" />
<label for="num_viewers">Viewers</label>
-->
<div id="humanDescription"></div>
<div class="attention"><span id="num_viewers_display">0</span></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/humanize-duration/3.20.1/humanize-duration.js"></script>
<script>
var width = 960,
height = 800,
radius = Math.min(width, height) / 1.9,
spacing = .09,
start = moment([2018, 1, 4, 14, 3, 22]),
cur_time = moment([2018, 1, 4, 14, 3, 22]),
last_update = moment(),
viewerCount = 0;
var color = d3.scale.linear()
// .range(["hsl(-180,60%,50%)", "hsl(180,60%,50%)"])
.range(["hsl(0,0,100%)", "hsl(0,0,50%)"])
.interpolate(function(a, b) { var i = d3.interpolateString(a, b); return function(t) { return d3.hsl(i(t)); }; });
var arcBody = d3.svg.arc()
.startAngle(0)
.endAngle(function(d) { return d.value * 2 * Math.PI; })
.innerRadius(function(d) { return d.index * radius; })
.outerRadius(function(d) { return (d.index + spacing) * radius; })
.cornerRadius(6);
var arcCenter = d3.svg.arc()
.startAngle(0)
.endAngle(function(d) { return d.value * 2 * Math.PI; })
.innerRadius(function(d) { return (d.index + spacing / 2) * radius; })
.outerRadius(function(d) { return (d.index + spacing / 2) * radius; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var field = svg.selectAll("g")
.data(fields)
.enter().append("g");
field.append("path")
.attr("class", "arc-body");
field.append("path")
.attr("id", function(d, i) { return "arc-center-" + i; })
.attr("class", "arc-center");
field.append("text")
.attr("dy", ".35em")
.attr("dx", ".75em")
.style("text-anchor", "start")
.append("textPath")
.attr("startOffset", "50%")
.attr("class", "arc-text")
.attr("xlink:href", function(d, i) { return "#arc-center-" + i; });
setInterval(refreshViewerCount, 5000);
tick();
d3.select(self.frameElement).style("height", height + "px");
function refreshViewerCount() {
var API_CLIENT_ID = '9lknlv5t889ducax0lzyfxyarnynb9';
var TWITCH_USER_ID = '57095087';
fetch('https://api.twitch.tv/helix/streams?user_id=' + TWITCH_USER_ID,
{
mode: 'cors',
headers: {
'Client-ID': API_CLIENT_ID
}
}
).then(response => {
return response.json();
}).then(function(responseJson) {
viewerCount = responseJson['data'][0]['viewer_count'];
document.querySelector('#num_viewers_display').innerText = viewerCount;
console.log("Updated viewer count to " + viewerCount);
}).catch(error => console.error(error));
}
function tick() {
/*
if (!document.hidden) field
.each(function(d) { this._value = d.value; })
.data(fields)
.each(function(d) { d.previousValue = this._value; })
.transition()
.duration(50)
.each(fieldTransition);
*/
var now = moment();
var num_viewers = viewerCount; // document.querySelector('#num_viewers').value;
var time_since_last_update = now.diff(last_update);
last_update = now;
cur_time = cur_time.add(time_since_last_update * num_viewers);
var delta = moment.duration(cur_time.diff(start));
var humanSeconds = humanizeDuration(parseInt(delta.as('seconds')) * 1000);
// Hack for keeping seconds on there so it doesn't wrap every minute
// Hour will still wrap but whatever
if (humanSeconds.indexOf('second') == -1) {
humanSeconds = humanSeconds + ", 0 seconds"
}
document.querySelector('#humanDescription').innerHTML =
"Viewers have spent " + humanSeconds + " watching this stream.";
setTimeout(tick, 50);
}
function fieldTransition() {
var field = d3.select(this).transition();
field.select(".arc-body")
.attrTween("d", arcTween(arcBody))
.style("fill", function(d) { return color(d.value); });
field.select(".arc-center")
.attrTween("d", arcTween(arcCenter));
field.select(".arc-text")
.text(function(d) { return d.text; });
}
function arcTween(arc) {
return function(d) {
var i = d3.interpolateNumber(d.previousValue, d.value);
return function(t) {
d.value = i(t);
return arc(d);
};
};
}
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function fields() {
var now = moment();
var num_viewers = viewerCount; // document.querySelector('#num_viewers').value;
var time_since_last_update = now.diff(last_update);
last_update = now;
cur_time = cur_time.add(time_since_last_update * num_viewers);
var delta = moment.duration(cur_time.diff(start));
document.querySelector('#num_viewers_display').value = num_viewers;
return [
{index: .1, text: delta.get('seconds') + ' seconds', value: num_viewers >= 60 ? 1.0 : (delta.get('seconds') + (delta.get('milliseconds') / 1000)) / 60},
{index: .2, text: delta.get('minutes') + ' minutes', value: num_viewers > 3600 ? 1.0 : (delta.get('minutes') + (delta.get('seconds') / 60)) / 60},
{index: .3, text: delta.get('hours') + ' hours', value: delta.get('hours') / 24},
{index: .4, text: delta.get('days') + ' days', value: delta.get('days') / 30},
{index: .5, text: delta.get('months') + ' months', value: delta.get('months') / 12},
{index: .6, text: delta.get('years') + ' years', value: delta.get('years') / 10}
];
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment