Parent SVG defaults to 150x300 when linking to fragments - how to fix? - css

I'm using an external SVG image, and linking to a fragment within it. This is so that:
My markup is clean
I can modify the SVG with CSS
I only need a single SVG document, acting as a sort of spritesheet.
HTML:
<style>
.icon-1{ fill: red;width: auto;height: auto;display: inline-block;}
</style>
<svg class="icon icon-1" preserveAspectRatio="xMinYMax meet">
<use xlink:href="svg.svg#icon-icon-map-pin"></use>
</svg>
SVG:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<defs>
<symbol id="icon-icon-map-pin" viewBox="0 0 1167 1024">
<title>icon-map-pin</title>
<path class="path1" d="M476.444 684.8l27.022 67.556c-26.311 10.667-52.622 18.489-77.511 23.467l-14.933-71.111c20.622-4.267 42.667-11.378 65.422-19.911zM259.556 772.267c27.022 7.822 54.756 12.089 83.911 12.089l1.422-73.244c-22.044-0.711-44.089-3.556-64.711-9.244l-20.622 70.4zM833.422 644.978c21.333 4.267 41.244 11.378 61.156 21.333l33.422-64.711c-25.6-13.511-52.622-22.756-80.356-27.733l-14.222 71.111zM681.244 584.533l22.044 69.689c22.044-7.111 44.089-11.378 65.422-12.8l-5.689-72.533c-27.022 2.133-54.044 7.111-81.778 15.644zM564.622 640c-8.533 4.978-16.356 9.956-24.178 14.222l35.556 64c9.244-4.978 17.778-9.956 27.022-15.644 12.8-7.822 24.889-14.933 36.978-20.622l-33.422-64.711c-13.511 5.689-27.733 13.511-41.956 22.756zM765.867 184.889c0 29.867-7.111 58.311-19.911 82.489l-162.133 319.289c0 0-163.556-320.711-164.267-322.133-11.378-23.467-17.778-50.489-17.778-78.933 0-100.978 81.778-182.044 182.044-182.044s182.044 81.067 182.044 181.333zM692.622 184.889c0-60.444-49.067-109.511-109.511-109.511s-108.8 49.067-108.8 109.511 49.067 109.511 109.511 109.511 108.8-49.067 108.8-109.511zM947.911 367.644h-171.378l-36.978 72.533h156.444l78.222 236.8-24.889 27.733c27.022 24.178 40.533 46.222 40.533 46.933l7.822-4.978 68.267 204.8h-964.978l73.244-219.022c2.844 2.133 4.267 3.556 7.111 4.978l39.111-61.867c-8.533-5.689-15.644-10.667-22.044-15.644l73.244-219.022h155.733c-15.644-29.867-27.733-54.044-36.978-73.244h-171.378l-219.022 656.356h1166.933l-219.022-656.356z"></path>
</symbol>
</defs>
</svg>
If I manually set the width or height to a pixel value, and the opposite to auto, it will still grab the default. For instance, height:25px; width: auto; would give me a 25x300 image.
This was originally inspired by http://css-tricks.com/svg-use-external-source/, but the width/height was fixed.
Even if I wrap it in a position:relative' div, and make the svg element absolute with `top:0;right:0;bottom:0;left:0;', it still ignores it.
I'm stumped - it seems like it's ignoring my rules entirely.
See http://jsfiddle.net/5rcsyk36/

I think you want width and height to be 100%, not auto.
A width of auto will use the svg element's intrinsic width and it doesn't have an intrinsic width as it doesn't have a viewBox. So you get the default which is 300. Similarly for height except that the default for height is 150.

Related

Animating SVGs Via CSS

