template/html/d3-graph.js
function centerGraph(newScale, duration, delay)
   {
      if (typeof delay === 'function') { delay = delay.call(this); }

      delay = typeof delay === 'number' ? delay : 0;

      setTimeout(function()
      {
         if (typeof newScale === 'function') { newScale = newScale.call(this); }
         if (typeof duration === 'function') { duration = duration.call(this); }

         newScale = typeof newScale === 'number' ? newScale : zoom.scale();
         duration = typeof duration === 'number' ? duration : 200;

         if (typeof newScale !== 'number') { throw new TypeError("centerGraph error: 'newScale' is not a 'number'."); }
         if (typeof duration !== 'number') { throw new TypeError("centerGraph error: 'duration' is not a 'number'."); }

         var bounds = graph.node().getBBox();

         var centerSVGX = (graphWidth * newScale / 2);
         var centerSVGY = (graphHeight * newScale / 2);

         var centerGraphX = (bounds.x * newScale) + (bounds.width * newScale / 2);
         var centerGraphY = (bounds.y * newScale) + (bounds.height * newScale / 2);

         // Translate
         var centerTranslate =
         [
            (graphWidth / 2) - centerSVGX + (centerSVGX - centerGraphX),
            (graphHeight / 2) - centerSVGY + (centerSVGY - centerGraphY)
         ];

         // Store values
         zoom
          .translate(centerTranslate)
          .scale(newScale);

         // Render transition
         graph.transition()
          .duration(duration)
          .attr('transform', 'translate(' + zoom.translate() + ')' + ' scale(' + zoom.scale() + ')');

         // Hides any existing node context menu.
         hideNodeContextMenu();

      }, delay);
   }
function centerGraph(newScale, duration, delay)
   {
      if (typeof delay === 'function') { delay = delay.call(this); }

      delay = typeof delay === 'number' ? delay : 0;

      setTimeout(function()
      {
         if (typeof newScale === 'function') { newScale = newScale.call(this); }
         if (typeof duration === 'function') { duration = duration.call(this); }

         newScale = typeof newScale === 'number' ? newScale : zoom.scale();
         duration = typeof duration === 'number' ? duration : 200;

         if (typeof newScale !== 'number') { throw new TypeError("centerGraph error: 'newScale' is not a 'number'."); }
         if (typeof duration !== 'number') { throw new TypeError("centerGraph error: 'duration' is not a 'number'."); }

         var bounds = graph.node().getBBox();

         var centerSVGX = (graphWidth * newScale / 2);
         var centerSVGY = (graphHeight * newScale / 2);

         var centerGraphX = (bounds.x * newScale) + (bounds.width * newScale / 2);
         var centerGraphY = (bounds.y * newScale) + (bounds.height * newScale / 2);

         // Translate
         var centerTranslate =
         [
            (graphWidth / 2) - centerSVGX + (centerSVGX - centerGraphX),
            (graphHeight / 2) - centerSVGY + (centerSVGY - centerGraphY)
         ];

         // Store values
         zoom
          .translate(centerTranslate)
          .scale(newScale);

         // Render transition
         graph.transition()
          .duration(duration)
          .attr('transform', 'translate(' + zoom.translate() + ')' + ' scale(' + zoom.scale() + ')');

         // Hides any existing node context menu.
         hideNodeContextMenu();

      }, delay);
   }
Centers the graph. All parameters can be either a number or a function evaluated for a number result.

`newScale` and `duration` are evaluated in the centering anonymous function allowing values to be determined
after debounce.

@param {number|function}   newScale - New scale value for graph.
@param {number|function}   duration - Duration of centering transition.
@param {number|function}   delay - Delay for debounce before centering occurs.