Tally Chart with configurable break_at_points and manual/automated updates
Last active
February 12, 2017 04:28
-
-
Save arpitnarechania/64b7994d99afe392063a6efaf5eb86d0 to your computer and use it in GitHub Desktop.
Tally Chart
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> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Tally Chart</title> | |
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> | |
<link rel="stylesheet" type="text/css" href="style.css"/> | |
</head> | |
<body> | |
<div id="chart"></div> | |
<button id="manual_add" onclick="refresh_data()">Manual Add Data</button> | |
<button id="stop_animation" onclick="stop_animation()">Stop Animation</button> | |
<button id="start_animation" onclick="start_animation()">Start Animation</button> | |
</body> | |
<script type="text/javascript" src="main.js"></script> | |
</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
var dataset = | |
[ | |
{ group: "Grp 1", count: 0}, | |
{ group: "Grp 2", count: 0}, | |
{ group: "Grp 3", count: 0}, | |
{ group: "Grp 4", count: 0}, | |
{ group: "Grp 5", count: 0}, | |
{ group: "Grp 6", count: 0}, | |
]; | |
var REFRESH_THRESHOLD = 100; | |
var BAR_HEIGHT = 25; | |
var BAR_WIDTH = 2; | |
var BREAK_AT_COUNT = 5; | |
var render_bars = function(){ | |
var flags = [], unique_groups=[], l = dataset.length, i; | |
flags = []; | |
for( i=0; i<l; i++) { | |
if( flags[dataset[i].group]) continue; | |
flags[dataset[i].group] = true; | |
unique_groups.push(dataset[i].group); | |
} | |
var groupScale = d3.scale.ordinal().domain(unique_groups).rangePoints([0, unique_groups.length-1 ]); | |
var categoryScale = d3.scale.ordinal().domain(unique_groups).rangePoints([0, unique_groups.length]); | |
var color = d3.scale.category20(); | |
// Set the dimensions of the canvas / graph | |
var margin = {top: 20, right: 50, bottom: 50, left: 150}, | |
width = 900 - margin.left - margin.right, | |
height = 400 - margin.top - margin.bottom; | |
// Set the ranges | |
var xScale = d3.scale.linear().range([50, width]); | |
var yScale = d3.scale.linear().range([height, 50]); | |
var xAxis = d3.svg.axis() | |
.scale(xScale) | |
.ticks(unique_groups.length) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient("left") | |
.tickFormat(function (d) { | |
return unique_groups[d]; | |
}) | |
.ticks(unique_groups.length) | |
var result = dataset.reduce(function(res, obj) { | |
if (!(obj.group in res)) | |
res.__array.push(res[obj.group] = obj); | |
else { | |
res[obj.group].count += obj.count; | |
} | |
return res; | |
}, {__array:[]}).__array | |
.sort(function(a,b) { return b.count - a.count; }); | |
xScale.domain([0,d3.max(dataset,function(d){return d.count;})]); | |
yScale.domain([0,d3.max(dataset,function(d){return groupScale(d.group);})]); | |
//Create SVG element | |
var svg = d3.select("#chart") | |
.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
//CREATE X-AXIS | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
//Create Y axis | |
svg.append("g") | |
.attr("transform", "translate(50,0)") | |
.attr("class", "y axis") | |
.call(yAxis); | |
function generate_array(d){ | |
var k = 0; | |
for(var j=0;j<dataset.length;j++){ | |
if(groupScale(dataset[j].group) == groupScale(d.group) && categoryScale(dataset[j].group) < categoryScale(d.group)){ | |
k = k + dataset[j].count; | |
} | |
} | |
var arr = new Array(d.count); | |
for(var i=0;i<d.count;i++){ | |
arr[i] = {y:groupScale(d.group),x:xScale(k+i),group:d.group}; | |
} | |
return arr; | |
} | |
var groups = svg | |
.selectAll("g.group") | |
.data( dataset ) | |
.enter() | |
.append('g') | |
.attr("class", "group"); | |
var new_dataset = []; | |
var barArray = groups.selectAll("g.barArray") | |
.data(function(d) {new_dataset = generate_array(d); return new_dataset;}); | |
var to_subtract = 0; | |
if(new_dataset.length > BREAK_AT_COUNT){ | |
to_subtract = new_dataset[BREAK_AT_COUNT].x-new_dataset[1].x; | |
} | |
else{ | |
to_subtract = xScale(BREAK_AT_COUNT)-xScale(1); | |
} | |
barArray.enter() | |
.append('g') | |
.attr("class", "barArray") | |
.append("rect") | |
.style("fill", function(d,i){return (i+1)%BREAK_AT_COUNT==0 ? '#0000ff' : '#ff0000'}) | |
.attr("width", function(d,i){return (i+1)%BREAK_AT_COUNT==0 ? (xScale(BREAK_AT_COUNT) - xScale(2)) : BAR_WIDTH}) | |
.attr("height", function(d,i){return (i+1)%BREAK_AT_COUNT==0 ? 2 : BAR_HEIGHT}) | |
.attr("transform", function(d,i){var rotate_string = (i+1)%BREAK_AT_COUNT==0 ? "rotate(0 0 0)" : "rotate(0)"; var translate_string = (i+1)%BREAK_AT_COUNT==0 ? ("translate("+ (d.x-to_subtract)+ "," + (yScale(d.y)) +")") : ("translate("+ d.x + "," + (yScale(d.y)-BAR_HEIGHT/2) +")"); return translate_string + " " + rotate_string; }) | |
var tooltip = d3.select("#chart") | |
.append('div') | |
.attr('class', 'tooltip'); | |
tooltip.append('div') | |
.attr('class', 'group'); | |
svg.selectAll("rect") | |
.on('mouseover', function(d,i) { | |
tooltip.select('.group').html("<b>Group: " + d.group+ "</b>"); | |
tooltip.style('display', 'block'); | |
tooltip.style('opacity',2); | |
}) | |
.on('mousemove', function(d) { | |
tooltip.style('top', (d3.event.layerY + 10) + 'px') | |
.style('left', (d3.event.layerX - 25) + 'px'); | |
}) | |
.on('mouseout', function() { | |
tooltip.style('display', 'none'); | |
tooltip.style('opacity',0); | |
}); | |
} | |
function refresh_data() { | |
var random_index = Math.floor(Math.random() * 6); | |
dataset[random_index].count += 1; | |
if(dataset[random_index].count > REFRESH_THRESHOLD){ | |
dataset = | |
[ | |
{ group: "Grp 1", count: 0}, | |
{ group: "Grp 2", count: 0}, | |
{ group: "Grp 3", count: 0}, | |
{ group: "Grp 4", count: 0}, | |
{ group: "Grp 5", count: 0}, | |
{ group: "Grp 6", count: 0}, | |
]; | |
} | |
$("#chart").empty(); | |
render_bars(); | |
} | |
var refreshId; | |
function start_animation(){ | |
refreshId = setInterval(refresh_data, 500); | |
$("#manual_add").prop('disabled', true); | |
$("#start_animation").prop('disabled', true); | |
$("#stop_animation").prop('disabled', false); | |
} | |
function stop_animation(){ | |
clearInterval(refreshId); | |
$("#manual_add").prop('disabled', false); | |
$("#start_animation").prop('disabled', false); | |
$("#stop_animation").prop('disabled', true); | |
} | |
start_animation(); |
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 { font: 12px Arial;} | |
path { | |
stroke: steelblue; | |
stroke-width: 2; | |
fill: none; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: grey; | |
stroke-width: 1; | |
shape-rendering: crispEdges; | |
} | |
/*.x.axis path, .x.axis text{ | |
display:none; | |
}*/ | |
.tooltip { | |
background: #eee; | |
box-shadow: 0 0 5px #999999; | |
color: #333; | |
font-size: 12px; | |
left: 130px; | |
padding: 10px; | |
position: absolute; | |
text-align: center; | |
top: 95px; | |
z-index: 10; | |
display: block; | |
opacity: 0; | |
} | |
.title{ | |
font-size:16px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment