So far I’ve used d3.svg.symbol() in a force-directed graph for distinguishing different node types from one another.
I’d now like to distinguish different node types by displaying node as a svg image. Following one of the examples I used the following code to display the node images:
var node = svg.selectAll("image.node").data(json.nodes);
var nodeEnter = node.enter().append("svg:g").append("svg:image")
.attr("class", "node")
.attr("xlink:href", function(d)
{
switch( d.source )
{
case "GEXP": return "img/node_gexp.svg";
case "CNVR": return "img/node_cnvr.svg";
case "METH": return "img/node_meth.svg";
case "CLIN": return "img/node_clin.svg";
case "GNAB": return "img/node_gnab.svg";
case "MIRN": return "img/node_mirn.svg";
case "SAMP": return "img/node_samp.svg";
case "RPPA": return "img/node_rppa.svg";
}
})
.attr("x", function(d) { return d.px; } )
.attr("y", function(d) { return d.py; } )
.attr("width", "50")
.attr("height", "50")
.attr("transform", "translate(-25,-25)")
.on("click", function(d) {
console.log("nodeclick");
} )
.on("mouseover", fade(0.10) )
.on("mouseout", fade(default_opacity) )
.call(force.drag);
This does display the svg images but I’ve two problems:
1) I want to scale the node sizes based on an attribute. From what I understand this can be done by supplying the “scale” attribute
transform="scale(something)"
to a suitable place, like to the image tag itself or to the group containing the image:
var node = svg.selectAll("image.node").data(json.nodes);
var nodeEnter = node.enter()
.append("svg:g")
.attr("transform", function(d)
{
var str = "scale(";
if( d.gene_interesting_score && d.gene_interesting_score > 0 )
{
return str + ( (d.gene_interesting_score - minScore ) / ( maxScore - minScore ) ) + ")";
}
return str + 0.7 + ")";
})
.append("svg:image")
....
As it happens, the scale() transform displaces the images: they are no longer on the endpoint of the edge. How do I resize the images properly when initializing the graph, preferrably so that the controlling mechanism is within a single function (e.g. so that I don’t have to control x,y,width,height separately)?
2) When the graph is zoomed, Chrome blurs the images whereas in Firefox the image remains crispy (picture). How can this blur be avoided?

Edit: Based on duopixel’s suggestions, the code is now:
var nodeGroup = svg.selectAll("image.node").data(json.nodes).enter()
.append("svg:g")
.attr("id", function(d) { return d.id; })
.attr("class", "nodeGroup")
.call(force.drag);
var node = nodeGroup.append("svg:image")
.attr("viewBox", "0 0 " + nodeImageW + " " + nodeImageH)
.attr("class", "node")
.attr("xlink:href", function(d)
{
switch( d.source )
{
case "GEXP": return "img/node_gexp.svg";
case "CNVR": return "img/node_cnvr.svg";
case "METH": return "img/node_meth.svg";
case "CLIN": return "img/node_clin.svg";
case "GNAB": return "img/node_gnab.svg";
case "MIRN": return "img/node_mirn.svg";
case "SAMP": return "img/node_samp.svg";
case "RPPA": return "img/node_rppa.svg";
}
})
.attr("width", nodeImageW)
.attr("height", nodeImageH)
.attr("transform", function(d)
{
var matrix = "matrix(";
var scale = 0.7; // sx & sy
if( d.gene_interesting_score && d.gene_interesting_score > 0 )
{
scale = ( (d.gene_interesting_score - minScore ) / ( maxScore - minScore ) ) * 0.5 + 0.25;
}
//console.log("id=" + d.id + ", score=" + scale );
matrix += scale + ",0,0," + scale + "," + ( d.x - ( scale*nodeImageW/2 ) ) + "," + ( d.y - ( scale*nodeImageH/2 ) ) + ")";
return matrix;
})
// .attr("transform", "translate(-25,-25)")
.on("click", function(d) {
console.log("nodeclick");
} )
.on("mouseover", fade(0.10) )
.on("mouseout", fade(node_def_opacity) );
It solves the problem #1, but not the second one: by selecting
var nodeImageH = 300;
var nodeImageW = 300;
The resulting svg image contains a lot empty space (seen by selecting the image with firebug’s selection tool). The images were created in Inkscape, canvas size cropped to 50×50 which should be the correct viewing pixel size.
#1You need to set the transform origin. In SVG this means that you are going to have to use a transform matrix as answered here: https://stackoverflow.com/a/6714140/524555#2To solve the blurry scaling modify theviewBox, width, heightof yoursvgfiles to start as large images (i.e.<svg viewBox="0 0 300 300" width="300" height="300">.