text: var pym = require("./lib/pym");
  var ANALYTICS = require("./lib/analytics");
  require("./lib/webfonts");
  var { isMobile } = require("./lib/breakpoints");
  
  // Global vars
  var pymChild = null;
  var skipLabels = ["label", "values","type","section"];
  
  var d3 = {
    ...require("d3-axis/dist/d3-axis.min"),
    ...require("d3-scale/dist/d3-scale.min"),
    ...require("d3-selection/dist/d3-selection.min")
  };
  
  var { COLORS, classify, makeTranslate, formatStyle, fmtComma } = require("./lib/helpers");
  
  var fmtComma = s => s.toLocaleString().replace(/\.0+$/, "");
  
  // Initialize the graphic.
  var onWindowLoaded = function() {
    formatData();
    render();
  
    window.addEventListener("resize", render);
  
    pym.then(child => {
      pymChild = child;
      child.sendHeight();
  
      pymChild.onMessage("on-screen", function(bucket) {
        ANALYTICS.trackEvent("on-screen", bucket);
      });
      pymChild.onMessage("scroll-depth", function(data) {
        data = JSON.parse(data);
        ANALYTICS.trackEvent("scroll-depth", data.percent, data.seconds);
      });
    });
  };
  
  // Format graphic data for processing by D3.
  var formatData = function() {
    DATA.forEach(function(d) {
      var x0 = 0;
  
      d.values = [];
  
      for (var key in d) {
        if (skipLabels.indexOf(key) > -1) {
          continue;
        }
  
        var x1 = x0 + d[key];
  
        d.values.push({
          name: key,
          x0: x0,
          x1: x1,
          val: d[key]
        });
  
        x0 = x1;
      }
    });
  };
  
  // Render the graphic(s). Called by pym with the container width.
  var render = function() {
    // group the data
    var groupBy = function(xs, key) {
      return xs.reduce(function(rv, x) {
        (rv[x[key]] = rv[x[key]] || []).push(x);
        return rv;
      }, {});
    };
  
    var MasterGroups = groupBy(DATA, 'section')
  
    for (var item in MasterGroups) {
      // add the sublabel
      var labelViz = `labelViz${item}`;
      document.getElementById(labelViz).innerHTML = MasterGroups[item][0].type;
  
      // add the overall
      var container = `#stacked-bar-chart${item}`;
      var element = document.querySelector(container);
      var width = element.offsetWidth;
  
      renderStackedBarChart({
        container,
        width,
        data: MasterGroups[item]
      });
    }
  
    // Update iframe
    if (pymChild) {
      pymChild.sendHeight();
    }
  };
  
  // Render a stacked bar chart.
  var renderStackedBarChart = function(config) {
    // Setup
    var labelColumn = "label";
  
    var barHeight = 30;
    var barGap = 5;
    var labelWidth = 70;
    var labelMargin = 6;
    var valueGap = 6;
  
    var margins = {
      top: 0,
      right: 20,
      bottom: 20,
      left: labelWidth + labelMargin
    };
  
    var ticksX = 5;
    var roundTicksFactor = 100;
  
    if (isMobile.matches) {
      ticksX = 5;
    }
  
    // Calculate actual chart dimensions
    var chartWidth = config.width - margins.left - margins.right;
    var chartHeight = (barHeight + barGap) * config.data.length;
  
    // Clear existing graphic (for redraw)
    var containerElement = d3.select(config.container);
    containerElement.html("");
    document.getElementById("fallback").innerHTML = "";
  
    var values = config.data.map(d => d.values[d.values.length - 1].x1);
    var floors = values.map(
      v => Math.floor(v / roundTicksFactor) * roundTicksFactor
    );
    var ceilings = values.map(
      v => Math.ceil(v / roundTicksFactor) * roundTicksFactor
    );
  
    var min = Math.min(...floors);
    var max = 100
  
    if (min > 0) {
      min = 0;
    }
  
    var xScale = d3
      .scaleLinear()
      .domain([min, 80000000])
      .rangeRound([0, chartWidth]);
  
    var colorScale = d3
      .scaleOrdinal()
      .domain(
        Object.keys(config.data[0]).filter(d => skipLabels.indexOf(d) == -1)
      )
      .range([COLORS.teal3, "rgb(187,187,187)", COLORS.teal3, "#ccc"]);
  
    // Create the root SVG element.
    var chartWrapper = containerElement
      .append("div")
      .attr("class", "graphic-wrapper");
  
    var chartElement = chartWrapper
      .append("svg")
      .attr("width", chartWidth + margins.left + margins.right)
      .attr("height", chartHeight + margins.top + margins.bottom)
      .append("g")
      .attr("transform", `translate(${margins.left},${margins.top})`);
  
    // Create D3 axes.
    var xAxis = d3
      .axisBottom()
      .scale(xScale)
      .ticks(ticksX)
      .tickFormat(d => "$" + (d / 1000000) + "M");
  
    // Render axes to chart.
    chartElement
      .append("g")
      .attr("class", "x axis")
      .attr("transform", makeTranslate(0, chartHeight))
      .call(xAxis);
  
    // Render grid to chart.
    var xAxisGrid = () => xAxis;
  
    chartElement
      .append("g")
      .attr("class", "x grid")
      .attr("transform", makeTranslate(0, chartHeight))
      .call(
        xAxisGrid()
          .tickSize(-chartHeight, 0, 0)
          .tickFormat("")
      );
  
    // Render bars to chart.
    var group = chartElement
      .selectAll(".group")
      .data(config.data)
      .enter()
      .append("g")
      .attr("class", d => "group " + classify(d[labelColumn]))
      .attr(
        "transform",
        (d, i) => "translate(0," + i * (barHeight + barGap) + ")"
      );
  
    group
      .selectAll("rect")
      .data(d => d.values)
      .enter()
      .append("rect")
      .attr("x", d => (d.x0 < d.x1 ? xScale(d.x0) : xScale(d.x1)))
      .attr("width", function(d){
  
        // if (Math.abs(xScale(d.x1) - xScale(d.x0)) < 1000) {
          return Math.abs(xScale(d.x1) - xScale(d.x0))
        // } else {
        //   return 0
        // }
  
  
  
      })
      .attr("height", barHeight)
      .style("fill", "#51AADE")
      .attr("class", d => classify(d.name));
  
    // Render bar values.
    group
      .append("g")
      .attr("class", "value")
      .selectAll("text")
      .data(d => d.values)
      .enter()
      .append("text")
      .text(d => (d.val ? "$" + fmtComma(d.val) : null))
      .attr("class", d => classify(d.name))
      .attr("x", d => xScale(d.x1))
      .attr("dx", function(d) {
        var xStart = xScale(d.x1);
        var textWidth = this.getComputedTextLength();
  
        // Negative case
        if (d.x1 < 0) {
          var outsideOffset = -(valueGap + textWidth);
  
          if (xStart + outsideOffset < 0) {
            d3.select(this).classed("in", true);
            return valueGap;
          } else {
            d3.select(this).classed("out", true);
            return outsideOffset;
          }
          // Positive case
        } else {
          if (xStart + valueGap + textWidth > chartWidth) {
            d3.select(this).classed("in", true);
            return -(valueGap + textWidth);
          } else {
            d3.select(this).classed("out", true);
            return valueGap;
          }
        }
      })
      .attr("dy", barHeight / 2 + 4);
  
    // Render 0-line.
    if (min < 0) {
      chartElement
        .append("line")
        .attr("class", "zero-line")
        .attr("x1", xScale(0))
        .attr("x2", xScale(0))
        .attr("y1", 0)
        .attr("y2", chartHeight);
    }
  
    // Render bar labels.
    chartWrapper
      .append("ul")
      .attr("class", "labels")
      .attr(
        "style",
        formatStyle({
          width: labelWidth + "px",
          top: margins.top + "px",
          left: "0"
        })
      )
      .selectAll("li")
      .data(config.data)
      .enter()
      .append("li")
      .attr("style", (d, i) =>
        formatStyle({
          width: labelWidth + "px",
          height: barHeight + "px",
          left: "0px",
          top: i * (barHeight + barGap) + "px;"
        })
      )
      .attr("class", d => classify(d[labelColumn]))
      .append("span")
      .text(d => d[labelColumn]);
  };
  
  /*
   * Initially load the graphic
   * (NB: Use window.load to ensure all images have loaded)
   */
  window.onload = onWindowLoaded;
  