I Googled this issue for about 30 minutes and was surprised nobody has asked so maybe it's not possible.
I'm using this line to embed the SVG file that I made in AI (note that when I saved the SVG, I had no fill OR stroke on the paths):
<object type="image/svg+xml" data="example.svg" height=600px width=600px>Your browser does not support SVG</object>
This obviously comes up with no image because the SVG file has no fill or stroke.
I tried adding in
...fill=yellow>
or
...style="fill:yellow;">
but I'm not having any luck. Thanks!
Have a nice trick: Embed it as <img> and use javascript to convert it into inline <svg> with this code (that came from SO I think). Now you can manipulate this SVG object
CODE::
/*
* Replace all SVG images with inline SVG
*/
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
});
});
Are you trying to add the fill or style on the object element? If so, that's not going to work. Those properties are not supported on the object element. You're going to have to add it into the SVG in the SVG file.
Related
I have an SVG loading like this:
<object id="svg-object" type="image/svg+xml" width="1400px" height="900px" data="media/1.svg?"></object>
I then have a function that works calling out one element in this svg and apply a style to it just fine. Here is the onload event that is working for getting me the element properly:
window.onload=function() {
var svgObject = document.getElementById('svg-object').contentDocument;
var element = svgObject.getElementById('sprite1');
};
But how do I set a .hover even in for this same element? I've tried:
$('#${element}').hover(function(e) { }
But no luck.
Also, how can I apply the svgObject variable to a whole class like path or polygon? I use this on a local inline SVG and it works fine:
$("polygon, path").hover(function(e) { }
I would like this to work on the object embedded in the svg also.
Sorry, I am not able to put an external svg in snippet (or at least I don't know how) as external URL will not load in an object. And it needs to load as an object for you to see the issue.
Any help?
Also, here is code that works defining element color from script but mouseover not working either. (tried instead of hover)
window.onload=function() {
var svgObject = document.getElementById('svgEmb').contentDocument;
var element = svgObject.getElementById('left');
element.style.fill = "blue";
element.style.stroke ="blue";
};
element.addEventListener("mouseover", function() {
element.style.fill = "red";
element.style.stroke ="red";
});
I am writing an web app that saves html to onenote. In order to save math formulas, I plan to convert math formulas to svg by MathJax.js and then convert svg to png, because the html/css supported in onenote api is limited.
But it seems the svg generated by MathJax.js in browser is not a valid svg. I tested it with a simple math formula: $$a^2 + b^2 = c^2$$ (demo code) and copy the svg to jsfiddle and it displays nothing.
Then I tried to write a MathJax-node demo and copy the svg to jsfiddle again, it looks good. Here is my demo code, it's almost the same as the GitHub repo demo:
// a simple TeX-input example
const fs = require('fs')
var mjAPI = require("mathjax-node");
mjAPI.config({
MathJax: {
// traditional MathJax configuration
}
});
mjAPI.start();
var yourMath = String.raw`a^2 + b^2 = c^2`
mjAPI.typeset({
math: yourMath,
format: "TeX", // or "inline-TeX", "MathML"
svg: true, // or svg:true, or html:true
}, function (data) {
if (!data.errors) {console.log(data.svg)}
// will produce:
// <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
// <mi>E</mi>
// <mo>=</mo>
// <mi>m</mi>
// <msup>
// <mi>c</mi>
// <mn>2</mn>
// </msup>
// </math>
fs.writeFile('math.txt', data.svg, (error) => {
console.log(error)
})
});
I also tested two svg with cloudconvert, it's the same result. Why are the two svg different? Do I miss something?
The difference is due to a specific setting: useGlobalCache
By default, MathJax (docs) sets this to true while mathjax-node (docs) sets this to false.
On the server MathJax-node does not have any document context and produces self-contained SVGs. On the client, MathJax has a full document context and thus can re-use the SVG paths across equations.
I have 12 graphs and I want to generate pdf with 2 pages each page has 6 graphs.
However, when I convert svg to canvas, then the jspdf can only see part of both sub-dives.
$('#downloadx2').click(function() {
var svgElements = $("#body_id").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStylex(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
var doc = new jsPDF("p", "mm");
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
html2canvas($("#div_pdf1"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png', 0.1);
doc.addImage(imgData, 'PNG', 5, 0, width, height/2,'','FAST');
doc.addPage();
}
});
html2canvas($("#div_pdf2"), {
onrendered: function(canvas2) {
var imgData2 = canvas2.toDataURL(
'image/png', 0.1);
doc.addImage(imgData2, 'PNG', 5, 0, width, height/2,'','FAST');
doc.save('.pdf');
}
});
});
<body id="body_id">
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
</body>
When I run this code, the generated pdf will view two pages with same canvas the first one (div_pdf1) div. So how to get both of them appearing in pdf as two pages.
You seem to be trying to run 2 parts in sequence but that's not how javascript works and actually runs your code.
No big deal, just a small misunderstanding between your mental model and the engine that executes the code.
A quick temporary debugging tool to see what's going on and verify that there is a discrepancy is to add console.log to key points and check the sequence of their printout once you run the code.
console.log('[1] just before: svgElements.each');
svgElements.each(function() {
console.log('[2] just after: svgElements.each');
And also around this part of the code:
console.log('[3] just before html2canvas-div_pdf1');
html2canvas($("#div_pdf1"), {
console.log('[4] just after html2canvas-div_pdf1');
Finally around this part of the code:
console.log('[5] just before html2canvas-div_pdf2');
html2canvas($("#div_pdf2"), {
console.log('[6] just after html2canvas-div_pdf2');
I suspect you'll see the code doesn't print the log lines in the order you think they will.
Next, you can try wrapping the 2 calls to html2canvas with one setTimeout function and force a delay in the execution of that code by an arbitrary amount of milliseconds.
Note that this is not the recommended final production quality solution but it will make the code output what you want.
I am having trouble in rendering svg element to pdf using jspdf . Iam using plugin https://github.com/CBiX/svgToPdf.js/ to do this.
Below is my code
// I recommend to keep the svg visible as a preview
var tmp = document.getElementById("chartContainer");
var svgDoc = tmp.getElementsByTagName("svg")[0];
var pdf = new jsPDF('p', 'pt', 'a4');
svgElementToPdf(svgDoc, pdf, {
scale: 72 / 96, // this is the ratio of px to pt units
removeInvalid: false // this removes elements that could not be translated to pdf from the source svg
});
pdf.output('datauri'); // use output() to get the jsPDF buffer
It is generarting blank pdf. Please help
You can do that using canvg.
Step1: Get "SVG" markup code from DOM
var svg = document.getElementById('svg-container').innerHTML;
if (svg)
svg = svg.replace(/\r?\n|\r/g, '').trim();
Step 2:
Use canvg to create canvas from svg.
var canvas = document.createElement('canvas');
canvg(canvas, svg);
Step 3:
Create image from canvas using .toDataURL()
var imgData = canvas.toDataURL('image/png');
// Generate PDF
var doc = new jsPDF('p', 'pt', 'a4');
doc.addImage(imgData, 'PNG', 40, 40, 75, 75);
doc.save('test.pdf');
Check the demo here http://jsfiddle.net/Purushoth/hvs91vpq/193/
Canvg Repo: https://github.com/gabelerner/canvg
I've tried both svg2pdf.js and addSvgAsImage using canvg internally.
Both didn't work well for me, the resulting images in the pdf where either incorrectly positioned or displayed.
I've ended up doing the following which works very well:
convert the SVG to PNG without any libraries, see my answer to "Convert SVG to image (JPEG, PNG, etc.) in the browser".
just add the result to the pdf using the normal addImage method
I think the current jspdf version (2.3.1) has an addSvgAsImage method, but it takes the svg as a string. I guess you could use an ajax call to retrieve the SVG content, but I just have the SVG in my code and pass it in that way.
Found a couple of solutions here about adding SVG patterns dynamically but it doesn't seem to work with jvectormap. I think the problem may be that there is no XMLNS attribute defined on the <SVG> tag by jvectormap but my attempt to add these attributes does not work.
I also tried changing all of the setAttribute to setAttributeNS for pattern and image. But no dice.
Here is my attempt (based on this solution: How to dynamically change the image pattern in SVG using Javascript):
// Set namespace for SVG elements.
var svgMap = $('.jvectormap-container > svg').get(0);
var svgNS = 'http://www.w3.org/2000/svg';
var svgNSXLink = 'http://www.w3.org/1999/xlink';
svgMap.setAttribute('xmlns', svgNS);
svgMap.setAttribute('xmlns:link', svgNSXLink);
svgMap.setAttribute('xmlns:ev', 'http://www.w3.org/2001/xml-events');
// Create pattern for markers.
var pattern = document.createElementNS(svgNS, 'pattern');
pattern.setAttribute('id', 'markeryellow');
pattern.setAttribute('patternUnits', 'userSpaceOnUse');
pattern.setAttribute('width', '38');
pattern.setAttribute('height', '38');
// Create image for pattern.
var image = document.createElementNS(svgNS, 'image');
image.setAttribute('x', '0');
image.setAttribute('y', '0');
image.setAttribute('width', '38');
image.setAttribute('height', '38');
image.setAttributeNS(svgNSXLink, 'xlink:href', '/path/to/image.png');
// Put it together
pattern.appendChild(image);
var defs =
svgMap.querySelector('defs') ||
svgMap.insertBefore(document.createElementNS(svgNS, 'defs'), svgMap.firstChild);
defs.appendChild(pattern);
var $markers = $(svgMap).find('.jvectormap-marker');
$.each($markers, function(i, elem) {
$(elem)
.attr({
'fill': 'url(#markeryellow)'
});
});