title: Scrollbar on svg zoom
body: <p>I am using D3 to create a visualization. The visualization fits well within the available canvas using viewBox</p>
  
  <pre><code>graphArea.attr("viewBox",bbox.x+" "+bbox.y+" "+bbox.width+" "+bbox.height);
  </code></pre>
  
  <p>This works great for smaller graphs. However, for some of the larger graphs, users need to zoom out the diagram for additional clarity.</p>
  
  <p>When the user zooms out the diagram, parts of the diagram are hidden as they are outside the viewBox. </p>
  
  <p><a href="https://i.stack.imgur.com/eBmwa.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/eBmwa.png" alt="Hidden diagram upon zoom"></a></p>
  
  <p>My requirement is that, when user zooms out the diagram, a scroll bar is automatically provided which would enable the user to see the hidden parts by scrolling horizontally or vertically.</p>
  
  <p>I tried dynamically setting the div width and height (which encloses the svg) but that did not help</p>
  
  <pre><code>d3.select("#containerdiv")          
   .attr('width', bbox.width)
   .attr('height', bbox.height);
  
  });
  </code></pre>
  
  <p>Below is the complete code</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var width = 960, height = 400;
  d3.select("body").append("div")
      .attr("id", "containerdiv");
  // REMOVE OLD SVG
  d3.select("#wkfsvg").remove();
  var bbox = null;
       
  // ADD NEW SVG
  var graphArea = d3.select("#containerdiv").append("svg")   
              .attr({ width: width, height: height, "pointer-events": "all" })
     .attr("id","wkfsvg");
  
  
  var g = new dagreD3.graphlib.Graph().setGraph({});
  
  graphArea.insert("g", "g");
  
  var nodesJson = [
      {
          
          "nodes": "Initiate",
          "status": "startend",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Automatic"
      },
      {
         
          "nodes": "Find the Next Approver",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Automatic"
      },
      {
          
          "nodes": "Check for Manager",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Automatic"
      },
      {
          "nodes": "Set Status &amp; ACL for IT Project Manager",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Automatic"
      },
      {
         
          "nodes": "Set Status &amp; ACL for IT Sign Off Approvers",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "IT Project Manager Approves",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          "id": "Finance Approver",
          "nodes": "Finance Approver",
          "status": "dormant",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Send Email for Completion",
          "status": "future",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
         
          "nodes": "Send to Requestor",
          "status": "future",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Send Email to Requestor",
          "status": "completed",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          "id": "Set ACL on Form for Requestor",
          "nodes": "Set ACL on Form for Requestor",
          "status": "future",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
         
          "nodes": "Set Completion ACL on Form",
          "status": "future",
          "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
           "id": "Set Completion ACL on PO",
          "nodes": "Set Completion ACL on PO",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
         
          "nodes": "Set Completion ACL on Attachments",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
         
          "nodes": "Set ACL on Attachment",
          "status": "completed",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Update Comments of PM Rejection",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Update Comments of FA Rejection",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Update Comments of PM",
          "status": "completed",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Update Comments of FA",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
          
          "nodes": "Update Comments of Requestor",
          "status": "future",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      },
      {
         
          "nodes": "End",
          "status": "startend",
           "creation_date": "",
          "performer_name": "",
          "execution_type": "Manual"
      }
  ];      
   
  
  // Automatically label each of the nodes
  nodesJson.forEach(function(node) {
     
      if(node.status == "future") {
          if(node.execution_type == "Manual") {
              g.setNode(node.nodes, { labelType: "html", label: node.nodes+' &lt;tspan dx="0" dy="-10"&gt;\uf007&lt;/tspan&gt;', class: "future" });            
          } else {
              g.setNode(node.nodes, { label: node.nodes, class: "future" }); 
          }
      } else if(node.status == "completed") {
          if(node.execution_type == "Manual") {
              g.setNode(node.nodes, { labelType: "html", label: node.nodes+' &lt;tspan dx="0" dy="-10"&gt;\uf007&lt;/tspan&gt;', class: "completed" });
          } else {
              g.setNode(node.nodes, { label: node.nodes, class: "completed" }); 
          }
      } else if(node.status == "dormant") {
         if(node.execution_type == "Manual") {
              g.setNode(node.nodes, { labelType: "html", label: node.nodes, class: "dormant" });
          } else {
              g.setNode(node.nodes, { label: node.nodes, class: "dormant" }); 
          }
      } else if(node.status == "startend") {
          g.setNode(node.nodes, { label: node.nodes, class: "startend" }); 
      } else {
          g.setNode(node.nodes, { label: node.nodes });
      }   
  });
  
  var edgesJson = [
      {
   
          "type": "approve",
          "source": "Find the Next Approver",
          "target": "Check for Manager"
      },
      {
          "type": "approve",
          "source": "Check for Manager",
          "target": "Set Status &amp; ACL for IT Sign Off Approvers"
      },
      {
          "type": "approve",
          "source": "Check for Manager",
          "target": "Set Status &amp; ACL for IT Project Manager"
      },
      {
          "type": "approve",
          "source": "Set Status &amp; ACL for IT Project Manager",
          "target": "IT Project Manager Approves"
      },
      {
          "type": "approve",
          "source": "Set Status &amp; ACL for IT Sign Off Approvers",
          "target": "Finance Approver"
      },
      {
          "type": "approve",
          "source": "Set ACL on Form for Requestor",
          "target": "Send to Requestor"
      },
      {
          "type": "approve",
          "source": "Set Completion ACL on Form",
          "target": "Set Completion ACL on PO"
      },
      {
          "type": "approve",
          "source": "IT Project Manager Approves",
          "target": "Send Email to Requestor"
      },
      {
          "type": "approve",
          "source": "Set Completion ACL on PO",
          "target": "Set Completion ACL on Attachments"
      },
      {
          "type": "approve",
          "source": "Set Completion ACL on Attachments",
          "target": "Send Email for Completion"
      },
      {
          "type": "approve",
          "source": "Initiate",
          "target": "Set ACL on Attachment"
      },
      {
          "type": "approve",
          "source": "Set ACL on Attachment",
          "target": "Find the Next Approver"
      },
      {
          "type": "approve",
          "source": "Update Comments of PM Rejection",
          "target": "Set ACL on Form for Requestor"
      },
      {
          "type": "reject",
          "source": "IT Project Manager Approves",
          "target": "Update Comments of PM Rejection"
      },
      {
          "type": "approve",
          "source": "Update Comments of FA Rejection",
          "target": "Set ACL on Form for Requestor"
      },
      {
          "type": "approve",
          "source": "Send Email to Requestor",
          "target": "Update Comments of PM"
      },
      {
          "type": "approve",
          "source": "Update Comments of PM",
          "target": "Set Status &amp; ACL for IT Sign Off Approvers"
      },
      {
          "type": "approve",
          "source": "Finance Approver",
          "target": "Update Comments of FA"
      },
      {
          "type": "approve",
          "source": "Update Comments of FA",
          "target": "Set Completion ACL on Form"
      },
      {
          "type": "reject",
          "source": "Finance Approver",
          "target": "Update Comments of FA Rejection"
      },
      {
          "type": "approve",
          "source": "Send to Requestor",
          "target": "Update Comments of Requestor"
      },
      {
          "type": "approve",
          "source": "Update Comments of Requestor",
          "target": "Check for Manager"
      },
      {
          "type": "approve",
          "source": "Send Email for Completion",
          "target": "End"
      }
  ]; 
  
  edgesJson.forEach(function(edge) {
      if(edge.type == "approve") {
          g.setEdge(edge.source, edge.target, { label: "" }); 
      }
      // Make the edge of rejected paths red and dashed
     if(edge.type == "reject") {
          g.setEdge(edge.source, edge.target, {
              label: "", class: "rejectEdgePath"
              
          });
      }
  });
  
  
  
   var inner = graphArea.select("g");
  
  // Set the rankdir
  //g.graph().rankdir = "LR";
  g.graph().nodesep = 10;
  
  
  // Create the renderer
  var render = new dagreD3.render();
  
  
  // Run the renderer. This is what draws the final graph.
  render(inner, g);
  
  // Center the graph
  /*var initialScale = 0.75;
  zoom
    .translate([(graphArea.attr("width") - g.graph().width * initialScale) / 2, 20])
    .scale(initialScale)
    .event(graphArea); */
  //graphArea.attr('height', g.graph().height * initialScale + 40);
  
  
  
  bbox = graphArea.node().getBBox();
  var selectedNode = inner.selectAll("g.node"); 
  selectedNode.on('click', function (d) { 
      var nodeInfo = getNodeInfo(d);
      console.log('clicked '+nodeInfo.nodes+' (status: '+nodeInfo.status+')'); 
  });
  
  function getNodeInfo(name) {
      for (var i=0;i&lt;nodesJson.length;i++) 
          if (nodesJson[i].nodes==name) return nodesJson[i]; 
  }
  
  
  console.log('bbox.x  '+bbox.x);
  console.log('bbox.y  '+bbox.y);
  console.log('bbox.width  '+bbox.width);
  console.log('bbox.height  '+bbox.height);
  graphArea.attr("viewBox",bbox.x+" "+bbox.y+" "+bbox.width+" "+bbox.height);
  /*
  d3.select("#containerdiv")   
       .attr('width', 200)
    .attr('height', 200);
  */
  
  // Set up zoom support
  var zoom = d3.behavior.zoom().on("zoom", function() {
        inner.attr("transform", "translate(" + d3.event.translate + ")" +
                                    "scale(" + d3.event.scale + ")");
     d3.select("#containerdiv")   
       .attr('width', bbox.width)
    .attr('height', bbox.height);
    
      });
  graphArea.call(zoom);</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.node rect {
    stroke: #333;
    fill: #fff;
  }
  
  .edgePath path {
    stroke: #333;
    fill: #333;
    stroke-width: 1.5px;
  }
  
  .rejectEdgePath path {
    stroke: red;
    fill: red;
    stroke-width: 1.5px;
    stroke-dasharray: 5, 5;
  }
  
  
  
  g.dormant &gt; rect { 
    fill: #CC66FF;
  }
  
  g.completed &gt; rect { 
    fill: #66FF99;
  }
  
  g.future &gt; rect { 
    fill: #99CCFF;
  }
  
  g.acquired &gt; rect { 
    fill: #EBBFFF;
  }
  
  g.paused &gt; rect { 
    fill: #FF0000;
  }
  
  g.startend &gt; rect { 
    fill: #CC6666;
  }
  
  foreignobject {
     fill: black;
     font-family: FontAwesome;
     font-size: 15px;
     text-anchor: middle;
  //   cursor: move;
  }
  #wkfsvg {
      border: 1px solid BLUE;
          overflow: scroll;
  
  }
  #containerdiv {
      border: 1px solid RED;    
  
      overflow-y:scroll;
      overflow-x:scroll;
      
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="http://cpettitt.github.io/project/dagre-d3/latest/dagre-d3.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>Any suggestions will be highly appreciated as I have hit the wall and totally clueless on how to proceed.</p>
  
  <p>Thank you</p>