SVG 图案以图案不被切断的方式缩放

SVG patterns scaling the way pattern is not cut off

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

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

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

最后,放大到 90px 以上会添加另一个圆圈(本例中宽度为 95px - 宽高比仍然被忽略):

我可以添加一些脚本来实现这种效果。但我很好奇我是否可以使用纯 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>

想法

您分 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"/>

答案是否定的。您无法使用纯 SVG 实现这一点。除非 "pure SVG" 包含嵌入了 Javascript(即 <script> 元素)的 SVG。

不过你可以用 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>