<commit_before>(function($, window, document, undefined){

    var PufferfishImageChangeEvent = function(element, newImageSrc, oldImageSrc){
        this.element = element;
        this.newImageSrc = newImageSrc;
        this.oldImageSrc = oldImageSrc;
    };

    PufferfishImageChangeEvent.prototype.element = null;
    PufferfishImageChangeEvent.prototype.newImageSrc = null;
    PufferfishImageChangeEvent.prototype.oldImageSrc = null;
    PufferfishImageChangeEvent.prototype.isDefaultPrevented = false;

    PufferfishImageChangeEvent.prototype.preventDefault = function(){
        this.isDefaultPrevented = true;
    };

    var defaults = {
        'onChange': function(element, newImageSrc, oldImageSrc){},
        'afterChange': function(element, newImageSrc, oldImageSrc){}
    };

    $.pufferfish = (function(){

        var settings = $.extend({}, defaults);

        var sizeDefinitionRegex =       /\[([^,]+)(\s+)?,(\s+)?\(([^\)]+)\)(\s+)?\]/;
        var sizeDefinitionRegexGlobal = /\[([^,]+)(\s+)?,(\s+)?\(([^\)]+)\)(\s+)?\]/g;
        var constraintRegex =       /([^,\s:]+):(\s+)?([^,]+)/;
        var constraintRegexGlobal = /([^,\s:]+):(\s+)?([^,]+)/g;

        var watchedImages = [];

        function getDataAttrKey(name){
            return 'data-pufferfish' + (typeof name !== 'undefined' ? '-' + name : '');
        }

        function getDataAttrSelector(name){
            return '[' + getDataAttrKey(name) + ']';
        }

        function parseConstraints(constraintString){

            var defaults = {
                'max-width': null,
                'min-width': null
            };

            var constraints = {};

            var constraintStringParts = constraintString.match(constraintRegexGlobal);
            constraintStringParts.forEach(function(constraintStringPart){
                var constraintVars = constraintStringPart.match(constraintRegex);
                constraints[constraintVars[1]] = parseInt(constraintVars[3]);
            });

            return $.extend({}, defaults, constraints);

        }

        function parseSizeDefinitions(sizeDefString){

            var sizeDefStringParts = sizeDefString.match(sizeDefinitionRegexGlobal);
            var sizeDefs = [];

            sizeDefStringParts.forEach(function(sizeDefStringPart){
                var sizeDefVars = sizeDefStringPart.match(sizeDefinitionRegex);

                sizeDefs.push({
                    'src': sizeDefVars[1],
                    'constraints': parseConstraints(sizeDefVars[4])
                });

            });

            return sizeDefs;

        }

        function watchImage(img){

            var sizeDefString = img.attr( getDataAttrKey() );
            var sizeDefinitions = parseSizeDefinitions(sizeDefString);

            var srcAttr = img.attr( getDataAttrKey('src-attr') );
            if(!srcAttr) srcAttr = 'src';

            img.data( getDataAttrKey('watched'), true );

            watchedImages.push({
                'img': img,
                'sizeDefinitions': sizeDefinitions,
                'srcAttr': srcAttr,
                'currentSrc': null,
                'visible': null
            });

        }

        function reflow(){

            watchedImages.forEach(function(watchedImage){

                var img = watchedImage.img;

                var sizeDefinitions = watchedImage.sizeDefinitions;
                var container = img.parent();
                var availableWidth = container.innerWidth();

                var selectedSizeDefinition = null;

                $.each(sizeDefinitions, function(key, sizeDefinition){

                    if(
                        sizeDefinition.constraints['min-width'] !== null &&
                        availableWidth < sizeDefinition.constraints['min-width']
                    ){
                        return;
                    }

                    if(
                        sizeDefinition.constraints['max-width'] !== null &&
                        availableWidth > sizeDefinition.constraints['max-width']
                    ){
                        return;
                    }

                    selectedSizeDefinition = sizeDefinition;
                    return false;

                });

                var visible = elementIsVisible(img);

                if((selectedSizeDefinition !== null && watchedImage.currentSrc !== selectedSizeDefinition.src) || (visible && watchedImage.visible === null)){

                    var oldImageSrc = watchedImage.currentSrc;
                    var newImageSrc = selectedSizeDefinition.src;

                    watchedImage.currentSrc = newImageSrc;

                    var event = new PufferfishImageChangeEvent(img, newImageSrc, oldImageSrc);
                    settings.onChange(event);

                    if(!event.isDefaultPrevented && visible){
                        img.attr(watchedImage.srcAttr, newImageSrc);
                    }

                    watchedImage.visible = visible;

                    settings.afterChange(event);
                }

            });

        }

        function elementIsVisible(element){
            if(element[0] === window || element[0] === document) return true;

            if(element.css('display') === 'none'){
                return false;
            }
            else{
                var parent = element.parent();
                if(parent.length === 0) return false;
                return elementIsVisible(parent);
            }
        }

        function bindUnwatched(context){
            if(typeof context === 'undefined') context = document;
            $(context).find( getDataAttrSelector() ).each(function(){
                var img = $(this);
                if(img.data( getDataAttrKey('watched') )) return;
                watchImage(img);
            });
        }

        function init(context, _settings){
            settings = $.extend({}, defaults, _settings);
            if(typeof context === 'undefined') context = document;
            bindUnwatched(context);
            reflow();
        }

        // Public methods
        return {
            'init': init,
            'reflow': reflow
        };

    })();

    $.fn.pufferfish = function(settings){
        $.pufferfish.init(this, settings);
        $(window).on('resize', function(){
            $.pufferfish.reflow();
        });
    };

})( jQuery, window, window.document);
<commit_msg>Fix by @rattler3<commit_after>(function($, window, document, undefined){

    var PufferfishImageChangeEvent = function(element, newImageSrc, oldImageSrc){
        this.element = element;
        this.newImageSrc = newImageSrc;
        this.oldImageSrc = oldImageSrc;
    };

    PufferfishImageChangeEvent.prototype.element = null;
    PufferfishImageChangeEvent.prototype.newImageSrc = null;
    PufferfishImageChangeEvent.prototype.oldImageSrc = null;
    PufferfishImageChangeEvent.prototype.isDefaultPrevented = false;

    PufferfishImageChangeEvent.prototype.preventDefault = function(){
        this.isDefaultPrevented = true;
    };

    var defaults = {
        'onChange': function(element, newImageSrc, oldImageSrc){},
        'afterChange': function(element, newImageSrc, oldImageSrc){}
    };

    $.pufferfish = (function(){

        var settings = $.extend({}, defaults);

        var sizeDefinitionRegex =       /\[([^,]+)(\s+)?,(\s+)?\(([^\)]+)\)(\s+)?\]/;
        var sizeDefinitionRegexGlobal = /\[([^,]+)(\s+)?,(\s+)?\(([^\)]+)\)(\s+)?\]/g;
        var constraintRegex =       /([^,\s:]+):(\s+)?([^,]+)/;
        var constraintRegexGlobal = /([^,\s:]+):(\s+)?([^,]+)/g;

        var watchedImages = [];

        function getDataAttrKey(name){
            return 'data-pufferfish' + (typeof name !== 'undefined' ? '-' + name : '');
        }

        function getDataAttrSelector(name){
            return '[' + getDataAttrKey(name) + ']';
        }

        function parseConstraints(constraintString){

            var defaults = {
                'max-width': null,
                'min-width': null
            };

            var constraints = {};

            var constraintStringParts = constraintString.match(constraintRegexGlobal);
            constraintStringParts.forEach(function(constraintStringPart){
                var constraintVars = constraintStringPart.match(constraintRegex);
                constraints[constraintVars[1]] = parseInt(constraintVars[3]);
            });

            return $.extend({}, defaults, constraints);

        }

        function parseSizeDefinitions(sizeDefString){

            var sizeDefStringParts = sizeDefString.match(sizeDefinitionRegexGlobal);
            var sizeDefs = [];

            sizeDefStringParts.forEach(function(sizeDefStringPart){
                var sizeDefVars = sizeDefStringPart.match(sizeDefinitionRegex);

                sizeDefs.push({
                    'src': sizeDefVars[1],
                    'constraints': parseConstraints(sizeDefVars[4])
                });

            });

            return sizeDefs;

        }

        function watchImage(img){

            var sizeDefString = img.attr( getDataAttrKey() );
            var sizeDefinitions = parseSizeDefinitions(sizeDefString);

            var srcAttr = img.attr( getDataAttrKey('src-attr') );
            if(!srcAttr) srcAttr = 'src';

            img.data( getDataAttrKey('watched'), true );

            watchedImages.push({
                'img': img,
                'sizeDefinitions': sizeDefinitions,
                'srcAttr': srcAttr,
                'currentSrc': null,
                'visible': null
            });

        }

        function reflow(){

            watchedImages.forEach(function(watchedImage){

                var img = watchedImage.img;

                var sizeDefinitions = watchedImage.sizeDefinitions;
                var container = img.parent();
                var availableWidth = container.innerWidth();

                var selectedSizeDefinition = null;

                $.each(sizeDefinitions, function(key, sizeDefinition){

                    if(
                        sizeDefinition.constraints['min-width'] !== null &&
                        availableWidth < sizeDefinition.constraints['min-width']
                    ){
                        return;
                    }

                    if(
                        sizeDefinition.constraints['max-width'] !== null &&
                        availableWidth > sizeDefinition.constraints['max-width']
                    ){
                        return;
                    }

                    selectedSizeDefinition = sizeDefinition;
                    return false;

                });

                var visible = elementIsVisible(img);

                if(
                    (selectedSizeDefinition !== null && watchedImage.currentSrc !== selectedSizeDefinition.src) ||
                    (visible !== watchedImage.visible && visible == true)
                ){

                    var oldImageSrc = watchedImage.currentSrc;
                    var newImageSrc = selectedSizeDefinition.src;

                    watchedImage.currentSrc = newImageSrc;

                    var event = new PufferfishImageChangeEvent(img, newImageSrc, oldImageSrc);
                    settings.onChange(event);

                    if(!event.isDefaultPrevented && visible){
                        img.attr(watchedImage.srcAttr, newImageSrc);
                    }

                    watchedImage.visible = visible;

                    settings.afterChange(event);
                }

            });

        }

        function elementIsVisible(element){
            if(element[0] === window || element[0] === document) return true;

            if(element.css('display') === 'none'){
                return false;
            }
            else{
                var parent = element.parent();
                if(parent.length === 0) return false;
                return elementIsVisible(parent);
            }
        }

        function bindUnwatched(context){
            if(typeof context === 'undefined') context = document;
            $(context).find( getDataAttrSelector() ).each(function(){
                var img = $(this);
                if(img.data( getDataAttrKey('watched') )) return;
                watchImage(img);
            });
        }

        function init(context, _settings){
            settings = $.extend({}, defaults, _settings);
            if(typeof context === 'undefined') context = document;
            bindUnwatched(context);
            reflow();
        }

        // Public methods
        return {
            'init': init,
            'reflow': reflow
        };

    })();

    $.fn.pufferfish = function(settings){
        $.pufferfish.init(this, settings);
        $(window).on('resize', function(){
            $.pufferfish.reflow();
        });
    };

})( jQuery, window, window.document);
<|endoftext|>