I found this immensely helpful CodePen about animating SVGs via CSS. First question, would it also work with line elements? I tried it with a few different keywords but didn't succeed:
svg {
width: 200px;
height: 200px;
}
.path path {
transition: d 400ms;
}
.line line {
transition: x1 400ms, y1 400ms, x2 400ms, y2 400ms;
}
.path:hover path {
d: path("M10,90 L90,10");
}
.line:hover line {
x1: line("10");
y1: point("90");
x2: coord("90");
y1: pos("10");
}
<svg class="path" viewBox="0 0 100 100">
<g stroke="black" stroke-width="5">
<path d="M10,10 L90,90"/>
</g>
</svg>
<svg class="line" viewBox="0 0 100 100">
<g stroke="black" stroke-width="5">
<line x1="10" y1="10", x2="90" y2="90"/>
</g>
</svg>
Also, where is the documentation for this, the fact that you have to write d: path("M10,90 L90,10"); instead of just d: "M10,90 L90,10"; seems non-trivial to me, how would that work with other properties of other elements?
Only presentation attributes have their counter-parts in CSS.
As of today, here is the list of these attributes:
Properties with a presentation attribute
Elements that support the presentation attribute
cx, cy
‘circle’ and ‘ellipse’
height, width, x, y
‘foreignObject’, ‘image’, ‘rect’, ‘svg’, ‘symbol’, and ‘use’
r
‘circle’
rx, ry
‘ellipse’ and ‘rect’
d
‘path’
fill
Any element in the SVG namespace except for animation elements, which have a different ‘fill’ attribute.
transform
For historical reasons, the transform property gets represented by different presentation attributes depending on the SVG element it applies to:transformAny element in the SVG namespace with the exception of the ‘pattern’, ‘linearGradient’ and ‘radialGradient’ elements.‘patternTransform’‘pattern’. ‘patternTransform’ gets mapped to the transform CSS property[css-transforms-1].‘gradientTransform’‘linearGradient’ and ‘radialGradient’ elements.‘gradientTransform’ gets mapped to the transform CSS property [css-transforms-1].
alignment-baseline, baseline-shift, clip-path, clip-rule, color, color-interpolation, color-interpolation-filters, cursor, direction, display, dominant-baseline, fill-opacity, fill-rule, filter, flood-color, flood-opacity, font-family, font-size, font-size-adjust, font-stretch, font-style, font-variant, font-weight, glyph-orientation-horizontal, glyph-orientation-vertical, image-rendering, letter-spacing, lighting-color, marker-end, marker-mid, marker-start, mask, mask-type, opacity, overflow, paint-order, pointer-events, shape-rendering, stop-color, stop-opacity, stroke, stroke-dasharray, stroke-dashoffset, stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-opacity, stroke-width, text-anchor, text-decoration, text-overflow, text-rendering, transform-origin, unicode-bidi, vector-effect, visibility, white-space, word-spacing, writing-mode
Any element in the SVG namespace.
You can see that lines's x1, x2, y1 and y2 aren't there, and thus can't be controlled and thus animated by CSS.
For the values d can receive in CSS it's described here and basically it can receive either a path() function, or the value none.

CSS3 - Select SVG group sibling

