text: /*
   *
   * ======================================================
   * We follow the vis template of init - wrangle - update
   * ======================================================
   *
   * */
  
  /**
   * @param _parentElement -- the HTML or SVG element (D3 node) to which to attach the vis
   * @param _data -- the data array
   * @param _eventHandler -- the Eventhandling Object to emit data to (see Task 4)
   * @constructor
   */
  VolumeVis = function(_parentElement, _data, _eventHandler){
      this.parentElement = _parentElement;
      this.data = _data;
      this.eventHandler = _eventHandler;
      this.displayData = [];
  
      // defines constants
      this.margin = {top: 20, right: 0, bottom: 30, left: 30},
      this.width = getInnerWidth(this.parentElement) - this.margin.left - this.margin.right,
      this.height = 400 - this.margin.top - this.margin.bottom;
  
      this.initVis();
  }
  
  
  /**
   * Method that sets up the SVG and the variables
   */
  VolumeVis.prototype.initVis = function(){
  
      var that = this;
  
      // constructs SVG layout
      this.svg = this.parentElement.append("svg")
          .attr("width", this.width + this.margin.left + this.margin.right)
          .attr("height", this.height + this.margin.top + this.margin.bottom)
        .append("g")
          .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
  
      // creates axis and scales
      this.x = d3.time.scale()
        .range([0, this.width]);
  
      this.y = d3.scale.linear()
        .range([this.height, 0]);
  
      this.xAxis = d3.svg.axis()
        .scale(this.x)
        .orient("bottom");
  
      this.yAxis = d3.svg.axis()
        .scale(this.y)
        .orient("left");
  
      this.area = d3.svg.area()
        .interpolate("monotone")
        .x(function(d) { return that.x(d.date); })
        .y0(this.height)
        .y1(function(d) { return that.y(d.calls.length); });
  
      this.brush = d3.svg.brush()
        .on("brush", function(){
          // Trigger selectionChanged event. You'd need to account for filtering by time AND type
          console.log(that.brush.extent());
        });
  
      // Add axes visual elements
      this.svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + this.height + ")");
  
      this.svg.append("g")
          .attr("class", "y axis")
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("Call volume, daily");
  
      this.svg.append("g")
        .attr("class", "brush");
  
      // filter, aggregate, modify data
      this.wrangleData(null);
  
      // call the update method
      this.updateVis();
  }
  
  
  /**
   * Method to wrangle the data. In this case it takes an options object
   * @param _filterFunction - a function that filters data or "null" if none
   */
  VolumeVis.prototype.wrangleData= function(_filterFunction){
  
      // displayData should hold the data which is visualized
      this.displayData = this.filterAndAggregate(_filterFunction);
  
      //// you might be able to pass some options,
      //// if you don't pass options -- set the default options
      //// the default is: var options = {filter: function(){return true;} }
      //var options = _options || {filter: function(){return true;}};
  }
  
  
  
  /**
   * the drawing function - should use the D3 selection, enter, exit
   */
  VolumeVis.prototype.updateVis = function(){
      // updates scales
      this.x.domain(d3.extent(this.displayData, function(d) { return d.date; }));
      this.y.domain(d3.extent(this.displayData, function(d) { return d.calls.length; }));
  
      // updates axis
      this.svg.select(".x.axis")
          .call(this.xAxis);
  
      this.svg.select(".y.axis")
          .call(this.yAxis)
  
      // updates graph
      var path = this.svg.selectAll(".area")
        .data([this.displayData])
  
      path.enter()
        .append("path")
        .attr("class", "area");
  
      path
        .transition()
        .attr("d", this.area);
  
      path.exit()
        .remove();
  
      this.brush.x(this.x);
      this.svg.select(".brush")
          .call(this.brush)
        .selectAll("rect")
          .attr("height", this.height);
  }
  
  
  /**
   * Gets called by event handler and should create new aggregated data
   * aggregation is done by the function "aggregate(filter)". Filter has to
   * be defined here.
   * @param selection
   */
  VolumeVis.prototype.onSelectionChange = function (type){
  
      this.wrangleData(function(d) { return d.type == type; });
  
      this.updateVis();
  }
  
  
  /**
   * The aggregate function that creates the counts for each age for a given filter.
   * @param _filter - A filter can be, e.g.,  a function that is only true for data of a given time range
   * @returns {Array|*}
   */
  VolumeVis.prototype.filterAndAggregate = function(_filter){
  
      // Set filter to a function that accepts all items
      // ONLY if the parameter _filter is NOT null use this parameter
      var filter = function(){return true;}
      if (_filter != null){
          filter = _filter;
      }
  
      // We want to filter in the inner "calls" array (so we need to map over it)
      // You'll generally just need `this.data.filter(filter)`
      return this.data.map(function(d) { return {date: d.date, calls: d.calls.filter(filter)}; });
  }
  