I'm trying to find tools to render a group of overlapping shapes so that within the group the fill acts as opaque (so the overlapped circle outlines are not shown), but at the same time the fills of group members are transparent to any background layers underneath.
I hope this picture will make it clearer:
What I'm able to accomplish is a bunch of circles with empty fills (d in the image). What I would like to achieve (h in the image) is circle outlines being hidden in the overlaps so that the layering in the outlined circle group is clear, but the group as a whole having a transparent fill so that the background layer (blue-filled bubbles in the picture) is visible.
The perimeter of the circles in the group would be determined by data and possibly dynamic so I guess they need to be identifiable as separate objects, so I cannot turn them into some kind of compound path to get what I need.
From what I found, this cannot be done in SVG or CSS alone, so I wonder if there is some knock-out filter or any kind of solution within Pixi.js or general WebGL that would allow me to set a different transparency behaviour within the layer and different towards other layers.
Something like this perhaps.
You can add more circles as desired. The mask circles overlap each other but as a whole when applied to the rectangle the masked parts are transparent.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%" viewBox="0 0 200 200" >
<defs>
<mask id="circle-mask" width="1" height="1" maskContentUnits="objectBoundingBox" maskUnits="objectBoundingBox">
<circle cx="0.2" cy="0.2" r="0.1" stroke="white" stroke-width="0.01"/>
<circle cx="0.3" cy="0.3" r="0.1" stroke="white" stroke-width="0.01"/>
</mask>
</defs>
<circle cx="30" cy="60" r="20" fill="blue" fill-opacity="0.5"/>
<rect width="200" height="200" mask= "url(#circle-mask)" fill="blue"/>
</svg>
I'm looking for a way to use an inline SVG pattern that scales vertically and only repeats horizontally. Does anyone know if this is possible and if so how?
I know I can makes this just using a SVG as a background-image, but I want to be able to use this SVG in a javascript/component-based workflow so inline is the best fit for that.
Here is link with my work-in-progress: https://codepen.io/devotee/pen/GRJJpKL
And some code:
<div class="divider">
<svg width="100%" height="40px">
<defs>
<pattern id="pattern" x="0" y="0" width="60" height="6" patternUnits="userSpaceOnUse">
<path fill="none" stroke="#F5A861" d="M60 5C45 5 45 1 30 1S15 5 0 5"/>
</pattern>
</defs>
<rect x="10" y="6" width="100%" height="12" fill="url(#pattern)" />
</svg>
As you can see in the link, this repeats in both directions, so setting a bigger height value does not accomplish what I want. I would like this pattern to always fill the containers height (or simply be set to a value with CSS) but repeat horizontally.
Here are some images to illustrate what I mean:
Top is wanted behaviour, bottom is unwanted behaviour:
The background scales vertically and does not repeat. It takes as much space vertically as it can (fills parent height or whatever height value it has specified)
Top is wanted behaviour, bottom is unwanted behaviour:
It does not stretch the SVG horizontally but merely repeats it.
Any ideas or input on how to achieve this?
I have an svg which has multiple stroked paths, and a rectangle shape behind them that has the shape of the paths cut out of them. Effectively, the stroked paths should be "plugging the holes" in the rectangle shape.
The reason for this is that I would like to animate the paths so that they are erased, revealing what is underneath through the holes in the rectangle shape.
That's all well and good, and the animation works fine. The problem is that there is a hairline-thin space between the holes and the outside of the path strokes, so you can see what is underneath even while the paths are still there. You can see a screen capture of that here:
How do I avoid this happening? The space is not in the svg, because making it bigger on the page still has the space hairline thin:
I figure it has something to do with the aliasing, but have no idea how to combat it. I can't just apply a thicker stroke to the paths, because then the stroke starts to bleed into the other shapes, as seen here:
What else is there to do?
You could use a mask instead of a clip-path, since masks allow using the stroke to define the masked area.
<mask id="strokemask" maskContentUnits="objectBoundingBox"
x="0" y="0" width="100%" height="100%">
<circle cx="0.5" cy="0.5" r="0.1" stroke="white" fill="white"
stroke-width="0.02"/>
<circle cx="0.5" cy="0.5" r="0.15" stroke="white" fill="none"
stroke-width="0.03"/>
<circle cx="0.5" cy="0.5" r="0.22" stroke="white" fill="none"
stroke-width="0.05"/>
<circle cx="0.5" cy="0.5" r="0.3" stroke="white" fill="none"
stroke-width="0.06"/>
</mask>
Here's a live example of an animated mask that uses some stroked circles.
The SVG elements <line>, <circle>, <rect>, <text> and , <image> allow for positioning by x and y based off of the view port. Furthermore they can also be relatively positioned. Is there any way to accomplish this for <polygon> than to wrap it in an <svg>? The closest substitute for <polygon>, <path>, also has this... issue.
Based on the excellent comment by #Michael Mullany I was able to find a solution to the issue. By putting the polygon or path in side a <defs> tag it can be used later on in a <use> tag. The <use> tag allows for setting of x and y attributes that function the same as the attributes of other simple shapes like <line>, <circle>, <rect>, <text>
http://jsbin.com/iqEkAsE/2
<svg width="100%" height="100%">
<defs >
<path id="Triangle"
d="M 1 1 L 200 1 L 100 200 z"
fill="orange"
stroke="black"
stroke-width="3" />
</defs>
<use x="33%" y="33%" xlink:href="#Triangle"/>
<use transform="scale(-1)" x="-66%" y="-66%" xlink:href="#Triangle"/>
</svg>
It would be nice to be able to scale the shape dynamically by setting the width and height property of the <use> to a percent but it can still be scaled with a transform.
Use transformations (translation, rotation, scale), that is the correct way to do it.
The other shapes allow you to use a point defined by x,y coordinates because that's just a part of the shape definition (i.e. how do you define a circle, you need the center point and the radius).
In theory you could position an element using its bounding box, however the bounding box is not "settable" (there is no setBBox method), there is only getBBox()
Below is a screen capture of SVG image which is rendered on Chrome 22.0.1229.79 Mac. The original svg is on jsfiddle:
http://jsfiddle.net/LGBk5/
The left image is made using SVG:s dilate and erode filters. The right one is made using Illustrator's Offset Path effect.
The left one has problems: the border at the bottom is distorted and curves are not as smooth. Meanwhile the thick black border is the same in both.
Has my SVG some parameter wrong or are the dilate and erode filters so seemingly buggy?
EDIT: The purpose is to make paths thinner or thicker in SVG, but according to this example, the erode/dilate is not stable enough to rely.
Filter effects are done on pixel data (the rasterized path), while the path offset operation in Illustrator (similar in Inkscape) is done using the original path data (or vector data if you wish).
The former is like using photoshop filters, the latter is creating new paths by using the existing path. They're both stable, but they're not the same operation.
Illustrator's path offset and SVG filters erode/dilate are different operations.
This erode filter is working as designed - there is no bug here. For every pixel in the input image, the filter looks at the maximum RGBA values in a rectangle around it (the radius). In a normal image this tends to generate "rectangular highlights" for want of a better term. And results in weird artifacts when applied to curved draw paths. From the spec:
The dilation (or erosion) kernel is a rectangle with a width of
2*x-radius and a height of 2*y-radius. In dilation, the output pixel
is the individual component-wise maximum of the corresponding R,G,B,A
values in the input image's kernel rectangle. In erosion, the output
pixel is the individual component-wise minimum of the corresponding
R,G,B,A values in the input image's kernel rectangle.
So, imagine that that single pixel at the pointy end of your shape. With a 10 pixel "radius" in your filter (and remember that radius is an incredibly misleading term because it's using a rectangle not a circle!). Let's say it's at 100,100, for arguments sake. When the filter processes values for pixels in the range 90,110 to 110,110, its dilation radius is going to detect that pixel at 100,100 and paint all pixels in that range black. And just like that, your nice pointy end has been dilated into a straight line.
Note that you can achieve most offset path effects using nested strokes (some of which have masks to trim the inside or outside of the path.
For example, here is the OP's path reimplemented this way:
<!-- Left drawing is made using erode and dilate -->
<!-- Right one is made by Illustrator's Offset Path -->
<svg width="612" height="792" viewBox="0 0 612 792" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="curve" d="M21.552,74.438c2.531-28.879,73.668-52.734,102.629-53.971
c32.164-1.373,74.764,23.746,61.766,53.197c-32,72.5-84.236-59.594-109.5-29.5c-23.367,27.833,55.4,142.969,55.4,142.969
S18.109,113.708,21.552,74.438z"/>
<mask id="inner">
<use xlink:href="#curve" fill="white"/>
</mask>
</defs>
<!-- this black outermost line -->
<use x="10" y="10" xlink:href="#curve" style="stroke:black;stroke-width:26;stroke-linejoin:miter;stroke-miterlimit:10"></use>
<!-- thick red outer line -->
<use x="10" y="10" xlink:href="#curve" style="stroke:#f00;stroke-width:24;stroke-linejoin:miter;stroke-miterlimit:10"></use>
<!-- innermost black thin line, with green fill -->
<use x="10" y="10" xlink:href="#curve" style="fill:#1CFF00;stroke:black;stroke-width:32;stroke-linejoin:miter;stroke-miterlimit:10" mask="url(#inner)"></use>
<!-- blue inner stroke -->
<use x="10" y="10" xlink:href="#curve" style="fill:none;stroke:#5555FF;stroke-width:30;stroke-linejoin:miter;stroke-miterlimit:10" mask="url(#inner)"></use>
<!-- lastly, the black line -->
<use x="10" y="10" xlink:href="#curve" style="fill:none;stroke:black;stroke-width:10;stroke-linejoin:miter;stroke-miterlimit:10"></use>
<g transform="translate(210,10)">
<path fill="#FF0000" stroke="#231F20" d="M126.273,201.917c-1.188-0.766-29.407-19.044-57.679-42.532c-41.739-34.676-60.31-60.754-58.441-82.068
c1.575-17.974,18.042-34.105,48.943-47.945c21.673-9.707,48.782-16.997,65.925-17.729c1.023-0.043,2.057-0.065,3.096-0.065
c26.722,0,55.103,13.789,67.484,32.787c7.866,12.07,9.101,25.736,3.476,38.482c-8.697,19.704-20.608,29.697-35.403,29.702
c-0.002,0-0.007,0-0.01,0C144.382,112.551,127.62,95,111.407,78.028c-7.054-7.385-18.575-19.446-23.912-21.338
c-1.086,2.002-6.186,15.821,20.666,67.477c16.226,31.214,35.475,59.438,35.668,59.72l35.977,52.589L126.273,201.917z"/>
<path fill="#5555FF" stroke="#231F20" stroke-width="10" stroke-miterlimit="10" d="M22.939,78.438
c2.531-28.879,73.668-52.734,102.629-53.971c32.164-1.373,74.764,23.746,61.766,53.197c-32,72.5-84.237-59.594-109.5-29.5
c-23.366,27.833,55.401,142.969,55.401,142.969S19.497,117.709,22.939,78.438z"/>
<path fill="#00FF00" stroke="#231F20" d="M79.986,131.678C38.498,95.796,38.41,81.397,38.549,79.807c0.289-3.29,5.843-10.151,19.371-17.933
C57.676,78.899,64.972,101.816,79.986,131.678L79.986,131.678z M163.665,84.044c-7.09,0-22.461-16.091-31.646-25.706
c-5.867-6.143-11.433-11.969-16.966-16.846c4.324-0.776,8.128-1.238,11.184-1.368c0.621-0.027,1.249-0.04,1.88-0.04
c16.911,0,36.471,8.903,43.603,19.846c3.317,5.089,2.508,8.623,1.278,11.408C168.884,80.659,165.163,84.043,163.665,84.044
L163.665,84.044z"/>
</g>
</svg>