diff --git a/hw6/public/css/style.css b/hw6/public/css/style.css
index d1fc3cc..34691ba 100755
--- a/hw6/public/css/style.css
+++ b/hw6/public/css/style.css
@@ -113,7 +113,7 @@ h1 {
.selected{
stroke: #404040;;
stroke-width:4;
- r:25px;
+ r:15px;
}
diff --git a/hw6/public/js/electoralVoteChart.js b/hw6/public/js/electoralVoteChart.js
index 670cb8c..2262435 100644
--- a/hw6/public/js/electoralVoteChart.js
+++ b/hw6/public/js/electoralVoteChart.js
@@ -73,13 +73,230 @@ class ElectoralVoteChart {
//HINT: Use .electoralVotesNote class to style this text element
//HINT: Use the chooseClass method to style your elements based on party wherever necessary.
+ let electionArray = d3.nest()
+ .key(function(d) {return d["State_Winner"]} )
+ .sortValues(function(a,b) {
+ return parseFloat(a.RD_Difference) - parseFloat(b.RD_Difference)
+ })
+ .entries(electionResult)
- //******* TODO: PART V *******
- //Implement brush on the bar chart created above.
- //Implement a call back method to handle the brush end event.
- //Call the update method of shiftChart and pass the data corresponding to brush selection.
- //HINT: Use the .brush class to style the brush.
+ let statesIArray = [];
+ let statesRArray = [];
+ let statesDArray = [];
+ for(let i=0; i parseInt(d['Total_EV']))])
+ .range([0, self.svgWidth]);
+
+ let rectG = this.svg.select('g');
+
+ if(rectG.empty())
+ {
+ rectG = this.svg.append('g')
+ }
+
+ let statesRect = rectG.selectAll('rect')
+ .data(statesArray);
+
+ statesRect.exit().remove();
+ statesRect = statesRect.enter().append('rect').merge(statesRect);
+
+ let votesSeen = 0;
+
+ statesRect
+ .attr('x', function(d){
+ let x = self.xScale(votesSeen);
+ votesSeen = votesSeen + parseInt(d['Total_EV']);
+ return x;
+ })
+ .attr('y', 5*this.svgHeight/8)
+ .attr('width', function(d){
+ return self.xScale(d['Total_EV'])
+ })
+ .attr('height', this.svgHeight/4)
+ .attr('class', '')
+ .attr('fill', function(d){
+
+ if(d['State_Winner'] == 'I')
+ {
+ d3.select(this).attr('class', function(d){
+ return self.chooseClass(d["State_Winner"])
+ });
+ return;
+ }
+
+ return colorScale(d["RD_Difference"])
+ })
+ .attr('rd_diff', function(d){
+ return d["RD_Difference"];
+ })
+ .attr('state_winner', function(d){
+ return d["State_Winner"];
+ })
+ .attr('abbr', function(d){
+ return d["Abbreviation"];
+ })
+ .attr('stroke', '#ffffff')
+ .attr('stroke-width', 1)
+
+ //Display total count of electoral votes won by the Democrat and Republican party
+ //on top of the corresponding groups of bars.
+ //HINT: Use the .electoralVoteText class to style your text elements; Use this in combination with
+ // chooseClass to get a color based on the party wherever necessary
+
+ let textDEV = this.svg.selectAll('.electoralVoteText').filter('.democrat')
+ .data([d3.sum(statesDArray, d => parseInt(d['D_EV']))])
+
+ textDEV = textDEV.enter().append('text').merge(textDEV)
+
+ textDEV.classed('electoralVoteText', true)
+ .classed('democrat', true)
+ .attr('x', 0)
+ .attr('y', 5*this.svgHeight/8 - 10)
+ .attr('text-anchor', 'start')
+ .text(function(d){
+ return d;
+ })
+
+ let textIEV = this.svg.selectAll('.electoralVoteText').filter('.independent')
+ .data([d3.sum(statesIArray, d => parseInt(d['I_EV']))])
+
+ if(statesIArray.length != 0)
+ {
+ textDEV.attr('x', this.svgWidth/5).attr('text-anchor', 'end')
+
+ textIEV = textIEV.enter().append('text').merge(textIEV)
+
+ textIEV.classed('electoralVoteText', true)
+ .classed('independent', true)
+ .attr('x', 0)
+ .attr('y', 5*this.svgHeight/8 - 10)
+ .attr('text-anchor', 'start')
+ .text(function(d){
+ return d;
+ })
+ }
+ else
+ {
+ textIEV = textIEV.data([]);
+ textIEV.exit().remove();
+ textIEV.enter().merge(textIEV)
+ }
+
+ let textREV = this.svg.selectAll('.electoralVoteText').filter('.republican')
+ .data([d3.sum(statesRArray, d => parseInt(d['R_EV']))])
+
+ textREV = textREV.enter().append('text').merge(textREV)
+
+ textREV.classed('electoralVoteText', true)
+ .classed('republican', true)
+ .attr('x', this.svgWidth)
+ .attr('y', 5*this.svgHeight/8 - 10)
+ .attr('text-anchor', 'end')
+ .text(function(d){
+ return d;
+ })
+
+ //Display a bar with minimal width in the center of the bar chart to indicate the 50% mark
+ //HINT: Use .middlePoint class to style this bar.
+
+ let evLine = this.svg.selectAll('path');
+ if(evLine.empty())
+ {
+ var data = [[this.svgWidth/2, 5*this.svgHeight/8 - 5], [this.svgWidth/2, 5*this.svgHeight/8 + this.svgHeight/4 + 5]];
+
+ var lineGenerator = d3.line();
+ var pathString = lineGenerator(data);
+
+ this.svg.append('path')
+ .attr('d', pathString)
+ .attr('stroke-width', '2')
+ .attr('stroke', '#000')
+ }
+
+ //Just above this, display the text mentioning the total number of electoral votes required
+ // to win the elections throughout the country
+ //HINT: Use .electoralVotesNote class to style this text element
+
+ let evText = this.svg.selectAll('.electoralVotesNote')
+ .data([d3.sum(statesArray, d => parseInt(d['Total_EV']))])
+
+ evText = evText.enter().append('text').merge(evText)
+
+ evText.classed('electoralVotesNote', true)
+ .attr('x', this.svgWidth/2)
+ .attr('y', 5*this.svgHeight/8 - 15)
+ .text(function(d){
+ let ev = d/2;
+ return 'Electoral Vote (' + ev + ' needed to win)';
+ })
+
+
+ //HINT: Use the chooseClass method to style your elements based on party wherever necessary.
+
+ //******* TODO: PART V *******
+ //Implement brush on the bar chart created above.
+ //Implement a call back method to handle the brush end event.
+ //Call the update method of shiftChart and pass the data corresponding to brush selection.
+ //HINT: Use the .brush class to style the brush.
+
+ let brushed = function() {
+ var selection = d3.event.selection;
+
+ if(selection == null)
+ return;
+
+ let selectedStatesArray = new Array();
+
+ let selectedStates = statesRect.filter(function(d){
+ let currentRect = d3.select(this);
+ let x1 = parseInt(currentRect.attr('x'));
+ let x2 = x1 + parseInt(currentRect.attr('width'));
+ if(x1 > selection[0] && x2 < selection[1])
+ {
+ selectedStatesArray.push(d);
+ return true;
+ }
+ return false;
+ })
+
+ console.log(selection)
+ console.log(selectedStatesArray)
+
+ self.shiftChart.update(selectedStatesArray)
+
+ };
+
+ var brush = d3.brushX()
+ .extent([[0, 5*this.svgHeight/8 - 5], [this.svgWidth, 5*this.svgHeight/8 + this.svgHeight/4 + 5]])
+ .on("end", brushed);
+
+ rectG.append("g")
+ .attr("class", "brush")
+ .call(brush)
};
diff --git a/hw6/public/js/tileChart.js b/hw6/public/js/tileChart.js
index a73d1e1..beb10aa 100644
--- a/hw6/public/js/tileChart.js
+++ b/hw6/public/js/tileChart.js
@@ -77,7 +77,96 @@ class TileChart {
//Call the tool tip on hover over the tiles to display stateName, count of electoral votes
//then, vote percentage and number of votes won by each party.
//HINT: Use the .republican, .democrat and .independent classes to style your elements.
-
+
+ var self = this;
+
+ let statesG = this.svg.selectAll('g')
+ .data(electionResult);
+
+ statesG.exit().remove();
+ statesG = statesG.enter().append('g').merge(statesG);
+
+ let statesRect = statesG.selectAll('rect')
+ .data(function(d){
+ return d3.select(this).data()
+ });
+
+ //statesRect.exit().remove();
+ statesRect = statesRect.enter().append('rect').merge(statesRect);
+
+ statesRect
+ .attr('width', this.svgWidth/this.maxColumns)
+ .attr('height', this.svgHeight/this.maxRows)
+ .attr('x', function(d){
+ return (self.svgWidth/self.maxColumns)*(parseInt(d["Space"]))
+ })
+ .attr('y', function(d){
+ return (self.svgHeight/self.maxRows)*(parseInt(d["Row"]))
+ })
+ .attr('fill', function(d){
+ return colorScale(d["RD_Difference"])
+ })
+ .attr('space-row', function(d){
+ return d["Space"] + '-' + d["Row"];
+ })
+ .attr('stroke', '#ffffff')
+ .attr('stroke-width', 1)
+ .call(tip)
+ .on('mouseover', tip.show)
+ .on('mouseout', tip.hide)
+
+ let statesNameText = statesG.selectAll('text').filter('.stateName')
+ .data(function(d){
+ return d3.select(this).data()
+ });
+
+ //statesNameText.exit().remove();
+ statesNameText = statesNameText.enter().append('text').merge(statesNameText);
+
+ statesNameText
+ .attr('x', function(d){
+ let startX = (self.svgWidth/self.maxColumns)*(parseInt(d["Space"]))
+ return startX + (self.svgWidth/self.maxColumns)/2
+ })
+ .attr('y', function(d){
+ let startY = (self.svgHeight/self.maxRows)*(parseInt(d["Row"]))
+ return startY + (self.svgHeight/self.maxRows)/2
+
+ })
+ .attr('class', 'tilestext stateName')
+ .text(function(d){
+ return d["Abbreviation"]
+ })
+ .call(tip)
+ .on('mouseover', tip.show)
+ .on('mouseout', tip.hide)
+
+ let statesEVText = statesG.selectAll('text').filter('.stateEV')
+ .data(function(d){
+ return d3.select(this).data()
+ });
+
+ statesEVText.exit().remove();
+ statesEVText = statesEVText.enter().append('text').merge(statesEVText);
+
+ statesEVText
+ .attr('x', function(d){
+ let startX = (self.svgWidth/self.maxColumns)*(parseInt(d["Space"]))
+ return startX + (self.svgWidth/self.maxColumns)/2
+ })
+ .attr('y', function(d){
+ let startY = (self.svgHeight/self.maxRows)*(parseInt(d["Row"]))
+ return startY + (self.svgHeight/self.maxRows)/2 + 15;
+ })
+ .attr('class', 'tilestext stateEV')
+ .text(function(d){
+ return d["Total_EV"]
+ })
+ .call(tip)
+ .on('mouseover', tip.show)
+ .on('mouseout', tip.hide)
+
+
};
diff --git a/hw6/public/js/votePercentageChart.js b/hw6/public/js/votePercentageChart.js
index 995f9c7..5aec8c4 100644
--- a/hw6/public/js/votePercentageChart.js
+++ b/hw6/public/js/votePercentageChart.js
@@ -65,23 +65,156 @@ class VotePercentageChart {
//Create the stacked bar chart.
//Use the global color scale to color code the rectangles.
//HINT: Use .votesPercentage class to style your bars.
+ let self = this;
- //Display the total percentage of votes won by each party
- //on top of the corresponding groups of bars.
- //HINT: Use the .votesPercentageText class to style your text elements; Use this in combination with
- // chooseClass to get a color based on the party wherever necessary
+ electionResult[0].
+ let iPercent = parseFloat(electionResult[0].I_PopularPercentage === "" ? 0: electionResult[0].I_PopularPercentage);
+ let dPercent = parseFloat(electionResult[0].D_PopularPercentage);
+ let rPercent = parseFloat(electionResult[0].R_PopularPercentage);
+ let percentArray = [];
+ percentArray.push({party: "I", percent:iPercent, nominee: electionResult[0].I_Nominee_prop});
+ percentArray.push({party: "D", percent:dPercent, nominee: electionResult[0].D_Nominee_prop});
+ percentArray.push({party: "R", percent:rPercent, nominee: electionResult[0].R_Nominee_prop});
+ percentArray.forEach(function(d){
+ d.D_Nominee_prop= electionResult[0].D_Nominee_prop;
+ d.R_Nominee_prop= electionResult[0].R_Nominee_prop;
+ d.I_Nominee_prop= electionResult[0].I_Nominee_prop;
+ d.D_Votes = electionResult[0].D_Votes;
+ d.R_Votes = electionResult[0].R_Votes;
+ d.I_Votes = electionResult[0].I_Votes;
- //Display a bar with minimal width in the center of the bar chart to indicate the 50% mark
- //HINT: Use .middlePoint class to style this bar.
+ })
+ //for reference:https://github.com/Caged/d3-tip
+ //Use this tool tip element to handle any hover over the chart
+ let tip = d3.tip().attr('class', 'd3-tip')
+ .direction('s')
+ .offset(function() {
+ return [0,0];
+ })
+ .html((d)=> {
+ let tooltip_data = {
+ "result":[
+ {"nominee": d.D_Nominee_prop,"votecount": d.D_Votes,"percentage": dPercent,"party":"D"} ,
+ {"nominee": d.R_Nominee_prop,"votecount": d.R_Votes,"percentage": rPercent,"party":"R"} ,
+ {"nominee": d.I_Nominee_prop,"votecount": d.I_Votes,"percentage": iPercent,"party":"I"}
+ ]
+ };
+ return self.tooltip_render(tooltip_data);
+ });
- //Just above this, display the text mentioning details about this mark on top of this bar
- //HINT: Use .votesPercentageNote class to style this text element
- //Call the tool tip on hover over the bars to display stateName, count of electoral votes.
- //then, vote percentage and number of votes won by each party.
+ // ******* TODO: PART III *******
- //HINT: Use the chooseClass method to style your elements based on party wherever necessary.
+ //Create the stacked bar chart.
+ //Use the global color scale to color code the rectangles.
+ //HINT: Use .votesPercentage class to style your bars.
+ let xScale = d3.scaleLinear()
+ .domain([0, 100])
+ .range([0, this.svgWidth]);
+ let xPosition = [0];
+ percentArray.forEach(function(data){
+ if(xPosition.length!==0){
+ xPosition.push(xPosition[xPosition.length-1]+data.percent);
+ }
+ });
+ let rect = this.svg.selectAll(".votesPercentage").data(percentArray);
+ let newRect = rect.enter().append("rect");
+ rect.exit().remove();
+ rect = newRect.merge(rect);
+ rect.attr("x", function(d,i){
+ return xScale(xPosition[i]);
+ })
+ .attr("y", 150)
+ .attr("height", 20)
+ .attr("width", function(d, i){
+ return xScale(d.percent);
+ })
+ .attr("class", function(d, i){
+ return self.chooseClass(d.party);
+ })
+ .classed("votesPercentage", true);
+ //Display the total percentage of votes won by each party
+ //on top of the corresponding groups of bars.
+ //HINT: Use the .votesPercentageText class to style your text elements; Use this in combination with
+ // chooseClass to get a color based on the party wherever necessary
+ let text = this.svg.selectAll(".votesPercentageText").data(percentArray);
+ let newText = text.enter().append("text");
+ text.exit().remove();
+ text = newText.merge(text);
+ text.attr("x", function(d, i){
+ if(i===percentArray.length-1){
+ return xScale(xPosition[xPosition.length-1]);
+ } else {
+ return xScale(xPosition[i]);
+ }
+ })
+ .attr("y", 120)
+ .text(function(d, i){
+ return d.percent===0? "": d.percent+"%";
+ })
+ .attr("class", function(d,i){
+ return self.chooseClass(d.party);
+ })
+ .classed("votesPercentageText", true);
+
+ let nominees = this.svg.selectAll(".nomineeNames").data(percentArray);
+ let newNominees = nominees.enter().append("text");
+ nominees.exit().remove();
+ nominees = newNominees.merge(nominees);
+ nominees.attr("x", function(d, i){
+ if(i===percentArray.length-1){
+ return xScale(xPosition[xPosition.length-1]);
+ } else {
+ return xScale(xPosition[i]);
+ }
+ })
+ .attr("y", 80)
+ .text(function(d, i){
+ return d.nominee;
+ })
+ .attr("class", function(d,i){
+ return self.chooseClass(d.party);
+ })
+ .classed("votesPercentageText", true);
+
+ if(percentArray[0].percent!==0){
+ let dText = text.filter(function(d){
+ return d.party=== 'D';
+ });
+ dText.attr("transform", "translate(50, 0)");
+
+ let dNominee = nominees.filter(function(d){
+ return d.party=== 'D';
+ });
+ dNominee.attr("transform", "translate(180, 0)");
+ }
+
+ //Display a bar with minimal width in the center of the bar chart to indicate the 50% mark
+ //HINT: Use .middlePoint class to style this bar.
+ let midPosition = xScale(xPosition[xPosition.length-1]/2);
+ this.svg.selectAll(".middlePoint").remove();
+ this.svg.append("rect")
+ .attr("x", xScale(50))
+ .attr("y", 145)
+ .attr("height", 30)
+ .attr("width", 3)
+ .classed("middlePoint", true);
+
+ //Just above this, display the text mentioning details about this mark on top of this bar
+ //HINT: Use .votesPercentageNote class to style this text element
+ this.svg.selectAll(".votesPercentageNote").remove();
+ this.svg.append("text")
+ .attr("x", xScale(50))
+ .attr("y", 120)
+ .classed("votesPercentageNote", true)
+ .text("Popular Vote(50%)");
+
+ //Call the tool tip on hover over the bars to display stateName, count of electoral votes.
+ //then, vote percentage and number of votes won by each party.
+ this.svg.call(tip);
+ rect.on("mouseover", tip.show);
+ rect.on("mouseout", tip.hide);
};
diff --git a/hw6/public/js/yearChart.js b/hw6/public/js/yearChart.js
index 8613024..2bbd45c 100644
--- a/hw6/public/js/yearChart.js
+++ b/hw6/public/js/yearChart.js
@@ -69,7 +69,7 @@ class YearChart {
.domain(domain)
.range(range);
- // ******* TODO: PART I *******
+ // ******* DONE: PART I *******
// Create the chart by adding circle elements representing each election year
@@ -91,6 +91,74 @@ class YearChart {
//Election information corresponding to that year should be loaded and passed to
// the update methods of other visualizations
+ let yChart = this;
+
+ var data = [[0, (this.svgHeight - 40)/2], [this.svgWidth, (this.svgHeight - 40)/2]];
+
+ let scaleX = d3.scaleLinear()
+ .range([this.margin.left, this.svgWidth - this.margin.right])
+ .domain([0, this.electionWinners.length]);
+
+
+
+ let line = d3.line();
+ let pathString = line(data);
+
+ this.svg.append('g').append('path')
+ .attr('d', pathString)
+ .style("stroke-dasharray", ("2, 2"))
+ .attr('stroke', 'black');
+
+ let years = this.svg.append('g').selectAll('g')
+ .data(this.electionWinners)
+ .enter()
+ .append('g');
+
+ years.append('circle')
+ .attr('cy', (this.svgHeight - 38) * .5)
+
+ .attr('cx', (d, i) => {return scaleX(i)} )
+ .attr('r', 10)
+
+ .attr('class', (d) => {
+ return yChart.chooseClass(d.PARTY)
+ });
+
+ //Append text information of each year right below the corresponding circle
+ //HINT: Use .yeartext class to style your text elements
+ years.append('text')
+ .attr('x', (d, i) => {return scaleX(i)} )
+ .attr('y', (this.svgHeight - 20) * .5 + 30)
+ .attr('yearText', true)
+ .attr('text-anchor', 'middle')
+ .text((d) => {return d.YEAR});
+
+ //Style the chart by adding a dashed line that connects all these years.
+ //HINT: Use .lineChart to style this dashed line
+ //Done. Before adding circles
+
+ //Clicking on any specific year should highlight that circle and update the rest of the visualizations
+ //HINT: Use .highlighted class to style the highlighted circle
+ years.selectAll('circle')
+ .on('mouseover', function (d) {
+ d3.select(this).classed('highlighted', true);
+ })
+ .on('mouseout', function (d) {
+ years.selectAll('circle').classed('highlighted', false);
+ })
+ .on('click', function (d) {
+ years.selectAll('circle').classed('selected', false);
+ d3.select(this).classed('selected', true);
+
+ let file = 'data/Year_Timeline_' + d.YEAR + '.csv';
+
+ d3.csv(file, function (error, electionResult) {
+ yChart.electoralVoteChart.update(electionResult, self.colorScale);
+ yChart.votePercentageChart.update(electionResult);
+ yChart.tileChart.update(electionResult, self.colorScale);
+ });
+
+ })
//******* TODO: EXTRA CREDIT *******
@@ -99,6 +167,7 @@ class YearChart {
//Call the update method of shiftChart and pass the data corresponding to brush selection.
//HINT: Use the .brush class to style the brush.
+
}
}