let ptboData = `{"type":"FeatureCollection","name":"FED_CA_2_2_ENG","features":[ {"type":"Feature","properties":{"FED_NUM":35084,"NID":"{C5A817F8-E941-42E5-93E2-A8F93F3C9B3C}","FEDNUM":35084,"ENNAME":"Peterborough--Kawartha","FRNAME":"Peterborough--Kawartha","PROVCODE":"ON","CREADT":"20131005","REVDT":"20140619","REPORDER":"2013","DECPOPCNT":115269,"QUIPOPCNT":0,"ENLEGALDSC":"http://www.elections.ca/res/cir/maps2/mapprov.asp?map=35084&lang=e#descrip","FRLEGALDSC":"http://www.elections.ca/res/cir/maps2/mapprov.asp?map=35084&lang=f#descrip"},"geometry":{"type":"Polygon","coordinates":[[[-77.96119811009635,44.91147640101107],[-77.88448063294759,44.7698866723411],[-77.88747432537885,44.769108512720145],[-77.8813294219811,44.7574903512605],[-77.82908693632191,44.629745899189004],[-77.81468370245574,44.60171780243068],[-77.7978352886451,44.57361240662294],[-77.75915870690189,44.49436791346317],[-77.72737240824847,44.43647221096338],[-77.75977269742086,44.42756400402205],[-77.80662060890656,44.4109436116682],[-77.8611852003063,44.40146217558128],[-77.91308041617172,44.38939089766243],[-77.92600762099067,44.41645815421616],[-77.93030880645436,44.413802990198704],[-78.11089258707332,44.368105805868595],[-78.11442731624199,44.36589959418327],[-78.11981718174484,44.36449630547536],[-78.29321250821518,44.3223221048783],[-78.28286552927894,44.300469956416684],[-78.27434264005045,44.30237355785461],[-78.27306633979246,44.29905316072017],[-78.27432625252573,44.29889123661348],[-78.27286592912536,44.29625691303955],[-78.27482733471521,44.29578904470244],[-78.28466683513389,44.286100791275956],[-78.28162603344937,44.27915548699592],[-78.29113784383262,44.276863680416454],[-78.29004992468407,44.274599767588384],[-78.29727748162993,44.2728224823706],[-78.29811384075144,44.27423100363946],[-78.30725205998102,44.27362382320998],[-78.31038321225722,44.26308969024293],[-78.31391861472524,44.25798220717846],[-78.3319682038333,44.25276070818239],[-78.33481774334187,44.259184580559726],[-78.32812717502738,44.26550758080076],[-78.34143367345186,44.261839567608924],[-78.34212388829164,44.26335283487665],[-78.34949491328626,44.26135609211497],[-78.35336595775529,44.253544940659715],[-78.3571099788865,44.252581559136985],[-78.35854068766403,44.2563808719247],[-78.36031365341032,44.25602760648035],[-78.35897426707031,44.25272557046086],[-78.3611662795666,44.25214079269956],[-78.36726720689131,44.263562589057656],[-78.37381518081038,44.26195627863465],[-78.37658791817304,44.265136165034114],[-78.37863143467474,44.2655698246808],[-78.37677019284149,44.266726585001194],[-78.37815037409578,44.2668442450576],[-78.37740937215189,44.26976493373654],[-78.38205276268987,44.280778214285846],[-78.37585888171093,44.28206786178737],[-78.3834417755298,44.30090038913837],[-78.42546930703739,44.29042390241789],[-78.48985826260608,44.43101188661884],[-78.49231466263967,44.44556791943121],[-78.48794065689738,44.465909364413854],[-78.49006550025146,44.474803814598275],[-78.49258773164394,44.47869764144614],[-78.50827473669916,44.49318230067653],[-78.51006548011023,44.49711862921662],[-78.51433374445514,44.52251577580198],[-78.52919023807637,44.55394236368405],[-78.54370784622476,44.55009663733173],[-78.61220535994093,44.697961802612014],[-78.61996519684904,44.717575905766374],[-78.65482845585241,44.79389170755395],[-78.48100481300663,44.83522000302956],[-78.46027676055584,44.83928417656724],[-78.41903315660379,44.85017511025206],[-78.37220576229488,44.85996587243251],[-78.3247246638362,44.87201635449448],[-78.19036959222775,44.902191797381015],[-78.14101068116288,44.91676919694432],[-78.13049383610799,44.896178690494985],[-78.1287243135896,44.89343809749344],[-78.12664131006787,44.89305249662196],[-78.11888740219827,44.875676513973666],[-77.96119811009635,44.91147640101107]]]},"turnout":{"Population":"115269","Electors":"93190","ValidBallots":"66542","ValidBallotPercentage":"99.7","RejectedBallots":"190","RejectedBallotsPercentage":"0.3","TotalBallotsCast":"66732","VoterTurnoutPercentage":"71.6","ElectedCandidate":"Monsef, Maryam Liberal/Libéral"},"MP":{"vacant":false,"name":"Maryam Monsef","party":"Liberal","elected":"10/19/2015 0:00"}, "history": [ { "year": 2015, "results": [ { "Party": "Liberal", "Candidate": "Maryam Monsef", "Votes": "29,091", "%": "43.08", "±%": "22.42" }, { "Party": "Conservative", "Candidate": "Michael Skinner", "Votes": "23,747", "%": "35.16", "±%": "-14.6" }, { "Party": "NDP", "Candidate": "Dave Nickle", "Votes": "12,713", "%": "18.83", "±%": "-6.19" }, { "Party": "Green", "Candidate": "Doug Mason", "Votes": "1,847", "%": "2.73", "±%": "-1.34" } ] }, { "year": 2011, "results": [ { "Party": "Conservative", "Candidate": "Dean Del Mastro", "Votes": "29,393", "%": "49.67", "±%": "2.27" }, { "Party": "NDP", "Candidate": "Dave Nickle", "Votes": "14,723", "%": "24.88", "±%": "10.96" }, { "Party": "Liberal", "Candidate": "Betsy McGregor", "Votes": "12,664", "%": "21.4", "±%": "-10.2" }, { "Party": "Green", "Candidate": "Michael Bell", "Votes": "2,105", "%": "3.56", "±%": "-3.35" } ] } ]} ]}` ; parsedData = {}; async function getData() { article = document.getElementById('election-map'); finalData = JSON.parse(ptboData) //parses all data from the JSON file parsedData = finalData; const update = await drawRidingMap(parsedData); //fires update page function } function drawRidingMap(data) { let pad = 0.1; //max 0.5 if (pad < 0) { pad = 0; } else if (pad > 0.5) { pad = 0.5; } let mapGrid = make('div', article, 'mapGrid') data.features[0].history.forEach((year, i) => { let mapContainer = make('div', mapGrid, 'mapContainer'); let map = d3.select(mapContainer).append("svg") let width = Number(map.style('width').split('px')[0]); let height = Number(map.style('height').split('px')[0]); let projection = d3.geoMercator().fitExtent([[width/20, 0], [width-width/20, height]], data.features[0]) let path = d3.geoPath().projection(projection); map.attr("class", "svgMap") .attr('viewBox', `0 0 ${width} ${height}`) map.selectAll('path') .data(data.features) .enter() .append("path") .attr('class', 'ridings') .attr("d", path) .style("fill", d => { return partyColor(d.history[i].results[0].Party)}) //return fill color of riding winner .attr('fill-opacity', 1) .attr('stroke-linejoin', 'round') .style("stroke-width", 0.35 + 'px') .attr("stroke", '#fff') let voteHistoryDiv = make('div', mapContainer, 'voteHistoryDiv infoDiv'); let voteHistoryTitle = make('h3', voteHistoryDiv, 'ridingListTitle bold'); voteHistoryTitle.innerHTML = `${data.features[0].history[i].year} results`; let voteHistoryList = make('ul', voteHistoryDiv, 'ridingList') let voteHistoryListItem = make('li', voteHistoryList, 'voteHistoryListItem ridingListItem ridingListHeader') let voteHistoryTitleName = make('div', voteHistoryListItem, 'voteHistoryTitleName bold'); voteHistoryTitleName.innerText = `Name`; let voteHistoryTitleParty = make('div', voteHistoryListItem, 'voteHistoryTitleParty bold'); voteHistoryTitleParty.innerText = `Party`; let voteHistoryTitleYear = make('div', voteHistoryListItem, 'voteHistoryTitleYear bold'); voteHistoryTitleYear.innerHTML = `%`; data.features[0].history[i].results.forEach(party => { let voteHistoryListItem = make('li', voteHistoryList, 'voteHistoryListItem ridingListItem') let voteHistoryTag = make('div', voteHistoryListItem, 'voteHistoryTag'); voteHistoryTag.style.background = partyColor(party.Party); let voteHistoryName = make('div', voteHistoryListItem, 'voteHistoryName bold'); voteHistoryName.innerText = party.Candidate; let voteHistoryParty = make('div', voteHistoryListItem, 'voteHistoryParty'); voteHistoryParty.innerText = partyShortName(party.Party); let voteHistoryYear = make('div', voteHistoryListItem, 'voteHistoryYear bold'); voteHistoryYear.innerHTML = party['%']; }) }) } function createRidingVoteHistory(voteHistory, parent) { let voteHistoryDiv = make('div', parent, 'voteHistoryDiv infoDiv'); let voteHistoryTitle = make('h3', voteHistoryDiv, 'ridingListTitle bold'); voteHistoryTitle.innerHTML = `Recent vote history`; let voteHistoryList = make('ul', voteHistoryDiv, 'ridingList') let voteHistoryListItem = make('li', voteHistoryList, 'voteHistoryListItem ridingListItem ridingListHeader') let voteHistoryTitleName = make('div', voteHistoryListItem, 'voteHistoryTitleName bold'); voteHistoryTitleName.innerText = `Name`; let voteHistoryTitleParty = make('div', voteHistoryListItem, 'voteHistoryTitleParty bold'); voteHistoryTitleParty.innerText = `Party`; let voteHistoryTitleYear = make('div', voteHistoryListItem, 'voteHistoryTitleYear bold'); voteHistoryTitleYear.innerHTML = `Year`; voteHistory.forEach(party => { let voteHistoryListItem = make('li', voteHistoryList, 'voteHistoryListItem ridingListItem') let voteHistoryTag = make('div', voteHistoryListItem, 'voteHistoryTag'); voteHistoryTag.style.background = partyColor(party.Party); let voteHistoryName = make('div', voteHistoryListItem, 'voteHistoryName bold'); voteHistoryName.innerText = party.Candidate; let voteHistoryParty = make('div', voteHistoryListItem, 'voteHistoryParty'); voteHistoryParty.innerText = party['%']; }) } /////////////Helper functions //Turn number into string with commas function displayCommas(number) { var parts = number.toString().split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return parts.join("."); } //Turn number into string with N decimal places function displayRound(value, precision) { var multiplier = Math.pow(10, precision || 0); return (Math.round(value * multiplier) / multiplier).toFixed(precision); } //Keys for turning party shortform to full name or color const partyShortArray = ['LIB', 'CON', 'NDP', 'GRN', 'BQ', 'PPC', 'IND', 'LT']; const partyLongArray = ['Liberal', 'Conservative', 'NDP', 'Green', 'Bloc Québécois', `People's Party`, `Independent`, `Libertarian`]; const partyColorArray = ['#B91319', '#1A4782', '#F37021', '#3D9B35', '#33B2CC', '#472e8c', '#888', '#555'] const provinceShortArray = ['BC', 'AB', 'SK', 'MB', 'ON', 'QC', 'NB', 'NS', 'PE', 'NL', 'YT', 'NT', 'NU']; const provinceMidArray = ['B.C.', 'Alta.', 'Sask.', 'Man.', 'Ont.', 'Que.', 'N.B.', 'N.S.', 'P.E.I.', 'Nfld.', 'Y.T.', 'N.W.T.', 'N.T.']; const provinceFullArray = ['British Columbia', 'Alberta', 'Saskatchewan', 'Manitoba', 'Ontario', 'Quebec', 'New Brunswick', 'Nova Scotia', 'Prince Edward Island', 'Newfoundland and Labrador', 'Yukon Territory', 'Northwest Territories', 'Nunavut'] //Return full name from short name (LIB -> Liberal) function partyFullName(shortName) { let fullName = shortName; if (partyShortArray.indexOf(shortName) !== -1) { fullName = partyLongArray[partyShortArray.indexOf(shortName)]; } return fullName; } function partyShortName(fullName) { let shortName = fullName; if (partyLongArray.indexOf(fullName) !== -1) { shortName = partyShortArray[partyLongArray.indexOf(fullName)]; } return shortName; } //Return color from short name function partyColor(name) { let color = '#4a4a4a'; if (partyShortArray.indexOf(name) !== -1) { color = partyColorArray[partyShortArray.indexOf(name)]; } else if (partyLongArray.indexOf(name) !== -1) { color = partyColorArray[partyLongArray.indexOf(name)]; } return color; } function provinceMidName(shortName) { let midName = shortName; if (provinceShortArray.indexOf(shortName) !== -1) { midName = provinceMidArray[provinceShortArray.indexOf(shortName)]; } return midName; } function provinceFullName(shortName) { let fullName = shortName; if (provinceShortArray.indexOf(shortName) !== -1) { fullName = provinceLongArray[provinceShortArray.indexOf(shortName)]; } return fullName; } //Create and append element to parent with optional classes, id function make(type, parent, CLASS, ID) { let element = document.createElement(type); if (typeof CLASS !== 'undefined') { element.setAttribute('class', CLASS); } if (typeof ID !== 'undefined') { element.setAttribute('id', ID); } return parent.appendChild(element); }