block by pnavarrc 6275777

Bee Anatomy

Full Screen

Bee Anatomy

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.

index.html

<!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>