<commit_before>var LQBViz = (function () {
  var nrOfEntries = 5,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      months = [],
      chartData;

  var json2Months = function ( data ) {
    var monthsArray = [];

    _.each(data, function(val, key) {
      if ( key.indexOf("_t") <0 ) return;
      var group = parseInt( key.substr(key.lastIndexOf("_t")+2) ),
          month = _.find( monthsArray, function( m ) { return m.id === group; });

      if ( !month ) { // create new month if not found yet
        month = {
          id: group,
          words: [],
          values: [],
          weights: [],
          result: 0
        };
        monthsArray.push( month );
      }

      // put into correct array
      if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
        month.values.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val ? val.trim() : ""
        });
      } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
        month.weights.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val
        })
      } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
        month.words.push({
          id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
          val: val
        })
      } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
        month.result = val;
      }
    });

    return checkMonths( monthsArray );
  };
  var checkMonths = function ( monthsToCheck ) {
    // Remove months with no result, insufficient data, or empty words.
    // Careful: First month is different, as there wasn't a Stichwort yet.
    return _.reject( monthsToCheck, function( m ) {
      return !m.result ||
             m.words.length !== 5 ||
             m.values.length !== 5 ||
             m.weights.length !== 5 ||
             _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
    });
  };

  var getMonths = function () { return months; };
  var setMonths = function ( jsonData ) { months = json2Months( jsonData ); };

  var getNrOfEntriesPerMonth = function () { return nrOfEntries; };

  var initialSettings = function () {
    Chart.defaults.global.animation.duration = 400;
    Chart.defaults.global.animation.easing = "easeInOutQuart";
    Chart.defaults.global.scaleOverride = true;
    Chart.defaults.global.scaleSteps = 5;
    Chart.defaults.global.scaleStepWidth = 20;
    Chart.defaults.global.scaleStartValue = 0;
    Chart.defaults.global.scaleFontSize = 16;
    Chart.defaults.global.hover.mode = "nearest";
    Chart.defaults.global.tooltips.titleFontSize = 18;
    Chart.defaults.global.tooltips.bodyFontSize = 18;
  }();

  /**
   * returns a human readable month name, depending on the supplied index.
   * Since the experiment started in November 16, this is index 1.

   * @param  {Number} index
   * @return {String}
   */
  var getMonthName = function ( index ) {
    var year = (index-(index%12))/12;
    year = index%12 > 2 ? year+1 : year;
    return monthNames[ (index-1) % 12 ] + " '" + (15+year);
  };
  var getMonthNameShort = function( lqbIndex ) {
    return monthNamesShort[ (lqbIndex-1) % 12 ];
  };

  /**
   * gets a color palette or a single color
   *
   * @param  {String} type  [description]
   * @param  {Boolean} light [description]
   * @param  {Number} index  [description]
   * @return {String}       [description]
   */
  var getColors = function ( type, light, index ) {
    var arr;
    if ( type === "pie" ) {
      arr = light ? pieColorsLight : pieColors;
    } else if ( type === "bar" ) {
      arr = light ? barColorsLight : barColors;
    }

    return ( typeof index === "undefined" ) ? arr : arr[index];
  };

  var get2dContext = function ( id ) { return $("#"+id)[0].getContext("2d"); };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", this.getColors( "pie", false, index ) );
    $(node).children(".text").html( text );
  };

  var truncate = function ( string, length ) {
    return string.length > length ? string.substr( 0, length - 3 ) + "..." : string;
  };

  var createMonthButtons = function () {
    if ( months.length <= 1 ) {
      $(".monthButtons").hide(); // If there's only one (or zero) months, it's useless to draw the buttons
    } else {
      var currentMonthID = this.getLastMonth().id;

      _.each( months, function ( m ) {
        $( '
\
              '+ this.getMonthName( m.id ) +'\

' ).insertBefore( ".monthButtons li:last-child" );
      }, this );
    }
  };

  var getMonthByID = function ( id ) { return _.find( months, function(m){return m.id === id; }); };
  var getLastMonth = function () { return _.last( months ); };
  var getFirstMonth = function () { return _.first( months ); };

  var getNextMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getLastMonth().id ) {
      return this.getFirstMonth();
    } else {
      return _.find( months, function(m){ return m.id > currentMonthID; });
    }
  };
  var getPrevMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getFirstMonth().id ) {
      return this.getLastMonth();
    } else {
      return _.last( _.filter( months, function(m){ return m.id < currentMonthID; } ) );
    }
  };

  var createGraphData = function () {
    var totalBarData = [],
        totalPieData = [];

    // initial setup
    chartData = {
      "line": {
        labels : [],
        datasets : [{
          backgroundColor : "rgba(151,187,220,0.4)",
          strokeColor : "rgb(151,187,220)",
          pointColor : "rgb(151,187,220)",
          pointStrokeColor : "#fff",
          pointHighlightFill : "#fff",
          pointHighlightStroke : "rgb(151,187,220)",
          data : []
        }]
      },
      "pie": {
        labels: new Array( nrOfEntries ),
        datasets: [{
          data: new Array( nrOfEntries ),
          backgroundColor: getColors( "pie", false ),
          hoverBackgroundColor: getColors( "pie", true )
        }]
      },
      "bar": {
        labels : [],
        datasets : [{
          backgroundColor : getColors( "bar", false ),
          strokeColor : "rgba(151,187,220,0.8)",
          highlightFill : getColors( "bar", true ),
          highlightStroke : "rgba(151,187,220,1)",
          data : []
        }]
      }
    };

    //from each month, get the data and put it in the chart-data containers
    _.each( months, function(m) {
      var monthName = getMonthName( m.id );

      // LINECHART
      if ( m.result && parseInt( m.result ) ) {
        chartData.line.labels.push( monthName );
        chartData.line.datasets[0].data.push(  parseInt( m.result ) );
      }

      // PIE
      totalPieData.push({
        id: m.id,
        name: monthName,
        data: []
      });

      // BARCHART
      totalBarData.push({
        id: m.id,
        name: monthName,
        labels: [],
        values: [],
        weights: []
      });

      _.each( m.words, function(w) {
        _.last( totalBarData ).labels.push( w.val );
      });
      _.each( m.values, function(v) {
        _.last( totalBarData ).values.push( v.val );
      });
      _.each( m.weights, function(w, index) {
        _.last( totalBarData ).weights.push( w.val );

        _.last( totalPieData ).data.push({
          label: _.last( totalBarData ).labels[ index ],
          value: w.val
        });
      });
    });

    chartData.bar.labels = _.last( totalBarData ).labels;
    chartData.bar.datasets[0].data = _.last( totalBarData ).values;

    // Fill initial month for bar chart
    for(var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++) {
      chartData.pie.labels[i] = _.last( totalPieData ).data[i].label;
      chartData.pie.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
    }
  };

  var getChartData = function ( type ) { return chartData[type]; };

  return {
    getMonthName: getMonthName,
    getMonthNameShort: getMonthNameShort,
    getColors: getColors,
    getNrOfEntriesPerMonth: getNrOfEntriesPerMonth,
    get2dContext: get2dContext,
    updatePieLegend: updatePieLegend,
    truncate: truncate,
    createMonthButtons: createMonthButtons,
    getFirstMonth: getFirstMonth,
    getLastMonth: getLastMonth,
    getMonthByID: getMonthByID,
    getNextMonth: getNextMonth,
    getPrevMonth: getPrevMonth,
    getMonths: getMonths,
    setMonths: setMonths,
    createGraphData: createGraphData,
    getChartData: getChartData
  };
})();

