Skip to content

Commit 91fba7f

Browse files
committed
starting new analysis tool
1 parent ace84f5 commit 91fba7f

File tree

8 files changed

+10994
-0
lines changed

8 files changed

+10994
-0
lines changed

app/assets/javascripts/crossfilter.js

Lines changed: 1402 additions & 0 deletions
Large diffs are not rendered by default.

app/assets/javascripts/d3.js

Lines changed: 9233 additions & 0 deletions
Large diffs are not rendered by default.

app/assets/javascripts/gg.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@
7070
//= require_tree ./angular/controllers/
7171
//= require ./angular/filters.js
7272

73+
//= require d3.js
74+
//= require crossfilter.js
75+
//= require scout.js
76+
7377
function dontDoThisEither() {
7478
// Proxino.log("log this");
7579
throw "help i'm having a cloudfront problem";

app/assets/javascripts/scout.js

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
var formatNumber = d3.format(",d"),
2+
formatChange = d3.format("+,d"),
3+
formatDate = d3.time.format("%B %d, %Y"),
4+
formatTime = d3.time.format("%I:%M %p");
5+
6+
function render(method) {
7+
d3.select(this).call(method);
8+
}
9+
10+
function renderAll() {
11+
chart.each(render);
12+
// dont have a number yet showing all
13+
// d3.select("#active").text(formatNumber(all.value()));
14+
}
15+
16+
window.filter = function(filters) {
17+
filters.forEach(function(d, i) { charts[i].filter(d); });
18+
renderAll();
19+
};
20+
21+
window.reset = function(i) {
22+
charts[i].filter(null);
23+
renderAll();
24+
};
25+
26+
27+
function barChart() {
28+
if (!barChart.id) barChart.id = 0;
29+
30+
var margin = {top: 10, right: 10, bottom: 20, left: 10},
31+
x,
32+
y = d3.scale.linear().range([100, 0]),
33+
id = barChart.id++,
34+
axis = d3.svg.axis().orient("bottom"),
35+
brush = d3.svg.brush(),
36+
brushDirty,
37+
dimension,
38+
group,
39+
round;
40+
41+
function chart(div) {
42+
var width = x.range()[1],
43+
height = y.range()[0];
44+
45+
y.domain([0, group.top(1)[0].value]);
46+
47+
div.each(function() {
48+
var div = d3.select(this),
49+
g = div.select("g");
50+
51+
// Create the skeletal chart.
52+
if (g.empty()) {
53+
div.select(".title").append("a")
54+
.attr("href", "javascript:reset(" + id + ")")
55+
.attr("class", "reset")
56+
.text("reset")
57+
.style("display", "none");
58+
59+
g = div.append("svg")
60+
.attr("width", width + margin.left + margin.right)
61+
.attr("height", height + margin.top + margin.bottom)
62+
.append("g")
63+
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
64+
65+
g.append("clipPath")
66+
.attr("id", "clip-" + id)
67+
.append("rect")
68+
.attr("width", width)
69+
.attr("height", height);
70+
71+
g.selectAll(".bar")
72+
.data(["background", "foreground"])
73+
.enter().append("path")
74+
.attr("class", function(d) { return d + " bar"; })
75+
.datum(group.all());
76+
77+
g.selectAll(".foreground.bar")
78+
.attr("clip-path", "url(#clip-" + id + ")");
79+
80+
g.append("g")
81+
.attr("class", "axis")
82+
.attr("transform", "translate(0," + height + ")")
83+
.call(axis);
84+
85+
// Initialize the brush component with pretty resize handles.
86+
var gBrush = g.append("g").attr("class", "brush").call(brush);
87+
gBrush.selectAll("rect").attr("height", height);
88+
gBrush.selectAll(".resize").append("path").attr("d", resizePath);
89+
}
90+
91+
// Only redraw the brush if set externally.
92+
if (brushDirty) {
93+
brushDirty = false;
94+
g.selectAll(".brush").call(brush);
95+
div.select(".title a").style("display", brush.empty() ? "none" : null);
96+
if (brush.empty()) {
97+
g.selectAll("#clip-" + id + " rect")
98+
.attr("x", 0)
99+
.attr("width", width);
100+
} else {
101+
var extent = brush.extent();
102+
g.selectAll("#clip-" + id + " rect")
103+
.attr("x", x(extent[0]))
104+
.attr("width", x(extent[1]) - x(extent[0]));
105+
}
106+
}
107+
108+
g.selectAll(".bar").attr("d", barPath);
109+
});
110+
111+
function barPath(groups) {
112+
var path = [],
113+
i = -1,
114+
n = groups.length,
115+
d;
116+
while (++i < n) {
117+
d = groups[i];
118+
path.push("M", x(d.key), ",", height, "V", y(d.value), "h9V", height);
119+
}
120+
return path.join("");
121+
}
122+
123+
function resizePath(d) {
124+
var e = +(d == "e"),
125+
x = e ? 1 : -1,
126+
y = height / 3;
127+
return "M" + (.5 * x) + "," + y
128+
+ "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6)
129+
+ "V" + (2 * y - 6)
130+
+ "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y)
131+
+ "Z"
132+
+ "M" + (2.5 * x) + "," + (y + 8)
133+
+ "V" + (2 * y - 8)
134+
+ "M" + (4.5 * x) + "," + (y + 8)
135+
+ "V" + (2 * y - 8);
136+
}
137+
}
138+
139+
brush.on("brushstart.chart", function() {
140+
var div = d3.select(this.parentNode.parentNode.parentNode);
141+
div.select(".title a").style("display", null);
142+
});
143+
144+
brush.on("brush.chart", function() {
145+
var g = d3.select(this.parentNode),
146+
extent = brush.extent();
147+
if (round) g.select(".brush")
148+
.call(brush.extent(extent = extent.map(round)))
149+
.selectAll(".resize")
150+
.style("display", null);
151+
g.select("#clip-" + id + " rect")
152+
.attr("x", x(extent[0]))
153+
.attr("width", x(extent[1]) - x(extent[0]));
154+
dimension.filterRange(extent);
155+
});
156+
157+
brush.on("brushend.chart", function() {
158+
if (brush.empty()) {
159+
var div = d3.select(this.parentNode.parentNode.parentNode);
160+
div.select(".title a").style("display", "none");
161+
div.select("#clip-" + id + " rect").attr("x", null).attr("width", "100%");
162+
dimension.filterAll();
163+
}
164+
});
165+
166+
chart.margin = function(_) {
167+
if (!arguments.length) return margin;
168+
margin = _;
169+
return chart;
170+
};
171+
172+
chart.x = function(_) {
173+
if (!arguments.length) return x;
174+
x = _;
175+
axis.scale(x);
176+
brush.x(x);
177+
return chart;
178+
};
179+
180+
chart.y = function(_) {
181+
if (!arguments.length) return y;
182+
y = _;
183+
return chart;
184+
};
185+
186+
chart.dimension = function(_) {
187+
if (!arguments.length) return dimension;
188+
dimension = _;
189+
return chart;
190+
};
191+
192+
chart.filter = function(_) {
193+
if (_) {
194+
brush.extent(_);
195+
dimension.filterRange(_);
196+
} else {
197+
brush.clear();
198+
dimension.filterAll();
199+
}
200+
brushDirty = true;
201+
return chart;
202+
};
203+
204+
chart.group = function(_) {
205+
if (!arguments.length) return group;
206+
group = _;
207+
return chart;
208+
};
209+
210+
chart.round = function(_) {
211+
if (!arguments.length) return round;
212+
round = _;
213+
return chart;
214+
};
215+
216+
return d3.rebind(chart, brush, "on");
217+
};
218+
219+
function scout_init() {
220+
matches = [];
221+
entities = [];
222+
$.getJSON("http://localhost:3000/matches.json", function( data ) {
223+
$.each( data, function( index, match ) {
224+
match.play_date = new Date(match.play_date);
225+
matches.push(match);
226+
});
227+
$.getJSON("http://localhost:3000/ents.json", function( data ) {
228+
$.each( data, function( index, entity ) {
229+
entities.push(entity);
230+
});
231+
ent_cf = crossfilter(entities);
232+
raceDim = ent_cf.dimension(function(ent) { return ent.race });
233+
winDim = ent_cf.dimension(function(ent) { return ent.race });
234+
235+
m_cf = crossfilter(matches);
236+
m_dur_d = m_cf.dimension(function(m) { return Math.min(40, m.duration_minutes) });
237+
m_dur_g = m_dur_d.group(function(d) { return Math.floor(d / 5) * 5 });
238+
239+
m_date_d = m_cf.dimension(function(m) { return m.play_date });
240+
m_date_g = m_date_d.group(d3.time.day);
241+
242+
charts = [
243+
barChart()
244+
.dimension(m_dur_d)
245+
.group(m_dur_g)
246+
.x(d3.scale.linear()
247+
.domain([0, 40])
248+
.rangeRound([0, 20 * 8])),
249+
250+
barChart()
251+
.dimension(m_date_d)
252+
.group(m_date_g)
253+
.round(d3.time.day.round)
254+
.x(d3.time.scale()
255+
.domain([new Date(2014, 7, 15), new Date(2014, 8, 15)])
256+
.rangeRound([0, 10 * 30]))
257+
];
258+
259+
chart = d3.selectAll(".chart")
260+
.data(charts)
261+
.each(function(chart) { chart.on("brush", renderAll).on("brushend", renderAll); });
262+
263+
renderAll();
264+
265+
// .domain([0, 24])
266+
// .rangeRound([0, 10 * 24]))
267+
});
268+
});
269+
270+
// raceDim.group().size()
271+
// raceDim.group().all() <-- counts for P, T and Z
272+
273+
}

app/views/home/scout.html

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<% content_for(:head) do %>
2+
<title>Scout</title>
3+
<meta name="Description" content="Learn what wins. Over 100,000 games of Starcraft 2.">
4+
5+
<style>
6+
#charts {
7+
padding: 10px 0;
8+
}
9+
10+
.chart {
11+
display: inline-block;
12+
height: 151px;
13+
margin-bottom: 20px;
14+
}
15+
16+
.reset {
17+
padding-left: 1em;
18+
font-size: smaller;
19+
color: #ccc;
20+
}
21+
22+
.background.bar {
23+
fill: #ccc;
24+
}
25+
26+
.foreground.bar {
27+
fill: steelblue;
28+
}
29+
30+
.axis path, .axis line {
31+
fill: none;
32+
stroke: #000;
33+
shape-rendering: crispEdges;
34+
}
35+
36+
.axis text {
37+
font: 10px sans-serif;
38+
}
39+
40+
.brush rect.extent {
41+
fill: steelblue;
42+
fill-opacity: .125;
43+
}
44+
45+
.brush .resize path {
46+
fill: #eee;
47+
stroke: #666;
48+
}
49+
50+
#duration-chart {
51+
width: 260px;
52+
}
53+
54+
#date-chart {
55+
width: 260px;
56+
}
57+
</style>
58+
<% end %>
59+
60+
<script type="text/javascript">
61+
scout_init();
62+
</script>
63+
64+
<div id="static">
65+
<div class="content">
66+
<div class="static_inner">
67+
68+
<div id="charts">
69+
<div id="duration-chart" class="chart">
70+
<div class="title">Game Length, minutes</div>
71+
</div>
72+
<div id="date-chart" class="chart">
73+
<div class="title">Game Date</div>
74+
</div>
75+
</div>
76+
</div>
77+
</div>
78+
</div>

config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@
136136

137137
post 'backend/ipn', :to => 'payment#paypal_ipn'
138138

139+
match 'scout' => 'home#scout'
140+
139141
# 404
140142
match "*path" => 'application#not_found'
141143
end

public/ents.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

public/matches.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)