Mobile - approx 350-500px
I've built a mask that has a circle cut out of it, it grows, shrinks and has a label. But I am having issues trying to get it to scale correctly.
I have tried rescaling features with the viewbox - but it doesn't work and resizing causes an opacity mask bug which I've not been able to fix.
Using ViewBox to resize svg depending on the window size
//latest js fiddle http://jsfiddle.net/NYEaX/1563/
$(document).ready(function() {
  function maskMaker(el) {
    var backcolor = $(el).data("color");
    var backopacity = $(el).data("opacity");
    var height = $(el).data("height");
    var width = $(el).data("width");
    var width = 1120;
    var height = 500;
    var labelName = $(el).data("label-name");
    var bubbleValue = $(el).data("bubble-value");
    var displaceLeft = $(el).data("displace-left");
    var displaceTop = $(el).data("displace-top");
    var data = [{
      "label": labelName,
      "x": displaceLeft,
      "y": displaceTop,
      "value": bubbleValue
    }];
    console.log("MASK data", data);
    // Set the main elements for the series chart
    var svgroot = d3.select($(el)[0])
      .append("svg")
      .attr("viewBox", "0 0 " + width + " " + height)
      /*
                  .attr("width", "100%")
                  .attr("height", "100%")*/
      .attr("width", width)
      .attr("height", height)
      .attr("preserveAspectRatio", "xMidYMid meet");
    // filters go in defs element
    var defs = svgroot.append("defs");
    var mask = defs.append("mask")
      .attr("id", "myMask");
    mask.append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", "100%")
      .attr("height", "100%")
      .style("fill", "white")
      .style("opacity", backopacity);
    var invisiblebubble = mask.append("circle")
      .data(data);
    //create a fixed bubble first                  
    invisiblebubble
      .attr("cx", "50%")
      .attr("cy", "50%")
      .attr("r", function(d) {
        return d.value - 20;
      });
    //now mask the fixed circle     
    var masker = defs.append(function() {
        return mask.node().cloneNode(true)
      })
      .attr("id", "myMaskForPointer")
      .select("rect")
      .style("opacity", 0.8);
    invisiblebubble
      .attr("r", 10);
    //animate this circle
    invisiblebubble
      .attr("cx", "50%")
      .attr("cy", "50%")
      .transition()
      .duration(1800)
      .attr("r", 10)
      .transition()
      .duration(900)
      .attr("r", function(d) {
        return d.value;
      });
    //apply the rest of the chart elements 
    var svg = svgroot
      .attr("class", "series")
      .append("g")
      .attr("transform", "translate(0,0)")
    var rect = svg
      .append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", "100%")
      .attr("height", "100%")
      .attr("mask", "url(#myMask)")
      .style("fill", backcolor);
    /*
                      //__labels 
                      var centrallabel = svgroot.append("g")
                        .attr("class", "centrallabel")
                        .data(data);
                  centrallabel    
                        .append("text")
                        .attr("text-anchor", "middle")
                        .attr("x", 550)
                        .attr("y", 250 + 10)
                        .text(function(d) {
                          return "200";
                        })
                        */
    function addLabel() {
      //__labels 
      var labels = svgroot.append("g")
        .attr("class", "labels")
      //__ enter
      var labels = labels.selectAll("text")
        .data(data);
      labels.enter()
        .append("text")
        .attr("text-anchor", "middle")
      //__ update
      //labels
      .attr("x", function(d) {
          return d.x;
        })
        .attr("y", function(d) {
          return d.y - 10;
        })
        .text(function(d) {
          return d.label;
        })
        .each(function(d) {
          var bbox = this.getBBox();
          d.sx = d.x - bbox.width / 2 - 2;
          d.ox = d.x + bbox.width / 2 + 2;
          d.sy = d.oy = d.y + 5;
          d.cx = 550;
          d.cy = 250;
        })
        .transition()
        .duration(300)
      labels
        .transition()
        .duration(300)
      //__ exit
      labels.exit().remove();
      //__labels                     
    }
    function addPointer() {
      //__pointers
      var pointers = svgroot.append("g")
        .attr("class", "pointers");
      var dots = defs.append("marker")
        .attr("id", "circ")
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("refX", 3)
        .attr("refY", 3);
      var pointers = pointers.selectAll("path.pointer")
        .data(data);
      //__ enter
      pointers.enter()
        .append("path")
        .attr("class", "pointer")
        .style("fill", "none")
        .attr("marker-end", "url(#circ)")
        .attr("mask", "url(#myMaskForPointer)")
      //__ update
      //pointers
      .attr("d", function(d) {
          if (d.cx > d.ox) {
            return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
          } else {
            return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
          }
        })
        .transition()
        .duration(300)
      pointers
        .transition()
        .duration(300)
      //__ exit
      pointers.exit().remove();
      //__pointers 
    }
    //delay for the mask
    setTimeout(function() {
      addLabel();
      addPointer();
    }, 1000);
  }
function resizeHandling(el){
  function maskResizer(width, height) {
    $(el).find('.series').attr("width", width);
    $(el).find('.series').attr("height", height);
    $(el).find('.series').attr("viewBox", "0 0 " + width + " " + height);
  }
  $(window).resize(function() {
    var paneWidth = $(el).width();
    var paneHeight = $(el).height();
    console.log("paneHeight", paneHeight);
    console.log("paneWidth", paneWidth);
    maskResizer(paneWidth, paneHeight);
  });
}
  //var el = $(".mask"); //selector
  $('[data-role="maskmaker"]').each(function(index) {
    console.log("test")
    maskMaker(this);
    resizeHandling(this);
  });
});


