diff options
author | Freeyorp <TheFreeYorp@NOSPAM.G.m.a.i.l.replace> | 2013-04-13 18:10:51 +1200 |
---|---|---|
committer | Freeyorp <TheFreeYorp@NOSPAM.G.m.a.i.l.replace> | 2013-04-13 18:20:57 +1200 |
commit | 8f34d7e6ce1142af2171d9ec31e20e9738c8223f (patch) | |
tree | 3469c004607cac366bda99d40365dbb8295b8029 /js/mv.js | |
parent | 35209fb4ddf117fa0cbde1eef4cff1fb45dfc24f (diff) | |
download | manavis-8f34d7e6ce1142af2171d9ec31e20e9738c8223f.tar.gz manavis-8f34d7e6ce1142af2171d9ec31e20e9738c8223f.tar.bz2 manavis-8f34d7e6ce1142af2171d9ec31e20e9738c8223f.tar.xz manavis-8f34d7e6ce1142af2171d9ec31e20e9738c8223f.zip |
Refactor mv.js into distinct modules
There are five modules, as follows:
load.js handles initialisation and management of files
parse.js handles initialisation and management of records
heap.js handles initialisation and management of dimensions
chart.js handles initialisation and management of charts
main.js manages the other modules and status
Status and file loading have been decoupled; file loading no longer directly
updates the status of the progress bars.
This makes the limitations of the current status system more apparent, and
should make the system also easier to maintain, as progress bars are now
updated at more logical times.
The parser remains mostly unchanged. It will need to be altered into a full
stateful parser, but this can happen later.
Dimension management is now simplified, due to the addition of monoGroup.
Most dimension/groups consisted of a single dimension and a group reduced by
count. This convenience function combines these and unifies their access,
beyond mere naming convention.
Charting management is also greatly simplified, adding in chain helpers to
categorise types of charts, by aspects such as being wide, being thin,
being short, as well as helpers to establish common properties for bar and
pie charts. There is now also a helper to take advantage of the unified
monoGroup accessors.
Diffstat (limited to 'js/mv.js')
-rw-r--r-- | js/mv.js | 332 |
1 files changed, 0 insertions, 332 deletions
diff --git a/js/mv.js b/js/mv.js deleted file mode 100644 index b4910ed..0000000 --- a/js/mv.js +++ /dev/null @@ -1,332 +0,0 @@ -"use strict"; -/* - * Globals accessible via the agent console for debugging purposes - */ -var mv = {}; -/* - * Processing - */ -(function() { - function softAssert(expr, msg) { - if (!expr) { - console.log("SOFTASSERT FAILURE: " + msg); - } - } - /* 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, i) { - var d; - d = e.match(/^(\d+\.\d+) PC(\d+) (\d+):(\d+),(\d+) GAINXP (\d+) (\d+) (\w+)/); - if (d) { - var mapSID = parseInt(d[3]); - var ts = new Date(0); - ts.setUTCSeconds(d[1]); - var rec = { - date: ts, - pc: parseInt(d[2]), - map: map.nameByServerID(parseInt(d[3]), ts), - x: parseInt(d[4]), - y: parseInt(d[5]), - e: parseInt(d[6]), - j: parseInt(d[7]), - type: d[8], - pcstat: pcstat[d[2]], - target: 0, - dmg: 0, - wpn: 0 - }; - if (pcstat[d[2]] == undefined && (!fullyDefinedCutoff || ts > fullyDefinedCutoff)) { - fullyDefinedCutoff = ts; - } - /* XXX: Fragile horrible and unstructured, this whole thing needs a rewrite really */ - if (i >= 2 && rec.type == "KILLXP") { - d = spl[i - 1].match(/^(\d+\.\d+) MOB(\d+) DEAD/); - if (d) { - var mID = parseInt(d[2]); - /* There's a massive wealth of data that can be collected from this. Number of assailants, weapons used, the relationships with the assailants... this can't be done with a simple lookbehind. For now, just extract what mob it was, and what the killing weapon used was. */ - d = spl[i - 2].match(/^(\d+\.\d+) PC(\d+) (\d+):(\d+),(\d+) WPNDMG MOB(\d+) (\d+) FOR (\d+) WPN (\d+)/); - if (d) { - softAssert(mID == parseInt(d[6]), "Integrity error: MOB ID mismatch!"); -// softAssert(rec.pc == parseInt(d[2]), "Integrity error: PC ID mismatch!"); - rec.target = parseInt(d[7]); - rec.dmg = parseInt(d[8]); - rec.wpn = parseInt(d[9]); - } - } else { - d = spl[i - 1].match(/^(\d+\.\d+) PC(\d+) (\d+):(\d+),(\d+) GAINXP (\d+) (\d+) (\w+)/); - if (d) { - var clone = records[records.length - 1]; - softAssert(rec.map == clone.map, "Integrity error: MAP ID mismatch!"); - rec.target = clone.target; - rec.dmg = clone.dmg; /* FIXME: Take into account actual assist damage */ - rec.wpn = clone.wpn; - } - } - } - records.push(rec); - 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; - } - }); - } - var cfdata, all, - dateDim, dateGroup, - pcDim, pcGroup, - mapDim, mapGroup, - blvlDim, blvlGroup, - typeDim, typeGroup, - targetDim, targetGroup, - dmgDim, dmgGroup, - wpnDim, wpnGroup, - /* - * 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(); - typeDim = cfdata.dimension(function(d) { return d.type; }); - typeGroup = typeDim.group().reduceCount(); - targetDim = cfdata.dimension(function(d) { return d.target; }); - targetGroup = targetDim.group().reduceCount(); - wpnDim = cfdata.dimension(function(d) { return d.wpn; }); - wpnGroup = wpnDim.group().reduceCount(); - /* Add new dimensions above here */ - 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(".vis-hide") - .style("display", "inline") - .transition() - .style("opacity", 1) - ; - mv.dateChart = dc.barChart("#date-chart") - .width(700) - .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(700) - .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(380) - .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.typeChart = dc.pieChart("#type-chart") - .width(380) - .height(130) - .radius(60) - .dimension(typeDim) - .group(typeGroup) - .colorCalculator(d3.scale.category20c()) - ; - mv.targetChart = dc.pieChart("#target-chart") - .width(380) - .height(130) - .radius(60) - .dimension(targetDim) - .group(targetGroup) - .colorCalculator(d3.scale.category20c()) - ; - mv.targetChart = dc.pieChart("#wpn-chart") - .width(380) - .height(130) - .radius(60) - .dimension(wpnDim) - .group(wpnGroup) - .colorCalculator(d3.scale.category20c()) - ; - mv.defChart = dc.pieChart("#def-chart") - .width(380) - .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) - .colorCalculator(d3.scale.category20c()) - /* 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(); - } -})(); |