Last active
April 27, 2017 17:54
-
-
Save alecrajeev/ec120ec7493c2cad0da1dcb8216d4b48 to your computer and use it in GitHub Desktop.
House 2018 Election
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this is the javascript file that has all the functions that regarding color | |
var color = d3.scale.linear() // initial color scale for the demographic data | |
.range(['rgb(247,252,245)','rgb(229,245,224)','rgb(199,233,192)','rgb(161,217,155)','rgb(116,196,118)','rgb(65,171,93)','rgb(35,139,69)','rgb(0,109,44)','rgb(0,68,27)']); | |
var eleven_domain = [-1.0,-0.3,-0.2,-0.1,-0.05,0.0,0.05,0.1,0.2,0.3,1.0]; | |
var color1; | |
var stateColor = ["#A94588","#D76940","#D13F46","#23A5C5", "#F0A851", "#F0A851", "#726198", "#23A5C5", "#228947", "#2B6AA1", "#D13F46", "#A94588", "#A94588", | |
"#2B6AA1", "#F0A851", "#D76940", "#D13F46", "#D13F46", "#6EAE51", "#A94588", "#A94588", "#D76940", "#D13F46", "#F0A851", "#228947", "#D76940", "#23A5C5", | |
"#23A5C5", "#D13F46", "#6EAE51", "#A94588", "#2B6AA1", "#23A5C5", "#2B6AA1", "#6EAE51", "#2B6AA1", "#2B6AA1", "#D13F46", "#23A5C5", "#6EAE51", "#6EAE51", | |
"#D76940", "#6EAE51", "#228947", "#F0A851", "#F0A851", "#D13F46", "#726198", "#726198", "#726198"]; | |
function buildColorRange(i) { // builds the color range | |
switch(i) { | |
case 0: // white | |
color.range(['rgb(252,251,253)','rgb(239,237,245)','rgb(218,218,235)','rgb(188,189,220)','rgb(158,154,200)','rgb(128,125,186)','rgb(106,81,163)','rgb(84,39,143)','rgb(63,0,125)']); | |
break; | |
case 1: // black | |
color.range(['rgb(247,252,245)','rgb(229,245,224)','rgb(199,233,192)','rgb(161,217,155)','rgb(116,196,118)','rgb(65,171,93)','rgb(35,139,69)','rgb(0,109,44)','rgb(0,68,27)']); | |
break; | |
case 2: // latinx | |
color.range(['rgb(247,251,255)','rgb(222,235,247)','rgb(198,219,239)','rgb(158,202,225)','rgb(107,174,214)','rgb(66,146,198)','rgb(33,113,181)','rgb(8,81,156)','rgb(8,48,107)']); | |
break; | |
case 3: // asian | |
color.range(['rgb(255,245,240)','rgb(254,224,210)','rgb(252,187,161)','rgb(252,146,114)','rgb(251,106,74)','rgb(239,59,44)','rgb(203,24,29)','rgb(165,15,21)','rgb(103,0,13)']); | |
break; | |
case 4: // native american | |
color.range(['rgb(255,245,235)','rgb(254,230,206)','rgb(253,208,162)','rgb(253,174,107)','rgb(253,141,60)','rgb(241,105,19)','rgb(217,72,1)','rgb(166,54,3)','rgb(127,39,4)']); | |
break; | |
case 5: // multiracial | |
color.range(['rgb(247,244,249)','rgb(231,225,239)','rgb(212,185,218)','rgb(201,148,199)','rgb(223,101,176)','rgb(231,41,138)','rgb(206,18,86)','rgb(152,0,67)','rgb(103,0,31)']); | |
break; | |
default: // election | |
color.range(['#ae000c','#fff','#010a79']); | |
//color.range(['#ae000c','#8185BC','#ffffff','#D78287','#010a79']); | |
//color.range(['#AE000C','#BA3035','#C56365','#D09697','#DBC8C8','#C8C8D5','#9697BD','#6465A5','#32358E', '#010a79']); | |
break; | |
} | |
} | |
function buildExtentData() { // builds the mininum and maximum value array, extent, for each dataset | |
extentData[0] = d3.extent(demoData, function(d) {return d.White; }); | |
extentData[1] = d3.extent(demoData, function(d) {return d.Black; }); | |
extentData[2] = d3.extent(demoData, function(d) {return d.Latinx; }); | |
extentData[3] = d3.extent(demoData, function(d) {return d.Asian; }); | |
extentData[4] = d3.extent(demoData, function(d) {return d.NativeAmerican; }); | |
extentData[5] = d3.extent(demoData, function(d) {return d.Multiracial; }); | |
} | |
function buildColorDomain(i, extent) { | |
var colorDomain = []; | |
if (i < 5) { // demographics | |
var j = 0; | |
for (k = extent[0]; k <= (extent[1]+.01); k += ((extent[1]+.01) - extent[0])/8.0) { | |
colorDomain[j++] = k; | |
} | |
} else { | |
if (i == 5) { // multiracial | |
// colorDomain = [.005, .01, .015, .02, .025, .03, .035, .04, .1, .25]; | |
colorDomain = [.025, .05, .075, .1, .125, .15, .175, .2, .25]; | |
} | |
else | |
if (i == 12) // Pres 2016 Change | |
colorDomain = [-35.0, 0.0, 35.0]; | |
else | |
if (i == 17) // House Map selector | |
colorDomain = [-1.0, 0.0, 1.0]; | |
else // All other elections | |
colorDomain = [-100.0, 0.0, 100.0]; | |
} | |
return colorDomain; | |
} | |
function grabLegendColor(i) { | |
if (i < 6) { | |
return color; | |
} | |
else { | |
color1 = new colorFunction(); | |
color1.domainValues = getCopyDomain(i); | |
color1.rangeValues = ['#ae000c','#fff','#010a79']; | |
return color1; | |
} | |
} | |
function colorFunction(domainValues, rangeValues) { | |
// this replicates the function color aka d3.scale.linear | |
// necessary to properly get the legend color to work | |
this.domainValues = domainValues; | |
this.rangeValues = rangeValues; | |
this.domain = function() { | |
return this.domainValues; | |
} | |
this.range = function() { | |
return this.rangeValues; | |
} | |
this.value = function(v) { | |
return color(v); | |
} | |
} | |
function getCopyDomain(i) { | |
if (i == 12) // 12 to 16 Change | |
return [-35.0, -25.0, -10.0, -5.0, 0.0, 5.0, 10.0, 25.0, 35.0]; | |
else // all other elections | |
return [-100.0, -50.0, -25.0, -10.0, 0.0, 10.0, 25.0, 50.0, 100.0]; | |
} | |
function updateHexagonColor(i) { // fills in the hexagons with the correct color according to the scale | |
hexagons | |
.transition() | |
.delay(500) | |
.style({fill: function(d) {return getDistrictColor(d.properties.districtID,i); }, | |
stroke: function(d) {return getDistrictColor(d.properties.districtID,i); }}); | |
} | |
function getDistrictColor(districtID,i) { | |
if (i == 17) { | |
} | |
if (districtID != -1) | |
return color(dataByDistrictID[districtID][i]); | |
} | |
function getStateColor(stateID) { | |
if (stateID != -1) | |
return stateColor[stateID]; | |
} | |
function updateVoteHexagonColor() { | |
hexagons | |
.transition() | |
.delay(500) | |
.style({fill: function(d) {return getVoteDistrictColor(d.properties.districtID); }, | |
stroke: function(d) {return getVoteDistrictColor(d.properties.districtID); }}); | |
} | |
function updateHexagonColorFast(i) { // fills in the hexagons with the correct color according to the scale quickly | |
hexagons | |
.transition() | |
.style({fill: function(d) {return getDistrictColor(d.properties.districtID,i); }, | |
stroke: function(d) {return getDistrictColor(d.properties.districtID,i); }}); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var width = 1250; | |
var height = 730; | |
var radius = 6.5; | |
var hexagons; | |
var demoData; | |
var presData; | |
var dataByDistrictID = {}; | |
var extentData = {}; | |
var specificDistrictID = -2; | |
var toolTipSelector = 0; | |
var houseSelector = true; | |
var legendRectSize = 15; | |
var legendSpacing = 7; | |
var dataSets = ["White", "Black", "Latinx", "Asian", "NativeAmerican", "Multiracial", "Clinton 2016", "Trump 2016", "Obama 2012", "Romney 2012", "2016 Presidential Election", "2012 Presidential Election", "2012 to 2016 Change", "House Dem", "Hosue GOP", "2016 House Races", "2016 Pres vs House Margins"]; | |
var dataSetSelector = 17; // used to figure out which data set is being shown | |
var legendRectSize = 15, | |
legendSpacing = 7; | |
var svg = d3.select(".map").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var svgLegend = d3.select(".legend").append("svg") | |
.attr("height", "220px") | |
.attr("width", "162px"); | |
queue() | |
.defer(d3.json, "https://raw.githubusercontent.com/alecrajeev/UnitedStatesHex/Democratic-Primary/ushex.json") | |
.defer(d3.csv, "https://raw.githubusercontent.com/alecrajeev/UnitedStatesHex/2016-Presidential-Election/Demographics.csv") | |
.defer(d3.csv, "https://raw.githubusercontent.com/alecrajeev/UnitedStatesHex/2016-Presidential-Election/ElectionResults.csv") | |
.await(makeMyMap); | |
function makeMyMap(error, ushex, demographicData, electionData) { | |
if (error) | |
return console.warn(error); | |
demographicData.forEach(function (d) { | |
d.districtID = +d.districtID; | |
d.White = +d.White; | |
d.Black = +d.Black; | |
d.Latinx = +d.Latinx; | |
d.Asian = +d.Asian; | |
d.NativeAmerican = +d.NativeAmerican; | |
d.Multiracial = +d.Multiracial; | |
dataByDistrictID[d.districtID] = [d.White, d.Black, d.Latinx, d.Asian, d.NativeAmerican, d.Multiracial]; | |
}); | |
demoData = demographicData; | |
electionData.forEach(function (d) { | |
dataByDistrictID[d.districtID].push(+d.Clinton2016, +d.Trump2016, +d.Obama2012, +d.Romney2012, +d.Margin2016, +d.Margin2012, +d.MarginChange, +d.HouseDem, +d.HouseRep, +d.HouseMargin, +d.HousePresMargin); | |
// this if/else statement below will be used to select House districts | |
if (dataByDistrictID[d.districtID][15] > 0) // if Dem district | |
dataByDistrictID[d.districtID].push(1); | |
else | |
dataByDistrictID[d.districtID].push(-1); | |
if (checkCompetitive(d.districtID)) // checks if a ditrict is competitive | |
dataByDistrictID[d.districtID][17] = 0; | |
}); | |
presData = electionData; | |
buildExtentData(); | |
if (dataSetSelector == 17) { | |
buildColorRange(dataSetSelector); | |
color.domain(buildColorDomain(dataSetSelector, [-1.0, 1.0])); | |
} | |
var projection = hexProjection(radius); | |
var path = d3.geo.path().projection(projection); | |
var hexFeatures = topojson.feature(ushex, ushex.objects.states).features; | |
hexagons = svg.append("g").attr("class", "hexagon").selectAll("hexagon") | |
.data(hexFeatures) | |
.enter() | |
.append("path") | |
.attr("d", path) | |
.style({fill: function(d) {return getDistrictColor(d.properties.districtID, dataSetSelector); }, | |
stroke: function(d) {return getDistrictColor(d.properties.districtID, dataSetSelector); }}) | |
.on("mouseover", hoverOnDistrict) | |
.on("mousedown", selectDistrict); | |
var stateBorder = svg.append("path") | |
.attr("class", "stateBorder") | |
.call(drawStateBorder); | |
var districtBorder = svg.append("path") | |
.attr("class", "districtBorder") | |
.call(drawDistrctBorder); | |
var specificDistrict = svg.append("path") | |
.attr("class", "specificBorder") | |
.call(drawSpecificDistrict); | |
function hoverOnDistrict(d) { | |
coordinates = d3.mouse(this); | |
showTooltip(d, coordinates); | |
specificDistrictID = d.properties.districtID; | |
specificDistrict.call(drawSpecificDistrict); | |
changeInfo(d); | |
} | |
function selectDistrict(d) { | |
if (houseSelector && d.properties.state != "Ocean") { // you are using the function that chooses House seats | |
houseSeatFlip(d.properties.districtID); | |
updateHexagonColorFast(17); | |
d3.select(".houseBar").text("Dem: " + getDemSeats() + " \tRep: " + getRepSeats() + "\t Tossup: " + getTossupSeats()); | |
} | |
} | |
function showTooltip(d, coordinates) { | |
if (d.properties.state != "Ocean"){ | |
d3.select(".g-tooltip") | |
.style({display: "block", | |
top: function (e) {return (coordinates[1] + 75).toString() + "px"; }, | |
left: function(e) {return (coordinates[0] + 175).toString() + "px"; } | |
}); | |
d3.select(".tooltip-district").text(d.properties.state + "-" + d.properties.district); | |
if (dataSetSelector != -1) { | |
if (dataSetSelector < 6) { | |
d3.select(".tooltip-data-a").text(""); | |
d3.select(".tooltip-data-b").text(""); | |
d3.select(".tooltip-data").text(dataSets[dataSetSelector] + ": " + getShortened(dataByDistrictID[d.properties.districtID][dataSetSelector])); | |
} | |
else { | |
switch(dataSetSelector) { | |
case 10: // 2016 election | |
d3.select(".tooltip-data").text(""); | |
d3.select(".tooltip-data-a").text("Clinton: " + getShortened(dataByDistrictID[d.properties.districtID][6])); | |
d3.select(".tooltip-data-b").text("Trump: " + " " + getShortened(dataByDistrictID[d.properties.districtID][7])); | |
break; | |
case 11: // 2012 election | |
d3.select(".tooltip-data").text(""); | |
d3.select(".tooltip-data-a").text("Obama: " + " " + getShortened(dataByDistrictID[d.properties.districtID][8])); | |
d3.select(".tooltip-data-b").text("Romney: " + getShortened(dataByDistrictID[d.properties.districtID][9])); | |
break; | |
case 12: // 2012 -> 2016 change | |
d3.select(".tooltip-data").text(""); | |
d3.select(".tooltip-data-a").text("2016: " + getShortened(dataByDistrictID[d.properties.districtID][10])); | |
d3.select(".tooltip-data-b").text("2012: " + getShortened(dataByDistrictID[d.properties.districtID][11])); | |
break; | |
case 15: // 2016 House | |
d3.select(".tooltip-data").text(""); | |
d3.select(".tooltip-data-a").text("Dem: " + getShortened(dataByDistrictID[d.properties.districtID][13])); | |
d3.select(".tooltip-data-b").text("Rep: " + getShortened(dataByDistrictID[d.properties.districtID][14])); | |
break; | |
} | |
} | |
} | |
} | |
else { | |
d3.select(".g-tooltip").style("display", "none"); | |
} | |
function getShortened(v) { | |
if (dataSetSelector < 6) | |
return d3.round(100.0*v,1).toString() + "%"; | |
if (dataSetSelector == 12) | |
if (v < 0) // republican | |
return d3.round(-1.0*v,1).toString() + "% (R)"; | |
else | |
return d3.round(v,1).toString() + "% (D)"; | |
return d3.round(v,1).toString() + "%"; | |
} | |
} | |
function drawSpecificDistrict(border) { | |
border.attr("d", path(topojson.mesh(ushex, ushex.objects.states, checkSpecificDistrict))); | |
} | |
function drawDistrctBorder(border) { | |
border.attr("d", path(topojson.mesh(ushex, ushex.objects.states, checkBorderByDistrict))); | |
} | |
function drawStateBorder(border) { | |
border.attr("d", path(topojson.mesh(ushex, ushex.objects.states, checkBorderByState))); | |
} | |
function checkSpecificDistrict(hex1, hex2) { | |
if (specificDistrictID < 0) // if there is no specific district to be highlighted | |
return false; | |
if (hex1.properties.districtID != specificDistrictID && | |
hex2.properties.districtID != specificDistrictID) | |
// if when traversing the hexmesh you are not near the specific district | |
return false; | |
if (hex1.properties.state == hex2.properties.state) | |
return hex1.properties.district != hex2.properties.district; | |
else | |
return true; | |
} | |
function checkBorderByDistrict(hex1, hex2) { | |
if (hex1.properties.state == hex2.properties.state) | |
return hex1.properties.district != hex2.properties.district; | |
else | |
return true; | |
} | |
function checkBorderByState(hex1, hex2) { | |
return hex1.properties.state != hex2.properties.state; | |
} | |
function hexProjection(radius) { // comes from Mike Bostock's hexagon mesh source code | |
var dx = radius * 2 * Math.sin(Math.PI / 3), | |
dy = radius * 1.5; | |
return { | |
stream: function(stream) { | |
return { | |
point: function(x, y) { stream.point(x * dx / 2, (y - (2 - (y & 1)) / 3) * dy / 2); }, | |
lineStart: function() { stream.lineStart(); }, | |
lineEnd: function() { stream.lineEnd(); }, | |
polygonStart: function() { stream.polygonStart(); }, | |
polygonEnd: function() { stream.polygonEnd(); } | |
}; | |
} | |
}; | |
} | |
if (dataSetSelector == 17) { | |
showHouseSeatSelector(); | |
} | |
} | |
function showRollCallVote() { | |
buildVoteColor(); | |
updateVoteHexagonColor(); | |
showVoteLegend(); | |
d3.select(".voteLegend").style("display", "block"); | |
d3.select(".legend").style("display", "none"); | |
// d3.select(".districtBorder").style("stroke-opacity", ".5"); | |
} | |
function showLegend(i) { | |
var demo = (i < 6 ? true : false); | |
d3.select(".legTitle").text(dataSets[i] + (demo ? " Demo" : "")); | |
var LegendColor = grabLegendColor(i); | |
var LegendContent = svgLegend.selectAll(".LegendContent") | |
.data(LegendColor.domain()) | |
var LegendEnter = LegendContent.enter() | |
.append("g") | |
.attr("class", "LegendContent") | |
.attr("transform", function(d,j) { | |
var rectHeight = j*(legendRectSize + legendSpacing); | |
var rectWidth = legendRectSize; | |
return "translate(" + rectWidth + ", " + rectHeight + ")"; | |
}) | |
LegendEnter.append("rect") | |
.attr("width", legendRectSize-2) | |
.attr("height", legendRectSize) | |
.style("fill", function(d) { | |
if (demo) | |
return color(d) | |
else | |
return LegendColor.value(d); | |
}) | |
.style("stroke", "black") | |
LegendEnter.append("text") | |
.attr("x", legendRectSize + legendSpacing*1.3) | |
.attr("y", legendRectSize-1) | |
.text(function(d) { | |
if (demo) | |
return d3.round(d*100,1).toString() + "%"; | |
return (d < 1 ? (-1.0*d).toString() + "% (R)" : d.toString() + "% (D)"); | |
}); | |
var updateSelection = svgLegend.selectAll(".LegendContent") | |
.transition() | |
.duration(1000) | |
.style("opacity", "1") | |
.attr("transform", function(d,j) { | |
var rectHeight = j*(legendRectSize + legendSpacing); | |
var rectWidth = legendRectSize; | |
return "translate(" + rectWidth + ", " + rectHeight + ")"; | |
}) | |
updateSelection.select("rect") | |
.style("fill", function(d) { | |
if (demo) | |
return color(d) | |
else | |
return LegendColor.value(d); | |
}); | |
updateSelection.select("text") | |
.text(function(d) { | |
if (demo) | |
return d3.round(d*100,1).toString() + "%"; | |
return (d < 1 ? (-1.0*d).toString() + "% (R)" : d.toString() + "% (D)"); | |
}); | |
LegendContent.exit() | |
.transition() | |
.duration(1000) | |
.style("opacity", "0") | |
.remove(); | |
} | |
function getRealDistrict(i, state) { // returns "at large" if the district number is 0, like Montana | |
if (i > 0) | |
return i; | |
return "At-Large"; | |
} | |
function changeInfo(d) { | |
if (d.properties.state != "Ocean") { // if you ARE on a district | |
d3.select(".whichState").text(d.properties.state); | |
d3.select(".whichDistrict").text(getRealDistrict(d.properties.district, d.properties.state)); | |
for (i = 0; i < 6; i++) { | |
var classNameSplit = dataSets[i].split(" "); | |
if (classNameSplit.length < 2) { // data set names that are one word (Asian) | |
d3.select("." + dataSets[i] + ".Info").text(dataSets[i] + ": " + d3.round(dataByDistrictID[d.properties.districtID][i]*100, 1) + "%"); | |
if (i == dataSetSelector) | |
d3.select("." + dataSets[i] + ".Info").style("font-weight", "bold"); | |
} | |
else {// data set names that are two words | |
d3.select("." + classNameSplit[0] + "." + classNameSplit[1] + ".Info").text("Native American" + ": " + d3.round(dataByDistrictID[d.properties.districtID][i]*100, 1) + "%"); | |
} | |
} | |
d3.select("." + "Pres2016" + ".Info").text("2016 Margin: " + getMarginString(dataByDistrictID[d.properties.districtID][10],0)); | |
d3.select("." + "Pres2012" + ".Info").text("2012 Margin: " + getMarginString(dataByDistrictID[d.properties.districtID][11],1)); | |
d3.select("." + "PresChange" + ".Info").text("'12 to '16 Change: " + getMarginString(dataByDistrictID[d.properties.districtID][12],2)); | |
d3.select("." + "HouseMargin" + ".Info").text("House Margin: " + getMarginString(d3.round(dataByDistrictID[d.properties.districtID][15],1),3)); | |
if (dataSetSelector > 6) { | |
switch(dataSetSelector) { | |
case 10: | |
d3.select("." + "Pres2016" + ".Info").style("font-weight", "bold"); | |
break; | |
case 11: | |
d3.select("." + "Pres2012" + ".Info").style("font-weight", "bold"); | |
break; | |
case 12: | |
d3.select("." + "PresChange" + ".Info").style("font-weight", "bold"); | |
break; | |
case 15: | |
d3.select("." + "HouseMargin" + ".Info").style("font-weight", "bold"); | |
break; | |
} | |
} | |
} | |
else { // if you are NOT on a district | |
d3.select(".whichState").text(""); | |
d3.select(".whichDistrict").text(""); | |
for (i = 0; i < 6; i++) { | |
var classNameSplit = dataSets[i].split(" "); | |
if (classNameSplit.length < 2) { // data set names that are one word (Asian) | |
d3.select("." + dataSets[i] + ".Info").text(dataSets[i] + ": "); | |
d3.select("." + dataSets[i] + ".Info").style("font-weight", "normal"); | |
} | |
else// data set names that are two words | |
d3.select("." + classNameSplit[0] + "." + classNameSplit[1] + ".Info").text("Native American" + ": "); | |
} | |
d3.select("." + "Pres2016" + ".Info").text("2016 Margin: "); | |
d3.select("." + "Pres2012" + ".Info").text("2012 Margin: "); | |
d3.select("." + "PresChange" + ".Info").text("'12 to '16 Change: "); | |
d3.select("." + "HouseMargin" + ".Info").text("House Margin: "); | |
d3.select("." + "Pres2016" + ".Info").style("font-weight", "normal"); | |
d3.select("." + "Pres2012" + ".Info").style("font-weight", "normal"); | |
d3.select("." + "PresChange" + ".Info").style("font-weight", "normal"); | |
d3.select("." + "HouseMargin" + ".Info").style("font-weight", "normal"); | |
} | |
} | |
function getdistrictID(statecd) { // give the id for the specific congressional district | |
// determined by the name of the state and district number | |
// will eventually preprocess a hashtable in node | |
for (i = 0; i < 435; i++) { | |
if (districtList[i][0] === statecd) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
function getMarginString(m, p) { | |
// gets the string displayed in the informational box to the left | |
switch(p) { | |
case 0: | |
if (m < 0) | |
return Math.abs(m).toString() + "% Trump"; | |
else | |
return m.toString() + "% Clinton"; | |
break; | |
case 1: | |
if (m < 0) | |
return Math.abs(m).toString() + "% Romney"; | |
else | |
return m.toString() + "% Obama"; | |
default: | |
if (m < 0) | |
return Math.abs(m).toString() + "% (R)"; | |
else | |
return m.toString() + "% (D)"; | |
} | |
} | |
function showStates() { | |
dataSetSelector = -1; | |
houseSelector = false; | |
shrinkTooltip(true) | |
d3.select(".header").text("States"); | |
hexagons | |
.style({fill: function(d) {return getStateColor(d.properties.stateID); }, | |
stroke: function(d) {return getStateColor(d.properties.stateID); }}); | |
d3.select(".legend").style("display", "none"); | |
d3.select(".houseBar").style("display", "none"); | |
toolTipSelector = 0; | |
} | |
function showDataSet(i) { | |
dataSetSelector = i; | |
houseSelector = false; | |
shrinkTooltip(false); | |
if (i < 6) | |
if (i != 4) | |
d3.select(".header").text(dataSets[i] + " Demographics by Congressional District"); | |
else | |
d3.select(".header").text("Native American" + " Demographics by Congressional District"); | |
else | |
d3.select(".header").text(dataSets[i] + " by Congressional District"); | |
buildColorRange(i); | |
color.domain(buildColorDomain(i,extentData[i])); | |
updateHexagonColor(i); | |
showLegend(i); | |
d3.select(".legend").style("display", "block"); | |
d3.select(".houseBar").style("display", "none"); | |
} | |
function showHouseSeatSelector() { | |
dataSetSelector = 17; | |
houseSelector = true; | |
shrinkTooltip(true); | |
d3.select(".header").text("House 2018 Election Map"); | |
d3.select(".houseBar").style("display", "block"); | |
buildColorRange(dataSetSelector); | |
color.domain(buildColorDomain(dataSetSelector, [-1.0, 1.0])); | |
updateHexagonColor(17); | |
d3.select(".legend").style("display", "none"); | |
d3.select(".houseBar").text("Dem: " + getDemSeats() + " \tRep: " + getRepSeats() + "\t Tossup: " + getTossupSeats()); | |
} | |
function shrinkTooltip(b) { | |
if (b) { // Tooltip is tiny | |
d3.select(".tooltip-data").text(""); | |
d3.select(".tooltip-data-a").text(""); | |
d3.select(".tooltip-data-b").text(""); | |
d3.select(".g-tooltip").style({height: "25px"}); | |
} | |
else { | |
d3.select(".g-tooltip").style({height: "50px"}) | |
} | |
} | |
function showPrimaryDistrictVote() { | |
d3.select(".header").text("Democratic Primary Vote by Congressional District"); | |
hexagons | |
.style({fill: function(d) {return getPrimaryVote(d.properties.districtID); }, | |
stroke: function(d) {return getPrimaryVote(d.properties.districtID); }}); | |
d3.select(".legend").style("display", "none"); | |
toolTipSelector = 4; | |
d3.select(".legend").style("display", ""); | |
showLegend(0) | |
} | |
function grabDistrictInfo(districtID, i) { | |
if (primaryByDistrictID[districtID][9]) | |
return ""; | |
return primaryByDistrictID[districtID][i]; | |
} | |
function grabStateInfo(stateID, districtID, i) { | |
if (primaryByDistrictID[districtID][9]) | |
return ""; | |
if (i >= 4) | |
return d3.round(primaryByStateID[stateID][i]*100.0, 2) + "%"; | |
if (i < 4) | |
return primaryByStateID[stateID][i]; | |
} | |
function getRealDistrict(i, state) { // returns "at large" if the district number is 0, like Montana | |
if (i > 0) | |
return i; | |
return "At-Large"; | |
} | |
function houseSeatFlip(districtID) { | |
switch (dataByDistrictID[districtID][17]) { | |
case 1: // Dem district | |
dataByDistrictID[districtID][17] = 0; | |
break; | |
case 0: // tossup district | |
dataByDistrictID[districtID][17] = -1; | |
break; | |
case -1: // Gop district | |
dataByDistrictID[districtID][17] = 1; | |
break; | |
} | |
} | |
function getDemSeats() { | |
var demSeats = 0; | |
for (var i = 0; i < 435; i++) | |
if (dataByDistrictID[i][17] == 1) | |
demSeats += 1; | |
return demSeats; | |
} | |
function getRepSeats() { | |
var repSeats = 0; | |
for (var i = 0; i < 435; i++) | |
if (dataByDistrictID[i][17] == -1) | |
repSeats += 1; | |
return repSeats; | |
} | |
function getTossupSeats() { | |
var tossupSeats = 0; | |
for (var i = 0; i < 435; i++) | |
if (dataByDistrictID[i][17] == 0) | |
tossupSeats +=1; | |
return tossupSeats; | |
} | |
function checkCompetitive(districtID) { | |
var competitive = false; | |
if (districtID == 68) | |
competitive = true; | |
if (districtID == 69) | |
competitive = true; | |
if (districtID == 119) | |
competitive = true; | |
if (districtID == 240) | |
competitive = true; | |
if (districtID == 383) | |
competitive = true; | |
return competitive; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<link rel="icon" href="favicon.ico" /> | |
<link rel="stylesheet", type="text/css", href="style.css"> | |
<title>2016 Presidential Election</title> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"> | |
</script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"> | |
</script> | |
</head> | |
<body> | |
<div class="top"> | |
<div class="pageTitle"> | |
<h3 class="header">House 2018 Election Map</h3> | |
</div> | |
<div class="houseBar"> | |
<!-- <svg height="100" width="100"><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg> --> | |
</div> | |
</div> | |
<div class="left"> | |
<div class="sidebar"> | |
<text>Data Set</text> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showStates()">States | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(0)">White Demographics | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(1)">Black Demographics | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(2)">Latinx Demographics | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(3)">Asian Demographics | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(4)">Native American Demo | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(5)">Multiracial Demo | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(10)">2016 Presidential | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(11)">2012 Presidential | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(12)">2016 Change | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" onclick="showDataSet(15)">House Margin | |
</div> | |
<div class="typeToggle"> | |
<input type="radio" name="data-selector" checked onclick="showHouseSeatSelector()">House 2018 Selector | |
</div> | |
</div> | |
<div class="information"> | |
<div>State: <span class="whichState"></span></div> | |
<div>District: <span class="whichDistrict"></span></div> | |
<div class="White Info">White: </div> | |
<div class="Black Info">Black: </div> | |
<div class="Latinx Info">Latinx: </div> | |
<div class="Asian Info">Asian: </div> | |
<div class="NativeAmerican Info">NativeAmerican: </div> | |
<div class="Multiracial Info">Multiracial: </div> | |
<div class="Pres2016 Info">2016 Margin: </div> | |
<div class="Pres2012 Info">2012 Margin: </div> | |
<div class="PresChange Info">'12 to '16 Change: </div> | |
<div class="HouseMargin Info">House Margin: </div> | |
</div> | |
<div class="legend"> | |
<div class="legTitle">Margin of Victory</div> | |
<div class="legendChart"></div> | |
</div> | |
</div> | |
<div class="main"> | |
<div class="map"></div> | |
<div class="sampleImage"> <img src="http://i.imgur.com/ATb2T5P.jpg" /></div> | |
</div> | |
<div class="g-tooltip"> | |
<div class="tooltip-district"></div> | |
<div class="tooltip-data"></div> | |
<div class="tooltip-data-a"></div> | |
<div class="tooltip-data-b"></div> | |
</div> | |
</body> | |
<script type="text/javascript" src="hexscript.js"></script> | |
<script type="text/javascript" src="colorBuilder.js"></script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.top { | |
position: absolute; | |
left:0px; right: 0px; | |
height: 92px; | |
margin-left: 15px; | |
font-family: 'Helvetica Neue'; | |
font-weight: bold; | |
} | |
.left { | |
position: absolute; | |
left:0; top:80px; bottom: 0; | |
width: 250px; | |
margin-left: 15px; | |
} | |
.main { | |
position: relative; | |
left:252px; top:92px; right:0; bottom:0; | |
} | |
.right { | |
position: relative; | |
background: #fff; | |
top: -656px; | |
left: 1200px; | |
width: 178px; | |
} | |
.map { | |
position: relative; | |
top: -60px; | |
} | |
.legend { | |
position: relative; | |
top: -6px; | |
height: 220px; | |
border: solid black; | |
padding: 5px; | |
padding-top: 10px; | |
display: block; | |
font-family: "Helvetica Neue"; | |
stroke-width: 2px; | |
display: none; | |
} | |
.houseBar { | |
position: relative; | |
left: 300px; | |
top: -50px; | |
height: 70px; | |
width: 300px; | |
margin-left: 15px; | |
display: block; | |
} | |
.buttonDiv { | |
padding: 5px 5px 5px 5px; | |
font-family: "Helvetica Neue"; | |
} | |
.passage { | |
width: 130px; | |
height: 40px; | |
} | |
.sidebar { | |
border: solid black; | |
padding: 5px; | |
font-family: 'Helvetica Neue'; | |
} | |
.sidebar text{ | |
position: relative; | |
text-align: center; | |
display: block; | |
border-bottom: thin solid black; | |
padding: 10px 30px 10px 30px; | |
font-weight: bold; | |
font-family: 'Helvetica Neue'; | |
} | |
.whichState { | |
font-weight: bold; | |
} | |
.whichDistrict { | |
font-weight: bold; | |
} | |
.typeToggle { | |
font-family: 'Helvetica Neue'; | |
padding: 3px; | |
font-size: 14px; | |
font-style: normal; | |
font-variant: normal; | |
font-weight: 400; | |
line-height: 20px; | |
} | |
.information { | |
position: relative; | |
top: -3px; | |
border: solid black; | |
padding: 5px; | |
font-family: 'Helvetica Neue'; | |
display: block; | |
line-height: 1.3; | |
} | |
.legTitle { | |
text-align: center; | |
font-weight: bold; | |
} | |
.toggleSideBar { | |
position: relative; | |
top: -3px; | |
border: solid black; | |
padding: 5px; | |
font-family: 'Helvetica Neue'; | |
display: block; | |
} | |
.hexagon { | |
fill: none; | |
pointer-events: all; | |
stroke: 0px; | |
z-index: 1; | |
} | |
.specificBorder { | |
fill: none; | |
stroke-width: 2.5px; | |
stroke-opacity: 1; | |
stroke: #fff; | |
pointer-events: none; | |
} | |
.districtBorder { | |
fill: none; | |
stroke: #000; | |
stroke-width: 1px; | |
stroke-opacity: .2; | |
pointer-events: none; | |
} | |
.stateBorder { | |
fill: none; | |
stroke: #000; | |
stroke-width: 2px; | |
pointer-events: none; | |
} | |
.g-tooltip { | |
position: absolute; | |
background-color: #fff; | |
padding: 5px 8px 5px 6px; | |
font-family: "Helvetica Neue"; | |
top: 800px; | |
width: 100px; | |
height: 25px; | |
overflow: hidden; | |
border: 1px solid #ccc; | |
box-shadow: 2px 2px 7px rgba(0,0,0,0.3); | |
/* font-size: 62.5%; | |
*/} | |
.tooltip-district { | |
font-weight: bold; | |
text-align: center; | |
} | |
.tooltip-data { | |
font-size: 80%; | |
text-align: center; | |
} | |
.tooltip-data-a { | |
font-size: 80%; | |
text-align: left; | |
} | |
.tooltip-data-b { | |
font-size: 80%; | |
text-align: left; | |
} | |
.sampleImage { | |
display: none; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment