How do I render svg images in React Native? - javascript

I've tried "react-native-remote-svg" and "react-native-svg-image"; neither of them manage to render the SVG file.
How do I handle SVG in React-native?
Example code:
import SVGImage from 'react-native-svg-image'
const EmailLogo = require('../static/others/Email.svg');
// Render etc....
<ButtonContainer>
<Button bgColor={colors.darkTeal} txtColor={colors.whiteText}
onPress={this.onSignInPress.bind(this)}>
LOG IN WITH
</Button>
<SVGImage
style={{ width: 80, height: 80 }}
source={EmailLogo}
/>
</ButtonContainer>
Result: It's a white square when it should be an email logo.
How does one handle SVG's properly in React-native?

I've been through this struggle. react-native-svg-icon helped me out, but there were some additional things that i had to do, to make it work.
First of all, this library uses react-native-svg underneath. And you need to convert your svg files into SVG objects that this library understands.
If your open your svg file with editor, it will look something like this
<svg xmlns="http://www.w3.org/2000/svg" viewBox="170.5 200.5 18.6 23">
<defs>
<style>.a{fill:#444;}.b{fill:#07b57a;}</style>
</defs>
<g transform="translate(171 201)">
<path class="a" d="M18.1,22.5H-.5V-.5H18.1ZM.5,21.5H17.1V.5H.5Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 5.4)"/>
<path class="b" d="M4.4,7.3,3,5.9l.7-.7.7.7L6.6,3.7l.7.7Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 10.5)"/>
<path class="b" d="M4.4,12.4,3,11l.7-.7.7.7L6.6,8.8l.7.7Z"/>
<rect class="b" width="5.4" height="1" transform="translate(9 15.6)"/>
<rect class="b" width="2.5" height="1" transform="translate(3.2 15.6)"/>
</g>
</svg>
You need to convert it to something like this
entry: {
svg: (
<G transform="translate(171 201)">
<Path fill="#444444" d="M-152.4-178H-171v-23h18.6V-178z M-170-179h16.6v-21H-170V-179z" />
<Rect x="-161.5" y="-195.1" fill="#07B57A" width="5.4" height="1" />
<Path
fill="#07B57A"
d="M-166.1-193.2l-1.4-1.4l0.7-0.7l0.7,0.7l2.2-2.2l0.7,0.7L-166.1-193.2z"
/>
<Rect x="-161.5" y="-190" fill="#07B57A" width="5.4" height="1" />
<Path
fill="#07B57A"
d="M-166.1-188.1l-1.4-1.4l0.7-0.7l0.7,0.7l2.2-2.2l0.7,0.7L-166.1-188.1z"
/>
<Rect x="-161.5" y="-184.9" fill="#07B57A" width="5.4" height="1" />
<Rect x="-167.3" y="-184.9" fill="#07B57A" width="2.5" height="1" />
</G>
),
viewBox: '0 0 18.6 23',
}
This is a representation of the svg file in components of react-native-svg library. One thing you need to pay attention here, is viewbox of the svg file. I am not sure why, but most of the time, it is 'off center'. I will show in screenshots below. Because of that, it cannot be displayed by the react-native-svg-icon as well. To bring it to center you can use Adobe Illustrator, or some other online tool to edit svg. One i used is http://editor.method.ac/. So, I uploaded my svg, recentered it and downloaded it again. and used that svg file to create object in my react native code.
This is my initial svg file that i uploaded to the service. if you zoom out and press cmd+a (or ctrl+a) to select all, it will highlight svg icon, like in screenshot below. You should position it to the white part, either by dragging it, or by setting X and Y on top right corner to 0s.
This is how it will look when centered
Once you save that svg file, use it to convert it to javascript object with react-native-svg components, more info on that can be found here
Once you create you svg objects, you can use it with react-native-svg-icon. You will find how to do that in the link I shared above.
I know, this is a lot of pain and seemingly over complicated, and I spent quite some time to make it work, but it is the only way I managed to accomplish it.
One other option would be to convert your svgs into font icons with icomoon.com and use it with react-native-vector-icons. but it will only work if your svgs are drawn with only one color, as multicolored ones cannot be converted to fonts
P.S. I didn't try, but maybe, libraries that you tried to use might work with centered svg file that we got from online service. Let me know if it works, then it can be helpful to other users as well.

react-native-svg-image and react-native-svg-image uses WebView to render SVG files so it do not support local files at the moment. Its written it the docs.
Use react-native-svg-uri to render SVG images in React Native from an URL or a static file. to use react-native-svg-uri you will need to link react-native-svg as well. So read docs carefully.

Related

Create a SVG node from an external file with JavaScript

It is possible to synchronously create a <svg> element with Javascript that is a copy of a SVG file?
I have a small SVG in an external file called cursor.svg located in a folder called svg. So its relative path to my base HTML file is svg/cursor.svg. The SVG is very simple:
<svg id="cursor">
<rect x="50" y="20" rx="20" ry="10" width="10" height="150" style="fill:red;stroke-width:0" opacity="0.75">
<animate attributeName="opacity" begin="indefinite" values="0.75;0" dur="1s" repeatCount="1" />
</rect>
</svg>
I would like to be able to have a createSvgNode() function that simply returns a SVG node that is a copy of the one within cursor.svg. (so that the function code would remains the same even if the SVG file changes)
But I want it to be synchronous. Is there a possible solution for this? Maybe by loading the cursor.svg file in the HTML DOM?
Thanks for any suggestion.

How to keep a constant font-size in svg

I'm new with SVG and I try to add some text in a shape that I created. I've done it like this : https://fiddle.jshell.net/30kL3mzt/
But the text in the SVG change with the polygone. Is it possible to keep a constant size of text? Or at least to control the size of letters?
<div id="tab">
<div class='chevron'>
<svg width="25%" height='100%' viewBox="0 0 20 20" preserveAspectRatio="none">
<polygon fill=steelblue stroke-width=0
points="0,0 2,10 0,20 18,20 20,10 18,0" />
<text x="0" y="10" font-family="Verdana" font-size="2" >I love SVG!</text>
</svg>
</div>
</div>
<div id="middle">
<svg width="25%" height='100%' viewBox="0 0 20 20" preserveAspectRatio="none">
<polygon fill=steelblue stroke-width=0
points="0,0 2,10 0,20 18,20 20,10 18,0" />
<text x="0" y="10" font-family="Verdana" font-size="2" >I love SVG!</text>
</svg>
</div>
Why do you need the textual content to be in the SVG if you don't want it to scale? Probably it's better to have the text outside and style it with CSS to be where you want it.
Instead of adding svg directly inside your HTML, why not use a font library like fontello/icomoon?
I know for a fact, when you choose the same grid size for your icons you can scale up your icons separately from your text.
This is because an icon from a font file uses CSS on the pseudo-elements :before and/or :after. Combined with line-height you have complete control on the size of an icon. => Line-height is best calculated by the height of the layer divided by the font-size.
For example: 24px div / 20px text = 1.2
In my opinion you're too far off from an x-browser solution to your problem.
convert your shapes into font library (import svg files)
add the proper CSS from the download (or read the readme.txt)
make sure to support .woff on the server
use font icon classes where needed
override the proper font-sizes to your need in CSS (there's your solution)

Convert svg-element to image

i have a html svg element (not canvas) and have to save the content to a image file (png or jpg).
Is there any solution for this?
canvas.toDataURL() didn't work, because it's a svg element.
example:
<svg:svg id ="svg">
<svg:svg width="{width}" height="{height}">
<svg:circle cx="{cx}" cy="{cy}" r="{radius}" id="circ" fill="white" stroke="black" stroke-width="2" />
<svg:text x="{tposW}" y="30" line="0" text-anchor="middle">{VORNAME}</svg:text>
<svg:text x="{tposW}" y="44" line="1" text-anchor="middle">{NAME}</svg:text>
<svg:text x="{tposW}" y="58" line="2" text-anchor="middle">{GEB}</svg:text>
</svg:svg>
</svg:svg>
Please post only solutions without using jQuery.
Use the canvg JavaScript library to render the SVG image using Canvas:
http://code.google.com/p/canvg/
and then use the canvas.toDataURL()

Changing path fill in svg file using css and javascript

Ok, i spent all day to trying "connect" css styles with svg files created in inkscape. I've got svg file with map and couple of path, and i want to change fill color when i mouseover on that path. Please, can You help me with that ? :/. If i'am creating
<img src="example.svg" />
, than in css style i put for example:
<style type="text/css">
#path6666
{ fill: green;
}
</style>
nothing happen. I dont wanna use jquery, only javascript and css.
Please, help !..
UPDATE:
This is svg code:
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2985"
version="1.1"
inkscape:version="0.48.4 r9939"
width="1176"
height="617"
sodipodi:docname="mainMapa.svg">
<metadata
id="metadata2991">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs2989">
<inkscape:path-effect
effect="spiro"
id="path-effect3794"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3790"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3786"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3782"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect3778"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect2997"
is_visible="true" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="962"
id="namedview2987"
showgrid="false"
inkscape:zoom="0.97789116"
inkscape:cx="374.5729"
inkscape:cy="311.15508"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2985" />
<image
width="1176"
height="617"
xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/
2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
BRRRQAUUUUAFFFFAB
RRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF
FFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUU
UAFFFFABRRRQAUUUUAf/2Q==
"
id="image2993"
x="0"
y="0" />
<path
style="fill:#2b54e6;stroke:#281300;stroke-width:1px;stroke-linecap:butt;
stroke-linej oin:miter;stroke-opacity:1 ;fill -opacity:1"
d="m 308.82783,502.72348 3.57913,4.60174 5.36869,2.04521 5.11305,
3.57914 4.34608,3.83478 -0.76695,3.32348 -4.34609,4.09043 -3.57913,
1.27826 -4.09044,
-1.78956 -3.83478,-2.04522 -3.57913,-0.51131 -1.78956,-4.09043 -0.51131,
-5.62435 1.53391, -6.3913 z"
id="path3833"
inkscape:connector-curvature="0" />
</svg>
I'am, starting giving up. I dont understand that: inkscape is very popular free software. Why there is no ANY tutorial how do that ?!
Looks like you have three problems here:
Style cascade issue
Inkscape is defining the fill of path #path3833 in an inline style declaration. That's more specific than your style sheet rule, so it overrides it.
MDN has some good information about how the cascade works.
To solve your problem, in the style-sheet use !important on the declaration to override Inkscape's inline syle:
#path3833 {
fill:green !important; /* override inline style */
}
Hosting the SVG in HTML
Note that Robert Longson's answer, to use <object type="image/svg+xml" data="[your file]"> rather than <img> is accurate; you can't change any part of an SVG hosted in an img tag.
Linking the CSS to the SVG
Static linking
To link the stylesheet you can add the following XML declaration to the SVG document:
<?xml-stylesheet type="text/css" href="your_style_sheet.css"?>
This should sit between the opening XML declaration <?xml version="1.0" ..., but come before the root svg element. Typically this means it should be the second line of the file.
Dynamic linking
To add a stylesheet through Javascript, you must create an XML processing instruction (i.e. the <? ... ?> markup). The SVG document object exposes a method to do that. However, getting a reference to the SVG document is tricky; you have to go through window.frames. That means you must know which "frame" of the parent HTML document contains the SVG. If you have one SVG file, it's easy. Otherwise, you might have to use trial-and-error.
In any case, this is roughly how it should go:
var frameNumber = 0; //this may vary depending on your page
var svgDoc = window.frames[frameNumber].document;
var procInstruction = svgDoc.createProcessingInstruction(
'xml-stylesheet', // the type of processing instruction
'type="text/css" href="your_style_sheet.css"' // the "data" of the PI
);
svgDoc.insertBefore( // the PI must come *before* the SVG root element
procInstruction, svgDoc.childNodes[0]
);
This fiddle demonstrates the two techniques above, with data URIs instead of files. I can't get the dynamic part to work with data URIs, but if you can use a file instead it will work fine. (Firefox v26 / Win7)
When you use SVG as an image i.e. via an image tag or background-image css it isn't interactive i.e. mouseover and the like don't work.
This is so the raster mental model people have for images is consistent with SVG.
If you want interactivity you'll have to include the <svg> via and <object> or <iframe> tag instead.
I found a solution a long time ago, but I am writing it because someone might use it in the future. The solution was removing style from the path. Then everything worked perfectly.
Also I have to say: Inkscape is the best program for SVG that I have ever tried.

Confused about SVG styling with d3.js

The most d3.js examples use SVG to draw the diagrams, etc. This means for instance rect instead of div. This then again means, that CSS properties like drop-shadow cannot be applied.
The alternative approach is to define filters in <defs>. The same is true if you want to fill the rect with a gradient color. Is that right so far?
So I define some filter and gradients, but it seems very redundant to redefine these definitions for every page again. Wouldn't it be possible to reference all these definitions from a separate svg-file?
I tried things like: filter: url(.../my_file.svg) but it does not seem to work, but isn't that how it's supposed to be?
Say you have a file called filters.svg, and it contains a few filter defitions. It looks something like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="my_filter" x="0%" y="0%" width="100%" height="100%">
...
</filter>
</svg>
If you were using my_filter in that same document, you'd just refer to it using #my_filter. But you're not. You want to use it in another document. What you have to do then is refer to it in those documents as /filters.svg#my_filter. Like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0" y="0" width="100" height="100" fill="url(/filters.svg#my_filter)" />
</svg>
This is of course assuming that both documents are accessible from the same domain, and that they're located in the right places, etc. I don't know if this will work in CSS stylesheets, but it will work across SVG documents. Check out the section on Linking in the SVG Specification for more details.

Categories

Resources