用其他元素填充SVG形状而不在边界处剪切它们的最佳方法是?

时间:2017-10-01 18:09:56

标签: svg overflow

我需要创建几个SVG形状(如圆形或多边形),并用一些SVG元素填充它们中的每一个。

实现此目的的一种方法是定义形状并使用fill属性应用模式(参见下面的代码段)。但是,内部SVG元素被外部形状的边界剪切(三角形被圆圈剪切)。

我想找到一种隐藏所有不与圆相交的三角形的方法,并保留在边界处溢出的三角形。

请注意,计算元素是否与圆相交在Javascript中非常容易,但我需要创建具有复杂边界的形状,例如多边形。



<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/pattern -->

<svg width="120" height="120" viewBox="0 0 120 120"
    xmlns="http://www.w3.org/2000/svg">

  <defs>
    <pattern id="Triangle" width="10" height="10"
        patternUnits="userSpaceOnUse">
      <polygon points="5,0 10,10 0,10"/>
	</pattern>
  </defs>

  <circle cx="60" cy="60" r="50" fill="url(#Triangle)"/>
</svg>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

这是我的示例代码,但它有点棘手(使用模式和掩码和过滤器)。

&#13;
&#13;
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <!--common settings-->
  <defs>
    <!--pattern to detect shape area-->
    <pattern id="Dots" width="10" height="10"
        patternUnits="userSpaceOnUse">
      <rect x="4" y="4" width="1" height="1" fill="white"/>
    </pattern>
    <!--filter to find area in which pattern shapes must be painted-->
    <filter id="Range">
      <feMorphology radius="4" operator="dilate"/>
        <feComponentTransfer>
          <feFuncA type="linear" slope="255"/>
      </feComponentTransfer>
      <feConvolveMatrix order="2 2" kernelMatrix="1 1 1 1" divisor="1"/>
    </filter>
  </defs>
  
  <!--paint structure-->
  <defs>
    <!--base shape-->
    <circle id="Base" cx="60" cy="60" r="50"/>
    <!--pattern for filling-->
    <pattern id="Triangle" width="10" height="10"
        patternUnits="userSpaceOnUse">
      <polygon points="5,0 10,10 0,10"/>
    </pattern>
    <!--mask by paint area-->
    <mask id="Mask" maskUnits="userSpaceOnUse">
      <use xlink:href="#Base" fill="url(#Dots)" stroke="url(#Dots)" stroke-width="5" filter="url(#Range)"/>
    </mask>
  </defs>
  <use xlink:href="#Base" fill="none" stroke="red"/>
  <!--fill all screen by pattern and mask by paint area-->
  <rect fill="url(#Triangle)" width="100%" height="100%" mask="url(#Mask)"/> 
</svg>
&#13;
&#13;
&#13;

所以我一步一步解释。

1)通过点图案填充找到&#34;击中区域&#34;(基本形状的绘画区域包括的图案形状的中心点)。

stroke-width用于扩大基本形状。

&#13;
&#13;
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background-color:gray;">
  <!--common settings-->
  <defs>
    <!--pattern to detect shape area-->
    <pattern id="Dots" width="10" height="10"
        patternUnits="userSpaceOnUse">
      <rect x="4" y="4" width="1" height="1" fill="white"/>
    </pattern>
  </defs>
  
  <!--paint structure-->
  <defs>
    <!--base shape-->
    <circle id="Base" cx="60" cy="60" r="50"/>
  </defs>
  <use xlink:href="#Base" fill="none" stroke="red"/>
  <use xlink:href="#Base" fill="url(#Dots)" stroke="url(#Dots)" stroke-width="5"/>
</svg>
&#13;
&#13;
&#13;

2)通过过滤器使命中区域变胖。这是模式区域。

feConvolveMatrix用于使框大小均匀。

10px(图案单元尺寸)= 1px(点尺寸)+ 4 * 2px(feMorphology)+ 1px(feConvolveMatrix)

