Reputation: 2004
in my D3 code, I'm using external SVGs to represent data points. I can embed them like this:
group.append("svg:image")
.attr("xlink:href","https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg")
However, they are displayed on mouseover and need a short time to load, so I'd like to preload them at the start of the script:
var icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
icon.setAttribute("xlink:href", "https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg");
I haven't been able to append that object to a group element with D3 though. I've tried group.append(icon)
as well as giving the object an id and then saying group.append("#id")
. Is there a way? Sample code below:
var icon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
icon.setAttribute("xlink:href", "https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg");
icon.setAttribute("id","icon");
var width = 400;
var height = 200;
var svg = d3.select("body")
.append("svg");
svg.attr("width", width)
.attr("height", height);
group = svg.append("g");
group.append("svg:image")
.attr("x",0)
.attr("y",0)
.attr("xlink:href","https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg")
.attr("height",200)
.attr("width",200);
/*group.append(icon)
.attr("x",0)
.attr("y",0)
.attr("height",200)
.attr("width",200);*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1
Views: 584
Reputation: 21578
There are two issues with your code:
The first one has already been addressed by Robert Longson's answer. You have to adjust the newly created element's type to image
and set the namespace argument when setting the attribute on this element.
var icon = document.createElementNS("http://www.w3.org/2000/svg", "image");
icon.setAttributeNS('http://www.w3.org/1999/xlink',
"xlink:href",
"https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg");
When appending the element to the DOM using D3's selection.append()
you have to provide a callback which returns the element to be appended. From the docs:
selection.append(name)
The name may be specified either as a constant string or as a function that returns the DOM element to append. [...] To append an arbitrary element based on the bound data it must be created in the function.
Of course, it doesn't need to be created in the function, but it must be returned by the function, no matter where it was created in the first place. In your code this requires
group.append(function() { return icon; })
var icon = document.createElementNS("http://www.w3.org/2000/svg", "image");
icon.setAttributeNS('http://www.w3.org/1999/xlink', "xlink:href", "https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg");
icon.setAttribute("id","icon");
var width = 400;
var height = 200;
var svg = d3.select("body")
.append("svg");
svg.attr("width", width)
.attr("height", height);
group = svg.append("g");
/*
group.append("svg:image")
.attr("x",0)
.attr("y",0)
.attr("xlink:href","https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg")
.attr("height",200)
.attr("width",200);
*/
group.append(function() { return icon; })
.attr("x",0)
.attr("y",0)
.attr("height",200)
.attr("width",200);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 2
Reputation: 124249
You need to fix your loading bugs with namespaces and elements
var icon = document.createElementNS('http://www.w3.org/2000/svg', 'image');
icon.setAttributeNS('http://www.w3.org/1999/xlink', "xlink:href", "https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg");
then you can do this
group.append("svg:image")
.attr("x",0)
.attr("y",0)
.attr("xlink:href", icon.getAttributeNS('http://www.w3.org/1999/xlink', "href"))
.attr("height",200)
.attr("width",200);
Alternatively you could store the images in Javascript image elements, the result would be the same. I.e.
var icon = new Image();
icon.src = "https://upload.wikimedia.org/wikipedia/commons/a/ac/SVG-Logo2.svg"
and set .attr("xlink:href", icon.src)
Upvotes: 3