【问题标题】:SVG patterns scaling the way pattern is not cut offSVG 模式缩放模式不被切断的方式
【发布时间】:2020-04-12 23:19:00
【问题描述】:

我正在尝试发现缩放 svg 模式的方法,以便该模式不会被使用它的元素的边界切割。然而,这种模式正在重复以覆盖该元素。

假设我有一个 20px 半径的圆作为图案。 将其应用于 80px 宽度的元素:

现在元素被缩放到 90px,图案应该水平拉伸(不需要保持纵横比):

最后,放大到 90 像素以上会增加另一个圆圈的出现(本示例中为 95 像素宽度 - 纵横比仍然被忽略):

我可以添加一些脚本来实现该效果。但我很好奇我是否可以使用纯 SVG 获得这种行为。

<svg style='display: block; height: 60px; width: 95px; '>
    <defs>
        <pattern patternUnits='userSpaceOnUse' viewBox='0 0 20 20' width='20'  height='20' id='the_pattern'>
            <circle cx='10' cy='10' r='10' stroke-width='0' fill='black'></circle>
        </pattern>
    </defs>

    <rect x='0' y='0' width='80' height='20' fill='url(#the_pattern)'></rect>
    <rect x='0' y='20' width='90' height='20' fill='url(#the_pattern)'></rect>
    <rect x='0' y='40' width='95' height='20' fill='url(#the_pattern)'></rect>

</svg>

【问题讨论】:

  • 你能发布你使用的svg元素吗?
  • 当然。为问题添加了一些基本代码。

标签: svg scaling


【解决方案1】:

答案是否定的。纯 SVG 无法实现这一点。除非“纯 SVG”包含嵌入了 Javascript 的 SVG(即 &lt;script&gt; 元素)。

不过,您可以使用 CSS border-image 来做到这一点。

https://developer.mozilla.org/en-US/docs/Web/CSS/border-image

这是一个例子:

忽略我在这里使用了钻石图像的事实。只需将其替换为边框图像文件的圆形版本即可。 :)

.circle-border {
  border-top: 30px solid;
  border-image: url('https://interactive-examples.mdn.mozilla.net/media/examples/border-diamonds.png') 30 / 20px 0 0 0;
  border-image-repeat: round;
}

div {
  width: 80px;
  height: 0px;
  margin-bottom: 50px;
}

div:nth-child(2) {
  width: 90px;
}

div:nth-child(3) {
  width: 100px;
}
<div class="circle-border"></div>
<div class="circle-border"></div>
<div class="circle-border"></div>

【讨论】:

  • 感谢您的回答。使用background-repeat: round 以SVG 作为背景图像实现了效果。
【解决方案2】:

想法

您在 2 遍中设置容器元素的尺寸。

通过 1:
将容器元素的宽度设置为这样的值,以使所需数量的模式元素恰好适合水平方向。前两种情况为 80,最后一种情况为 100。

通过 2: 将容器元素水平缩放到实际的目标宽度(80、90、95)。

在下面的代码示例中,transform 属性指定缩放。请注意,translate 动词在应用缩放之前首先将元素位置移动到原点,然后恢复翻译(`translate 属性内的动词从右到左评估)。

x 缩放因子是目标宽度和指定宽度的商,y 保持高度不变。

SVG 示例

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="8cm" height="4cm" viewBox="0 0 800 500" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
    <defs>
        <pattern id="circlePattern" patternUnits="userSpaceOnUse"
             x="0" y="0" width="20" height="20"
        >
            <circle cx="10" cy="10" r="10" fill="black" stroke="black" stroke-width="0"/>
        </pattern> 
    </defs>

    <!-- 1. base case 80 px width -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0"
           x="100" y="200" width="80" height="20"
    />

    <!-- 2. scale width to 90px -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0" 
           x="100" y="300" width="80" height="20"
           transform="translate(100, 300) scale (1.125, 1.0) translate(-100, -300)"
    />

    <!-- 3. scale width to 95px -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0" 
           x="100" y="400" width="100" height="20"
           transform="translate(100, 400) scale (0.95, 1.0) translate(-100, -400)"
    />
</svg>

内联示例

与问题有关的 SVG 部分与上述相同。

.showcase {
  /*  background-image: url('#glyph');
    background-size:100% 100%;*/
    filter: url(#embedded);
}
.showcase:before {
   display:block;
   content:'';
   color:transparent;
}
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
   "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="embedded" width="16cm" height="8cm" viewBox="0 0 800 500" version="1.1"
    xmlns="http://www.w3.org/2000/svg"
>
    <defs>
        <pattern id="circlePattern" patternUnits="userSpaceOnUse"
            x="0" y="0" width="20" height="20"
        >
            <circle cx="10" cy="10" r="10" fill="black" stroke="black" stroke-width="0"/>
        </pattern> 
    </defs>

    <!-- 1. base case 80 px width -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0"
        x="100" y="200" width="80" height="20"
    />

    <!-- 2. scale width to 90px -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0" 
         x="100" y="300" width="80" height="20"
         transform="translate(100, 300) scale (1.125, 1.0) translate(-100, -300)"
    />

    <!-- 3. scale width to 95px -->
    <rect fill="url(#circlePattern)" stroke="white" stroke-width="0" 
         x="100" y="400" width="100" height="20"
         transform="translate(100, 400) scale (0.95, 1.0) translate(-100, -400)"
    />
</svg>
<div id="showcase"/>

【讨论】:

  • 不幸的是,这种方法毕竟需要脚本。伪代码: if(desiredWidth % patternWidth == 0 ){.. 保持宽度不变 } elseif(desiredWidth % patternWidth > patternWidth/2 ){.. 放大 }
  • 好的,我明白你的目标了。我不知道 svg 声明性语法来实现这一点,虽然