"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 Stat(str, agi, vit, int, dex, luk) { this.str = str; this.agi = agi; this.vit = vit; this.int = int; this.dex = dex; this.luk = luk; this.blvl = stat.minLevelForStats(str, agi, vit, int, dex, luk); } Stat.prototype.valueOf = function() { return this.str * 1e15 + this.agi * 1e12 + this.vit * 1e9 + this.int * 1e6 + this.dex * 1e3 + this.luk; /*this.str + ":" + this.agi + ":" + this.vit + ":" + this.dex + ":" + this.int + ":" + this.luk*/; }; var nullstat = new Stat(0,0,0,0,0,0); 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]] ? pcstat[d[2]] : nullstat }); 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) { pcstat[d[1]] = new Stat(parseInt(d[2]), parseInt(d[3]), parseInt(d[4]), parseInt(d[5]), parseInt(d[6]), parseInt(d[7])); return; } }); } var attrs = ["str", "agi", "vit", "int", "dex", "luk"]; var cfdata, all, dateDim, dateGroup, pcDim, pcGroup, mapDim, mapGroup, blvlDim, blvlGroup, attrDims, attrGroups, /* * 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() { cfdata = crossfilter(records); mv.all = all = cfdata.groupAll().reduceCount(); 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( function(p, d) { return { e: p.e + d.e, j: p.j + d.j, r: p.r + 1 }; }, function(p, d) { return { e: p.e - d.e, j: p.j - d.j, r: p.r - 1 }; }, function(p, d) { return { e: 0, j: 0, r: 0 }; } ); blvlDim = cfdata.dimension(function(d) { return d.pcstat != nullstat ? d.pcstat.blvl : 0; }); blvlGroup = blvlDim.group().reduceCount(); mv.attrDims = attrDims = {}; mv.attrGroups = attrGroups = {}; for (var y = 0; y != attrs.length - 1; ++y) { attrDims[attrs[y]] = {}; attrGroups[attrs[y]] = {}; for (var x = y + 1; x != attrs.length; ++x) { attrDims[attrs[y]][attrs[x]] = cfdata.dimension(function(h, l) { return function(d) { return Math.floor(d.pcstat[h] / 7) * 7 * 1e3 + Math.floor(d.pcstat[l] / 7) * 7; } }(attrs[y], attrs[x])); attrGroups[attrs[y]][attrs[x]] = attrDims[attrs[y]][attrs[x]].group().reduceCount(); } } // for (var i = 0; i != attrs.length; ++i) { // attrDims[attrs[i]] = cfdata.dimension(function(d) { return d.pcstat ? d.pcstat[attrs[i]] }); // attrGroups[attrs[i]] = attrDims[attrs[i]].group().reduceCount(); // } defDim = cfdata.dimension(function(d) { if (d.pcstat == nullstat) { return 0; } if (d.date <= fullyDefinedCutoff) { return 1; } return 2; }); defGroup = defDim.group().reduceCount(); /* * 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) ; 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!"; }}) ; 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) ; mv.defChart.filter(2); var c = function(v) { return "rgb(" + 25 * v + "," + 15 * v + "," + 3 * v + ")"; }; c.range = function() { return { length: 11 }; }; mv.attrCharts = {}; for (var y = 0; y != attrs.length - 1; ++y) { mv.attrCharts[attrs[y]] = {}; for (var x = y + 1; x != attrs.length; ++x) { mv.attrCharts[attrs[y]][attrs[x]] = dc.bubbleChart("#" + attrs[x] + "-" + attrs[y]) .width(100) .height(100) .margins({left: 0, right: 0, top: 0, bottom: 0}) .dimension(attrDims[attrs[y]][attrs[x]]) .group(attrGroups[attrs[y]][attrs[x]]) .colors(c) .colorAccessor(function(d, i){ return d.value; }) .keyAccessor(function(k) { return function(d) { return d.key % 1e3; }; }(attrs[x])) .valueAccessor(function(k) { return function(d) { return Math.floor(d.key / 1e3); }; }(attrs[y])) .radiusValueAccessor(function(d) { return 3; }) .x(d3.scale.linear().domain([1, 99])) .y(d3.scale.linear().domain([1, 99])) .r(d3.scale.identity()) .renderLabel(false) ; } } dc.renderAll(); } })();