273 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| $(document).ready(function () {
 | |
|   var bootcamps = ''
 | |
|   $.getJSON('/json/bootcamps.json', function(data) {
 | |
|     bootcamps = data;
 | |
|   });
 | |
|   var city = "";
 | |
|   $("body").data("state", "stacked");
 | |
|   $('#city-buttons').on("click", "button", function () {
 | |
|     $(this).addClass('animated pulse');
 | |
|     city = $(this).attr("id");
 | |
|     $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
 | |
|         return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
 | |
|       }) + ', and making $_______, your true costs will be:');
 | |
|     setTimeout(function () {
 | |
|       $('#city-buttons').hide();
 | |
|       $('#income').addClass('animated fadeIn').show();
 | |
|     }, 1000);
 | |
|   });
 | |
|   $('#income').on("click", "button", function () {
 | |
|     $(this).addClass('animated pulse');
 | |
|     setTimeout(function () {
 | |
|       $('#income').hide();
 | |
|       $('#chart').addClass('animated fadeIn').show();
 | |
|       $('#chart-controls').addClass('animated fadeIn').show();
 | |
|       $('#explanation').addClass('animated fadeIn').show();
 | |
|     }, 1000);
 | |
|     var lastYearsIncome = parseInt($(this).attr("id"));
 | |
|     $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) {
 | |
|         return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
 | |
|       }) + ', and making $' + lastYearsIncome.toString().replace(/0000$/, '0,000') + ', your true costs will be:');
 | |
|     var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Est. Wage Garnishing'];
 | |
|     bootcamps.forEach(function (camp) {
 | |
|       var x0 = 0;
 | |
|       if (camp.cities.indexOf(city) > -1) {
 | |
|         weeklyHousing = 0;
 | |
|       } else {
 | |
|         weeklyHousing = +camp.housing;
 | |
|       }
 | |
|       camp.mapping = [{
 | |
|         name: camp.name,
 | |
|         label: 'Tuition / Est. Wage Garnishing',
 | |
|         value: +camp.cost,
 | |
|         x0: x0,
 | |
|         x1: x0 += +camp.cost
 | |
|       }, {
 | |
|         name: camp.name,
 | |
|         label: 'Financing Cost',
 | |
|         value: +Math.floor(camp.cost * .09519),
 | |
|         x0: +camp.cost,
 | |
|         x1: camp.finance ? x0 += +Math.floor(camp.cost * .09519) : 0
 | |
|       }, {
 | |
|         name: camp.name,
 | |
|         label: 'Housing Cost',
 | |
|         value: +weeklyHousing * camp.weeks,
 | |
|         x0: camp.finance ? +Math.floor(camp.cost * 1.09519) : camp.cost,
 | |
|         x1: x0 += weeklyHousing * camp.weeks
 | |
|       }, {
 | |
|         name: camp.name,
 | |
|         label: 'Lost Wages',
 | |
|         value: +(Math.floor(camp.weeks * lastYearsIncome / 50)),
 | |
|         x0: camp.finance ? +(Math.floor(camp.cost * 1.09519) + weeklyHousing * camp.weeks) : +camp.cost + weeklyHousing * camp.weeks,
 | |
|         x1: x0 += +(Math.floor(camp.weeks * lastYearsIncome / 50))
 | |
|       }];
 | |
|       camp.total = camp.mapping[camp.mapping.length - 1].x1;
 | |
|     });
 | |
|     bootcamps.sort(function (a, b) {
 | |
|       return a.total - b.total;
 | |
|     });
 | |
|     maxValue = 0;
 | |
