text: class LinearCalendar{
      constructor(selection, data, config = {}) {
          let self = this;
          this.selection = selection;
          this.data = data;
  
          // Graph configuration
          this.cfg = {
              'margin': {'top': 30, 'right': 20, 'bottom': 40, 'left': 40},
              'year': 'key',
              'start': 'start',
              'end': 'end',
              'domain': ['01-01-1900', '12-31-1900'],
              'dateformat': '%d-%m-%Y', // https://github.com/d3/d3-time-format/blob/master/README.md#locale_format
              'scaleformat': '%B',
              'color': 'steelblue',
              'title': false,
              'source': false,
              'radius': 3,
              'stroke': 2,
          };
          Object.keys(config).forEach(function(key) {
              if(config[key] instanceof Object && config[key] instanceof Array === false){
                  Object.keys(config[key]).forEach(function(sk) {
                      self.cfg[key][sk] = config[key][sk];
                  });
              } else self.cfg[key] = config[key];
          });
  
          this.cfg.width = parseInt(this.selection.node().offsetWidth) - this.cfg.margin.left - this.cfg.margin.right,
          this.cfg.height = parseInt(this.selection.node().offsetHeight)- this.cfg.margin.top - this.cfg.margin.bottom;
  
          this.parseTime = d3.timeParse(this.cfg.dateformat);
          this.formatTime = d3.timeFormat(this.cfg.dateformat);
          this.formatTimeLeg = d3.timeFormat('%d %B');
          this.yScale = d3.scaleBand().rangeRound([0, self.cfg.height]).padding(1);
          this.xScale = d3.scaleTime().range([0, this.cfg.width]);
  
          this.initGraph();
      }
      initGraph() {
       var self = this;
  
          this.data.forEach(function(d){
              d.jsdateStart = self.parseTime(d[self.cfg.start]);
              d.jsdateEnd = self.parseTime(d[self.cfg.end]);
          });
  
          this.yScale.domain(this.data.map(function(d){ return +d[self.cfg.year]}))
          this.xScale.domain([self.parseTime(self.cfg.domain[0]), self.parseTime(self.cfg.domain[1])]);
  
          this.svg = this.selection.append('svg')
              .attr("class", "chart calendar-linear")
              .attr("viewBox", "0 0 "+(this.cfg.width + this.cfg.margin.left + this.cfg.margin.right)+" "+(this.cfg.height + this.cfg.margin.top + this.cfg.margin.bottom))
              .attr("width", this.cfg.width + this.cfg.margin.left + this.cfg.margin.right)
              .attr("height", this.cfg.height + this.cfg.margin.top + this.cfg.margin.bottom);
  
          this.g = this.svg.append("g")
              .attr("transform", "translate(" + (self.cfg.margin.left) + "," + (self.cfg.margin.top) + ")");
          
          this.yGrid = this.g.append("g")           
              .attr("class", "grid grid--y")
              .call(self.make_y_gridlines()
                  .tickSize(-self.cfg.width)
                  .tickFormat(""));
  
          this.g.append("g")
              .attr("class", "axis axis--x")
              .attr("transform", "translate(0," + this.cfg.height + ")")
              .call(d3.axisBottom(self.xScale)
                  .tickFormat(d3.timeFormat(self.cfg.scaleformat)));
  
          this.g.append("g")
              .attr("class", "axis axis--y")
              .call(d3.axisLeft(self.yScale));
  
          // TITLE
          if(self.cfg.title){
              this.svg.append('text')
                  .attr('class', 'title label')
                  .attr('text-anchor', 'middle')
                  .attr('transform', 'translate('+ (self.cfg.width/2) +',20)')
                  .text(self.cfg.title)
          }
  
          // SOURCE
          if(self.cfg.source){
              this.svg.append('text')
                  .attr('class', 'source label')
                  .attr('transform', 'translate('+ (self.cfg.margin.left) +','+(self.cfg.height + self.cfg.margin.top + self.cfg.margin.bottom - 5)+')')
                  .html(self.cfg.source)
  
          }
  
  
          // ITEM GROUP
          this.itemg = this.g.selectAll('.itemgroup')
              .data(this.data)
              .enter().append('g')
              .attr('class', 'itemgroup')
              .attr('transform', function(d, i){
                  return 'translate(0,'+ self.yScale(d[self.cfg.year]) +')';
          })
  
          this.itemg.append('line')
              .attr('y1', 0)
              .attr('x1', function(d){
                  return self.xScale(d.jsdateStart);
              })
              .attr('y2', 0)
              .attr('x2', function(d){
                  return self.xScale(d.jsdateEnd);
              })
              .attr('stroke', self.cfg.color)
              .attr('stroke-width', self.cfg.stroke)
  
          this.itemg.append('circle')
              .attr('class', 'start')
              .attr('cy', 0)
              .attr('cx', function(d){
                  return self.xScale(d.jsdateStart);
              })
              .attr('r', self.cfg.radius)
              .attr('stroke-width', 3)
              .attr('fill', self.cfg.color);
  
          this.itemg.append('circle')
              .attr('class', 'end')
              .attr('cy', 0)
              .attr('cx', function(d){
                  return self.xScale(d.jsdateEnd);
              })
              .attr('r', self.cfg.radius)
              .attr('stroke-width', 3)
              .attr('fill', self.cfg.color);
  
          // MOUSE INDICATOR
          this.mouseover = this.g.append('rect')
              .attr('x', 0)
              .attr('y', 0)
              .attr('width', self.cfg.width)
              .attr('height', self.cfg.height)
              .attr('fill', 'none')
              .attr('pointer-events', 'all')
  
          this.mousegroup = this.g.append('g')
              .attr('class', 'mousegroup')
              .attr('pointer-events', 'none')
              .style("opacity", "0");
  
          this.mouseline = this.mousegroup.append("path") // this is the black vertical line to follow mouse
              .attr("class", "mouse-line")
              .attr("shape-rendering", "crispEdges")
              .style("stroke", "black")
              .style("stroke-width", "1px")
              .style("opacity", 0.3)
              .attr("d", "M0,"+ (self.cfg.height - self.yScale.step()) + " 0," + self.yScale.step())
  
          this.mousetext = this.mousegroup.append("text")
              .attr('text-anchor', 'middle')
              .attr('class', 'label')
              .style('font-size', '10px')
              .attr('y', self.yScale.step() -2);
  
          this.mouseover.on('mouseover', function(){
              self.mousegroup.style('opacity', '1')
          }).on('mouseout', function(){
              self.mousegroup.style('opacity', '0')
          }).on('mousemove', function(){
              var mouse = d3.mouse(this);
              var tim = self.formatTime(self.xScale.invert(mouse[0]));
              self.mousegroup.attr("transform", "translate("+mouse[0]+",0)")
              self.mousetext.text(self.formatTimeLeg(self.xScale.invert(mouse[0])))
              
              self.itemg.selectAll('circle')
                  .attr('stroke', 'trasparent')
              self.itemg.filter(function(d){ return d.inicio ==  tim; })
                  .selectAll('.start')
                  .attr('stroke', self.cfg.color)
              self.itemg.filter(function(d){ return d.fin ==  tim; })
                  .selectAll('.end')
                  .attr('stroke', self.cfg.color)
          })
      }
  
      // gridlines in y axis function
      make_y_gridlines() {       
          return d3.axisLeft(this.yScale);
      }
  }