我需要创建几个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;
答案 0 :(得分:1)
这是我的示例代码,但它有点棘手(使用模式和掩码和过滤器)。
<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;
所以我一步一步解释。
1)通过点图案填充找到&#34;击中区域&#34;(基本形状的绘画区域包括的图案形状的中心点)。
stroke-width
用于扩大基本形状。
<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;
2)通过过滤器使命中区域变胖。这是模式区域。
feConvolveMatrix
用于使框大小均匀。
10px(图案单元尺寸)= 1px(点尺寸)+ 4 * 2px(feMorphology)+ 1px(feConvolveMatrix)
<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;
3)最后,将rect
元素传播到所有svg区域,然后用图案形状填充它并用2)创建的图案区域掩盖它。
答案 1 :(得分:1)
这个答案现在对OP没有帮助。但无论如何我都会发布这篇文章,因为它可能对未来的读者有所帮助。
以下Javascript函数应该使用任何模式填充任何形状。它使用新的SVG2 SVGSVGElement.checkIntersection()
方法。
很遗憾,checkIntersection()
在任何浏览器中都无法正常使用。方法调用适用于Chrome,但它不能正确执行交叉测试。其他浏览器甚至没有实现该方法。
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;