【问题标题】:Make svg pattern content overflow from the frame of <pattern>, rather than being cut off使svg pattern内容从<pattern>的frame溢出,而不是被截断
【发布时间】:2023-02-02 07:40:59
【问题描述】:

我创建了一个带有图标的图案。用户可以拖动滑块来旋转图案的图标。这是我的代码:

const slider = document.getElementById("slider")

const carrotIcon = document.getElementById("carrotIcon")

slider.oninput = function(){ 

  carrotIcon.setAttribute('transform', 'rotate('+slider.value+' 25 25) translate(0 0)')
}
<svg width="200px" height="150px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  
  
  <symbol id="carrot" viewBox="0 0 50 50">
        <rect width="50" height="50" fill="none" stroke="black" stroke-width="1"/>
    <path d="M30 13c-1-3-5-4-7-2h-1l1-11h-3l-1 9-4-7-3 1 5 8-8-4-1 2 9 5h-1c-2 2-3 5-2 7l2 2 5-3 1 2-5 3 8 9 5-3 2 2-5 3 12 14 3-2-8-25-5 3-1-2 5-3-3-8z" />

  </symbol>
  
  <pattern id="myPat" patternUnits="userSpaceOnUse" width="50" height="50" patternTransform="rotate(0)">
    <use id="carrotIcon" xlink:href="#carrot" width="50" height="50" fill="orange" transform="rotate(0 25 25) translate(0 0)"></use>
  </pattern>
  
  <rect x="0px" y="0px" width="300px" height="200px" fill="url(#myPat)"> </rect>
</svg>


<p style=font-size:15px>Rotate Icons </p>
<input id="slider" type="range" min="0" max="360" value="0" step='1' >

可以注意到当你旋转的时候,pattern的内容会被&lt;pattern&gt;的frame截掉,因为在某些维度上pattern的内容比pattern的frame要大。

希望旋转时图案的内容能从图案中溢出。它们可以相互重叠。这是预期结果的图表:

你知道如何实现吗?

2023 年 2 月 2 日更新:

我用比&lt;pattern&gt; 更大的图标尝试了@ccprog 的解决方案。 我把&lt;pattern&gt;的宽高设置为50,&lt;use&gt;的宽高设置为70,那么图标还是会被切掉。

这是我的代码:

const slider = document.getElementById("slider")

const carrotIcon = document.getElementById("carrotIcon")

slider.oninput = function(){ 

  carrotIcon.setAttribute('transform', 'rotate('+slider.value+' 25 25) translate(0 0)')
}
<svg width="200px" height="150px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  
  
  <symbol id="carrot" viewBox="0 0 50 50" overflow="visible">
     <g id="carrotIcon">
        <path d="M30 13c-1-3-5-4-7-2h-1l1-11h-3l-1 9-4-7-3 1 5 8-8-4-1 2 9 5h-1c-2 2-3 5-2 7l2 2 5-3 1 2-5 3 8 9 5-3 2 2-5 3 12 14 3-2-8-25-5 3-1-2 5-3-3-8z" />
     </g>
  </symbol>
  
  <pattern id="myPat" patternUnits="userSpaceOnUse" width="50" height="50" style="overflow:visible">
    <use xlink:href="#carrot" width="70" height="70" fill="orange"></use>
    <use xlink:href="#carrot" x="-50" width="70" height="70" fill="orange"></use>
    <use xlink:href="#carrot" x="50" width="70" height="70" fill="orange"></use>
    <use xlink:href="#carrot" y="-50" width="70" height="70" fill="orange"></use>
    <use xlink:href="#carrot" y="50" width="70" height="70" fill="orange"></use>
  </pattern>
  
  <rect x="0px" y="0px" width="300px" height="200px" fill="url(#myPat)" overflow="visible"> </rect>
</svg>


<p style=font-size:15px>Rotate Icons </p>
<input id="slider" type="range" min="0" max="360" value="0" step='1' >

图标的截断:

