Display image in d3.js from Android tablet image path

I am using Android to send data to d3.js webview in JSON format. I have faced a problem. Here I have a d3.js code like this. I have attached the example of this code so that it can be run. https://drive.google.com/file/d/0B7Ztdu46v0uOZjhvTG5HRlVRRG8/edit?usp=sharing

var RADIUS = 5;
var moved = false;
var graph = {};
var nodes, links;

var svg = d3.select("svg");

// Retreive SVG element's width and height
// TODO: This needs to be fixed. This code terribly fails when width and
// height attributes are not specified in pixels.
var SVG_WIDTH = svg.attr('width');
var SVG_HEIGHT = svg.attr('height');
svg.append("image")
     .attr("x", 0)
      .attr("y", 0)
       .attr("xlink:href", "Map.jpg")
        .attr("width", SVG_WIDTH)
         .attr("height", SVG_HEIGHT);


svg.append("defs")
  .append("marker")
    .attr("id", "head")
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("refY", 0)
    .attr("markerWidth", 2)
    .attr("markerHeight", 2)
    .attr("orient", "auto")
    .attr("class", "link")
  .append("path")
    .attr("d", "M0,-5L10,0L0,5");

var drag = d3.behavior.drag()
  .origin(Object)
  .on("drag", dragMove)
  .on("dragend", dragEnd)
  ;

// Prepare a group to draw links
svg.append("g").attr("class", "links");

// Prepare a group to draw nodes
svg.append("g").attr("class", "nodes");

///////////////////////////////////////////////////////////////////
// Function to update SVG contents with current nodes and links 
// info attached to each SVG element (including the newly added
// ones).  Animation effects are performed if anim is true.
///////////////////////////////////////////////////////////////////
function update(anim) {
  nodes.select(".node")
      .classed("gw", function(d) 
      {
        return graph.nodes[d].type == 'gw';
      });

  if (anim)
  {
    updatedNodes = nodes.transition().duration(300).ease("linear");
    updatedLinks = links.transition().duration(300).ease("linear")
                      .attr("opacity", "1");
  }
  else
  {
    updatedNodes = nodes;
    updatedLinks = links;
  }
  updatedLinkShadow = linkShadow;

  updatedNodes.attr("transform", function(d) {
        return "translate(" + graph.nodes[d].pos + ")";
      });
  updatedLinks.attr("d", drawLink);
  updatedLinkShadow.attr("d", drawLink);
}

function drawLink(pair) {
    console.log(pair);
  var dx = graph.nodes[pair[0]].pos[0] - graph.nodes[pair[1]].pos[0];
  var dy = graph.nodes[pair[0]].pos[1] - graph.nodes[pair[1]].pos[1];
  var dist = Math.sqrt(dx*dx+dy*dy);
  return "M" + graph.nodes[pair[0]].pos 
      + "A" + dist + "," + dist + " 0 0,0 " +
      graph.nodes[pair[1]].pos;
}

///////////////////////////////////////////////////////////////////
// Function to perform data join between the graph model ('graph')
// and SVG elements
///////////////////////////////////////////////////////////////////
function joinGraph() {
  //////////////////////
  // Link data join
  //////////////////////
  links = svg.select("g.links").selectAll("path.link")
    .data(graph.links, function(d) { return d;});
  linkShadow = svg.select("g.links").selectAll("path.linkshadow")
    .data(graph.links, function(d) { return d;});

  linkShadow.enter()
    .append("path")
    .classed("linkshadow", true)
    .attr("marker-end", "url(#head)")
    .attr("d", drawLink)
    .attr("opacity","1")

  links.enter()
    .append("path")
    .classed("link", true)
    //.attr("marker-end", "url(#head)")
    .attr("d", drawLink)
    .attr("opacity","0")

  var goneLinks = links.exit();
  linkShadow.exit().remove();

  // Node data join
  // *Notes* Set key to be value rather than index
  nodes = svg.select("g.nodes").selectAll("g")
        .data(d3.keys(graph.nodes), Number); 

  // Nodes just appearing
  var newNodes = nodes.enter().append("g").call(drag);

  // Nodes no longer exist
  var goneNodes = nodes.exit();

  newNodes
    .append("circle")
    .attr("r", RADIUS)
    .classed("node", true)
    ;

  newNodes
    .append("text")
    .attr("x", RADIUS+2)
    .attr("y", RADIUS+2)
    .attr("class", "shadow")
    .text(String)
    ;

  newNodes
    .append("text")
    .attr("x", RADIUS+2)
    .attr("y", RADIUS+2)
    .attr("fill", "blue")
    .text(String)
    ;

  // Update SVG elements with animation
  update(true);

  // Remove nodes and links that no longer exist
  goneNodes
    .transition().duration(300).ease("linear")
      .attr("transform", "translate(0,0)")
    .remove();
  goneLinks
    .attr("opacity", "1")
    .transition().duration(300).ease("linear")
      .attr("opacity", "0")
    .remove();

}

