[ Launch: Pimp my Tribe (update4 - redux) ] 4614246 by enjalot
[ Launch: Pimp my Tribe (update3 - redux) ] 4612056 by zeffii
[ Launch: Pimp my Tribe (update2) ] 4603089 by zeffii
[ Launch: Pimp my Tribe (update2) ] 4596906 by enjalot
[ Launch: Pimp my Tribe ] 4594558 by zeffii
[ Launch: Pimp my Tribe ] 4585252 by zeffii
[ Launch: Pimp my Tribe ] 4573091 by zeffii
[ Launch: Pimp my Tribe ] 4572416 by zeffii
[ Launch: Pimp my Tribe ] 4571945 by zeffii
[ Launch: Pimp my Tribe ] 4568998 by enjalot
[ Launch: Pimp my Tribe ] 4567995 by zeffii
[ Launch: Pimp my Tribe ] 4564213 by zeffii
[ Launch: Pimp my Tribe ] 4558845 by enjalot
[ Launch: Pimp my Tribe ] 4558042 by zeffii
[ Launch: Tributary Inlets ] 4552099 by zeffii
[ Launch: Tributary Inlets ] 4551425 by zeffii
[ Launch: Tributary Inlets ] 4549657 by enjalot
[ Launch: An inlet to Tributary ] 4545400 by enjalot
-
-
Save enjalot/4614246 to your computer and use it in GitHub Desktop.
Pimp my Tribe (update4 - redux)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Pimp my Tribe (update4 - redux)","endpoint":"","display":"html","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"play":true,"loop":true,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"tab":"edit","display_percent":0.6597453544693251,"hidepanel":false} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* NOTES | |
In firefox text attribute "alignment-baseline" will fail. | |
Instead, to get this to look similar on a variety of | |
browsers i'd consider making y depend on text height of | |
(boxWidth / 2) + (lowercase n height / 2). Right now | |
this is a hardcoded value. | |
- marker & usernames are links | |
- marker mouseover shows inlet title | |
- username mouseover shows user stats | |
*/ | |
/* HELPER FUNCTIONS + CONSTANTS */ | |
function translate(value_x, value_y){ | |
return "translate(" + [value_x, value_y] + ")" | |
} | |
var users_url = '/api/users'; | |
var created_url = '/api/latest/created'; | |
var trib_inlet = 'http://tributary.io/inlet/'; | |
var iso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ").parse; | |
/* AXIS SETUP */ | |
var margin = {top: 76, right: 130, bottom: 2, left: 45}, | |
extent_width = tributary.sw -20, | |
width = extent_width - margin.left - margin.right, | |
height = 645 - margin.top - margin.bottom; | |
var extent_size = 0.05; | |
tributary.duration = 5000; | |
var boxWidth = 12, | |
boxHeight = 12; | |
var x = d3.time.scale().range([0, width]), | |
x2 = d3.time.scale().range([0, width]); | |
var yScale = d3.scale.ordinal() | |
.rangeBands([0, height], 0) | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom") | |
.ticks(7) | |
.tickSubdivide(1) | |
.tickSize(11, 4, 5); | |
var xAxis2 = d3.svg.axis() | |
.scale(x2) | |
.orient("bottom") | |
.ticks(7) | |
.tickSubdivide(2) | |
.tickSize(11, 4, 5); | |
/* SVG SETUP */ | |
var display = d3.select("#display") | |
var button = display.append("input") | |
.attr({ | |
id: "fetch", | |
type: "button", | |
value: "fetch" | |
}) | |
var svg = display.append("svg") | |
.attr({ | |
"xmlns": "http://www.w3.org/2000/svg", | |
"xlink": "http://www.w3.org/1999/xlink", | |
"class": "tributary_svg" | |
}) | |
//initialize chart containers | |
var userBars = svg.append("g") | |
.classed("userBars", true) | |
.attr("transform", translate(0, margin.top)) | |
svg.append("g") | |
.classed("usernames", true) | |
.attr("transform", translate(width, margin.top)) | |
var box = svg.append("g") | |
.classed("funky", true) | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.attr("transform", translate(margin.left, margin.top)); | |
box.append("g").attr({ | |
"class": "x axis", | |
"transform": translate(0, height) | |
}) | |
box.append("g").attr({ | |
"class": "x2 axis", | |
"transform": translate(0, -37) | |
}) | |
// bush setup (slider) | |
var xscale = d3.scale.linear() | |
.domain([0, 1]) | |
.range([0, width]); | |
var brush = d3.svg.brush() | |
.x(xscale); | |
var slider = svg.append("g").attr("transform", translate(margin.left,0)); | |
brush.extent([0., .05]); | |
brush(slider); | |
slider.selectAll("rect.background") | |
.attr("height", 32); | |
slider.selectAll("g.resize rect") | |
.attr("height", 32); | |
slider.selectAll(".extent") | |
.attr("height", 32); | |
var posx = brush.extent(); | |
// theme | |
var marker_style = { | |
"fill": "#49BDFF", | |
"fill-opacity": 0.33, | |
"stroke": "none" | |
} | |
var bar_style = { | |
"fill": "#FFFFFF", | |
"fill-opacity": 0.74681 | |
} | |
var text_style = { | |
"font-size": 1.3 + "em", | |
"font-family": 'Roboto', // sans-serif', | |
"font-weight": 300 | |
} | |
//font | |
WebFontConfig = { | |
google: { families: [ 'Roboto:400,100:latin' ] } | |
}; | |
(function() { | |
var wf = document.createElement('script'); | |
var dlp = document.location.protocol; | |
wf.src = ('https:' == dlp ? 'https' : 'http') + | |
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'; | |
wf.type = 'text/javascript'; | |
wf.async = 'true'; | |
var s = document.getElementsByTagName('script')[0]; | |
s.parentNode.insertBefore(wf, s); | |
})(); | |
/* GET USERS */ | |
if(!tributary.users) { | |
d3.json(users_url, function(err, res) { | |
tributary.users = {}; | |
res.forEach(function(u) { | |
tributary.users[u.login] = u; | |
}) | |
render(); | |
}) | |
} | |
button.on("click", function() { | |
d3.json(created_url, function(err, res) { | |
tributary.inlets = res; | |
update_content(); | |
}) | |
}) | |
/* DATA PRUNING FUNCTIONS */ | |
function make_user_obj(){ | |
var inlets = tributary.inlets | |
var user_list = tributary.users; | |
var user_strata = new Object(); | |
// convert the userlist to a strata index | |
var counter = 0; | |
function populateStrata(name){ | |
user_strata[name] = counter | |
counter += 1 | |
} | |
user_list = d3.keys(user_list); | |
user_list.forEach(populateStrata); | |
return { | |
user_list: user_list, | |
user_strata: user_strata | |
} | |
} | |
function get_domain(){ | |
return { | |
newest: tributary.inlets.slice(-1)[0].createdAt, | |
oldest: tributary.inlets.slice(0, 1)[0].createdAt | |
} | |
} | |
function filter_time(cutoff){ | |
// pick time cutoff | |
var time_domain = get_domain(), | |
time_start = iso(time_domain.newest), | |
time_end = iso(time_domain.oldest); | |
var transit = d3.interpolate(time_start, time_end)(cutoff); | |
return new Date(Math.round(transit)); | |
} | |
function between_cutoffs(d, cutoff_0, cutoff_1){ | |
return (d.createdAt >= cutoff_0) && (d.createdAt <= cutoff_1); | |
} | |
function cherry_pick(){ | |
var data_reduced = []; | |
var cutoff_0 = filter_time(posx[0]); | |
var cutoff_1 = filter_time(posx[1]); | |
// use the map iterator to populate data_reduced | |
var data = _.map(tributary.inlets, function(d){ | |
var user_datum = { | |
createdAt: iso(d.createdAt), | |
t_user: d.user.login, | |
description: d.description || "no description", | |
gist_id: d.gistid | |
} | |
if (between_cutoffs(user_datum, cutoff_0, cutoff_1)) { | |
data_reduced.push(user_datum) | |
} | |
return user_datum | |
}); | |
return {data: data, reduced: data_reduced} | |
} | |
function compose_stats(d){ | |
var stat = tributary.users[d]; | |
return "visits: " + (stat.visits || 0) + | |
" forks: " + (stat.nforks || 0) + | |
" inlets: " + (stat.inlets || 0) | |
} | |
/* MAIN DRAW FUNCTION */ | |
function render() { | |
if(!tributary.inlets) return; | |
var user_object = make_user_obj(); | |
var cp = cherry_pick(); | |
var data = cp.data; | |
var data_reduced = cp.reduced; | |
x.domain(d3.extent(data_reduced, function(d) { return d.createdAt } )); | |
x2.domain(d3.extent(data, function(d) { return d.createdAt } )); | |
yScale.domain(user_object.user_list) | |
svg.select("g.x.axis") | |
.call(xAxis) | |
.style(text_style) | |
svg.select("g.x2.axis") | |
.call(xAxis2) | |
.style(text_style) | |
var ubSel = userBars | |
.selectAll("rect.userbar") | |
.data(user_object.user_list) | |
ubSel | |
.enter() | |
.append("rect") | |
.classed("userbar", true) | |
ubSel | |
.attr({ | |
"y": function(d) { return yScale(d) - boxHeight/2 - 1 }, | |
"x": margin.left - boxWidth/2, | |
"width": width + margin.left + margin.right + 90, | |
"height": boxHeight + 2 | |
}) | |
.style(bar_style) | |
var markers = svg.select("g.funky") | |
.selectAll("a") | |
.data(data_reduced); | |
markers | |
.enter() | |
.append("a") | |
.attr({ | |
"xlink:href": function(d){ return trib_inlet + d.gist_id }, | |
"xlink:title": function(d){ return d.description }, | |
"xlink:show": "new", | |
"cursor": "pointer" | |
}) | |
.append("rect") | |
markers.select("a rect") | |
.attr({ | |
"transform": function(d, i) { | |
var y_loc = yScale(d.t_user) - boxHeight/2; | |
return translate(x(d.createdAt)- boxWidth/2, y_loc) | |
}, | |
"width": boxWidth, | |
"height": boxHeight | |
}) | |
.style(marker_style) | |
markers.exit().remove(); | |
var userNames = svg.select("g.usernames") | |
.selectAll("g.username") | |
.data(user_object.user_list); | |
userNames | |
.enter() | |
.append("g") | |
.classed("username", true) | |
.append("a") | |
.attr({ | |
"xlink:href": function(d){ | |
return tributary.users[d].html_url | |
}, | |
"xlink:title": function(d){ | |
return compose_stats(d) | |
}, | |
"xlink:show": "new", | |
"cursor": "pointer" | |
}) | |
.append("text") | |
userNames.select("text") | |
.text(function(d) { return d }) | |
.attr({ | |
"y": function(d) { return yScale(d) + 3.864 }, | |
"x": -margin.left + margin.right - 25 | |
}) | |
.style(text_style) | |
}; | |
update_content() | |
if(!tributary.inlets || !tributary.inlets.length) { | |
d3.json(created_url, function(err, res) { | |
tributary.inlets = res; | |
update_content(); | |
}) | |
} | |
function update_content(){ | |
posx = brush.extent(); | |
render(); | |
} | |
brush.on("brushstart", function(){ update_content(); }) | |
brush.on("brush", function(){ update_content(); }) | |
brush.on("brushend", function(){ update_content(); }) | |
tributary.run = function(g,t) { | |
console.log(t) | |
var start = d3.max([0, t - extent_size/2]); | |
var end = d3.min([1, t + extent_size/2]); | |
brush.extent([start, end]); | |
brush(slider); | |
update_content(); | |
} | |
/* EOF */ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#fetch { | |
position:relative; | |
margin-top: 20px; | |
left: 10px; | |
font-size:1.7em; | |
padding: 3px 10px 3px 10px; | |
float:left; | |
} | |
.inlet { | |
margin-left: 10px; | |
margin-top: 20px; | |
} | |
.inlet img { | |
margin-left: 10px; | |
//margin-top: 5px; | |
} | |
.time { | |
font-size: 0.8em; | |
margin-left: 10px; | |
} | |
svg { | |
font: 9px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #919191; | |
shape-rendering: crispEdges; | |
} | |
#panel #file-list {overflow-x: hidden;} | |
/* | |
.x.axis path { | |
display: none; | |
} | |
*/ | |
.background{ | |
visibility: visible !important; | |
fill: #FFFFFF; | |
} | |
.extent { | |
visibility: visible !important; | |
fill: #84D8F8; | |
} | |
.resize rect { | |
visibility: visible !important; | |
fill: #888888; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment