Reputation: 796
I am trying to create stacked bar charts such that when you click on them it will give you more detailed information regarding that stack.
Consider each bar represents a subject and each section in the bar represents mastery of students learning that subject in six different levels: say level 1 to level 6; level 1- very poor performance of a student and level 6 indicates the student has mastered the subject
Lets say initially stacked bars look like this:
If you select a subject, lets say solid geometry.
Then I click on one of the bars:
As shown above one can see that there are 4 students who are struggling in this subject while 4 students need practice of this subject.. and so on...
Then that stacked bar will expand this way , giving me more information regarding what is about
How can we do this in D3?
Any help appreciated.
Upvotes: 3
Views: 155
Reputation: 453
I don't see any research into, or attempts at, learning or using D3. While D3 can initially be daunting, the documentation makes it fairly approachable and you'd likely get more traction here if your question was slightly more specific.
That said, take a look at the example below. You'll see that D3 is a helper for mapping data to elements and orchestrating DOM manipulation. Also note that plain old CSS can accomplish much of the interactivity requirements. Finally, understand that you could accomplish this many different ways; this is just one quick hack.
var student_data = [{
category: 'Struggling',
students: [
'Ben',
'Elizabeth'
]
}, {
category: 'Level One',
students: [
'Jessica',
'Matt'
]
}, {
category: 'Mastered',
students: [
'John',
'Katie'
]
}];
// the quantile scale maps an input domain of
// values to an output range of values by 'spreading'
// the domain across the range.
var colors = d3.scale.quantile()
.domain([0, student_data.length])
.range(['red', 'grey', 'lightblue', 'darkblue']);
// the base element
var root = d3.select('.panel');
// selectAll ~= querySelectorAll
// says, find all elements with class 'category'
// if none exist, prepare a selection of
// student_data.length elements
var display = root.selectAll('.category')
.data(student_data);
// take the prepared selection and
// for each
display.enter()
// create an element
.append('div')
// assign the 'category' class to the element
.attr('class', 'category')
// set the background color
.style('background-color', function(d, i) {
// d is the current array element of student_data
// i is the index of the current array element of student_data
// so, pass i to the colors scale/map to get back a color
return colors(i);
})
// add a mouse enter handler to set the text of a
// yet to be added label.
.on('mouseenter', function(d) {
// this is the current element
d3.select(this)
// so, select the first element
// with class label
.select('.label')
// and set it's text to the category property
// of current array element of student_data
.text(d.category);
})
// add a mouse leave handler to reset the text of the still
// yet to be added label.
.on('mouseleave', function(d) {
d3.select(this).select('.label').text(d.students.length);
})
// for each created element
.each(function(d) {
// select the current element
var selection = d3.select(this);
// create the label referenced above
var label = selection.append('div')
// assign it a class of 'label'
.attr('class', 'label')
// and set it's text to count of
// the students property
.text(function(d) {
// d = student_data[i]
return d.students.length;
});
// also, prepare a new selection of
// elements for each of the student names
var names = selection
.selectAll('.student')
.data(d.students);
// take the prepared selection and
// for each
names.enter()
// create an element
.append('div')
// assign the 'student' class
.attr('class', 'student')
// and set the text to that
// of the current element
.text(function(dd) {
// dd = student_data[i].students[j]
return dd;
});
});
div {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-family: arial;
}
.panel {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-align: start;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start;
width: 100%;
font-size: 0.8rem;
}
.category {
display: inline-block;
padding: 0.5rem;
min-width: 2rem;
min-height: 2rem;
color: white;
background-color: black;
transition: all 250ms ease;
}
.category:hover {
min-width: 10rem;
width: auto;
height: auto;
transition: all 250ms ease;
}
.label {
transition: all 250ms ease;
}
.student {
display: none;
padding: 0.25rem;
width: 100%;
color: black;
background-color: white;
cursor: pointer;
transition: all 250ms ease;
}
.student:hover {
background-color: lightblue;
}
.category:hover .label {
padding-bottom: 0.5rem;
}
.category:hover .student {
display: inline-block;
}
<div class='panel'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 2