$(document).ready(function () {
  var currentMonth,
      lineChart,
      pieChart,
      barChart;

  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    var clickedBtnAttribute = $(e.target).data("month") || $(e.target).parent().data("month") || $(e.originalEvent.currentTarget).data("month");

    if ( clickedBtnAttribute === "next" ) {
      currentMonth = LQBViz.getNextMonth( currentMonth ).id;
    } else if ( clickedBtnAttribute === "prev" ) {
      currentMonth = LQBViz.getPrevMonth( currentMonth ).id;
    } else {
      currentMonth = +clickedBtnAttribute;
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + currentMonth).parent().addClass("activeMonth");

    updateGraphs();

    e.stopPropagation();
    return false;
  });

  var updateGraphs = function() {
    var relevantData = LQBViz.getMonthByID( currentMonth );

    for( var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++ ) {
      pieChart.data.datasets[0].data[i] = relevantData.weights[i].val;
      var val = relevantData.words[i].val;
      pieChart.data.labels[i] = LQBViz.truncate(val, 28);
      LQBViz.updatePieLegend( i, val );

      barChart.data.datasets[0].data[i] = +relevantData.values[i].val;
      barChart.data.labels[i] = LQBViz.truncate(val, 15);
      // TODO: allow full text in tooltip
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    lineChart = new Chart( LQBViz.get2dContext("chart-area1"), {
      type: "line",
      data: LQBViz.getChartData("line"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true } }],
          xAxes: [{ ticks: { autoSkip: false /* show all labels, always */ } }]
        }
      }
    });

    pieChart = new Chart( LQBViz.get2dContext("chart-area2"), {
      type: "pie",
      data: LQBViz.getChartData("pie"),
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30,
        legend: { display: false }
      }
    });

    barChart = new Chart( LQBViz.get2dContext("chart-area3"), {
      type: "bar",
      data: LQBViz.getChartData("bar"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true, min: 0, max: 100 } }]
        }
      }
    });

  };

  var getData = function () {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: function ( data ) {

        LQBViz.setMonths( data );

        LQBViz.createGraphData();

        // take last available month as the currently selected month
        currentMonth = LQBViz.getLastMonth().id;
        LQBViz.createMonthButtons();

        drawCharts();
        updateGraphs();
      }
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<commit_msg>module complete<commit_after>var LQBViz = (function () {
  var nrOfEntries = 5,
      selectedMonth,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      months = [],
      chartData,
      lineChart,
      pieChart,
      barChart;

  var json2Months = function ( data ) {
    var monthsArray = [];

    _.each(data, function(val, key) {
      if ( key.indexOf("_t") <0 ) return;
      var group = parseInt( key.substr(key.lastIndexOf("_t")+2) ),
          month = _.find( monthsArray, function( m ) { return m.id === group; });

      if ( !month ) { // create new month if not found yet
        month = {
          id: group,
          words: [],
          values: [],
          weights: [],
          result: 0
        };
        monthsArray.push( month );
      }

      // put into correct array
      if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
        month.values.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val ? val.trim() : ""
        });
      } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
        month.weights.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val
        })
      } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
        month.words.push({
          id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
          val: val
        })
      } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
        month.result = val;
      }
    });

    return checkMonths( monthsArray );
  };
  var checkMonths = function ( monthsToCheck ) {
    // Remove months with no result, insufficient data, or empty words.
    // Careful: First month is different, as there wasn't a Stichwort yet.
    return _.reject( monthsToCheck, function( m ) {
      return !m.result ||
             m.words.length !== 5 ||
             m.values.length !== 5 ||
             m.weights.length !== 5 ||
             _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
    });
  };

  var getMonths = function () { return months; };
  var setMonths = function ( jsonData ) {
    months = json2Months( jsonData );
    selectedMonth = _.last( months );
  };

  var getNrOfEntriesPerMonth = function () { return nrOfEntries; };

  var initialSettings = function () {
    Chart.defaults.global.animation.duration = 400;
    Chart.defaults.global.animation.easing = "easeInOutQuart";
    Chart.defaults.global.scaleOverride = true;
    Chart.defaults.global.scaleSteps = 5;
    Chart.defaults.global.scaleStepWidth = 20;
    Chart.defaults.global.scaleStartValue = 0;
    Chart.defaults.global.scaleFontSize = 16;
    Chart.defaults.global.hover.mode = "nearest";
    Chart.defaults.global.tooltips.titleFontSize = 18;
    Chart.defaults.global.tooltips.bodyFontSize = 18;
  }();

  /**
   * returns a human readable month name, depending on the supplied index.
   * Since the experiment started in November 16, this is index 1.

   * @param  {Number} index
   * @return {String}
   */
  var getMonthName = function ( index ) {
    var year = (index-(index%12))/12;
    year = index%12 > 2 ? year+1 : year;
    return monthNames[ (index-1) % 12 ] + " '" + (15+year);
  };
  var getMonthNameShort = function( lqbIndex ) {
    return monthNamesShort[ (lqbIndex-1) % 12 ];
  };

  /**
   * gets a color palette or a single color
   *
   * @param  {String} type  [description]
   * @param  {Boolean} light [description]
   * @param  {Number} index  [description]
   * @return {String}       [description]
   */
  var getColors = function ( type, light, index ) {
    var arr;
    if ( type === "pie" ) {
      arr = light ? pieColorsLight : pieColors;
    } else if ( type === "bar" ) {
      arr = light ? barColorsLight : barColors;
    }

    return ( typeof index === "undefined" ) ? arr : arr[index];
  };

  var get2dContext = function ( id ) { return $("#"+id)[0].getContext("2d"); };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", getColors( "pie", false, index ) );
    $(node).children(".text").html( text );
  };

  var truncate = function ( string, length ) {
    return string.length > length ? string.substr( 0, length - 3 ) + "..." : string;
  };

  var createMonthButtons = function () {
    if ( months.length <= 1 ) {
      $(".monthButtons").hide(); // If there's only one (or zero) months, it's useless to draw the buttons
    } else {
      _.each( months, function ( m ) {
        $( '
\
              '+ getMonthName( m.id ) +'\

' ).insertBefore( ".monthButtons li:last-child" );
      }, this );
    }
  };

  var getNextMonth = function () {
    if ( selectedMonth === _.last( months ) ) {
      return _.first( months );
    } else {
      return _.find( months, function(m){ return m.id > selectedMonth.id; });
    }
  };
  var getPrevMonth = function () {
    if ( selectedMonth === _.first( months ) ) {
      return _.last( months );
    } else {
      return _.last( _.filter( months, function(m){ return m.id < selectedMonth.id; } ) );
    }
  };

  var createGraphData = function () {
    var totalBarData = [],
        totalPieData = [];

    // initial setup
    chartData = {
      "line": {
        labels : [],
        datasets : [{
          backgroundColor : "rgba(151,187,220,0.4)",
          strokeColor : "rgb(151,187,220)",
          pointColor : "rgb(151,187,220)",
          pointStrokeColor : "#fff",
          pointHighlightFill : "#fff",
          pointHighlightStroke : "rgb(151,187,220)",
          data : []
        }]
      },
      "pie": {
        labels: new Array( nrOfEntries ),
        datasets: [{
          data: new Array( nrOfEntries ),
          backgroundColor: getColors( "pie", false ),
          hoverBackgroundColor: getColors( "pie", true )
        }]
      },
      "bar": {
        labels : [],
        datasets : [{
          backgroundColor : getColors( "bar", false ),
          strokeColor : "rgba(151,187,220,0.8)",
          highlightFill : getColors( "bar", true ),
          highlightStroke : "rgba(151,187,220,1)",
          data : []
        }]
      }
    };

    //from each month, get the data and put it in the chart-data containers
    _.each( months, function(m) {
      var monthName = getMonthName( m.id );

      // LINECHART
      if ( m.result && parseInt( m.result ) ) {
        chartData.line.labels.push( monthName );
        chartData.line.datasets[0].data.push(  parseInt( m.result ) );
      }

      // PIE
      totalPieData.push({
        id: m.id,
        name: monthName,
        data: []
      });

      // BARCHART
      totalBarData.push({
        id: m.id,
        name: monthName,
        labels: [],
        values: [],
        weights: []
      });

      _.each( m.words, function(w) {
        _.last( totalBarData ).labels.push( w.val );
      });
      _.each( m.values, function(v) {
        _.last( totalBarData ).values.push( v.val );
      });
      _.each( m.weights, function(w, index) {
        _.last( totalBarData ).weights.push( w.val );

        _.last( totalPieData ).data.push({
          label: _.last( totalBarData ).labels[ index ],
          value: w.val
        });
      });
    });

    chartData.bar.labels = _.last( totalBarData ).labels;
    chartData.bar.datasets[0].data = _.last( totalBarData ).values;

    // Fill initial month for bar chart
    for(var i = 0; i < nrOfEntries; i++) {
      chartData.pie.labels[i] = _.last( totalPieData ).data[i].label;
      chartData.pie.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
    }
  };

  var handleMonthChange = function ( e ) {
    var clickedBtnAttribute = $(e.target).data("month") || $(e.target).parent().data("month") || $(e.originalEvent.currentTarget).data("month");

    if ( clickedBtnAttribute === "next" ) {
      selectedMonth = getNextMonth();
    } else if ( clickedBtnAttribute === "prev" ) {
      selectedMonth = getPrevMonth();
    } else {
      selectedMonth = _.find( months, function(m){return m.id === +clickedBtnAttribute; });
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + selectedMonth.id).parent().addClass("activeMonth");

    updateGraphs();
  };

  var updateGraphs = function() {
    for( var i = 0; i < nrOfEntries; i++ ) {
      pieChart.data.datasets[0].data[i] = selectedMonth.weights[i].val;
      var val = selectedMonth.words[i].val;
      pieChart.data.labels[i] = truncate(val, 28);
      updatePieLegend( i, val );

      barChart.data.datasets[0].data[i] = +selectedMonth.values[i].val;
      barChart.data.labels[i] = truncate(val, 15);
      // TODO: allow full text in tooltip
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    lineChart = new Chart( get2dContext("chart-area1"), {
      type: "line",
      data: chartData.line,
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true } }],
          xAxes: [{ ticks: { autoSkip: false /* show all labels, always */ } }]
        }
      }
    });
    pieChart = new Chart( get2dContext("chart-area2"), {
      type: "pie",
      data: chartData.pie,
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30,
        legend: { display: false }
      }
    });
    barChart = new Chart( get2dContext("chart-area3"), {
      type: "bar",
      data: chartData.bar,
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true, min: 0, max: 100 } }]
        }
      }
    });
  };

  var processData = function ( rawData ) {
    setMonths( rawData );
    createGraphData();
    createMonthButtons();
    drawCharts();
    updateGraphs();
  };

  return {
    handleMonthChange: handleMonthChange,
    processData: processData
  };
})();

