diff --git a/hw6/.idea/workspace.xml b/hw6/.idea/workspace.xml index 194178a..108f9c7 100644 --- a/hw6/.idea/workspace.xml +++ b/hw6/.idea/workspace.xml @@ -5,14 +5,6 @@ - - - - - - - - @@ -39,28 +31,28 @@ - + - + - + - + @@ -89,8 +81,8 @@ - - + + @@ -98,17 +90,35 @@ - - + + + + + + + + + + + - + - - + + + + + + + + + + + @@ -116,17 +126,17 @@ - - + + - + - - + + @@ -142,8 +152,11 @@ electionResult gSvg 'r' - selected i + selected + democrat + text + (d @@ -154,10 +167,10 @@ @@ -190,6 +203,17 @@ + + + + + + + + + + + @@ -220,6 +244,11 @@ + + + + + - @@ -262,13 +291,9 @@ - - - - - + @@ -276,6 +301,10 @@ + + + + @@ -287,6 +316,18 @@ + + + + + file://$PROJECT_DIR$/public/js/electoralVoteChart.js + 124 + + + + + @@ -301,38 +342,52 @@ - + - - + + - + - - - - - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw6/public/js/electoralVoteChart.js b/hw6/public/js/electoralVoteChart.js index 2262435..d7e9db3 100644 --- a/hw6/public/js/electoralVoteChart.js +++ b/hw6/public/js/electoralVoteChart.js @@ -1,303 +1,186 @@ class ElectoralVoteChart { - /** - * Constructor for the ElectoralVoteChart - * - * @param shiftChart an instance of the ShiftChart class - */ - constructor (shiftChart){ - this.shiftChart = shiftChart; - - this.margin = {top: 30, right: 20, bottom: 30, left: 50}; - let divelectoralVotes = d3.select("#electoral-vote").classed("content", true); + /** + * Constructor for the ElectoralVoteChart + * + * @param shiftChart an instance of the ShiftChart class + */ + constructor (shiftChart){ + this.shiftChart = shiftChart; - //Gets access to the div element created for this chart from HTML - this.svgBounds = divelectoralVotes.node().getBoundingClientRect(); - this.svgWidth = this.svgBounds.width - this.margin.left - this.margin.right; - this.svgHeight = 150; + this.margin = {top: 30, right: 20, bottom: 30, left: 50}; + let divelectoralVotes = d3.select("#electoral-vote").classed("content", true); - //creates svg element within the div - this.svg = divelectoralVotes.append("svg") - .attr("width",this.svgWidth) - .attr("height",this.svgHeight) - ; + //Gets access to the div element created for this chart from HTML + this.svgBounds = divelectoralVotes.node().getBoundingClientRect(); + this.svgWidth = this.svgBounds.width - this.margin.left - this.margin.right; + this.svgHeight = 150; - }; + //creates svg element within the div + this.svg = divelectoralVotes.append("svg") + .attr("width",this.svgWidth) + .attr("height",this.svgHeight) + ; - /** - * Returns the class that needs to be assigned to an element. - * - * @param party an ID for the party that is being referred to. - */ - chooseClass (party) { - if (party == "R"){ - return "republican"; + }; + + /** + * Returns the class that needs to be assigned to an element. + * + * @param party an ID for the party that is being referred to. + */ + chooseClass (party) { + if (party == "R"){ + return "republican"; + } + else if (party == "D"){ + return "democrat"; + } + else if (party == "I"){ + return "independent"; + } } - else if (party == "D"){ - return "democrat"; - } - else if (party == "I"){ - return "independent"; - } - } - /** - * Creates the stacked bar chart, text content and tool tips for electoral vote chart - * - * @param electionResult election data for the year selected - * @param colorScale global quantile scale based on the winning margin between republicans and democrats - */ + /** + * Creates the stacked bar chart, text content and tool tips for electoral vote chart + * + * @param electionResult election data for the year selected + * @param colorScale global quantile scale based on the winning margin between republicans and democrats + */ - update (electionResult, colorScale){ + update (electionResult, colorScale){ - // ******* TODO: PART II ******* + // ******* TODO: PART II ******* - //Group the states based on the winning party for the state; - //then sort them based on the margin of victory + //Group the states based on the winning party for the state; + //then sort them based on the margin of victory - //Create the stacked bar chart. - //Use the global color scale to color code the rectangles. - //HINT: Use .electoralVotes class to style your bars. + //Create the stacked bar chart. + //Use the global color scale to color code the rectangles. + //HINT: Use .electoralVotes class to style your bars. - //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 + //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 - //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. + //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. - //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 + //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 - //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) + //HINT: Use the chooseClass method to style your elements based on party wherever necessary. - let statesIArray = []; - let statesRArray = []; - let statesDArray = []; + this.svg.selectAll("*").remove(); - for(let i=0; i { + if(d.RD_Difference < 0) democratParty.push(d); + else if (d.RD_Difference > 0) republicanParty.push(d); + else independentParty.push(d); + }) - if(electionArray[i].key == 'D') - statesDArray = electionArray[i].values + //Sorts group of states based on the margin of victory + independentParty.sort((a, b) => b.Total_EV - a.Total_EV); + democratParty.sort((a, b) => a.RD_Difference - b.RD_Difference); + republicanParty.sort((a, b) => a.RD_Difference - b.RD_Difference); - } + let sortedData = []; + sortedData = sortedData.concat(independentParty); + sortedData = sortedData.concat(democratParty); + sortedData = sortedData.concat(republicanParty); - let statesArray = [] - statesArray = statesArray.concat(statesIArray) - statesArray = statesArray.concat(statesDArray) - statesArray = statesArray.concat(statesRArray) + let xCoordinates = []; + sortedData.forEach(d => { + xCoordinates.push(allVotes); + allVotes += parseInt(d.Total_EV); + }); - //Create the stacked bar chart. - //Use the global color scale to color code the rectangles. - //HINT: Use .electoralVotes class to style your bars. - var self = this; + let electoralVoteScale = d3.scaleLinear() + .domain([0, allVotes]) + .range([0, this.svgWidth]); - this.xScale = d3.scaleLinear() - .domain([0, d3.sum(statesArray, d => parseInt(d['Total_EV']))]) - .range([0, self.svgWidth]); + //Create the stacked bar chart. + let electoralVoteChart = this.svg + .selectAll("rect") + .data(sortedData) + .enter(); - let rectG = this.svg.select('g'); + electoralVoteChart + .append("rect") + .attr("width", d => this.svgWidth * d.Total_EV / allVotes) + .attr("height", 20) + .attr("x", (_, i) => electoralVoteScale(xCoordinates[i])) + .attr("y", 50) + //Uses the global color scale to color code the rectangles. + .attr("fill", d => d.RD_Difference === "0" ? "green" : colorScale(d.RD_Difference)) + .attr("class", "electoralVotes") - if(rectG.empty()) - { - rectG = this.svg.append('g') - } + //Displays the total count of electoral votes won by the Democrat and Republican party + //on top of the corresponding groups of bars. + electoralVoteChart + .append("text") + .text(d => d.I_EV_Total) + .attr("y", 50) + .attr("class", "electoralVoteText independent") - let statesRect = rectG.selectAll('rect') - .data(statesArray); + electoralVoteChart + .append("text") + .text(d => d.D_EV_Total) + .attr("y", 50) + .attr("dx", d => d.I_EV_Total === "" ? 0 : 120) + .attr("class", "electoralVoteText democrat") - statesRect.exit().remove(); - statesRect = statesRect.enter().append('rect').merge(statesRect); + electoralVoteChart + .append("text") + .text(d => d.R_EV_Total) + .attr("y", 50) + .attr("dx", this.svgWidth) + .attr("class", "electoralVoteText republican"); - let votesSeen = 0; + //Display a bar with minimal width in the center of the bar chart to indicate the 50% mark + electoralVoteChart + .append("line") + .attr("x1", this.svgWidth/2) + .attr("y1", 50) + .attr("x2", this.svgWidth/2) + .attr("y2", 50) + .style("stroke", "black") + .style("stroke-width", 2) + .attr("class", "middlePoint") - 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){ + //Displays the text mentioning the total number of electoral votes required + // to win the elections throughout the country + let votesToWin + if (electionResult[0].Year == 1960) + votesToWin = 269 + else if(electionResult[0].Year > 1960) + votesToWin = 270 + else + votesToWin = 266 - if(d['State_Winner'] == 'I') - { - d3.select(this).attr('class', function(d){ - return self.chooseClass(d["State_Winner"]) - }); - return; - } + electoralVoteChart + .append("text") + .text(`Electoral Vote (${votesToWin} needed to win)`) + .attr('y', 45) + .attr("dx", this.svgWidth/2 - 140) + .attr("font-size", 16) - 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) + //******* 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. - //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 beb10aa..1f60088 100644 --- a/hw6/public/js/tileChart.js +++ b/hw6/public/js/tileChart.js @@ -2,172 +2,83 @@ /** Class implementing the tileChart. */ class TileChart { - /** - * Initializes the svg elements required to lay the tiles - * and to populate the legend. - */ - constructor(tooltip){ + /** + * Initializes the svg elements required to lay the tiles + * and to populate the legend. + */ + constructor(tooltip){ - let divTiles = d3.select("#tiles").classed("content", true); - this.margin = {top: 30, right: 20, bottom: 30, left: 50}; - //Gets access to the div element created for this chart and legend element from HTML - let svgBounds = divTiles.node().getBoundingClientRect(); - this.svgWidth = svgBounds.width - this.margin.left - this.margin.right; - this.svgHeight = this.svgWidth/2; - let legendHeight = 150; - //add the svg to the div - let legend = d3.select("#legend").classed("content",true); + let divTiles = d3.select("#tiles").classed("content", true); + this.margin = {top: 30, right: 20, bottom: 30, left: 50}; + //Gets access to the div element created for this chart and legend element from HTML + let svgBounds = divTiles.node().getBoundingClientRect(); + this.svgWidth = svgBounds.width - this.margin.left - this.margin.right; + this.svgHeight = this.svgWidth/2; + let legendHeight = 150; + //add the svg to the div + let legend = d3.select("#legend").classed("content",true); - //creates svg elements within the div - this.legendSvg = legend.append("svg") - .attr("width",this.svgWidth) - .attr("height",legendHeight) - .attr("transform", "translate(" + this.margin.left + ",0)") - this.svg = divTiles.append("svg") - .attr("width",this.svgWidth) - .attr("height",this.svgHeight) - .attr("transform", "translate(" + this.margin.left + ",0)") + //creates svg elements within the div + this.legendSvg = legend.append("svg") + .attr("width",this.svgWidth) + .attr("height",legendHeight) + .attr("transform", "translate(" + this.margin.left + ",0)") + this.svg = divTiles.append("svg") + .attr("width",this.svgWidth) + .attr("height",this.svgHeight) + .attr("transform", "translate(" + this.margin.left + ",0)") - this.tooltip = tooltip; - }; + this.tooltip = tooltip; + }; - /** - * Returns the class that needs to be assigned to an element. - * - * @param party an ID for the party that is being referred to. - */ - chooseClass (party) { - if (party == "R"){ - return "republican"; + /** + * Returns the class that needs to be assigned to an element. + * + * @param party an ID for the party that is being referred to. + */ + chooseClass (party) { + if (party == "R"){ + return "republican"; + } + else if (party== "D"){ + return "democrat"; + } + else if (party == "I"){ + return "independent"; + } } - else if (party== "D"){ - return "democrat"; - } - else if (party == "I"){ - return "independent"; - } - } - /** - * Creates tiles and tool tip for each state, legend for encoding the - * color scale information. - * - * @param electionResult election data for the year selected - * @param colorScale global quantile scale based on the winning - * margin between republicans and democrats - */ - update (electionResult, colorScale){ + /** + * Creates tiles and tool tip for each state, legend for encoding the + * color scale information. + * + * @param electionResult election data for the year selected + * @param colorScale global quantile scale based on the winning + * margin between republicans and democrats + */ + update (electionResult, colorScale){ - //Calculates the maximum number of rows and columns - this.maxColumns = d3.max(electionResult, d => +d.Space) + 1; - this.maxRows = d3.max(electionResult, d => +d.Row) + 1; + //Calculates the maximum number of rows and columns + this.maxColumns = d3.max(electionResult, d => +d.Space) + 1; + this.maxRows = d3.max(electionResult, d => +d.Row) + 1; - // ******* TODO: PART IV ******* - //Tansform the legend element to appear in the center and make a call to this element for it to display. + // ******* TODO: PART IV ******* + //Tansform the legend element to appear in the center and make a call to this element for it to display. - //Lay rectangles corresponding to each state according to the 'row' and 'column' information in the data. + //Lay rectangles corresponding to each state according to the 'row' and 'column' information in the data. - //Display the state abbreviation and number of electoral votes on each of these rectangles + //Display the state abbreviation and number of electoral votes on each of these rectangles - //Use global color scale to color code the tiles. + //Use global color scale to color code the tiles. - //HINT: Use .tile class to style your tiles; - // .tilestext to style the text corresponding to tiles + //HINT: Use .tile class to style your tiles; + // .tilestext to style the text corresponding to tiles - //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. + //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 5aec8c4..995f9c7 100644 --- a/hw6/public/js/votePercentageChart.js +++ b/hw6/public/js/votePercentageChart.js @@ -65,156 +65,23 @@ 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; - 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 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 - }) - //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); - }); + //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. + //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 - // ******* TODO: PART III ******* + //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. - //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); + //HINT: Use the chooseClass method to style your elements based on party wherever necessary. - //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 2bbd45c..00e622d 100644 --- a/hw6/public/js/yearChart.js +++ b/hw6/public/js/yearChart.js @@ -69,7 +69,7 @@ class YearChart { .domain(domain) .range(range); - // ******* DONE: PART I ******* + // ******* TODO: PART I ******* // Create the chart by adding circle elements representing each election year @@ -91,6 +91,7 @@ class YearChart { //Election information corresponding to that year should be loaded and passed to // the update methods of other visualizations + let domainOfYears = []; let yChart = this; var data = [[0, (this.svgHeight - 40)/2], [this.svgWidth, (this.svgHeight - 40)/2]]; @@ -133,32 +134,20 @@ class YearChart { .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 + .on("click", d => { years.selectAll('circle').classed('selected', false); - d3.select(this).classed('selected', true); + d3.select(d3.event.target).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); + // Election information corresponding to the year selected is loaded and passed to the update methods of the other visualizations. + d3.csv(`data/Year_Timeline_${d.YEAR}.csv`).then(electionResult => { + this.electoralVoteChart.update(electionResult, this.colorScale); + this.votePercentageChart.update(electionResult, this.colorScale); + this.tileChart.update(electionResult, this.colorScale) }); - }) + .on("mouseenter", () => d3.select(d3.event.target).classed("highlighted", true)) + .on("mouseleave", () => d3.select(d3.event.target).classed("highlighted", false)); //******* TODO: EXTRA CREDIT *******