|     bootcamps.forEach(function (camp) {
 | |
|       camp.mapping.forEach(function (elem) {
 | |
|         if (elem.value > maxValue) {
 | |
|           maxValue = elem.value;
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|     var xStackMax = d3.max(bootcamps, function (d) {
 | |
|         return d.total;
 | |
|       }), //Scale for Stacked
 | |
|       xGroupMax = bootcamps.map(function (camp) {
 | |
|         return camp.mapping.reduce(function (a, b) {
 | |
|           return a.value > b.value ? a.value : b.value;
 | |
|         });
 | |
|       }).reduce(function (a, b) {
 | |
|         return a > b ? a : b;
 | |
|       });
 | |
|     var margin = {
 | |
|         top: 30,
 | |
|         right: 60,
 | |
|         bottom: 50,
 | |
|         left: 140
 | |
|       },
 | |
|       width = 800 - margin.left - margin.right,
 | |
|       height = 1200 - margin.top - margin.bottom;
 | |
|     var barHeight = 20;
 | |
|     var xScale = d3.scale.linear()
 | |
|       .domain([0, xStackMax])
 | |
|       .rangeRound([0, width]);
 | |
|     var y0Scale = d3.scale.ordinal()
 | |
|       .domain(bootcamps.map(function (d) {
 | |
|         return d.name;
 | |
|       }))
 | |
|       .rangeRoundBands([0, height], .1);
 | |
|     var y1Scale = d3.scale.ordinal()
 | |
|       .domain(categoryNames).rangeRoundBands([0, y0Scale.rangeBand()]);
 | |
|     var color = d3.scale.ordinal()
 | |
|       .range(["#215f1e", "#5f5c1e", "#1e215f", "#5c1e5f"])
 | |
|       .domain(categoryNames);
 | |
|     var svg = d3.select("svg")
 | |
|       .attr("width", width + margin.left + margin.right)
 | |
|       .attr("height", height + margin.top + margin.bottom)
 | |
|       .append("g")
 | |
|       .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
 | |
|     var selection = svg.selectAll(".series")
 | |
|       .data(bootcamps)
 | |
|       .enter().append("g")
 | |
|       .attr("class", "series")
 | |
|       .attr("transform", function (d) {
 | |
|         return "translate(0," + y0Scale(d.name) + ")";
 | |
|       });
 | |
|     var rect = selection.selectAll("rect")
 | |
|       .data(function (d) {
 | |
|         return d.mapping;
 | |
|       })
 | |
|       .enter().append("rect")
 | |
|       .attr("x", 0)
 | |
|       .attr("width", 0)
 | |
|       .attr("height", y0Scale.rangeBand())
 | |
|       .style("fill", function (d) {
 | |
|         return color(d.label);
 | |
|       })
 | |
|       .style("stroke", "white")
 | |
|       .on("mouseover", function (d) {
 | |
|         showPopover.call(this, d);
 | |
|       })
 | |
|       .on("mouseout", function (d) {
 | |
|         removePopovers();
 | |
|       });
 | |
|     rect.transition()
 | |
|       .delay(function (d, i) {
 | |
|         return i * 10;
 | |
|       })
 | |
|       .attr("x", function (d) {
 | |
|         return xScale(d.x0);
 | |
|       })
 | |
|       .attr("width", function (d) {
 | |
|         return xScale((d.x1) - (d.x0));
 | |
|       });
 | |
|     d3.selectAll("#transform").on("click", function () {
 | |
|       $('#transform').addClass('animated pulse');
 | |
|       change();
 | |
|       setTimeout(function () {
 | |
|         $('#transform').removeClass('animated pulse');
 | |
|       }, 1000);
 | |
|     });
 | |
| 
 | |
|     d3.selectAll("#chart").on("click", function () {
 | |
|       change();
 | |
|     });
 | |
| 
 | |
|     function change() {
 | |
|       if ($("body").data("state") === "stacked") {
 | |
|         transitionGrouped();
 | |
|         $("body").data("state", "grouped");
 | |
|       } else {
 | |
|         transitionStacked();
 | |
|         $("body").data("state", "stacked");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     function transitionGrouped() {
 | |
|       xScale.domain = ([0, xGroupMax]);
 | |
|       rect.transition()
 | |
|         .duration(500)
 | |
|         .delay(function (d, i) {
 | |
|           return i * 10;
 | |
|         })
 | |
|         .attr("width", function (d) {
 | |
|           return xScale((d.x1) - (d.x0));
 | |
|         })
 | |
|         .transition()
 | |
|         .attr("y", function (d) {
 | |
|           return y1Scale(d.label);
 | |
|         })
 | |
|         .attr("x", 0)
 | |
|         .attr("height", y1Scale.rangeBand());
 | |
|     }
 | |
| 
 | |
|     function transitionStacked() {
 | |
|       xScale.domain = ([0, xStackMax]);
 | |
|       rect.transition()
 | |
|         .duration(500)
 | |
|         .delay(function (d, i) {
 | |
|           return i * 10;
 | |
|         })
 | |
|         .attr("x", function (d) {
 | |
|           return xScale(d.x0);
 | |
|         })
 | |
|         .transition()
 | |
|         .attr("y", function (d) {
 | |
|           return y0Scale(d.label);
 | |
|         })
 | |
|         .attr("height", y0Scale.rangeBand());
 | |
|     }
 | |
| 
 | |
|     //axes
 | |
|     var xAxis = d3.svg.axis()
 | |
|       .scale(xScale)
 | |
|       .orient("bottom");
 | |
|     var yAxis = d3.svg.axis()
 | |
|       .scale(y0Scale)
 | |
|       .orient("left");
 | |
|     svg.append("g")
 | |
|       .attr("class", "y axis")
 | |
|       .call(yAxis);
 | |
|     svg.append("g")
 | |
|       .attr("class", "x axis")
 | |
|       .attr("transform", "translate(0," + height + ")")
 | |
|       .call(xAxis)
 | |
|       .append("text")
 | |
|       .attr("x", 300)
 | |
|       .attr("y", 35)
 | |
|       .attr("dy", ".35em")
 | |
|       .style("text-anchor", "middle")
 | |
|       .text("Cost in $USD");
 | |
|     //tooltips
 | |
|     function removePopovers() {
 | |
|       $('.popover').each(function () {
 | |
|         $(this).remove();
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     function showPopover(d) {
 | |
|       $(this).popover({
 | |
|         title: d.name,
 | |
|         placement: 'auto top',
 | |
|         container: 'body',
 | |
|         trigger: 'manual',
 | |
|         html: true,
 | |
|         content: function () {
 | |
|           return d.label +
 | |
|             "<br/>$" +
 | |
|             d3.format(",")(d.value ? d.value : d.x1 - d.x0);
 | |
|         }
 | |
|       });
 | |
|       $(this).popover('show');
 | |
|     }
 | |
| 
 | |
|     //legends
 | |
|     var legend = svg.selectAll(".legend")
 | |
|       .data(categoryNames.slice().reverse())
 | |
|       .enter().append("g")
 | |
|       .attr("class", "legend")
 | |
|       .attr("transform", function (d, i) {
 | |
|         return "translate(30," + i * y0Scale.rangeBand() * 1.1 + ")";
 | |
|       });
 | |
|     legend.append("rect")
 | |
|       .attr("x", width - y0Scale.rangeBand())
 | |
|       .attr("width", y0Scale.rangeBand())
 | |
|       .attr("height", y0Scale.rangeBand())
 | |
|       .style("fill", color)
 | |
|       .style("stroke", "white");
 | |
|     legend.append("text")
 | |
|       .attr("x", width - y0Scale.rangeBand() * 1.2)
 | |
|       .attr("y", 12)
 | |
|       .attr("dy", ".35em")
 | |
|       .style("text-anchor", "end")
 | |
|       .text(function (d) {
 | |
|         return d;
 | |
|       });
 | |
|   });
 | |
| });
 |