【问题标题】:Can I draw a SVG shape in objectBoundingBox units?我可以在 objectBoundingBox 单位中绘制 SVG 形状吗?
【发布时间】:2016-10-12 19:27:10
【问题描述】:

嗨,

我用 SVG 制作了这个形状:

<svg xmlns="http://www.w3.org/2000/svg" height="280" width="130">
 <defs>
  <clipPath id="buscar" clipPathUnits="objectBoundingBox">
   <polygon points="0.08,0 0.08,0.07 0.14,0.12 0.14,0.96 0.92,0.964 0.97,0.923 0.97,0.15 0.99,0.13 0.99,0"/>
  </clipPath>
 </defs> 
 <polygon points="10.2539,0.918692 10.2539,1.24946 9.92309,19.111 17.8616,31.6803 18.1923,269.669 119.077,270.165 125.858,259.746 125.692,42.9264 128.338,37.3033 128.338,0.918692 10.2539,0.918692" id="p2" style="fill:none; stroke-width: 1px;" stroke="#555555"/>
</svg>

两种形状完全相同,但剪辑路径中的坐标以 objectBoundingBox 为单位,我也想将它用于下面的多边形,这样我就可以对两者拥有完全相同的坐标。有可能吗?

我的目标是有一个剪裁的 div,当然,它被具有相同形状的边框包围。

谢谢。

【问题讨论】:

  • objectBoundingBox 单元用于剪辑路径、蒙版和过滤器。如果您正在创建其中之一,那么如果您愿意,您的形状坐标可以被解释为采用这样的单位。如果不是,那么 objectBoundingBox 单位是什么意思,什么对象的边界框?
  • 你的意思是我不能在这个例子中使用 objectBoundingBox 单位?
  • 你的问题基本上相当于“我可以在我的独角兽中使用灯具吗?”我不知道如何解释这样的问题。你说的单位是什么对象的边界框?
  • 我将 SVG 图像用作这样的背景: background:url("images/shape.svg") no-repeat 0 0 / 100% 100%;
  • 可爱,描述一下你想要达到的效果,以及它与你目前使用上述标记获得的效果有何不同。

标签: svg polygons


【解决方案1】:

正如罗伯特试图告诉你的那样,你的问题无法回答,因为它毫无意义。

objectBoundingBox 单位仅用于应用于其他元素的事物。例如:渐变、遮罩等。例如,您可以将渐变定义为相对于它所应用的元素,以便它“适合”其他元素的大小。

您不能在 objectBoundingBox 单位中定义独立的多边形,因为没有其他元素可以作为单位的基础。


您还不是很清楚您想要什么,但也许您的意思是给定一个图像和一个多边形,您想要转换该多边形,以便它以相对于该图像的 objectBoundingBox 单位定义?

如果这就是你的意思,那么答案就是没有简单的方法可以做到这一点。您可以采取的几种方法是:

  1. 给定图像宽度 W 和高度 H,手动遍历多边形并将所有 X 坐标除以 W 和 a;所有 Y 坐标除以 H。

    因此,如果图像是 300x400,那么多边形的第一个坐标将变为:

    (121.67/300), (271.958/400) 或 0.41,0.68

  2. 另一种方法是使用 SVG 编辑器并将图像和多边形一起缩小,使它们位于文档的左上角,从 0,0 到 100,100。然后,当您保存新的 SVG 时,所有多边形坐标都将在 0-100 范围内。然后,您可以将所有值除以 100 以获得您的 objectBoundingBox 坐标值。这有点乏味,但如果你有很多坐标要转换,它可以为你节省很多时间。


另一方面,如果您想为图像和剪切路径使用相同的多边形,那么您需要有一个viewBox"0 0 1 1"。例如:

<svg width="400px" height="400px" viewBox="0 0 1 1">
  <defs>
    <clipPath id="myclip" clipPathUnits="objectBoundingBox">
      <use xlink:href="#poly"/>
    </clipPath>
  </defs>

  <polygon id="poly" points="0.1 0.1 0.9 0.5 0.1 0.9"
           fill="none" stroke="red" stroke-width="0.02"/>

  <image xlink:href="http://placekitten.com/200/200" width="1" height="1"
         clip-path="url(#myclip)"/>