$(document).ready(function () {
  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    LQBViz.handleMonthChange( e );
    e.stopPropagation();
    return false;
  });

  var getData = function () {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: LQBViz.processData
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<|endoftext|>


<commit_before>$(document).ready(function () {
  var nrOfEntries = 5,
      currentMonth,
      lineChart,
      pieChart,
      barChart,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      months = [],
      totalBarData = [],
      totalPieData = [],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      lineChartData = {
        labels : [],
        datasets : [{
          backgroundColor : "rgba(151,187,220,0.4)",
          strokeColor : "rgb(151,187,220)",
          pointColor : "rgb(151,187,220)",
          pointStrokeColor : "#fff",
          pointHighlightFill : "#fff",
          pointHighlightStroke : "rgb(151,187,220)",
          data : []
        }]
      },
      pieData = function() {
        return {
          labels: new Array(nrOfEntries),
          datasets: [{
            data: new Array(nrOfEntries),
            backgroundColor: pieColors,
            hoverBackgroundColor: pieColorsLight
          }]
        };
      }(),
      barChartData = {
        labels : [],
        datasets : [{
          backgroundColor : barColors,
          strokeColor : "rgba(151,187,220,0.8)",
          highlightFill : barColorsLight,
          highlightStroke : "rgba(151,187,220,1)",
          data : []
        }]
      };

  Chart.defaults.global.animation.easing = "easeInOutQuart";
  Chart.defaults.global.scaleOverride = true;
  Chart.defaults.global.scaleSteps = 5;
  Chart.defaults.global.scaleStepWidth = 20;
  Chart.defaults.global.scaleStartValue = 0;
  Chart.defaults.global.scaleFontSize = 16;
  Chart.defaults.global.hover.mode = "nearest";

  //First month was November
  var getMonthName = function( lqbIndex ) {
    var year = (lqbIndex-(lqbIndex%12))/12;
    year = lqbIndex%12 > 2 ? year+1 : year;
    return monthNames[ (lqbIndex-1) % 12 ] + " '" + (15+year);
  };
  var getShortMonthName = function( lqbIndex ) { return monthNamesShort[ (lqbIndex-1) % 12 ]; };

  var createMonthButtons = function() {
    // If there's only one (or zero) months, it's useless to draw the buttons
    if ( months.length <= 1 ) {
      $(".monthButtons").hide();
    } else {
      _.each( months, function( m ){
        var classes = 'changeMonthBtn month'+ m.id +' '+ (m.id === currentMonth ? "activeMonth" : "");
        $( '
'+ getShortMonthName( m.id ) +'
' ).insertBefore( ".monthButtons li:last-child" );
      });
    }
  };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", pieColors[index] );
    $(node).children(".text").html( text );
  };

  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    var nextMonth = $(e.target).data("month"),
        lastMonthID = _.last( months ).id,
        firstMonthID = _.first( months ).id;

    if ( nextMonth === undefined ) { // in case the icon on prev/next recognizes the click
      nextMonth = $(e.target).parent().data("month");
    }
    if ( nextMonth === undefined ) { // in case caret recognizes the click
      nextMonth = $(e.originalEvent.currentTarget).data("month");
    }

    if ( nextMonth === "next" ) {
      if ( currentMonth >= lastMonthID ) {
        currentMonth = firstMonthID;
      } else {
        currentMonth = _.find( months, function(m){ return m.id > currentMonth; }).id;
      }
    } else if ( nextMonth === "prev" ) {
      if ( currentMonth <= firstMonthID ) {
        currentMonth = lastMonthID;
      } else {
        currentMonth = _.last( _.filter( months, function(m){ return m.id < currentMonth; } ) ).id;
      }
    } else {
      currentMonth = +nextMonth;
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + currentMonth).addClass("activeMonth");

    updateGraphs();

    e.stopPropagation();
    return false;
  });

  var updateGraphs = function() {
    var relevantData = _.find( months, function(m){return m.id === currentMonth; });

    for( var i = 0; i < pieChart.data.datasets[0].data.length; i++ ) {
      pieChart.data.datasets[0].data[i] = relevantData.weights[i].val;
      var val = relevantData.words[i].val;
      pieChart.data.labels[i] = ( val.length > 28 ? val.substr( 0, 25 ) + "..." : val );

      // TODO: use native legend!
      updatePieLegend( i, val );
    }

    for( var i = 0; i < barChart.data.datasets[0].data.length; i++ ) {
      barChart.data.datasets[0].data[i] = +relevantData.values[i].val;
      var val = relevantData.words[i].val;  // make label for bar chart max. 15 chars
      // wat
      //barChart.scale.xLabels[i] = ( val.length > 15 ? val.substr( 0, 12 ) + "..." : val );
      barChart.data.labels[i] = relevantData.words[i].val;
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    var ctx = $("#chart-area1")[0].getContext("2d");
    lineChart = new Chart(ctx, {
      type: 'line',
      data: lineChartData,
      options: {
        responsive: true,
        legend: {
          display: false
        },
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true
            }
          }]
        }
      }
    });

    var ctx2 = $("#chart-area2")[0].getContext("2d");
    pieChart = new Chart(ctx2, {
      type: 'pie',
      data: pieData,
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30
      }
    });

    var ctx3 = $("#chart-area3")[0].getContext("2d");
    barChart = new Chart(ctx3, {
      type: 'bar',
      data: barChartData,
      options: {
        responsive: true,
        legend: {
          display: false
        },
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true
            }
          }]
        }
      }
    });

  };

  var getData = function() {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: function( data ){

        _.each(data, function(val, key) {
          if ( key.indexOf("_t") <0 ) return;
          var group = key.substr(key.lastIndexOf("_t")+2),
              month = _.find( months, function( m ) {
                return m.id === parseInt( group );
              });

          if ( !month ) { // create new month if not found yet
            month = {
              id: parseInt( group ),
              words: [],
              values: [],
              weights: [],
              result: 0
            };
            months.push( month );
          }

          // put into correct array
          if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
            month.values.push({
              id: key.substr( key.indexOf("_t"+group) -1, 1),
              val: val ? val.trim() : ""
            });
          } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
            month.weights.push({
              id: key.substr( key.indexOf("_t"+group) -1, 1),
              val: val
            })
          } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
            month.words.push({
              id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
              val: val
            })
          } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
            month.result = val;
          }
        });

        // Remove months with no result, insufficient data, or empty words.
        // Careful: First month is different, as there wasn't a Stichwort yet.
        months = _.reject( months, function(m) {
          return !m.result ||
                 m.words.length !== 5 ||
                 m.values.length !== 5 ||
                 m.weights.length !== 5 ||
                 _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
        });

        currentMonth = _.max( months, function(m){ return m.id; });
        _.each( months, function(m) {
          // LINECHART
          if ( m.result && parseInt( m.result ) ) {
            lineChartData.labels.push( getMonthName( m.id ) );
            lineChartData.datasets[0].data.push(  parseInt( m.result ) );
          }

          // PIE
          totalPieData.push({
            id: m.id,
            name: getMonthName( m.id ),
            data: []
          });

          // BARCHART
          totalBarData.push({
            id: m.id,
            name: getMonthName( m.id ),
            labels: [],
            values: [],
            weights: []
          });
          _.each( m.words, function(w) {
            _.last( totalBarData ).labels.push( w.val );
          });
          _.each( m.values, function(v) {
            _.last( totalBarData ).values.push( v.val );
          });
          _.each( m.weights, function(w, index) {
            _.last( totalBarData ).weights.push( w.val );

            _.last( totalPieData ).data.push({
              label: _.last( totalBarData ).labels[ index ],
              value: w.val
            });
          });

        });

        currentMonth = _.last( months ).id;
        createMonthButtons();

        barChartData.labels = _.last( totalBarData ).labels;
        barChartData.datasets[0].data = _.last( totalBarData ).values;

        // Fill initial month for bar chart
        for(var i = 0; i < nrOfEntries; i++) {
          pieData.labels[i] = _.last( totalPieData ).data[i].label;
          pieData.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
        }

        drawCharts();
        updateGraphs();
      }
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<commit_msg>graphs update<commit_after>$(document).ready(function () {
  var nrOfEntries = 5,
      currentMonth,
      lineChart,
      pieChart,
      barChart,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      months = [],
      totalBarData = [],
      totalPieData = [],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      lineChartData = {
        labels : [],
        datasets : [{
          backgroundColor : "rgba(151,187,220,0.4)",
          strokeColor : "rgb(151,187,220)",
          pointColor : "rgb(151,187,220)",
          pointStrokeColor : "#fff",
          pointHighlightFill : "#fff",
          pointHighlightStroke : "rgb(151,187,220)",
          data : []
        }]
      },
      pieData = function() {
        return {
          labels: new Array(nrOfEntries),
          datasets: [{
            data: new Array(nrOfEntries),
            backgroundColor: pieColors,
            hoverBackgroundColor: pieColorsLight
          }]
        };
      }(),
      barChartData = {
        labels : [],
        datasets : [{
          backgroundColor : barColors,
          strokeColor : "rgba(151,187,220,0.8)",
          highlightFill : barColorsLight,
          highlightStroke : "rgba(151,187,220,1)",
          data : []
        }]
      };

  Chart.defaults.global.animation.duration = 400;
  Chart.defaults.global.animation.easing = "easeInOutQuart";
  Chart.defaults.global.scaleOverride = true;
  Chart.defaults.global.scaleSteps = 5;
  Chart.defaults.global.scaleStepWidth = 20;
  Chart.defaults.global.scaleStartValue = 0;
  Chart.defaults.global.scaleFontSize = 16;
  Chart.defaults.global.hover.mode = "nearest";

  //First month was November
  var getMonthName = function( lqbIndex ) {
    var year = (lqbIndex-(lqbIndex%12))/12;
    year = lqbIndex%12 > 2 ? year+1 : year;
    return monthNames[ (lqbIndex-1) % 12 ] + " '" + (15+year);
  };
  var getShortMonthName = function( lqbIndex ) { return monthNamesShort[ (lqbIndex-1) % 12 ]; };

  var createMonthButtons = function() {
    // If there's only one (or zero) months, it's useless to draw the buttons
    if ( months.length <= 1 ) {
      $(".monthButtons").hide();
    } else {
      _.each( months, function( m ){
        var classes = 'changeMonthBtn month'+ m.id +' '+ (m.id === currentMonth ? "activeMonth" : "");
        $( '
'+ getShortMonthName( m.id ) +'
' ).insertBefore( ".monthButtons li:last-child" );
      });
    }
  };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", pieColors[index] );
    $(node).children(".text").html( text );
  };

  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    var nextMonth = $(e.target).data("month"),
        lastMonthID = _.last( months ).id,
        firstMonthID = _.first( months ).id;

    if ( nextMonth === undefined ) { // in case the icon on prev/next recognizes the click
      nextMonth = $(e.target).parent().data("month");
    }
    if ( nextMonth === undefined ) { // in case caret recognizes the click
      nextMonth = $(e.originalEvent.currentTarget).data("month");
    }

    if ( nextMonth === "next" ) {
      if ( currentMonth >= lastMonthID ) {
        currentMonth = firstMonthID;
      } else {
        currentMonth = _.find( months, function(m){ return m.id > currentMonth; }).id;
      }
    } else if ( nextMonth === "prev" ) {
      if ( currentMonth <= firstMonthID ) {
        currentMonth = lastMonthID;
      } else {
        currentMonth = _.last( _.filter( months, function(m){ return m.id < currentMonth; } ) ).id;
      }
    } else {
      currentMonth = +nextMonth;
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + currentMonth).addClass("activeMonth");

    updateGraphs();

    e.stopPropagation();
    return false;
  });

  var updateGraphs = function() {
    var relevantData = _.find( months, function(m){return m.id === currentMonth; });

    for( var i = 0; i < pieChart.data.datasets[0].data.length; i++ ) {
      pieChart.data.datasets[0].data[i] = relevantData.weights[i].val;
      var val = relevantData.words[i].val;
      pieChart.data.labels[i] = ( val.length > 28 ? val.substr( 0, 25 ) + "..." : val );
      updatePieLegend( i, val );
    }

    for( var i = 0; i < barChart.data.datasets[0].data.length; i++ ) {
      barChart.data.datasets[0].data[i] = +relevantData.values[i].val;
      var val = relevantData.words[i].val;  // make label for bar chart max. 15 chars
      debugger;
      //barChart.scale.xLabels[i] = ( val.length > 15 ? val.substr( 0, 12 ) + "..." : val );
      barChart.data.labels[i] = ( val.length > 15 ? val.substr( 0, 12 ) + "..." : val );
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    var ctx = $("#chart-area1")[0].getContext("2d");
    lineChart = new Chart(ctx, {
      type: 'line',
      data: lineChartData,
      options: {
        responsive: true,
        legend: {
          display: false
        },
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true
            }
          }],
          xAxes: [{
            ticks: {
              autoSkip: false /* show all labels, always */
            }
          }]
        }
      }
    });

    var ctx2 = $("#chart-area2")[0].getContext("2d");
    pieChart = new Chart(ctx2, {
      type: 'pie',
      data: pieData,
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30,
        legend: {
          display: false
        }
      }
    });

    var ctx3 = $("#chart-area3")[0].getContext("2d");
    barChart = new Chart(ctx3, {
      type: 'bar',
      data: barChartData,
      options: {
        responsive: true,
        legend: {
          display: false
        },
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true,
              min: 0,
              max: 100
            }
          }]
        }
      }
    });

  };

  var getData = function() {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: function( data ){

        _.each(data, function(val, key) {
          if ( key.indexOf("_t") <0 ) return;
          var group = key.substr(key.lastIndexOf("_t")+2),
              month = _.find( months, function( m ) {
                return m.id === parseInt( group );
              });

          if ( !month ) { // create new month if not found yet
            month = {
              id: parseInt( group ),
              words: [],
              values: [],
              weights: [],
              result: 0
            };
            months.push( month );
          }

          // put into correct array
          if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
            month.values.push({
              id: key.substr( key.indexOf("_t"+group) -1, 1),
              val: val ? val.trim() : ""
            });
          } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
            month.weights.push({
              id: key.substr( key.indexOf("_t"+group) -1, 1),
              val: val
            })
          } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
            month.words.push({
              id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
              val: val
            })
          } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
            month.result = val;
          }
        });

        // Remove months with no result, insufficient data, or empty words.
        // Careful: First month is different, as there wasn't a Stichwort yet.
        months = _.reject( months, function(m) {
          return !m.result ||
                 m.words.length !== 5 ||
                 m.values.length !== 5 ||
                 m.weights.length !== 5 ||
                 _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
        });

        currentMonth = _.max( months, function(m){ return m.id; });
        _.each( months, function(m) {
          // LINECHART
          if ( m.result && parseInt( m.result ) ) {
            lineChartData.labels.push( getMonthName( m.id ) );
            lineChartData.datasets[0].data.push(  parseInt( m.result ) );
          }

          // PIE
          totalPieData.push({
            id: m.id,
            name: getMonthName( m.id ),
            data: []
          });

          // BARCHART
          totalBarData.push({
            id: m.id,
            name: getMonthName( m.id ),
            labels: [],
            values: [],
            weights: []
          });
          _.each( m.words, function(w) {
            _.last( totalBarData ).labels.push( w.val );
          });
          _.each( m.values, function(v) {
            _.last( totalBarData ).values.push( v.val );
          });
          _.each( m.weights, function(w, index) {
            _.last( totalBarData ).weights.push( w.val );

            _.last( totalPieData ).data.push({
              label: _.last( totalBarData ).labels[ index ],
              value: w.val
            });
          });

        });

        currentMonth = _.last( months ).id;
        createMonthButtons();

        barChartData.labels = _.last( totalBarData ).labels;
        barChartData.datasets[0].data = _.last( totalBarData ).values;

        // Fill initial month for bar chart
        for(var i = 0; i < nrOfEntries; i++) {
          pieData.labels[i] = _.last( totalPieData ).data[i].label;
          pieData.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
        }

        drawCharts();
        updateGraphs();
      }
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<|endoftext|>


