// Predatory For-Profits; 12-11-2017; Harrison James Cramer
var widthratio = 650
var heightratio = 850
var pickerCounter = 0;
var zoomExtent = d3.zoom().scaleExtent([1,20]);
var svg = d3.select("body")
.style("margin-top","0px")
.append("div")
.attr("id", "svgContainer")
.style("max-width", 750 + "px")
.style("margin", "0 auto")
.style("display", "block")
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox",`0 0 ${widthratio} ${heightratio}`)
.classed("svg-content-responsive", true)
.style("background-color","lightgrey")
.call(zoomExtent
.on("zoom", zoom))
.on("wheel.zoom", null)
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
d3.select("#svgContainer").style("max-width", "10000px")
}
function zoom() {
g.attr("transform", d3.event.transform);
}
var g = svg.append("g");
svg.append("g").append("svg:image")
.attr("x",30)
.attr("y",225)
.attr("width",30)
.attr("height",30)
.attr("xlink:href","https://s3.amazonaws.com/aws-website-ngivisualization-md5xp/reseticon.png")
.on("mouseover",function(){ d3.select(this).style("opacity",.5)})
.on("mouseleave",function(){ d3.select(this).style("opacity",1)})
.on("click", function(){
location.reload()})
var circleChart = d3.select("svg").append("g")
.attr("class","circleChart")
.attr("transform","translate(100,375)")
function allData(){
var colorScale = d3.scaleOrdinal().range(["#6845A4","#EC6077","#B84AA7","#F0914C","#5176D7"]);
d3.tsv("https://s3.amazonaws.com/aws-website-ngivisualization-md5xp/bdreportdata2.txt", data => {
var sampleData = [];
// Conglomerate Data
data.forEach(function(d,i){
if(data[i+1]){
var next = data[i+1]
var current = data[i]
if((current.Institution != "") && (current.Institution === next.Institution)){
next.Claims = parseInt(next.Claims) + parseInt(current.Claims)
}
else{
sampleData.push(d)
}
}
})
// Set up forces
var collision = d3.forceCollide().radius(function(d){
var radius = Math.sqrt((d.Claims)/Math.PI)
return radius + .5
}).strength(1.5)
var forceX = d3.forceX().x(function(d){
if((d.Type == "For-Profit")&&(d.Claims<50))
{return widthratio/2 + 50}
else
{return widthratio/2}
}).strength(1)
var forceY = d3.forceY().y(function(d){
if(d.Type == "International"){ return 150}
if(d.Type == "Public"){return 200}
if((d.Type == "For-Profit")&& (d.Claims<50)){return 675}
if((d.Type == "For-Profit")&& (d.Claims>=50)){return 545}
else{ return 250}
}).strength(1.08)
// Set up simulation
var simulation = d3.forceSimulation(sampleData)
.force("collision", collision)
.force("charge", d3.forceManyBody().strength(-5))
.force("x", forceX)
.force("y", forceY)
.on("tick", updateNetwork)
.alphaDecay(.2)
.alphaMin(.0000000001)
// Update network function
function updateNetwork() {
u.attr("cx", function(d){ return d.x})
.attr("cy", function(d){ return d.y})
}
// DRAW THE CIRCLES
var u = d3.select("svg").select("g")
.selectAll("circle").data(sampleData).enter().append("circle")
.style("fill", (d,i) => colorScale(d.Type))
.attr("r", function(d){
var radius
if(Math.sqrt((d.Claims)/Math.PI) > 1){
radius = Math.sqrt((d.Claims)/Math.PI)
}
else { radius = 1}
return radius
})
.attr("id",(d,i) => "circle" + i)
// Data Tooltip + Zoom
d3.selectAll("circle").on("mouseover", showData)
function showData(d,i) {
clearInterval(interval)
let toolTip = d3.select("#toolTip")
let typeInfo = toolTip.select(".type")
let institutionInfo = toolTip.select(".institution")
let corporationInfo = toolTip.select(".corporation")
let claimsInfo = toolTip.select(".claims")
let institutionData = d.Institution.replace(/\b./g, function(m){ return m.toUpperCase(); });
typeInfo.html("Type: " + d.Type)
institutionInfo.html("Institution: " + institutionData)
corporationInfo.html("Corporation: " + `${d.Corporation ? d.Corporation : "N/A"}`)
claimsInfo.html("BD Claims: " + d.Claims)
d3.selectAll("circle").filter(b => ((b.Corporation == d.Corporation)&&(b.Corporation != ""))).style("fill","lightyellow")
d3.select(this)
.transition()
.attr("r", function(){
var newRadius = Math.sqrt((d.Claims)/Math.PI) + 4
return newRadius
})
.style("fill","yellow")
toolTip.transition().style("opacity", 1)
this.parentNode.appendChild(this)
toolTip.style("left",d3.event.clientX + 20 + "px")
toolTip.style("top",d3.event.clientY + 20 + "px")
let Ratio = parseInt(svg.style("width").substr(0,3))/750
toolTip.style("width", 200*Ratio + "px")
toolTip.style("font-size", 12*Ratio + "px")
toolTip.style("padding", 10*Ratio + "px")
createPie(d);
}
d3.selectAll("circle").on("mouseleave", hideData)
function hideData(d) {
d3.select("#toolTip")
.transition().style("opacity",0)
d3.select(this)
.transition()
.attr("r", function(){
var radius
if(Math.sqrt((d.Claims)/Math.PI) > 1){
radius = Math.sqrt((d.Claims)/Math.PI)
}
else { radius = 1}
return radius
})
.style("fill", d => colorScale(d.Type))
d3.selectAll("circle").style("fill", b => colorScale(b.Type))
}
// Legend
var ordinal = d3.scaleOrdinal()
.domain(["International", "Public", "Nonprofit", "Nonprofit (converted)", "For-profit"])
.range(["#5176D7","#F0914C","#EC6077","#B84AA7","#6845A4"]);
var svg = d3.select("svg");
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(20,20)");
var legendOrdinal = d3.legendColor()
.shape("path", d3.symbol().type(d3.symbolCircle).size(20)())
.shapePadding(10)
.scale(ordinal)
.title("Institution Type")
.labelOffset(10)
svg.select(".legendOrdinal")
.call(legendOrdinal)
.style("font-family","Open Sans, sans-serif")
.style("font-size",".75em")
.attr("transform","translate(40,100)")
d3.select(".legendTitle")
.attr("transform","translate(-5,5)")
.style("font-size","1.2em")
svg.append("g").classed("info",true)
.append("text")
.text("*double click to zoom")
.style("font-style","strong")
.style("font-family","Open Sans, sans-serif")
.style("font-size",".6em")
.attr("transform","translate(40,205)")
svg.append("g").classed("info",true)
.append("text")
.text("**drag to move")
.style("font-style","strong")
.style("font-family","Open Sans, sans-serif")
.style("font-size",".6em")
.attr("transform","translate(40,220)")// TITLE
svg.append("g").classed("info",true)
.append("text")
.text("Borrower Defense Claims")
.style("font-style","strong")
.style("font-family","Open Sans, sans-serif")
.style("font-size","x-large")
.attr("transform",`translate(${widthratio/2},50)`)
.style("text-anchor","middle")
.style("font-variant","small-caps")
});
var interval
function randomPicker() {
interval = window.setInterval(function(){
let circleTarget = Math.round(Math.random() * (49 - 1) + 1)
var circle = d3.select("#circle" + circleTarget)
var newdata = circle._groups["0"]["0"].__data__
circle._groups["0"]["0"].parentNode.appendChild(circle._groups["0"]["0"])
let leftMarg = document.getElementById("svgContainer").getBoundingClientRect().left;
Ratio = parseInt(svg.style("width").substr(0,3))/750
let xCoord = circle.attr("cx")
let yCoord = circle.attr("cy")
d3.selectAll("circle")
.filter(b => (b.Corporation == newdata.Corporation))
.transition()
.style("fill","lightyellow")
.transition()
.delay(2500)
.style("fill", b => colorScale(b.Type))
circle
.transition()
.style("fill","yellow")
.attr("r", function(){
if(Math.sqrt((newdata.Claims)/Math.PI) > 1){
radius = Math.sqrt((newdata.Claims)/Math.PI) + 4
}
else { radius = 3}
return radius
})
.transition()
.delay(2500)
.style("fill", colorScale(newdata.Type))
.attr("r", function(){
if(Math.sqrt((newdata.Claims)/Math.PI) > 1){
radius = Math.sqrt((newdata.Claims)/Math.PI)
}
else { radius = 1}
return radius
})
let toolTip = d3.select("#toolTip")
.style("color","white")
.style("width", 200*Ratio + "px")
.style("font-size", 12*Ratio + "px")
let typeInfo = toolTip.select(".type")
let institutionInfo = toolTip.select(".institution")
let corporationInfo = toolTip.select(".corporation")
let claimsInfo = toolTip.select(".claims")
let institutionData = newdata.Institution.toLowerCase().replace(/\b./g, function(m){ return m.toUpperCase(); });
typeInfo.html("Type: " + newdata.Type)
institutionInfo.html("Institution: " + institutionData)
corporationInfo.html("Corporation: " + `${newdata.Corporation ? newdata.Corporation : "N/A"}`)
claimsInfo.html("BD Claims: " + newdata.Claims)
toolTip.transition().style("opacity", 1)
toolTip.style("left", (parseInt(xCoord)*Ratio) + leftMarg + 75*Ratio + "px")
toolTip.style("top", parseInt(yCoord)*Ratio + "px")
toolTip.style("padding", 10*Ratio + "px")
createPie(newdata);
}, 2500)}
randomPicker();
var total = 98864
function createPie(d) {
d3.select(".circleLabel").remove();
d3.select(".circleTitle").remove();
svg.append("g")
.append("text")
.classed("circleTitle",true)
.style("font-style","strong")
.style("font-family","Open Sans, sans-serif")
.style("font-size","x-large")
.attr("transform",`translate(35,300)`)
.style("text-anchor","start")
.style("font-size","12px")
.style("width","100px")
.style("text-align","center")
svg.append("g")
.append("text")
.classed("circleLabel",true)
.style("font-style","strong")
.style("font-family","Open Sans, sans-serif")
.style("font-size","x-large")
.attr("transform",`translate(35,460)`)
.style("text-anchor","start")
.style("font-size","12px")
.style("width","100px")
.style("text-align","center")
if(d.Corporation != ""){
d3.selectAll("circle")
d3.select(".circleTitle").text(() => d.Corporation ? d.Corporation : d.Institution)
var pieColors = d3.scaleOrdinal().range(["yellow",colorScale(d.Type)])
let corporation = d.Corporation
let institution = d.Institution
let type = d.Type
var allClaims = [parseInt(d.Claims)]
d3.selectAll("circle").filter(b => b.Corporation == corporation).each(function(b){
if((b.Corporation != "")&&(b.Institution != d.Institution)){
allClaims.push(parseInt(b.Claims))
}
})
var total = allClaims.reduce(function(a,b){return parseInt(a)+parseInt(b)})
d3.select(".circleLabel").text(() => total + " borrower defense claims.")
var percent = (d.Claims/total * 100).toFixed(2)
var pieChart = d3.pie()
var myPie = pieChart(allClaims);
var newArc = d3.arc()
.innerRadius(10)
.outerRadius(60)
d3.select(".circleChart")
.selectAll("path")
.remove()
d3.select(".circleChart")
.selectAll("path")
.data(myPie)
.enter()
.append("path")
.attr("d", d => newArc(d))
.attr("fill", function(b,i){if (i==0){return "yellow"}else{return "lightyellow"}})
.style("stroke","black")
.style("stroke-width",.5)
}
else{
d3.select(".circleLabel").html("")
d3.select(".circleTitle").html("");
d3.select(".circleChart")
.selectAll("path")
.remove()
}
}
};
allData();