Changing path fill in svg file using css and javascript - 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.

Related

How to extract data <d> in svg through javascript

I wrote an icon component through reactjs to parse the svg files. I use storybook to show my icon component. Now I need help for writing a command line to parse the svg file to the component. I need to script the element in in a svg file and I have no idea how to achieve it.
I am planning to write it in javascript. And here is one example of my svg files.
<svg viewBox="0 0 1024 1024" p-id="3378" width="200" height="200">
<path d="..." p-id="3379"></path>
</svg>
May anyone gives me some ideas on how to achieve it. I am bad at extracting data from a file.
For the specific question from the title, use the following JS code:
document.querySelector("object")
.contentDocument.querySelectorAll("path[path-id='3379']")[0].getAttribute("d")
The SVG should be referenced using the object element (replace width/height attribute content with proper values):
<object
type="image/svg+xml"
data="./logo.svg"
width="480"
height="240"
></object>
It is assumed that there is a single object element in your html. Otherwise tag them with an id attribute and use #<the_id_goes_here> in the first selector:
document.querySelector("#<the_id_goes_here>")
.contentDocument.querySelectorAll("path[path-id='3379']")[0].getAttribute("d")

How do I render svg images in React Native?

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.

Can JavaScript function outside of the [CDATA[ tag?

From what I read, JavaScript within an SVG must be put into a [CDATA[ tag (the type designation is apparently now optional):
<script type="application/javascript">
<![CDATA[
(JavaScipt stuff here)
]]>
</script>
However, the following markup/code works without that tag even though it looks like JavaScript methods are being used:
<svg width="400px" height="400px" viewBox="0 0 400 400">
<rect id="rect1" x="160" y="10" width="60" height="60" fill="blue"
onmouseenter="evt.target.setAttribute('fill', 'red');"
onmouseout="evt.target.setAttribute('x', '0');"
/>
</svg>
So, are the evt.target.setattribute commands all SVG? I know this is a super newbie question...but I am having a hard time establishing where SVG ends and JavaScript begins. Documentation is very sketchy on the delineation, and I want to learn the total extent of what I can do in SVG before needing to learn another language. Thanks much for any clarification. And if anyone knows of a reference that is very clear on the subject, I'd love to know.
A CDATA section is a feature of XML documents. It's not part of html. You seem to be using SVG in html given that your SVG example has not namespaces so CDATA is neither required nor useful there.
In standalone SVG you need namespaces defined i.e. xmlns="http://www.w3.org/2000/svg" and there you need CDATA to prevent various characters in javascript e.g. < being interpreted as the beginning of a tag. Other characters are problematic too.

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.

modify existing paths for Raphael?

I have a JS object that Raphael uses to generate a clickable SVG map. I need to modify some of the paths. Is there a tool I can use to do that in a user-friendly manner? I don't want to fiddle with numbers using trial-and-error technique, I want to drag and drop paths/anchor points. Can I somehow import the coordinates into Illustrator/Dreamweaver/any other tool?
Thank you.
Here's what the JS object looks like:
map.coords = [
{ type:"path" ,id:"K15" ,d:"/*edited out*/"},
{ type:"rect" ,id:"K14" ,x:"496" ,y:"386" ,width:"9" ,height:"5"}
];
Here's what the markup looks like (with Raphael-generated markup inside the svg element):
<div style="position: relative;">
<div id="mapOverlay" style="position: absolute; top: 0; left: 0; z-index: 2">
<svg height="777" width="777" version="1.1" xmlns="http://www.w3.org/2000/svg">
<desc>Created with Raphaƫl</desc>
<defs></defs>
<path fill-opacity="0" stroke-width="0.25" style="stroke-width: 0.25; fill-opacity: 0;" d="[/*edited out*/]" stroke="#000000" fill="#000000"></path>
</svg>
</div>
<img src="map.jpg" alt="Interactive Map">
</div>
Though Kevin Nielsen's comment to the question is a perfectly doable approach, while waiting I figured out how to do it in Illustrator. Here's how:
yank out the entire contents of <svg> tag and save it as a separate file
add this to the beginning of your file:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
In Illustrator File -> Open. If it doesn't open you can run it through the W3 validator to see what is wrong with it. Make sure you specify SVG 1.1 as Document Type in the settings.
You can then superimpose any image (it's best if it's the same dimensions) by using File -> Place command in Illustrator.

Categories

Resources