<commit_before>var LQBViz = (function () {
  var nrOfEntries = 5,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      months = [],
      lineChartData,
      pieChartData,
      barChartData;

  var json2Months = function ( data ) {
    var monthsArray = [];

    _.each(data, function(val, key) {
      if ( key.indexOf("_t") <0 ) return;
      var group = parseInt( key.substr(key.lastIndexOf("_t")+2) ),
          month = _.find( monthsArray, function( m ) { return m.id === group; });

      if ( !month ) { // create new month if not found yet
        month = {
          id: group,
          words: [],
          values: [],
          weights: [],
          result: 0
        };
        monthsArray.push( month );
      }

      // put into correct array
      if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
        month.values.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val ? val.trim() : ""
        });
      } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
        month.weights.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val
        })
      } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
        month.words.push({
          id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
          val: val
        })
      } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
        month.result = val;
      }
    });

    return checkMonths( monthsArray );
  };
  var checkMonths = function ( monthsToCheck ) {
    // Remove months with no result, insufficient data, or empty words.
    // Careful: First month is different, as there wasn't a Stichwort yet.
    return _.reject( monthsToCheck, function( m ) {
      return !m.result ||
             m.words.length !== 5 ||
             m.values.length !== 5 ||
             m.weights.length !== 5 ||
             _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
    });
  };

  var getMonths = function () { return months; };
  var setMonths = function ( jsonData ) { months = json2Months( jsonData ); };

  var getNrOfEntriesPerMonth = function () { return nrOfEntries; };

  var initialSettings = function () {
    Chart.defaults.global.animation.duration = 400;
    Chart.defaults.global.animation.easing = "easeInOutQuart";
    Chart.defaults.global.scaleOverride = true;
    Chart.defaults.global.scaleSteps = 5;
    Chart.defaults.global.scaleStepWidth = 20;
    Chart.defaults.global.scaleStartValue = 0;
    Chart.defaults.global.scaleFontSize = 16;
    Chart.defaults.global.hover.mode = "nearest";
    Chart.defaults.global.tooltips.titleFontSize = 18;
    Chart.defaults.global.tooltips.bodyFontSize = 18;
  }();

  /**
   * returns a human readable month name, depending on the supplied index.
   * Since the experiment started in November 16, this is index 1.

   * @param  {Number} index
   * @return {String}
   */
  var getMonthName = function ( index ) {
    var year = (index-(index%12))/12;
    year = index%12 > 2 ? year+1 : year;
    return monthNames[ (index-1) % 12 ] + " '" + (15+year);
  };
  var getMonthNameShort = function( lqbIndex ) {
    return monthNamesShort[ (lqbIndex-1) % 12 ];
  };

  /**
   * gets a color palette or a single color
   *
   * @param  {String} type  [description]
   * @param  {Boolean} light [description]
   * @param  {Number} index  [description]
   * @return {String}       [description]
   */
  var getColors = function ( type, light, index ) {
    var arr;
    if ( type === "pie" ) {
      arr = light ? pieColorsLight : pieColors;
    } else if ( type === "bar" ) {
      arr = light ? barColorsLight : barColors;
    }

    return ( typeof index === "undefined" ) ? arr : arr[index];
  };

  var get2dContext = function ( id ) { return $("#"+id)[0].getContext("2d"); };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", this.getColors( "pie", false, index ) );
    $(node).children(".text").html( text );
  };

  var truncate = function ( string, length ) {
    return string.length > length ? string.substr( 0, length - 3 ) + "..." : string;
  };

  var createMonthButtons = function () {
    if ( months.length <= 1 ) {
      $(".monthButtons").hide(); // If there's only one (or zero) months, it's useless to draw the buttons
    } else {
      var currentMonthID = this.getLastMonth().id;

      _.each( months, function ( m ) {
        $( '
\
              '+ this.getMonthName( m.id ) +'\

' ).insertBefore( ".monthButtons li:last-child" );
      }, this );
    }
  };

  var getMonthByID = function ( id ) { return _.find( months, function(m){return m.id === id; }); };
  var getLastMonth = function () { return _.last( months ); };
  var getFirstMonth = function () { return _.first( months ); };

  var getNextMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getLastMonth().id ) {
      return this.getFirstMonth();
    } else {
      return _.find( months, function(m){ return m.id > currentMonthID; });
    }
  };
  var getPrevMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getFirstMonth().id ) {
      return this.getLastMonth();
    } else {
      return _.last( _.filter( months, function(m){ return m.id < currentMonthID; } ) );
    }
  };

  var createGraphData = function () {
    var totalBarData = [],
        totalPieData = [];

    // initial setup
    lineChartData = {
      labels : [],
      datasets : [{
        backgroundColor : "rgba(151,187,220,0.4)",
        strokeColor : "rgb(151,187,220)",
        pointColor : "rgb(151,187,220)",
        pointStrokeColor : "#fff",
        pointHighlightFill : "#fff",
        pointHighlightStroke : "rgb(151,187,220)",
        data : []
      }]
    };
    pieChartData = {
      labels: new Array( nrOfEntries ),
      datasets: [{
        data: new Array( nrOfEntries ),
        backgroundColor: getColors( "pie", false ),
        hoverBackgroundColor: getColors( "pie", true )
      }]
    };
    barChartData = {
      labels : [],
      datasets : [{
        backgroundColor : getColors( "bar", false ),
        strokeColor : "rgba(151,187,220,0.8)",
        highlightFill : getColors( "bar", true ),
        highlightStroke : "rgba(151,187,220,1)",
        data : []
      }]
    };

    //from each month, get the data and put it in the chart-data containers
    _.each( months, function(m) {
      var monthName = getMonthName( m.id );

      // LINECHART
      if ( m.result && parseInt( m.result ) ) {
        lineChartData.labels.push( monthName );
        lineChartData.datasets[0].data.push(  parseInt( m.result ) );
      }

      // PIE
      totalPieData.push({
        id: m.id,
        name: monthName,
        data: []
      });

      // BARCHART
      totalBarData.push({
        id: m.id,
        name: monthName,
        labels: [],
        values: [],
        weights: []
      });

      _.each( m.words, function(w) {
        _.last( totalBarData ).labels.push( w.val );
      });
      _.each( m.values, function(v) {
        _.last( totalBarData ).values.push( v.val );
      });
      _.each( m.weights, function(w, index) {
        _.last( totalBarData ).weights.push( w.val );

        _.last( totalPieData ).data.push({
          label: _.last( totalBarData ).labels[ index ],
          value: w.val
        });
      });
    });

    barChartData.labels = _.last( totalBarData ).labels;
    barChartData.datasets[0].data = _.last( totalBarData ).values;

    // Fill initial month for bar chart
    for(var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++) {
      pieChartData.labels[i] = _.last( totalPieData ).data[i].label;
      pieChartData.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
    }
  };

  var getChartData = function ( type ) {
    if ( type === "line" ) {
      return lineChartData;
    } else if ( type === "pie" ) {
      return pieChartData;
    } else if ( type === "bar" ) {
      return barChartData;
    }
  };

  return {
    getMonthName: getMonthName,
    getMonthNameShort: getMonthNameShort,
    getColors: getColors,
    getNrOfEntriesPerMonth: getNrOfEntriesPerMonth,
    get2dContext: get2dContext,
    updatePieLegend: updatePieLegend,
    truncate: truncate,
    createMonthButtons: createMonthButtons,
    getFirstMonth: getFirstMonth,
    getLastMonth: getLastMonth,
    getMonthByID: getMonthByID,
    getNextMonth: getNextMonth,
    getPrevMonth: getPrevMonth,
    getMonths: getMonths,
    setMonths: setMonths,
    createGraphData: createGraphData,
    getChartData: getChartData
  };
})();

