How can I import a png image into a nextJS svg component.
This is the sample code I'm working with.
<Page title="Logo Designer" className="max-w-xl">
<div>
<svg id="logoDesigner" width={700} height={600} style={{ backgroundColor: 'lightgray' }}>
<rect class="draggable" x="4" y="5" width="80" height="100" fill="#007bff" />
<rect class="draggable" x="18" y="5" width="80" height="400" fill="#888" />
</svg>
</div>
</Page>
you can use the image tag
<image
width="100"
height="100"
xlink:href="my-logo.png"
/>
make sure to change the width height and xlink:href based on your need
I'm using create-content-loader package for creating placeholder loading but can't make it responsive.
How to make svg fill parent content. I don't want to set width hardcoded 1060px. I tried with viewbox property too.
<ContentLoader
height={40}
width={1060}
speed={2}
primaryColor="#d9d9d9"
secondaryColor="#ecebeb"
>
<rect x="10" y="40" rx="0" ry="0" width="75" height="10" />
<rect x="10" y="60" rx="0" ry="0" width="75" height="10" />
<rect x="10" y="100" rx="0" ry="0" width="75" height="10" />
<rect x="10" y="80" rx="0" ry="0" width="75" height="10" />
<rect x="10" y="120" rx="0" ry="0" width="75" height="10" />
<rect x="110" y="40" rx="0" ry="0" width="370" height="125" />
<rect x="275" y="63" rx="0" ry="0" width="72" height="4" />
<rect x="430" y="5" rx="5" ry="5" width="75" height="20" />
<rect x="110" y="10" rx="0" ry="0" width="200" height="15" />
<rect x="10" y="5" rx="4" ry="4" width="75" height="20" />
<circle cx="493" cy="54" r="2" />
<circle cx="497" cy="47" r="7" />
<circle cx="497" cy="77" r="7" />
<circle cx="497" cy="107" r="7" />
</ContentLoader>```
ContentLoader uses html5 canvas for rendering, so viewbox won't work. What I would do is:
add ref to container element (which holds ContentLoader).
get that element width by using ref
pass that value to the ContentLoader width prop.
Keep in mind that on the first render ref.current will be null or undefined
Update:
Also you can try to extract svg from create-content-loader example and turn it into your component. Just change svg attributes to match rect related svg props. Than set css class on svg to have these properties:
.responsive-svg {
width: 100%;
height: auto;
}
Svg (before you turn it into react component) might look something like this:
<svg
role="img"
width="400"
height="160"
aria-labelledby="loading-aria"
viewBox="0 0 400 160"
preserveAspectRatio="none"
>
<title id="loading-aria">Loading...</title>
<rect
x="0"
y="0"
width="100%"
height="100%"
clip-path="url(#clip-path)"
style='fill: url("#fill");'
></rect>
<defs>
<clipPath id="clip-path">
<rect x="48" y="8" rx="3" ry="3" width="88" height="6" />
<rect x="48" y="26" rx="3" ry="3" width="52" height="6" />
<rect x="0" y="56" rx="3" ry="3" width="410" height="6" />
<rect x="0" y="72" rx="3" ry="3" width="380" height="6" />
<rect x="0" y="88" rx="3" ry="3" width="178" height="6" />
<circle cx="20" cy="20" r="20" />
</clipPath>
<linearGradient id="fill">
<stop
offset="0.599964"
stop-color="#f3f3f3"
stop-opacity="1"
>
<animate
attributeName="offset"
values="-2; -2; 1"
keyTimes="0; 0.25; 1"
dur="2s"
repeatCount="indefinite"
></animate>
</stop>
<stop
offset="1.59996"
stop-color="#ecebeb"
stop-opacity="1"
>
<animate
attributeName="offset"
values="-1; -1; 2"
keyTimes="0; 0.25; 1"
dur="2s"
repeatCount="indefinite"
></animate>
</stop>
<stop
offset="2.59996"
stop-color="#f3f3f3"
stop-opacity="1"
>
<animate
attributeName="offset"
values="0; 0; 3"
keyTimes="0; 0.25; 1"
dur="2s"
repeatCount="indefinite"
></animate>
</stop>
</linearGradient>
</defs>
</svg>
Here's one of my original SVG:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<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 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g>
<path class="st0" d="M34.2,19h-4l-0.6-2.5c-0.2-0.9-1-1.5-1.9-1.5h-3.9c-0.9,0-1.7,0.6-1.9,1.5L21.3,19h-4c-1.7,0-3,1.3-3,3v12
c0,0.6,0.4,1,1,1h21c0.6,0,1-0.4,1-1V22C37.2,20.3,35.9,19,34.2,19z"/>
<rect x="17.2" y="17" class="st0" width="2" height="2"/>
<path class="st0" d="M27.2,19h-3c-0.6,0-1-0.4-1-1l0,0c0-0.6,0.4-1,1-1h3c0.6,0,1,0.4,1,1l0,0C28.2,18.6,27.8,19,27.2,19z"/>
<circle class="st0" cx="25.7" cy="27.5" r="5.5"/>
<circle class="st0" cx="25.7" cy="27.5" r="3.5"/>
<circle class="st0" cx="34.2" cy="22" r="1"/>
<path class="st0" d="M17.2,35V24c0-0.6-0.4-1-1-1h-2"/>
</g>
</svg>
Open it in a browser like Safari, and the image shows correctly:
Now I'm creating an SVG containing two SVGs using defs and symbol - one of them is the one I've shown here above, the other is a similar one:
<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">
<defs>
<symbol viewBox="0 0 50 50" id="videographer">
<style type="text/css">
.st0{fill:none;stroke:#010101;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g>
<circle class="st0" cx="21" cy="19.5" r="2.5"/>
<circle class="st0" cx="26" cy="19.5" r="2.5"/>
<polyline class="st0" points="33.5,27.8 37.5,31 37.5,23 33.5,26.2 "/>
<rect x="30.5" y="25" class="st0" width="3" height="4"/>
<rect x="14.5" y="24" class="st0" width="2" height="6"/>
<rect x="16.5" y="22" class="st0" width="14" height="10"/>
</g>
</symbol>
<symbol viewBox="0 0 50 50" id="photographer">
<style type="text/css">
.st0{fill:none;stroke:#010101;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g>
<path class="st0" d="M34.2,19h-4l-0.6-2.5c-0.2-0.9-1-1.5-1.9-1.5h-3.9c-0.9,0-1.7,0.6-1.9,1.5L21.3,19h-4c-1.7,0-3,1.3-3,3v12
c0,0.6,0.4,1,1,1h21c0.6,0,1-0.4,1-1V22C37.2,20.3,35.9,19,34.2,19z"/>
<rect x="17.2" y="17" class="st0" width="2" height="2"/>
<path class="st0" d="M27.2,19h-3c-0.6,0-1-0.4-1-1l0,0c0-0.6,0.4-1,1-1h3c0.6,0,1,0.4,1,1l0,0C28.2,18.6,27.8,19,27.2,19z"/>
<circle class="st0" cx="25.7" cy="27.5" r="5.5"/>
<circle class="st0" cx="25.7" cy="27.5" r="3.5"/>
<circle class="st0" cx="34.2" cy="22" r="1"/>
<path class="st0" d="M17.2,35V24c0-0.6-0.4-1-1-1h-2"/>
</g>
</symbol>
</defs>
</svg>
My React code to import that SVG and render it...
import VendorIcons from '../../images/vendor_icons.svg';
const VendorIcon = props => {
return (
<svg version="1.1" id="Layer_1" x="0px" y="0px"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink">
<use xlinkHref={`${VendorIcons}#${props.icon}`} />
</svg>
)
};
Code to render it:
<VendorIcon icon={"videographer"}/>
And this is how it renders, without style:
Why is this happening? why is the style lost? Can this be fixed?
It should work fine if you have change the styles in vendor_icons.svg to presentation attributes rather than CSS in a style tag. It looks like you are using Adobe Illustrator, so you should be able to change the SVG export settings to do this for you. The result will be something like:
<symbol viewBox="0 0 50 50" id="videographer">
<g>
<circle fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" cx="21" cy="19.5" r="2.5"/>
<circle fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" cx="26" cy="19.5" r="2.5"/>
<polyline fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" points="33.5,27.8 37.5,31 37.5,23 33.5,26.2 "/>
<rect x="30.5" y="25" fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" width="3" height="4"/>
<rect x="14.5" y="24" fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" width="2" height="6"/>
<rect x="16.5" y="22" fill="none" stroke="#010101" stroke-linecap="round" stroke-width="0.75" width="14" height="10"/>
</g>
</symbol>
Result using the component as you’ve written it:
Can anyone help me identify why my text is not rendering in the defined path #textPath03 ? The path is rendered as supposed, but when I put it inside a <defs> and try to use it, it doesn`t work.
<svg version="1.1" height="700" width="700" viewBox="-5 -5 110 110" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-reactid="13">
<defs data-reactid="14">
<path id="#textPath03" d="M95,50 A45,45 0 0 0 50,5" data-reactid="15"></path>
</defs>
<line x1="50" y1="50" x2="100" y2="50" stroke="black" data-reactid="16"></line>
<line x1="50" y1="50" x2="50" y2="0" stroke="black" data-reactid="17"></line>
<path d="M90,50 A40,40 0 0 0 50,10" fill="none" stroke="green" data-reactid="18"></path>
<use xlink:href="#textPath03" fill="none" stroke="red" data-reactid="19"></use>
<text x="2" y="40%" font-size="20" data-reactid="20">
<textPath xlink:href="#textPath03" data-reactid="21">Teste</textPath>
</text>
</svg>
This is a REACT rendered SVG.
Thanks!!
The path id contains an extraneous # character. Only the reference to the path should have that. Removing it fixes your example...
<svg version="1.1" height="700" width="700" viewBox="-5 -5 110 110" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-reactid="13">
<defs data-reactid="14">
<path id="textPath03" d="M95,50 A45,45 0 0 0 50,5" data-reactid="15"></path>
</defs>
<line x1="50" y1="50" x2="100" y2="50" stroke="black" data-reactid="16"></line>
<line x1="50" y1="50" x2="50" y2="0" stroke="black" data-reactid="17"></line>
<path d="M90,50 A40,40 0 0 0 50,10" fill="none" stroke="green" data-reactid="18"></path>
<use xlink:href="#textPath03" fill="none" stroke="red" data-reactid="19"></use>
<text x="2" y="40%" font-size="20" data-reactid="20">
<textPath xlink:href="#textPath03" data-reactid="21">Teste</textPath>
</text>
</svg>
I'm trying to create an angular (1.5.5) directive where the template is an svg element. I read this answer, and several others, but I'm not able to get my simple svg element to show.
I have tried to simplify it as much as possible. So this simple directive should draw a circle when used inside a svg element, at least that is what I'm trying to achieve.
app.directive("svg01", () => {
return {
templateNamespace: "svg",
template: `
<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="green" />
`
//template: `
// <svg width="100" height="100">
// <circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="white" />
// </svg>
//`
}
});
This does not show the circle with this html
<div style="height: 100px; background-color: lightgreen">
<svg width="100" height="100">
<svg01></svg01>
</svg>
</div>
if instead I change the directive to include the svg element, then it shows (since this is now an html element I assume)
app.directive("svg01", () => {
return {
templateNamespace: "svg",
//template: `
// <circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="green" />
//`
template: `
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="white" />
</svg>
`
}
});
<div style="height: 100px; background-color: lightgreen">
<svg01></svg01>
</div>
And it doesn't matter if I set the templateNamespace to "html" or "svg". It shows in either case.
Is it not possible to define an svg template in a directive, and instead I need to add it programmatically as suggested in this answer
What am I missing ?
Thanks
Ahh - I found the problem, and I will post this as an answer instead of modifying my question, adding replace: true and the shape is shown
app.directive("svg01", () => {
return {
replace: true,
templateNamespace: "svg",
template: `
<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="4" fill="yellow" />
`