This gist is to show how to integrate a raster image and a svg overlay to create images that show the parts of an object. In this case, I show the main parts of the bee anatomy.
The svg image was created with Inkscape. First, the raster image is inserted in the svg file to draw the shapes. Then, each path is given an id to allow its identification in the web version. For instance, the forewings, the lines and the corresponding text are given ids to allow its identification and assignment of a class in the page.
WIth D3, we use mouseover
and mouseout
to show and hide the elements of the same class that the selected element.
Thanks to Joost Witteveen for sharing the photo of the bee with cc Attribution license.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.active {
fill-opacity: 0.0;
stroke: #fff;
stroke-width: 1.5;
stroke-opacity: 0.75;
}
.hidden {
fill-opacity: 0.0;
stroke-opacity: 0.0;
}
text.label {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 14pt;
}
text.hidden {
fill-opacity: 0.0;
}
text.active {
fill: #fff;
fill-opacity: 1.0;
}
</style>
<body>
<div id="chart"></div>
</body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var img = {
width: 1024,
height: 684,
scale: 0.8
}
var div = d3.select('#chart'),
svg = div.append('svg');
svg
.attr('width', img.width * img.scale)
.attr('height', img.height * img.scale);
var grp = svg.append('g')
.attr('transform', 'scale(' + img.scale + ')');
grp.append('image')
.attr('xlink:href', 'bee.jpg')
.attr('width', img.width)
.attr('height', img.height);
d3.xml('anatomy.svg', 'image/svg+xml', function(error, xml) {
grp.node().appendChild(document.importNode(xml.documentElement, true));
grp.selectAll('path')
.each(function() {
// Remove any existing styles
d3.select(this)
.attr('style', '')
.classed('hidden', true)
.classed('active', false);
// Split the id in the '-', and store the first part in the _class attribute
var t = d3.select(this).attr('id').split('-');
if (t.length > 1) {
d3.select(this)
.attr('_class', t[0])
.classed(t[0], true);
}
});
grp.selectAll('text')
.each(function() {
// Get the content of the tspan element
var label = d3.select(this).select('tspan').node().textContent;
// Remove the syles and add the text
d3.select(this)
.attr('style', '')
.classed('hidden', true)
.classed('active', false)
.classed('label', true)
.text(label);
// Remove the tspan element
d3.select(this).select('tspan').remove();
var t = d3.select(this).attr('id').split('-');
if (t.length > 1) {
d3.select(this)
.attr('_class', t[0])
.classed(t[0], true);
}
});
grp.selectAll('path')
.on('mouseover', function() {
// Highlight the elements belonging to the class of the
// selected element
var _class = d3.select(this).attr('_class');
if (_class) {
grp.selectAll('.' + _class)
.classed('hidden', false)
.classed('active', true);
}
})
.on('mouseout', function() {
// Hide the elements with the same class of the
// mouseout element
var _class = d3.select(this).attr('_class');
if (_class) {
grp.selectAll('.' + _class)
.classed('hidden', true)
.classed('active', false);
}
});
});
</script>
</html>