[ Launch: force-bubble-1 ] a3ae3755c4a61dbd7e2b by jdutta
[ Launch: diagonal-test-1 ] e52929a90ea8b7a25bbd by jdutta
[ Launch: quick-chart-vert ] 2c8553335067321f44a4 by jdutta
[ Launch: quick-chart-1 ] 99181b7e0eb393be4380 by jdutta
[ Launch: scratchpad ] 9721189 by jdutta
-
-
Save jdutta/a3ae3755c4a61dbd7e2b to your computer and use it in GitHub Desktop.
people-projects
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":"people-projects","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"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},"s_action.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"inlet.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"c_ip.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"chart_data.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"foo.csv":{"default":true,"vim":false,"emacs":false,"fontSize":12},"foo2.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"data.json":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"ajax-caching":true,"thumbnail":"http://i.imgur.com/17M6lV0.png"} |
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
{ | |
"categoriesMap": { | |
"project1": { | |
"name": "Project1" | |
}, | |
"project2": { | |
"name": "Project2" | |
}, | |
"project3": { | |
"name": "Project3" | |
}, | |
"project4": { | |
"name": "Project4" | |
} | |
}, | |
"locationsMap": { | |
"sfo": { | |
"name": "San Francisco" | |
}, | |
"sjc": { | |
"name": "San Jose" | |
} | |
}, | |
"people": [ | |
{ | |
"name": "Fname1 Lname1", | |
"cats": ["project1"], | |
"locid": "sjc", | |
"imgUrl": "" | |
}, | |
{ | |
"name": "Fname2 Lname2", | |
"cats": ["project3"], | |
"locid": "sjc", | |
"imgUrl": "" | |
}, | |
{ | |
"name": "Fname3 Lname3", | |
"cats": ["project1"], | |
"locid": "sfo", | |
"imgUrl": "" | |
}, | |
{ | |
"name": "Fname4 Lname4", | |
"cats": ["project4"], | |
"locid": "sfo", | |
"imgUrl": "" | |
}, | |
{ | |
"name": "Fname5 Lname5", | |
"cats": ["project2"], | |
"locid": "sjc", | |
"imgUrl": "" | |
}, | |
{ | |
"name": "Fname6 Lname6", | |
"cats": ["project1"], | |
"locid": "sfo", | |
"imgUrl": "" | |
} | |
] | |
} |
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
// Custom viz for people and projects | |
// Show projects in the middle and teams/people on either side | |
// Configurable params | |
// Click on the number and see a magic slider appears to tweak it. | |
var config = { | |
width: 700, | |
height: 600, | |
categoryRectWidth: 150, | |
categoryRectHeight: 30, | |
personRectWidth: 120, | |
personRectHeight: 20, | |
personRectGap: 25, | |
imageSize: 40, | |
paddingForImage: 50, | |
defaultImgUrl: 'https://assets3.assembla.com/assets/avatars/big/8-b25e82266d6568a6bcd262c5630fe562.png' | |
}; | |
var data = tributary.data; | |
function isLeftColPerson(p) { | |
return (p.locid === 'sjc'); | |
} | |
function processDataForViz(data, config) { | |
var catList = []; | |
Object.keys(data.categoriesMap).forEach(function (k, i) { | |
var cat = data.categoriesMap[k]; | |
cat.id = k; | |
cat.index = i; | |
cat.x = config.width / 2 - config.categoryRectWidth / 2; | |
cat.y = i * (config.categoryRectHeight + 5); | |
catList.push(cat); | |
}); | |
var locList = []; | |
Object.keys(data.locationsMap).forEach(function (k) { | |
var loc = data.locationsMap[k]; | |
loc.id = k; | |
locList.push(loc); | |
}); | |
var links = []; | |
var indexForLoc = {}; | |
data.people.forEach(function (p, i) { | |
p.index = i; | |
indexForLoc[p.locid] = indexForLoc[p.locid] || 0; | |
p.x = config.paddingForImage; | |
if (!isLeftColPerson(p)) { | |
p.x = config.width - config.personRectWidth - config.paddingForImage; | |
} | |
p.y = indexForLoc[p.locid] * (config.personRectHeight + config.personRectGap); | |
indexForLoc[p.locid]++; | |
p.cats.forEach(function (catId) { | |
var cat = data.categoriesMap[catId]; | |
// link connection points at the edge of person nodes (rectangles) | |
var source = { | |
index: p.index, | |
x: isLeftColPerson(p) ? p.x + config.personRectWidth : p.x, | |
y: p.y + config.personRectHeight / 2 | |
}; | |
var target = { | |
index: cat.index, | |
x: isLeftColPerson(p) ? cat.x : cat.x + config.categoryRectWidth, | |
y: cat.y + config.categoryRectHeight / 2 | |
}; | |
links.push({source: source, target: target}); | |
}); | |
}); | |
data.categoriesList = catList; | |
data.locationsList = locList; | |
data.links = links; | |
} | |
processDataForViz(data, config); | |
console.log(data); | |
visualize(data); | |
function visualize(data) { | |
var svg = d3.select('svg'); | |
var gRoot = svg.append('svg:g') | |
.attr('transform', 'translate(20, 100)'); | |
var diagonal = d3.svg.diagonal(); | |
var gCat = gRoot.selectAll('.category-node') | |
.data(data.categoriesList) | |
.enter() | |
.append('svg:g') | |
.attr('class', function (d) { | |
return 'category-node category-'+d.index; | |
}) | |
.attr('transform', function (d, i) { | |
return 'translate('+[d.x, d.y]+')'; | |
}) | |
.on('mouseenter', function (d) { | |
d3.select(this).classed('active', true); | |
d3.selectAll('path.link-to-' + d.index) | |
.classed('active', true) | |
.moveToFront(); | |
data.links.forEach(function (link) { | |
if (link.target.index === d.index) { | |
d3.select('.person-'+link.source.index).classed('active', true); | |
} | |
}); | |
}) | |
.on('mouseleave', function (d) { | |
d3.selectAll('.person-node').classed('active', false); | |
d3.selectAll('.category-node').classed('active', false); | |
d3.selectAll('path.link-to-' + d.index) | |
.classed('active', false) | |
.moveToFront(); | |
}); | |
gCat | |
.append('svg:rect') | |
.attr('width', config.categoryRectWidth) | |
.attr('height', config.categoryRectHeight); | |
gCat | |
.append('svg:text') | |
.attr('x', 5) | |
.attr('y', 16) | |
.text(function (d) { | |
return d.name; | |
}); | |
var gPerson = gRoot.selectAll('.person-node') | |
.data(data.people) | |
.enter() | |
.append('svg:g') | |
.attr('class', function (d) { | |
return 'person-node person-'+d.index; | |
}) | |
.attr('transform', function (d, i) { | |
return 'translate('+[d.x, d.y]+')'; | |
}) | |
.on('mouseenter', function (d) { | |
d3.select(this).classed('active', true); | |
d3.selectAll('path.link-from-' + d.index).classed('active', true); | |
data.links.forEach(function (link) { | |
if (link.source.index === d.index) { | |
d3.select('.category-'+link.target.index).classed('active', true); | |
} | |
}); | |
}) | |
.on('mouseleave', function (d) { | |
d3.selectAll('.person-node').classed('active', false); | |
d3.selectAll('.category-node').classed('active', false); | |
d3.selectAll('path.link-from-' + d.index).classed('active', false); | |
}); | |
gPerson | |
.append('svg:rect') | |
.attr('width', config.personRectWidth) | |
.attr('height', config.personRectHeight); | |
gPerson | |
.append('svg:text') | |
.attr('x', 5) | |
.attr('y', 11) | |
.text(function (d) { | |
return d.name; | |
}); | |
gPerson.append('svg:image') | |
.attr('xlink:href', function (d) { | |
return d.imgUrl || config.defaultImgUrl | |
}) | |
.attr('x', function (d) { | |
return isLeftColPerson(d) ? -config.imageSize - 3 : config.personRectWidth + 3; | |
}) | |
.attr('y', -(config.imageSize - config.personRectHeight)/2) | |
.attr('width', config.imageSize) | |
.attr('height', config.imageSize) | |
var gLink = gRoot.selectAll('.link') | |
.data(data.links) | |
.enter() | |
.append('svg:path') | |
.attr('d', diagonal) | |
.attr('class', function (d) { | |
return 'link link-from-' + d.source.index + ' link-to-' + d.target.index; | |
}); | |
} | |
d3.selection.prototype.moveToFront = function() { | |
return this.each(function() { | |
this.parentNode.appendChild(this); | |
}); | |
}; | |
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
text { | |
font-size: 12px; | |
alignment-baseline: middle; | |
} | |
g.category-node rect, | |
g.person-node rect { | |
stroke: #aaa; | |
stroke-opacity: 0.3; | |
fill: #eee; | |
} | |
g.category-node.active rect, | |
g.person-node.active rect, | |
path.link.active { | |
stroke: #1ca8dd; | |
stroke-opacity: 0.8; | |
stroke-width: 2; | |
} | |
path.link { | |
stroke: #aaa; | |
stroke-opacity: 0.3; | |
fill: none; | |
} | |
g.person-node image { | |
display: none; | |
} | |
g.person-node.active image { | |
display: block; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment