Source: glyphchart.js


var Chart = {};

/**
 * Creates a Glyph chart element
 *
 * @returns {chart}
 */
Chart.rose = function () {
    var margin = {'top': 1, 'right': 1, 'bottom': 1, 'left': 1},
        height = 0,
        width = 0,
        centerX = 0,
        centerY = 0,
        area = function (d) { return [d.y]; }, //y-achse = länge
        angle = function (d) { return d.x; }, // x-achse = index
        radiusScale = d3.scaleLinear(),
        angleScale = d3.scaleLinear().range([Math.PI, 3 * Math.PI]),
        domain = [0, 1],
        legend = [''],
        label = function (d) {return d.label; },
        canvas, graph, centerX, centerY, numWedges, wedgeGroups,
        wedges, legendGroup;

    // Arc Generator:
    var arc = d3.arc()
        .innerRadius(0)
        .outerRadius(function (d, i) { return radiusScale(d.radius); })
        .startAngle(function (d, i) { return angleScale(d.angle); });

    /**
     * Creates the chart element
     *
     * @param selection
     */
    function chart(selection) {
        selection.each(function (data) {
            // Determine the number of wedges:
            numWedges = data.length;

            // Standardize the data:
            data = formatData(data);

            // Update the chart parameters:
            updateParams();

            // Create the chart base:
            canvas = d3.select(this).append('svg')
                .attr('width', width)
                .attr('height', height)
                .attr('class', 'canvas');

            // Create the graph element:
            graph = canvas.append('g')
                .attr('class', 'graph')
                .attr('transform', 'translate(' + (centerX + margin.left/2) + ','
                    + (centerY + margin.top/2) + ')');

            // Create the wedges:
            createWedges(data);
        });
    };

    /**
     * Format and calculate the needed data for each arc
     *
     * @param data datapoint with the set parameters
     * @returns mapped data
     */
    function formatData(data) {
        // Convert data to standard representation; needed for
        // non-deterministic accessors:

        glyphData = data.map(function (d, i) {
            return {
                'score': d.score,
                'color': d.c,
                'label': label.call(data, d, i),
                'angle': angle.call(data, d, i),
                'area': area.call(data, d, i)
            };
        });

        // Now convert the area values to radii:
        // http://understandinguncertainty.org/node/214
        return glyphData.map(function (d, i) {
            return {
                'score': d.score,
                'color': d.color,
                'label': d.label,
                'angle': d.angle,
                'radius': d.area.map(function (area) {
                    return Math.sqrt(area * numWedges / Math.PI);
                })
            }
        })
    };

    /**
     * Set angle and radius for each arc of the chart
     */
    function updateParams() {
        // Update the arc generator:
        arc.endAngle(function (d, i) {
            return angleScale(d.angle) + (Math.PI / (numWedges / 2));
        });

        // Update the radius scale:
        radiusScale.domain(domain)
            .range([0, d3.min([centerX/2, centerY/2])]);

        // Update the angle scale:
        angleScale.domain([0, numWedges]);
    };

    /**
     * Create wedge groups and wedges for each attribute
     *
     * @param data formatted data
     */
    function createWedges(data) {
        // Create the wedge groups:
        wedgeGroups = graph.selectAll('.wedgeGroup')
            .data(data)
            .enter().append('svg:g')
            .attr('class', 'wedgeGroup')
            .attr('transform', 'scale(0, 0)')
        // create a tooltip

        var Tooltip = d3.select('.glyphs')
            .append("div")
            .style("opacity", 0)
            .attr("class", "tooltip")

        wedgeGroups
            .on('mouseover', function(d, i) {
                Tooltip
                    .style("opacity", 1)
            })
            .on('mousemove', function(d, i){
                Tooltip
                    .html('name: ' + d.label + '<br> Dominating Score: ' + d.score)
                    .style("left", d3.mouse(this)[0] + "px")
                    .style("top", d3.mouse(this)[1] + "px")
            })
            .on('mouseout', () => {
                Tooltip
                    .style("opacity", 0)
            });

        // Create the wedges:
        wedges = wedgeGroups.selectAll('.wedge')
            .data(function (d) {
                var ids = d3.range(0, legend.length);

                ids.sort(function (a, b) { return d.radius[b] - d.radius[a]; });

                return ids.map(function (i) {
                    return {
                        'color': d.color,
                        'legend': legend[i],
                        'radius': d.radius[i],
                        'angle': d.angle
                    };
                });
            })
            .enter().append('svg:path')
            .attr('class', function (d) { return 'wedge ' + d.legend; })
            .attr('d', arc )
            .attr('fill', function(d){return d.color});

        // Transition the wedges to view:
        wedgeGroups.transition()
            .attr('transform', 'scale(1, 1)');
    };

    // Set/Get: margin
    chart.margin = function (_) {
        if (!arguments.length) {
            return margin;
        }

        margin = _;
        return chart;
    };

    // Set/Get: width
    chart.width = function (_) {
        if (!arguments.length) {
            return width;
        }

        width = _;
        return chart;
    };

    // Set/Get: height
    chart.height = function (_) {
        if (!arguments.length) {
            return height;
        }

        height = _;
        return chart;
    };

    // Set/Get: area
    chart.area = function (_) {
        if (!arguments.length) {
            return area;
        }

        area = _;
        return chart;
    };

    // Set/Get: angle
    chart.angle = function (_) {
        if (!arguments.length) {
            return angle;
        }

        angle = _;
        return chart;
    };

    // Set/Get: label
    chart.label = function (_) {
        if (!arguments.length) {
            return label;
        }

        label = _;
        return chart;
    };

    // Set/Get: domain
    chart.domain = function (_) {
        if (!arguments.length) {
            return domain;
        }

        domain = _;
        return chart;
    };

    // Set/Get: legend
    chart.legend = function (_) {
        if (!arguments.length) {
            return legend;
        }

        legend = _;
        return chart;
    };

    // Set/Get: centerX
    chart.centerX = function (_) {
        if (!arguments.length) {
            return centerX;
        }

        centerX = _;
        return chart;
    };

    // Set/Get: centerY
    chart.centerY = function (_) {
        if (!arguments.length) {
            return centerY;
        }

        centerY = _;
        return chart;
    };

    return chart;

};