Skip to content

Commit 5dbdc63

Browse files
author
Carolina Gonzalez
committed
technical functionality
1 parent efbe6c5 commit 5dbdc63

File tree

8 files changed

+117
-63
lines changed

8 files changed

+117
-63
lines changed
File renamed without changes.

backend/server.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ const db = pgp(cnxn)
2828

2929
app.post('/table/:table/', function(req, res) {
3030
let {table} = req.params
31-
let {filterOn, filterBy, columns, unique} = req.body
31+
let {filterOn, filterBy, columns, unique, addtlQuery} = req.body
3232
columns = columns && columns.length > 0 ? columns.join(',') : '*'
3333
unique = unique ? 'DISTINCT' : ''
3434

3535
let query = `SELECT ${unique} ${columns} FROM ${table}`
3636
if (filterOn && filterBy) {
3737
query += ` WHERE ${filterOn} = '${filterBy}'`
3838
}
39+
if (addtlQuery) {
40+
query += addtlQuery
41+
}
3942

4043
console.log(query)
4144
db.query(query, [true])

competitiveness/src/App.jsx

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import './App.css';
77
//can add more complexity here in the children eventually
88
class AppContainer extends Component {
99
componentWillMount() {
10-
//check for mapData?
1110
let parentDistType = (typeof(this.props.match.params.parentDistType) === 'undefined') ? 'AD' : this.props.match.params.parentDistType
1211
let parentDistId= (typeof(this.props.match.params.parentDistId) === 'undefined') ? 0 : this.props.match.params.parentDistId
1312
this.props.loadMap({parentDistType, parentDistId})

competitiveness/src/actions/index.js

+26-38
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,35 @@
1-
import { filterFiles } from './mapHelpers'
2-
import axios from 'axios'
1+
import { filterFiles, returnLoadParams, queryDB } from './mapHelpers'
32
const d3 = require('d3');
43

5-
//META MAP VARS -- MAKE THIS BETTER LATER
6-
const assemblyLoc = 'https://raw.githubusercontent.com/cngonzalez/nycet-flatfiles/master/locational/nyad_geo.json'
7-
const electionLoc = 'https://raw.githubusercontent.com/cngonzalez/nycet-flatfiles/master/locational/nyed_geo.json'
8-
const assemblyDataLoc = 'https://raw.githubusercontent.com/cngonzalez/nycet-flatfiles/master/ad_margins.tsv'
9-
const electionDataLoc = 'https://raw.githubusercontent.com/cngonzalez/nycet-flatfiles/master/ed_margins.tsv'
10-
11-
const DISTRICT_LEVEL_LABELS = {
12-
//top-level: NYC show all AD, SD, CD
13-
//eventually add diff levels
14-
AD: [assemblyLoc, assemblyDataLoc, 'AssemDist', 'districtnumber'],
15-
//mid-level: show EDs for a specific level
16-
ED: [electionLoc, electionDataLoc, 'ElectDist', 'ed']}
17-
18-
194
//ACTION CREATORS
205
export const loadMapData = (props) =>
216
//use this thunk syntax, because d3.queue happens async
227
dispatch => {
23-
248
dispatch(announceLoading)
259
let selected = props.parentDistId
2610
let districtType = (selected === 0) ? props.parentDistType : 'ED'
27-
let [geoSource,
28-
dataSource,
29-
mapRegionType,
30-
dataRegionType] = DISTRICT_LEVEL_LABELS[districtType];
31-
32-
return (
33-
d3.queue()
34-
.defer(d3.json, geoSource)
35-
.defer(d3.tsv, dataSource)
36-
.await((error, geoFile, dataFile) => {
37-
let [filteredGeo,
38-
filteredData] = filterFiles(geoFile, dataFile, mapRegionType, dataRegionType, selected);
39-
40-
let dataMap = d3.map()
41-
filteredData.forEach((d) => {
42-
d.margin = ((d.winning_party === 'Republican') ? -d.margin : +d.margin)
43-
dataMap.set(d[dataRegionType], d.margin)})
44-
dispatch(storeMapData(
45-
{geoJson: filteredGeo,
46-
geoData: dataMap}, 'LOAD_MAP_DATA'))
11+
console.log(districtType)
12+
dispatch(changeDistrict(districtType))
13+
let {mapRegionType,
14+
geoSource, table}= returnLoadParams(districtType)
15+
16+
//changes econd parent dist type to election state eventaully
17+
queryDB(props.parentDistType, table, props.parentDistType, selected).then(dataPull => {
18+
d3.queue()
19+
.defer(d3.json, geoSource)
20+
.await((error, geoFile) => {
21+
let [filteredGeo,
22+
filteredData] = filterFiles(geoFile, dataPull.data, mapRegionType, selected);
23+
24+
let dataMap = d3.map()
25+
filteredData.forEach((d) => {
26+
d.most_rec_pl_margin = ((d.winning_pol_lean === 'right') ? -d.most_rec_pl_margin : +d.most_rec_pl_margin)
27+
dataMap.set(d.district, d.most_rec_pl_margin)})
28+
dispatch(storeMapData(
29+
{geoJson: filteredGeo,
30+
geoData: dataMap}, 'LOAD_MAP_DATA'))
4731
})
48-
)
32+
})
4933
}
5034

5135

@@ -63,3 +47,7 @@ export const setMapDimensions = (width, height) => (
6347
export const announceLoading = () => (
6448
{type: 'LOAD_DATA'}
6549
)
50+
51+
export const changeDistrict = (distType) => (
52+
{type: 'CHANGE_DISTRICT_TYPE',
53+
payload: distType})
+52-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,62 @@
1-
const filterToParent = (geoFile, selected) => {
2-
let getParentRegion = (region) => (parseInt(region.toString().slice(0,2), 10))
3-
return geoFile.features.filter((d) => {
4-
return (getParentRegion(d.properties.districtNumber) === selected)
5-
})
1+
import axios from 'axios'
2+
3+
//MAP METADATA
4+
const getGeoSource = (dist) => (
5+
`https://raw.githubusercontent.com/cngonzalez/nycet-flatfiles/master/locational/${dist}.json`)
6+
7+
const MAP_REGIONS = {
8+
'AD': 'AssemDist',
9+
'SD': 'StSenDist',
10+
'CD': 'CongDist',
11+
'ED': 'ElectDist'}
12+
13+
export const returnLoadParams = (dist) => (
14+
{mapRegionType: MAP_REGIONS[dist],
15+
geoSource: getGeoSource(dist),
16+
table: (dist !== 'ED') ? 'hl_metrics' : 'ed_metrics'})
17+
18+
//DB QUERY
19+
const getHlQuery = (dist) => (
20+
{columns: ['district',
21+
'most_rec_pl_margin', 'winning_pol_lean'],
22+
filterOn: 'office',
23+
filterBy: dist})
24+
25+
const getEdQuery = (parentDist, election, selected) => (
26+
{columns: [`e.pl_margin_${election.toString().toLowerCase()} as most_rec_pl_margin`, 'd.ad', 'e.countyed', 'p.map as winning_pol_lean'],
27+
addtlQuery: ` as e JOIN electiondistricts as d on d.countyed = e.countyed JOIN maps_pollean p on e.wp_${election.toString().toLowerCase()} = p.party where d.${parentDist.toString().toLowerCase()} = ${selected}`})
28+
29+
// as d where d.${parentDist.toLowerCase()} = ${selected}`})
30+
31+
32+
export const queryDB = (dist, table, election, selected) => {
33+
let query = (selected === 0) ? getHlQuery(dist) : getEdQuery(dist, election, selected)
34+
return axios({method: 'post',
35+
url: `http://localhost:8080/table/${table}/`,
36+
data: query })
637
}
738

8-
export const filterFiles = (geoFile, dataFile, mapRegionType, dataRegionType, selected) => {
39+
const filterToParents = (geoFile, dataPull) => {
40+
dataPull.forEach((d) => d.district = parseInt(`${d.ad}${d.countyed.split(" ")[4]}`, 10))
41+
let validEds = dataPull.map((d) => d.district)
42+
return geoFile.features.filter((d) => (validEds.indexOf(d.properties.districtNumber) >= 0))
43+
}
44+
45+
export const filterFiles = (geoFile, dataPull, mapRegionType, selected) => {
46+
47+
geoFile.features.forEach((d) => d.properties['districtNumber'] = d.properties[mapRegionType])
948

10-
geoFile.features.forEach((d) => d.properties['districtNumber'] = d.properties[mapRegionType])
11-
let filteredFeatures = (selected !== 0) ? filterToParent(geoFile, parseInt(selected, 10)) : geoFile.features
49+
let filteredFeatures = (selected !== 0) ? filterToParents(geoFile, dataPull) : geoFile.features
1250

1351
//get all valid regions in the geodata and filter data
1452
let regionIds = filteredFeatures.map((d) => (d.properties.districtNumber))
15-
let filteredData = dataFile.filter((d) => (regionIds.indexOf(
16-
parseInt(d[dataRegionType], 10)) >= 0))
53+
let filteredData = dataPull.filter((d) => (regionIds.indexOf(
54+
parseInt(d.district, 10)) >= 0))
55+
// filteredData.forEach((d) => {
56+
// d.most_rec_pl_margin = parseInt(d.most_rec_pl_margin,10)
1757

58+
// })
59+
1860
return [{'type': geoFile['type'], 'features': filteredFeatures},
1961
filteredData]
2062
}
+26-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,39 @@
11
import { Dropdown } from 'semantic-ui-react';
22
import { connect } from 'react-redux';
3+
import { loadMapData } from '../actions/index';
34
const React = require('react');
45

5-
const DistrictTypeSelectContainer = ({districtType}) => (
6+
const DistrictTypeSelectContainer = ({districtType, changeDistrict}) => (
67
<Dropdown options={
7-
[{text: 'S. Assembly District', value: 'AD'},
8-
{text: 'S. Senate District', value: 'SD'},
9-
{text: 'Congressional District', value: 'CD'}]}
8+
[{text: 'State Assembly District', value: 'AD'},
9+
{text: 'State Senate District', value: 'SD'},
10+
{text: 'Congressional District', value: 'CD'},
11+
]}
1012
defaultValue={districtType}
13+
onChange={(e, d) => changeDistrict({parentDistType: d.value, parentDistId: 0})}
1114
/>
1215
)
1316

1417
const mapStateToDistrictProps = (state) => ({
1518
districtType: state.districtType})
1619

17-
export const DistrictTypeSelect = connect(mapStateToDistrictProps)(DistrictTypeSelectContainer)
20+
const RaceTypeSelectContainer = ({raceType}) => (
21+
<Dropdown options={
22+
[{text: 'Overall', value: ''},
23+
{text: 'President/Vice President', value: 'President_VP'},
24+
{text: 'US Representative', value: 'CD'},
25+
{text: 'US Senator', value: 'US_Senator'},
26+
{text: 'State Senator', value: 'SD'},
27+
{text: 'State Assembly Member', value: 'AD'},
28+
]}
29+
defaultValue={raceType}
30+
/>
31+
)
32+
//{text: 'City Council Member', value: 'CD'} hmm?
33+
34+
const mapStateToRaceProps = (state) => ({
35+
raceType: state.RaceType })
36+
37+
export const DistrictTypeSelect = connect(mapStateToDistrictProps, {changeDistrict: loadMapData})(DistrictTypeSelectContainer)
38+
export const RaceTypeSelect = connect(mapStateToRaceProps)(RaceTypeSelectContainer)
1839

competitiveness/src/components/Map.jsx

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { loadMapData } from '../actions/index';
44
const React = require('react');
55
const d3 = require('d3');
66

7-
const Map = ({mapWidth, mapHeight, mapComponents, drillDown}) => {
7+
const Map = ({mapWidth, mapHeight, mapComponents, parentDist, drillDown}) => {
88
let projection = d3.geoIdentity()
99
.reflectY(true)
1010
.fitSize([mapWidth,mapHeight], mapComponents.geoJson)
@@ -22,13 +22,13 @@ const Map = ({mapWidth, mapHeight, mapComponents, drillDown}) => {
2222
// let selected = (d.properties[props.mapRegionType] === props.selectedId) ? 'glow' : 'district'
2323
return (
2424
//'AD' is hardcoded here, but that should eventually come from store
25-
<Link key={`link-${i}`} to={{pathname: `/AD/${d.properties.districtNumber}`}}>
25+
<Link key={`link-${i}`} to={{pathname: `/${parentDist}/${d.properties.districtNumber}`}}>
2626
<path
2727
data={d}
2828
key={ `path-${ i }` }
2929
d={ `${d3.geoPath().projection(projection)(d)}` }
3030
fill={ `${ color(mapComponents.geoData.get(d.properties.districtNumber))}`}
31-
onClick={() => drillDown(d.properties.districtNumber)}
31+
onClick={() => drillDown(d.properties.districtNumber, parentDist)}
3232
className='district'
3333
/>
3434
</Link>
@@ -51,12 +51,13 @@ const Map = ({mapWidth, mapHeight, mapComponents, drillDown}) => {
5151
//filter map from ownprops
5252
const mapStateToProps = (state) => ({
5353
mapWidth: state.mapDimensions[0],
54-
mapHeight: state.mapDimensions[1]})
54+
mapHeight: state.mapDimensions[1],
55+
parentDist: state.districtType})
5556

5657
const mapDispatchToProps = (dispatch, ownProps) => (
57-
{drillDown: (selected) =>
58+
{drillDown: (selected, parentDist) =>
5859
//again, remove hardcoding eventually
59-
dispatch(loadMapData({parentDistId: selected, parentDistType: 'AD'}))}
60+
dispatch(loadMapData({parentDistId: selected, parentDistType: parentDist }))}
6061
)
6162

6263
const DataMap = connect(mapStateToProps, mapDispatchToProps)(Map)

competitiveness/src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import registerServiceWorker from './registerServiceWorker'
1515
let store = createStore(NYCETAppReducers, applyMiddleware(thunkMiddleware))
1616

1717
// debugging helper
18-
// const announce = () => console.log(store.getState())
19-
// setInterval(announce, 7000)
18+
const announce = () => console.log(store.getState())
19+
setInterval(announce, 7000)
2020

2121
//eventually, put a top level "Competetiveness" container component and allocate
2222
//components per route -- e.g., detail pages etc.

0 commit comments

Comments
 (0)