how to replace text inside an svg using js? - javascript

in this code I am trying to load an svg file into snap paper and then convert it to a group by :
replacing <svg with <g and </svg> with </g> ?
how can I fix this to work please?
var s1 = Snap('#svg1');
Snap.load( "https://dl.dropboxusercontent.com/u/140225334/bicycle.svg", function( frag ) {
var maing = s1.g();
maing.append(frag);
maing.attr({id: 'maing' });
// city_name=city_name.replace(/ /gi,'_');
var maing = maing.replace("<svg", "<maing").replace("</svg>", "</maing>"); // how this can be fixed to work?!
Edit: # dystroy, do you mean something like this?:
var s1 = Snap('#svg1');
Snap.ajax("https://dl.dropboxusercontent.com/u/140225334/bike2.svg", function(request)
{
var svg = Snap(request.responseXML.documentElement);
var maing = svg.selectAll("svg>*");//you can select any elements.
s1.append(maing);
maing.attr({id: 'maing' });
} );
Edit: # dystroy, If I go this way some svg styling is not going to be copied over:
please check to see how these 2 would differ:
copying over the svg nodes to an g:
http://jsbin.com/geyog/1/edit
vs
original svg file:
https://dl.dropboxusercontent.com/u/140225334/bike2.svg

You should add fill-rule attribute to svg element.
Original svg file has fill-rule attribute which value is "evenodd", but svg element described in html has no fill-rule, so browser treats the fill-rule attribute has "nonzero" as default value.
Thus the copied svg graphic looks like its style info was lost.
Snap.ajax("https://dl.dropboxusercontent.com/u/140225334/bike2.svg", function(request)
{
var maing = s1.g();
var svg = Snap(request.responseXML.documentElement);
var maing = svg.selectAll("svg>*");//you can select any elements.
//copy fill-rule attribute.
s1.attr("fill-rule", svg.node.getAttribute("fill-rule"));
s1.append(maing);
maing.attr({id: 'maing' });
// maing.transform('r45');
});

Related

Get the bounding box of an SVG element [duplicate]

I'm trying to solve this problem for more than one day now, but I can't find an answer. My problem is that I need to scale an SVG image (responsive design). I need to manipulate the SVG code on the client side, so embedding it via img tag is not an option. Therefore I tried to use an inline image instead. However, to scale it properly it seems that I need to set the viewBox property. The SVG files are generated by some software which can't set the bounding box on it's own, so my idea was to use JavaScript for that purpose.
The problem is that my software uses various tab controls from a library which I can't modify. I can't just get the bounding box, because it's not rendered initially and therefore I just get back zeros (in Chrome) or error messages (in Firefox).
What I need is a way to get the size of the bounding box without actually rendering the object. It is not possible to manipulate the display parameter, which the library uses to show and hide tabs.
Any ideas?
One idea was to copy the SVG into another, visible div, but I don't know if that would solve the problem. And I don't know how to do it.
Best regards
Based on the previous answers, I monkeypatched getBBox on my app init so it will transparently apply the hack.
Now I can call getBBox directly on any element, whether it's attached or not.
_getBBox = SVGGraphicsElement.prototype.getBBox;
SVGGraphicsElement.prototype.getBBox = function() {
var bbox, tempDiv, tempSvg;
if (document.contains(this)) {
return _getBBox.apply(this);
} else {
tempDiv = document.createElement("div");
tempDiv.setAttribute("style", "position:absolute; visibility:hidden; width:0; height:0");
if (this.tagName === "svg") {
tempSvg = this.cloneNode(true);
} else {
tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
tempSvg.appendChild(this.cloneNode(true));
}
tempDiv.appendChild(tempSvg);
document.body.appendChild(tempDiv);
bbox = _getBBox.apply(tempSvg);
document.body.removeChild(tempDiv);
return bbox;
}
};
you can clone it to a visible svg and then getBBox.
Add into you html:
<div style="position:absolute;left:-9999cm;top:-9999cm;visibility:hidden;">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
Add into your javascript:
function getBBox(elem){
var svg1 = document.getElementById('svg1'), e = elem.cloneNode(true);
e.style.display = "inline";
svg1.appendChild(e);
var b = e.getBBox();
svg1.removeChild(e);
return b;
}
cuixiping's answer as a function:
function svgBBox (svgEl) {
let tempDiv = document.createElement('div')
tempDiv.setAttribute('style', "position:absolute; visibility:hidden; width:0; height:0")
document.body.appendChild(tempDiv)
let tempSvg = document.createElementNS("http://www.w3.org/2000/svg", 'svg')
tempDiv.appendChild(tempSvg)
let tempEl = svgEl.cloneNode(true)
tempSvg.appendChild(tempEl)
let bb = tempEl.getBBox()
document.body.removeChild(tempDiv)
return bb
}

Inserting svg-files as foreignObject, in to SVG embedded to DOM as <оbject>

i have got SVG-file embedded to DOM as <оbject>.
<object id="motor" type="image/svg+xml"
data="img/motor.svg" width="119.055mm" height="119.055mm">
</object>
Inside svg-object, i had defined container (g-tag) for (in future) inserting other SVG-images from selected svg-files.
Container:
<g id="shape35-26" transform="translate(31.1811,-48.189)" data-id="MainSwitch">
<rect x="0" y="102.047" width="17.0079" height="17.0079" class="st3"/>
//from rect-tag i will read the container sizes
</g>
I read selected svg-files by XMLHttpRequest, after that i have two definition of results:
string with svg-file content <svg ... </svg> (from XMLHttpRequest.responseTex)
document-object ( resul of:
var parser = new DOMParser();
var stringContainingXMLSource = s;
var doc = parser.parseFromString(stringContainingXMLSource, "image/svg+xml");
)
How can i create and insert foreignObject (with svg-file) to container?
No foreignObject is needed. <svg> elements can be nested.
var parser = new DOMParser();
var stringContainingXMLSource = s;
var doc = parser.parseFromString(stringContainingXMLSource, "image/svg+xml");
var svg = doc.querySelector('svg');
// select the <object> content document
const objectDoc = document.querySelector('#motor').contentDocument;
// select the insertion group
const mainSwitch = objectDoc.querySelector('[data-id="MainSwitch"]');
// get the bounding box of the <rect>
const box = mainSwitch.querySelector('rect').getBBox();
// set all of them on the svg to insert
svg.setAttribute('x', box.x);
svg.setAttribute('y', box.y);
svg.setAttribute('width', box.width);
svg.setAttribute('height', box.height);
// now insert into the object DOM
mainSwitch.appendChild(svg);
This will not work as expected if the SVG to insert is missing its viewBox attribute. It would be best to make sure it exists on all files.

Access SVG DOM / 'g' Elements Created in Adobe Illustrator

I am trying to access the SVG DOM that has a variety of adobe illustrator (layered) elements within the SVG file. Ideally, I would align the HTML slider range number (1-100) with a individual 'g' elements and animate, hide, show when that range number is reached as the user engages with the slider.
Please see github project:
https://github.com/EdBrooks/media-stroke
$(document).ready(function() {
var input = document.getElementsByTagName('input')[0];
var svg = $('#svgFile').svg({loadURL: 'img/media_stroke.svg'});
for (i=0; i < svg.length; i++) {
var g = document.getElementsByTagName('g');
var g1 = [{0:g}];
console.log(g1);
// var g1 = document.getElementById('group1').style.visibility = "hidden";
// var re = [{0:g}];
// console.log(re);
}
function InputVal() {
this.number =
$('input');
var change = input.addEventListener('change', function() {
var value = this.value
console.log(value);
if (value == 23) {
alert('wow dumb')
}
}, false);
}
InputVal();
});
It looks like you want to perform manipulation on SVG elements and do some animation.. for that you can use library like Snap.svg which is similar to jQuery for HTML Dom!
Check out it's getting started page (look for section 15)
or watch video

How to programmatically ng-bind a property on an svg element?

I'd like to bind a background color to an svg element. I have an external svg file that I'm referencing, myfile.svg, inside of this file there's a circle with the id 'mycircle'.
So my html looks like:
<div ng-controller="MyCtrl">
<embed src="myfile.svg" id="mySvg"/>
</div>
I have a controller that looks like:
function MyCtrl($scope) {
$scope.myfill = 'yellow';
}
Now I'd like to set up the binding programmatically, this is what I do:
var mySvg = document.getElementById("mySvg");
mySvg.addEventListener("load", function() {
var svg = mySvg.getSVGDocument();
var mycircle = svg.getElementById("mycircle");
//this works:
//mycircle.setAttribute("fill", "yellow");
$(mycircle).attr('ng-bind','myfill');
});
However, this doesn't set the fill. I'm thinking I might need to use angular "compile" or something in order to get this to work (?) can anyone clue me in on how to do this?
Yes you need to compile. Should bind as an exp and compile against the scope. Below snippet should work.
var mySvg = document.getElementById("mySvg");
mySvg.addEventListener("load", function() {
var svg = mySvg.getSVGDocument();
var mycircle = angular.element(svg.getElementById("mycircle"));
mycircle.attr('fill', '{{myfill}}');
$compile(mycircle)($scope);
});

GetBBox of SVG when hidden

I'm trying to solve this problem for more than one day now, but I can't find an answer. My problem is that I need to scale an SVG image (responsive design). I need to manipulate the SVG code on the client side, so embedding it via img tag is not an option. Therefore I tried to use an inline image instead. However, to scale it properly it seems that I need to set the viewBox property. The SVG files are generated by some software which can't set the bounding box on it's own, so my idea was to use JavaScript for that purpose.
The problem is that my software uses various tab controls from a library which I can't modify. I can't just get the bounding box, because it's not rendered initially and therefore I just get back zeros (in Chrome) or error messages (in Firefox).
What I need is a way to get the size of the bounding box without actually rendering the object. It is not possible to manipulate the display parameter, which the library uses to show and hide tabs.
Any ideas?
One idea was to copy the SVG into another, visible div, but I don't know if that would solve the problem. And I don't know how to do it.
Best regards
Based on the previous answers, I monkeypatched getBBox on my app init so it will transparently apply the hack.
Now I can call getBBox directly on any element, whether it's attached or not.
_getBBox = SVGGraphicsElement.prototype.getBBox;
SVGGraphicsElement.prototype.getBBox = function() {
var bbox, tempDiv, tempSvg;
if (document.contains(this)) {
return _getBBox.apply(this);
} else {
tempDiv = document.createElement("div");
tempDiv.setAttribute("style", "position:absolute; visibility:hidden; width:0; height:0");
if (this.tagName === "svg") {
tempSvg = this.cloneNode(true);
} else {
tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
tempSvg.appendChild(this.cloneNode(true));
}
tempDiv.appendChild(tempSvg);
document.body.appendChild(tempDiv);
bbox = _getBBox.apply(tempSvg);
document.body.removeChild(tempDiv);
return bbox;
}
};
you can clone it to a visible svg and then getBBox.
Add into you html:
<div style="position:absolute;left:-9999cm;top:-9999cm;visibility:hidden;">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
Add into your javascript:
function getBBox(elem){
var svg1 = document.getElementById('svg1'), e = elem.cloneNode(true);
e.style.display = "inline";
svg1.appendChild(e);
var b = e.getBBox();
svg1.removeChild(e);
return b;
}
cuixiping's answer as a function:
function svgBBox (svgEl) {
let tempDiv = document.createElement('div')
tempDiv.setAttribute('style', "position:absolute; visibility:hidden; width:0; height:0")
document.body.appendChild(tempDiv)
let tempSvg = document.createElementNS("http://www.w3.org/2000/svg", 'svg')
tempDiv.appendChild(tempSvg)
let tempEl = svgEl.cloneNode(true)
tempSvg.appendChild(tempEl)
let bb = tempEl.getBBox()
document.body.removeChild(tempDiv)
return bb
}

Categories

Resources