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>
I'm working on an SVG image and I can't figure out how to erase a certain part of a path.
This is the current situation: https://gyazo.com/db59fcaf9f122e7e2c0bba5833db9ec5
There are two green letters which overlap and a red bar which does basically represent the area I want to erase so the letters don't stick directly on each other. It works fine when I have a set background colour since I can then easily overwrite lower paths, but with transparent background, this method no longer works, since it appears to make the path transparent, not the entire pixel itself.
TL;DR: How do I make a path actually render the pixel transparent, not just the path element?
You can mask the J with a white rect and a black N with an extra stroke. Next you use again the N. Please play with the stroke width of the mask <use>
svg{border:1px solid; width:90vh}
text{font-family:arial;dominant-baseline:middle}
<svg viewBox="0 0 24 24">
<defs>
<text id="n" x="7" y="14" >N</text>
<mask id="mascara">
<rect width="24" height="24" fill="white" />
<use xlink:href="#n" fill="black" stroke="black" />
</mask>
</defs>
<text x="5" y="10" style="mask: url(#mascara)">J</text>
<use xlink:href="#n" fill="black" />
</svg>
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>
I would like to move a particular composite shape to a <Symbol> definition, and then re-use it. This helps make the SVG code neater, and provides some global control over the actual structure of that shape. The shape is symmetrical about a given mid-point; however, the x/y coordinates of subsequent <Use> statements need to reference the top-left corner rather than its natural original, and this means that all usage of the shape must be aware of its total size. Is there a way to position a Symbol by some origin other than its top-left corner?
Contrived example, purely to explain this better. The following concentric-circle Symbol has a natural origin. However, the subsequent Use statement has to offset its x/y coordinates by half the Symbol size in order to position it correctly (at 20,20 in this example). Ideally, the usage of the symbol should not have to know this information.
<defs>
<symbol id="ex">
<circle fill="green" cx="8" cy="8" r="8"/>
<circle fill="white" cx="8" cy="8" r="6"/>
<circle fill="green" cx="8" cy="8" r="4"/>
</symbol>
</defs>
<use xlink:href="#ex" x="12" y="12">
The downside to a symbol is that it cuts of rendering at the border of a viewport. (which is also an upside, since you can define a viewBox.) But you can avoid using it at all. Everything in a <defs> element is not rendered directly, so you can exchange the <symbol> for a <g> and center everything on the origin:
<defs>
<g id="ex">
<circle fill="green" cx="0" cy="0" r="8"/>
<circle fill="white" cx="0" cy="0" r="6"/>
<circle fill="green" cx="0" cy="0" r="4"/>
</g>
</defs>
<use xlink:href="#ex" x="12" y="12">
http://jsfiddle.net/nuzwn07n/
If I read your question correctly, you want to be able to say
<use xlink:href="#ex" x="20" y="20">
..and then the circle symbol is positioned with its center at [20,20]. The solution I propose requires you to know the size of the symbol, but only once (in the <symbol> declaration), and not on every <use> element.
1: In the <symbol>, put everything in a group which you translate so the center of the graphics lies on the top-left corner.
<symbol id="ex">
<g transform="translate(-8,-8)">
<circle ...
</g>
</symbol>
2: If you now <use> that symbol, you'll only see the quarter circle that's still within the symbol's "viewport". To display the whole circle, simply apply overflow="visible" to the <symbol>.
<symbol id="ex" overflow="visible">
<g transform="translate(-8,-8)">
<circle ...
</g>
</symbol>
http://jsfiddle.net/0ghucsrp/
I have a pin that needs to be shown inside a circle in Svg.
My current code is the following:
<svg viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<circle cx="50%" cy="1.5" r="1.5" style="fill: green;"></circle>
<svg x="47.5%" y="5%" viewBox="0 0 10000 10000" fill="#fff" preserveAspectRatio="none">
<g>
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z">
</path>
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z">
</path>
</g>
</svg>
</svg>
which works somewhat but seems inelegant, and perhaps also buggy. What I would like is a better way to center the group 'inside' the circle without using JavaScript
It would be nice if I could get rid of the extra SVG element in the middle with its really big viewBox that I'm using to place the pin. So if you can show me how to do it with just a g and make a scaling function that would be good.
If you want to use coordinates that contain percentage values, you need an element that has x and y attributes. <use> is such an element, <g> is not.
Your live will be easier if you draw your pin centered on the origin of the coordinate system: translate(-250 -230).
After that, you can easily scale it to the size you need: scale(0.0025) (remember: multiple transform commands are processed right-to-left.)
Finally, you use the pin template with the same x and y coordinates as your circle.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<defs>
<!--center the pin around the origin and scale it to final size-->
<g id="pin" transform="scale(0.0025) translate(-250 -230)">
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z" />
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z" />
</g>
</defs>
<!--use the same coordinates for the center of the circle and the pin-->
<circle cx="50%" cy="1.5" r="1.5" fill="green" />
<use xlink:href="#pin" x="50%" y="1.5" fill="white" />
</svg>