Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get color of svg linearGradient at specific position

I have a linear gradient that is used as percentage bar with a small ellipse that moves along the bar to show the current completion percentage. The completion percentage is updated via an AngularJS binding that calls a function.

I need to change the color of the ellipse depending on the color of the gradient bar in the current position. Let'say the percentage is 80%, I need to get the color of the gradient at the 80% position.

Is that possible?

<svg height="20px" width="100%">
<defs>
    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
        <stop offset="50%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
        <stop offset="100%" style="stop-color:rgb(79,189,0);stop-opacity:1" />
    </linearGradient>
</defs>
<rect width="100%" height="3px" y="50%" fill="url(#gradient)" style="stroke-width:0" />
<rect width="30px" height="20px" x="{{calculateProfilePercentage()}}%" rx="8" ry="8" fill="rgb(249,166,31)" style="stroke-width:0" />
</svg>
like image 210
Pankas Avatar asked Oct 21 '25 20:10

Pankas


1 Answers

AFAIK you cannot read a value off from a gradient as the gradient object do not expose methods to do so.

You can however create an off-screen canvas, draw a gradient and read the pixel value from there.

For example, lets create an object GradientReader. This allows us to instantiate it and embed methods and so forth:

function GradientReader(colorStops) {

    const canvas = document.createElement('canvas');   // create canvas element
    const ctx = canvas.getContext('2d');               // get context
    const gr = ctx.createLinearGradient(0, 0, 101, 0); // create a gradient
    
    canvas.width = 101;                                // 101 pixels incl.
    canvas.height = 1;                                 // as the gradient

    for (const { stop, color } of colorStops) {               // add color stops
        gr.addColorStop(stop, color);
    }
    
    ctx.fillStyle = gr;                                // set as fill style
    ctx.fillRect(0, 0, 101, 1);                        // draw a single line
    
    // method to get color of gradient at % position [0, 100]
    return {
        getColor: (pst) => ctx.getImageData(pst|0, 0, 1, 1).data
    };
}

Now we can setup the object with the color stops.

const gr = new GradientReader([{stop: 0.0, color: '#f00'},
                               {stop: 0.5, color: '#ff0'},
                               {stop: 1.0, color: 'rgb(79,189,0)'}]);

We now have an object which mimics the gradient and all we need to do now is to call its method getColor() with a percentage value:

const col = gr.getColor(pst);
el.style.backgroundColor = `rgb(${col[0]}, ${col[1]}, ${col[2]})`;

FIDDLE

Modify to your liking/needs.

Hope this helps!


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!