Search code examples
jquerydrawinggeometryvector-graphicsgraphael

How do I change this Raphael drawn pie chart, so that the colors dont change


I'm trying to change this pie chart, so that when I click on a segment, the color of the different segments don't change. I see that the fill has a direct relationship with the shape of the segment, but I totally suck. Please help! You can see the pie chart in action here:

http://raphaeljs.com/growing-pie.html

function drawgrowingpie () {
    var r = Raphael("holder");

    r.customAttributes.segment = function (x, y, r, a1, a2) {
        var flag = (a2 - a1) > 180,
            clr = (a2 - a1) / 360;
        a1 = (a1 % 360) * Math.PI / 180;
        a2 = (a2 % 360) * Math.PI / 180;
        return {
            path: [["M", x, y], ["l", r * Math.cos(a1), r * Math.sin(a1)], ["A", r, r, 0, +flag, 1, x + r * Math.cos(a2), y + r * Math.sin(a2)], ["z"]],
            fill: "hsb(" + clr + ", .75, .8)"
        };
    };

    function animate(ms) {
        var start = 0,
            val;
        for (i = 0; i < ii; i++) {
            val = 360 / total * data[i];
            paths[i].animate({segment: [200, 200, 150, start, start += val]}, ms || 1500, "bounce");
            paths[i].angle = start - val / 2;
        }
    }

    var data = [24, 92, 24, 52, 78, 99, 82, 27],
        paths = r.set(),
        total,
        start,
        bg = r.circle(200, 200, 0).attr({stroke: "#fff", "stroke-width": 4});
    data = data.sort(function (a, b) { return b - a;});

    total = 0;
    for (var i = 0, ii = data.length; i < ii; i++) {
        total += data[i];
    }
    start = 0;
    for (i = 0; i < ii; i++) {
        var val = 360 / total * data[i];
        (function (i, val) {
            paths.push(r.path().attr({segment: [200, 200, 1, start, start + val], stroke: "#fff"}).click(function () {
                total += data[i];
                data[i] *= 2;
                animate();
            }));
        })(i, val);
        start += val;
    }
    bg.animate({r: 151}, 1000, "bounce");
    animate(1000);
};

Solution

  • Change

    return {
        // snip...
        fill: "hsb(" + clr + ", .75, .8)"
    };
    

    to something else, or remove the fill property entirely from the returned object.


    Here's a nudge in the right direction: instead of changing the color every time a slice is animated, the color is now passed to the segment function. This means that the two different callers (the initializer and the click handler) can control the color differently. The segment function is changed to not return any fill information if no clr (color) was passed to it. This means the color is unchanged by the click handler, since only the initialization code passes color information.

    Hopefully this makes sense to you.

    function drawgrowingpie() {
        var r = Raphael("holder");
                                                            // ↓↓↓ pass the color
        r.customAttributes.segment = function(x, y, r, a1, a2, clr) {
            var flag = (a2 - a1) > 180;
            a1 = (a1 % 360) * Math.PI / 180;
            a2 = (a2 % 360) * Math.PI / 180;
            var props = {
                path: [["M", x, y], ["l", r * Math.cos(a1), r * Math.sin(a1)], ["A", r, r, 0, +flag, 1, x + r * Math.cos(a2), y + r * Math.sin(a2)], ["z"]]
            };
    
            // only return fill properties if the color was passed
            if (clr) {
                props.fill = "hsb(" + clr + ", .75, .8)";
                console.log(clr);
            }
            return props;
        };
    
        function animate(ms) {
            var start = 0,
                val;
            for (i = 0; i < ii; i++) {
                val = 360 / total * data[i];
                paths[i].animate({
                    // notice that no color data is passed here...
                    segment: [200, 200, 150, start, start += val]
                }, ms || 1500, "bounce");
                paths[i].angle = start - val / 2;
            }
        }
    
        var data = [24, 92, 24, 52, 78, 99, 82, 27],
            paths = r.set(),
            total, start, bg = r.circle(200, 200, 0).attr({
                stroke: "#fff",
                "stroke-width": 4
            });
        data = data.sort(function(a, b) {
            return b - a;
        });
    
        total = 0;
        for (var i = 0, ii = data.length; i < ii; i++) {
            total += data[i];
        }
        start = 0;
        for (i = 0; i < ii; i++) {
            var val = 360 / total * data[i];
            (function(i, val) {
                paths.push(r.path().attr({
                    // ...but we do pass color data here      ↓↓↓↓  
                    segment: [200, 200, 1, start, start + val, val],
                    stroke: "#fff"
                }).click(function() {
                    total += data[i];
                    data[i] *= 2;
                    animate();
                }));
            })(i, val);
            start += val;
        }
        bg.animate({
            r: 151
        }, 1000, "bounce");
        animate(1000);
    }
    

    http://jsfiddle.net/mattball/xsfQj/