User can see a Force-directed Graph that shows which campers are posting links on Camper News to which domains. User can see each camper's icon on their node. User can see the relationship between the campers and the domains they're posting. User can tell approximately many times campers have linked to a specific domain from it's node size. User can tell approximately how many times a specific camper has posted a link from their node's size.
Last active
November 25, 2017 18:59
-
-
Save rfprod/c78d21f223e0453527a1 to your computer and use it in GitHub Desktop.
Data Visualization with Force Directed Chart
This file contains hidden or 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
<div class="container-fluid nopadding"> | |
<nav class="navbar navbar-inverse navbar-fixed-top topnav" role="navigation"> | |
<div class="navbar-header"> | |
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#toggle-nav" aria-expanded="false"> | |
<span class="sr-only">Toggle navigation</span> | |
<span class="icon-bar"></span> | |
<span class="icon-bar"></span> | |
<span class="icon-bar"></span> | |
</button> | |
<a class="navbar-brand font-effect-neon" target=_blank href="http://codepen.io/rfprod"><span class="glyphicon glyphicon-wrench"></span> RFProd</a> | |
</div> | |
<div class="collapse navbar-collapse" id="toggle-nav"> | |
<div class="container-fluid"> | |
<ul class="nav navbar-nav navbar-right font-effect-emboss"> | |
<li class="nav-tabs"><a href="#approot"><span class="glyphicon glyphicon-stats"></span> Data Visualization with Force Directed Chart</a></li> | |
<li class="nav-tabs"><a href="https://gist.github.com/rfprod/c78d21f223e0453527a1" target=_blank><span class="glyphicon glyphicon-download-alt" ></span> GIST</a></li> | |
</ul> | |
</div> | |
</div> | |
</nav> | |
<a name="approot"></a> | |
<div class="home sect"> | |
<div class="container-fluid"> | |
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12"> | |
<h2 class="hidden-md hidden-lg hidden-xl"><span class="glyphicon glyphicon-stats"></span> Data Visualization with Force Directed Chart</h2> | |
<div id="output"> | |
Output | |
</div> | |
<span class="credits">info <a href="https://d3js.org/" target=_blank>D3.js</a> | <a href="https://www.freecodecamp.com/news/hot" target=_blank>data</a> <br/>licence <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target=_blank>GPL 3.0</a></span> | |
</div> | |
</div> | |
</div> | |
</div> |
This file contains hidden or 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
$(document).on('ready',function(){ | |
(function (){ | |
var UserInstructionsAndGDPChart = React.createClass({ | |
render: function(){ | |
return ( | |
<span> | |
<p id="user-instructions">Camper News Network visualization using D3.js.</p> | |
<div id="map"></div> | |
</span> | |
); | |
} | |
}); | |
ReactDOM.render(<UserInstructionsAndGDPChart />,document.getElementById('output')); | |
var chartContainerObj = d3.select('#map'); | |
/* | |
* DEPRECATED endpoint | |
*/ | |
// $.getJSON('https://www.freecodecamp.com/news/hot', function(json){ | |
const mockDeprecatedAPI = (dummyUrl, callback) => callback([ | |
{ | |
id: '1', | |
link: 'https://www.domain1.dummy/link1', | |
author: { | |
username: 'username 1', | |
picture: 'https://image.flaticon.com/icons/svg/145/145867.svg', | |
userId: '1' | |
} | |
}, | |
{ | |
id: '2', | |
link: 'https://www.domain2.dummy/link2', | |
author: { | |
username: 'username 2', | |
picture: 'https://image.flaticon.com/icons/svg/145/145852.svg', | |
userId: '2' | |
} | |
}, | |
{ | |
id: '3', | |
link: 'https://www.domain3.dummy/link3', | |
author: { | |
username: 'username 3', | |
picture: 'https://image.flaticon.com/icons/svg/145/145859.svg', | |
userId: '3' | |
} | |
}, | |
{ | |
id: '4', | |
link: 'https://www.domain4.dummy/link2', | |
author: { | |
username: 'username 4', | |
picture: 'https://image.flaticon.com/icons/svg/145/145862.svg', | |
userId: '4' | |
} | |
}, | |
{ | |
id: '5', | |
link: 'https://www.domain3.dummy/link3', | |
author: { | |
username: 'username 2', | |
picture: 'https://image.flaticon.com/icons/svg/145/145852.svg', | |
userId: '2' | |
} | |
} | |
]); | |
mockDeprecatedAPI('https://www.freecodecamp.com/news/hot', (json) => { | |
//console.log(json[0].id); | |
//console.log(json[0].link); | |
//console.log(json[0].author.picture); | |
//console.log(json[0].author.userId); | |
var domains = [], uniqueDomCounter = 0, domainArrCheckDupl = []; | |
var users = [], uniqueUsrsCounter = 0, usersArrCheckDupl = []; | |
var links = []; | |
for (var i=0;i<json.length;i++){ | |
var domain = '', domainValue = 1; | |
var domArr = json[i].link.split('/'); | |
if (json[i].link.indexOf('://') != -1) domain = domArr[2]; | |
else domain = domArr[0]; | |
if (domain.indexOf('www.') != -1) domain = domain.substr(4,domain.length); | |
var domId = domainArrCheckDupl.indexOf(domain); | |
var tempDomIndex = 0; | |
if (domId != -1) { | |
domains[domId].value++; | |
tempDomIndex = domId; | |
} | |
else{ | |
domainArrCheckDupl.push(domain); | |
domains.push({'index':uniqueDomCounter,'domain':domain,'value':domainValue}); | |
tempDomIndex = uniqueDomCounter; | |
uniqueDomCounter++; | |
} | |
var usrId = usersArrCheckDupl.indexOf(json[i].author.username); | |
if (usrId != -1) { | |
users[usrId].linksCount++; | |
links.push({'source':users[usrId].index,'target':tempDomIndex}); | |
}else{ | |
usersArrCheckDupl.push(json[i].author.username); users.push({'index':uniqueUsrsCounter,'username':json[i].author.username,'pic':json[i].author.picture,'linksCount':1}); | |
links.push({'source':uniqueUsrsCounter,'target':tempDomIndex}); | |
uniqueUsrsCounter++; | |
} | |
} | |
//console.log(JSON.stringify(domains)); | |
//console.log(JSON.stringify(users)); | |
//console.log(JSON.stringify(links)); | |
var nodes = []; | |
for (var i=0;i<domains.length;i++) { | |
nodes.push(domains[i]); | |
} | |
for (var i=0;i<users.length;i++) { | |
for (var l=0;l<links.length;l++){ | |
if (links[l].source == users[i].index) links[l].source = domains.length+i; | |
} | |
users[i].index = domains.length+i; | |
nodes.push(users[i]); | |
} | |
console.log(JSON.stringify(nodes)); | |
console.log(JSON.stringify(links)); | |
var k = 0, windowWidth = $(window).width(); | |
if (windowWidth < 1000) k = windowWidth/500; | |
else k = windowWidth/500; | |
var width = $('#map').width()-75*k, height = 400; | |
var restHeight = $(window).height() - $('nav').height()*2 - $('.home').find('h2').height() - $('#user-instructions').height() - $('.credits').height()*2; | |
//console.log('restHeight: '+restHeight); | |
height = restHeight; | |
chartContainerObj.append('svg').attr('class','chart'); | |
var chartObj = d3.select('.chart').attr("width", width).attr("height", height); | |
chartObj.append('defs').selectAll('pattern').data(users).enter() | |
.append('pattern') | |
.attr('id', function(val,i){return 'img-'+val.index}) | |
.attr('x',0) | |
.attr('y',0) | |
.attr('height',function(val){ | |
if (typeof val.value == 'undefined') return 30+val.linksCount*2; | |
}) | |
.attr('width',function(val){ | |
if (typeof val.value == 'undefined') return 30+val.linksCount*2; | |
}) | |
.append('image') | |
.attr('x',0) | |
.attr('y',0) | |
.attr('height',function(val){ | |
if (typeof val.value == 'undefined') return 30+val.linksCount*2; | |
}) | |
.attr('width',function(val){ | |
if (typeof val.value == 'undefined') return 30+val.linksCount*2; | |
}) | |
.attr('xlink:href', function(val){return val.pic}); | |
var color = d3.scale.category20(); | |
var force = d3.layout.force() | |
.charge(-130) | |
.friction(0.95) | |
.linkDistance(90) | |
.theta(0.9) | |
.size([width,height]); | |
var div = d3.select("body").append("div").attr("class", "tooltip").style("opacity", 0); | |
var tooltip = d3.select('.tooltip'); | |
var xCursorPosition = 0, yCursorPosition = 0; | |
force.nodes(nodes).links(links).start(); | |
var link = chartObj.selectAll('.link').data(links) | |
.enter().append('line') | |
.attr('class','link') | |
.style('stroke-width', 5); | |
var node = chartObj.selectAll('.node').data(nodes) | |
.enter().append('circle') | |
.attr('class','node') | |
.attr('r', function(val,i){ | |
if (typeof val.value != 'undefined') return val.value*3; | |
else return 15+val.linksCount*1.001; | |
}) | |
.style('stroke-width', function(val){ | |
if (typeof val.value == 'undefined') return 1.5; | |
else return 2+val.linksCount*1.01; | |
}) | |
.style('fill', function(val){ | |
if (typeof val.value != 'undefined') return '#ff0000'; | |
else return 'url(#img-'+val.index+')'; | |
}) | |
.call(force.drag); | |
node.append("title") | |
.text(function(val) { | |
if (typeof val.domain != 'undefined') return val.domain; | |
else return val.username; | |
}); | |
force.on("tick", function() { | |
link.attr("x1", function(d) {return d.source.x;}) | |
.attr("y1", function(d) {return d.source.y;}) | |
.attr("x2", function(d) {return d.target.x;}) | |
.attr("y2", function(d) {return d.target.y;}); | |
node.attr("cx", function(d) {return d.x;}) | |
.attr("cy", function(d) {return d.y;}); | |
}); | |
}); | |
})(); | |
}); |
This file contains hidden or 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
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script> | |
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | |
<script src="https://d3js.org/d3.v3.min.js"></script> |
This file contains hidden or 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
$black: #000000 | |
$white: #ffffff | |
$grey: #bfbfbf | |
$blue: #3366cc | |
$green: #33cc33 | |
$darkblue1: #000066 | |
$darkblue2: #0000ff | |
$lightyellow: #ffff99 | |
$yellow: #ffff00 | |
$orange: #ff6600 | |
$red: #ff3300 | |
body | |
color: $black | |
font-family: 'Play', sans-serif | |
font-size: 2.2em | |
overflow-x:hidden | |
.tooltip | |
position: absolute | |
text-align: center | |
width: auto !important | |
height: auto !important | |
padding: 2px | |
font: 12px sans-serif | |
background: lightsteelblue | |
border: 0px | |
border-radius: 8px | |
pointer-events: none | |
.nopadding | |
padding: 0 | |
.navbar-brand | |
font-size: 1em | |
.home | |
min-height: 92vh | |
height: auto !important | |
.sect | |
padding-top: 8vh | |
.githublogo | |
height: 1em | |
h2 | |
text-align: center | |
font-weight: bold | |
#output | |
text-align: center | |
width: 100% | |
height: auto !important | |
#user-instructions | |
text-align: center | |
font-size: 0.75em | |
margin-top: 1em | |
#map | |
display: block | |
background-color: $grey | |
padding-top: 1em | |
padding-left: 1em | |
.chart | |
width: 97% | |
.node | |
stroke: #fff | |
stroke-width: 1.5px | |
.link | |
stroke: #999 | |
stroke-opacity: 0.6 | |
.hidden | |
display: none | |
a | |
text-decoration: none | |
.credits | |
display: block | |
text-align: center | |
font-size: 0.75em | |
a:hover | |
text-decoration: none |
This file contains hidden or 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
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="//cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.3/animate.min.css" rel="stylesheet" /> | |
<link href="https://fonts.googleapis.com/css?family=Play&effect=neon" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment