Skip to content
This repository has been archived by the owner on Mar 5, 2020. It is now read-only.

Test map #74

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/Zip_Code_GeoJson.json

Large diffs are not rendered by default.

630 changes: 630 additions & 0 deletions assets/leaflet.css

Large diffs are not rendered by default.

Binary file added assets/marker-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@
"d3-format": "^1.1.1",
"d3-sankey": "^0.4.2",
"d3-shape": "^1.0.6",
"isomorphic-fetch": "^2.2.1",
"leaflet": "^1.0.3",
"ramda": "^0.23.0",
"rc-slider": "^5.4.0",
"react": "^15.4.2",
"react-addons-transition-group": "^15.4.2",
"react-dom": "^15.4.2",
"react-faux-dom": "^3.0.1",
"react-leaflet": "^1.1.6",
"react-motion": "^0.4.7",
"react-router": "^3.0.0",
"react-selectize": "^2.1.0",
Expand Down
254 changes: 254 additions & 0 deletions src/Maps/LeafletMap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
import React, { Component } from 'react';
import { Map, TileLayer, GeoJSON } from 'react-leaflet';
import fetch from 'isomorphic-fetch';
import classNames from 'classnames/bind';
import styles from './LeafletMap.styles.css';
import myGeoJsonData from '../../assets/Zip_Code_GeoJson.json';

const cx = classNames.bind(styles);
const classMap = cx({ mapSize: true });

function wrapMyComponent(WrappedComponent, GeoJsonWrapper) {
return class extends Component {
static displayName = `GeoJsonWrapper(<${WrappedComponent.displayName} />`;
static propTypes = {
data: React.PropTypes.object,
};

constructor(props) {
super(props);
this.state = {
center: props.data.map.position,
maxBounds: props.data.map.maxBounds,
zoom: props.data.map.zoom,
minZoom: props.data.map.minZoom,
geoJsonData: GeoJsonWrapper,
dataByYear: {},
dataByZip: {},
zipYear: 2016,
};
this.style = this.style.bind(this);
this.onEachFeature = this.onEachFeature.bind(this);
}

componentDidMount() {
this.goFetch();
}

// Get Data Functions
goFetch = () => {
fetch('http://54.213.83.132/hackoregon/http/current_candidate_transactions_in/5591/')
.then(response => response.json())
.then((transactions) => {
const dataByYear = {};
transactions.forEach((t) => {
const year = t.tran_date.substring(0, 4);
const yearToUpdate = dataByYear[year];
if (yearToUpdate) {
dataByYear[year].push(t);
} else {
dataByYear[year] = [t];
}
});
return dataByYear;
})
.then((dataByYear) => {
const dataByZip = this.sortByZip(dataByYear, 2016);
const geoJsonData = this.countByZip(dataByZip);
this.setState({ dataByYear, dataByZip, geoJsonData });
})
.catch(ex => console.log('failed', ex)) // eslint-disable-line
};

sortByZip = (dataByYear, zipYear) => {
const yearData = dataByYear || this.state.dataByYear;
const myYear = yearData[zipYear];
const dataByZip = {};
myYear.forEach((t) => {
const zip = t.zip;
const zipToUpdate = dataByZip[zip];
if (zipToUpdate) {
dataByZip[zip].push(t);
} else {
dataByZip[zip] = [t];
}
});
return dataByZip;
};

countByZip = (dataByZip) => {
const geoData = this.state.geoJsonData;
const findZip = dataByZip || this.state.dataByZip;
geoData.features.forEach((t) => {
const geoRecord = t;
const zip = t.properties.ZIPCODE;
let count = 0;
if (findZip[zip] !== undefined) {
count = findZip[zip].length;
}
geoRecord.properties.COUNT = count;
});
return geoData;
};

upDateYear = (e) => {
const zipYear = Number(e.target.value);
const dataByZip = this.sortByZip(this.dataByYear, zipYear);
const geoJsonData = this.countByZip(dataByZip);

this.setState({ dataByZip, geoJsonData, zipYear });
}

showMe = () => {
console.log(this.state); // eslint-disable-line
}

// Build Map Functions
getColor(d) {
switch (true) {
case (d > 50):
return '#084594';
case (d > 40):
return '#2171b5';
case (d > 20):
return '#4292c6';
case (d > 10):
return '#6baed6';
case (d > 5):
return '#9ecae1';
case (d > 1):
return '#c6dbef';
default:
return '#eff3ff';
}
}

style(feature) {
return {
fillColor: this.getColor(feature.properties.COUNT),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
};
}

// Hover and Interactive Functions
highlightFeature(e) {
const layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7,
});
layer.openPopup();
}

