Space between SVG and path - svg

I am using SVG to clip an image to the shape of SVG.The screenshot I have attached is of chrome(first) and IE(second).In IE it looks very small in size.The issue is I find space between the SVG and path. I have tried out many combinations of viewBox but nothing worked out.I even scaled my SVG to 1*1 even then I am facing this issue.
<div>
<svg class="svg-graphic" width="100%" height="100%" viewBox="35 35 1000 1000" xmlns="http://www.w3.org/2000/svg" >
<g>
<clipPath id="arch-mask" >
<path class="st0" d="M905.33,324.23c0-4.36-3.42-7.48-7.89-7.89c-72.15-3.95-130.16-61.96-134.11-134.11
c-0.18-4.35-3.53-7.89-7.89-7.89H297.89c-4.36,0-7.48,3.42-7.89,7.89c-3.95,72.15-61.96,130.16-134.11,134.11
c-4.35,0.18-7.89,3.53-7.89,7.89v457.55c0,4.36,3.42,7.48,7.89,7.89c72.15,3.95,130.16,61.96,134.11,134.11
c0.18,4.35,3.53,7.89,7.89,7.89h457.55c4.36,0,7.48-3.42,7.89-7.89c3.95-72.15,61.96-130.16,134.11-134.11
</clipPath>
</g>
<image clip-path="url(#arch-mask)" height="100%" width="100%" xlink:href="https://picsum.photos/id/1003/500/500" />
</svg>

You have a few errors in your code like the path that isn't closing. I've changed the viewBox of the svg element so that you have no spaces between the clipping path and the borders of the svg element. Also I've changed the size and the position of the image to be the same as the bounding box of the clipping path. To get the bounding box you can use the getBBox() method.
In javaScript you'll find commented out the bounding box of the path inside the clipping path.
/*let bb = document.querySelector("#arch-mask path").getBBox();
console.log(bb)*/
svg{border:solid}
<svg class="svg-graphic" width="100%" height="100%" viewBox="148 174 757.33 757.33" xmlns="http://www.w3.org/2000/svg" >
<g>
<clipPath id="arch-mask" >
<path class="st0" d="M905.33,324.23c0-4.36-3.42-7.48-7.89-7.89c-72.15-3.95-130.16-61.96-134.11-134.11
c-0.18-4.35-3.53-7.89-7.89-7.89H297.89c-4.36,0-7.48,3.42-7.89,7.89c-3.95,72.15-61.96,130.16-134.11,134.11
c-4.35,0.18-7.89,3.53-7.89,7.89v457.55c0,4.36,3.42,7.48,7.89,7.89c72.15,3.95,130.16,61.96,134.11,134.11
c0.18,4.35,3.53,7.89,7.89,7.89h457.55c4.36,0,7.48-3.42,7.89-7.89c3.95-72.15,61.96-130.16,134.11-134.11"/>
</clipPath>
</g>
<image clip-path="url(#arch-mask)" x="148" y="174" width="757.33" height="757.33" xlink:href="https://picsum.photos/id/1003/500/500" />
</svg>

Related

SVG clipPath - clipped area offset and size problem

