Skip to content

Instantly share code, notes, and snippets.

@arpitnarechania
Last active February 12, 2017 04:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arpitnarechania/64b7994d99afe392063a6efaf5eb86d0 to your computer and use it in GitHub Desktop.
Save arpitnarechania/64b7994d99afe392063a6efaf5eb86d0 to your computer and use it in GitHub Desktop.
Tally Chart

Tally Chart with configurable break_at_points and manual/automated updates

<!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>
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();
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