$(document).ready(function () {
  var currentMonth,
      lineChart,
      pieChart,
      barChart;

  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    var clickedBtnAttribute = $(e.target).data("month") || $(e.target).parent().data("month") || $(e.originalEvent.currentTarget).data("month");

    if ( clickedBtnAttribute === "next" ) {
      currentMonth = LQBViz.getNextMonth( currentMonth ).id;
    } else if ( clickedBtnAttribute === "prev" ) {
      currentMonth = LQBViz.getPrevMonth( currentMonth ).id;
    } else {
      currentMonth = +clickedBtnAttribute;
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + currentMonth).parent().addClass("activeMonth");

    updateGraphs();

    e.stopPropagation();
    return false;
  });

  var updateGraphs = function() {
    var relevantData = LQBViz.getMonthByID( currentMonth );

    for( var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++ ) {
      pieChart.data.datasets[0].data[i] = relevantData.weights[i].val;
      var val = relevantData.words[i].val;
      pieChart.data.labels[i] = LQBViz.truncate(val, 28);
      LQBViz.updatePieLegend( i, val );

      barChart.data.datasets[0].data[i] = +relevantData.values[i].val;
      barChart.data.labels[i] = LQBViz.truncate(val, 15);
      // TODO: allow full text in tooltip
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    lineChart = new Chart( LQBViz.get2dContext("chart-area1"), {
      type: "line",
      data: LQBViz.getChartData("line"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true } }],
          xAxes: [{ ticks: { autoSkip: false /* show all labels, always */ } }]
        }
      }
    });

    pieChart = new Chart( LQBViz.get2dContext("chart-area2"), {
      type: "pie",
      data: LQBViz.getChartData("pie"),
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30,
        legend: { display: false }
      }
    });

    barChart = new Chart( LQBViz.get2dContext("chart-area3"), {
      type: "bar",
      data: LQBViz.getChartData("bar"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true, min: 0, max: 100 } }]
        }
      }
    });

  };

  var getData = function () {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: function ( data ) {

        LQBViz.setMonths( data );

        LQBViz.createGraphData();

        // take last available month as the currently selected month
        currentMonth = LQBViz.getLastMonth().id;
        LQBViz.createMonthButtons();

        drawCharts();
        updateGraphs();
      }
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<commit_msg>unified graph data<commit_after>var LQBViz = (function () {
  var nrOfEntries = 5,
      monthNames = [ "November", "Dezember", "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober" ],
      monthNamesShort = [ "Nov.", "Dez.", "Jan.", "Feb", "März", "April", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt." ],
      pieColors =      [ "#F00", "#CF0", "#0F6", "#06F", "#C0F" ],
      pieColorsLight = [ "rgba(255, 0, 0, 0.75)", "rgba(204,255,0,0.75)", "rgba(0, 255, 102, 0.75)", "rgba(0, 102, 255, 0.75)", "rgba(204, 0, 255, 0.75)" ],
      barColors =      [ "rgba(255, 0, 0, 0.6)", "rgba(204,255,0,0.6)", "rgba(0, 255, 102, 0.6)", "rgba(0, 102, 255, 0.6)", "rgba(204, 0, 255, 0.6)" ],
      barColorsLight = [ "rgba(255, 0, 0, 0.4)", "rgba(204,255,0,0.4)", "rgba(0, 255, 102, 0.4)", "rgba(0, 102, 255, 0.4)", "rgba(204, 0, 255, 0.4)" ],
      months = [],
      chartData;

  var json2Months = function ( data ) {
    var monthsArray = [];

    _.each(data, function(val, key) {
      if ( key.indexOf("_t") <0 ) return;
      var group = parseInt( key.substr(key.lastIndexOf("_t")+2) ),
          month = _.find( monthsArray, function( m ) { return m.id === group; });

      if ( !month ) { // create new month if not found yet
        month = {
          id: group,
          words: [],
          values: [],
          weights: [],
          result: 0
        };
        monthsArray.push( month );
      }

      // put into correct array
      if ( key.indexOf( "Zufriedenheit" ) >= 0 ) {
        month.values.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val ? val.trim() : ""
        });
      } else if ( key.indexOf( "Gewichtung" ) >= 0 ) {
        month.weights.push({
          id: key.substr( key.indexOf("_t"+group) -1, 1),
          val: val
        })
      } else if ( key.indexOf( "Aspekt" ) >= 0 ) {
        month.words.push({
          id: key.substr( key.indexOf( "Aspekt_" ) + 7, 1),
          val: val
        })
      } else if ( key.toLowerCase().indexOf( "seiqol" ) >= 0 ) {
        month.result = val;
      }
    });

    return checkMonths( monthsArray );
  };
  var checkMonths = function ( monthsToCheck ) {
    // Remove months with no result, insufficient data, or empty words.
    // Careful: First month is different, as there wasn't a Stichwort yet.
    return _.reject( monthsToCheck, function( m ) {
      return !m.result ||
             m.words.length !== 5 ||
             m.values.length !== 5 ||
             m.weights.length !== 5 ||
             _.any( m.words, function(w){ return _.isEmpty( w.val.trim() ); });
    });
  };

  var getMonths = function () { return months; };
  var setMonths = function ( jsonData ) { months = json2Months( jsonData ); };

  var getNrOfEntriesPerMonth = function () { return nrOfEntries; };

  var initialSettings = function () {
    Chart.defaults.global.animation.duration = 400;
    Chart.defaults.global.animation.easing = "easeInOutQuart";
    Chart.defaults.global.scaleOverride = true;
    Chart.defaults.global.scaleSteps = 5;
    Chart.defaults.global.scaleStepWidth = 20;
    Chart.defaults.global.scaleStartValue = 0;
    Chart.defaults.global.scaleFontSize = 16;
    Chart.defaults.global.hover.mode = "nearest";
    Chart.defaults.global.tooltips.titleFontSize = 18;
    Chart.defaults.global.tooltips.bodyFontSize = 18;
  }();

  /**
   * returns a human readable month name, depending on the supplied index.
   * Since the experiment started in November 16, this is index 1.

   * @param  {Number} index
   * @return {String}
   */
  var getMonthName = function ( index ) {
    var year = (index-(index%12))/12;
    year = index%12 > 2 ? year+1 : year;
    return monthNames[ (index-1) % 12 ] + " '" + (15+year);
  };
  var getMonthNameShort = function( lqbIndex ) {
    return monthNamesShort[ (lqbIndex-1) % 12 ];
  };

  /**
   * gets a color palette or a single color
   *
   * @param  {String} type  [description]
   * @param  {Boolean} light [description]
   * @param  {Number} index  [description]
   * @return {String}       [description]
   */
  var getColors = function ( type, light, index ) {
    var arr;
    if ( type === "pie" ) {
      arr = light ? pieColorsLight : pieColors;
    } else if ( type === "bar" ) {
      arr = light ? barColorsLight : barColors;
    }

    return ( typeof index === "undefined" ) ? arr : arr[index];
  };

  var get2dContext = function ( id ) { return $("#"+id)[0].getContext("2d"); };

  var updatePieLegend = function( index, text ){
    var node = $("#pieLegend li")[index];
    $(node).children(".color").css("background-color", this.getColors( "pie", false, index ) );
    $(node).children(".text").html( text );
  };

  var truncate = function ( string, length ) {
    return string.length > length ? string.substr( 0, length - 3 ) + "..." : string;
  };

  var createMonthButtons = function () {
    if ( months.length <= 1 ) {
      $(".monthButtons").hide(); // If there's only one (or zero) months, it's useless to draw the buttons
    } else {
      var currentMonthID = this.getLastMonth().id;

      _.each( months, function ( m ) {
        $( '
\
              '+ this.getMonthName( m.id ) +'\

' ).insertBefore( ".monthButtons li:last-child" );
      }, this );
    }
  };

  var getMonthByID = function ( id ) { return _.find( months, function(m){return m.id === id; }); };
  var getLastMonth = function () { return _.last( months ); };
  var getFirstMonth = function () { return _.first( months ); };

  var getNextMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getLastMonth().id ) {
      return this.getFirstMonth();
    } else {
      return _.find( months, function(m){ return m.id > currentMonthID; });
    }
  };
  var getPrevMonth = function ( currentMonthID ) {
    if ( currentMonthID === this.getFirstMonth().id ) {
      return this.getLastMonth();
    } else {
      return _.last( _.filter( months, function(m){ return m.id < currentMonthID; } ) );
    }
  };

  var createGraphData = function () {
    var totalBarData = [],
        totalPieData = [];

    // initial setup
    chartData = {
      "line": {
        labels : [],
        datasets : [{
          backgroundColor : "rgba(151,187,220,0.4)",
          strokeColor : "rgb(151,187,220)",
          pointColor : "rgb(151,187,220)",
          pointStrokeColor : "#fff",
          pointHighlightFill : "#fff",
          pointHighlightStroke : "rgb(151,187,220)",
          data : []
        }]
      },
      "pie": {
        labels: new Array( nrOfEntries ),
        datasets: [{
          data: new Array( nrOfEntries ),
          backgroundColor: getColors( "pie", false ),
          hoverBackgroundColor: getColors( "pie", true )
        }]
      },
      "bar": {
        labels : [],
        datasets : [{
          backgroundColor : getColors( "bar", false ),
          strokeColor : "rgba(151,187,220,0.8)",
          highlightFill : getColors( "bar", true ),
          highlightStroke : "rgba(151,187,220,1)",
          data : []
        }]
      }
    };

    //from each month, get the data and put it in the chart-data containers
    _.each( months, function(m) {
      var monthName = getMonthName( m.id );

      // LINECHART
      if ( m.result && parseInt( m.result ) ) {
        chartData.line.labels.push( monthName );
        chartData.line.datasets[0].data.push(  parseInt( m.result ) );
      }

      // PIE
      totalPieData.push({
        id: m.id,
        name: monthName,
        data: []
      });

      // BARCHART
      totalBarData.push({
        id: m.id,
        name: monthName,
        labels: [],
        values: [],
        weights: []
      });

      _.each( m.words, function(w) {
        _.last( totalBarData ).labels.push( w.val );
      });
      _.each( m.values, function(v) {
        _.last( totalBarData ).values.push( v.val );
      });
      _.each( m.weights, function(w, index) {
        _.last( totalBarData ).weights.push( w.val );

        _.last( totalPieData ).data.push({
          label: _.last( totalBarData ).labels[ index ],
          value: w.val
        });
      });
    });

    chartData.bar.labels = _.last( totalBarData ).labels;
    chartData.bar.datasets[0].data = _.last( totalBarData ).values;

    // Fill initial month for bar chart
    for(var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++) {
      chartData.pie.labels[i] = _.last( totalPieData ).data[i].label;
      chartData.pie.datasets[0].data[i] = +_.last( totalPieData ).data[i].value;
    }
  };

  var getChartData = function ( type ) { return chartData[type]; };

  return {
    getMonthName: getMonthName,
    getMonthNameShort: getMonthNameShort,
    getColors: getColors,
    getNrOfEntriesPerMonth: getNrOfEntriesPerMonth,
    get2dContext: get2dContext,
    updatePieLegend: updatePieLegend,
    truncate: truncate,
    createMonthButtons: createMonthButtons,
    getFirstMonth: getFirstMonth,
    getLastMonth: getLastMonth,
    getMonthByID: getMonthByID,
    getNextMonth: getNextMonth,
    getPrevMonth: getPrevMonth,
    getMonths: getMonths,
    setMonths: setMonths,
    createGraphData: createGraphData,
    getChartData: getChartData
  };
})();

