Search code examples
google-chromesvgwebkitraphaelradial-gradients

Why does this combination of Raphael radiant fill coordinates fail?


Using Raphael, I noticed that if I tried to apply a radial fill on a circle using 0.9 and 0.2 as the radial focus points, it fails to draw the radial fill.

paper.circle(50,300,20).attr({"fill":"r(0.5,0.1)#f00-000"});
paper.circle(100,300,20).attr({"fill":"r(0.9,0.2)#f00-000"}); // <-- fails
paper.circle(150,300,20).attr({"fill":"r(0.9,0.3)#f00-000"}); 

I've set up a fiddle, here, and did a 10x10 grid, and the (0.9,0.2) is the only one that failed.

I'd like to understand why. http://jsfiddle.net/ENMry/2/


Solution

  • This is not problem of Raphael library but most probably of JS SVG rendering. You can repeat the same problem using just JavaScript and SVG markup without Raphael library. See example at jsBin

    I changed your example to have bigger circles with 11x11 grid (from 0.0 to 1.0) and put also one row separately on the top to show how is focus point moving. See example at jsBin.

    Using browser console (ctrl+shift+J in Chrome) you can inspect DOM elements. The following markup is set for our white element (the 2nd one in the first row):

    <radialGradient id="2r_0.1_0.2__f00-_000" fx="0.1" fy="0.2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
        <stop offset="0%" stop-color="#ff0000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></stop>
        <stop offset="100%" stop-color="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></stop>
    </radialGradient>
    
    <circle cx="175" cy="50" r="30" fill="url(#2r_0.1_0.2__f00-_000)" stroke="#000" opacity="1" fill-opacity="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); opacity: 1; fill-opacity: 1;">
    </circle>
    

    This MDN Gradients tutorial explains how radial gradient works.

    If I understand correctly radial gradient is defined with 5 data and stop markup:

    • where is point of radiation: for example cx="0.25" cy="0.25" r="0.25". They define position and where the gradient ends. If not set cx and cy are in the midle of the element (same as value 0.5 or 50%; cx=0, cy=0 means top-left), r is 1 or 100%. In our case radiation starts in the middle of the circle and ends on its edge.
    • stop markup defines which colors should be at certain position.
    • where is focal (focus) point: in our case fx="0.1" fy="0.2". Standard says: fx and fy define the focal point for the radial gradient. The gradient will be drawn such that the 0% gradient stop is mapped to (fx, fy).

    If you imagine a rectange around the circle, fx="0.1" fy="0.2" is somewhere to the left upper corner. This tutorial says: If the focal point is moved outside the circle described earlier, its impossible for the gradient to be rendered correctly, so the spot will be assumed to be on the edge of the circle. If the focal point isn't given at all, its assumed to be at the same place as the center point.

    The first circle in the top row has fx="0.0" fy="0.2" and is out of radiation circle. So the spot is set on the edge: left, middle.

    The "problematic" white circle has fx="0.1" fy="0.2" and this point is exactly on the edge of (radiation) circle. And rendering somehow fails. The same is for fx="0.9" fy="0.2", fx="0.2" fy="0.1" and fx="0.2" fy="0.9".

    Following the same logic we should have another 4 white circles:

    fx="0.8" fy="0.1"
    fx="0.8" fy="0.9"
    fx="0.1" fy="0.8"
    fx="0.9" fy="0.8"
    

    but they are rendered correctly.

    You can easily see all those "problematic" points if you draw a circle and a grid.

    So, I do not know if this is some rounding problem or something else. Anyway, it could be a bug. I found one connected with radial rendering but it is not exactly the same.

    BTW, FireFox and IE10 render it without problem.

    Note: I submit an issue 322487