Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG linearGradient direction

Tags:

svg

I have a simple linearGradient inside a circle.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <linearGradient id="ct-svg-gradient" gradientTransform="rotate(65)">
    <stop offset="0%" stop-color="red" />
    <stop offset="100%" stop-color="yellow" />
  </linearGradient>

  <circle cx="100" cy="100" r="50" fill="url(#ct-svg-gradient)"/>
</svg>

As you can see I'm trying to rotate gradient by 65 degrees. At least, that's what docs claims it to be. I've tried to set this rotate to a bigger number and this will not give an expected result.

I understand that the problem with this one is that linearGradient doesn't have it's transform origin to the center. I guess, I'd have to use x1, y1, x2, y2 attributes for linearGradient, with no gradientTransform at all. If that's the case, what's the simplest way to get those four values if I have just angle I should rotate gradient to?

I'm interested in implementing such a function, my input is dynamic.

function convert(angle_in_degrees) { // or radians, I'll take care of conversion

  // the algorithm I'm interested in

  return {
    x1: ...,
    y1: ...,
    x2: ...,
    y2: ...,
  };
}

I'm thankful for any response or suggestion.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <linearGradient id="ct-svg-gradient" gradientTransform="rotate(150)">
    <stop offset="0%" stop-color="red" />
    <stop offset="100%" stop-color="yellow" />
  </linearGradient>
  <circle cx="100" cy="100" r="50" fill="url(#ct-svg-gradient)"/>
</svg>
like image 400
Andrei Glingeanu Avatar asked Aug 22 '26 16:08

Andrei Glingeanu


1 Answers

It's not quite as simple as that. in order for your gradient to fill the object from edge to edge, you would need to pass in the element as well and take into account its bounding box.

If you only need to worry about circles, then it would be simpler to apply an axis aligned gradient and rotate the circle.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <linearGradient id="ct-svg-gradient">
    <stop offset="0%" stop-color="red" />
    <stop offset="100%" stop-color="yellow" />
  </linearGradient>
  <circle cx="100" cy="100" r="50" fill="url(#ct-svg-gradient)" transform="rotate(150,100,100)"/>
</svg>

Update

Here's a simple JS function that does what you want. It won't always give the best results, but it should be easy to understand.

function setGradientAngle(elementId, gradientId, angle)
{
  // Convert angle to radians
  angle = angle * Math.PI / 180;
  // Get element bounding box
  var bbox = document.getElementById(elementId).getBBox();
  // Calculate centre of rotation
  var cx = bbox.x + bbox.width/2;
  var cy = bbox.y + bbox.height/2;
  // Minimum radius we need, to guarantee that gradient stretches the full width
  // This calculation could be cleverer. We are just doing worst case here for simplicity.
  var radius = Math.sqrt(bbox.width*bbox.width+bbox.height*bbox.height)/2;
  // Calculate vector from centre to gradient coords
  var rx = Math.cos(angle) * radius;
  var ry = Math.sin(angle) * radius;
  // Update the gradient coords
  var grad = document.getElementById(gradientId);
  grad.setAttribute("gradientUnits", "userSpaceOnUse");
  grad.setAttribute("x1", cx - rx);
  grad.setAttribute("y1", cy + ry);
  grad.setAttribute("x2", cx + rx);
  grad.setAttribute("y2", cy - ry);
}

setGradientAngle("mypath", "ct-svg-gradient", 150);
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
  <linearGradient id="ct-svg-gradient">
    <stop offset="0%" stop-color="red" />
    <stop offset="100%" stop-color="yellow" />
  </linearGradient>
  <path id="mypath" fill="url(#ct-svg-gradient)" vector-effect="non-scaling-stroke" d="M116.48,288.71a582.68,582.68,0,0,0-69.84-40.32q-36.32-17.74-33.52-58.06a582.72,582.72,0,0,0,0-80.65Q10.32,69.35,46.64,51.61a582.68,582.68,0,0,0,69.84-40.32q33.52-22.58,67,0a582.67,582.67,0,0,0,69.84,40.32q36.32,17.74,33.52,58.06a582.65,582.65,0,0,0,0,80.65q2.79,40.32-33.52,58.06a582.67,582.67,0,0,0-69.84,40.32Q150,311.29,116.48,288.71Z"/>
</svg>
like image 144
Paul LeBeau Avatar answered Aug 26 '26 22:08

Paul LeBeau



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!