// 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();