modify stroke and fill of svg image with javascript - javascript

I am trying to modify the stroke and fill of an .svg image.
I have been getting some information from Is it possible to manipulate an SVG document embedded in an HTML doc with JavaScript?.
I used javascript to manipulate it, the javascript in the header:
function svgMod(){
var s = document.getElementById("svg_img");
s.setAttribute("stroke","0000FF");
}
the html:
...
<body onload="svgMod();">
<img id="svg_img" src="image.svg">
...
Any help appreciated!
EDIT:1
I think the main problem here is how to display an svg image as an svg element, an actual image that instead of an ending like .png or .jpeg, uses an ending of .svg, and furthermore how the fill and stroke of it can then be manipulated!

If you use an img tag then for security reasons you will not be able to access the DOM of the image data. The image is effectively the same as an animated bitmap as far as the container is concerned.
Using an <iframe> or <object> tag will allow you to manipulate the embedded object's DOM.

I've already answered something like this before, save this snippet as an html file.
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in">
<circle id="circle1" r="30" cx="34" cy="34" style="fill: red; stroke: blue; stroke-width: 2"/>
</svg>
<button onclick=circle1.style.fill="yellow";>Click to change to yellow</button>
EDIT: To prove this function can be set in the head, here is a modified version:
<html>
<head>
<script>
function svgMod(){
var circle1 = document.getElementById("circle1");
circle1.style.fill="blue";
}
</script>
</head>
<body>
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in">
<circle id="circle1" r="30" cx="34" cy="34" style="fill: red; stroke: blue; stroke-width: 2"/>
</svg>
<button onclick=circle1.style.fill="yellow";>Click to change to yellow</button>
<button onclick=jacascript:svgMod();>Click to change to blue</button>
</body>
</html>

I think you will need to modify the stroke of the individual element, not just the svg element itself. The svg will be composed of a tree of nodes, and it is these nodes which have the stroke attribute.

I'm not sure if this has been resolved. I had experienced a similar scenario and the best way is to put the svg file in an <bject> tag and change the stroke property not fill property.
svgItem.style.stroke="lime";
Also you may refer to the section: Changing CSS Properties of SVG in this link
I had tested this and could change the stroke property. Please refer to this screnshot and below is the sample code which worked for me.
window.onload=function() {
// Get the Object by ID
var a = document.getElementById("svgObject");
// Get the SVG document inside the Object tag
var svgDoc = a.contentDocument;
// Get one of the SVG items by ID;
var svgItem = svgDoc.getElementById("pin1");
// Set the colour to something else
svgItem.style.stroke ="lime";
};

Here is a simple example that demonstrates modifying an attribute of an SVG HTML object using javascript:
<html>
<body>
<svg>
<rect id="A1" x="10" y="10" width="25" height="25" fill="red" />
</svg>
</body>
<script>
alert("Acknowledge to modify object color.");
var object = document.getElementById("A1");
object.setAttribute("fill", "green");
</script>
</html>

Related

How can I change an SVG color without using an ID in the SVG file itself?