$(document).ready(function () {
  var currentMonth,
      lineChart,
      pieChart,
      barChart;

  $("ul.monthButtons").on("click", ".changeMonthBtn", function( e ) {
    var clickedBtnAttribute = $(e.target).data("month") || $(e.target).parent().data("month") || $(e.originalEvent.currentTarget).data("month");

    if ( clickedBtnAttribute === "next" ) {
      currentMonth = LQBViz.getNextMonth( currentMonth ).id;
    } else if ( clickedBtnAttribute === "prev" ) {
      currentMonth = LQBViz.getPrevMonth( currentMonth ).id;
    } else {
      currentMonth = +clickedBtnAttribute;
    }

    $(".activeMonth").removeClass("activeMonth");
    $(".month" + currentMonth).parent().addClass("activeMonth");

    updateGraphs();

    e.stopPropagation();
    return false;
  });

  var updateGraphs = function() {
    var relevantData = LQBViz.getMonthByID( currentMonth );

    for( var i = 0; i < LQBViz.getNrOfEntriesPerMonth(); i++ ) {
      pieChart.data.datasets[0].data[i] = relevantData.weights[i].val;
      var val = relevantData.words[i].val;
      pieChart.data.labels[i] = LQBViz.truncate(val, 28);
      LQBViz.updatePieLegend( i, val );

      barChart.data.datasets[0].data[i] = +relevantData.values[i].val;
      barChart.data.labels[i] = LQBViz.truncate(val, 15);
      // TODO: allow full text in tooltip
    }

    barChart.update();
    pieChart.update();
  };

  var drawCharts = function() {
    lineChart = new Chart( LQBViz.get2dContext("chart-area1"), {
      type: "line",
      data: LQBViz.getChartData("line"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true } }],
          xAxes: [{ ticks: { autoSkip: false /* show all labels, always */ } }]
        }
      }
    });

    pieChart = new Chart( LQBViz.get2dContext("chart-area2"), {
      type: "pie",
      data: LQBViz.getChartData("pie"),
      options: {
        Easing: "easeInOutQuart",
        animationSteps: 30,
        legend: { display: false }
      }
    });

    barChart = new Chart( LQBViz.get2dContext("chart-area3"), {
      type: "bar",
      data: LQBViz.getChartData("bar"),
      options: {
        responsive: true,
        legend: { display: false },
        scales: {
          yAxes: [{ ticks: { beginAtZero: true, min: 0, max: 100 } }]
        }
      }
    });

  };

  var getData = function () {
    $.ajax({
      url: "php/getData.php",
      type: "POST",
      dataType : 'json',
      success: function ( data ) {

        LQBViz.setMonths( data );

        LQBViz.createGraphData();

        // take last available month as the currently selected month
        currentMonth = LQBViz.getLastMonth().id;
        LQBViz.createMonthButtons();

        drawCharts();
        updateGraphs();
      }
    }).fail(function( data ) {
      alert("Ein Fehler ist aufgetreten. Bitte laden Sie die Seite neu oder melden Sie sich bei der Versuchsleitung.");
    });
  };

  getData();
});
<|endoftext|>


