Svg image representing a node, resizing node in force graphics

So far, I have used d3.svg.symbol () in a force-oriented graph to distinguish different types of nodes from each other.

Now, I would like to distinguish between different types of node, displaying the node as an svg image. Following one example, I used the following code to display 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 displays svg images, but I have two problems:

1) I want to scale node sizes based on attribute. From what I understand, this can be done by providing the attribute "scale"

 transform="scale(something)" 

in a suitable place, for example, the image tag itself or 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 this happens, the scale () transform shifts the images: they are no longer at the endpoint of the edge. How to correctly resize images when initializing the graph, it is preferable that the control mechanism is within the same function (for example, so I do not need to control x, y, width and height separately)?

2) When the graph is scaled, Chrome blurs the image, while in Firefox the image remains crisp (image). How to avoid this blur?

Chrome above, FF below

Edit: Based on duopixel suggestions, the code 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 + "," + ( dx - ( scale*nodeImageW/2 ) ) + "," + ( dy - ( 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) ); 

Solves the problem number 1, but not the second: by choosing

 var nodeImageH = 300; var nodeImageW = 300; 

The resulting svg image contains a lot of empty space (you can see it by selecting the image using the firebug selection tool). Images were created in Inkscape, the canvas size was reduced to 50x50, which should be the correct viewing pixel size.

+4
source share
1 answer

#1 You need to set the start of the conversion. In SVG, this means that you will need to use the transformation matrix as indicated here: fooobar.com/questions/83790 / ...

#2 To solve blurry scaling, change the viewBox, width, height your svg files to start with large images (i.e. <svg viewBox="0 0 300 300" width="300" height="300"> .

+3
source

Source: https://habr.com/ru/post/1432569/


All Articles