</svg>

请注意,这种方法存在一些限制。如果两者的纵横比不同,您可能会遇到一些对齐问题。

【讨论】:

  • 那为什么可以在clip-path中使用objectBoundingBox呢?我想做的很简单。我想将 SVG 图像用作页面上大小不同的 div 容器的背景。问题是我也将使用与剪辑路径相同的 SVG 图像,为了使其适合容器,我必须使用 objectBoundingBox 单元。但是我看不出为每个单位系统绘制两次相同的形状有什么意义。这就是为什么我想在两者中都使用 objectBoundingBox 单位。我想我再清楚不过了。
  • 因为 clipPath 就像渐变和蒙版 - 它应用于其他对象。您可以按照 Robert 的建议进行操作,并使用 "0 0 1 1" 的 viewBox。然后,您可以在 0->1 范围内定义所有坐标,并且可以使用相同的多边形来渲染图像作为 clipPath。但是,如果您需要图像和 clipPath 对齐,除非 SVG 是方形的或者您愿意让图像拉伸(通过设置 `preserveAspectRatio="none"),否则您可能会遇到麻烦。
  • 你的意思是我必须将当前坐标除以宽度和高度,然后声明一个 0 0 1 1 的 viewBox?
  • 我对您想要什么进行了另一个猜测,并在我的答案中添加了更多内容。
  • 是的,有点像。但是为什么图像在 SVG 标签内呢?在外部加载 SVG 作为 div 容器的背景怎么样?像:div {clip-path:url("images/shape.svg#poly");background:url("images/shape.svg") no-repeat 0 0 / 100% 100%;width:400px;height: 400 像素;}
【解决方案2】:

尝试使用 SVG feMorphology 过滤器来实现您想要的... https://stackoverflow.com/a/37930426/5776618

在您的示例中缩小/放大形状的方法将不起作用,因为您示例中的不规则形状会导致切角 - 您最终会得到一个不均匀的边框。

重申我在上面的链接答案中所说的话......

使用扩张过滤器的关键方面是:

  • 创建高度和宽度的匹配和形状
  • 用所需的形状路径/多边形剪辑两者
  • 使用过滤器扩大剪裁的矩形以制作边框

.clipper{
  clip-path: url(#clip_shape);
}
.dilate{
  filter: url("#dilate_shape");
}
<svg xmlns="http://www.w3.org/2000/svg" height="300" width="300">
 <defs>
  <clipPath id="clip_shape" clipPathUnits="objectBoundingBox">
    <polygon points="0.08,0 0.08,0.07 0.14,0.12 0.14,0.96 0.92,0.964 0.97,0.923 0.97,0.15 0.99,0.13 0.99,0"/>
  </clipPath>
   <filter id="dilate_shape">
      <feMorphology operator="dilate" in="SourceGraphic" radius="3" />
   </filter>
   
 </defs> 
 
 <g transform="translate(5,5)">
   <g class="dilate">
     <rect class="clipper" x=0 y=0 height="200px" width="200px" fill="lightgreen"></rect>
   </g>
   <image class="clipper" xlink:href="http://placekitten.com/200/200" height="200px" width="200px">
 </g>
</svg>

【讨论】:

  • 这很好,但如何将 svg 用作背景?
  • 它将与示例代码中的&lt;polygon&gt; 元素相同。 SVG 中的元素/形状是按照它们写入的顺序绘制的,因此如果您希望它位于背景中,请先放置它。之后的所有内容都将绘制在上面。如果我误解了您的问题,请随时澄清。试一试——这应该是一个很好的真实测试,看看它的行为是否符合您的要求。
  • 抱歉,我看不到如何将您的示例用作背景。我必须删除图像标签吗?
  • 我不确定您所说的“作为背景”是什么意思。至于删除图像标签,这个例子是说明性的,它展示了如何从元素中剪切形状并添加边框。您可能需要为您的情况调整一些东西,即。如果您不想剪辑图像,请将图像标签换成您要剪辑的内容。
  • 我的意思是这样的:div {clip-path:url("images/shape.svg#poly");background:url("images/shape.svg") no-repeat 0 0 / 100% 100%;宽度:400px;高度:400px;}
猜你喜欢
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
相关资源
最近更新 更多