&#13;
&#13;
<svg width="120" height="120" viewBox="0 0 120 120"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background-color:gray;">
  <!--common settings-->
  <defs>
    <!--pattern to detect shape area-->
    <pattern id="Dots" width="10" height="10"
        patternUnits="userSpaceOnUse">
      <rect x="4" y="4" width="1" height="1" fill="white"/>
    </pattern>
    <!--filter to find area in which pattern shapes must be painted-->
    <filter id="Range">
      <feMorphology radius="4" operator="dilate"/>
        <feComponentTransfer>
          <feFuncA type="linear" slope="255"/>
      </feComponentTransfer>
      <feConvolveMatrix order="2 2" kernelMatrix="1 1 1 1" divisor="1"/>
    </filter>
  </defs>
  
  <!--paint structure-->
  <defs>
    <!--base shape-->
    <circle id="Base" cx="60" cy="60" r="50"/>
  </defs>
  <use xlink:href="#Base" fill="url(#Dots)" stroke="url(#Dots)" stroke-width="5" filter="url(#Range)"/>
  <use xlink:href="#Base" fill="none" stroke="red"/>
</svg>
&#13;
&#13;
&#13;

3)最后,将rect元素传播到所有svg区域,然后用图案形状填充它并用2)创建的图案区域掩盖它。

答案 1 :(得分:1)

这个答案现在对OP没有帮助。但无论如何我都会发布这篇文章,因为它可能对未来的读者有所帮助。

以下Javascript函数应该使用任何模式填充任何形状。它使用新的SVG2 SVGSVGElement.checkIntersection()方法。

很遗憾,checkIntersection()在任何浏览器中都无法正常使用。方法调用适用于Chrome,但它不能正确执行交叉测试。其他浏览器甚至没有实现该方法。

&#13;
&#13;
function fillShapeWithPattern(shapeId, patternId)
{
  var shape = document.getElementById(shapeId);
  var pattern = document.getElementById(patternId);
  var svg = shape.ownerSVGElement;

  var shapeBounds = shape.getBBox();
  var patternBounds = pattern.getBBox();
  
  if (patternBounds.width == 0 || patternBounds.height == 0)
    return;  // Avoid infinite loops

  // To simplify the intersection test, let's adjust the shape bounding
  // boxe so that we can pretend the pattern box is at (0,0).
  shapeBounds.x -= patternBounds.x;
  shapeBounds.y -= patternBounds.y;

  // An SVGRect object that we need for the intersection test
  var testRect = svg.createSVGRect();
  testRect.width = patternBounds.width;
  testRect.height = patternBounds.height;

  // Loop through a grid checking whether a rectangle representing
  // the bounding box of the pattern, intersect with the shape
  for (var y = shapeBounds.y;
           y < (shapeBounds.y + shapeBounds.height);
           y += patternBounds.height)
  {
    testRect.y = y + patternBounds.y;

    for (var x = shapeBounds.x;
             x < (shapeBounds.x + shapeBounds.width);
             x += patternBounds.width)
    {
      testRect.x = x + patternBounds.y;

      if (svg.checkIntersection(shape, testRect))
      {
        // Add a copy of the pattern shape to the SVG, by creating
        // a <use> element at the right coordinates
        var use = document.createElementNS(svg.namespaceURI, "use");
        use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#"+patternId);
        use.setAttribute("x", x);
        use.setAttribute("y", y);
        svg.appendChild(use);
      }
    }
  }
}


fillShapeWithPattern("shape", "pattern");
&#13;
<svg width="120" height="120" viewBox="0 0 120 120"
    xmlns="http://www.w3.org/2000/svg">

  <defs>
    <polygon id="pattern" points="5,0 10,10 0,10"/>
  </defs>

  <circle id="shape" cx="60" cy="60" r="50" fill="none" stroke="red"/>
</svg>
&#13;
&#13;
&#13;