Newbie to working with SVGs and I've run into a problem. Basically I'm using the Noun Project API pro version ( https://api.thenounproject.com/ ) to scrape icons as SVGs. Right now, I save the SVGs in a local folder. I want to be able to change the color of the icon (right now they download as black, and I want to change the color). I am loading the SVGs via the tag with a reference to the folder where the SVGs are being saved. I know it's fairly simple to change the color using vanilla JS (using document.getElementById('svgObject').contentDocument, and then accessing the inner document using a unique id). The problem is that the SVGs I save don't have any ID, and I don't know how to give them an ID. Right now, I'm looping through the folder and displaying the folder contents in a webpage. That's all working fine, but I can't manage to figure out how to change the color.
Basically, I just want all the icons in the folder to be set to a different color (for example, they could all be set to "red." They don't need to each have a different color). How do I do that without specifying the actual ID (since the SVG doesn't include an ID upon download), or else how do I add an ID to the SVG tag itself?
Assuming you have a bunch of svgs on your page and you'd like to change the color of each to the same color, you could do the following:
function changeSvgColors() {
const svgs = document.getElementsByTagName('svg')
for (let i = 0; i < svgs.length; i++) {
svgs[i].setAttribute('fill', 'red')
}
}
This will loop through every svg on your page and set their fill attribute to red.
Essentially, this is equivalent to doing this:
<svg viewBox="0 0 512 512" fill="red">
...
</svg>
Here's a quick demo:
JSFiddle
Alternatively, if you're using something like the img tag to load your svgs onto your page, using object instead would let you do the same thing as above.
Assuming your html looks like the following:
<div>
<object
data="http://localhost:5000/image.svg"
type="image/svg+xml"
></object>
</div>
Then,
function changeSvgColors() {
const objects = document.getElementsByTagName('object')
for (let i = 0; i < objects.length; i++) {
const object = objects[i]
const svg = object.contentDocument.rootElement
svg.setAttribute('fill', 'red')
}
}
One option would be using the svg as an image (or as an object if you prefer) and filters to change the color.
#theImage{filter: invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);}
<img id="theImage" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/bone300.svg" >
Please read this article: Solved with CSS! Colorizing SVG Backgrounds
Yet another option is using the svg as a mask. Keep in mind that the support for mask is not that good.
#theDiv{
display: inline-block;
width:300px;
height:134px;
-webkit-mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/bone300.svg);
mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/bone300.svg);
mask-size: cover;
background:red;
}
<div id="theDiv"></div>
But the best option would be to use the svg inline. You may save all your icons in a root svg element with width="0"; height="0"; position="absolute". Next you can use the icons with <use> and you change the color using the fill attribute <use fill="red" xlink:href="..... or styling it in CSS
You can give the SVGs a class instead of an id & set the color using javascript's getElementsByClassName
This Mozilla article explains:
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
Your best shot in achiveing this is to make use of the fill attibute for svg elements. Now, you can work this out two ways
Method 1:
Using img tag like this <img src="your_file.svg" />. In this case, you will need to edit the file directly, and that's it, it should reflect everywhere you reference the svg.
Method 2:
You can use svg as inline like below. The advantage in this approach is that if you have varying instance of the same svg, then this is the way to go. On the other side, if your svg stays same throughout the app, this goes against the DRY principle.
svg {
max-width: 200px;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path d="M25,7l28,36l40-18l-36,25l19,44l-27-37l-41,17l36-26z" fill="#cfc"/>
<ellipse cx="50" cy="50" rx="32" ry="30" stroke="#fc0" fill="none" stroke-width="11"/>
<path d="M63,2l-7,43l42,17l-45-6l-16,42l7,-45l-42-16l45,6z" fill="#3cc"/>
</svg>
If you don't mind having the svg all one color, you could set the fill attribute of the svg to currentcolor. Then it will take on the color of the element that it is in.
#span1 {
color: red;
}
#span2 {
color: blue;
}
#span3 {
color: green;
}
<body>
<span id=span1>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="150" height="150" fill-rule="evenodd" fill="currentcolor">
<title>HTML5 Logo</title>
<path d="M12,0 188,0 172,180 100,200 28,180Z M45,37 156,37 154,59 69,59 71,81 152,81 146,149 100,162 54,149 52,114 74,114 76,132 100,139 124,132 127,103 51,103Z"/>
</svg>
</span>
<span id=span2>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="150" height="150" fill-rule="evenodd" fill="currentcolor">
<title>HTML5 Logo</title>
<path d="M12,0 188,0 172,180 100,200 28,180Z M45,37 156,37 154,59 69,59 71,81 152,81 146,149 100,162 54,149 52,114 74,114 76,132 100,139 124,132 127,103 51,103Z"/>
</svg>
</span>
<span id=span3>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="150" height="150" fill-rule="evenodd" fill="currentcolor">
<title>HTML5 Logo</title>
<path d="M12,0 188,0 172,180 100,200 28,180Z M45,37 156,37 154,59 69,59 71,81 152,81 146,149 100,162 54,149 52,114 74,114 76,132 100,139 124,132 127,103 51,103Z"/>
</svg>
</span>
</body>

How to change the 'transform' attribute in svg directly?