<commit_before>// ## draeton.github.com
//
// Site code for my personal site
// [http://draeton.github.com/draeton.github.com](http://draeton.github.com/draeton.github.com)
//
// Copyright 2011, Matthew Cobbs
// Licensed under the MIT license.
//
/*global jQuery*/
(function (window, $) {

    var document = window.document;

    var Draeton = function () {
        this.init();
    };

    Draeton.prototype = {
        init: function () {
            this.bindHandlers();
            this.initMenu();
        },

        bindHandlers: function () {
            var $search = $(".navbar form");

            // search form
            $search.on("a.add-on", "click", function () {
                $search.submit();
            });

            // tooltips
            if ($.fn.tooltip) {
                $('a[data-toggle="tooltip"]').tooltip();
            }
        },

        initMenu: function () {
            var href = document.location.href;

            $("ul.nav li > a").each(function () {
                if (this.href.replace(/[/#]+$/, "") === href.replace(/[/#]+$/, "")) {
                    $(this).parents("li").addClass("active");
                }
            });
        }
    };

    $(document).ready(function () {
        window.draeton = new Draeton();
    });

})(window, jQuery);<commit_msg> Test search<commit_after>// ## draeton.github.com
//
// Site code for my personal site
// [http://draeton.github.com/draeton.github.com](http://draeton.github.com/draeton.github.com)
//
// Copyright 2011, Matthew Cobbs
// Licensed under the MIT license.
//
/*global jQuery*/
(function (window, $) {

    var document = window.document;

    var Draeton = function () {
        this.init();
    };

    Draeton.prototype = {
        init: function () {
            this.bindHandlers();
            this.initMenu();
        },

        bindHandlers: function () {
            var $search = $(".navbar form");

            // search form
            $search.on("a.add-on", "click", function () {
                console.log("submitting");
                //$search.submit();
            });

            // tooltips
            if ($.fn.tooltip) {
                $('a[data-toggle="tooltip"]').tooltip();
            }
        },

        initMenu: function () {
            var href = document.location.href;

            $("ul.nav li > a").each(function () {
                if (this.href.replace(/[/#]+$/, "") === href.replace(/[/#]+$/, "")) {
                    $(this).parents("li").addClass("active");
                }
            });
        }
    };

    $(document).ready(function () {
        window.draeton = new Draeton();
    });

})(window, jQuery);<|endoftext|>


<commit_before>;(function() {
'use strict';

// Cryptodog OTR functions and callbacks.
Cryptodog.otr = {}

// Construct a new OTR conversation
Cryptodog.otr.add = function(nickname) {
	// file protocol doesn't support WebWorkers
	if (window.location.protocol === 'file:'){
		var otr = new OTR({
			priv: Cryptodog.me.otrKey
		})
	}
	else {
		var otr = new OTR({
			priv: Cryptodog.me.otrKey,
			smw: {
				path: 'js/workers/smp.js',
				seed: Cryptodog.random.generateSeed
			}
		})
	}
	otr.REQUIRE_ENCRYPTION = true
	otr.on('ui',     onIncoming.bind(null, nickname))
	otr.on('io',     onOutgoing.bind(null, nickname))
	otr.on('smp',    onSMPAnswer.bind(null, nickname))
	otr.on('status', onStatusChange.bind(null, nickname))
	otr.on('file',   onFile.bind(null, nickname))
	return otr
}

// Handle incoming messages.
var onIncoming = function(nickname, msg, encrypted) {
	// Drop unencrypted messages.
	if (!encrypted) {
		return
	}
	Cryptodog.addToConversation(
		msg, nickname, Cryptodog.buddies[nickname].id, 'message'
	)
	if (Cryptodog.me.currentBuddy !== Cryptodog.buddies[nickname].id && !Cryptodog.buddies[nickname].ignored()) {
		Cryptodog.messagePreview(msg, nickname)
	}
}

// Handle outgoing messages depending on connection type.
var onOutgoing = function(nickname, message) {
	Cryptodog.xmpp.connection.muc.message(
		Cryptodog.me.conversation
			+ '@'
			+ Cryptodog.xmpp.currentServer.conference,
		nickname, message, null, 'chat', 'active'
	)
}

// Handle otr state changes.
var onStatusChange = function(nickname, state) {
	/*jshint camelcase:false */
	var buddy = Cryptodog.buddies[nickname]
	if (state === OTR.CONST.STATUS_AKE_SUCCESS) {
		var fingerprint = buddy.otr.their_priv_pk.fingerprint()
		if (buddy.fingerprint === null) {
			buddy.fingerprint = fingerprint
			Cryptodog.UI.closeGenerateFingerprints(nickname)
		}
		else if (buddy.fingerprint !== fingerprint) {
			// re-aked with a different key
			buddy.fingerprint = fingerprint
			Cryptodog.UI.removeAuthAndWarn(nickname)
		}
	}
}

// Store received filename.
var onFile = function(nickname, type, key, filename) {
	var buddy = Cryptodog.buddies[nickname]
	// filename is being relied on as diversifier
	// and should continue to be generated uniquely
	// as in sendFile()
	var derivedKey = CryptoJS.PBKDF2(key, filename, { keySize: 16 })
	derivedKey = derivedKey.toString(CryptoJS.enc.Latin1)
	if (!buddy.fileKey) {
		buddy.fileKey = {}
	}
	buddy.fileKey[filename] = {
		encryptKey: derivedKey.substring(0, 32),
		macKey:     derivedKey.substring(32)
	}
}

// Receive an SMP question
var onSMPQuestion = function(nickname, question) {
	var buddy = Cryptodog.buddies[nickname];

	// Silently answer question if buddy is ignored.
	if (buddy.ignored()){
		var answer = Cryptodog.prepareAnswer(' ', false, buddy.mpFingerprint);
		buddy.otr.smpSecret(answer);
		if (!answer){
			buddy.otr.smpSecret(Cryptodog.random.encodedBytes(16, CryptoJS.enc.Hex));
		}
		return;
	}

	var chatWindow = Cryptodog.locale.chatWindow,
		answer = false
	var info = Mustache.render(Cryptodog.templates.authRequest, {
		authenticate: chatWindow.authenticate,
		authRequest: chatWindow.authRequest.replace('(NICKNAME)', nickname),
		answerMustMatch: chatWindow.answerMustMatch
			.replace('(NICKNAME)', nickname),
		question: question,
		answer: chatWindow.answer
	})
	$('#dialogBoxClose').click()
	window.setTimeout(function() {
		Cryptodog.UI.dialogBox(info, {
			height: 240,
			closeable: true,
			onAppear: function() {
				$('#authReplySubmit').unbind('click').bind('click', function(e) {
					e.preventDefault()
					answer = $('#authReply').val()
					answer = Cryptodog.prepareAnswer(answer, false, buddy.mpFingerprint)
					buddy.otr.smpSecret(answer)
					$('#dialogBoxClose').click()
				})
			},
			onClose: function() {
				if (answer) { return }
				buddy.otr.smpSecret(
					Cryptodog.random.encodedBytes(16, CryptoJS.enc.Hex)
				)
			}
		})
	}, 500)
}

// Handle SMP callback
var onSMPAnswer = function(nickname, type, data, act) {
	var chatWindow = Cryptodog.locale.chatWindow,
		buddy = Cryptodog.buddies[nickname]
	switch(type) {
	case 'question':
		onSMPQuestion(nickname, data)
		break
	case 'trust':
		if (act === 'asked') {
			// Set authentication result
			buddy.updateAuth(data)
			if ($('.authSMP').length) {
				if (buddy.authenticated) {
					$('#authSubmit').val(chatWindow.identityVerified)
					$('#authenticated').click()
				}
				else {
					$('#authSubmit').val(chatWindow.failed)
						.animate({'background-color': '#F00'})
				}
			}
		}
		break
	case 'abort':
		if ($('.authSMP').length) {
			$('#authSubmit').val(chatWindow.failed)
				.animate({'background-color': '#F00'})
		}
		break
	}
}

}())
<commit_msg>Format otr.js<commit_after>(function() {
    'use strict';

    // Cryptodog OTR functions and callbacks.
    Cryptodog.otr = {};

    // Construct a new OTR conversation
    Cryptodog.otr.add = function(nickname) {
        // file protocol doesn't support WebWorkers
        if (window.location.protocol === 'file:') {
            var otr = new OTR({
                priv: Cryptodog.me.otrKey
            });
        } else {
            var otr = new OTR({
                priv: Cryptodog.me.otrKey,
                smw: {
                    path: 'js/workers/smp.js',
                    seed: Cryptodog.random.generateSeed
                }
            });
        }

        otr.REQUIRE_ENCRYPTION = true;
        otr.on('ui', onIncoming.bind(null, nickname));
        otr.on('io', onOutgoing.bind(null, nickname));
        otr.on('smp', onSMPAnswer.bind(null, nickname));
        otr.on('status', onStatusChange.bind(null, nickname));
        otr.on('file', onFile.bind(null, nickname));
        return otr;
    };

    // Handle incoming messages.
    var onIncoming = function(nickname, msg, encrypted) {
        // Drop unencrypted messages.
        if (!encrypted) {
            return;
        }

        Cryptodog.addToConversation(msg, nickname, Cryptodog.buddies[nickname].id, 'message');

        if (Cryptodog.me.currentBuddy !== Cryptodog.buddies[nickname].id && !Cryptodog.buddies[nickname].ignored()) {
            Cryptodog.messagePreview(msg, nickname);
        }
    };

    // Handle outgoing messages depending on connection type.
    var onOutgoing = function(nickname, message) {
        Cryptodog.xmpp.connection.muc.message(
            Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
            nickname,
            message,
            null,
            'chat',
            'active'
        );
    };

    // Handle otr state changes.
    var onStatusChange = function(nickname, state) {
        /*jshint camelcase:false */
        var buddy = Cryptodog.buddies[nickname];

        if (state === OTR.CONST.STATUS_AKE_SUCCESS) {
            var fingerprint = buddy.otr.their_priv_pk.fingerprint();

            if (buddy.fingerprint === null) {
                buddy.fingerprint = fingerprint;
                Cryptodog.UI.closeGenerateFingerprints(nickname);
            } else if (buddy.fingerprint !== fingerprint) {
                // re-aked with a different key
                buddy.fingerprint = fingerprint;
                Cryptodog.UI.removeAuthAndWarn(nickname);
            }
        }
    };

    // Store received filename.
    var onFile = function(nickname, type, key, filename) {
        var buddy = Cryptodog.buddies[nickname];

        // filename is being relied on as diversifier
        // and should continue to be generated uniquely
        // as in sendFile()
        var derivedKey = CryptoJS.PBKDF2(key, filename, { keySize: 16 });
        derivedKey = derivedKey.toString(CryptoJS.enc.Latin1);

        if (!buddy.fileKey) {
            buddy.fileKey = {};
        }

        buddy.fileKey[filename] = {
            encryptKey: derivedKey.substring(0, 32),
            macKey: derivedKey.substring(32)
        };
    };

    // Receive an SMP question
    var onSMPQuestion = function(nickname, question) {
        var buddy = Cryptodog.buddies[nickname];

        // Silently answer question if buddy is ignored.
        if (buddy.ignored()) {
            var answer = Cryptodog.prepareAnswer(' ', false, buddy.mpFingerprint);
            buddy.otr.smpSecret(answer);
            if (!answer) {
                buddy.otr.smpSecret(Cryptodog.random.encodedBytes(16, CryptoJS.enc.Hex));
            }
            return;
        }

        var chatWindow = Cryptodog.locale.chatWindow,
            answer = false;

        var info = Mustache.render(Cryptodog.templates.authRequest, {
            authenticate: chatWindow.authenticate,
            authRequest: chatWindow.authRequest.replace('(NICKNAME)', nickname),
            answerMustMatch: chatWindow.answerMustMatch.replace('(NICKNAME)', nickname),
            question: question,
            answer: chatWindow.answer
        });

        $('#dialogBoxClose').click();

        window.setTimeout(function() {
            Cryptodog.UI.dialogBox(info, {
                height: 240,
                closeable: true,

                onAppear: function() {
                    $('#authReplySubmit')
                        .unbind('click')
                        .bind('click', function(e) {
                            e.preventDefault();
                            answer = $('#authReply').val();
                            answer = Cryptodog.prepareAnswer(answer, false, buddy.mpFingerprint);
                            buddy.otr.smpSecret(answer);
                            $('#dialogBoxClose').click();
                        });
                },

                onClose: function() {
                    if (answer) {
                        return;
                    }
                    buddy.otr.smpSecret(Cryptodog.random.encodedBytes(16, CryptoJS.enc.Hex));
                }
            });
        }, 500);
    };

    // Handle SMP callback
    var onSMPAnswer = function(nickname, type, data, act) {
        var chatWindow = Cryptodog.locale.chatWindow,
            buddy = Cryptodog.buddies[nickname];

        switch (type) {
            case 'question':
                onSMPQuestion(nickname, data);
                break;

            case 'trust':
                if (act === 'asked') {
                    // Set authentication result
                    buddy.updateAuth(data);
                    if ($('.authSMP').length) {
                        if (buddy.authenticated) {
                            $('#authSubmit').val(chatWindow.identityVerified);
                            $('#authenticated').click();
                        } else {
                            $('#authSubmit')
                                .val(chatWindow.failed)
                                .animate({ 'background-color': '#F00' });
                        }
                    }
                }
                break;

            case 'abort':
                if ($('.authSMP').length) {
                    $('#authSubmit')
                        .val(chatWindow.failed)
                        .animate({ 'background-color': '#F00' });
                }
                break;
        }
    };
})();
<|endoftext|>


<commit_before>angular.module('customFilters.markdown', []).filter('markdown', function() {
	var converter = new showdown.converter();
	return function(input) {
		return converter.makeHtml(input || '');
	}
});

angular.module('customFilters.trust', []).filter('trust', function($sce) {
	return function(input) {
		return $sce.trustAsHtml(input || '');
	}
});
<commit_msg>fix bug after update showdown to 1.4.3  again<commit_after>angular.module('customFilters.markdown', []).filter('markdown', function() {
	var converter = new showdown.Converter();
	return function(input) {
		return converter.makeHtml(input || '');
	}
});

angular.module('customFilters.trust', []).filter('trust', function($sce) {
	return function(input) {
		return $sce.trustAsHtml(input || '');
	}
});
<|endoftext|>


<commit_before>//APIのモジュールを読み込み
google.load("feeds", "1");
function initialize() {

	var d = new Date();
	var dq = d.getMonth()+""+d.getDate()+""+d.getHours();
	//フィードの取得
	var feed = new google.feeds.Feed("http://tokka.ipon.biz/feed.xml" + "?" + dq);

	//エントリの表示数の設定
	feed.setNumEntries(20);

	//関数の定義
	feed.load(function(result) {
		if (!result.error) {
			//読み込みが成功したときの処理
			var container = document.getElementById("get-feed");
			var htmlstr = "";
			for (var i = 0; i < result.feed.entries.length; i++) {

				var entry = result.feed.entries[i];

				//日付の取得
				var pdate = new Date(entry.publishedDate); //Dateクラス
				var pyear = pdate.getFullYear();   //年
				var pmonth = pdate.getMonth() + 1; //月
				var pday = pdate.getDate();        //日

				//日付を2桁表示に変更
				if (pyear < 2000) pyear += 1900;
				if (pmonth < 10) {pmonth = "0" + pmonth;}
				if (pday < 10) {pday = "0" + pday;}

				var date = pyear + "." + pmonth + "." + pday + " ";

				//画像の取得
				imgsrc = entry.content.match(/src="(.*?)"/igm);

				//html生成
				htmlstr += '
';
				htmlstr += '';
				htmlstr += '' + date + '| ' + entry.categories[0] + '| ' + entry.title + '
';
			}
			container.innerHTML = htmlstr;
		} else {
			//読み込みが失敗したときの処理
			alert(result.error.code + ":" + result.error.message);
		}
	});
}
google.setOnLoadCallback(initialize);<commit_msg>modify js<commit_after>//APIのモジュールを読み込み
google.load("feeds", "1");
function initialize() {

	var d = new Date();
	var dq = d.getMonth()+""+d.getDate()+""+d.getHours();
	//フィードの取得
	var feed = new google.feeds.Feed("http://tokka.ipon.biz/feed.xml" + "?" + dq);

	//エントリの表示数の設定
	feed.setNumEntries(20);

	//関数の定義
	feed.load(function(result) {
		if (!result.error) {
			//読み込みが成功したときの処理
			var container = document.getElementById("get-feed");
			var htmlstr = "";
			for (var i = 0; i < result.feed.entries.length; i++) {

				var entry = result.feed.entries[i];

				//日付の取得
				var pdate = new Date(entry.publishedDate); //Dateクラス
				var pyear = pdate.getFullYear();   //年
				var pmonth = pdate.getMonth() + 1; //月
				var pday = pdate.getDate();        //日

				//日付を2桁表示に変更
				if (pyear < 2000) pyear += 1900;
				if (pmonth < 10) {pmonth = "0" + pmonth;}
				if (pday < 10) {pday = "0" + pday;}

				var date = pyear + "." + pmonth + "." + pday + " ";

				//画像の取得
				imgsrc = entry.content.match(/src="(.*?)"/igm);

				//html生成
				htmlstr += '
';
				htmlstr += '';
				htmlstr += '' + date + '| ' + entry.categories[0] + '| ' + entry.title + '
';
			}
			container.innerHTML = htmlstr;
		} else {
			//読み込みが失敗したときの処理
			console.log(result.error.code + ":" + result.error.message);
		}
	});
}
google.setOnLoadCallback(initialize);<|endoftext|>