summaryrefslogblamecommitdiff
path: root/js/mv.js
blob: 82a7d5fe6e216f8c681048e3065e5a303cdd471f (plain) (tree)
1
2
3
4
5



                                                                  
            













































                                                                              


                               
                     





















                                                                                                                                                                               









                                                                                                                    


                                  






















                                                                                                             
                  






                              

                                                                                 

               
       
                                
   



                       






                                                                                                
                     

                                               










                                                                                   

                                                                                     


                                                                                                                                                  


















































                                                                                                        












                                                                      
















                                                                                  





                                                         

                                                                                           















                                                                           

     
"use strict";
/*
 * Globals accessible via the agent console for debugging purposes
 */
var mv = {};
/*
 * Processing
 */
(function() {
  /* Set up handlers for file selector */
  document.getElementById('input').addEventListener('change', function(fevt) {
    var reader = new FileReader();
    var loadbar = progress('loadbar');
    var filesbar = progress('filesbar');

    reader.onerror = function(evt) {
      switch(evt.target.error.code) {
      case evt.target.error.NOT_FOUND_ERR:
        alert('File Not Found!');
        break;
      case evt.target.error.NOT_READABLE_ERR:
        alert('File is not readable');
        break;
      case evt.target.error.ABORT_ERR:
        break; // noop
      default:
        alert('An error occurred reading this file.');
      };
    }
    reader.onprogress = function(evt) {
      if (evt.lengthComputable) {
        loadbar.update(evt.loaded, evt.total);
      }
    }
    reader.onabort = function(evt) {
      alert('File load aborted!');
    }
    reader.onloadstart = function(evt) {
      loadbar.reset();
    }
    reader.onload = function(evt) {
      loadbar.complete();
      ++cur;
      parseRecords(reader.result);
      if (cur == fevt.target.files.length) {
        filesbar.complete();
        /* TODO: Make this fade out nicely? */
        setTimeout(function() {
          loadbar.hide();
        }, 2000);
        makeHeap();
        setTimeout(function() {
          filesbar.hide();
        }, 2000);
        makeCharts();
      } else {
        filesbar.update(cur, fevt.target.files.length);
        nextFile();
      }
    }
    var cur = 0;
    var lbase = loadbar.label;
    loadbar.label = function() {
      return lbase() == '100%' ? "Loaded '" + fevt.target.files[cur].name + "' - Done!" : "Loading '" + fevt.target.files[cur].name + "' - " + lbase();
    };
    var fbase = filesbar.label;
    filesbar.label = function () {
      return fbase() == '100%' ? "Loaded " + fevt.target.files.length + " file(s) - Done!" : "Loading file " + (cur + 1) + " of " + fevt.target.files.length + " - " + fbase();
    }
    loadbar.show();
    filesbar.show();
    function nextFile() {
      reader.readAsBinaryString(fevt.target.files[cur]);
    }
    nextFile();
  }, false);
  var records = [];
  var pcstat = {};
  var fullyDefinedCutoff = false;
  function defLevelVerbose(level) {
    switch (level) {
      case 0: return "Undefined";
      case 1: return "Mixed";
      case 2: return "Defined";
      default: console.log(d, d.data); throw "Unknown definedness case (" + d.data.key + "); this shouldn't happen";
    }
  }
  function parseRecords(data) {
    var spl = data.split(/\r?\n/);
    spl.forEach(function(e) {
      var d;
      d = e.match(/^(\d+\.\d+) PC(\d+) (\d+):(\d+),(\d+) GAINXP (\d+) (\d+) (\w+)/);
      if (d) {
        var ts = new Date(0);
        ts.setUTCSeconds(d[1]);
        records.push({
          date: ts,
          pc:   parseInt(d[2]),
          map:  parseInt(d[3]),
          x:    parseInt(d[4]),
          y:    parseInt(d[5]),
          e:    parseInt(d[6]),
          j:    parseInt(d[7]),
          type: d[8],
          pcstat: pcstat[d[2]]
        });
        if (pcstat[d[2]] == undefined && (!fullyDefinedCutoff || ts > fullyDefinedCutoff)) {
          fullyDefinedCutoff = ts;
        }
        return;
      }
      d = e.match(/^(?:\d+\.\d+) PC(\d+) (?:\d+):(?:\d+),(?:\d+) STAT (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) /);
      if (d) {
         var s = {
          str: parseInt(d[2]),
          agi: parseInt(d[3]),
          vit: parseInt(d[4]),
          int: parseInt(d[5]),
          dex: parseInt(d[6]),
          luk: parseInt(d[7])
        };
        s.blvl = stat.minLevelForStats(s.str, s.agi, s.vit, s.int, s.dex, s.luk);
        pcstat[d[1]] = s;
        return;
      }
    });
    console.log(records.length);
  }
  var cfdata, all,
    dateDim, dateGroup,
    pcDim, pcGroup,
    mapDim, mapGroup,
    blvlDim, blvlGroup,
    /*
     * How well defined a record is.
     *  0 -> Record contains undefined data
     *  1 -> Record is defined, but undefined records follow and may impede validity of findings
     *  2 -> Record and all succeeding records are well defined
     */
    defDim, defGroup;
  /* The record files are set, do everything */
  function makeHeap() {
    function a(p, d) { return { e: p.e + d.e, j: p.j + d.j, r: p.r + 1 }; }
    function s(p, d) { return { e: p.e - d.e, j: p.j - d.j, r: p.r - 1 }; }
    function z(p, d) { return { e: 0, j: 0, r: 0 }; }
    cfdata = crossfilter(records);
    all = cfdata.groupAll().reduce(a, s, z);
    dateDim = cfdata.dimension(function(d) { return d3.time.hour.round(d.date); });
    dateGroup = dateDim.group().reduceCount();
    pcDim = cfdata.dimension(function(d) { return d.pc; });
    pcGroup = pcDim.group().reduceCount();
    mapDim = cfdata.dimension(function(d) { return d.map; });
    mapGroup = mapDim.group().reduce(a, s, z);
    blvlDim = cfdata.dimension(function(d) { return d.pcstat ? d.pcstat.blvl : 0; });
    blvlGroup = blvlDim.group().reduceCount();
    defDim = cfdata.dimension(function(d) { if (d.pcstat == undefined) { return 0; } if (d.date <= fullyDefinedCutoff) { return 1; } return 2; });
    defGroup = defDim.group().reduceCount();
    defDim.filterExact(2);
    /*
     * The viewport is the bubble frame.
     * - K: Map
     * - X: Exp
     * - Y: JExp
     * - r: Record count
     */
  }
  function makeCharts() {
    d3.select("#mask")
      .transition()
      .style("opacity", 0)
      .remove();
    d3.selectAll(".chart-root")
      .style("display", "inline")
      .transition()
      .style("opacity", 1)
      ;
    mv.dateChart = dc.barChart("#date-chart")
      .width(630)
      .height(130)
      .margins({left: 60, right: 18, top: 5, bottom: 30})
      .dimension(dateDim)
      .group(dateGroup)
      .centerBar(true)
      .gap(1)
      .elasticY(true)
      .elasticX(true)
      .x(d3.time.scale().domain([dateDim.bottom(1)[0].date, dateDim.top(1)[0].date]).nice(d3.time.hour))
      .xUnits(d3.time.hours)
      .xAxisPadding(2)
    //     .renderVerticalGridLines(true)
      .renderHorizontalGridLines(true)
      .title(function(d) { return d.key + ": " + d.value; })
      .brushOn(true)
      ;
    console.log([pcDim.bottom(1)[0], pcDim.top(1)[0]])
    mv.pcChart = dc.barChart("#player-chart")
      .width(630)
      .height(130)
      .margins({left: 60, right: 18, top: 5, bottom: 30})
      .dimension(pcDim)
      .group(pcGroup)
      .gap(1)
//       .elasticX(true)
      .elasticY(true)
      .x(d3.scale.linear().domain([pcDim.bottom(1)[0].pc, pcDim.top(1)[0].pc]).nice())
      .renderHorizontalGridLines(true)
      .title(function(d) { return d.key + ": " + d.value; })
      .brushOn(true)
      ;
    mv.blvlChart = dc.barChart("#blvl-chart")
      .width(630)
      .height(130)
      .margins({left: 60, right: 18, top: 5, bottom: 30})
      .dimension(blvlDim)
      .group(blvlGroup)
      .gap(1)
      .elasticY(true)
      .x(d3.scale.linear().domain([0, blvlDim.top(1)[0].pcstat.blvl]))
      .renderHorizontalGridLines(true)
      .title(function(d) { return d.key + ": " + d.value; })
      .brushOn(true)
      ;
    mv.defChart = dc.pieChart("#def-chart")
      .width(630)
      .height(130)
      .radius(60)
      .dimension(defDim)
      .group(defGroup)
      .label(function(d) { return defLevelVerbose(d.data.key); })
      .title(function(d) { return defLevelVerbose(d.data.key) + ": " + d.value; })
      .colorAccessor(function(d) { return d.data.key; })
      .colorCalculator(function(k) { switch(k) {
        case 0: return "#fd350d";
        case 1: return "#fdae6b";
        case 2: return "#6baed6";
        default: throw "Definition chart: Color access key out of range!";
      }})
      .filter(2)
      ;
    mv.mapChart = dc.bubbleChart("#map-chart")
      .width(700)
      .height(500)
      .margins({left: 60, right: 18, top: 5, bottom: 30})
      .dimension(mapDim)
      .group(mapGroup)
      .colorDomain(function(d) { return [mapDim.bottom(1)[0].map, mapDim.top(1)[0].map]; })
      .colorAccessor(function(d, i){ return d.key; })
      /* X */
      .keyAccessor(function(d) { return d.value.e + 1; })
      /* Y */
      .valueAccessor(function(d) { return d.value.j + 1; })
      /* R */
      .radiusValueAccessor(function(d) { return Math.log(d.value.r + 1); })
      .x(d3.scale.log().domain([1, 100000]))
      .y(d3.scale.log().domain([1, 300000]))
      .elasticX(true)
      .elasticY(true)
      .renderHorizontalGridLines(true)
      .renderVerticalGridLines(true)
      .title(function(d) { return "Map " + d.key; })
      .renderTitle(true)
      ;
    dc.renderAll();
  }
})();