text: /*=========================================================================================
      File Name: line.js
      Description: D3 simple line chart
      ----------------------------------------------------------------------------------------
      Item Name: Modern Admin - Clean Bootstrap 4 Dashboard HTML Template
      Author: PIXINVENT
      Author URL: http://www.themeforest.net/user/pixinvent
  ==========================================================================================*/
  
  // Line chart
  // ------------------------------
  $(window).on("load", function(){
  
      // Revealing module pattern to store some global data that will be shared between different functions.
      var d3CalendarGlobals = function() {
          var ele = d3.select("#pie-calendar"),
              // calendarWidth = ele.node().getBoundingClientRect().width,
              calendarWidth = 1380,
              calendarHeight = 820,
              gridXTranslation = 10,
              gridYTranslation = 40,
              cellColorForCurrentMonth = '#EAEAEA',
              cellColorForPreviousMonth = '#FFFFFF',
              counter = 0, // Counter is used to keep track of the number of "back" and "forward" button presses and to calculate the month to display.
              currentMonth = new Date().getMonth(),
              monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
              datesGroup;
  
          function publicCalendarWidth() {
              return calendarWidth;
          }
  
          function publicCalendarHeight() {
              return calendarHeight;
          }
  
          function publicGridXTranslation() {
              return gridXTranslation;
          }
  
          function publicGridYTranslation() {
              return gridYTranslation;
          }
  
          function publicGridWidth() {
              return calendarWidth - 10;
          }
  
          function publicGridHeight() {
              return calendarHeight - 40;
          }
  
          function publicCellWidth() {
              return publicGridWidth() / 7;
          }
  
          function publicCellHeight() {
              return publicGridHeight() / 5;
          }
  
          function publicGetDatesGroup() {
              return datesGroup;
          }
  
          function publicSetDatesGroup(value) {
              datesGroup = value;
          }
  
          function publicIncrementCounter() {
              counter = counter + 1;
          }
  
          function publicDecrementCounter() {
              counter = counter - 1;
          }
  
          function publicMonthToDisplay() {
              var dateToDisplay = new Date();
              // We use the counter that keep tracks of "back" and "forward" presses to get the month to display.
              dateToDisplay.setMonth(currentMonth + counter);
              return dateToDisplay.getMonth();
          }
  
          function publicMonthToDisplayAsText() {
              return monthNames[publicMonthToDisplay()];
          }
  
          function publicYearToDisplay() {
              var dateToDisplay = new Date();
              // We use the counter that keep tracks of "back" and "forward" presses to get the year to display.
              dateToDisplay.setMonth(currentMonth + counter);
              return dateToDisplay.getFullYear();
          }
  
          function publicGridCellPositions() {
  
              // We store the top left positions of a 7 by 5 grid. These positions will be our reference points for drawing
              // various objects such as the rectangular grids, the text indicating the date etc.
              var cellPositions = [];
              for (y = 0; y < 5; y++) {
                  for (x = 0; x < 7; x++) {
                      cellPositions.push([x * publicCellWidth(), y * publicCellHeight()]);
                  }
              }
  
              return cellPositions;
          }
  
          // This function generates all the days of the month. But since we have a 7 by 5 grid, we also need to get some of
          // the days from the previous month and the next month. This way our grid will have all its cells filled. The days
          // from the previous or the next month will have a different color though. 
          function publicDaysInMonth() {
              var daysArray = [];
  
              var firstDayOfTheWeek = new Date(publicYearToDisplay(), publicMonthToDisplay(), 1).getDay();
              var daysInPreviousMonth = new Date(publicYearToDisplay(), publicMonthToDisplay(), 0).getDate();
  
              // Lets say the first week of the current month is a Wednesday. Then we need to get 3 days from 
              // the end of the previous month. But we can't naively go from 29 - 31. We have to do it properly
              // depending on whether the last month was one that had 31 days, 30 days or 28.
              for (i = 1; i <= firstDayOfTheWeek; i++) {
                  daysArray.push([daysInPreviousMonth - firstDayOfTheWeek + i, cellColorForCurrentMonth]);
              }
  
              // These are all the days in the current month.
              var daysInMonth = new Date(publicYearToDisplay(), publicMonthToDisplay() + 1, 0).getDate();
              for (i = 1; i <= daysInMonth; i++) {
                  daysArray.push([i, cellColorForPreviousMonth]);
              }
  
              // Depending on how many days we have so far (from previous month and current), we will need
              // to get some days from next month. We can do this naively though, since all months start on
              // the 1st.
              var daysRequiredFromNextMonth = 35 - daysArray.length;
  
              for (i = 1; i <= daysRequiredFromNextMonth; i++) {
                  daysArray.push([i, cellColorForCurrentMonth]);
              }
  
              return daysArray.slice(0, 35);
          }
  
          return {
              calendarWidth: publicCalendarWidth(),
              calendarHeight: publicCalendarHeight(),
              gridXTranslation: publicGridXTranslation(),
              gridYTranslation: publicGridYTranslation(),
              gridWidth: publicGridWidth(),
              gridHeight: publicGridHeight(),
              cellWidth: publicCellWidth(),
              cellHeight: publicCellHeight(),
              getDatesGroup: publicGetDatesGroup,
              setDatesGroup: publicSetDatesGroup,
              incrementCounter: publicIncrementCounter,
              decrementCounter: publicDecrementCounter,
              monthToDisplay: publicMonthToDisplay(),
              monthToDisplayAsText: publicMonthToDisplayAsText,
              yearToDisplay: publicYearToDisplay,
              gridCellPositions: publicGridCellPositions(),
              daysInMonth: publicDaysInMonth
          }
      }();
  
      $(document).ready(function() {
          renderCalendarGrid();
          renderDaysOfMonth();
          $('#back').on('click',displayPreviousMonth);
          $('#forward').on('click',displayNextMonth);
      });
  
      function displayPreviousMonth() {
          // We keep track of user's "back" and "forward" presses in this counter
          d3CalendarGlobals.decrementCounter();
          renderDaysOfMonth();
      }
  
      function displayNextMonth() {
          // We keep track of user's "back" and "forward" presses in this counter
          d3CalendarGlobals.incrementCounter();
          renderDaysOfMonth();
      }
  
      // This function is responsible for rendering the days of the month in the grid.
      function renderDaysOfMonth(month, year) {
          $('#currentMonth').text(d3CalendarGlobals.monthToDisplayAsText() + ' ' + d3CalendarGlobals.yearToDisplay());
          // We get the days for the month we need to display based on the number of times the user has pressed
          // the forward or backward button.
          var daysInMonthToDisplay = d3CalendarGlobals.daysInMonth();
          var cellPositions = d3CalendarGlobals.gridCellPositions;
  
          // All text elements representing the dates in the month are grouped together in the "datesGroup" element by the initalizing
          // function below. The initializing function is also responsible for drawing the rectangles that make up the grid.
          d3CalendarGlobals.datesGroup
              .selectAll("text")
              .data(daysInMonthToDisplay)
              .attr("x", function(d, i) {
                  return cellPositions[i][0];
              })
              .attr("y", function(d, i) {
                  return cellPositions[i][1];
              })
              .attr("dx", 20) // right padding
              .attr("dy", 20) // vertical alignment : middle
              .attr("transform", "translate(" + d3CalendarGlobals.gridXTranslation + "," + d3CalendarGlobals.gridYTranslation + ")")
              .text(function(d) {
                  return d[0];
              }); // Render text for the day of the week
  
          d3CalendarGlobals.calendar
              .selectAll("rect")
              .data(daysInMonthToDisplay)
              // Here we change the color depending on whether the day is in the current month, the previous month or the next month.
              // The function that generates the dates for any given month will also specify the colors for days that are not part of the
              // current month. We just have to use it to fill the rectangle
              .style("fill", function(d) {
                  return d[1];
              });
  
          drawGraphsForMonthlyData();
  
      }
  
      function drawGraphsForMonthlyData() {
          // Get some random data
          var data = getDataForMonth();
          // Set up variables required to draw a pie chart
          var outerRadius = d3CalendarGlobals.cellWidth / 3;
          var innerRadius = 0;
          var pie = d3.layout.pie();
          // var color = d3.scale.category10();
          var color = d3.scale.ordinal()
          .range(["#99B898", "#FECEA8", "#FF847C", "#E84A5F", "#F8B195", "#F67280", "#C06C84"]);
          var arc = d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius);
  
          // We need to index and group the pie charts and slices generated so that they can be rendered in
          // the appropriate cells. To do that, we call D3's 'pie' function of each of the data elements.
          var indexedPieData = [];
          for (i = 0; i < data.length; i++) {
              var pieSlices = pie(data[i]);
              // This loop is to store an index (j) for each of the slices of a given pie chart. Two different charts
              // on two different days will have the the same set of numbers for slices (eg: 0,1,2). This will help us
              // pick the same colors for the slices for two independent charts. Otherwise, the colors of the slices
              // will be different each day.
              for (j = 0; j < pieSlices.length; j++) {
                  indexedPieData.push([pieSlices[j], i, j]);
              }
          }
  
          var cellPositions = d3CalendarGlobals.gridCellPositions;
  
          d3CalendarGlobals.chartsGroup
              .selectAll("g.arc")
              .remove();
  
          var arcs = d3CalendarGlobals.chartsGroup.selectAll("g.arc")
              // use the indexed data so that each pie chart can be draw in a different cell and therefore for a different day
              .data(indexedPieData)
              .enter()
              .append("g")
              .attr("class", "arc")
              .attr("transform", function(d) {
                  // This is where we use the index here to translate the pie chart and rendere it in the appropriate cell. 
                  // Normally, the chart would be squashed up against the top left of the cell, obscuring the text that shows the day of the month.
                  // We use the gridXTranslation and gridYTranslation and multiply it by a factor to move it to the center of the cell. There is probably
                  // a better way of doing this though.
                  var currentDataIndex = d[1];
                  return "translate(" + (outerRadius + d3CalendarGlobals.gridXTranslation * 5 + cellPositions[currentDataIndex][0]) + ", " + (outerRadius + d3CalendarGlobals.gridYTranslation * 1.25 + cellPositions[currentDataIndex][1]) + ")";
              });
  
          arcs.append("path")
              .attr("fill", function(d, i) {
                  // The color is generated using the second index. Each slice of the pie is given a fixed number. This applies to all charts (see the indexing loop above).
                  // This way, by using the index we can generate teh same colors for each of the slices for different charts on different days.
                  return color(d[2]);
              })
              .attr("d", function(d, i) {
                  // Standard functions for drawing a pie charts in D3.
                  return arc(d[0]);
              });
  
          arcs.append("text")
              .attr("transform", function(d, i) {
                  // Standard functions for drawing a pie charts in D3.
                  return "translate(" + arc.centroid(d[0]) + ")";
              })
              .attr("text-anchor", "middle")
              .text(function(d, i) {
                  return d[0].value;
              })
              .style("fill", "#FFF");
  
      }
  
      // Generates some random data that can be used to draw pie charts.
      function getDataForMonth() {
          var randomData = [];
          for (var i = 0; i < 35; i++) {
              randomData.push([Math.floor(Math.random() * 100), Math.floor(Math.random() * 100), Math.floor(Math.random() * 100)]);
          }
          return randomData;
      }
  
      // This is the initializing function. It adds an svg element, draws a set of rectangles to form the calendar grid,
      // puts text in each cell representing the date and does the initial rendering of the pie charts.
      function renderCalendarGrid(month, year) {
  
          // Add the svg element.
          d3CalendarGlobals.calendar = d3.select("#pie-calendar")
              .append("svg")
              .attr("class", "calendar")
              .attr("width", d3CalendarGlobals.calendarWidth)
              .attr("height", d3CalendarGlobals.calendarHeight)
              .append("g");
  
          // Cell positions are generated and stored globally because they are used by other functions as a reference to render different things.
          var cellPositions = d3CalendarGlobals.gridCellPositions;
  
          // Draw rectangles at the appropriate postions, starting from the top left corner. Since we want to leave some room for the heading and buttons,
          // use the gridXTranslation and gridYTranslation variables.
          d3CalendarGlobals.calendar.selectAll("rect")
              .data(cellPositions)
              .enter()
              .append("rect")
              .attr("x", function(d) {
                  return d[0];
              })
              .attr("y", function(d) {
                  return d[1];
              })
              .attr("width", d3CalendarGlobals.cellWidth)
              .attr("height", d3CalendarGlobals.cellHeight)
              .style("stroke", "#555")
              .style("fill", "white")
              .attr("transform", "translate(" + d3CalendarGlobals.gridXTranslation + "," + d3CalendarGlobals.gridYTranslation + ")");
  
          var daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
          // This adds the day of the week headings on top of the grid
          d3CalendarGlobals.calendar.selectAll("headers")
              .data([0, 1, 2, 3, 4, 5, 6])
              .enter().append("text")
              .attr("x", function(d) {
                  return cellPositions[d][0];
              })
              .attr("y", function(d) {
                  return cellPositions[d][1];
              })
              .attr("dx", d3CalendarGlobals.gridXTranslation + 5) // right padding
              .attr("dy", 30) // vertical alignment : middle
              .text(function(d) {
                  return daysOfTheWeek[d]
              });
  
          // The intial rendering of the dates for the current mont inside each of the cells in the grid. We create a named group ("datesGroup"),
          // and add our dates to this group. This group is also stored globally. Later on, when the the user presses the back and forward buttons
          // to navigate between the months, we clear and re add the new text elements to this group
          d3CalendarGlobals.datesGroup = d3CalendarGlobals.calendar.append("svg:g");
          var daysInMonthToDisplay = d3CalendarGlobals.daysInMonth();
          d3CalendarGlobals.datesGroup
              .selectAll("daysText")
              .data(daysInMonthToDisplay)
              .enter()
              .append("text")
              .attr("x", function(d, i) {
                  return cellPositions[i][0];
              })
              .attr("y", function(d, i) {
                  return cellPositions[i][1];
              })
              .attr("dx", 20) // right padding
              .attr("dy", 20) // vertical alignment : middle
              .attr("transform", "translate(" + d3CalendarGlobals.gridXTranslation + "," + d3CalendarGlobals.gridYTranslation + ")")
              .text(function(d) {
                  return d[0];
              });
  
          // Create a new svg group to store the chart elements and store it globally. Again, as the user navigates through the months by pressing 
          // the "back" and "forward" buttons on the page, we clear the chart elements from this group and re add them again.
          d3CalendarGlobals.chartsGroup = d3CalendarGlobals.calendar.append("svg:g");
          // Call the function to draw the charts in the cells. This will be called again each time the user presses the forward or backward buttons.
          drawGraphsForMonthlyData();
      }
  
      // Resize chart
      // ------------------------------
  
      // Call function on window resize
      $(window).on('resize', resize);
  
      // Call function on sidebar width change
      $('.menu-toggle').on('click', resize);
  
      // Resize function
      // ------------------------------
      function resize() {
  
          width = ele.node().getBoundingClientRect().width - margin.left - margin.right;
  
          // Main svg width
          container.attr("width", width + margin.left + margin.right);
  
          // Width of appended group
          svg.attr("width", width + margin.left + margin.right);
  
  
          // Axis
          // -------------------------
          x.range([0, width]);
          svg.selectAll('.d3-xaxis').call(xAxis);
  
  
          svg.selectAll('.d3-line').attr("d", line);
      }
  });