I'm struggling with an SVG clip path scaling behaviour. I would like to scale a clip path to fit the element size it's applied to. I've been reading about clipPath units but I can't get this working.
Here is an example of what I am trying to do without any scaling: http://jsfiddle.net/1196o7n0/1/
...and the SVG ( the main shape and the clippath shape are exactly the same ):
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<clipPath id="svgPath">
<circle r="40" cy="50" cx="50" />
<circle r="74.576" cy="235" cx="193.949" />
<circle r="47.034" cy="108.305" cx="426.576" />
<circle r="43.644" cy="255.763" cx="346.915" />
<circle r="35.17" cy="82.882" cx="255.39" />
</clipPath>
<g fill="#000">
<circle r="40" cy="50" cx="50" />
<circle r="74.576" cy="235" cx="193.949" />
<circle r="47.034" cy="108.305" cx="426.576" />
<circle r="43.644" cy="255.763" cx="346.915" />
<circle r="35.17" cy="82.882" cx="255.39" />
</g>
</svg>
Now if I define a viewbox and make that SVG scales to fit the document width and height, the clip path doesn't seem to scale: http://jsfiddle.net/1196o7n0/2/
Any idea on how I can make this work ? Am i missing out on something?
To scale a clip path to fit the element that you are applying it to you need to add clipPathUnits="objectBoundingBox" to your clippath element.
Here is a JsFiddle based on your example demonstrating how to do this.
<svg width="0" height="0" >
<defs>
<clipPath id="svgPath" clipPathUnits="objectBoundingBox">
<circle r="0.05" cy="0.0625" cx="0.1625" />
<circle r="0.09322" cy="0.29375" cx="0.2424" />
<!-- rest of path here-->
</clipPath>
</defs>
</svg>
<div class="content centered">
<div class="clipped"></div>
</div>
The catcher is that the units of the path need to be decimal numbers between 0 and 1; these represent fractions of the corresponding element's width or height.
The clipPath is defined in absolute units (pixels). If it was being applied to something in the SVG, it would get scaled. But the HTML side of things doesn't know that. It just applies the clipPath as defined.
Related
I could probably manually fake it using a solid-edged drop shadow filter around the strokes, set to the background color, but that's neither resilient nor ideal.
Visually, instead of this:
I want to have this (if the circle is on top):
A posible solution would be creating a mask with a white rectangle and a black stroked <use> element that is using the circle.
Please note that the white rectangle is covering all the svg element and the stroke-width of the <use> element is wider than the stroke of the circle.
This way you create a hole in the rect that is letting you to see whatever you have in the background.
<svg fill="none" stroke="black" stroke-width="3">
<mask id="m">
<rect width="100%" height="100%" fill="white" />
<use xlink:href="#c" stroke-width="10" />
</mask>
<rect x="10" y="5" width="70" height="70" mask="url(#m)" />
<circle id="c" cx="80" cy="75" r="40" />
</svg>
I'm trying to create a filter for only the stroke of path in SVG, but the feImage keeps getting clipped to what I assume is that bounding box (see green rectangle below in code as bounding box). I've tried setting the filter's x/y and width/height to all sorts of positions/sizes, as seems to be the prevailing advice, but nothing works. x/y just offset the feImage and width/height of greater than 100% has no effect.
I won't know in advance if the stroke or fill is solid or something else (like linearGradient.
The below demonstrates what I'm looking to do - just get the stroke of a shape (regardless of size or fill) and apply a filter to it for all modern browsers.
Notes: FF doesn't even display the left-hand feImage. Chrome clips the left and top. Edge clips all 4 sides.
<html>
<body>
<svg width="960" height="540" >
<rect width="960" height="540" stroke="#385D8A" fill="white" stroke-width="3"/>
<svg name="BoundingBox1" class="rect" x="100" y="100" overflow="visible" fill="none" stroke="#00ff00" stroke-width="1">
<path d="M0,0L121.68,0L121.68,121.68L0,121.68Z" />
</svg>
<!-- BELOW IS MODIFIED "SPEECH" SHAPE. NEED A FILTER ON THE STROKE ONLY. -->
<svg name="Speech-strokeonly" x="100" y="100" overflow="visible" fill="blue" stroke="orange" stroke-width="12" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="strokeOnly" fill="none"/>
<filter id="effs0sp9" color-interpolation-filters="sRGB" x="0" y="0">
<feImage xlink:href="#strokeOnly" />
</filter>
</defs>
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="effs0sp9" filter="url(#effs0sp9)" overflow="visible" />
<text y="160" stroke="black" stroke-width="0.2">this is the one that has undesirable clipping of</text>
<text y="178" stroke="black" stroke-width="0.2">of stroke in Chrome/Edge. Doesn't appear at all in FF</text>
</svg>
<!-- BELOW IS ORIGINAL WITH BOTH FILL AND STROKE -->
<svg name="BoundingBox2" x="400" y="100" overflow="visible" fill="none" stroke="green" stroke-width="1">
<path d="M0,0L121.68,0L121.68,121.68L0,121.68Z" />
</svg>
<svg name="Speech-original" x="400" y="100" overflow="visible" fill="blue" stroke="orange" stroke-width="12">
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="effs0sp9" />
<text y="-22" stroke="black" stroke-width="0.2">this is the original one</text>
<text y="-6" stroke="black" stroke-width="0.2">that I just want the stroke as feImage from</text>
</svg>
</svg>
</body>
</html>
Is there a way to grab the whole stroke of a shape only and use in a filter?
I am trying to understand how the coordinate systems works in svg.
In the following HTML, I am unable to understand why the images enlarge if I don't specify viewport.
There seems to be a default size of viewport if I don't specify any value. What is it?
<!-- what is the default dimension of a viewport? -->
<p> no viewport or view box. viewport seem to have a default size. anything outside is clipped</p>
<svg style="border-style: dotted">
<ellipse cx="50" cy="50" rx="50" ry="50"></ellipse>
</svg>
<p> no viewport or view box. viewport seem to have a default size. anything outside is clipped</p>
<svg style="border-style: dotted">
<ellipse cx="50" cy="50" rx="1500" ry="1500"></ellipse>
</svg>
<p>viewport but no viewbox. Only what is in viewport is visible. Same as default viewport value case but we are specifying the dimensions of viewport here</p>
<svg width="50" height="50" style="border-style: dotted">
<ellipse cx="50" cy="50" rx="50" ry="50"></ellipse>
</svg>
<p>viewport but no viewbox. Only what is in viewport is visible. Same as default viewport value case but we are specifying the dimensions of viewport here</p>
<svg width="50" height="50" style="border-style: dotted">
<ellipse cx="50" cy="50" rx="1500" ry="1500"></ellipse>
</svg>
<!-- why this is large?-->
<p>viewbox but no viewport. Viewport takes same space as viewbox</p>
<svg viewBox="0 0 50 50" style="border-style: dotted">
<ellipse cx="50" cy="50" rx="50" ry="50"></ellipse>
</svg>
<!-- why this is large?-->
<p>viewbox but no viewport. Viewport takes same space as viewbox</p>
<svg viewBox="20 20 100 100" style="border-style: dotted">
<ellipse cx="50" cy="50" rx="50" ry="50"></ellipse>
</svg>
<p>viewport and viewbox. Value of viewport determines what would be visible</p>
<svg width="10" height="10" viewBox="0 0 50 50" style="border-style: dotted">
<ellipse cx="50" cy="50" rx="50" ry="50"></ellipse>
</svg>
I have a rectangle
<rect id="greenRect" fill="lightgreen" height="20" width="20"/>
Now I want to reuse the rect, but make it bigger
<use href="#greenRect" y="150" height="50" width="50"/>
The size (height/width) don't seem to get overwritten from the original <rect> element.
How would I achieve such a thing?
Solution 1: Wrap the rect in a <symbol> with a viewBox attribute.
<symbol id="greenRect" viewBox="0 0 20 20">
<rect fill="lightgreen" height="20" width="20"/>
</symbol>
<!-- symbols are not rendered, so if you want to see your original,
you have to also use it -->
<use href="#greenRect" height="20" width="20"/>
<use href="#greenRect" y="150" height="50" width="50"/>
Solution 2: scale and translate your rectangle
<rect id="greenRect" fill="lightgreen" height="20" width="20"/>
<!-- transformation are applied right-to-left -->
<use href="#greenRect" transform="translate(0 150) scale(2.5)"/>
I need to apply mask to a different objects.
Mask should cover whole object (visible part of it). I put the mask inside one specific place, at the top of the page, changed maskContentUnits to objectBoundingBox, so it worked perfectly.
But then a problem appeared.
I made a fiddle to illustrate the problem: http://jsfiddle.net/8qdt7vjr/1/
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="objectBoundingBox">
<ellipse cx=".5" cy=".5" rx=".5" ry=".5" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
In this fiddle i want to apply mask to svg element with id="zzz". But inside this element there is a rect element, that increases zzz's bounding box. In the fiddle it is rect, but in my project it is an image tag. zzz has overflow set to hidden (in the fiddle I changed it to visible, so it is easier to see the problem), so I have a specific portion of image visible inside zzz.
The real problem is that zzz's inner content increases zzz's bounding box.
In the fiddle I want ellipse mask to be inside red rectangle (visible zzz's area), but it is inside green rectangle (zzz's bounding box) instead.
So the main question is: is there any way to achieve this goal? Mask will be used by many elements with different sizes and content and I do not want to clone it.
Is there any way to do this without cloning mask inside each element?
Is there any way to reduce bounding box to visible area?
Is there any way to show a part of an image without expanding parent's bounding box?
Is there any other way to do this?
Is it something like this you try to achieve?
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="userSpaceOnUse">
<ellipse cx="100" cy="75" rx="100" ry="75" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
Maybe using userSpaceOnUse instead of objectBoundingBox can help achieve what you want... In combination with nested svg elements you can define the userspace to use and with that the part the mask is applied to...