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;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 |