///////////////////////////////////////////////////////////////////
// Function to be called by D3 when a node SVG element is dragged.
// The new position is updated to the 'graph' variable and then the
// corresponding SVG elements.
///////////////////////////////////////////////////////////////////
function dragMove(d) {
  // Update position of the dragged node in the graph model
  var newpos = graph.nodes[d].pos;
  newpos[0] += d3.event.dx;
  newpos[1] += d3.event.dy;
  newpos[0] = Math.max(0, Math.min(newpos[0], SVG_WIDTH));
  newpos[1] = Math.max(0, Math.min(newpos[1], SVG_HEIGHT));

  // Update SVG elements without animation
  update(false);

  moved = true;
}

///////////////////////////////////////////////////////////////////
// Function to be called by D3 when a node SVG element is dropped.
///////////////////////////////////////////////////////////////////
function dragEnd(d) {
  if (moved)
  {
    d3.select("#msg").text("Updating node " + d + " to database");
    moved = false;
  }
  else
    d3.select("#msg").text("Showing " + d + " details");
}

///////////////////////////////////////////////////////////////////
// *FOR TESTING* Function to be called when test buttons are clicked.
// It reloads a graph from the given name in form of JSON
///////////////////////////////////////////////////////////////////
function reload(g) {
  d3.json("./" + g + ".json.php", function(json)
  {
    graph = json;
    joinGraph();
  });
}

And my JSON data are in the file graph1.json.php. I would like to append an image from a path in an Android tablet, such as /mnt/sdcard/DCIM/Camera/Map.jpg, but I don't know how to extract an element, select("g"), selectAll, and so on. I also don't know how to bring that path into xlink:href. I just put the image into Android asset/ which is not versatile at all. I want to use any path for a picture to be inserted as the screen background.

Moreover, I would like to use width and height obtained in graph1.json.php to be set in update-anim.html. I wonder if this is possible or if I have to set it through JavaScript only.

Can anybody help me on this?

Answers


Your sample data format is

{
  "nodes": {
   "1": {"pos":[100,200], "type":"gw" },
   "2": {"pos":[330,150], "type":"node" },
   "3": {"pos":[130,150], "type":"node" },
   "5": {"pos":[230,100], "type":"gw" },
  "10": {"pos":[430,200], "type":"node" }
  },
  "links": [[3,5],[1,2],[10,1],[1,3],[3,1]]
  "mapimage": {"path":"/mnt/sdcard/DCIM/Camera/Map.jpg", 
                "width":"1280", "height"":"720"}
}

So when you read in the data, you have the path in your data object. You just need to set the xlink:href of your <image> element in your data-handling function (joinGraph()). You can still create the image element in your initialization, without the source path, and then either save it in a variable or re-select it later on.

/* Initialization */
var background = svg.append("image")
     .attr("x", 0)
     .attr("y", 0)
     .attr("preserveAspectRatio", "xMidYMid slice") 
       // This prevents the aspect ratio from being distorted;
       // skip if the image can be stretched to fit.
       // xMidYMid will center the image in the SVG;
       // slice means that it will be sized big enough to cover 
       // the background, even if some of the image is cut off.
       // Use "xMidYMid meet" if you want the whole image shown
       // even if that leaves empty space on the sides
     .attr("width", SVG_WIDTH)
     .attr("height", SVG_HEIGHT);

/* Link to data */
function joinGraph() {

   background.attr("xlink:href", graph.mapImage.path);

   /* The rest of the joinGraph method is the same */
}

As for how to figure out the width and height of a SVG sized by CSS, you use window.getComputedStyle() to get the actual pixel length that's being used. Note, though, that if there's any chance your code will also be used on Firefox, you have to set CSS display:block; or display:inline-block; on the SVG -- there's a firefox bug that gives unprocessed width and height values on inline SVG.

var svg = d3.select("svg")

var SVG_WIDTH = parseFloat( getComputedStyle(svg.node())['width'] );
var SVG_HEIGHT = parseFloat( getComputedStyle(svg.node())['height'] );
    //selection.node() extracts the first (and only) svg DOM element
    //from the selection, so it can be used by Javascript functions
    //getComputedStyle returns height and width as pixel lengths
    //parseFloat strips off the "px" to return a number

Need Your Help

IF ELSE condition when working with numbers

php if-statement resolution screen-resolution

There is a problem that my brain I can not afford to solve, namely the creation of if-else conditions: