Is it possible to convert a raidal gradient expressed in objectBoundingBox coordinates to userSpaceOnUse coordinates?

大兔子大兔子 提交于 2021-02-10 14:46:28

问题


I have this radial gradient expressed in objectBoundingBox coordinates.

<svg width="300" height="300">
  <defs>
    <radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
                    cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="blue" />
      <stop offset="100%" stop-color="black" />
    </radialGradient>
  </defs>

  <rect fill="url(#MyGradient)" stroke="black" stroke-width="5"  
        x="50" y="100" width="200" height="100"/>
</svg>

Is it possible to convert it to userSpaceOnUse coordinates?

For this question it is same to assume that each radial gradient only applies to one shape, and that we know x, y, width, and height of said shape.

<svg width="300" height="300">
  <defs>
    <radialGradient id="MyGradient" gradientUnits="userSpaceOnUse"
                    cx="?" cy="?" r="?" fx="?" fy="?">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="blue" />
      <stop offset="100%" stop-color="black" />
    </radialGradient>
  </defs>

  <rect fill="url(#MyGradient)" stroke="black" stroke-width="5"  
        x="50" y="100" width="200" height="100"/>
</svg>

回答1:


First I would show how to do it if the rect you fill with the gradient is a square:

svg{border:solid; width:45vw}
<svg viewBox="0 0 300 300">
  <defs>
    <radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
                    cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="blue" />
      <stop offset="100%" stop-color="black" />
    </radialGradient>
  </defs>

  <rect fill="url(#MyGradient)" stroke="black" stroke-width="5"  
        x="50" y="100" width="200" height="200"/>
</svg>

<svg viewBox="0 0 300 300">
  <defs>
    <radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse"
                    cx="110" cy="180" r="60" fx="70" fy="140" >
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="blue" />
      <stop offset="100%" stop-color="black" />
    </radialGradient>
  </defs>

  <rect fill="url(#MyGradient1)" stroke="black" stroke-width="5"  
        x="50" y="100" width="200" height="200"/>
</svg>

In the case of `gradientUnits="userSpaceOnUse":

The bounding box of the rect to fill is:

bb:{x:50, y:100, width:200, height:200}

The calculated attributes for gradientUnits="userSpaceOnUse" are:

cx = bb.x + bb.width *.3 = 50 + 200 * .3 = 110
cy = bb.y + bb.height *.4 100 + 200*.4 = 180
r = bb.width*.3 = 200*.3 = 60
fx = bb.x + bb.width *.1 = 50 + 200 * .1 = 70
fy = bb.y + bb.height *.2 = 100 + 200 * .2 = 140

So you can use

<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse" cx="110" cy="180" r="60" fx="70" fy="140" >

When using objectBoundingBox the values of the attributes of the radialGradient are taking values between 0 and 1 or 0 and 100% of the filled box.

You can also use objectBoundingBox as a value for clipPathUnits. Please take a look at the folowing example.

There is this clipPath where the clipping path is a circle. If the clipped shape is a square the result is a circle. If the clipped shape is a rectangle the result is an ellipse meaning that the clipping path is stretched according to the aspect ratio of the clipped shape.

<svg viewBox="0 0 120 60"> 
  <defs>
  <clipPath id="clip" clipPathUnits="objectBoundingBox">
    <circle cx=".5" cy=".5" r=".45" />
  </clipPath> 
  </defs>
    <rect id="r"  x="5" y="5" width="50"  height="50" />
  <use xlink:href="#r" fill="gold" clip-path="url(#clip)" />
  
  <rect id="r1"  x="60" y="15" width="55"  height="30" />
  <use xlink:href="#r1" fill="gold" clip-path="url(#clip)" />
</svg>

The same is happening with the gradient. If the radial gradient with gradientUnits="objectBoundingBox" is used to fill a rectangle with a different width and height the result would be an elliptical gradient (as in your example). If you want to translate an elliptical gradient to gradientUnits="userSpaceOnUse" you would need a way to create a gradient with a different rx and ry. Unfortunately this is not posible.



来源:https://stackoverflow.com/questions/62816432/is-it-possible-to-convert-a-raidal-gradient-expressed-in-objectboundingbox-coord

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!