Skip to content

Instantly share code, notes, and snippets.

@akulmehta
Last active May 21, 2020 19:05
Show Gist options
  • Save akulmehta/6f1120ad6f3bf96bf0e36cbf4a3afa61 to your computer and use it in GitHub Desktop.
Save akulmehta/6f1120ad6f3bf96bf0e36cbf4a3afa61 to your computer and use it in GitHub Desktop.
racing_bar_play_pause
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
text{
font-size: 16px;
font-family: Open Sans, sans-serif;
}
text.title{
font-size: 24px;
font-weight: 500;
}
text.subTitle{
font-weight: 500;
fill: #777777;
}
text.caption{
font-weight: 400;
font-size: 14px;
fill: #777777;
}
text.label{
font-weight: 600;
}
text.valueLabel{
font-weight: 300;
}
text.yearText{
font-size: 64px;
font-weight: 700;
opacity: 0.25;
}
.tick text {
fill: #777777;
}
.xAxis .tick:nth-child(2) text {
text-anchor: start;
}
.tick line {
shape-rendering: CrispEdges;
stroke: #dddddd;
}
.tick line.origin{
stroke: #aaaaaa;
}
path.domain{
display: none;
}
#play-button {
position: absolute;
top: 140px;
left: 50px;
background: #f08080;
padding-right: 26px;
border-radius: 3px;
border: none;
color: white;
margin: 0;
padding: 0 12px;
width: 60px;
cursor: pointer;
height: 30px;
}
#play-button:hover {
background-color: #696969;
}
.ticks {
font-size: 10px;
}
.track,
.track-inset,
.track-overlay {
stroke-linecap: round;
}
.track {
stroke: #000;
stroke-opacity: 0.3;
stroke-width: 10px;
}
.track-inset {
stroke: #dcdcdc;
stroke-width: 8px;
}
.track-overlay {
pointer-events: stroke;
stroke-width: 50px;
stroke: transparent;
cursor: crosshair;
}
.handle {
fill: #fff;
stroke: #000;
stroke-opacity: 0.5;
stroke-width: 1.25px;
}
</style>
</head>
<div id="vis">
<button id="play-button">Play</button>
</div>
<body>
<script>
// Feel free to change or delete any of the code you see in this editor!
var n_case_range = [0,100, 500,1000,2000,3000,4000,5000];
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 600);
var tickDuration = 500;
var top_n = 10;
var height = 500;
var width = 800;
var padding_w_bar = 100;
const margin = {
top: 0,
right: 0,
bottom: 5,
left: 0
};
var svg1 = d3.select("#vis")
.append("svg")
.attr("width", 1100)
.attr("height", 400);
let barPadding = (height-(margin.bottom+margin.top))/(top_n*5);
let title = svg.append('text')
.attr('class', 'title')
.attr('y', 24)
.html('18 years of Interbrand’s Top Global Brands');
let subTitle = svg.append("text")
.attr("class", "subTitle")
.attr("y", 55)
.html("Brand value, $m");
let caption = svg.append('text')
.attr('class', 'caption')
.attr('x', width)
.attr('y', height-5)
.style('text-anchor', 'end')
.html('Source: Interbrand');
var log = console.log;
d3.json('https://api.rootnet.in/covid19-in/unofficial/covid19india.org/statewise/history').then(function(json_data) {
var data = json_data.data.history[7].statewise;
var data1 = json_data.data.history
data = data
.sort((a,b) => d3.descending(a.confirmed, b.confirmed))
.slice(0, top_n);
log("data:::::::", data);
// yearSlice.forEach((d,i) => d.rank = i);
const dateList = data1.map(function (el) {
// log("XXXX:", el);
return (el.day);
});
const lang = 'en-US';
function dateToTS(date) {
return date.valueOf();
}
function tsToDate(ts) {
const d = new Date(ts);
return d.toLocaleDateString(lang, {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
var formatDateIntoYear = d3.timeFormat("%d-%m-%Y");
var formatDate = d3.timeFormat("%d-%m-%Y");
var parseDate = d3.timeParse("%d-%m-%Y");
const sDate = new Date(dateList[0]);
const eDate = new Date(dateList[dateList.length-1]);
log("sDate,eDate:", sDate, eDate);
startDate = sDate;
endDate = eDate;
var year = startDate;
var moving = false;
var currentValue = 0;
var targetValue = width;
var playButton = d3.select("#play-button");
var x1 = d3.scaleTime()
.domain([startDate, endDate])
.range([0, targetValue])
.clamp(true);
var slider = svg1.append("g")
.attr("class", "slider")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
// log("X!!!!!!!:",x1.range()[1]);
slider.append("line")
.attr("class", "track")
.attr("x1", x1.range()[0])
.attr("x2", x1.range()[1])
.select(function() {
// log("!@@@@@@@@@:", this.parentNode.appendChild(this.cloneNode(true)) );
return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-inset")
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-overlay")
.call(d3.drag()
.on("start.interrupt", function() { slider.interrupt(); })
.on("start drag", function() {
log("!!!!!!!!:", d3.event.x);
currentValue = d3.event.x;
update(x1.invert(currentValue));
})
);
slider.insert("g", ".track-overlay")
.attr("class", "ticks")
.attr("transform", "translate(0," + 18 + ")")
.selectAll("text")
.data(x1.ticks(10))
.enter()
.append("text")
.attr("x", x1)
.attr("y", 10)
.attr("text-anchor", "middle")
.text(function(d) { return formatDateIntoYear(d); });
var handle = slider.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 9);
var label = slider.append("text")
.attr("class", "label")
.attr("text-anchor", "middle")
.text(formatDate(startDate))
.attr("transform", "translate(0," + (-25) + ")")
var dataset;
var plot = svg.append("g")
.attr("class", "plot")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
dataset = data1;
drawPlot(dataset);
playButton
.on("click", function() {
var button = d3.select(this);
if (button.text() == "Pause") {
moving = false;
clearInterval(timer);
// timer = 0;
button.text("Play");
} else {
moving = true;
timer = setInterval(step, 100);
button.text("Pause");
}
console.log("Slider moving: " + moving);
})
function prepare(d) {
d.id = d.id;
d.date = parseDate(d.date);
return d;
}
function step() {
update(x1.invert(currentValue));
currentValue = currentValue + (targetValue/151);
if (currentValue > targetValue) {
moving = false;
currentValue = 0;
clearInterval(timer);
// timer = 0;
playButton.text("Play");
console.log("Slider moving: " + moving);
}
}
function update(h) {
// update position and text of label according to slider scale
handle.attr("cx", x1(h));
label
.attr("x", x1(h))
.text(formatDate(h));
// filter data set and redraw plot
var newData = dataset.filter(function(d) {
return new Date(d.day) <= h;
})
drawPlot(newData);
}
function drawPlot(data)
{
var yearSlice = data.slice(-1)[0].statewise;
yearSlice.sort(function(a,b){
return d3.descending(a.confirmed, b.confirmed) ;})
.slice(0, top_n);
yearSlice.forEach((d,i) => {
d.colour = d3.hsl(Math.random()*360,0.75,0.75);
d.rank = i;
});
let x = d3.scaleLinear()
.domain([0, yearSlice[0].confirmed])
.range([margin.left, width-margin.right-65]);
let y = d3.scaleLinear()
.domain([top_n, 0])
.range([height-margin.bottom, margin.top]);
let xAxis = d3.axisTop()
.scale(x)
.ticks(width > 500 ? 5:2)
.tickSize(-(height-margin.top-margin.bottom))
.tickFormat(d => d.confirmed);
// svg.append('g')
// .attr('class', 'axis xAxis')
// .attr('transform', `translate(0, ${margin.top})`)
// .call(xAxis)
// .selectAll('.tick line')
// .classed('origin', d => d == 0);
svg.selectAll('rect.bar')
.data(yearSlice, function(d)
{
console.log("DDDDD:", d.state);
return d.state;
})
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', x(0)+1)
.attr('width', function(d)
{
// console.log("SSSSSSS:", d.confirmed, x(0), x(d.confirmed), x(d.confirmed)-x(0));
return x(d.confirmed)-x(0); }
)
.attr('y', function(d)
{
// console.log("ssss:", y(d.confirmed));
return y(d.rank)+30;
})
.attr('height', 40)
.style('fill', function(d){
// log("color:",d.colour);
return d.colour});
svg.selectAll('text.label')
.data(yearSlice, function(d)
{
// console.log("DDDDD:", d.state);
return d.state;
})
.enter()
.append('text')
.attr('class', 'label')
.attr('x', d => x(d.confirmed)+x(0))//+(d.state.length*10.6))
.attr('y', d => y(d.rank)+50)
.style('text-anchor', 'end')
.html(d => d.state);
svg.selectAll('text.valueLabel')
.data(yearSlice, function(d)
{
// console.log("DDDDD:", d.state);
return d.state;
})
.enter()
.append('text')
.attr('class', 'valueLabel')
.attr('x', d => x(d.confirmed)+20)
.attr('y', d => y(d.rank)+50)
.text(d => d3.format(',.0f')(d.confirmed));
let yearText = svg.append('text')
.attr('class', 'yearText')
.attr('x', width-margin.right)
.attr('y', height-25)
.style('text-anchor', 'end')
.html(~~year);
// .call(halo, 10);
x.domain([0, yearSlice[0].confirmed]);
svg.select('.xAxis')
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.call(xAxis);
let bars = svg.selectAll('.bar').data(yearSlice, d => d.state);
bars
.enter()
.append('rect')
.attr('class', d => d.state)
.attr('x', x(0)+1)
.attr( 'width', d => x(d.confirmed)-x(0)-1)
.attr('y', d => y(top_n+1)+5)
.attr('height', y(1)-y(0)-barPadding)
.style('fill', d => d.colour)
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('y', d => y(d.rank)+5);
bars
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('width', d => x(d.confirmed)-x(0)-1)
.attr('y', d => y(d.rank)+5);
bars
.exit()
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('width', d => x(d.confirmed)-x(0)-1)
.attr('y', d => y(top_n+1)+5)
.remove();
let labels = svg.selectAll('.label')
.data(yearSlice, d => d.state);
labels
.enter()
.append('text')
.attr('class', 'label')
.attr('x', d => x(d.confirmed)-8)
.attr('y', d => y(top_n+1)+5+((y(1)-y(0))/2))
.style('text-anchor', 'end')
.html(d => d.state)
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('y', d => y(d.rank)+5+((y(1)-y(0))/2)+1);
labels
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('x', d => x(d.confirmed)-8)
.attr('y', d => y(d.rank)+5+((y(1)-y(0))/2)+1);
labels
.exit()
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('x', d => x(d.confirmed)-8)
.attr('y', d => y(top_n+1)+5)
.remove();
let valueLabels = svg.selectAll('.valueLabel').data(yearSlice, d => d.state);
valueLabels
.enter()
.append('text')
.attr('class', 'valueLabel')
.attr('x', d => x(d.confirmed)+5)
.attr('y', d => y(top_n+1)+5)
.text(d => d3.format(',.0f')(d.confirmed))
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('y', d => y(d.rank)+5+((y(1)-y(0))/2)+1);
valueLabels
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('x', d => x(d.confirmed)+5)
.attr('y', d => y(d.rank)+5+((y(1)-y(0))/2)+1)
.tween("text", function(d) {
let i = d3.interpolateRound(d.confirmed, d.confirmed);
return function(t) {
this.textContent = d3.format(',')(i(t));
};
});
valueLabels
.exit()
.transition()
.duration(tickDuration)
.ease(d3.easeLinear)
.attr('x', d => x(d.confirmed)+5)
.attr('y', d => y(top_n+1)+5)
.remove();
yearText.html(sDate.toDateString());
};
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment