d3js toggling bars animation - javascript

I am trying to animate the bars when the user clicks on the legend. I've built the update function - but I am unsure on how to do the required filter and animation for this feature
http://jsfiddle.net/0ht35rpb/211/
function update(){
console.log("data", data);
var barData = data.filter(function(d1) {
console.log("d1", d1);
return !d1.disabled;
});
console.log("barData", barData);
var bar = chartHolder.selectAll(".bar")
.data(data)
console.log("bar", bar);
bar.transition()
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
bar.exit().remove();
/*
var bar = bar.selectAll("rect")
bar.transition()
//.attr("id", function(d){ return 'tag'+d.state.replace(/\s|\(|\)|\'|\,+/g, '');})
.attr("x", function(d) { return x1(d.name); })
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
//bar.exit().remove();
*/

This code var bar = chartHolder.selectAll(".bar") returns empty selection. You should select all .bars apply new data with method data, after that select all react, set animation parameters transition, duration, delay and set new values for approptiate attributes.
I rewrite your code - http://jsfiddle.net/168x28p3/1/ Here, I simply animate height of bars after click on legend. But this way you can create the another animation which you need.
var $this = document.querySelector('.chart');
var data = [{
label: "a",
"Current Period": 20,
"Prior Year": 10
}, {
label: "b",
"Current Period": 15,
"Prior Year": 30
}, {
label: "c",
"Current Period": 25,
"Prior Year": 40
}, {
label: "d",
"Current Period": 5,
"Prior Year": 60
}];
var configuration = [{
"yLabel": "People Count"
}];
var w = 660;
var h = 500;
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f", "#8bf41b"];
return colores_g[n % colores_g.length];
}
var margin = {
top: 20,
right: 110,
bottom: 30,
left: 20
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var svg = d3.select($this).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var axisHolder = svg.append("g")
.attr("class", "axis");
var chartHolder = svg.append("g")
.attr("class", "chart");
var legendHolder = svg.append("g")
.attr("class", "legend");
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
//var colorRange = d3.scale.category20();
//var color = d3.scale.ordinal()
//.range(colorRange.range());
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var options = d3.keys(data[0]).filter(function(key) {
return key !== "label";
});
data.forEach(function(d) {
d.valores = options.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(data.map(function(d) {
return d.label;
}));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.valores, function(d) {
return d.value;
});
})]);
axisHolder.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
axisHolder.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(configuration[0].yLabel);
var bar = chartHolder.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bars")
.attr("transform", function(d) {
return "translate(" + x0(d.label) + ",0)";
});
bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("value", function(d) {
return d.name;
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d, i) {
return colores_google(i);
});
bar
.on("mousemove", function(d) {
divTooltip.style("left", d3.event.pageX + 10 + "px");
divTooltip.style("top", d3.event.pageY - 25 + "px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX,
y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l - 1
elementData = elements[l].__data__
divTooltip.html((d.label) + "<br>" + elementData.name + "<br>" + elementData.value + "%");
});
bar
.on("mouseout", function(d) {
divTooltip.style("display", "none");
});
var legend = legendHolder.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(" + margin.right + "," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
})
.on("click", function(d) {
console.log("d", d);
d.disabled = !d.disabled;
update();
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
function update() {
var barData = data.map(item => {
item.valores = item.valores.map(valor => {
return Object.assign({}, valor, { value: Math.random() * 40 })
})
return item;
})
var bar = chartHolder.selectAll(".bars")
.data(barData)
var rect = bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
rect
.transition()
.duration(1000)
.delay(100)
.attr("width", x0.rangeBand() / 2)
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
}
* {
margin: 0;
padding: 0;
border: 0;
}
body {
background: #ffd;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: relative;
}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
rect {
stroke-width: 2;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path {
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axisHorizontal path {
fill: none;
}
.axisHorizontal line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
/*
.x.axis path {
display: none;
}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div class="chart"></div>

Related

TypeError: Cannot read property 'year' of undefined

I am trying to create an interactive line chart with mouseover function. When you place your mouse over the line you can see the value of the GDP and the year at that certain point. But for some reason,I am getting the below error but I am not sure why it is happening as i am passing the right format data-set into the function.
Uncaught TypeError: Cannot read property 'year' of undefined
My code is below:
HTML
<!DOCTYPE html>
<htmL>
<meta charset="utf-8">
<head>
<style>
.line-chart2{
margin-top:200px;
margin-left:100px;
border:1px solid lightgray;
}
circle {
fill: steelblue;
}
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;
}
div.tooltip {
position: absolute;
text-align: center;
width: 80px;
height: 64px;
padding: 2px;
font: 14px sans-serif;
color: black;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: #F1F3F3;
stroke: #6F257F;
stroke-width: 5px;
}
.hover-line {
stroke: #6F257F;
stroke-width: 2px;
stroke-dasharray: 3,3;
}
</style>
</head>
<body>
<svg class='line-chart2'></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="math.js" type="text/javascript"></script>
<script src="./regression.js"></script>
</body>
</htmL>
Javascript
var gdp=[ 387.65, 410.32, 415.73, 452.69, 462.14,
478.96, 508.06, 599.59, 699.68, 808.90,
920.31, 1201.11, 1186.95, 1323.94, 1656.61,
1823.04, 1827.63, 1856.72, 2039.12, 2102.39,
2274.22, 2600.81]; //y or GDP of India
var years=['1996','1997','1998','1999','2000','2001','2002','2003','2004','2005','2006','2007','2008','2009','2010','2011','2012','2013','2014','2015','2016','2017'];
var data_gdp=[]
for(i=0;i<forexp.length;i++){
data_gdp.push({year:years[i],value:gdp[i]})
}
function drawChart_gdp(data,class_name) {
var svgWidth = 1200, svgHeight = 400;
var margin = { top: 60, right: 60, bottom: 60, left: 60 };
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select(class_name)
.attr("width", svgWidth)
.attr("height", svgHeight);
var bisectDate= d3.bisector(function(d) { return d.year; }).left;
var g = svg.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")"
);
var x = d3.scaleTime().range([0,width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(new Date(parseInt(d.year),0))})
.y(function(d) { return y(d.value)})
x.domain(d3.extent(data, function (d) { return new Date(parseInt(d.year),0); }));
y.domain(d3.extent(data, function(d) { return d.value }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.text("Year")
.attr("dy", "1.90em")
.attr("y", 5)
.attr("x",500)
.attr("font-size", "20px")
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", -80)
.attr("x",-55)
.attr("dy", "1.90em")
.attr("text-anchor", "center")
.attr("font-size", "20px")
.text("GDP ($)")
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
var focus = g.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 7.5);
focus.append("text")
.attr("x", 15)
.attr("dy", ".31em");
svg.append("rect")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", function() { //problem in this function
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.year > d1.year - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
focus.select("text").text(function() { return d.value; });
focus.select(".x-hover-line").attr("y2", height - y(d.value));
focus.select(".y-hover-line").attr("x2", width + width);
});
}
drawChart_gdp(data_gdp,'.line-chart2');
Since x is a time scale, the returned value of...
var x0 = x.invert(d3.mouse(this)[0])
... is a date object, like this:
Fri Nov 29 1996 19:56:00
However, in your data, you have strings:
[{year: "1996", value: 387.65}, {year: "1997", value: 410.32} etc...];
The solution is quite straightforward, just format the dates:
var x0 = d3.timeFormat("%Y")(x.invert(d3.mouse(this)[0]))
Here is your code with that change:
var gdp = [387.65, 410.32, 415.73, 452.69, 462.14,
478.96, 508.06, 599.59, 699.68, 808.90,
920.31, 1201.11, 1186.95, 1323.94, 1656.61,
1823.04, 1827.63, 1856.72, 2039.12, 2102.39,
2274.22, 2600.81
]; //y or GDP of India
var years = ['1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017'];
var data_gdp = []
for (i = 0; i < years.length; i++) {
data_gdp.push({
year: years[i],
value: gdp[i]
})
}
function drawChart_gdp(data, class_name) {
var svgWidth = 1200,
svgHeight = 400;
var margin = {
top: 60,
right: 60,
bottom: 60,
left: 60
};
var width = svgWidth - margin.left - margin.right;
var height = svgHeight - margin.top - margin.bottom;
var svg = d3.select(class_name)
.attr("width", svgWidth)
.attr("height", svgHeight);
var bisectDate = d3.bisector(function(d) {
return d.year;
}).left;
var g = svg.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")"
);
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var line = d3.line()
.x(function(d) {
return x(new Date(parseInt(d.year), 0))
})
.y(function(d) {
return y(d.value)
})
x.domain(d3.extent(data, function(d) {
return new Date(parseInt(d.year), 0);
}));
y.domain(d3.extent(data, function(d) {
return d.value
}));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.append("text")
.attr("fill", "#000")
.text("Year")
.attr("dy", "1.90em")
.attr("y", 5)
.attr("x", 500)
.attr("font-size", "20px")
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", -80)
.attr("x", -55)
.attr("dy", "1.90em")
.attr("text-anchor", "center")
.attr("font-size", "20px")
.text("GDP ($)")
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
var focus = g.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 7.5);
focus.append("text")
.attr("x", 15)
.attr("dy", ".31em");
svg.append("rect")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none");
})
.on("mousemove", function() { //problem in this function
var x0 = d3.timeFormat("%Y")(x.invert(d3.mouse(this)[0])),
i = bisectDate(data, x0, 1);
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.year > d1.year - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
focus.select("text").text(function() {
return d.value;
});
focus.select(".x-hover-line").attr("y2", height - y(d.value));
focus.select(".y-hover-line").attr("x2", width + width);
});
}
drawChart_gdp(data_gdp, '.line-chart2');
<head>
<style>
circle {
fill: steelblue;
}
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;
}
div.tooltip {
position: absolute;
text-align: center;
width: 80px;
height: 64px;
padding: 2px;
font: 14px sans-serif;
color: black;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: #F1F3F3;
stroke: #6F257F;
stroke-width: 5px;
}
.hover-line {
stroke: #6F257F;
stroke-width: 2px;
stroke-dasharray: 3, 3;
}
</style>
</head>
<body>
<svg class='line-chart2'></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
</body>

D3 Chart values are not grouped (from JSON load)

I have a JSON query and I am presenting the data using a D3 chart. It seems that the grouping (Countries) does not work. We can some more than one line for each country (e.g. Canada). Part of the code:
data.forEach(function (a) {
groups[a.value] = groups[a.value] || [];
groups[a.value].push(a);
});
result = Object.keys(groups).reduce(function (r, k) {
return r.concat(groups[k]);
}, []);
Ideally, I want to make this work by changing the script. A second solution is to change the format of the JSON (manipulation). I am trying to focus on the first solution... The snippet is here:
var json_data= {"headers":["Dimension 1","Metric 1","Metric 2"],"rows":[["Australia",174,23],["Canada",502,17],["France",242,37],["Germany",102,42],["United Kingdom",126,44],["United States",1246,47],["Australia",680,80],["Canada",1241,66],["Canada",1241,66],["France",150,30],["Germany",244,22],["United Kingdom",501,9],["United States",4960,41],["Australia",9,8],["Canada",3655,70],["France",1654,95],["Germany",1190,36],["United Kingdom",1222,38],["United States",7941,53],["Australia",6829,56],["Canada",1664,75],["France",2995,88],["Germany",1487,100],["United Kingdom",9245,29],["United States",9008,66],["Australia",9376,7],["Canada",1531,31],["France",5421,22],["Germany",6975,41],["United Kingdom",4320,100],["United States",3200,41],["Australia",6688,41],["Canada",699,42],["France",5403,70],["Germany",6377,49],["United Kingdom",2471,14],["United States",6650,4],["Australia",865,70],["Canada",511,20],["France",981,36],["Germany",57,10],["United Kingdom",675,38],["United States",40,72],["Australia",400,63],["Canada",971,90],["France",357,93],["Germany",820,40],["United Kingdom",520,32],["United States",448,24],["Australia",513,40],["Canada",977,8],["France",118,84],["Germany",161,29],["United Kingdom",239,89],["United States",327,79]]};
var headers = json_data.headers;
var platform_data = json_data.rows;
var data = [];
var metric = 0;
for (var i in platform_data)
{
var dimension = platform_data[i][0];
metric = (platform_data[i][1]).toFixed(0);
object = { label: dimension, value: metric};
data.push(object);
}
//Sorting
var data = data,
groups = Object.create(null),
result = [];
data.forEach(function (a) {
groups[a.value] = groups[a.value] || [];
groups[a.value].push(a);
});
result = Object.keys(groups).reduce(function (r, k) {
return r.concat(groups[k]);
}, []);
//Descending - Reverse JSON order
var objAssetSelection = result.reverse();
data = objAssetSelection;
//D3 Code
var div = d3.select("body").append("div").attr("class", "toolTip");
var axisMargin = 20,
margin = 40,
valueMargin = 4,
width = parseInt(d3.select('body').style('width'), 10),
height = parseInt(d3.select('body').style('height'), 10),
barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
barPadding = (height-axisMargin-margin*2)*0.6/data.length,
data, bar, svg, scale, xAxis, labelWidth = 0;
max = d3.max(data, function(d) { return d.value; });
svg = d3.select('body')
.append("svg")
.attr("width", width)
.attr("height", height);
bar = svg.selectAll("g")
.data(data)
.enter()
.append("g");
bar.attr("class", "bar")
.attr("cx",0)
.attr("transform", function(d, i) {
return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
});
bar.append("text")
.attr("class", "label")
.attr("y", barHeight / 2)
.attr("dy", ".35em") //vertical align middle
.text(function(d){
return d.label;
}).each(function() {
labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});
scale = d3.scale.linear()
.domain([0, max])
.range([0, width - margin*2 - labelWidth]);
xAxis = d3.svg.axis()
.scale(scale)
.tickSize(-height + 2*margin + axisMargin)
.orient("bottom");
bar.append("rect")
.attr("transform", "translate("+labelWidth+", 0)")
.attr("height", barHeight)
.attr("width", function(d){
return scale(d.value);
});
bar.append("text")
.attr("class", "value")
.attr("y", barHeight / 2)
.attr("dx", -valueMargin + labelWidth) //margin right
.attr("dy", ".35em") //vertical align middle
.attr("text-anchor", "end")
.text(function(d){
return (d.value);
})
.attr("x", function(d){
var width = this.getBBox().width;
return Math.max(width + valueMargin, scale(d.value));
});
bar
.on("mousemove", function(d){
div.style("left", d3.event.pageX+10+"px");
div.style("top", d3.event.pageY-25+"px");
div.style("display", "inline-block");
div.html((d.label)+"<br>"+(d.value));
});
bar
.on("mouseout", function(d){
div.style("display", "none");
});
svg.insert("g",":first-child")
.attr("class", "axisHorizontal")
.attr("transform", "translate(" + (margin + labelWidth) + ","+ (height - axisMargin - margin)+")")
.call(xAxis);
#import url('https://fonts.googleapis.com/css?family=Roboto');
body {
font-family: "Roboto"!important;
width: 100%;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
.toolTip {
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
text {
font: 10px sans-serif;
color: white;
}
text.value {
font-size: 100%;
fill: white;
}
.axisHorizontal path{
fill: none;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
The grouping code is incorrect. If you console log data after your grouping data, it's the same non-grouped data.
For better grouping, you can take a look at d3.nest. Here's the grouping code using d3.nest (grouping data based on label and summing up the values using d3.sum (d3.sum):
var nested_data = d3.nest()
.key(function(d) { return d.label; })
.rollup(function (d) {
return d3.sum(d, function(v) { return +v.value;})
}).entries(data);
And to not disturb your rest of the code, I'm mapping this nested_data to the original format by this:
data = nested_data.map(function(row) {
return {label: row.key, value: row.values};
});
EDIT: Adding sorting code
data.sort(function(a, b) { return a.value > b.value ? -1 : a.value === b.value ? 0 : 1; });
Using the above nesting/grouping, here's a code snippet:
var json_data= {"headers":["Dimension 1","Metric 1","Metric 2"],"rows":[["Australia",174,23],["Canada",502,17],["France",242,37],["Germany",102,42],["United Kingdom",126,44],["United States",1246,47],["Australia",680,80],["Canada",1241,66],["Canada",1241,66],["France",150,30],["Germany",244,22],["United Kingdom",501,9],["United States",4960,41],["Australia",9,8],["Canada",3655,70],["France",1654,95],["Germany",1190,36],["United Kingdom",1222,38],["United States",7941,53],["Australia",6829,56],["Canada",1664,75],["France",2995,88],["Germany",1487,100],["United Kingdom",9245,29],["United States",9008,66],["Australia",9376,7],["Canada",1531,31],["France",5421,22],["Germany",6975,41],["United Kingdom",4320,100],["United States",3200,41],["Australia",6688,41],["Canada",699,42],["France",5403,70],["Germany",6377,49],["United Kingdom",2471,14],["United States",6650,4],["Australia",865,70],["Canada",511,20],["France",981,36],["Germany",57,10],["United Kingdom",675,38],["United States",40,72],["Australia",400,63],["Canada",971,90],["France",357,93],["Germany",820,40],["United Kingdom",520,32],["United States",448,24],["Australia",513,40],["Canada",977,8],["France",118,84],["Germany",161,29],["United Kingdom",239,89],["United States",327,79]]};
var headers = json_data.headers;
var platform_data = json_data.rows;
var data = [];
var metric = 0;
for (var i in platform_data)
{
var dimension = platform_data[i][0];
metric = (platform_data[i][1]).toFixed(0);
object = { label: dimension, value: metric};
data.push(object);
}
//Sorting
var data = data,
groups = Object.create(null),
result = [];
/* data.forEach(function (a) {
groups[a.value] = groups[a.value] || [];
groups[a.value].push(a);
});
result = Object.keys(groups).reduce(function (r, k) {
return r.concat(groups[k]);
}, []); */
var nested_data = d3.nest()
.key(function(d) { return d.label; })
.rollup(function (d) {
return d3.sum(d, function(v) { return +v.value;})
}).entries(data);
data = nested_data.map(function(row) {
return {label: row.key, value: row.values};
}).sort(function(a, b) { return a.value > b.value ? -1 : a.value === b.value ? 0 : 1; });
//Descending - Reverse JSON order
/* var objAssetSelection = result.reverse();
data = objAssetSelection;
*/
//D3 Code
var div = d3.select("body").append("div").attr("class", "toolTip");
var axisMargin = 20,
margin = 40,
valueMargin = 4,
width = parseInt(d3.select('body').style('width'), 10),
height = parseInt(d3.select('body').style('height'), 10),
barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
barPadding = (height-axisMargin-margin*2)*0.6/data.length,
data, bar, svg, scale, xAxis, labelWidth = 0;
max = d3.max(data, function(d) { return d.value; });
svg = d3.select('body')
.append("svg")
.attr("width", width)
.attr("height", height);
bar = svg.selectAll("g")
.data(data)
.enter()
.append("g");
bar.attr("class", "bar")
.attr("cx",0)
.attr("transform", function(d, i) {
return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
});
bar.append("text")
.attr("class", "label")
.attr("y", barHeight / 2)
.attr("dy", ".35em") //vertical align middle
.text(function(d){
return d.label;
}).each(function() {
labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});
scale = d3.scale.linear()
.domain([0, max])
.range([0, width - margin*2 - labelWidth]);
xAxis = d3.svg.axis()
.scale(scale)
.tickSize(-height + 2*margin + axisMargin)
.orient("bottom");
bar.append("rect")
.attr("transform", "translate("+labelWidth+", 0)")
.attr("height", barHeight)
.attr("width", function(d){
return scale(d.value);
});
bar.append("text")
.attr("class", "value")
.attr("y", barHeight / 2)
.attr("dx", -valueMargin + labelWidth) //margin right
.attr("dy", ".35em") //vertical align middle
.attr("text-anchor", "end")
.text(function(d){
return (d.value);
})
.attr("x", function(d){
var width = this.getBBox().width;
return Math.max(width + valueMargin, scale(d.value));
});
bar
.on("mousemove", function(d){
div.style("left", d3.event.pageX+10+"px");
div.style("top", d3.event.pageY-25+"px");
div.style("display", "inline-block");
div.html((d.label)+"<br>"+(d.value));
});
bar
.on("mouseout", function(d){
div.style("display", "none");
});
svg.insert("g",":first-child")
.attr("class", "axisHorizontal")
.attr("transform", "translate(" + (margin + labelWidth) + ","+ (height - axisMargin - margin)+")")
.call(xAxis);
body {
font-family: "Roboto"!important;
width: 100%;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
.toolTip {
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
text {
font: 10px sans-serif;
color: white;
}
text.value {
font-size: 100%;
fill: white;
}
.axisHorizontal path{
fill: none;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
To learn more about d3 nest, here's a good examples list: http://bl.ocks.org/phoebebright/raw/3176159/
Hope this helps.

d3js scroll visibility - series animation for bar chart

I am working on a d3 application and I am interested in taking the following jsfiddle -- and onload or on an action -- revoking an animation where the bar charts animate one by one.
So the first bar animates to its height, then the second and so forth. Also a reversal of the animation would be good too -- so maybe something that is invoked automatically on scroll visibility?
http://jsfiddle.net/pg886/201/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<div
class="barchart"
data-role="barchart"
data-width=300
data-height=400
data-data="x"
data-configurations=""
>
</div>
<style>
.barchart{
/*width:100%;
border: 1px solid red;*/
}
.barchart svg{
width:100%;
/*border: 1px solid green;*/
}
.barchartg{
}
.barchart .axis path{
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.barchart .axis line {
fill: none;
stroke: none;
shape-rendering: crispEdges;
}
.barchart .x.axis path {
display: none;
}
.barchart .axis text{
fill: #005a70;
}
.barchart.dark .axis text{
fill: #ffffff;
}
.barchart.dark .axis path{
stroke: #ffffff;
}
.barchart .bar:hover {
fill: #e9168a;
}
</style>
<script>
$(document).ready(function() {
console.log("test")
var $this = $(".barchart");
var w = $this.data("width");
var h = $this.data("height");
var data = $this.data("data");
var data = [{
"label": "Apples",
"value": 100
},
{
"label": "Pears",
"value": 120
},
{
"label": "Bananas",
"value": 20
}];
var configurations = $this.data("configurations");
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#2b2d39", "#c12f39", "#f8dd2f", "#1b91dc"];
return colores_g[n % colores_g.length];
}
//asess the margin bottom for the chart based on the max char label
var charLabelCount = [];
data.map(function(d) {
var labelStr = d.label.toString();
charLabelCount.push(labelStr.length);
})
var maxChars = charLabelCount.reduce(function(a, b) {
return Math.max(a, b);
});
var bottomMarg = 60;
if(maxChars > 15){
bottomMarg = 170;
}
//bottom margin calculation
var margin = {top: 15, right: 20, bottom: bottomMarg, left: 40},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var x = d3.scaleBand()
.rangeRound([0, width]).padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var svg = d3.select($this[0])
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("viewBox", "0 0 "+w+" "+h)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "barchartg");
function sortBy(array,key){
var sorted = array.sort(function(a, b) {
return parseFloat(b[key]) - parseFloat(a[key]);
});
return sorted;
}
var sortedMax = 45;//45 as an initial value
//if there is a configuration file - it acts as an overide -- this is so there could be just one chart -- or a set of charts next to each other
if(configurations){
//if its a comparison chart -- use a max value that will be shared amongst a stack of sibling charts
if(configurations[0]["maxValue"]){
sortedMax = configurations[0]["maxValue"] + 5;//add 5 value buffer
}
}
else{
//if its a stand alone chart - adjust the max val by this chart's own values
sortedMax = sortBy(data, "value")[0]["value"] + 5;//add 5 value buffer
}
x.domain(data.map(function(d) {
return d.label;
}));
y.domain([0, sortedMax]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.selectAll(".x.axis text")
.attr("transform", "rotate(-60) translate(-5,-5)")
.style("text-anchor", "end");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("fill", function(d, i) {
return colores_google(i);
})
.attr("x", function(d) {
return x(d.label);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
});
</script>
Use .transition() to trigger animation to each rect.
But you have to start each rect with a height of zero and y of zero as well, so that you have something to work with in the animation.
$(document).ready(function() {
console.log("test")
var $this = $(".barchart");
var w = $this.data("width");
var h = $this.data("height");
var data = $this.data("data");
var data = [{
"label": "Apples",
"value": 100
},
{
"label": "Pears",
"value": 120
},
{
"label": "Bananas",
"value": 20
}
];
var configurations = $this.data("configurations");
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#2b2d39", "#c12f39", "#f8dd2f", "#1b91dc"];
return colores_g[n % colores_g.length];
}
//asess the margin bottom for the chart based on the max char label
var charLabelCount = [];
data.map(function(d) {
var labelStr = d.label.toString();
charLabelCount.push(labelStr.length);
})
var maxChars = charLabelCount.reduce(function(a, b) {
return Math.max(a, b);
});
var bottomMarg = 60;
if (maxChars > 15) {
bottomMarg = 170;
}
//bottom margin calculation
var margin = {
top: 15,
right: 20,
bottom: bottomMarg,
left: 40
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var x = d3.scaleBand()
.rangeRound([0, width]).padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var svg = d3.select($this[0])
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("viewBox", "0 0 " + w + " " + h)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "barchartg");
function sortBy(array, key) {
var sorted = array.sort(function(a, b) {
return parseFloat(b[key]) - parseFloat(a[key]);
});
return sorted;
}
var sortedMax = 45;
if (configurations) {
if (configurations[0]["maxValue"]) {
sortedMax = configurations[0]["maxValue"] + 5;
}
} else {
sortedMax = sortBy(data, "value")[0]["value"] + 5;
}
x.domain(data.map(function(d) {
return d.label;
}));
y.domain([0, sortedMax]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.selectAll(".x.axis text")
.attr("transform", "rotate(-60) translate(-5,-5)")
.style("text-anchor", "end");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("fill", function(d, i) {
return colores_google(i);
})
.attr("x", function(d) {
return x(d.label);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(0);
})
.attr("height", function(d) {
return 0
});
d3.selectAll("rect").transition()
.duration(500)
.delay(function(d,i){ return 500*i;})
.attr("height",function(d){ return height - y(d.value);})
.attr("y",function(d){return y(d.value);});
setTimeout(function(){
d3.selectAll("rect").transition()
.duration(500)
.delay(function(d,i){ return 600*(3-i);})
.attr("height",function(d){ return 0;})
.attr("y",function(d){return y(0);});
},2000);
});
.barchart {
/*width:100%;
border: 1px solid red;*/
}
.barchart svg {
width: 100%;
/*border: 1px solid green;*/
}
.barchartg {}
.barchart .axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.barchart .axis line {
fill: none;
stroke: none;
shape-rendering: crispEdges;
}
.barchart .x.axis path {
display: none;
}
.barchart .axis text {
fill: #005a70;
}
.barchart.dark .axis text {
fill: #ffffff;
}
.barchart.dark .axis path {
stroke: #ffffff;
}
.barchart .bar:hover {
fill: #e9168a;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<div class="barchart" data-role="barchart" data-width=300 data-height=400 data-data="x" data-configurations="">
</div>
you need to add transition for each bar while generating and delay the transion according to your wish.the code is as.
.transition()
.delay(function (d,i){ return i * 300;})
.duration(250)
the updated code with your code block is as follows
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.transition()
.delay(function (d,i){ return i * 300;})
.duration(250)
.attr("fill", function(d, i) {
return colores_google(i);
})
.attr("x", function(d) {
return x(d.label);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
})

Convert vertical stacked bar to horizontal stacked bar D3.js v4

I found a vertical stack bar graph sample on google - http://bl.ocks.org/juan-cb/43f10523858abf6053ae
I want to convert it in horizontal stacked bar graph. I have done the changes but something is wrong. Graph is not correct.I think all the bars are overlapped.
Please help me to resolve this. Code is copied.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
text{
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path{
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<body>
<div class="barGraph" id='stacked-bar'></div>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script>
<script>
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
init();
function init(){
var dataset = [{
"goodRating": 27,
"avgRating": 21,
"badRating": 16,
"rooms": "0.01"
},
{
"goodRating": 26,
"avgRating": 22,
"badRating": 31,
"rooms": "0.02"
},
{
"goodRating": 100,
"avgRating": 0,
"badRating": 0,
"rooms": "1"
}];
var groupSpacing = 6;
var margin = {top: 10, right: 10, bottom: 60, left: 100},
width = 1000 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0]);
var x = d3.scaleLinear()
.range([0, width], .1,.3);
// var colorRange = d3.scale.category20();
var color = d3.scaleOrdinal(d3.schemeCategory20);
var xAxis = d3.axisBottom(x).tickFormat(dataset.rooms),
yAxis = d3.axisLeft(y);
var svg = d3.select("#stacked-bar").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "rooms"; }));
dataset.forEach(function(d) {
var y0 = 0;
var y1 = 0;
d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.values[d.values.length - 1].y1;
});
y.domain(dataset.map(function(d) { return d.rooms; }));
x.domain([0, d3.max(dataset, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".5em")
.attr("transform", "rotate(-65)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Satisfaction %");
var bar = svg.selectAll(".rooms")
.data(dataset)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
svg.selectAll(".x.axis .tick text")
.call(wrap, y.bandwidth());
var bar_enter = bar.selectAll("rect")
.data(function(d) { return d.values; })
.enter();
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y1); })
.attr("width", function(d) { return x(d.y1) - x(d.y0) })
.style("fill", function(d) { return color(d.name); });
bar_enter.append("text")
.text(function(d) { return d3.format(".2s")(d.y1-d.y0)+"%"; })
.attr("x", function(d) { return x(d.y1)+(x(d.y0) - x(d.y1))/2; })
.attr("y", y.bandwidth()/3)
.style("fill", '#ffffff');
bar.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
element = elements[l].__data__
value = element.y1 - element.y0
divTooltip.html("Room No : "+(d.rooms)+"<br>"+element.name+" : "+value+"%");
});
bar.on("mouseout", function(d){
divTooltip.style("display", "none");
});
}
</script>
</body>
Regards,
Pinki Sharma
A few minor things were missing/incorrect:
The group (<g>) containing the bars was being transformed incorrectly (I'm guessing you missed this while changing from vertical stacked to horizontal) i.e. the following line
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
translates the bar groups from the left and the y position would be 0 and hence the overlap. I've changed that to this:
.attr("transform", function(d) { return "translate(0, " + y(d.rooms) + ")"; });
The rects' x value is changed from x(d.y1) to x(d.y0) (might be a typo)
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y0); })
Axis padding was missing for the scaleBand(). I've added that (check docs for more info)
var y = d3.scaleBand()
.rangeRound([height, 0]).padding(0.1);
Reset the margins to adapt to the SVG dimensions:
var margin = {top: 10, right: 60, bottom: 60, left: 50},
Combining all of the above, here's a fork of your codepen:
HORIZONTAL STACKED BAR CHART DEMO
Hope this helps.

Getting d3.js stacked bar chart to match the same design?

I am trying to work on getting a d3.js bar chart similar to the one. I have in HTML & CSS as following :
Here is HTML Link : http://huntedhunter.com/venue_report/
Can I know if it would be possible to get this one similar like the above HTML & CSS one :
https://codepen.io/nicefellow1234/pen/aEZrma
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
dataset = [
{label:"Art and Humanities", "Not Satisfied":25, "Not Much Satisfied":40, "Satisfied": 15, "Very Satisfied":20},
{label:"Sciences", "Not Satisfied":5, "Not Much Satisfied":30, "Satisfied": 50, "Very Satisfied":15},
{label:"Health Sciences", "Not Satisfied":20, "Not Much Satisfied":30, "Satisfied": 40, "Very Satisfied":10},
{label:"Social Sciences", "Not Satisfied":10, "Not Much Satisfied":40, "Satisfied": 45, "Very Satisfied":5},
{label:"Architecture and Engineering", "Not Satisfied":5, "Not Much Satisfied":15, "Satisfied": 40, "Very Satisfied":40},
];
var margin = {top: (parseInt(d3.select('body').style('height'), 10)/20), right: (parseInt(d3.select('body').style('width'), 10)/20), bottom: (parseInt(d3.select('body').style('height'), 10)/6), left: (parseInt(d3.select('body').style('width'), 10)/20)},
width = parseInt(d3.select('body').style('width'), 10) - margin.left - margin.right,
height = parseInt(d3.select('body').style('height'), 10) - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1,.3);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "label"; }));
dataset.forEach(function(d) {
var y0 = 0;
d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.values[d.values.length - 1].y1;
});
x.domain(dataset.map(function(d) { return d.label; }));
y.domain([0, d3.max(dataset, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Satisfaction %");
var bar = svg.selectAll(".label")
.data(dataset)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.label) + ",0)"; });
svg.selectAll(".x.axis .tick text")
.call(wrap, x.rangeBand());
var bar_enter = bar.selectAll("rect")
.data(function(d) { return d.values; })
.enter();
bar_enter.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
bar_enter.append("text")
.text(function(d) { return d3.format(".2s")(d.y1-d.y0)+"%"; })
.attr("y", function(d) { return y(d.y1)+(y(d.y0) - y(d.y1))/2; })
.attr("x", x.rangeBand()/3)
.style("fill", '#ffffff');
bar
.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
element = elements[l].__data__
value = element.y1 - element.y0
divTooltip.html((d.label)+"<br>"+element.name+"<br>"+value+"%");
});
bar
.on("mouseout", function(d){
divTooltip.style("display", "none");
});
svg.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(0,"+(height+30)+")");
var legend = d3.legend.color()
.shapeWidth(height/4)
.shapePadding(10)
.orient('horizontal')
.scale(color);
svg.select(".legendLinear")
.call(legend);
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
text{
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path{
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script>

Categories

Resources