summaryrefslogtreecommitdiff
path: root/js/util
diff options
context:
space:
mode:
authorFreeyorp <TheFreeYorp@NOSPAM.G.m.a.i.l.replace>2013-04-23 15:26:48 +1200
committerFreeyorp <TheFreeYorp@NOSPAM.G.m.a.i.l.replace>2013-04-23 15:26:48 +1200
commita7da1fafe2ca8c9115ce76f99a903e1b3da692a3 (patch)
treeee4465cbebc54cd937f69ede32b2b99513dd76a0 /js/util
parentf12d953786784ca8e8b8e9db146ce494b30f6647 (diff)
downloadmanavis-a7da1fafe2ca8c9115ce76f99a903e1b3da692a3.tar.gz
manavis-a7da1fafe2ca8c9115ce76f99a903e1b3da692a3.tar.bz2
manavis-a7da1fafe2ca8c9115ce76f99a903e1b3da692a3.tar.xz
manavis-a7da1fafe2ca8c9115ce76f99a903e1b3da692a3.zip
Add initial stat trellis chart
This should now be implemented efficiently enough for everything else to still work. This currently does not allow filtering, but the dimensions are prepared in a manner that makes this a simple addition.
Diffstat (limited to 'js/util')
-rw-r--r--js/util/trellis-chart.js130
1 files changed, 130 insertions, 0 deletions
diff --git a/js/util/trellis-chart.js b/js/util/trellis-chart.js
new file mode 100644
index 0000000..139d663
--- /dev/null
+++ b/js/util/trellis-chart.js
@@ -0,0 +1,130 @@
+function trellisChart(anchor, monoGroups) {
+ /* attr -> {dim, group} key -> str amount, value -> { str, agi, vit, dex, int, luk } */
+
+ var attrs = monoGroups.map(function(d) { return d.name; });
+ var attrsIdByName = {};
+ monoGroups.forEach(function(d, i) { attrsIdByName[d.name] = i; });
+
+ var cellWidth = 5;
+ var radius = cellWidth / 2;
+ var subChartLength = 57;
+ var subChartUnpaddedLength = 50;
+ var subChartPadding = 7;
+
+ var margin = {top: 10, right: 10, bottom: 20, left: 10};
+ var anchor = d3.select(anchor);
+ var g = anchor.select("g");
+ var filler = d3.scale.log().domain([1, 2]).range([0, 255]);
+
+ var _chart = function() {
+ if (g.empty()) {
+ /* Make stuff! */
+ var svg = anchor.append("svg");
+ g = svg
+ .append("g");
+ attrs.forEach(function(d, i) {
+ g
+ .append("text")
+ .attr("transform", function(d) { return "translate(0," + ((attrs.length - i) * subChartLength + 10 - subChartLength / 2) + ")"; })
+ .text(d)
+ ;
+ g
+ .append("text")
+ .attr("transform", function(d) { return "translate(" + (i * subChartLength + 25 + 22) + "," + (attrs.length * subChartLength + 18) + ")"; })
+ .text(d)
+ ;
+ })
+ g = svg
+ .append("g")
+ .attr("transform", "translate(" + (margin.left + 25) + "," + (margin.top) + ")");
+ }
+ /* Group first into columns for each stat. We have one column for each of the stat monoGroups. */
+ /*
+ * monoGroups is an array of each stat dimension. We can consider each column to have data in the following format:
+ * { group: function, dim: function, name: stat }
+ */
+ var columns = g.selectAll(".column")
+ .data(monoGroups);
+ var colE = columns
+ .enter().append("g")
+ .attr("class", "column")
+ .attr("transform", function(d) { return "translate(" + (attrsIdByName[d.name] * subChartLength) + ",0)"; })
+ ;
+ colE
+ .append("line")
+ .attr("x1", -cellWidth)
+ .attr("x2", -cellWidth)
+ .attr("y1", -cellWidth)
+ .attr("y2", subChartLength * attrs.length - subChartPadding)
+ .attr("class", "border-line")
+ ;
+ colE
+ .append("line")
+ .attr("x1", subChartUnpaddedLength)
+ .attr("x2", subChartUnpaddedLength)
+ .attr("y1", -cellWidth)
+ .attr("y2", subChartLength * attrs.length - subChartPadding)
+ .attr("class", "border-line")
+ ;
+ /* Each stat has an array for its value. Group these to find the x position. */
+ /*
+ * The function transforms the data to take the grouping. We can consider each x position grouping to have data in the following format:
+ * { key: position, value: [{[stat] -> [y pos] -> count}] }
+ */
+ var colposg = columns.selectAll(".colpos")
+ .data(function(d, i) {
+// console.log("Incoming colposg format:", d, i, "Transformed to:", d.group.all().map(function(d2) { d2.name = d.name; return d2; }));
+ return d.group.all().map(function(d2) { d2.name = d.name; return d2; });
+ }, function(d) { return d.key; });
+ colposg
+ .enter().append("g")
+ .attr("class", "colpos")
+ .attr("transform", function(d) { return "translate(" + (d.key * cellWidth) + ",0)"; })
+ ;
+ /* Next, split up each x position grouping into its y stat grouping. */
+ /*
+ * We can consider each y stat grouping to have data in the following format:
+ * v[y pos] -> count; v.name -> name
+ */
+ var rows = colposg.selectAll(".row")
+ .data(function(d, i) {
+// console.log("Incoming row format:", d, i, "Transformed to:", attrs.map(function(d2) { return { name: d2, data: d.value[d2] }; }));
+ return attrs.map(function(d2) { return { name: d2, data: d.value[d2] }; });
+ });
+ rows
+ .enter().append("g")
+ .attr("class", "row")
+ .attr("transform", function(d) { return "translate(0," + ((attrs.length - attrsIdByName[d.name] - 1) * subChartLength) + ")"; })
+ ;
+ /* Finally, split up each y stat grouping into x. */
+ var vmax = 0;
+ var cells = rows.selectAll(".cell")
+ .data(function(d, i) {
+// console.log("Incoming cells format:", d, i, "Transformed to:", d.data);
+ return d.data;
+ });
+ cells
+ .enter().append("circle")
+ .attr("class", "cell")
+ .attr("r", radius)
+ ;
+ cells
+ .each(function(d) {
+ if (d > vmax) vmax = d;
+ })
+ ;
+ filler.domain([1, vmax + 1]);
+ cells
+ .attr("fill", function(d) {
+ return d ? d3.rgb(255 - filler(d + 1), 255 - filler(d + 1) / 2, 255 - filler(d + 1) / 3) : "white";
+ })
+ .attr("transform", function(d, i) { return "translate(0," + ((10-i) * cellWidth) + ")"; })
+ ;
+ cells
+ .exit()
+ .remove()
+ ;
+ }
+
+ return _chart;
+}