title: How can I render a d3 chart, export it as an image, then load the next data set, plot the next chart and export again
body: <p>I'm building a medical application where I have to show injuries to certain people from a certain department. I'm using d3 to mark the injured areas on an svg illustration that I traced. So for example, if someone had a spill on their arm, the svg graphic would show the arm in red. I managed to do this part and write a function to export the svg as an image and show it on the same screen in a div, as a thumbnail. </p>
  
  <p>My goal is to enable the user to select a department and I need to render an svg map for everyone in that department and show the thumbnails inside a div tag so they can visually see whats going on.</p>
  
  <p>My data set is in this format: x1,x2,x3...|y1,y2,y3...|... where x are the ids of the svg to light up red for person X and y are the ids for another person Y.</p>
  
  <p>Example:     boneID_043,boneID_046,boneID_038,boneID_029,boneID_027|boneID_043,boneID_046,boneID_038,boneID_029,boneID_027</p>
  
  <p>The way I designed it is:</p>
  
  <ol>
  <li>Load the data set from a SQL query</li>
  <li>Load the first data group into the SVG using d3</li>
  <li>Render the SVG inside a div tag #diagram which is set to display:none;</li>
  <li>Run the export function to make an image blob and show it in a new div </li>
  <li>Load next data group from data set and repeat</li>
  </ol>
  
  <p>This is what it looks like after running for one person and clicking on my export to image button, which calls a function exportD3();</p>
  
  <p><img src="https://i.imgur.com/kBwlRJh.jpg" alt="injury map"></p>
  
  <p>EDIT: Apologies, i forgot to output wthe current result. Here is what I see after my code runs, for 2 people's data groups. There is a link to a blob file, so the export did create an image blob If i click on my manual export button then it exports the 2nd person's data correctly as shown above.</p>
  
  <p><img src="https://i.imgur.com/59PQpKO.jpg" alt="[blank map"></p>
  
  <p>My problem is that after postback (via a button that does the query in c#/asp.net to get the data and post it inside a div) I try to loop through the data set above and load the SVG with these ids, and then run my export function but I only see blank images, as if the export ran before the svg was loaded. However after postback if I click on my export button, it does export the latest svg with the last data (y in this case).</p>
  
  <p>I cant figure out why the export wont work through code. Is there a way for javascript to wait for the render to complete and then export for example could this be a concurrency issue? I thought it was because the #diagram div (where the render happens) was hidden but it does work when I push my manual button. I also did try to copy and paste the export code from exportD3() right into the for loop but that doesnt work either</p>
  
  <p>Here is my code:</p>
  
  <p>Assume:</p>
  
  <ol>
  <li><p>A div tag called #diagram that hold the svg during every render</p></li>
  <li><p>combined.json is my svg illustration file for the human body</p></li>
  <li><p>imgSVG is a div tag that will hold multiple divs with a thumbnail image blob everytime we append a new image to it</p></li>
  <li><p>bArray contains the bones affected and fArray contains the flesh/surface injuries and they will always have the same length</p>
  
  <pre><code>var bArray = document.getElementById("     &lt;%=boneIds.ClientID%&gt;").innerHTML.split('|');
  var fArray = document.getElementById("&lt;%=bodyPartsIds.ClientID%&gt;").innerHTML.split('|');
  
  var width = 720, height = 720;
  
  svg = d3.select("#diagram").append("svg")
  .attr("width", width)
  .attr("height", height)
  .call(d3.behavior.zoom()
  .on("zoom", redraw))
  .append("g")
  .attr("transform", "translate(5.1261,2)scale(0.4152752)"); //15.1261,-38.639
  </code></pre></li>
  </ol>
  
  <p>Now I want to loop through the data groups within the dataset, load up the svg and export into a thumbnail and append each inside the #imgSVG div</p>
  
  <pre><code>for(var i = 0; i &lt; bArray.Length; i++) 
      {
  //Split the data by comma
  d3.json("data/combined.json", function (data) {
              svg.selectAll("polygon")
                  .data(data.Polygons)
                  .enter().append("polygon")
                  .attr("points", function (d) { //logic here }
                  .attr("fill", function (d) { //logic here };
  
      //Then export to image blob
      exportD3();
  }
  
   function exportD3()
      {
          //This function xports the d3 figures to a div tag
          var doctype = '&lt;?xml version="1.0" standalone="no"?&gt;'
              + '&lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt;';
  
          // serialize the SVG to a string.
          var source = (new XMLSerializer()).serializeToString(d3.select('svg').node());
  
          // create a file blob
          var blob = new Blob([doctype + source], { type: 'image/svg+xml;charset=utf-8' });
  
          var url = window.URL.createObjectURL(blob);
  
          //Next line just shows the parts affected
          var info2 = "&lt;h3&gt;" + document.getElementById("&lt;%=nameInfo.ClientID%&gt;").innerText + "&lt;/h3&gt;&lt;br/&gt;&lt;b&gt;Bones Affected:&lt;/b&gt;&lt;br /&gt;" + boneParts.join(", ") + "&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Surface Parts Affected:&lt;/b&gt;&lt;br /&gt;" + bParts.join(", ");
  
  
          var img = d3.select('#imgSVG').append("div")
              .attr('class', 'divs')
              .style("opacity", 1)
              .style('width', '300px')
              .style('height', '400px')
              .style('float', 'left')
          .html(info)
              .append('img')
               .attr('width', 300)
               .attr('height', 300)
               .node();
  
          img.src = url;
      }
  </code></pre>