Adapted from Scott Murray's examples. Used for my own learning:
use div for tooltip styling
use css class for event styling
mouseover / mouseout
use d3.event to determine mouse location
use groups to group individual bars and text elements and then position each with respect to each other
use .filter to change style of individual datapoints/elements
add class after filtering data and use css to style these data separately
forked from jalapic's block: bars: groups, events
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<title>D3: An HTML div as tooltip</title>
<style type="text/css">
body {
background-color: gray;
}
svg {
background-color: white;
}
g.bar text {
font-family: sans-serif;
font-size: 11px;
fill: white; /*use fill with svg, not color, to color*/
font-style: bold;
text-anchor: middle;
opacity: 0;
}
/* Commented out, now that we have a <div> tooltip */
/*
g.bar.highlight text {
opacity: 1;
}
*/
g.bar.highlight rect {
fill: #15ff00;
stroke: #2a7a00;
}
g.bar.highlight rect.filtereddata { /*rect.filtereddata refers to data selected based on value and class was only applied to rect element of the group */
fill: #fdcb4e;
stroke: #415b00;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
/* Styling for new <div> */
#tooltip {
position: absolute;
top: 0;
left: 0;
z-index: 10;
margin: 0;
padding: 10px;
width: 15px;
height: 12px;
color: white;
font-family: sans-serif;
font-size: 12px;
font-weight: bold;
text-align: center;
background-color: rgba(0, 0, 0, 0.75);
opacity: 0; /* initially not visible */
pointer-events: none;
}
</style>
</head>
<body>
<!-- New HTML div functions as our tooltip -->
<div id="tooltip">
</div>
<script type="text/javascript">
//Width, height, padding
var w = 800;
var h = 450;
var padding = 25;
//Array of dummy data values
var dataset = [ 1, 4, 8, 9, 11, 15, 22, 24, 22, 21,
17, 12, 15, 11, 12, 7, 6, 8, 3, 5 ];
//Configure x and y scale functions
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([ padding, w - padding ], 0.1); //gap bt bars
var yScale = d3.scale.linear()
.domain([ 0, d3.max(dataset) ])
.rangeRound([ h - padding, padding ]);
//Configure y axis generator
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(6)
;
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create groups
var groups = svg.selectAll("g")
.data(dataset) // bind data to the group
.enter()
.append("g")
.attr("class", "bar") // give each 'g' a bar class
//
//Instead of positioning each rect and text element
//individually, now we position the entire *group*.
//Then the rects and gs just need to be nudged a bit
//in the right direction.
//
//For simplicity, the transform here is only being used
//for the x direction. Note the y value for all groups
//is zero.
//
.attr("transform", function(d, i) {
return "translate(" + xScale(i) + ",0)";
})
//
//Also, the mouseover/mouseout behavior is now on the
//group level, not on individual rects. This is so mousing
//over *anywhere* on the group (e.g., on the labels themselves)
//can trigger the highlight behavior.
//
.on("mouseover", function(d) {
d3.select(this)
.classed("highlight", true); //adding class dynamically makes it easier to adjust styles without many lines here
//Position the tooltip <div> and set its content
var x = d3.event.pageX;
var y = d3.event.pageY - 40;
d3.select("#tooltip")
.style("left", x + "px") //with tooltips define top left corner
.style("top", y + "px")
.style("opacity", 1)
.text(d);
//Note: No need for an anonymous function here,
//e.g. function(d) {…}, because the data value
//'d' we want here belongs to the <g> element
//on which mouseover was triggered, not the
//tooltip div (which has no data bound to it).
})
.on("mouseout", function() {
d3.select(this)
.classed("highlight", false); // no longer has class highlight
//Hide the tooltip - revert back to invisible
d3.select("#tooltip")
.style("opacity", 0);
});
//Add bar to each group
// initially starts at bottom of graph y=(h-padding), height=0
// also starts intitially at x=0- as defined above in transform,
// all bars start at their own 0.
// store initial info in rects so can then apply .transition() to rects
var rects = groups.append("rect")
.attr("x", 0)
.attr("y", function(d) {
return h - padding;
})
.attr("width", xScale.rangeBand())
.attr("height", 0)
.attr("fill", "#4400ff"); //initial color
//Add label to each group
groups.append("text")
.attr("x", xScale.rangeBand() / 2)
.attr("y", function(d) {
return yScale(d) + 14;
})
.text(function(d) {
return d;
})
//Transition rects into place
rects.transition()
.delay(function(d, i) { //kind of goes in order left to right
return i * 100;
})
.duration(1500)
.attr("y", function(d) {
return yScale(d);
})
.attr("height", function(d) {
return h - padding - yScale(d);
})
.filter(function(d) { //filter and if true do following
if (d > 20) {
return true;
}
return false;
})
.attr("fill", "#84eeff") //change fill if above is true- this is not a color that is designated by css - it is done by javascript
// add another class here by which can change hover only for high value highlighted?
.attr("class", "filtereddata") // adds class *only* to the rect part of filtered <g>
;
//Create y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)") //location y-axis
.attr("opacity", 0) //initially invisible
.call(yAxis)
.transition() //transitions in
.delay(2000)
.duration(1500)
.attr("opacity", 1.0);
</script>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js