【问题讨论】:

  • 感谢您的 cmets,但这并不能解决我的问题。作者在这个视频中使用patternTransform属性旋转了整个&lt;pattern&gt;。但是,我只想旋转&lt;pattern&gt;里面的元素,我想知道如何让这些元素不被&lt;pattern&gt;的frame截断。

标签: css svg


【解决方案1】:

理论上,这应该通过在&lt;pattern&gt; 元素中添加一个overflow="visible" 来解决。不幸的是,您遇到了浏览器实现冲突的未解决问题。

SVG 2 规范says this

SVG 的用户代理样式表将 pattern 元素的溢出属性设置为,这会导致在图案拼贴的边界处创建一个矩形剪切路径。除非 overflow 属性被覆盖,否则图案内超出图案矩形的任何图形都将被剪裁...

请注意,如果溢出属性设置为可见的当前未定义模式边界外模式的渲染行为。未来版本的 SVG 可能需要显示溢出。鼓励 SVG 实现者呈现溢出,因为这是作者期望的行为......

2016 年关于此的公开 issue 解释说:

SVG 1 中未明确定义图案拼贴的可见溢出效果,导致无法互操作的实现...

这不是一个理论问题。我从作者那里得到抱怨和困惑,为什么在一种浏览器中按他们想要的方式工作的模式在另一种浏览器中不起作用。具体来说,当图案的重复元素不适合整齐的矩形拼贴时,就会出现问题。

这是最近的示例屏幕截图。上图来自 Firefox,尽管有溢出值,但显示了对图案拼贴的裁剪,下图来自 Chrome...

我目前对作者的最佳建议是使用 &lt;use&gt; 元素创建足够的重复以完全填充矩形图块。但这远非理想。不仅是杂乱重复的代码,还开启了渲染中边缘效果的可能性(显露图案瓷砖的边缘)。

从那以后,什么都没有发生:

boggydigital 于 2018 年 6 月 11 日将此添加到 SVG 2.1 工作草案里程碑

因此,您不得不在 &lt;pattern&gt; 中输入多个 &lt;use&gt; 元素。每个人都需要围绕自己的旋转中心旋转。最好的解决方案是旋转 &lt;symbol&gt; 的内容 - 然后需要它自己的 overflow="visible" 才能工作。

const slider = document.getElementById("slider")

const carrotIcon = document.getElementById("carrotIcon")

slider.oninput = function(){ 

  carrotIcon.setAttribute('transform', 'rotate('+slider.value+' 25 25) translate(0 0)')
}
<svg width="200px" height="150px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  
  
  <symbol id="carrot" viewBox="0 0 50 50" overflow="visible">
     <g id="carrotIcon">
        <rect width="50" height="50" fill="none" stroke="black" stroke-width="1"/>
        <path d="M30 13c-1-3-5-4-7-2h-1l1-11h-3l-1 9-4-7-3 1 5 8-8-4-1 2 9 5h-1c-2 2-3 5-2 7l2 2 5-3 1 2-5 3 8 9 5-3 2 2-5 3 12 14 3-2-8-25-5 3-1-2 5-3-3-8z" />
     </g>
  </symbol>
  
  <pattern id="myPat" patternUnits="userSpaceOnUse" width="50" height="50" style="overflow:visible">
    <use xlink:href="#carrot" width="50" height="50" fill="orange"></use>
    <use xlink:href="#carrot" x="-50" width="50" height="50" fill="orange"></use>
    <use xlink:href="#carrot" x="50" width="50" height="50" fill="orange"></use>
    <use xlink:href="#carrot" y="-50" width="50" height="50" fill="orange"></use>
    <use xlink:href="#carrot" y="50" width="50" height="50" fill="orange"></use>
  </pattern>
  
  <rect x="0px" y="0px" width="300px" height="200px" fill="url(#myPat)" overflow="visible"> </rect>
</svg>


<p style=font-size:15px>Rotate Icons </p>
<input id="slider" type="range" min="0" max="360" value="0" step='1' >

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-03
    • 2012-06-02
    • 2017-03-23
    • 1970-01-01
    • 2020-10-07
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多