Built with blockbuilder.org
forked from ninjakx's block: racing_bar_weird_unsigned_state
license: mit |
Built with blockbuilder.org
forked from ninjakx's block: racing_bar_weird_unsigned_state
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<style> | |
text{ | |
/* position: absolute; */ | |
font-size: 12px; | |
/* marrgin-left:10px; */ | |
font-family: Open Sans, sans-serif; | |
} | |
text.title{ | |
/* position: absolute; | |
top-left:10px; */ | |
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: 40px; | |
font-weight: 700; | |
opacity: 0.25; | |
} | |
.tick text { | |
fill: #777777; | |
} | |
.xAxis .tick:nth-child(2) text { | |
text-anchor: start; | |
} | |
.tick line { | |
/* display: none; */ | |
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", 600) // <-- state | |
.attr("height", 500); | |
var tickDuration = 500; | |
var top_n = 10; | |
var height = 500; | |
var width = 600; // <-- state | |
var padding_w_bar = 100; | |
const margin = { | |
top: 40, | |
right: 0, | |
bottom: 5, | |
left: 90 | |
}; | |
var svg1 = d3.select("#vis") | |
.append("svg") | |
.attr("width", 750) | |
.attr("height", 400); | |
let barPadding = (height-(margin.bottom+margin.top))/(top_n*5); | |
let title = svg.append('text') | |
.attr('class', 'title') | |
.attr('y', 20) | |
.attr('x', 80) | |
.html('Top 10 States'); | |
let subTitle = svg.append("text") | |
.attr("class", "subTitle") | |
.attr("y", 35) | |
.attr('x', 85) | |
.html("Confirmed Cases"); | |
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) { | |
let x, y, xAxis, yearText; | |
var line_ticks; | |
// var data = json_data.data.history[7].statewise; | |
var data1 = json_data.data.history | |
for (var start = 0; start <= data1.length-1; start++) { | |
var filtered = data1[start].statewise.filter(function(item) { | |
return !['State Unassigned', 'Dadra and Nagar Haveli and Daman and Diu', 'Daman and Diu', 'Dadra and Nagar Haveli'].includes( item.state); | |
}); | |
log("%%%%:", filtered); | |
data1[start].statewise = filtered; | |
} | |
const dateList = data1.map(function (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 + ")"); | |
slider.append("line") | |
.attr("class", "track") | |
.attr("x1", x1.range()[0]) | |
.attr("x2", x1.range()[1]) | |
.select(function() { | |
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() { | |
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()) | |
.enter() | |
.append("text") | |
.attr("x", x1) | |
// .attr("y", 15) | |
// .attr("text-anchor", "middle") | |
// .attr("transform", "rotate(45)") | |
.attr("transform",function(d,i){return "translate(0,"+ (i) * (-35) +") rotate(45)"; | |
log("==:", d,i ) | |
}) | |
.text(function(d) { return formatDateIntoYear(d); }); | |
// .attr("transform", "rotate(45)"); | |
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, true); | |
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"); | |
} | |
}) | |
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); | |
playButton.text("Play"); | |
} | |
} | |
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, false); | |
} | |
function drawPlot(data, initial_plot) | |
{ | |
var yearSlice = data.slice(-1)[0].statewise; | |
var cDate = new Date(data.slice(-1)[0].day); | |
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; | |
}); | |
if (initial_plot==true) | |
{ | |
x = d3.scaleLinear() | |
.domain([0,yearSlice[0].confirmed]) | |
.range([margin.left, width-margin.right-65]); | |
y = d3.scaleLinear() | |
.domain([top_n, 0]) | |
.range([height-margin.bottom, margin.top]); | |
xAxis = d3.axisTop() | |
.scale(x) | |
.ticks(width > 500 ? 5:2) | |
.tickSize(-(height-margin.top-margin.bottom)) | |
.tickFormat(d => d.confirmed); | |
// d3.select("g").attr('axis xAxis', null); | |
// log("@@@@@@:", d3.selectAll("g.x.axis")) | |
line_ticks = svg.append('g') | |
.attr('class', 'axis xAxis') | |
.attr('transform', `translate(0, ${margin.top})`) | |
.call(xAxis) | |
.selectAll('.tick line') | |
.classed('origin', d => d == 0); | |
// log("line_ticks:", line_ticks); | |
// line_ticks.remove(); | |
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)); .html(d => d.name) | |
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)); | |
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); | |
// log("@@@@@@@@@@:", yearSlice); | |
let bars = svg.selectAll('.bar').data(yearSlice, d => d.state); | |
bars | |
.enter() | |
.append('rect') | |
.attr('class', function(d){ | |
return d.state; | |
}) | |
.attr('x', x(0)+1) | |
.attr( 'width', d => x(d.confirmed)-x(0)) | |
.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)) | |
.attr('y', d => y(d.rank)+5); | |
bars | |
.exit() | |
.transition() | |
.duration(tickDuration) | |
.ease(d3.easeLinear) | |
.attr('width', d => x(d.confirmed)-x(0)) | |
.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) | |
// log("-------->", yearSlice); | |
yearText.html(cDate.toDateString()); | |
}; | |
}); | |
</script> | |
</body> |