resetHighlight(e) {
const layer = e.target;
layer.setStyle({
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
});
layer.closePopup();
}

onEachFeature(feature, layer) {
if (feature.properties && feature.properties.ZIPCODE) {
const zip = feature.properties.ZIPCODE.toString();
layer.bindPopup(` ZIP: ${zip}`);
layer.on({
mouseover: this.highlightFeature,
mouseout: this.resetHighlight,
});
}
}

render() {
return (
<WrappedComponent
data={this.state.geoJsonData}
center={this.state.center}
maxBounds={this.state.maxBounds}
zoom={this.state.zoom}
minZoom={this.state.minZoom}
zipYear={this.state.zipYear}
choices={this.state.dataByYear}

upDateYear={this.upDateYear}
showMe={this.showMe}
style={this.style}
onEachFeature={this.onEachFeature}
/>
);
}
};
}

const BareLeafletMap = (props) => {
require('../../assets/leaflet.css');
let options = [];
if (props.choices !== undefined) {
options = Object.keys(props.choices).map(key =>
<option key={key} value={key} >{key}</option>,
);
}

return (
<div>
<select
value={props.zipYear}
onChange={props.upDateYear}
style={{
width: '100px',
height: '25px',
}}
>
{options}
</select>
<Map
className={classMap}
center={props.center}
maxBounds={props.maxBounds}
zoom={props.zoom}
minZoom={props.minZoom}
>
<TileLayer
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
/>
<GeoJSON
data={props.data}
style={props.style}
onEachFeature={props.onEachFeature}
/>
</Map>
</div>
);
};
BareLeafletMap.displayName = 'BareLeafletMap';

BareLeafletMap.propTypes = {
center: React.PropTypes.array,
maxBounds: React.PropTypes.array,
zoom: React.PropTypes.number,
minZoom: React.PropTypes.number,
zipYear: React.PropTypes.number,
data: React.PropTypes.object,
choices: React.PropTypes.object,
style: React.PropTypes.func,
upDateYear: React.PropTypes.func,
onEachFeature: React.PropTypes.func,
};

const PDXLeafletMap = wrapMyComponent(
BareLeafletMap,
myGeoJsonData,
);

export default PDXLeafletMap;
37 changes: 37 additions & 0 deletions src/Maps/LeafletMap.styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.mapSize {
height: 600px;
width: 75%;
}

.my-div-icon {
background: url('../../assets/marker-icon.png');
background-size: contain;
background-repeat: no-repeat;
width: 25px;
height: 25px;
}

.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}

.legend {
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
51 changes: 51 additions & 0 deletions src/ViewData/BarData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, {Component} from 'react';
// import { Motion, spring } from 'react-motion';

class BarData extends Component {
constructor() {
super();
this.state = {
data: []
}
}

componentDidMount() {
fetch('http://54.213.83.132/hackoregon/http/current_candidate_transactions_out/931/')
.then(response => response.json())
.then(data => this.setState({ data }));
}

render() {
const contributionData = this.state.data.map(item => item.amount);
const filedDates = this.state.data.map((item, idx) => item.filed_date);
let years = filedDates.map(value => {
let firstFour = value.substring(0, 4);
return firstFour;
});
const sortHighToLow = (a,b) => b-a;
const containerHeight = 300;
const containerWidth = 950;

const topFiveContributors = contributionData.sort(sortHighToLow)
.slice(0, 50)
.map((item, idx) => {
//pushes bars to bottom of container, instead of hanging like stalactites
const marginFromTop = containerHeight-(item/1000);
return(
<div
key={idx}
style={{ height: `${item/1000}px`, width: '100px', backgroundColor: 'blue', margin: `${marginFromTop}px 5px 0 5px`}}>
</div>
)
});

return (
<div style={{ height: `${containerHeight}px`, width: `${containerWidth}px`, border: '1px solid black', display: 'flex'}}>
{ topFiveContributors }
</div>
);
}

}

export default BarData;
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export Slider from './Slider/Slider';
export Header from './Navigation/Header';
export Nav from './Navigation/Nav';
export NavRouterLink from './Navigation/NavRouterLink';
export LeafletMap from './Maps/LeafletMap';
22 changes: 22 additions & 0 deletions stories/BarData.story.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import { BarData } from '../src';

const displayName = BarData.displayName || 'BarData';
const title = 'Simple usage';
const description = `
Display data using React Motion`;

const demoCode = () => (
<BarData />
);

const propDocs = { inline: true, propTables: [BarData] };

export default () => storiesOf(displayName, module)
.addWithInfo(
title,
description,
demoCode,
propDocs,
);
Loading