I have an html code with svg embedded like this:
<svg id="mysvg" ...
<rect id="myrect" x="10" y="10" width="90" height="90" ... />
...
</svg>
In Javascript, I want the rectangle rotate, so I tried (with JQuery):
$("#myrect").attr("transform", "rotate(45, 50, 50)");
but it doesn't work, even though in the html code, the transform attribute is added to the rectangle. I tried the Element.setAttributeNS() function but it does not work either.
After some study, I learnt the following approach works:
var r = $("#mysvg").get(0).createSVGTransform();
var t = $("#myrect").get(0);
t.transform.baseVal.appendItem(r);
r.setRotate(45, 50, 50);
Although it works, it will be much easier if I can change the transform attribute directly. I don't know if there is any way to do so (I can change other attribute like x and y directly using $().attr()). By the way, the browser I am using is Chrome.
Changing transform using attr seems to work here,..
Have you got more of your code you can show?
$('#myrect').attr('transform', 'rotate(10)');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg id="mysvg">
<rect id="myrect" x="10" y="10" width="90" height="90"/>
</svg>

How to change part of an inline SVG's appearance when hovering over another outside source div or text element using javascript?

I have been looking for an HTML/CSS only solution to this issue for about 2 weeks now and nothing has come from any research or experimentation. I have come to the understanding that this is not possible with CSS so I was wondering if anyone could provided me a Javascript example that could possibly work for my case as javascript isn't my strong suit at the moment. My issue is that I have a multi-component SVG element. It is inline in the HTML and within a section tag. There is also a set of text elements in the section above the SVG. What I am trying to make happen is that when a portion of the SVG is hovered, the corresponding text element and the hovered SVG piece both change color. Vice versa if the text element is hovered, the corresponding SVG piece will change color as well.
<section>
<h1>Section 1</h1><h1>Section 2</h1>
<svg id="World_Map"...<path class="_russia_"...</svg>
</section>
It is probably important to note that the SVG has multiple paths with unique ID's and these are the pieces that I am trying to get working in this fashion.
Yes, without the SVG elements being siblings or ancestors to your text elements this is very difficult (if not impossible) to do with CSS. I have seen some pretty tricky and amazing things done with CSS selectors, though, so I wouldn't rule it out that someone more clever than me could get it to work. :)
Anyway, I have a working example of what you asked for using JavaScript. It actually makes use of jQuery because there is the .hover() binding, which cleanly allows you to bind a single function to the mouseenter and mouseleave events simultaneously, and the .toggleClass() method, which will add a class to an element if it doesn't exist or remove the class from the element if it's already there.
Since you did not post any functional code, here is a JSFiddle with my simple example.
https://jsfiddle.net/davecripps/o6mwjokj/
$(function() {
$("h1").hover(function() {
$("#map" + $(this).attr("id").substring(4)).toggleClass("mapHover");
});
$("rect").hover(function() {
$("#text" + $(this).attr("id").substring(3)).toggleClass("textHover");
});
});
.textHover,
h1:hover {
color: red;
cursor: pointer;
}
.mapHover,
rect:hover {
fill: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<section>
<h1 id="textRussia">Russia (yellow)</h1>
<h1 id="textSpain">Spain (blue)</h1>
<h1 id="textFrance">France (green)</h1>
<svg width="340" height="100" viewbox="0 0 340 100">
<rect id="mapRussia" x="0" y="0" width="100" height="100" fill="yellow" />
<rect id="mapSpain" x="120" y="0" width="100" height="100" fill="blue" />
<rect id="mapFrance" x="240" y="0" width="100" height="100" fill="green" />
</svg>
</section>
You should be able to understand the methodology and apply to your code.

How to setup data binding to an SVG image using knockout.js?

I'm trying to get a click event on a SVG to fire using knockout.js:
HTML
<img id="the-image" src="img/image.svg" data-bind="????????" />
SVG
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x="100" fill="#707070"
width="20"
height="200"
data-bind="click: $root.open" />
</svg>
this doesn't work if the SVG file is given as source for the img element, it does however work if I just paste it into the img element.
Is there a way to setup the binding so that the data-context is accessible for the SVG?
SVG elements are not added to the DOM when you use an img element to display the image, therefore knockout.js is unable to bind to those elements. The answers to this question contain some solutions that might help you: How do you access the contents of an SVG file in an <img> element?.

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