How to draw conic gradient?

Hi !

Does anyone know how to achieve this kind of gradient ? (the gradient part, not the mask part)



Thanks !

Add a gradient to the graphics state and draw?

For your gradient use the isRadial=true and follow the api-docs...


Hi Daniel, thanks for helping :)

I dont want a radial gradient,  I want a linear one, but with a circular shape.


I want this:

not this:


Right, radial != radial. Sorry, my fault... Interesting question though...

Yes ... seems tricky even in an SVG file :/

It doesn't look like JUCE has anything for Conical Gradients.  You might be able to find something on the Web on how you can make one, or how to make something like a color wheel if that's what you're after. 

The only way I can think of doing it in JUCE is by brute force. Convert the X,Y coordinates to radians and in a loop create small gradients and draw the shape piece by piece.


"Conic Gradient", thats the keyword I was missing, thanks !

I'll try to derive a ColourConicalGradient class from ColourGradient, thanks everyone !

This thread just came up.

You might be able to use it to implement what you're wanting, if it's still working. Take a look at the "angle gradient" in that post. It looks like a conical gradient to me.

If you look at the GradientOverlay image, it's doing pretty much exactly what you're wanting.

Bumping a very old thread, does anyone have a modern way to do that?

I’ve got some code somewhere that does this.
I’ll try and dig it out tomorrow.


Here you go. It’s not the fastest implementation as it uses an intermediate image and fills every pixel but should work ok:

/** Fills and angle gradient.
    The gradient will start at -Pi radians (or 90 degrees to the left) and continue all the way round.
inline void fillAngleGradient (Graphics& g, const ColourGradient& cg, Rectangle<int> bounds)
    Image img (Image::ARGB, bounds.getWidth(), bounds.getHeight(), false);
    const Image::BitmapData destData (img, Image::BitmapData::writeOnly);

    const float cx = (float) bounds.getCentreX();
    const float cy = (float) bounds.getCentreY();

    const float scale = (1.0f / (2.0f * MathConstants<float>::pi));

    HeapBlock<PixelARGB> lookup;
    const int numEntries = cg.createLookupTable (AffineTransform(), lookup);

    for (int y = 0; y < bounds.getHeight(); ++y)
        for (int x = 0; x < bounds.getWidth(); ++x)
            const float angleRadians = FastMathApproximations::atan2 (bounds.getY() + y - cy, bounds.getX() + x - cx);
            const float a = scale * (angleRadians + MathConstants<float>::pi);
            const int index = roundToInt (a * (numEntries - 1));
            jassert (isPositiveAndNotGreaterThan (a, 1.0f));
            jassert (isPositiveAndBelow (index, numEntries));

            destData.setPixelColour (x, y, lookup[index]);

    g.drawImageAt (img, bounds.getX(), bounds.getY());

I’ve created a pull request to add a conical gradient pattern to the ColourGradient class:

Here’s an example…

…from the following code:

void MainComponent::paint (juce::Graphics& g)
    const auto centre = getLocalBounds().toFloat().getCentre();
    const auto pi = juce::MathConstants<float>::pi;

    juce::ColourGradient gradient (juce::Colours::purple, centre,
                                   juce::Colours::yellow, centre.withY (centre.y + 100.f),
                                   false, // We don't want a radial pattern
                                   true); // We DO want a conical pattern
    gradient.addColour (0.125, juce::Colours::purple);
    gradient.addColour (0.875, juce::Colours::yellow);
    g.setGradientFill (gradient);

    juce::Path p;
    p.addCentredArc (centre.x, centre.y, 100.f, 100.f, 0.f, -pi * 0.75f, pi * 0.75f, true);
    g.strokePath (p, juce::PathStrokeType (50.f));

maybe the bool should be an enum to tell which gradient to use (linear, radial, conic) so it would be maybe more future proof (mirror, diamond, …)?

That makes it two votes:

That’s why cross posting isn’t great… :-/

The nice way would have been a new thread that you still can link from several places. But sparking a discussion in multiple places is meh…