Built with blockbuilder.org
Created
July 16, 2020 19:50
-
-
Save ninjakx/9ee1324250e2d0bb62eac34e147a5da3 to your computer and use it in GitHub Desktop.
dash_corona
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Covid Dashboard</title> | |
<meta charset="UTF-8"> | |
<link rel="stylesheet" type="text/css" href="https://dc-js.github.io/dc.js/css/dc.css"/> | |
<link rel="stylesheet" type="text/css" href="main.css" media="screen"/> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="chart-holder"> | |
<div id="kpi-confirmed" class="kpi-box" , value="confirmed"> | |
<div class="label"></div> | |
<div class="value"></div> | |
<div class="description"></div> | |
<div class="chart-caption"> Daily new cases</div> | |
</div> | |
<div id="kpi-active" class="kpi-box" , value="active"> | |
<div class="label"></div> | |
<div class="value"></div> | |
<div class="description"></div> | |
<div class="chart-caption"> Daily new cases</div> | |
</div> | |
<div id="kpi-recovery" class="kpi-box" , value="recovered"> | |
<div class="label"></div> | |
<div class="value"></div> | |
<div class="description"></div> | |
<div class="chart-caption"> Daily new cases</div> | |
</div> | |
<div id="kpi-deceased" class="kpi-box" , value="deaths"> | |
<div class="label"></div> | |
<div class="value"></div> | |
<div class="description"></div> | |
<div class="chart-caption"> Daily new cases</div> | |
</div> | |
</div> | |
</div> | |
<div id="tooltip" class="hidden"> | |
<p><strong id="header"></strong> </p> | |
<p><span id="value"></span> </p> | |
</div> | |
<div id="ui"></div> | |
<button type="button" id="combined_button">View All</button> | |
<div class="container"> | |
<div id="cases_header" class="header_col">Covid Cases Stats</div> | |
<div class="chart-holder"> | |
<div class="column"> | |
<div class="chart-title"> <span style="font-size: 1.1em"> | |
<strong>Total Cases</strong> | |
<br> | |
</span> </div> | |
<div id="total_cases" class="svg-container"></div> | |
</div> | |
<div class="column"> | |
<div class="chart-title"> <span> | |
<strong style="margin-right:10px;">Total Cases Statewise</strong> <select id="interval"></select> | |
<br> | |
</span> </div> | |
<div id="line-chart" class="svg-container"></div> | |
</div> | |
<div class="column"> | |
<div class="chart-title"> <span style="font-size: 1.1em"> | |
<strong>Total Cases</strong> | |
<br> | |
</span> </div> | |
<div id="line-chart2" class="svg-container"></div> | |
</div> | |
</div> | |
</div> | |
<br> | |
<div class="container"> | |
<div id="pat_header" class="header_col">Patient Info. (Hospitalized Cases)</div> | |
<div class="chart-holder"> | |
<div class="column"> | |
<div class="chart-title"> <span> | |
<strong>Total Cases Statewise</strong> | |
<a href="javascript:pieChart.filterAll(); barChart2.redraw(); pieChart.redraw()" class="reset">reset</a> | |
<br> | |
</span> </div> | |
<div id="patients_age" class="svg-container"></div> | |
</div> | |
<div class="column"> | |
<div class="chart-title"> <span style="font-size: 1.1em"> | |
<strong>Total Cases</strong> | |
<a href="javascript:barChart2.filterAll(); barChart2.redraw(); pieChart.redraw()" class="reset">reset</a> | |
<br> | |
</span> </div> | |
<div id="patients_gender" class="svg-container"></div> | |
</div> | |
<div id="map_timeline" class="header_col">Covid Spread</div> | |
<div class="chart-holder"> | |
<div class="column"> | |
<div class="tooltip"></div> | |
<div onload="sizeChange()" id="chart"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script type="text/javascript" src="https://dc-js.github.io/dc.js/js/d3.js"></script> | |
<script type="text/javascript" src="https://dc-js.github.io/dc.js/js/crossfilter.js"></script> | |
<script type="text/javascript" src="https://dc-js.github.io/dc.js/js/dc.js"></script> | |
<script type="text/javascript" src="https://dc-js.github.io/dc.js/resizing/dc-restore-transition-duration.js"></script> | |
<!--Plugin CSS file with desired skin--> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css"/> | |
<!--jQuery--> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/reductio/1.0.0/reductio.min.js"></script> | |
<!--Plugin JavaScript file--> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js"></script> | |
<script src="http://d3js.org/topojson.v2.min.js"></script> | |
<!-- <script src="https://d3js.org/d3-array.v1.min.js"></script> --> | |
<script src="https://d3js.org/d3-geo.v1.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/5.1.5/turf.min.js"></script> | |
<!-- <script src="https://unpkg.com/d3-scale-cluster@1.1.2/dist/d3-scale-cluster.min.js"></script> --> | |
<script src="http://d3-legend.susielu.com/d3-legend.min.js"></script> | |
<script> | |
map_state = { | |
"Andaman and Nicobar Islands": "AN", | |
"Andhra Pradesh": "AP", | |
"Arunachal Pradesh": "AR", | |
"Assam": "AS", | |
"Bihar": "BR", | |
"Chandigarh": "CG", | |
"Chhattisgarh": "CH", | |
"Delhi": "DL", | |
"Goa": "GA", | |
"Gujarat": "GJ", | |
"Haryana": "HR", | |
"Himachal Pradesh": "HP", | |
"Jammu and Kashmir": "HK", | |
"Jharkhand": "JH", | |
"Karnataka": "KA", | |
"Kerala": "KL", | |
"Ladakh": "LD", | |
"Lakshadweep": "LK", | |
"Madhya Pradesh": "MP", | |
"Maharashtra": "MH", | |
"Manipur": "MN", | |
"Meghalaya": "MH", | |
"Mizoram": "MZ", | |
"Nagaland": "NL", | |
"Odisha": "OD", | |
"Puducherry": "PY", | |
"Punjab": "PB", | |
"Rajasthan": "RJ", | |
"Tamil Nadu": "TN", | |
"Telangana": "TS", | |
"Tripura": "TR", | |
"Sikkim": "SK", | |
"Uttar Pradesh": "UP", | |
"Uttarakhand": "UK", | |
"West Bengal": "WB", | |
} | |
var log = console.log; | |
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', | |
}); | |
} | |
function filterData(dt, from, to, formatReq) { | |
if (!formatReq) { | |
dt = dateToTS(new Date(dt)); | |
} else { | |
const parts = dt.split('/'); | |
dt = new Date( | |
parts[1] + '-' + parts[0] + '-' + parts[2].split(' ')[0] | |
); | |
} | |
if (dt >= from && dt <= to) { | |
return true; | |
} | |
} | |
var daily_recov = dc.lineChart("#kpi-recovery"); | |
var daily_conf = dc.lineChart("#kpi-confirmed"); | |
var daily_dcsd = dc.lineChart("#kpi-deceased"); | |
var daily_actv = dc.lineChart("#kpi-active"); | |
var total_chart = dc.compositeChart("#total_cases"); | |
var composite = dc.compositeChart("#line-chart"); | |
var composite2 = dc.barChart("#line-chart2"); | |
var pieChart = dc.pieChart("#patients_age"); | |
var barChart2 = dc.barChart("#patients_gender"); | |
var age_by_cases, barTypeDimension, binwidth; | |
var pieTypeDimension, group1; | |
function plot_age_bar(type) { | |
barChart2 | |
.height(null) | |
.width(null) //give it a width | |
.margins({ | |
top: 10, | |
right: 10, | |
bottom: 20, | |
left: 60 | |
}) //give it margin left of some number so that the y axis ticks dont cut off | |
.dimension(barTypeDimension) | |
.group(age_by_cases, type) | |
.elasticY(true) | |
.valueAccessor(function(p) { | |
return p.value[type]; | |
}) | |
.x(d3.scaleLinear().domain([1, 101])) | |
.xUnits(dc.units.fp.precision(binwidth)) | |
.elasticX(true); | |
} | |
function plot_gender_pie(type) { | |
var val_arr = group1.all() | |
var val_type_count = val_arr[0].value[type] + val_arr[1].value[type] | |
pieChart | |
.height(null) | |
.width(null) | |
.dimension(pieTypeDimension) | |
.group(group1, type) | |
.valueAccessor(function(kv) { | |
return kv.value[type] || 0; | |
}) | |
.othersGrouper(null) | |
.innerRadius(50) | |
.drawPaths(true) | |
.legend(dc.legend()) | |
.label(function(d) { | |
return d.key + ": " + ((d.value[type] / val_type_count) * 100).toFixed(2) + "%"; | |
}); | |
} | |
Promise.all([ | |
d3.json("https://api.covid19india.org/data.json"), | |
d3.json("https://api.rootnet.in/covid19-in/unofficial/covid19india.org/statewise/history"), | |
d3.json("https://api.covid19india.org/raw_data1.json"), | |
d3.json("https://api.covid19india.org/raw_data2.json"), | |
d3.json("https://api.covid19india.org/raw_data3.json"), | |
d3.json("https://api.covid19india.org/raw_data4.json"), | |
d3.json("https://api.covid19india.org/raw_data5.json"), | |
d3.json("https://api.covid19india.org/raw_data6.json"), | |
d3.json("https://api.covid19india.org/raw_data7.json"), | |
d3.json("https://api.covid19india.org/raw_data8.json") | |
]).then(([data1, data2, p1, p2, p3, p4, p5, p6, p7, p8]) => { | |
var data = data1.cases_time_series; | |
var from = new Date(2020, 0, 31); | |
var to = new Date() | |
var co = 0, | |
count = 0; | |
for (var start = 0; start <= data.length - 1; start++) { | |
var day = new Date(data[start].date + "2020"); | |
date = day.toDateString().split(" ") | |
date = date[2] + "-" + date[1] + "-" + date[3] | |
if (new Date(date) <= new Date('2020-03-14')) { | |
conf = parseInt(data[co]['totalconfirmed']); | |
recov = parseInt(data[co]['totalrecovered']); | |
dcsd = parseInt(data[co]['totaldeceased']); | |
actv = conf - recov - dcsd; | |
d_conf = parseInt(data[co]['dailyconfirmed']); | |
d_recov = parseInt(data[co]['dailyrecovered']); | |
d_dcsd = parseInt(data[co]['dailydeceased']); | |
d_actv = d_conf - d_recov - d_dcsd; | |
data[co] = { | |
"day": date, | |
"daily_confirmed": d_conf, | |
"daily_recovered": d_recov, | |
"daily_deceased": d_dcsd, | |
"daily_active": d_conf - d_recov - d_dcsd | |
}; | |
data[co]['total'] = { | |
"confirmed": conf, | |
"recovered": recov, | |
"deaths": dcsd, | |
"active": actv | |
}; | |
statewise_arr = new Array(35); | |
for (var st = 0; st < 35; st++) { | |
var state_name = Object.keys(map_state)[st]; | |
statewise_arr[st] = ({ | |
'state': state_name, | |
"confirmed": 0, | |
"recovered": 0, | |
"deaths": 0, | |
"active": 0 | |
}) | |
} | |
data[co]['statewise'] = statewise_arr; | |
count = count + 1; | |
} else { | |
data_add = data2.data.history[co - count + 1]; | |
conf = parseInt(data_add['total'].confirmed); | |
recov = parseInt(data_add['total'].recovered); | |
actv = parseInt(data_add['total'].active); | |
dcsd = parseInt(data_add['total'].deaths); | |
d_conf = parseInt(data[co]['dailyconfirmed']); | |
d_recov = parseInt(data[co]['dailyrecovered']); | |
d_dcsd = parseInt(data[co]['dailydeceased']); | |
d_actv = d_conf - d_recov - d_dcsd; | |
data[co] = { | |
"day": date, | |
"daily_confirmed": d_conf, | |
"daily_recovered": d_recov, | |
"daily_deceased": d_dcsd, | |
"daily_active": d_conf - d_recov - d_dcsd | |
}; | |
data[co]['total'] = { | |
"confirmed": conf, | |
"recovered": recov, | |
"deaths": dcsd, | |
"active": actv | |
}; | |
var i = 0; | |
statewise_arr = new Array(); | |
for (var st = 0; st < data_add['statewise'].length; st++) { | |
if (data_add['statewise'][st].state != 'State Unassigned') { | |
statewise_arr[i] = (data_add['statewise'][st]); | |
i = i + 1; | |
} | |
} | |
data[co]['statewise'] = statewise_arr; | |
} | |
co = co + 1; | |
} | |
var latest_data = data[data.length - 1]; | |
var dateList = data.map(function(el) { | |
return new Date(el.day); | |
}); | |
const startDate = new Date("2020-03-15"); | |
const endDate = new Date(Math.max.apply(null, dateList)); | |
var datas = [p1, p2, p3, p4, p5, p6, p7, p8] | |
var data_mod = new Array(); | |
for (var dat = 0; dat < 8; dat++) { | |
var p_data = datas[dat].raw_data; | |
var co = 0; | |
for (var i = 0; i < p_data.length; i++) { | |
if (!(p_data[i].agebracket == "") && !(p_data[i].gender == "") && (['M', 'F'].includes(p_data[i].gender))) { | |
data_mod.push(p_data[i]); | |
co = co + 1 | |
} | |
} | |
} | |
const saveResult = function(datetime) { | |
const from = datetime['from']; | |
const to = datetime['to']; | |
const tsDataSliced = data.filter(function(d) { | |
return filterData(d.day, from, to, false); | |
}); | |
stateline_chart(tsDataSliced); | |
return tsDataSliced; | |
}; | |
$('#ui').ionRangeSlider({ | |
skin: 'round', | |
type: 'double', | |
grid: true, | |
min: dateToTS(startDate), | |
max: dateToTS(endDate), | |
from: dateToTS(startDate), | |
to: dateToTS(endDate), | |
prettify: tsToDate, | |
onChange: saveResult, | |
onFinish: saveResult, | |
}); | |
data = data.filter(function(d) { | |
return filterData(d.day, dateToTS(startDate), dateToTS(endDate), false); | |
}); | |
let select_elem = document.querySelector("#chart"); | |
select_elem.style.height = "50vh"; | |
select_elem.style.width = "32.6vw"; | |
stateline_chart(data); | |
patients_info(data_mod); | |
conf_map(); | |
}) | |
.catch(error => log('error', error)) | |
d3.select(window) | |
.on("resize", sizeChange); | |
function hexToRGB(hex, alpha) { | |
var r = parseInt(hex.slice(1, 3), 16), | |
g = parseInt(hex.slice(3, 5), 16), | |
b = parseInt(hex.slice(5, 7), 16); | |
if (alpha) { | |
return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")"; | |
} else { | |
return "rgb(" + r + ", " + g + ", " + b + ")"; | |
} | |
} | |
function sizeChange() { | |
// d3.select("g").attr("transform", "scale("+$("#chart").width()/ $("#chart").height() *1.4 + ")"); | |
d3.select("#chart g").attr("transform", "scale(1)"); | |
$("#chart svg").height($("#chart").height()); | |
$("#chart svg").width($("#chart").width()) | |
} | |
function conf_map() { | |
d3.json("https://api.covid19india.org/v2/state_district_wise.json").then(function(data) { | |
var w = $("#chart").width(); | |
var h = $("#chart").height(); | |
var proj = d3.geoMercator(); | |
var path = d3.geoPath().projection(proj); | |
var t = proj.translate(); // the projection's default translation | |
var s = proj.scale() // the projection's default scale | |
colors = ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"]; // alternatively | |
var map = d3.select("#chart") | |
const zoom = d3.zoom() | |
.scaleExtent([1, 40]) | |
.extent([ | |
[0, 0], | |
[w, h] | |
]) | |
.on("zoom", zoomed); | |
const svg = map.append("svg:svg") | |
.attr("width", "100%") | |
.attr("height", "100%") | |
.call(zoom); | |
const india = svg.append("g").attr("id", "india"); | |
india.style("stroke", "#101010") | |
.style("stroke-width", "0.6"); | |
function zoomed() { | |
india.attr("transform", d3.event.transform); | |
} | |
var div = d3.select(".tooltip"); | |
d3.json("https://raw.githubusercontent.com/covid19india/covid19india-react/master/public/maps/india.json").then(function(json) { | |
var pc = topojson.feature(json, json.objects['districts']) | |
var fixed = pc.features; | |
proj.fitSize([$("#chart").width(), $("#chart").height()], { | |
"type": "FeatureCollection", | |
"features": fixed | |
}) | |
var count = 0; | |
var count_exist = 0; | |
conf_val = new Set(); | |
var max_conf = 0; | |
for (var i = 0; i < data.length; i++) { | |
var state_name = data[i].state; | |
var state_code = data[i].statecode; | |
var district = data[i].districtData; | |
for (var j = 0; j < district.length; j++) { | |
var district_name = district[j].district; | |
if (district_name != 'Unknown') { | |
var dataState = state_name; | |
var dataPCName = district_name; | |
var district_conf_val = district[j].confirmed | |
conf_val.add(district_conf_val); | |
var state_name_res = state_name.toUpperCase(); | |
count_exist = count_exist + 1; | |
for (var k = 0; k < fixed.length; k++) { | |
var jsonState = fixed[k].properties.st_nm; | |
var jsonPCNo = fixed[k].properties.district; | |
if (state_name_res == jsonState.toUpperCase() && dataPCName == jsonPCNo) { | |
count = count + 1; | |
fixed[k].properties.confirmed = district_conf_val; | |
if (district_conf_val > max_conf) { | |
max_conf = district_conf_val; | |
} | |
break; | |
} | |
} | |
} | |
} | |
} | |
var maxTotal = 100; | |
var svg = d3.select("#chart svg"); | |
// create a list of keys | |
var keys = ["0 Case", "Only 1 Case", "< 50 Cases", "< 100 Cases", "< 500 Cases", "< 1,000 Cases", " < 5,000 Cases", "< 10,000 Cases", ">= 10,000 Cases"]; | |
var colour = ['#FDEDEC', '#FADBD8', '#F5B7B1', '#F1948A', '#E74C3C', '#CB4335', '#B03A2E', '#78281F', '#591d16'] | |
// Usually you have a color scale in your chart already | |
var color = d3.scaleOrdinal() | |
.domain(keys) | |
.range(colour); | |
domain = Array.from(conf_val).sort(function(a, b) { | |
return a - b; | |
}); | |
var colors = ['#FDEDEC', '#FADBD8', '#F5B7B1', '#F1948A', '#E74C3C', '#CB4335', '#B03A2E', '#78281F', '#591d16']; | |
var colorScale = d3.scaleThreshold() | |
.domain([1, 50, 100, 500, 1000, 2000, 5000, 10000]) | |
.range(colors); | |
svg.append("g") | |
.attr("class", "legendLog") | |
.attr("transform", "translate(250,20)"); | |
var logLegend = d3.legendColor() | |
.shapeHeight(10) | |
// .shapePadding(10) | |
.labels(d3.legendHelpers.thresholdLabels) | |
.scale(colorScale) | |
.labelFormat(d3.format(",.0f")) | |
.cells([0, 10, 1000, 10000, 100000, 300000]); | |
svg.select(".legendLog") | |
.call(logLegend); | |
var size = "0.2vw"; | |
var rect = svg.select(".legendCells").selectAll("g"); | |
rect.each(function(d) { | |
d3.select(this).select('rect') | |
.attr("width", "1.5vw") | |
.attr("height", "1.5vh") | |
.attr("x", "3.5vw") | |
.attr("y", "30vh") | |
.style("fill", function(d) { | |
return color(d) | |
}) | |
.on('mouseover', function(d, i) { | |
rects = india.selectAll('path'); | |
rects.each(function() { | |
var r = d3.select(this); | |
if (r.style('fill') != hexToRGB(color(d))) { | |
r.style('fill', "white"); | |
// | |
} | |
}) | |
}) | |
.on('mouseleave', function(d, i) { | |
india.selectAll("path") | |
.style("fill", function(d) { | |
return colorScale(d.properties.confirmed); | |
}) | |
d3.select(this).style('outline', 'none'); | |
}); | |
d3.select(this).select('text') | |
.attr("width", "1.5vw") | |
.attr("height", "1.5vh") | |
.attr("x", "4vw") | |
.attr("y", "30vh") | |
}); //and so on | |
india.selectAll("path") | |
.data(fixed) | |
.enter().append("path") | |
.attr("d", path) | |
.style("fill", "#ffffd9") | |
.on('mouseleave', function(d, i) { | |
div.transition().duration(300) | |
.style("opacity", 0); | |
}) | |
.on('mouseenter', function(d, i) { | |
div.transition().duration(300) | |
.style("opacity", 1); | |
}) | |
.on('mouseover', function(d, i) { | |
// Highlight hovered province | |
d3.select(this).style('fill', 'orange'); | |
d3.select(this).transition().duration(300).style("opacity", 1); | |
div.transition().duration(300) | |
.style("opacity", 1) | |
div.html('<strong>' + d.properties.st_nm + '</strong>' + '<br>' + d.properties.district + ': ' + d.properties.confirmed) | |
.style("left", (d3.event.pageX) + "px") | |
.style("top", (d3.mouse(d3.event.target)[1]) + "px") | |
.style("position", "absolute") | |
.style("color", "#222") | |
.style("background", "#FFF") | |
.style("box-shadow", "0px 0px 2px 0px #a6a6a6") | |
.style("border-radius", "2px") | |
.style("pointer-events", "none") | |
.style("padding", "0.5rem"); | |
}) | |
.on('mouseout', function(d, i) { | |
d3.select(this).style('fill', colorScale(d.properties.confirmed)); | |
}); | |
india.selectAll("path") | |
.style("fill", function(d) { | |
return colorScale(d.properties.confirmed); | |
}); | |
}); | |
}); | |
} | |
const callback = chart => entries => { | |
redraw_chart_no_transitions( | |
chart | |
.width(null) | |
.height(null) | |
// .rescale() | |
); | |
}; | |
function patients_info(data_mod) { | |
cf_p = crossfilter(data_mod); | |
pieTypeDimension = cf_p.dimension(function(d) { | |
return d.gender | |
}); | |
// This will give histogram for overall | |
binwidth = 10; | |
barTypeDimension = cf_p.dimension(function(d) { | |
return binwidth * Math.floor(parseInt(d.agebracket) / binwidth); | |
}); | |
age_by_cases = barTypeDimension.group().reduce( | |
// add | |
(p, v) => { | |
p[v.currentstatus] = (p[v.currentstatus] || 0) + 1; | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
p[v.currentstatus] -= 1; | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
group1 = pieTypeDimension.group().reduce( | |
function(p, v) { // add | |
p[v.currentstatus] = (p[v.currentstatus] || 0) + 1; | |
return p; | |
}, | |
function(p, v) { // remove | |
p[v.currentstatus] -= 1; | |
return p; | |
}, | |
function() { // initial | |
return {}; | |
}); | |
function plot_gender_pie(type) { | |
var val_arr = group1.all() | |
var val_type_count = val_arr[0].value[type] + val_arr[1].value[type] | |
pieChart | |
.height(null) | |
.width(null) | |
.dimension(pieTypeDimension) | |
.group(group1, type) | |
.valueAccessor(function(kv) { | |
// log("kv:", kv); | |
return kv.value[type] || 0; | |
}) | |
.othersGrouper(null) | |
.innerRadius(50) | |
.drawPaths(true) | |
.legend(dc.legend()) | |
.label(function(d) { | |
return d.key + ": " + ((d.value[type] / val_type_count) * 100).toFixed(2) + "%"; | |
}); | |
} | |
plot_gender_pie("Hospitalized"); | |
pieChart.ordinalColors(['red', '#ff7063']); | |
pieChart.render(); | |
plot_age_bar("Hospitalized"); | |
barChart2.colors("#f44334"); | |
barChart2.render(); | |
new ResizeObserver(callback(pieChart)).observe(d3.select('#patients_age').node()); | |
new ResizeObserver(callback(barChart2)).observe(d3.select('#patients_gender').node()); | |
} | |
function stateline_chart(data) { | |
cf = crossfilter(data); // Main crossfilter object | |
var cases_bar_d = cf.dimension(function(d) { | |
return new Date(d.day) | |
}); | |
var daily_cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
p['dailyconfirmed'] = v.daily_confirmed || 0; | |
p['dailyrecovered'] = v.daily_recovered || 0; | |
p['dailydeaths'] = v.daily_deceased || 0; | |
p['dailyactive'] = v.daily_active || 0; | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
p['dailyconfirmed'] -= v.daily_confirmed; | |
p['dailyrecovered'] -= v.daily_recovered; | |
p['dailydeaths'] -= v.daily_deceased; | |
p['dailyactive'] -= v.daily_active; | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
var cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
confirmed | |
}) => p[state] = (p[state] || 0) + confirmed); | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
confirmed | |
}) => p[state] -= confirmed); | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
var active_cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
confirmed, | |
recovered | |
}) => p[state] = (p[state] || 0) + (confirmed - recovered)); | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
v.statewise.forEach(function({ | |
state, | |
confirmed, | |
recovered | |
}) { | |
p[state] -= (confirmed - recovered) | |
}); | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
var recovered_cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
recovered | |
}) => p[state] = (p[state] || 0) + recovered); | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
recovered | |
}) => p[state] -= recovered); | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
var death_cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
deaths | |
}) => p[state] = (p[state] || 0) + deaths); | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
v.statewise.forEach(({ | |
state, | |
deaths | |
}) => p[state] -= deaths); | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
var total_cases_bar_g = cases_bar_d.group().reduce( | |
// add | |
(p, v) => { | |
p['totalconfirmed'] = v.total.confirmed || 0; | |
p['totalrecovered'] = v.total.recovered || 0; | |
p['totaldeaths'] = v.total.deaths || 0; | |
p['totalactive'] = v.total.active || 0; | |
return p; | |
}, | |
// remove | |
(p, v) => { | |
p['totalconfirmed'] -= v.total.confirmed; | |
p['totalrecovered'] -= v.total.recovered; | |
p['totaldeaths'] -= v.total.deaths; | |
p['totalactive'] -= v.total.active; | |
return p; | |
}, | |
// init | |
() => ({}) | |
); | |
const states = data[0].statewise.map(d => d.state); | |
var dateList = data.map(function(el) { | |
return new Date(el.day); | |
}); | |
var latest_data = data[data.length - 1]; | |
var top_states = latest_data.statewise; | |
const sDate = new Date(dateList[0]); | |
const eDate = new Date(dateList[dateList.length - 1]); | |
var selected_state = "top 10 states", | |
selected_case_type = "confirmed"; | |
var charts_cases_type = { | |
confirmed: cases_bar_g, | |
active: active_cases_bar_g, | |
recovered: recovered_cases_bar_g, | |
deaths: death_cases_bar_g | |
}; | |
var colorScales = [ | |
d3.scaleOrdinal(d3.schemeCategory10), | |
d3.scaleOrdinal(d3.schemeSet3) | |
]; | |
function drawLegendToggles(chart) { | |
chart.selectAll('g.dc-legend .dc-legend-item') | |
.style('opacity', function(d, i) { | |
var subchart = chart.select('g.sub._' + i); | |
var visible = subchart.style('visibility') !== 'hidden'; | |
return visible ? 1 : 0.2; | |
}); | |
} | |
function legendToggle(chart) { | |
chart.selectAll('g.dc-legend .dc-legend-item') | |
.on('click.hideshow', function(d, i) { | |
var subchart = chart.select('g.sub._' + i); | |
var visible = subchart.style('visibility') !== 'hidden'; | |
subchart.style('visibility', function() { | |
return visible ? 'hidden' : 'visible'; | |
}); | |
drawLegendToggles(chart); | |
}) | |
drawLegendToggles(chart); | |
} | |
function find_max(state, case_type) { | |
var max_case = charts_cases_type[case_type].top(Infinity); | |
var max = 0, | |
val; | |
for (var j = 0; j < max_case.length; j++) { | |
val = max_case[j].value[state]; | |
if (max <= val) { | |
max = val; | |
} | |
} | |
return max; | |
} | |
$(document).ready( | |
function() { | |
$('#kpi-confirmed .label').text('Confirmed'); | |
$('#kpi-confirmed .value').html(latest_data.total.confirmed); | |
$('#kpi-confirmed .value').append('<span class="diff">( +' + latest_data.daily_confirmed + ' )</span>'); | |
$('#kpi-active .label').text('Active'); | |
$('#kpi-active .value').text(latest_data.total.active); | |
$('#kpi-active .value').append('<span class="diff">( +' + latest_data.daily_active + ' )</span>') | |
$('#kpi-recovery .label').text('Recovered'); | |
$('#kpi-recovery .value').text(latest_data.total.recovered); | |
$('#kpi-recovery .value').append('<span class="diff">( +' + latest_data.daily_recovered + ' )</span>') | |
$('#kpi-deceased .label').text('Deaths'); | |
$('#kpi-deceased .value').text(latest_data.total.deaths); | |
$('#kpi-deceased .value').append('<span class="diff">( +' + latest_data.daily_deceased + ' )</span>') | |
} | |
); | |
let select_elem = document.querySelector("#interval"); | |
select_elem.style.backgroundColor = "DodgerBlue"; | |
select_elem.style.borderColor = "#fff transparent transparent transparent"; | |
select_elem.style.color = "white"; | |
select_elem.style.borderRadius = "10px"; | |
function dailyconf() { | |
daily_conf | |
.width(null) | |
.height(null) | |
.margins({ | |
top: 0, | |
right: 0, | |
bottom: -1, | |
left: -1 | |
}) | |
.transitionDuration(500) | |
.dimension(cases_bar_d) | |
.group(daily_cases_bar_g, "dailyconfirmed") | |
.valueAccessor(function(d) { | |
return d.value['dailyconfirmed']; | |
}) | |
.renderArea(true) | |
.elasticY(true) | |
.elasticX(true) | |
.colors("red") | |
.brushOn(false) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])); | |
return daily_conf; | |
} | |
dailyconf(); | |
function dailyrecov() { | |
daily_recov.width(null) | |
.height(null) | |
.margins({ | |
top: 0, | |
right: 0, | |
bottom: -1, | |
left: -1 | |
}) | |
.transitionDuration(500) | |
.dimension(cases_bar_d) | |
.group(daily_cases_bar_g, "dailyrecovered") | |
.valueAccessor(function(d) { | |
return d.value['dailyrecovered']; | |
}) | |
.renderArea(true) | |
.elasticY(true) | |
.elasticX(true) | |
.colors("#389e05") | |
.brushOn(false) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])); | |
} | |
dailyrecov(); | |
function dailyactv() { | |
daily_actv.width(null) | |
.height(null) | |
.margins({ | |
top: 0, | |
right: 0, | |
bottom: -1, | |
left: -1 | |
}) | |
.transitionDuration(500) | |
.dimension(cases_bar_d) | |
.group(daily_cases_bar_g, "dailyactive") | |
.valueAccessor(function(d) { | |
return d.value['dailyactive']; | |
}) | |
.renderArea(true) | |
.elasticY(true) | |
.elasticX(true) | |
.colors("#1876d3") | |
.brushOn(false) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])); | |
} | |
dailyactv(); | |
function dailydcsd() { | |
daily_dcsd.width(null) | |
.height(null) | |
.margins({ | |
top: 0, | |
right: 0, | |
bottom: -1, | |
left: -1 | |
}) | |
.transitionDuration(500) | |
.dimension(cases_bar_d) | |
.group(daily_cases_bar_g, "dailydeaths") | |
.valueAccessor(function(d) { | |
return d.value['dailydeaths']; | |
}) | |
.renderArea(true) | |
.elasticY(true) | |
.elasticX(true) | |
.colors("#36484f") | |
.brushOn(false) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])); | |
} | |
dailydcsd(); | |
function total_cases_chart() { | |
total_chart | |
.width(null) | |
.height(null) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.margins({ | |
left: 60, | |
top: 1, | |
right: 30, | |
bottom: 30 | |
}) | |
.brushOn(false) | |
.yAxisLabel("Total Cases") | |
.dimension(cases_bar_d) | |
.elasticY(true) | |
.elasticX(true) | |
// .xUnits(dc.units.ordinal) | |
.compose([ | |
dc.lineChart(total_chart) | |
.colors("red") | |
.group(total_cases_bar_g, "totalconfirmed") | |
.valueAccessor(function(d) { | |
return d.value['totalconfirmed'] | |
}), | |
dc.lineChart(total_chart) | |
.colors("#1876d3") | |
.group(total_cases_bar_g, "totalactive") | |
.valueAccessor(function(d) { | |
return d.value['totalactive'] | |
}), | |
dc.lineChart(total_chart) | |
.colors("#389e05") | |
.group(total_cases_bar_g, "totalrecovered") | |
.valueAccessor(function(d) { | |
return d.value['totalrecovered'] | |
}), | |
dc.lineChart(total_chart) | |
.colors("#36484f") | |
.group(total_cases_bar_g, "totaldeaths") | |
.valueAccessor(function(d) { | |
return d.value['totaldeaths'] | |
}) | |
]) | |
.legend(dc.legend().x(85).y(15).gap(5).horizontal(false).legendText(function(d) { | |
return d.name; | |
})); | |
total_chart.on('pretransition', function(chart) { | |
chart.children().forEach( | |
child => child.selectAll('circle.dot') | |
.on('mousemove', null) | |
.on('mouseout', null) | |
); | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
total_chart.renderTitle(false); | |
total_chart.on('postRender', chart => { | |
chart.svg().on('mousemove', () => { | |
// find closest data point | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.children()[0].group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
var closest_y = 10000000; | |
var ch_y; | |
var chart_count = 0; | |
chart.children().forEach(child => { | |
child.g().selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
if (d.x === xs[closest]) { | |
var diff = Math.abs(d3.mouse(d3.event.target)[1] - child.y()(d.y)); | |
if (closest_y >= diff) { | |
closest_y = diff; | |
ch_y = child.y()(d.y); | |
} | |
child._showDot(d3.select(this)); | |
if (chart_count == 3) { | |
var text_cases = d3.select(this).data()[0]['data'].value; | |
var tooltip_cases = d3.select("#tooltip") | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - d3.mouse(d3.event.target)[0] + child.x()(d.x) + "px") | |
// px distance from top edge of svg | |
.style("top", d3.event.pageY - d3.mouse(d3.event.target)[1] + ch_y - 40 + "px") | |
// update value for label box | |
//Show the tooltip | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html("<div><span style='color:red'>Total Confirmed: </span><strong>" + text_cases['totalconfirmed'] + "</strong><div>" + "<div><span style='color:#1876d3'>Total Active: </span><strong>" + text_cases['totalactive'] + "</strong><div>" + "<div><span style='color:#389e05'>Total Recovered: </span><strong>" + text_cases['totalrecovered'] + "</strong><div>" + "<div><span style='color:#36484f'>Total Deaths: </span><strong>" + text_cases['totaldeaths'] + "</strong><div>"); | |
tooltip_cases.classed("hidden", false); | |
} | |
} | |
}); | |
chart_count = chart_count + 1; | |
}) | |
}) | |
chart.svg().on('mouseout', () => { | |
chart.children().forEach(child => { | |
child.g().select('text.data-tip') | |
.attr('visibility', 'hidden') | |
child.selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}) | |
}) | |
}); | |
} | |
total_cases_chart(); | |
total_chart.render(); | |
function total_cases_type(case_type) { | |
var cases_color = { | |
'totalconfirmed': 'red', | |
'totalactive': '#1876d3', | |
'totalrecovered': '#389e05', | |
'totaldeaths': '#36484f' | |
}; | |
total_chart | |
.width(null) | |
.height(null) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.margins({ | |
left: 60, | |
top: 1, | |
right: 30, | |
bottom: 30 | |
}) | |
.brushOn(false) | |
.yAxisLabel("Total Cases") | |
.dimension(cases_bar_d) | |
.elasticY(true) | |
.elasticX(true) | |
// .xUnits(dc.units.ordinal) | |
.compose([ | |
dc.lineChart(total_chart) | |
.colors(cases_color[case_type]) | |
.group(total_cases_bar_g, case_type) | |
.dimension(cases_bar_d) | |
.valueAccessor(function(d) { | |
return d.value[case_type] | |
}) | |
]) | |
.legend(dc.legend().x(85).y(15).gap(5).horizontal(false).legendText(function(d) { | |
return d.name; | |
})); | |
total_chart.on('pretransition', function(chart) { | |
chart.children().forEach( | |
child => child.selectAll('circle.dot') | |
.on('mousemove', null) | |
.on('mouseout', null) | |
); | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
total_chart.renderTitle(false); | |
total_chart.on('postRender', chart => { | |
chart.svg().on('mousemove', () => { | |
// find closest data point | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.children()[0].group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
var closest_y = 10000000; | |
var ch_y; | |
var chart_count = 0; | |
chart.children().forEach(child => { | |
child.g().selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
if (d.x === xs[closest]) { | |
var diff = Math.abs(d3.mouse(d3.event.target)[1] - child.y()(d.y)); | |
if (closest_y >= diff) { | |
closest_y = diff; | |
ch_y = child.y()(d.y); | |
} | |
child._showDot(d3.select(this)); { | |
var text_cases = d3.select(this).data()[0]['data'].value; | |
var tooltip_cases = d3.select("#tooltip") | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - d3.mouse(d3.event.target)[0] + child.x()(d.x) + "px") | |
// px distance from top edge of svg | |
.style("top", d3.event.pageY - d3.mouse(d3.event.target)[1] + ch_y - 40 + "px") | |
// update value for label box | |
//Show the tooltip | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html("<div><span style=" + `color:${cases_color[case_type]}` + ">" + `${case_type}`.replace(/^(.{5})(.*)$/, "$1 $2").replace(/(^\w|\s\w)/g, m => m.toUpperCase()) + ": </span><strong>" + text_cases[case_type] + "</strong><div>"); | |
tooltip_cases.classed("hidden", false); | |
} | |
} | |
}); | |
chart_count = chart_count + 1; | |
}) | |
}) | |
chart.svg().on('mouseout', () => { | |
chart.children().forEach(child => { | |
child.g().select('text.data-tip') | |
.attr('visibility', 'hidden') | |
child.selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}) | |
}) | |
}); | |
} | |
comp_chart(selected_case_type); | |
composite.render(); | |
function comp_chart(case_type) { | |
top_states_res = top_states.sort(function(a, b) { | |
return b[case_type] - a[case_type]; | |
}).slice(0, 10).map(d => d.state); | |
var max_cases = find_max(top_states_res[0], case_type) | |
composite | |
.width(null) | |
.height(null) | |
.margins({ | |
left: 55, | |
top: 1, | |
right: 20, | |
bottom: 30 | |
}) | |
.yAxisLabel("Total Cases") | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.y(d3.scaleLinear().domain([0, max_cases * 1.1])) | |
.xUnits(d3.timeDays()) | |
.legend(dc.legend().x(85).y(15).itemHeight(13).gap(5)) | |
.renderHorizontalGridLines(true) | |
.brushOn(false) | |
.elasticX(true) | |
.elasticY(true) | |
.shareTitle(false) | |
.compose(top_states_res.map( | |
(state, i) => dc.lineChart(composite) | |
.dimension(cases_bar_d) | |
.group(charts_cases_type[case_type], state) | |
.valueAccessor(kv => kv.value[state]) | |
.colors(colorScales[0] | |
(Math.random())) | |
.x(d3.scaleTime().domain([sDate, eDate])) | |
.title(function(d) { | |
return (d.key.toDateString() + "\n" + state + ': ' + d.value[state]) | |
}) | |
)); | |
composite.on('pretransition', function(chart) { | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
composite | |
.on('pretransition.hideshow', legendToggle); | |
composite.renderTitle(false); | |
composite.on('postRender', chart => { | |
var show_tooltip = true; | |
chart.svg().on('mousemove', () => { | |
chart.select('g.dc-legend').on('mousemove', () => { | |
show_tooltip = false; | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
chart.select('g.dc-legend').on('mouseout', () => { | |
show_tooltip = true; | |
d3.select("#tooltip").classed("hidden", false); | |
}); | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.children()[0].group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
if (show_tooltip == true) { | |
var closest_y = 10000000; | |
var ch_y; | |
var chart_count = 0; | |
chart.children().forEach(child => { | |
child.g().selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
if (d.x === xs[closest]) { | |
var diff = Math.abs(d3.mouse(d3.event.target)[1] - child.y()(d.y)); | |
if (closest_y >= diff) { | |
closest_y = diff; | |
ch_y = child.y()(d.y); | |
} | |
child._showDot(d3.select(this)); | |
if (chart_count == 3) { | |
var text_cases = d3.select(this).data()[0]['data'].value; | |
var legend_info = d3.select("#line-chart").selectAll(".dc-legend-item").data(); | |
var tooltip_cases = d3.select("#tooltip") | |
var str = ''; | |
for (var i = 0; i < 10; i++) { | |
str += "<div><span style=" + `color:${legend_info[i].color}` + ">" + `${legend_info[i].name}` + ": </span><strong>" + `${text_cases[legend_info[i].name]}` + "</strong><div>"; | |
} | |
tooltip_cases | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - d3.mouse(d3.event.target)[0] + child.x()(d.x) + "px") | |
// px distance from top edge of svg | |
.style("top", d3.event.pageY - d3.mouse(d3.event.target)[1] + ch_y - 40 + "px"); | |
//Show the tooltip | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html(str); | |
d3.select("#tooltip").classed("hidden", false); | |
} | |
} | |
}); | |
chart_count = chart_count + 1; | |
}) | |
} | |
}) | |
chart.svg().on('mouseout', () => { | |
chart.children().forEach(child => { | |
child.selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}) | |
}) | |
}); | |
}; | |
function line_chart(state, case_type) { | |
var cases_color = { | |
'confirmed': 'red', | |
'active': '#1876d3', | |
'recovered': '#389e05', | |
'deaths': '#36484f' | |
}; | |
var state_cases = find_max(state, case_type) | |
composite | |
.width(null) | |
.height(null) | |
.margins({ | |
left: 55, | |
top: 1, | |
right: 20, | |
bottom: 30 | |
}) | |
.yAxisLabel("Total Cases") | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.y(d3.scaleLinear().domain([0, state_cases * 1.1])) | |
.xUnits(d3.timeDays()) | |
.legend(dc.legend().x(85).y(15).itemHeight(13).gap(5)) | |
.renderHorizontalGridLines(true) | |
.brushOn(false) | |
.elasticX(true) | |
.elasticY(true) | |
.shareTitle(false) | |
.compose( | |
[dc.lineChart(composite) | |
.dimension(cases_bar_d) | |
.group(charts_cases_type[case_type], state) | |
.valueAccessor(kv => kv.value[state]) | |
.colors(cases_color[case_type]) | |
.x(d3.scaleTime().domain([sDate, eDate])) | |
.title(function(d) { | |
return (d.key.toDateString() + "\n" + state + ': ' + d.value[state]) | |
}) | |
]); | |
composite.on('pretransition', function(chart) { | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
composite.renderTitle(false); | |
composite.on('postRender', chart => { | |
chart.svg().on('mousemove', () => { | |
// find closest data point | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.children()[0].group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
var closest_y = 10000000; | |
var ch_y; | |
var chart_count = 0; | |
chart.children().forEach(child => { | |
child.g().selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
if (d.x === xs[closest]) { | |
var diff = Math.abs(d3.mouse(d3.event.target)[1] - child.y()(d.y)); | |
if (closest_y >= diff) { | |
closest_y = diff; | |
ch_y = child.y()(d.y); | |
} | |
child._showDot(d3.select(this)); { | |
var text_cases = d3.select(this).data()[0]['data'].value; | |
var tooltip_cases = d3.select("#tooltip") | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - d3.mouse(d3.event.target)[0] + child.x()(d.x) + "px") | |
// px distance from top edge of svg | |
.style("top", d3.event.pageY - d3.mouse(d3.event.target)[1] + ch_y - 40 + "px") | |
// update value for label box | |
//Show the tooltip | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html("<div><span style=" + `color:${cases_color[case_type]}` + ">" + `${case_type}` + ": </span><strong>" + text_cases[state] + "</strong><div>"); | |
tooltip_cases.classed("hidden", false); | |
} | |
} | |
}); | |
chart_count = chart_count + 1; | |
}) | |
}) | |
chart.svg().on('mouseout', () => { | |
chart.children().forEach(child => { | |
child.g().select('text.data-tip') | |
.attr('visibility', 'hidden') | |
child.selectAll('circle.dot').each(function(d) { | |
child._hideDot(d3.select(this)); | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}) | |
}) | |
}); | |
} | |
function daily_chart() { | |
composite2 | |
.width(null) | |
.height(null) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.xUnits(function() { | |
return daily_cases_bar_g.all().length | |
}) | |
.margins({ | |
left: 55, | |
top: 1, | |
right: 30, | |
bottom: 30 | |
}) | |
.elasticX(true) | |
.elasticY(true) | |
.brushOn(false) | |
.yAxisLabel("Daily Cases") | |
.dimension(cases_bar_d) | |
.centerBar(true) | |
.ordinalColors(['#389e05', '#36484f', 'red']) | |
.group(daily_cases_bar_g, "dailyrecovered") | |
.valueAccessor(function(d) { | |
return d.value['dailyrecovered'] | |
}) | |
.stack(daily_cases_bar_g, "dailydeaths", function(d) { | |
return d.value['dailydeaths']; | |
}) | |
.stack(daily_cases_bar_g, "dailyactive", function(d) { | |
return d.value['dailyactive']; | |
}) | |
.legend(dc.legend().x(75).y(15).gap(5).horizontal(false).legendText(function(d) { | |
return d.name; | |
})); | |
composite2.on('pretransition', function(chart) { | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
composite2.renderTitle(false); | |
composite2.on('postRender', chart => { | |
var show_tooltip = true; | |
chart.svg().on('mousemove', () => { | |
chart.select('g.dc-legend').on('mousemove', () => { | |
show_tooltip = false; | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
chart.select('g.dc-legend').on('mouseout', () => { | |
show_tooltip = true; | |
d3.select("#tooltip").classed("hidden", false); | |
}); | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
if (show_tooltip == true) { | |
var chart_count = 0; | |
var all_rect = d3.selectAll('rect.bar').data(); | |
chart.stack()[2].values.forEach(child => { | |
if (child["x"] == xs[closest]) { | |
var case_val = child['data']['value']; | |
var tooltip_cases = d3.select("#tooltip") | |
tooltip_cases | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - 200 + "px") | |
// px distance from top edge of svg | |
.style("top", d3.event.pageY + "px") | |
// .style("top", d3.event.pageY - d3.mouse(d3.event.target)[1] + "px") | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html("<div><span style='color:red'>Total Confirmed: </span><strong>" + case_val['dailyconfirmed'] + "</strong><div>" + "<div><span style='color:#1876d3'>Total Active: </span><strong>" + case_val['dailyactive'] + "</strong><div>" + "<div><span style='color:#389e05'>Total Recovered: </span><strong>" + case_val['dailyrecovered'] + "</strong><div>" + "<div><span style='color:#36484f'>Total Deaths: </span><strong>" + case_val['dailydeaths'] + "</strong><div>"); | |
tooltip_cases.classed("hidden", false); | |
} | |
chart_count = chart_count + 1; | |
}); | |
} | |
}) | |
chart.svg().on('mouseout', () => { | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}); | |
} | |
daily_chart(); | |
composite2.render(); | |
function daily_cases_type(case_type) { | |
var cases_color = { | |
'dailyconfirmed': 'red', | |
'dailyactive': '#1876d3', | |
'dailyrecovered': '#389e05', | |
'dailydeaths': '#36484f' | |
}; | |
composite2 | |
.width(null) | |
.height(null) | |
.x(d3.scaleTime().domain([new Date('15 Mar 2020'), eDate])) | |
.margins({ | |
left: 60, | |
top: 1, | |
right: 30, | |
bottom: 30 | |
}) | |
.brushOn(false) | |
.yAxisLabel("Daily Cases") | |
.dimension(cases_bar_d) | |
.centerBar(true) | |
.elasticX(true) | |
.elasticY(true) | |
.colors(cases_color[case_type]) | |
.group(daily_cases_bar_g, case_type) | |
.valueAccessor(function(d) { | |
return d.value[case_type] | |
}) | |
.legend(dc.legend().x(75).y(15).gap(5).horizontal(false).legendText(function(d) { | |
return d.name; | |
})); | |
composite2.on('pretransition', function(chart) { | |
chart.xAxis().ticks(8).tickFormat(d3.timeFormat("%d %b")); | |
chart.selectAll("g.x text") | |
.attr('transform', "rotate(30)") | |
.style('text-anchor', 'start') | |
.style('font-weight', 'bold'); | |
chart.selectAll("g.y text") | |
.style('font-weight', 'bold'); | |
}); | |
composite2.on('postRender', chart => { | |
var show_tooltip = true; | |
chart.svg().on('mousemove', () => { | |
chart.select('g.dc-legend').on('mousemove', () => { | |
show_tooltip = false; | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
chart.select('g.dc-legend').on('mouseout', () => { | |
show_tooltip = true; | |
d3.select("#tooltip").classed("hidden", false); | |
}); | |
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left), | |
xs = chart.group().all().map(kv => kv.key), | |
right = d3.bisectLeft(xs, x); | |
const y = chart.y().invert(d3.mouse(chart.svg().node())[1]); | |
let closest = right; | |
if (right >= xs.length) | |
closest = right - 1; | |
else if (right > 0) { | |
// see if point to the left is closer | |
if (x - xs[right - 1] < xs[right] - x) | |
closest = right - 1; | |
} | |
if (show_tooltip == true) { | |
var chart_count = 0; | |
var all_rect = d3.selectAll('rect.bar').data(); | |
chart.stack()[0].values.forEach(child => { | |
if (child["x"] == xs[closest]) { | |
var case_val = child['data']['value']; | |
var tooltip_cases = d3.select("#tooltip") | |
tooltip_cases | |
// px distance from left edge of svg | |
.style("left", d3.event.pageX - 200 + "px") | |
// px distance from top edge of svg | |
.style("top", d3.mouse(d3.event.target)[1] + "px") | |
tooltip_cases.select("#header").text(x.toDateString()); | |
tooltip_cases.select("#value").html("<div><span style=" + `color:${cases_color[case_type]}` + ">" + `${case_type}`.replace(/^(.{5})(.*)$/, "$1 $2").replace(/(^\w|\s\w)/g, m => m.toUpperCase()) + ": </span><strong>" + case_val[case_type] + "</strong><div>"); | |
tooltip_cases.classed("hidden", false); | |
} | |
chart_count = chart_count + 1; | |
}); | |
} | |
}) | |
chart.svg().on('mouseout', () => { | |
d3.select("#tooltip").classed("hidden", true); | |
}); | |
}); | |
} | |
composite2.renderTitle(""); | |
$('#combined_button').on('click', function() { | |
total_cases_chart(); | |
total_chart.render(); | |
plot_age_bar("Hospitalized"); | |
barChart2.colors("red"); | |
barChart2.render(); | |
plot_gender_pie("Hospitalized"); | |
pieChart.ordinalColors(['red', '#ff7063']); | |
pieChart.render(); | |
$('pat_header').text('Patient Info. (Hospitalized Cases)') | |
selected_state = 'top 10 states'; | |
comp_chart('confirmed') | |
composite.margins({ | |
left: 65, | |
top: 1, | |
right: 20, | |
bottom: 30 | |
}) | |
composite.render(); | |
daily_chart(); | |
composite2.render(); | |
d3.select('#interval').property('value', 'Top 10 states'); | |
d3.selectAll('.kpi-box').each(function() { | |
$(this).css({ | |
"box-shadow": "0px 2px 4px 0px rgba(0,0,0,0.2)" | |
}); | |
}) | |
$('#cases_header').text('Covid Cases Stats'); | |
}); | |
d3.selectAll('.kpi-box') //.select("kpi-confirmed") | |
.on('click', function() { | |
var pat_cases = { | |
'confirmed': 'Hospitalized', | |
'active': 'Hospitalized', | |
'deaths': 'Deceased', | |
'recovered': 'Recovered' | |
}; | |
var pat_color = { | |
'confirmed': ['red', '#ff7063'], | |
'active': ['red', '#ff7063'], | |
'deaths': ['#223238', '#36484f'], | |
'recovered': ['green', '#389e05'] | |
}; | |
d3.selectAll('.kpi-box').each(function() { | |
$(this).css({ | |
"box-shadow": "0px 2px 4px 0px rgba(0,0,0,0.2)" | |
}); | |
}) | |
$(this).css({ | |
"box-shadow": "inset 0 1px 1px #dab6b6, 0 0 8px #da0707" | |
}); | |
var ctype = d3.select(this).attr('value'); | |
selected_case_type = ctype; | |
$('#pat_header').html('Patient Info. (' + pat_cases[ctype] + ' Cases)'); | |
$('#cases_header').html('Covid ' + ctype.charAt(0).toUpperCase() + ctype.slice(1) + ' Cases Stats'); | |
plot_age_bar(pat_cases[ctype]); | |
barChart2.colors(pat_color[ctype][0]); | |
barChart2.render(); | |
plot_gender_pie(pat_cases[ctype]); | |
pieChart.ordinalColors(pat_color[ctype]); | |
pieChart.render(); | |
switch (selected_state) { | |
case "top 10 states": { | |
var div = d3.selectAll("g.sub"); | |
div.style("display", "none"); | |
comp_chart(ctype); | |
composite.margins({ | |
left: 65, | |
top: 1, | |
right: 20, | |
bottom: 30 | |
}) | |
composite.render(); | |
break; | |
} | |
default: { | |
line_chart(selected_state, ctype); | |
// composite.colors(pat_cases[ctype][0]) | |
composite.render(); | |
} | |
} | |
daily_cases_type("daily" + ctype); | |
composite2.render(); | |
total_cases_type("total" + ctype); | |
total_chart.render(); | |
}); | |
var intervals = { | |
"Top 10 states": "top 10 states" | |
}; | |
states.forEach(function(state, index) { | |
intervals[state] = state; | |
}); | |
var defint = 'Top 10 states'; | |
d3.select('#interval').selectAll('option') | |
.data(Object.keys(intervals)) | |
.enter().append('option') | |
.text(function(d) { | |
return d; | |
}) | |
.attr('selected', function(d) { | |
return d === defint ? '' : null; | |
}); | |
function setup() { | |
var start_t = window.performance.now(); | |
var interval_name = d3.select('#interval').nodes()[0].value; | |
var interval = intervals[interval_name]; | |
selected_state = interval; | |
switch (interval_name) { | |
case 'Top 10 states': | |
comp_chart(selected_case_type); | |
composite.render(); | |
break; | |
default: | |
line_chart(interval_name, selected_case_type); | |
composite.margins({ | |
left: 65, | |
top: 1, | |
right: 20, | |
bottom: 30 | |
}) | |
composite.render(); | |
break; | |
} | |
}; | |
d3.select('#interval').on('change', function() { | |
setup(); | |
}); | |
// dc.renderAll(); | |
daily_conf.render() | |
daily_actv.render() | |
daily_recov.render() | |
daily_dcsd.render() | |
total_chart.render() | |
composite.render() | |
composite2.render() | |
new ResizeObserver(callback(daily_conf)).observe(d3.select('#kpi-confirmed').node()); | |
new ResizeObserver(callback(daily_recov)).observe(d3.select('#kpi-recovery').node()); | |
new ResizeObserver(callback(daily_actv)).observe(d3.select('#kpi-recovery').node()); | |
new ResizeObserver(callback(daily_dcsd)).observe(d3.select('#kpi-deceased').node()); | |
new ResizeObserver(callback(total_chart)).observe(d3.select('#total_cases').node()); | |
new ResizeObserver(callback(composite2)).observe(d3.select('#line-chart2').node()); | |
new ResizeObserver(callback(composite)).observe(d3.select('#line-chart').node()); | |
}; | |
</script> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body, | |
.container { | |
left: 0; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
} | |
#map_timeline { | |
top: 0px; | |
left: 65.8vw; | |
position: absolute; | |
width: 32.8vw; | |
} | |
.header_col { | |
background-color: #292c2f; | |
box-shadow: 0 1px 1px #ccc; | |
padding-top: 0.2%; | |
height: 30px; | |
text-align: center; | |
vertical-align: middle; | |
justify-content: center; | |
color: #ffffff; | |
box-sizing: border-box; | |
} | |
#cases_header { | |
width: 98.6vw; | |
} | |
#pat_header { | |
width: 65.5vw; | |
} | |
.column { | |
background: #fff; | |
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2); | |
margin-right: 0.3vw; | |
/* border-radius: 10px; | |
*/ | |
/*margin: 5px 5px 5px 5px;*/ | |
} | |
.container { | |
display: flex; | |
flex-direction: column; | |
position: relative; | |
} | |
.controls { | |
flex: 0; | |
} | |
.chart-holder { | |
flex: 1; | |
display: flex; | |
flex-direction: row; | |
min-height: 0; | |
} | |
#kpi-confirmed, | |
#kpi-recovery, | |
#kpi-active, | |
#kpi-deceased { | |
max-height: 20%; | |
max-width: 20%; | |
display: flex; | |
flex: 1; | |
/*background: #fff;*/ | |
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2); | |
border-radius: 10px; | |
margin: 5px 5px 5px 5px; | |
} | |
#kpi-confirmed { | |
margin-left: 8%; | |
color: #f44334; | |
} | |
#kpi-active { | |
color: #1876d3; | |
} | |
#kpi-recovery { | |
color: #389e05; | |
} | |
#kpi-deceased { | |
color: #36484f; | |
} | |
.kpi-box .diff { | |
font-size: 1rem; | |
} | |
.kpi-box .value { | |
top: 24px; | |
margin-left: 0.5%; | |
font-size: 1.4rem; | |
font-weight: 800; | |
z-index: 10; | |
position: absolute; | |
} | |
.kpi-box .label { | |
margin-left: 0.5%; | |
color: #000a12; | |
font-size: 0.9rem; | |
font-weight: 800; | |
z-index: 10; | |
position: absolute; | |
} | |
.kpi-box .chart-caption { | |
position: absolute; | |
bottom: 5px; | |
z-index: 13; | |
} | |
* { | |
box-sizing: border-box; | |
} | |
#total_cases, | |
#line-chart, | |
#line-chart2 { | |
max-height: 20%; | |
max-width: 20%; | |
min-width: 32vw; | |
min-height: 40vh; | |
display: flex; | |
flex: 1; | |
margin: 5px 5.5px; | |
} | |
#tooltip { | |
position: absolute; | |
width: 200px; | |
height: auto; | |
padding: 10px; | |
z-index: 14; | |
background-color: white; | |
-webkit-border-radius: 10px; | |
-moz-border-radius: 10px; | |
border-radius: 10px; | |
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
box-shadow: 4px 4px 10px rgba(0, 100, 100, 0.4); | |
pointer-events: none; | |
} | |
#tooltip.hidden { | |
display: none; | |
} | |
#tooltip p { | |
margin: 0; | |
font-family: sans-serif; | |
font-size: 16px; | |
line-height: 20px; | |
} | |
.irs--round .irs-grid-text { | |
color: #002bff !important; | |
} | |
.irs--round .irs-grid-pol { | |
background-color: #6644df !important; | |
} | |
.irs--round.irs-with-grid { | |
width: 93% !important; | |
left: 3% !important; | |
margin-bottom: 1%; | |
} | |
.chart-title { | |
margin: 15px 15px; | |
} | |
#combined_button { | |
margin-left: 45%; | |
margin-bottom: 1%; | |
background-color: #2196F3; | |
height: 40px; | |
color: white | |
} | |
#patients_age, | |
#patients_gender { | |
max-height: 20%; | |
max-width: 20%; | |
min-width: 32vw; | |
min-height: 40vh; | |
/*max-width: 340px;*/ | |
display: flex; | |
flex: 1; | |
margin: 5px 5px; | |
/* margin-left:2%; | |
margin-right:10%;*/ | |
} | |
#vis { | |
height: 20vh; | |
} | |
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; | |
} | |
/* #india { | |
stroke: #101010; | |
stroke-width: .6; | |
}*/ | |
/* .tooltip { | |
position: absolute; | |
text-align: center; | |
padding: 0.5em; | |
font-size: 10px; | |
color: #222; | |
background: #FFF; | |
border-radius: 2px; | |
pointer-events: none; | |
box-shadow: 0px 0px 2px 0px #a6a6a6; | |
} | |
*/ | |
.key path { | |
display: none; | |
} | |
.key line { | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.key text { | |
font-size: 10px; | |
} | |
.key rect { | |
stroke-width: .4; | |
} | |
#chart { | |
width: 32.8vw; | |
height: 60vh; | |
/* position: absolute; | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment