How to make svg fit container in React? - javascript

See the image above. That is the svg container I have highlighted but I only want the svg to take up it's actual size (i.e. just the inner white triangle)
I've tried changing parent width and height but nothing seems to work. how do I fix this?
this is the markup:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="#fff">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M12 16l-6-6h12z"></path>
</svg>
the second path seems to be the exact width and height of what I need
second edit:
export const Icon = ({ name }) => {
let Icon: any = icons[name]
return (
<div
className={css`
display: flex;
align-items: center;
`}
>
<Icon height={24} fill="red" />
</div>
)
}
and icons is
import { ReactComponent as MyIcon } from "./my-icon.svg"
const icons = {
"my-icon": MyIcon
}

M12 16l-6-6h12z represents your triangle and means
move to the point with coordinates 12 16
then draw the line to -6 -6 (relatively to current point)
then draw the horizontal line with the length equals to 12 then
to go the first point
And you get your icon as the result.
There are several ways you can fit the path, but you should understand how a path works. You can read about it here.
And see examples below
First way to fit:
svg {
border: 1px solid red;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="#red">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M 12 24 l -12 -24 h24 z"></path>
</svg>
Second:
svg {
border: 1px solid red;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="#red">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M 12 12 l -12 -12 h24 z"></path>
</svg>

You can see from the SVG that the width and height are currently set to 24.
A good start would be to set the width and height to 1em to better match the font size. See first example in the demo below.
If you feel the triangle is too small now, you can make it appear bigger by adjusting the viewBox. At the moment it has quite a bit of padding around it. To shring that padding, increase the viewBox x and y (first two numbers) and reduce the width and height (second two numbers. In the second example below, I have shrunk the padding by 3 units all around the icon by increasing the x and y by 3, and reducing the width and height, by 2 * 3 correspondingly.
The icon is now bigger compared to the text, But it can appear a bit high now.
There are a few ways to adjust that. Including the following:
Use position: relative and top: 2px to push the <svg> down a bit.
Reduce the icon size to something like 0.7em, so that the icon matches better the X height of the font, rather than the full Em height.
Use a different vertical-align setting to adjust the position of the icon relative to the rest of the line. In example 3 below, I have set the icon to vertical-align: text-top.
Push the icon lower in the viewBox by increasing the padding at the top of the viewBox. In example 4 below I've reduced the viewBox y (second number) to increase the top padding.
body {
background-color: dodgerblue;
}
div {
font: 16px sans-serif;
color: white;
}
svg {
width: 1em;
height: 1em;
}
<div>
Show
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="#fff">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M12 16l-6-6h12z"></path>
</svg>
</div>
<div>
Show
<svg xmlns="http://www.w3.org/2000/svg" viewBox="3 3 18 18" width="24" height="24" fill="#fff">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M12 16l-6-6h12z"></path>
</svg>
</div>
<div>
Show
<svg xmlns="http://www.w3.org/2000/svg" viewBox="3 3 18 18" width="24" height="24" fill="#fff" style="vertical-align: text-top">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M12 16l-6-6h12z"></path>
</svg>
</div>
<div>
Show
<svg xmlns="http://www.w3.org/2000/svg" viewBox="3 1 18 18" width="24" height="24" fill="#fff">
<path fill="none" d="M0 0h24v24H0z"></path>
<path d="M12 16l-6-6h12z"></path>
</svg>
</div>

Related

Add svg on exists path

I had an exsits path that represent line with arrow:
<path {...lineProps} id={id} />
it looks like:
is there a chance to add the next svg in the middle of the current link:
<svg width="32" height="18" viewBox="0 0 32 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="32" height="18" rx="9" fill="#F8788F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.6531 10.9423L12 9.28917L10.3468 10.9423L10.0577 10.6532L11.7109 9.00003L10.0577 7.34693L10.3468 7.05784L12 8.71094L13.6531 7.05784L13.9421 7.34693L12.289 9.00003L13.9421 10.6532L13.6531 10.9423Z" fill="#FEFEFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.6531 11.4001L12 9.74695L10.3468 11.4001L9.59993 10.6532L11.2531 9.00003L9.59992 7.34693L10.3468 6.60006L12 8.25316L13.6531 6.60006L14.3999 7.34693L12.7468 9.00003L14.3999 10.6532L13.6531 11.4001ZM12.289 9.00003L13.9421 7.34693L13.6531 7.05784L12 8.71094L10.3468 7.05784L10.0577 7.34693L11.7109 9.00003L10.0577 10.6532L10.3468 10.9423L12 9.28917L13.6531 10.9423L13.9421 10.6532L12.289 9.00003Z" fill="#FEFEFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0001 13.7081C13.3154 13.1808 14.0955 12.8115 14.6823 11.926C15.302 10.9909 15.7984 9.31606 15.8863 5.9205C14.5265 5.74148 13.1976 5.26052 12.0002 4.4796C10.8027 5.26052 9.4738 5.74148 8.11402 5.9205C8.20188 9.31606 8.69829 10.9909 9.31803 11.926C9.90483 12.8115 10.6849 13.1808 12.0001 13.7081ZM11.7768 14.911C11.9199 14.968 12.0804 14.968 12.2235 14.911L12.2434 14.9031C15.0408 13.7903 16.9994 13.0112 17.0964 5.40383C17.1006 5.07248 16.8312 4.80237 16.5007 4.77785C15.0545 4.67052 13.6299 4.17427 12.3834 3.2891C12.1546 3.12662 11.8457 3.12662 11.6169 3.2891C10.3705 4.17427 8.94583 4.67052 7.49961 4.77785C7.16914 4.80237 6.8997 5.07248 6.90392 5.40383C7.00086 13.0112 8.95954 13.7903 11.7569 14.9031L11.7768 14.911Z" fill="#FEFEFF"/>
</svg>
it looks like:
eventually it should look like:
As #AKX commented you need to find the point in the middle of the path. You can do it using the getTotalLength and getPointAtLength methods.
As for the tag you can put it inside a symbol and use the symbol with <use>. The use element can take an x and y attributes, the x and y of the point in the middle of the path. In order to center the use element around the point you need also to translate the use element backward half width and height
//the path length
let l = thePath.getTotalLength();
//the point in the middle of the path
let p = thePath.getPointAtLength(l/2);
//set the x andy attributes in the middle of the path
theUse.setAttribute("x", p.x);
theUse.setAttribute("y", p.y);
<svg viewBox="0 0 300 200" width="300">
<symbol viewBox="0 0 32 18" fill="none" id="s">
<rect width="32" height="18" rx="9" fill="#F8788F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.6531 10.9423L12 9.28917L10.3468 10.9423L10.0577 10.6532L11.7109 9.00003L10.0577 7.34693L10.3468 7.05784L12 8.71094L13.6531 7.05784L13.9421 7.34693L12.289 9.00003L13.9421 10.6532L13.6531 10.9423Z" fill="#FEFEFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.6531 11.4001L12 9.74695L10.3468 11.4001L9.59993 10.6532L11.2531 9.00003L9.59992 7.34693L10.3468 6.60006L12 8.25316L13.6531 6.60006L14.3999 7.34693L12.7468 9.00003L14.3999 10.6532L13.6531 11.4001ZM12.289 9.00003L13.9421 7.34693L13.6531 7.05784L12 8.71094L10.3468 7.05784L10.0577 7.34693L11.7109 9.00003L10.0577 10.6532L10.3468 10.9423L12 9.28917L13.6531 10.9423L13.9421 10.6532L12.289 9.00003Z" fill="#FEFEFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0001 13.7081C13.3154 13.1808 14.0955 12.8115 14.6823 11.926C15.302 10.9909 15.7984 9.31606 15.8863 5.9205C14.5265 5.74148 13.1976 5.26052 12.0002 4.4796C10.8027 5.26052 9.4738 5.74148 8.11402 5.9205C8.20188 9.31606 8.69829 10.9909 9.31803 11.926C9.90483 12.8115 10.6849 13.1808 12.0001 13.7081ZM11.7768 14.911C11.9199 14.968 12.0804 14.968 12.2235 14.911L12.2434 14.9031C15.0408 13.7903 16.9994 13.0112 17.0964 5.40383C17.1006 5.07248 16.8312 4.80237 16.5007 4.77785C15.0545 4.67052 13.6299 4.17427 12.3834 3.2891C12.1546 3.12662 11.8457 3.12662 11.6169 3.2891C10.3705 4.17427 8.94583 4.67052 7.49961 4.77785C7.16914 4.80237 6.8997 5.07248 6.90392 5.40383C7.00086 13.0112 8.95954 13.7903 11.7569 14.9031L11.7768 14.911Z" fill="#FEFEFF"/>
</symbol>
<marker id="mk" viewBox="0 0 4 4" markerWidth="4" markerHeight="4" refX="0" refY="2" orient="auto-start-reverse">
<polygon points="0,0 4,2 0,4" fill="black" />
</marker>
<path id="thePath" d="M10,10 L270,160" stroke="black" stroke-width="4" stroke-dasharray="5" marker-end="url(#mk)" />
<use id="theUse" xlink:href="#s" width="32" height="18" transform="translate(-16,-9)" />
<svg>

change the filled color of an SVG image in react

I'm trying the control the filled level of an oval SVG.
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" fill="grey">
<g>
<g>
<path d="M256,0C114.837,0,0,114.837,0,256s114.837,256,256,256s256-114.837,256-256S397.163,0,256,0z M256,490.667
c-129.387,0-234.667-105.28-234.667-234.667S126.613,21.333,256,21.333S490.667,126.613,490.667,256S385.387,490.667,256,490.667z
"/>
</g>
i started to just trying to fill the oval to 100% and it'snot working.
<Card sx={{ maxWidth: 345 }}>
<CardHeader
}
...
<div>
<img src={OvalTank} style={Style} alt="Oval Tank" className=" ovalFilled" />
</div>
Style being set this way
const Style = {
height: 200,
margin: 'auto',
display: 'flex',
justifyContent: 'center',
fill: blue,
}
I try removing the fill attribute from the svg file(which is controlling the border color only).
can someone help to find out how to control filled color?
thanks
With some adjustments in your svg markup, you could place your svg assets by a <use> element.
Your svg element will need a an id for referencing.
I recommend wrapping your graphic in a <symbol> element like so:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<symbol id="path">
<path d="M256,0C114.837,0,0,114.837,0,256s114.837,256,256,256s256-114.837,256-256S397.163,0,256,0z M256,490.667
c-129.387,0-234.667-105.28-234.667-234.667S126.613,21.333,256,21.333S490.667,126.613,490.667,256S385.387,490.667,256,490.667z" />
</symbol>
</svg>
Now you're able to place an instance of your image by a reference:
<svg viewBox="0 0 512 512" style="fill:red">
<use href="ovalTank.svg#path" />
</svg>
Since we've stripped all fill attributes, we can style/override colors for every symbol instance.
The main benefit of this symbol/use approach is the idea of storing multiple graphic assets in one single svg file.
However, loading symbols from a external file will need this file to be on same domain.
Here is an inlined svg example:
svg {
display: inline-block;
width: 5em;
}
<!-- svg file content -->
<svg style="display:none;" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512">
<symbol id="path">
<path d="M256,0C114.837,0,0,114.837,0,256s114.837,256,256,256s256-114.837,256-256S397.163,0,256,0z M256,490.667
c-129.387,0-234.667-105.28-234.667-234.667S126.613,21.333,256,21.333S490.667,126.613,490.667,256S385.387,490.667,256,490.667z" />
</symbol>
<symbol id="icon-calendar" viewBox="0 0 448 512">
<path d="M152 64H296V24C296 10.75 306.7 0 320 0C333.3 0 344 10.75 344 24V64H384C419.3 64 448 92.65 448 128V448C448 483.3 419.3 512 384 512H64C28.65 512 0 483.3 0 448V128C0 92.65 28.65 64 64 64H104V24C104 10.75 114.7 0 128 0C141.3 0 152 10.75 152 24V64zM48 448C48 456.8 55.16 464 64 464H384C392.8 464 400 456.8 400 448V192H48V448z" />
</symbol>
</svg>
<!-- usage -->
<svg viewBox="0 0 512 512" style="fill:red">
<use href="#path" />
</svg>
<svg viewBox="0 0 448 512" style="fill:green">
<use href="#icon-calendar" />
</svg>

Dynamically generate SVG with images inside?

AngularJS app.
Basically I've to make an horizontal arrow-like drawing with images that will be repeating inside depending on the array of items i sent to the html(ng-repeat).
I got told the best would be svg so here I am, but my knowledge of svg is pretty low. So I managed to make a little arrow with fixed witdh and height. But now I need it a lot bigger.
So I read about viewBox online. It scales the items I have in the SVG, but I have two problems so far.
Images don't work.
All items are stacked up and don't follow the space in between them that I had before.
This code is the working code I have right now, so you get an idea of the element I'm trying to draw. I use the element so I can ng-repeat it with tooltips and text inside, this code is simplified.
.container {
display: flex;
}
.justaclass {
fill: #9b3d9c;
background-color: #9b3d9c;
}
.justaclass-group {
display: inline-block;
position: relative;
}
.justaclass-image {
padding: 2px;
}
<div class="container">
<svg width="8" height="34">
<path class="justaclass"
d="M 0 0 L 7 17 L 0 34 L 17 34 L 17 0 z">
</path>
</svg>
<svg width="33" height="34" class="justaclass justaclass-image">
<image x="0" y="3" width="33" height="25" href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"></image>
</svg>
<div class="justaclass-group">
<svg width="50" height="34" class="justaclass image">
<image width="45" height="30"
x="0" y="0"
href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg">
</image>
</svg>
<svg width="10" height="34">
<path class="justaclass"
d="M 0 0 L 0 34 L 10 17 z">
</path>
</svg>
</div>
The code isn't perfect pixel-wise here, but that's not my main issue.
Now that I try to make it bigger with viewBox, I can draw the 4 elements but they are misplaced. So If I add display:flex or display:table I quite cannot get the elements aligned horizontally, the elements just disappear.
Anyone got any idea of how to dinamically resize all this elements plus making them all in the same line just like display flex would do?
My first try at doing the above image with viewBox
But If I add display:flex into the container, the svg's are gone and I only see images.
.container {}
.justaclass {
fill: #9b3d9c;
background-color: #9b3d9c;
}
<div class="container">
<svg viewBox="0 0 150 50">
<path class="justaclass"
d="M 0 0 L 7 17 L 0 34 L 17 34 L 17 0 z">
</path>
</svg>
<svg viewBox="0 0 150 50">
<image width="150" height="50" href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"></image>
</svg>
<svg viewBox="0 0 150 50">
<image width="150" height="50" href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"></image>
</svg>
<svg viewBox="0 0 150 50">
<path class="justaclass"
d="M 0 0 L 0 34 L 10 17 z">
</path>
</svg>
</div>
There are a lot of things that need to change here. First lets talk about viewBox. This attribute describes how the numbers inside the <svg> tag relate to those outside. It gives a rectangle into which the inside content is rendered. Then, this rectangle is scaled such that it fits into the size given by width and height. That means, giving a viewBox without also defining width and height makes not much sense, as the size the content should be scaled to is missing.
What happens if the aspect ratio of the viewBox and that of the width and height do not match? As a default, the content is set into the middle and scaled such that it just fits. Other values can be given with the preserveAspectRatio attribute. For example, to get the left "arrow" part to the right of its rectangle (so there is no gap), set preserveAspectRatio="xMaxYMid meet".
width and height can be given as attributes for SVG content or as CSS properties. It makes sense to define them as styles if they are to be changeable.
Your linked images do not need to have a concrete size. Giving them width="100%" height="100%" scales them to the containing SVG element, without distorting them (unless you define so with preserveAspectRatio="none".
.container {
display: flex;
}
.container svg {
width: 50px;
height: 50px;
}
.container .justaclass {
fill: #9b3d9c;
background-color: #9b3d9c;
width: 150px;
}
<div class="container">
<svg width="50" height="50" viewBox="0 0 8 34" preserveAspectRatio="xMaxYMid meet">
<path
d="M 0 0 L 7 17 L 0 34 L 17 34 L 17 0 z">
</path>
</svg>
<svg class="justaclass">
<image width="100%" height="100%" href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"></image>
</svg>
<svg class="justaclass">
<image width="100%" height="100%" href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"></image>
</svg>
<svg viewBox="0 0 10 34" preserveAspectRatio="xMinYMid meet">
<path
d="M 0 0 L 0 34 L 10 17 z">
</path>
</svg>
</div>
viewBox defines the size of the contents of the svg before being scaled. You need to set them to the original size of your image and then scale the elements up either with the width and height tags you used before or with css. Here's a fiddle of everything scaled up to double size: https://jsfiddle.net/ohnqbufa/
You can see here that the viewport of your first element is set to the original size and the width and height are set to double.
<svg width="16" height="68" viewBox="0 0 8 34">
<path class="justaclass"
d="M 0 0 L 7 17 L 0 34 L 17 34 L 17 0 z">
</path>
</svg>

How can I make this SVG adapt to viewport size without scaling?

I finally dared to start on a small, first project I was thinking about for a while after taking a few courses on full-stack developement and a little bit of design.
This small sketch represents how I would like my navigation to look.
The problem I'm facing is that I don't know how I would make the SVG Path that underlines the nav scale like I want it to (The little ECG thingy should move without being squished while the lines next to it get smaller, check the picture to see what I mean).
This is the SVG Code:
<svg width="1440px" height="63px" viewBox="0 0 1440 63" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.1 (51147) - http://www.bohemiancoding.com/sketch -->
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Desktop-HD" transform="translate(0.000000, -20.000000)" stroke="#000000">
<path d="M0,75 L684.996099,75 C686.664718,71.6666667 688.332684,70 690,70 C691.667316,70 693.333982,71.6666667 695,75 L712.215347,75 L715,82.3654775 L720,20 L725,78.2084488 L726.833442,75 L745,75 C748.15577,68.3333333 751.489104,65 755,65 C758.510896,65 761.84423,68.3333333 765,75 L1440,75" id="Path-3"></path>
</g>
</g>
Do you guys have any idea on how to approach this?
As I commented above you can keep your element with a fixed big width and center it within the container and make it overflowing:
.container {
display: flex;
justify-content: center;
overflow: hidden;
}
svg {
width: 1440px;
height: 63px;
}
<div class="container">
<div>
<svg width="1440px" height="63px" viewBox="0 0 1440 63" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.1 (51147) - http://www.bohemiancoding.com/sketch -->
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Desktop-HD" transform="translate(0.000000, -20.000000)" stroke="#000000">
<path d="M0,75 L684.996099,75 C686.664718,71.6666667 688.332684,70 690,70 C691.667316,70 693.333982,71.6666667 695,75 L712.215347,75 L715,82.3654775 L720,20 L725,78.2084488 L726.833442,75 L745,75 C748.15577,68.3333333 751.489104,65 755,65 C758.510896,65 761.84423,68.3333333 765,75 L1440,75" id="Path-3"></path>
</g>
</g>
</svg>
</div>
</div>

svg - draw hollow rectangle(rect donut)?

Can anybody help me with drawing hollow rectangle with svg WITHOUT using any js lib(e.g. Raphael)?
In basic, it should be same idea as "donut shape" but rectangle.
something like this:
Here you go
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 2624 1462" width="1312" height="736" id="svg2">
<path d="M 80,112 l 528,0 0,528 -528,0 z m -64,-64.000003 656,0 0,656.000023 -656,0 z" fill="gold" stroke="black" fill-rule="evenodd" />
</svg>
The path winds in one direction outside and the other inside and the evenodd fill-rule cuts out the middle.
Here's an example:
<svg viewBox="0 0 400 400" shape-rendering="crispEdges">
<path d="M10,10h100v100h-100zM20,20v80h80v-80z" fill="yellow" stroke="black"/>
</svg>

Categories