Search code examples
javascriptfabricjsradial-gradients

FabricJs - Radial gradient for pie pieces


As you see here: http://jsfiddle.net/Da7SP/60/ I have 64 pie pieces that I want to have a radial gradient from the middle out to the edge. (Live each piece will have different colors) but I don't succeed to create that effect.

Here is the code:

var canvas = window._canvas = new fabric.Canvas('c');

var x=300
, y=300
, totalGates=64
, start=0
, radius=200
, val = 360 / totalGates;

for (var i = 0; i < totalGates; i++) {
  createPath(x, y, radius, val*i, (val*i)+val);
}

function createPath (x, y, radius, startAngle, endAngle) {
    var flag = (endAngle - startAngle) > 180;
        startAngle = (startAngle % 360) * Math.PI / 180;
        endAngle = (endAngle % 360) * Math.PI / 180;

        var path = 'M '+x+' '+y+' l ' + radius * Math.cos(startAngle) + ' ' + radius * Math.sin(startAngle) + 
            ' A ' + radius + ' ' + radius + ' 0 ' + (+flag) + ' 1 ' + (x + radius * Math.cos(endAngle))+ ' ' + (y + radius * Math.sin(endAngle)) + ' z';
    var piePiece = new fabric.Path(path);
        piePiece.set({
         strokeWidth:0
     });

    piePiece.setGradient('fill', {
        type:'radial',
        x1: x,
        y1: y,
        //x2: x + radius * Math.cos(endAngle),
        //y2: y + radius * Math.sin(endAngle),
        r1: radius, 
        r2: 0,
        colorStops: {           
            0: '#000',
            1: '#fff',
        }
    });
    canvas.add(piePiece);
}

I thought that it would be enough to set x1 to x and y1 to y to define the coordinates for the middle and then the radius, (before when I used PathGroup that did the trick). but now when I add the Path to a Group or directly to the Canvas the gradient looks completely different.

So, how do I use the setGradient with a radial gradient so it is displayed as if the complete pie was a circle, it would go from the center to the edge

Update: I noticed that if I set x=0 and y=0 then the gradient get centered.

Update2: If both x1 and y2 is set to 0 the gradient is drawn from the top left corner, this makes the gradient looks good in the 90 degree bottom - right corner: http://jsfiddle.net/Da7SP/61/

Update3: I solved it! Here http://jsfiddle.net/Da7SP/64/ is the Fiddle for you who has the same problem and below you see the result and the code.

This made the trick:

x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,

Here is the expected result:

Expected result

Here is the code

var canvas = window._canvas = new fabric.Canvas('c');

var x=300
, y=300
, totalGates=64
, start=0
, radius=200
, val = 360 / totalGates;

            /* Loops through each gate and prints selected options */
for (var i = 0; i < totalGates; i++) {
  createPath(x, y, radius, val*i, (val*i)+val, i);
}

function createPath (x, y, radius, startAngle, endAngle,i ) {
var flag = (endAngle - startAngle) > 180;
        startAngle = (startAngle % 360) * Math.PI / 180;
        endAngle = (endAngle % 360) * Math.PI / 180;

        var path = 'M '+x+' '+y+' l ' + radius * Math.cos(startAngle) + ' ' + radius * Math.sin(startAngle) + 
            ' A ' + radius + ' ' + radius + ' 0 ' + (+flag) + ' 1 ' + (x + radius * Math.cos(endAngle))+ ' ' + (y + radius * Math.sin(endAngle)) + ' z';
        var piePiece = new fabric.Path(path);
    piePiece.set({
    strokeWidth:0
    });

        piePiece.setGradient('fill', {
            type:'radial',
            x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
            y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
            x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
            y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
            r1: radius, 
            r2: 0,
            colorStops: {           
                0: '#000',
                1: '#f0f',
            }
        });
    canvas.add(piePiece);
}

Solution

  • Here is the code that was missing:

       piePiece.setGradient('fill', {
            type:'radial',
            x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
            y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
            x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
            y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
            r1: radius, 
            r2: 0,
            colorStops: {           
                0: '#000',
                1: '#f0f',
            }
        });