I have this D3js line graph I'm working with.
I'd like to be able to save it as an image in the same directory as shown in this example
d3.select('#saveButton').on('click', function(){
var svgString = getSVGString(svg.node());
svgString2Image( svgString, 2*width, 2*height, 'png', save ); // passes Blob and filesize String to the callback
function save( dataBlob, filesize ){
saveAs( dataBlob, 'D3 vis exported to PNG.png' ); // FileSaver.js
function
}
});
no errors running the above
Although I am getting no errors, the file is not downloading when the button is clicked. What am I missing here? Thanks!
In your fiddle, you're appending g to your svg and assigning it your variable svg:
var svg = d3.select("#priceWithMilestones")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
It looks like getSVGString() expects the root node, and not a g element. You should probably change your code so that svg reflects the root svg element, and create another variable to store the g element, but for a quick and dirty fix, you can change
var svgString = getSVGString(svg.node());
to
var svgString = getSVGString(d3.select('svg').node());
And should save. Updated fiddle: https://jsfiddle.net/c19664p3/8/
Edit: As for exported styles, it looks like you can't refer to selectors outside of the svg when declaring selecting. Additionally it looks like it has to consist of exactly just an id or a class. See my other answer for a more lax CSS rule exporter.
So changing this:
#priceWithMilestones .line {
fill: none;
stroke: #14da9e;
stroke-width: 2px;
}
to:
.line {
fill: none;
stroke: #14da9e;
stroke-width: 2px;
}
exports the line style for just the svg. Updated fiddle: https://jsfiddle.net/c19664p3/10/
After looking at getCSSStyles, it looks like it only checks for rules that match exactly the id or the class of the root svg and its child elements. I think this is a more forgiving implementation:
function getCSSStyles( parentElement ) {
var nodesToCheck = [ parentElement ], i;
// Add all the different nodes to check
var childNodes = parentElement.getElementsByTagName("*");
for (i = 0; i < childNodes.length; i++) {
nodesToCheck.push(childNodes[i]);
}
// Extract CSS Rules
var extractedCSSRules = [];
for (i = 0; i < document.styleSheets.length; i++) {
var s = document.styleSheets[i];
try {
if (!s.cssRules) continue;
} catch( e ) {
if (e.name !== 'SecurityError') throw e; // for Firefox
continue;
}
var cssRules = s.cssRules;
var ruleMatches;
for (var r = 0; r < cssRules.length; r++) {
ruleMatches = nodesToCheck.reduce(function (a, b) {
return a || b.matches(cssRules[r].selectorText);
}, false);
if (ruleMatches)
extractedCSSRules.push(cssRules[r].cssText);
}
}
return extractedCSSRules.join(' ');
}
You still need to use rules internal to the svg (e.g. you still need to change #priceWithMilestones .line to .line in the CSS), but for future projects, I think it should catch more elements.
Updated fiddle with all of the changes: https://jsfiddle.net/c19664p3/12/
Related
I have a problem with a panel development. The panel generates a bar graph for the current reading and draws lines for the lower and upper limits. This works great. Now I want to draw a sparkline to it. I first draw this sparkline in a separate div element below the actual graph.
In the graph I have two rect elements, one for the background and one for the actual bar. My goal now is to determine the size of the background rect element, then assign this size to my div for the sparkline and then place the sparkline div over the graph.
But the problem is that I can't access the rect element (it's just not found).
Hopefully my question is understandable. What am I doing wrong?
Here is the code snippet:
...
var panelID = "dd-multistat-panel-" + id;
var tooltipDivID = "dd-multistat-panel-tooltip-" + id;
var RectBackID = "dd-multistat-panel-back-" + id;
var RectBackClass = "dd-multistat-panel-back-" + id;
var RectBarID = "dd-multistat-panel-bar-" + id;
...
// draw the background
svg
.append("g")
//.attr("id", RectBackID)
//.attr("class", RectBackClass)
.selectAll("rect")
.data(stripedata)
.enter()
.append("rect")
.attr("id", RectBackID)
.attr("class", RectBackClass)
.attr("width", w)
.attr("height", stripeScale.step())
.attr("x", left)
.attr("y", function (d) {
return stripeScale(d);
})
.attr("fill", "rgba(0,0,0,0)")
.attr("stroke", OutlineColor)
.on("mouseover", function (d) {
if (showTooltips || Links.length /* && i < data.length*/)
tooltipShow(d);
})
.on("mouseleave", function () {
if (!isInTooltip) {
tooltipHide(false);
}
});
...
//my seach code
var BarClassID = "." + panelID;
var PanelBackID = "#" + RectBackID;
var PanelBackClass = "." + RectBackClass;
console.log("var findBar = d3.select(" + BarClassID + ")");
var findBar = d3.select(BarClassID);
console.log(findBar.nodes()); // --> finds 1 svg
console.log("var findRect = findBar.selectAll(" + PanelBackID + ")");
var findRect = findBar.selectAll(PanelBackID);
console.log(findRect.nodes()); // --> finds 0 elements
console.log("var findRect2 = d3.selectAll(" + PanelBackID + ")");
var findRect2 = d3.selectAll(PanelBackID);
console.log(findRect2.nodes()); // --> finds 0 elements
console.log("var findRect3 = d3.selectAll(" + PanelBackClass + ")");
var findRect3 = d3.selectAll(PanelBackClass);
console.log(findRect3.nodes()); // --> finds 0 elements
console.log("var findRect4 = d3.selectAll(svg)");
var findRect4 = d3.selectAll("svg");
console.log(findRect4.nodes()); // --> finds 55 svg
console.log("var findRect5 = d3.selectAll(g)");
var findRect5 = d3.selectAll("g");
console.log(findRect5.nodes()); // --> finds 0 elements
console.log("var findRect6 = d3.selectAll(rect)");
var findRect6 = d3.selectAll("rect");
console.log(findRect6.nodes()); // --> finds 0 elements
Instead of creating multiple svgs, you should create one svg and append your bar graph and spakrline to that.
In case you stick to same logic, try using d3-selection to select your rect.
import * as d3Select from 'd3-selection';
d3Select.select('#your-rect-id');
Here are some helpful links -
ngx-charts
Simple Bar Graph
Graph Gallery
function base_axes() {
var s = Snap("#base_axes");
var dim = 0.1*window.innerWidth;
var x_line = s.line(0, dim, 0, dim);
x_line.attr("stroke", "#5e0734");
x_line.attr("stroke-width", "5px");
x_line.animate({
x2: window.innerWidth
}, 1000, mina.easein);
var y_line = s.line(dim, 0, dim, 0);
y_line.attr("stroke", "#5e0734");
y_line.attr("stroke-width", "5px");
y_line.animate({
y2: window.innerHeight
}, 1000, mina.easein);
Snap.load('https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg', function(data) {
var logo = s.append(data);
var bbox = logo.getBBox();
var scale_factor = dim/bbox.height;
var transform_string = "s" + scale_factor + "," + scale_factor;
logo.transform(transform_string);
});
}
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/snap.svg.js"></script>
<body onload="base_axes()">
<svg id="base_axes" height="100%" width="100%"></svg>
I'm using this to load an svg into another svg and then transform it:
<svg id="base" height="100%" width="100%"></svg>
JS:
var s = Snap("#base");
var dim = 1;
Snap.load('img.svg', function(data) {
var logo = s.append(data);
var bbox = logo.getBBox();
console.log(bbox);
var scale_factor = dim/bbox.height;
var transform_string = "'s" + scale_factor + "," + scale_factor + "'";
logo.transform(transform_string);
});
But nothing happens. In an effort to troubleshoot, I replaced the bottom line with logo.transform('s0.1,0.1'), and that failed too. Is there something wrong with the creation of logo?
To clarify - the first svg, #id, is selected correctly, the new svg (logo) is correctly appended to it, and bbox is calculated correctly, but the final transform does nothing. The transform string looks correct, evaluating to s0.03,0.03, but the final line logo.transform(transform_string) does nothing.
I think your problem is this line, but I can't be sure without seeing it in a test example...
var logo = s.append(data);
If you look at the docs here, it says it returns the parent element. So you are saying 'logo = the svg element'.
The svg element doesn't allow transforms (in some browsers, see Roberts comment below).
So you either want to select for example a 'g' element in the svg logo by selecting it (eg s.select('#logo') or Snap('#logo'), but we haven't seen that to know if it exists), or append the svg logo to a 'g' element thats inside your svg element eg
<svg id="base" height="100%" width="100%"><g id="logo"></g></svg>
then you can apply the transform to that, rather than the svg, eg
var logo = Snap('#logo').append(data)
You also need to remove the quotes in your transform string. I.e
var transform_string = "s" + scale_factor + "," + scale_factor;
While I'm on my way into learning the secrets of the beautiful world of Data Visualization, I'm encountering some difficulties with D3.js and the loading process of external data from a csv or a json file.
I'm kinda a newbie with JS so I'd like some help from experts.
Below my code:
var w = 500;
var h = 500;
// I'm setting up an empty array
var csvData = [];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Get the data
d3.csv("csv/cities.csv", function(dataset) {
for(var i = 0; i < dataset.length; i++) {
csvData.push(dataset[i]);
}
});
// Draw data
svg.select("body").selectAll("p")
.data(csvData)
.enter()
.append("p")
.text(function(d) { return d });
Well, I'm not sure I did understand well the correct way to load data and process these values. Can someone be so kind to give me an hint? I have access to the csvData array (using the console from the developers tools) but I can't see any data returned with the // Draw data section.
This is the csv file:
csv/cities.csv
city,state,population,land area
seattle,WA,652405,83.9
new york,NY,8405837,302.6
boston,MA,645966,48.3
kansas city,MO,467007,315.0
Thanks
The snippet below is an ajax call which loads csv/cities.csv asynchronously:
// Get the data
d3.csv("csv/cities.csv", function(dataset) {
for(var i = 0; i < dataset.length; i++) {
csvData.push(dataset[i]);
}
});
Thus the draw data section should have been like shown below:
// Get the data
d3.csv("csv/cities.csv", function(dataset) {
for(var i = 0; i < dataset.length; i++) {
csvData.push(dataset[i]);
}
// Draw data
svg.select("body").selectAll("p")
.data(csvData)
.enter()
.append("p")
.text(function(d) { return d });
});
Next Mistake:
You cannot add a p DOM inside SVG, that is the reason why you don't see the p DOM elements. I have appended the p DOM element into the body DOM that fixed the problem.
Working fiddle here
I am working with a d3 force based graph, whose node labels are in fact URLs, which when clicked, take the user to the target URL. For usability reasons, is there a way to underline the url? Better yet, can the underline appear and disappear, can the color of the text be changed, as the user hovers over a certain label? This would help users understand that the labels are clickable. Please help.
document.addEventListener('DOMContentLoaded', function () {
drawVisual();
});
var QueuedORG = [];
var tempLIST = [];
function drawVisual()
{
//alert(sessionStorage["queuedArray"]);
/*var getArr = [];
getArr = JSON.parse(localStorage.getItem('storeArray'));
document.getElementById('myMSG').innerHTML = getArr[1].parentURL;*/
QueuedORG.length = 0;
tempLIST.length = 0;
//var w = 1024, h = 768;
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
//var w = 1024, h = 768;
//var vis = d3.select("#tab_5_contents").append("svg:svg").attr("width", w).attr("height", h);
var vis = d3.select("#forcedLayoutGraph").append("svg:svg").attr("width", w).attr("height", h);
//get links from LocalStorage
//QueuedORG = JSON.parse(sessionStorage.getItem("queuedArray"));
//QueuedORG = JSON.parse(localStorage["queuedArray"]);
QueuedORG.push({url: "http://understandblue.blogspot.com/", parentURL: "http://understandblue.blogspot.com", used:0});
QueuedORG.push({url: "http://www.google.com", parentURL: "http://understandblue.blogspot.com/", used:0});
QueuedORG.push({url: "http://paperfriendly.blogspot.com", parentURL: "http://understandblue.blogspot.com/", used:0});
QueuedORG.push({url: "http://4pawsforever.org", parentURL: "http://understandblue.blogspot.com/", used:0});
QueuedORG.push({url: "http://en.wikipedia.org", parentURL: "http://understandblue.blogspot.com/", used:0});
var nodes = [];
nodes.length = 0;
var labelAnchors = [];
labelAnchors.length = 0;
var labelAnchorLinks = [];
labelAnchorLinks.length = 0;
var links = [];
links.length = 0;
for(var i = 0; i < QueuedORG.length; i++)
{
var nodeExists = 0;
//check to see if a node for the current url has already been created. If yes, do not create a new node
for(var j = 0; j < nodes.length; j++)
{
if(QueuedORG[i].url == nodes[j].label)
nodeExists = 1;
}
if (nodeExists == 0)
{
var urlLabel = QueuedORG[i].url;
//remove 'http://' part
/*urlLabel = urlLabel.split("http://")[1];
if(urlLabel.match("www"))
urlLabel = urlLabel.split("www.")[1];
var rest = urlLabel.split("\.")[1];
urlLabel = urlLabel.split("\.")[0];*/
var node = {
label : QueuedORG[i].url,
category : QueuedORG[i].category
};
nodes.push(node);
labelAnchors.push({
node : node
});
labelAnchors.push({
node : node
});
}
};
/*for(var i=0;i<nodes.length; i++)
{
console.log("node i:"+i+nodes[i]+"\n");
console.log("labelAnchor i:"+i+labelAnchors[i]+"\n");
}*/
//To create links for connecting nodes
for(var i = 0; i < QueuedORG.length; i++)
{
var srcIndx = 0, tgtIndx = 0;
for(var j = 0; j < nodes.length; j++)
{
if( QueuedORG[i].url == nodes[j].label ) //to find the node number for the current url
{
srcIndx = j;
}
if( QueuedORG[i].parentURL == nodes[j].label ) //to find the node number for the parent url
{
tgtIndx = j;
}
}
//console.log("src:"+srcIndx+" tgt:"+tgtIndx);
//connecting the current url's node to the parent url's node
links.push({
source : srcIndx,
target : tgtIndx,
weight : 1,
});
labelAnchorLinks.push({
source : srcIndx * 2,
target : srcIndx * 2 + 1,
weight : 1
});
};
var force = d3.layout.force().size([w, h]).nodes(nodes).links(links).gravity(1).charge(-10000).linkStrength(function(x) {
return x.weight * 10 // charge is for inter-node repel, link distance is node-node distance
});
force.linkDistance(function(d) {
return d.weight * 100;
});
force.start();
var force2 = d3.layout.force().nodes(labelAnchors).links(labelAnchorLinks).gravity(0).linkStrength(10).charge(-500).size([w, h]); //charge is for inter-label repel, link distance is node-label distance
force2.linkDistance(function(d) {
return d.weight * 10;
});
force2.start();
var link = vis.selectAll("line.link").data(links).enter().append("svg:line").attr("class", "link").style("stroke", "#CCC");
var colors = {"1": "black", "2": "blue", "3": "red"}; // 1=root node 2=blog nodes 3=.org nodes
var shape = {"1": "diamond", "2": "cross", "3": "circle"};
var node = vis.selectAll("g.node").data(force.nodes()).enter().append("path").attr("class", "node").call(force.drag);
//node.append("circle").attr("r", 5).style("stroke", "#FFF").style("stroke-width", 3).attr("class", function(d) {return "node category"+d.category});
node.attr("d", d3.svg.symbol().type(function(d) {return shape[d.category];})).style("stroke", "#FFF").style("fill", function(d){ return colors[d.category];}).on('click', function(d, i) {
var win = window.open(d.node.label, '_blank);
win.focus();
});
var anchorLink = vis.selectAll("line.anchorLink").data(labelAnchorLinks)//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999");
var anchorNode = vis.selectAll("g.anchorNode").data(force2.nodes()).enter().append("svg:g").attr("class", "anchorNode").on('click', function(d, i){
var win = window.open(d.node.label, '_blank);
win.focus();
});
anchorNode.append("svg:circle").attr("r", 0).style("fill", "#FFF");
anchorNode.append("svg:text").text(function(d, i) {
return i % 2 == 0 ? "" : d.node.label
}).style("fill", "#555").style("font-family", "Arial").style("font-size", 12);
var updateLink = function() {
this.attr("x1", function(d) {
return d.source.x;
}).attr("y1", function(d) {
return d.source.y;
}).attr("x2", function(d) {
return d.target.x;
}).attr("y2", function(d) {
return d.target.y;
});
}
var updateNode = function() {
this.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
force.on("tick", function() {
force2.start();
node.call(updateNode);
anchorNode.each(function(d, i) {
if(i % 2 == 0) {
d.x = d.node.x;
d.y = d.node.y;
} else {
var b = this.childNodes[1].getBBox();
var diffX = d.x - d.node.x;
var diffY = d.y - d.node.y;
var dist = Math.sqrt(diffX * diffX + diffY * diffY);
var shiftX = b.width * (diffX - dist) / (dist * 2);
shiftX = Math.max(-b.width, Math.min(0, shiftX));
var shiftY = 5;
this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
}
});
anchorNode.call(updateNode);
link.call(updateLink);
anchorLink.call(updateLink);
});
}
As Matt Walters said, you can change the text colour and add underlining with CSS, including adding hover effects.
However, I would highly recommend that you implement your links as actual <a> element hyperlinks, which are perfectly acceptable in SVG. I've tested it, and you can either wrap the text element in a link, or put the link inside the text element, but surrounding the actual text content. The only complication is that you have to use xlink:href for the url attribute, instead of simply href.
Here's a force-directed graph I created for someone else's debugging, adapted to turn all the text labels into links:
http://codepen.io/AmeliaBR/pen/AoFHg
Key code in the update function:
hypertext = hypertext.data(force.nodes());
// hypertext refers to a selection of text elements, joined to the data
// Add labels for new nodes:
hypertext.enter().append("text") //add the text element
//add any unchanging attributes of the <text>:
.attr("text-anchor", "middle")
//add a link element within each text element
.append("a")
//add unchanging attributes of the <a> link
.attr("target", "_blank") //set the link to open in an unnamed tab
.attr("xlink:show", "new");
//show="new" is an XML way to tell the link to open in a new tab/window.
//Either attribute *should* work on its own, but best use both to be safe.
// At this point, each new <text> element contains an <a> element, but the
// variable hypertext still refers to the text elements.
// Remove any outgoing/old text elements for non-existent nodes:
hypertext.exit().remove();
// Compute data-based attributes for entering and updating texts:
hypertext.attr("x", 8) //attributes of the <text> elements
.attr("y", "0.3em")
//Select the existing <a> element within each <text>
.select("a")
//Update the link attributes. Note that the <a> element was never given
//its own data, so it inherits the data from the parent <text> element.
.attr("xlink:href", function (d) {
return "http://example.com/" + d.name; //create url from data
})
//Set the text within the link, which in this case is the only text
//within the text element.
.text(function (d) {
return d.name; //link text content
});
Using the link element created all the necessary functionality, but it didn't add the default HTML link styles. For that, there's CSS:
text a {
fill: navy;
}
text a:visited {
fill:darkpurple;
}
text a:hover, text a:active {
text-decoration: underline;
fill:darkred;
}
I think you should be able to do all of this in css. Thats part of the beauty of d3.js
Without seeing some code it'll be hard to say exactly what you need, but Ill bet you could do something like this for the underlining and something similar for the other effects you have.
Can you post some code, so we can help you further?
Has anyone tried using a svg to canvas library when creating d3.js visualizations? I've tried to use canvg.js and d3.js to convert svg to canvas from within an android 2.3 application webview, but when I call:
svg.selectAll(".axis")
.data(d3.range(angle.domain()[1]))
.enter().append("g")
.attr("class", "axis")
.attr("transform", function(d) { return "rotate(" + angle(d) * 180 / Math.PI + ")"; })
.call(d3.svg.axis()
.scale(radius.copy().range([-5, -outerRadius]))
.ticks(5)
.orient("left"))
.append("text")
.attr("y",
function (d) {
if (window.innerWidth < 455){
console.log("innerWidth less than 455: ",window.innerWidth);
return -(window.innerHeight * .33);
}
else {
console.log("innerWidth greater than 455: ",window.innerWidth);
return -(window.innerHeight * .33);
}
})
.attr("dy", ".71em")
.attr("text-anchor", "middle")
.text(function(d, i) { return capitalMeta[i]; })
.attr("style","font-size:12px;");
I get the error: Uncaught TypeError: Cannot call method setProperty of null http://mbostock.github.com/d3/d3.js?2.5.0:1707
Would some sort of headless browser application, or a server side js parser work? Has anyone encountered this before?
Here's one way you could write your svg to canvas (and then save the result as a png or whatever):
// Create an export button
d3.select("body")
.append("button")
.html("Export")
.on("click",svgToCanvas);
var w = 100, // or whatever your svg width is
h = 100;
// Create the export function - this will just export
// the first svg element it finds
function svgToCanvas(){
// Select the first svg element
var svg = d3.select("svg")[0][0],
img = new Image(),
serializer = new XMLSerializer(),
svgStr = serializer.serializeToString(svg);
img.src = 'data:image/svg+xml;base64,'+window.btoa(svgStr);
// You could also use the actual string without base64 encoding it:
//img.src = "data:image/svg+xml;utf8," + svgStr;
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = w;
canvas.height = h;
canvas.getContext("2d").drawImage(img,0,0,w,h);
// Now save as png or whatever
};
The answer by #ace is very good, however it doesn't handle the case of external CSS stylesheets. My example below will automatically style the generated image exactly how the original SVG looks, even if it's pulling styles form separate stylesheets.
// when called, will open a new tab with the SVG
// which can then be right-clicked and 'save as...'
function saveSVG(){
// get styles from all required stylesheets
// http://www.coffeegnome.net/converting-svg-to-png-with-canvg/
var style = "\n";
var requiredSheets = ['phylogram_d3.css', 'open_sans.css']; // list of required CSS
for (var i=0; i<document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
if (sheet.href) {
var sheetName = sheet.href.split('/').pop();
if (requiredSheets.indexOf(sheetName) != -1) {
var rules = sheet.rules;
if (rules) {
for (var j=0; j<rules.length; j++) {
style += (rules[j].cssText + '\n');
}
}
}
}
}
var svg = d3.select("svg"),
img = new Image(),
serializer = new XMLSerializer(),
// prepend style to svg
svg.insert('defs',":first-child")
d3.select("svg defs")
.append('style')
.attr('type','text/css')
.html(style);
// generate IMG in new tab
var svgStr = serializer.serializeToString(svg.node());
img.src = 'data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svgStr)));
window.open().document.write('<img src="' + img.src + '"/>');
};
And, to be complete, the button that calls the function:
// save button
d3.select('body')
.append("button")
.on("click",saveSVG)
.attr('class', 'btn btn-success')
Have you tried the same code on a browser supporting SVG to see if it's a problem with webview? Then try this example using canvg or this one using DOM serialization. For server-side rendering, you could start with this example for how to render it to canvas server-side using Node.js.
I've not tried a library, but have rendered a d3-produced SVG to a canvas following this post on MDN.
This code is a quick mish-mash of the MDN and some jQuery, that'll you'll need to tidy up, and it has no error- or platfrom-checking, but it works, and I hope it helps.
$(document.body).append(
'<canvas id="canvas" width="'+diameter+'" height="'+diameter+'"></canvas>'
);
// https://developer.mozilla.org/en/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas
var el = $($('svg')[0]);
var svgMarkup = '<svg xmlns="http://www.w3.org/2000/svg"'
+ ' class="' + el.attr('class') +'"'
+ ' width="' + el.attr('width') +'"'
+ ' height="' + el.attr('height') +'"'
+ '>'
+ $('svg')[0].innerHTML.toString()+'</svg>';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = this.URL || this.webkitURL || this;
var img = new Image();
var svg = new Blob([svgMarkup], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
alert('ok');
DOMURL.revokeObjectURL(url);
};
img.src = url;