In a React application, I'm returning an SVG tag from a component. The SVG consists of a ring, and groups of elements positioned around it. Each group contains a shape (circle or rect) and a path depicting a number overlaying and identifying the shape.
For a minimum working example:
https://codepen.io/notthelewis/pen/gOGRZQQ
Each group can be either active or inactive. In the inactive state, I want the background colour of the shape to change on hover , but I want the path's fill to stay the same colour. Current behaviour of the codepen works when hovering over the shape itself, but reverts when hovering over the path (number) element, which is inside the shape; meaning that the fill of the shape returns to default rather than the chosen hover colour.
In looking around, I tried a few solutions, but could not get the selectors to perform quite how I want.
To surmise:
.inactive path:hover should somehow target: is(rect, circle) contained in the same group
.inactive path's stroke property should remain unaffected.
I've tried the following (to no avail!):
.inactive ~ path:hover {
fill: red;
}
.inactive path:hover ~ {
fill: red;
}
.inactive path:hover+rect {
fill: red;
}
.inactive :is(rect, circle)+path:hover {
fill: red;
}
I did find the has selector, but it doesn't appear to be adopted anywhere meaningful...
https://caniuse.com/css-has
And the has selector is also mentioned alongside the general successor selector answer provided in this SO question:
Is there a "previous sibling" selector?
Put the :hover on the <g>, not a descendant of <g>:
g.inactive:hover > rect,
g.inactive:hover > circle {
fill: grey;
}
Also, replace the huge <path> elements that are being used to represent text with <text> elements:
Before:
<svg width="468" height="304" viewBox="0 0 468 304" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Sensors">
<circle id="Sensor Ring" cx="228" cy="154" r="149" stroke="black" strokeWidth="2"/>
<g id="6" class='inactive'>
<rect id="6_sensor" x="80" y="203" width="20" height="20" fill="white" stroke="black" strokeWidth="2"/>
<path id="6_tag" d="M86.9941 213.561C86.9941 211.866 87.3516 210.604 88.0664 209.776C88.7852 208.948 89.8594 208.534 91.2891 208.534C91.7773 208.534 92.1602 208.563 92.4375 208.622V210.069C92.0898 209.991 91.7461 209.952 91.4062 209.952C90.7852 209.952 90.2773 210.046 89.8828 210.233C89.4922 210.421 89.1992 210.698 89.0039 211.065C88.8086 211.432 88.6934 211.954 88.6582 212.63H88.7344C89.1211 211.966 89.7402 211.634 90.5918 211.634C91.3574 211.634 91.957 211.874 92.3906 212.354C92.8242 212.835 93.041 213.499 93.041 214.346C93.041 215.261 92.7832 215.985 92.2676 216.52C91.752 217.052 91.0371 217.317 90.123 217.317C89.4902 217.317 88.9375 217.171 88.4648 216.878C87.9961 216.585 87.6328 216.157 87.375 215.595C87.1211 215.032 86.9941 214.354 86.9941 213.561ZM90.0879 215.87C90.4746 215.87 90.7715 215.741 90.9785 215.483C91.1855 215.221 91.2891 214.85 91.2891 214.37C91.2891 213.952 91.1914 213.624 90.9961 213.386C90.8047 213.143 90.5137 213.022 90.123 213.022C89.7559 213.022 89.4414 213.141 89.1797 213.38C88.9219 213.618 88.793 213.895 88.793 214.212C88.793 214.677 88.9141 215.069 89.1562 215.389C89.4023 215.71 89.7129 215.87 90.0879 215.87Z" fill="black"/>
</g>
After:
<svg width="468" height="304" viewBox="0 0 468 304" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Sensors">
<circle id="Sensor Ring" cx="228" cy="154" r="149" stroke="black" strokeWidth="2"/>
<g id="6" class='inactive'>
<rect id="6_sensor" x="80" y="203" width="20" height="20" fill="white" stroke="black" strokeWidth="2"/>
<text>6</text>
</g>
(You'll need to set font-size though).

Path not fitting inside SVG

I am working with SVG from some time now. But still I can't understand the viewbox after watching many videos and reading many articles.
I am trying to generate SVG dynamically:
import SvgIcon from '#material-ui/core/SvgIcon';
<SvgIcon className="svg" width="24" height="24" viewBox="0 0 24 24">
<g>
<path
d={scrapbookElement.icon.path}
/>
</g>
</SvgIcon>
Here is my JSON file which provides me scrapbookElements:
[
{
"id": "image",
"text": "Image",
"icon": {
"path": "M9.5999776,12.699997L11.899997,15.099998 13.299991,14.300003 19.000005,20 22.899999,18 28.299995,20.699997 28.299995,25.699997 3.5999767,25.699997 3.5999767,18.599998z M20.500005,11.699997L21.199987,11.699997 21.000005,12.800003 20.699987,12.800003z M23.09998,10.699997L23.799993,11.599998 23.59998,11.800003 22.699987,11.099998z M18.699987,10.699997L19.199987,11.199997 18.299993,11.900002 18.000005,11.599998z M23.59998,8.5999985L24.699987,8.8000031 24.699987,9 23.59998,9.1999969z M18.09998,8.5999985L18.09998,9.3000031 17.000005,9 17.000005,8.8000031z M20.799993,7C21.899999,7 22.699987,7.9000015 22.699987,8.9000015 22.699987,10 21.799993,10.800003 20.799993,10.800003 19.699987,10.800003 18.899999,9.9000015 18.899999,8.9000015 18.899999,7.8000031 19.799993,7 20.799993,7z M23.500005,6.0999985L23.699987,6.3000031 23.000005,7.1999969 22.500005,6.6999969z M18.199987,6.0999985L19.09998,6.8000031 18.59998,7.3000031 18.000005,6.3000031z M20.699987,5L21.000005,5 21.199987,6.0999985 20.500005,6.0999985z M2.1999823,2.4000015L2.1999823,26.800003 29.400001,26.800003 29.400001,2.4000015z M0,0L31.900001,0 31.900001,32 0,32z"
}
},
{
"id": "text",
"text": "Text",
"icon": {
"path": "M29.15,0L30.186011,0.012001038 30.610999,0.43099976 31.096015,3.868 31.209998,7.8079987 31.101996,8.3949966 30.610999,8.6230011 29.875007,8.5510025 29.437018,7.9520035 28.312018,5.298996 26.993995,3.7130013 25.82801,3.072998 24.294013,2.6170006 22.390996,2.3429985 20.12,2.2509995 18.580998,2.3590012 17.940007,2.6829987 17.868993,3.0900002 17.868993,26.970001 18.048009,28.272003 18.58701,29.113998 19.659001,29.697998 21.437016,30.227997 22.149999,30.389 22.467015,30.490997 22.707005,31.401001 22.179997,32 21.910008,31.994003 21.198003,31.928001 15.424992,31.640999 10.755008,31.879997 9.4850186,31.879997 9.1740131,31.305 9.2879972,30.665001 10.011996,30.275002 11.737002,29.695 12.791018,29.005997 13.401005,27.909996 13.605015,26.298996 13.605015,3.0900002 13.390018,2.5390015 12.743014,2.2750015 12.342013,2.2579994 11.329989,2.2509995 7.3779925,2.6469994 4.6229872,3.8320007 3.0840158,5.4970016 1.7250066,8.1439972 1.2399907,8.7959976 0.598999,8.7900009 0.041992187,8.4729996 0,7.9039993 0.62899778,4.7839966 0.83898971,0.59899902 1.2040105,0.20999908 2.2999882,0.14400101 7.7489947,0.39500046 13.748997,0.47900009 19.16602,0.44900131 23.539008,0.35900116 26.867011,0.20999908z"
}
}
]
Here is the output:
I can handle that with overflow: visible in css. But I dont want to do it because then i will get problems with height and width, which will lead me to incorrect centering using flexbox.
Here is codesandbox that reproduces the issue:
Click here for code sandbox
Basically if you want to fit SVG into a container you need to set the viewBox attribute to exact values of its content. In this case, from the points in the d attributes you can see that it's 0 0 32 32 (as in: x, y, width, height).
Then you can resize the SVG using the width and height attributes to stretch/shrink to the container you want it to fit into (taking into account aspect ratio, of course).
If you don't know the right value of viewBox for a given SVG, and you don't have strokes - like the examples above, you can try using dev tools in the browser and call .getBBox() on the <svg> element, which will give you the x, y, width, and height to place in the viewBox.
In order to get the size of a path I've transformed yours icons in true svg
console.log(test.getBBox());
console.log(test1.getBBox())
<svg className="svg" width="24" height="24" viewBox="0 0 32 32" >
<g>
<path id="test"
d="M9.5999776,12.699997L11.899997,15.099998 13.299991,14.300003 19.000005,20 22.899999,18 28.299995,20.699997 28.299995,25.699997 3.5999767,25.699997 3.5999767,18.599998z M20.500005,11.699997L21.199987,11.699997 21.000005,12.800003 20.699987,12.800003z M23.09998,10.699997L23.799993,11.599998 23.59998,11.800003 22.699987,11.099998z M18.699987,10.699997L19.199987,11.199997 18.299993,11.900002 18.000005,11.599998z M23.59998,8.5999985L24.699987,8.8000031 24.699987,9 23.59998,9.1999969z M18.09998,8.5999985L18.09998,9.3000031 17.000005,9 17.000005,8.8000031z M20.799993,7C21.899999,7 22.699987,7.9000015 22.699987,8.9000015 22.699987,10 21.799993,10.800003 20.799993,10.800003 19.699987,10.800003 18.899999,9.9000015 18.899999,8.9000015 18.899999,7.8000031 19.799993,7 20.799993,7z M23.500005,6.0999985L23.699987,6.3000031 23.000005,7.1999969 22.500005,6.6999969z M18.199987,6.0999985L19.09998,6.8000031 18.59998,7.3000031 18.000005,6.3000031z M20.699987,5L21.000005,5 21.199987,6.0999985 20.500005,6.0999985z M2.1999823,2.4000015L2.1999823,26.800003 29.400001,26.800003 29.400001,2.4000015z M0,0L31.900001,0 31.900001,32 0,32z"
/>
</g>
</svg>
<hr>
<svg className="svg" width="24" height="24" viewBox="0 0 32 32" >
<g>
<path id="test1"
d="M29.15,0L30.186011,0.012001038 30.610999,0.43099976 31.096015,3.868 31.209998,7.8079987 31.101996,8.3949966 30.610999,8.6230011 29.875007,8.5510025 29.437018,7.9520035 28.312018,5.298996 26.993995,3.7130013 25.82801,3.072998 24.294013,2.6170006 22.390996,2.3429985 20.12,2.2509995 18.580998,2.3590012 17.940007,2.6829987 17.868993,3.0900002 17.868993,26.970001 18.048009,28.272003 18.58701,29.113998 19.659001,29.697998 21.437016,30.227997 22.149999,30.389 22.467015,30.490997 22.707005,31.401001 22.179997,32 21.910008,31.994003 21.198003,31.928001 15.424992,31.640999 10.755008,31.879997 9.4850186,31.879997 9.1740131,31.305 9.2879972,30.665001 10.011996,30.275002 11.737002,29.695 12.791018,29.005997 13.401005,27.909996 13.605015,26.298996 13.605015,3.0900002 13.390018,2.5390015 12.743014,2.2750015 12.342013,2.2579994 11.329989,2.2509995 7.3779925,2.6469994 4.6229872,3.8320007 3.0840158,5.4970016 1.7250066,8.1439972 1.2399907,8.7959976 0.598999,8.7900009 0.041992187,8.4729996 0,7.9039993 0.62899778,4.7839966 0.83898971,0.59899902 1.2040105,0.20999908 2.2999882,0.14400101 7.7489947,0.39500046 13.748997,0.47900009 19.16602,0.44900131 23.539008,0.35900116 26.867011,0.20999908z"
/>
</g>
</svg>
Then I've used the method .getBBox() to get the size of the bounding boxes for the two icons. In both cases the width and the height for the bounding box is almost 32 and the and the x and y is 0. I've changed the viewBox to x y w h i.e 0 0 32 32. This will scale down the image inside the svg, while the width and the height of the svg element stays at 24/24

Complex SVG clip-path responsive

I'm trying to take a complex path shape and apply it as a clip-path mask in css, but I can't figure out how to get the clip mask to "fill" the parent container.
Rather it just gets cut off or doesn't expand to fill the available space.
If I add clipPathUnits="objectBoundingBox" it doesn't appear at all.
<svg viewBox="0 0 720 720">
<defs>
<clipPath id="map">
<path d="M568.421 326.842L511.579 270v37.895h-18.947v-18.948h-56.843v37.895l18.948 37.894v18.948h-18.948l37.896 56.842h-37.896l-18.947-18.948v-18.947h-37.895L360 383.684h-18.947l-18.948-37.894v-37.895L360 270l37.895-37.895-18.948-37.895H360v18.948l-18.947-18.948h-18.948v37.895h-37.894l-56.843-18.947-37.894-56.842h-56.842l-18.947-18.948-75.79 75.79v37.895h18.947v75.789L37.895 345.79l5.532 48.163 32.362 46.573 113.685 37.895 94.737 18.947h94.736v-18.947h37.895l18.947 37.895h18.948v56.842l56.842-37.894v-37.896h37.895l18.947-37.894v-37.896l56.842-37.894V345.79l-18.948-18.948z"/><path d="M246.315 194.21h56.843v-18.947l-18.947-37.895h-18.948v37.895h-18.948zM227.368 137.368h18.947v-18.947h-37.894V156.316h18.947zM341.053 175.263h56.842l37.894 37.895-18.947 18.947V270h75.79v-18.947h-37.895v-18.948h37.895V194.21h-37.895l-56.842-56.842h-56.842zM265.263 99.474h18.948v18.947h-18.948zM284.211 61.579h18.947v18.948h-18.947zM303.158 108.947h18.947v18.947h-18.947zM341.053 99.474h37.895v18.947h-37.895zM227.368 80.526h18.947v18.947h-18.947zM378.947 80.526V4.737H360l-37.895 37.894v18.948l18.948 18.947zM587.368 440.526h37.895v37.895h-37.895zM663.158 364.736V345.79h-18.947V402.631l56.842-18.947v-18.948zM378.947 270h18.947v18.947h-18.947zM644.211 421.578h18.947v18.948h-18.947zM644.211 459.474h18.947v18.947h-18.947z"/>
</clipPath>
</defs>
</svg>
https://codepen.io/picard102/pen/aEwJzR
As Robert said, when you specify clipPathUnits="objectBoundingBox", the coordinates in the clip path definition are supposed to be between 0,0 (the top left) and 1,1 (the bottom right).
Your paths are about 700x575, so your path is about 600 to 700 times too big.
The simplest solution is to add a transform attribute to your <clipPath> that scales the coordinates down to the correct range.
<clipPath id="map" clipPathUnits="objectBoundingBox" transform="scale(0.00143, 0.00174)">
1/700 ~= 0.00143
1/575 ~= 0.00174
https://codepen.io/anon/pen/GyvZOM

How to make a SVG diagram not truncate overflowing shapes?

I have the following SVG shape which is created programmatically.
<svg style="overflow:visible; margin-left:121px; margin-top:39px; " height="206" width="327">
<path d=" M 244.3,102.7 A 82.3,52 0,0 0,82.3 102.7 L 1.3,102.7 A 163.3,102.7 0,0 1,325.3 102.7 L 325.3,102.7 365.8,102.7 284.8,153.3 203.8,102.7 244.3,102.7 L 244.3,102.7 " x="1.5" y="1.5" style="fill:#92d050; stroke-width:3; stroke:blue; "></path>
</svg>
The fiddle for the above is : http://fiddle.jshell.net/VJL5W/
As one can see the right tip of the arrow is truncated because its path coordinates move outside the dimensions of the SVG.
One thing I can do is to traverse the path of the shape after it has been created and change the height and width of the svg tag according to the highest coordinate values I find, but it will make my code inefficient.
I tried overflow:visible; but it didn't work.
Is there anyway I can make the truncated part visible without changing the SVG's height and width?
Thanx in advance!!
Note: Interestingly overflow:visible is working on firefox but not in chrome based browsers. Also, my SVG is being created server-side from a corresponding VML image in a single parse conversion, so solutions that involve using any client side script can't be used by me.
You can wrap the svg element with a div element, and set styles to the div element, then enlarge the svg size enough to render whole graphic.
<div style="overflow:visible; margin-left:121px; margin-top:39px; height:206px; width:327px;">
<svg height="206px" width="500px">
<path d=" M 244.3,102.7 A 82.3,52 0,0 0,82.3 102.7 L 1.3,102.7 A 163.3,102.7 0,0 1,325.3 102.7 L 325.3,102.7 365.8,102.7 284.8,153.3 203.8,102.7 244.3,102.7 L 244.3,102.7 " x="1.5" y="1.5" style="fill:#92d050; stroke-width:3; stroke:blue; "></path>
</svg>
</div>
document.getElementsByTagName("path")[0].getBBox() will get the bounds of the path (x, y, width, height) you can use those to set the <svg> element width and height.
Use the viewBox attribute of SVG. The viewBox tells the SVG is to take all the image that is being drawn within the viewBox and then apply width and height to it.
Fiddle here
<svg style="overflow:visible; margin-left:121px; margin-top:39px; " height="206" width="327" viewBox="0 0 300 300">
<path d=" M 244.3,102.7 A 82.3,52 0,0 0,82.3 102.7 L 1.3,102.7 A 163.3,102.7 0,0 1,325.3 102.7 L 325.3,102.7 365.8,102.7 284.8,153.3 203.8,102.7 244.3,102.7 L 244.3,102.7 " x="1.5" y="1.5" style="fill:#92d050; stroke-width:3; stroke:blue; "></path>
</svg>
Adding this to Chrome seems make it work but I am not sure if your layout can accommodate wider SVG. Have not tried in IE.
svg {
width:100%;
}

Resources