Please see the yellow rectangle, this is exactly the same as the rectangle clipping the image.
However image is clipped smaller and moved right.
The image is just one element, but imagine few more elements which all need to be clipped to a shape of a yellow rectangle.
I know I can fix this by wrapping the <image> element (and any more elements) inside a <g> element and applying the clipPath to this <g> element.
Is it possible to fix this issue by modifying just the clipPath part, without touching the rest of the svg structure?
<defs>
<clipPath id="clipPath">
<path d="M150-750 L150,750 L-150,750 L-150,-750Z" transform="matrix(1,0,0,1,152.5,770.5)"></path>
</clipPath>
</defs>
<path fill="#ffff00" d="M150-750 L150,750 L-150,750 L-150,-750Z" transform="matrix(1,0,0,1,152.5,770.5)"></path>
<image x="-1632" y="-1224" width="3264" height="2448" preserveAspectRatio="none"
xlink:href="https://cdn.pixabay.com/photo/2017/07/25/01/22/cat-2536662_960_720.jpg"
transform="matrix(0.3529,0,0,0.3529,246.2554,998.5607)"
style="clip-path: url(#clipPath);"></image>
Please see the jsfiddle here.
Everything happens because you transform the path and the image with a different value. I've removed the transforms and changed the viewBox value so that the clipping path falls inside the svg canvas.
Also I've removed the height of the svg element because I wanted to keep the same aspect ratio as the viewBox.
Please take a look. Let me know if this is what you need.
<svg width="305" style="overflow: hidden; position: relative;"
viewBox="-200 -800 750 3964" preserveAspectRatio="xMinYMin">
<defs>
<clipPath id="clipPath">
<path id="test" d="M150-750 L150,750 L-150,750 L-150,-750Z" ></path>
</clipPath>
</defs>
<use xlink:href="#test" fill="#ffff00" ></use>
<image x="-1632" y="-1224" width="3264" height="2448" preserveAspectRatio="none"
xlink:href="https://cdn.pixabay.com/photo/2017/07/25/01/22/cat-2536662_960_720.jpg"
style="clip-path: url(#clipPath);"></image>
</svg>

How to automatically create the minimal size of the viewbox which fits for the complete content?

I have a simple or complex SVG graphic. For example a rotated rectangle.
Without calculating you cannot know the minimal size of the viewbox, where the graphic fits into completely.
<svg viewBox="0 0 30 30">
<rect x="20" y="0" width="100" height="20" transform="rotate(45)" fill="black" />
</svg>
The result is, that the graphic does not fit into the viewbox.
Is there any method, how to get an the minimal size of the viewbox, where the graphic is shown completely?
Ideally I do not want to declare a size/ratio of a viewbox. I just want that the minimal size is a result of the content of the SVG graphics.
Is there any disadvantage, when I do not declare the viewBox attribute at all?
Thanks for your help.
One way to do it is wrapping the transformed rectangle in a <g> element and then get the value of the bounding box for theG. Next you use the values of the bounding box (BB) to reset the viewBox of theSVG. I hope it helps.
// the bounding box for the wrapping g
let BB = theG.getBBox();
theSVG.setAttributeNS(null, "viewBox", `${BB.x} ${BB.y} ${BB.width} ${BB.height}`)
svg{border:1px solid}
<svg id="theSVG" viewBox="0 0 30 30" width="300">
<g id="theG">
<rect x="20" y="0" width="100" height="20" transform="rotate(45)" fill="black" />
</g>
</svg>

How to reduce svg size to clipped area?

Is it possible to reduce the actual size (i.e. width and height) to the clipping? Let's see the svg below for an example:
The underlying "base" image has a size of 272x136 pixels. The clipping result has a size of 17x17 pixels. Now I would like that the resulting svg is resized to 17x17 pixels. Is that even possible?
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="cut-off-bottom">
<rect x="102" y="102" width="17" height="17"/>
</clipPath>
</defs>
<image xlink:href="https://openmaptiles.github.io/osm-bright-gl-style/sprite.png" clip-path="url(#cut-off-bottom)" />
</svg>
Select the area you want to see with a viewBox and then set the size of the SVG to whatever you want using the outer <svg> element's width and height
I've also added width and height attributes to the image element so it works on browsers other than Chrome/Opera.
<svg width="17px" height="17px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="102 102 17 17">
<defs>
<clipPath id="cut-off-bottom">
<rect x="102" y="102" width="17" height="17"/>
</clipPath>
</defs>
<image xlink:href="https://openmaptiles.github.io/osm-bright-gl-style/sprite.png" clip-path="url(#cut-off-bottom)" width="272px" height="136px" />
</svg>

An SVG having only definitions for another scaling SVG still needs to scale?

My SVG is width="1200" height="600" viewBox="0 0 1200 600". It uses a clipPath from defs of another SVG.
<svg class="svg-def">
<defs>
<clipPath id="clip-1"> ...
</defs>
</svg>
<svg width="1200" height="600" viewBox="0 0 1200 600">
<g clip-path="url(#clip-1)">
...
</g>
</svg>
Demo
When .svg-def does not have width="1200" height="600" viewBox="0 0 1200 600" (the first image), on window width narrower than 1200, the right side is clipped. This is not desired.
I want the second image -- the clip is just the size of the SVG. The second image is good because the <clipPath> being used is from an <svg> element with the same width="1200" height="600" viewBox="0 0 1200 600"
<svg class="svg-def">
<defs>
<clipPath id="clip-1"> ...
</defs>
</svg>
<svg class="svg-def" width="1200" height="600" viewBox="0 0 1200 600">
<defs>
<clipPath id="clip-2"> ...
</defs>
</svg>
Questions
1) In <clipPath> <rect width="100%" height="100%"/>, what is 100% relative to?
2) The first clip's display width varies with window width (when the latter is narrow than 1200px). Narrower window width = narrower display width. What is the display width relative to?
3) So if I have an SVG which has only <defs>, its <svg> tag still has to have viewbox values, so that the other SVG which uses the definitions (and which scales with window width) can have definitions in correct sizes?

Masking an SVGPattern

fiIs it possible to Mask an SVGPattern?
I've made the following SVG, but I can't get the mask to work.
Or should I be using clipPath?
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="160px" height="600px" viewBox="0 0 160 600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="circlePattern" patternUnits="userSpaceOnUse"
x="0" y="0" width="10" height="10"
viewBox="0 0 10 10" fill="blue" >
<circle cx='4' cy='4' r='4'/>
</pattern>
<clipPath id="clipPath" maskUnits="userSpaceOnUse">
<rect x="0" y="0" width="200" height="100" fill="white" />
</clipPath>
</defs>
<!-- Outline the drawing area in blue -->
<g id="box">
<rect fill="url(#circlePattern)" width="160" height="600" clip-path="url(#clipPath)"/>
</g>
</svg>
UPDATE: (I would like to use this complex path)
I can't seem to use this path to create the mask/clipPath
<path style="fill:#FFFFFF;" d="M9.35,37.5c4.1,2.467,8.566,3.7,13.4,3.7
c7.667,0,13.783-2.05,18.35-6.15c5.066-4.566,7.6-11.167,7.6-19.8c0-5.7-2.367-12.133-7.1-19.3c-4.1-6.267-9.7-12.684-16.8-19.25
c-5.133-4.8-10.383-8.983-15.75-12.55c-2.4-1.6-3.883-2.6-4.45-3c-1.733-1.033-3.267-1.8-4.6-2.3h-0.05c-1.3,0.5-2.8,1.267-4.5,2.3
c-0.633,0.434-2.133,1.417-4.5,2.95c-5.467,3.667-10.867,8-16.2,13c-6.967,6.566-12.467,12.917-16.5,19.05
c-4.633,7.1-6.95,13.467-6.95,19.1c0,8.633,2.534,15.233,7.6,19.8c4.567,4.1,10.684,6.15,18.35,6.15c4.833,0,9.3-1.233,13.4-3.7
c4-2.367,7.1-5.6,9.3-9.7C2.25,31.9,5.383,35.133,9.35,37.5z"/>
Your mask rect has no fill specified so it will use the default which is black i.e. i.e. rgba(0, 0, 0, 1). So the luminance of the mask is 0 everywhere and you see nothing.
If you change the fill on the mask <rect> to fill="white" you'll see the mask act as a clip which would seem to be what you're looking for. Other colours like "orange" or "blue" as they have a luminance which is neither 0 nor 1 will give you an intermediate effect.
clipPaths clip a shape to a boundary. Masks generally modify colours, you can use them to clip by having a white mask but if all you want is to clip something then a clipPath is faster.
clipPaths and masks can contain any graphics element including a path.

Resources