diff --git a/src/App.js b/src/App.js index 01a37b5..1f9f50c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,20 +1,20 @@ + import React, { Component } from 'react'; -import {merge} from 'lodash'; import './App.min.css'; import 'font-awesome/css/font-awesome.min.css'; import 'react-tippy/dist/tippy.css'; import * as d3 from 'd3'; import * as d3sc from 'd3-scale-chromatic'; +import {merge} from 'lodash'; import { Tooltip } from 'react-tippy'; import Visualizer from './Visualizer.js'; -import {flags} from './flags.js'; -import {LPRCheckbox, NICheckbox, Modal} from './Reusables.js'; -import {lprStatics, niStatics, noteStatics} from './Statics.js'; import Legend from './Legend.js'; import Card from './Card.js'; +import {flags} from './Flags.js'; +import {LPRCheckbox, NICheckbox, Modal} from './Reusables.js'; +import {lprStatics, niStatics, noteStatics} from './Statics.js'; - -let playing; +//Variable Declarations export let lprScale = d3.scaleThreshold() .domain([0.05,0.1,0.25,0.75,1.5,4,7.5]) .range(d3sc.schemePuBuGn[9].slice(1)); @@ -23,6 +23,7 @@ export let niScale = d3.scaleThreshold() .range(d3sc.schemeYlGnBu[9].slice(1)); export let map; let yearBounds = [2005,2016]; +let playing; class App extends Component { @@ -39,7 +40,7 @@ class App extends Component { isPlaying: false, hoverCountry: null, map: null, - immigrationData: null, + datums: null, modal: true, //set to true before prod }; this.props.lprItems.forEach(function(item) { @@ -58,8 +59,8 @@ class App extends Component { render() { const selectedCategories = this.getSelectedCategories(); const selectedDataset = ( - this.state.immigrationData && - this.state.immigrationData[(this.state.radioDataset).toLowerCase()+this.state.dataYear] + this.state.datums && + this.state.datums[(this.state.radioDataset).toLowerCase()+this.state.dataYear] ); let countryImmigrationData = selectedDataset && selectedDataset.find(item => { @@ -69,8 +70,10 @@ class App extends Component { } else { countryImmigrationData = {}; } - const colors = (this.state.radioDataset === 'LPR') ? this.props.lprColors : this.props.niColors; - const thresholds = (this.state.radioDataset === 'LPR') ? this.props.lprThresholds : this.props.niThresholds; + const colors = (this.state.radioDataset === 'LPR') ? + this.props.lprColors : this.props.niColors; + const thresholds = (this.state.radioDataset === 'LPR') ? + this.props.lprThresholds : this.props.niThresholds; return ( @@ -94,24 +97,35 @@ class App extends Component {
{ this.D3box = div; }}> - +
+ + {/*Card Section*/} {this.state.hoverCountry && } + {/*Legend & Year Display Section*/}
- +
- + Data: US Department of Homeland Security, {this.state.dataYear}
@@ -120,7 +134,8 @@ class App extends Component {
@@ -139,10 +154,19 @@ class App extends Component {
@@ -150,10 +174,19 @@ class App extends Component {
@@ -165,7 +198,8 @@ class App extends Component {
{this.props.lprItems.map(function(item, index){ - return ; @@ -174,7 +208,8 @@ class App extends Component {
{this.props.niItems.map(function(item, index){ - return ; @@ -273,7 +308,7 @@ class App extends Component { loadData() { const self = this; - const immigrationData = {}; + const datums = {}; d3.json('./map_geo.json', (err,map) => { if (err) { @@ -285,8 +320,8 @@ class App extends Component { this.setState({map}) for (let i=yearBounds[0]; i <= yearBounds[1]; i++) { - immigrationData['lpr' + i] = makeMyData(i, 'lpr', combinerProgress, map); - immigrationData['ni' + i] = makeMyData(i, 'ni', combinerProgress, map); + datums['lpr' + i] = makeMyData(i, 'lpr', combinerProgress, map); + datums['ni' + i] = makeMyData(i, 'ni', combinerProgress, map); } } }); @@ -300,7 +335,7 @@ class App extends Component { combinator(map,csvData,flags,year,radioset); combinerProgress.filesLeft -= 1; if (combinerProgress.filesLeft === 0) { - self.setState({immigrationData}); + self.setState({datums}); } } }); @@ -331,14 +366,14 @@ class App extends Component { } let dataFlags = dataset.map(data => ({...data, href: flags.find( flag => flag[0] === data.ISO)[2] })) - immigrationData[radioset+year] = world.features.map(f => ({ + datums[radioset+year] = world.features.map(f => ({ type: 'Feature', id: f.properties.iso_a3, name: f.properties.name_long, formalName: f.properties.formal_en, population: f.properties.pop_est, geometry: f.geometry, - immigrationData: dataFlags.find(dataFlag => + immigrationData: dataFlags.find(dataFlag => //** maybe change? dataFlag.ISO === f.properties.iso_a3) }) ) diff --git a/src/Card.js b/src/Card.js index 3c25081..602cef1 100644 --- a/src/Card.js +++ b/src/Card.js @@ -1,8 +1,8 @@ -/*D3 Cards*/ + import React, { Component } from 'react'; import './Card.css'; -const cardWidth = 400; // how can i access the cardWidth? self.getBoundingClientRect().width? +const cardWidth = 400; //^ how can i access the cardWidth? self.getBoundingClientRect().width? class Card extends Component { @@ -16,6 +16,7 @@ class Card extends Component { return left-(cardWidth+25); } } + function yPlacement(top,bottom,height) { //only handles top issues if (top < 70) { return top+(height/2); //return top of D3box? @@ -40,9 +41,11 @@ class Card extends Component {

{countryImmigrationData.countryName}

{this.props.dataYear} Selected {this.props.radioDataset} Total: {this.props.radioDataset === "LPR" ? - selectedCategories.length === 6 ? countryImmigrationData.total.toLocaleString() + selectedCategories.length === 6 ? + countryImmigrationData.total.toLocaleString() : countryImmigrationData.countrySelectedTotal.toLocaleString() - : selectedCategories.length === 5 ? countryImmigrationData.total.toLocaleString() + : selectedCategories.length === 5 ? + countryImmigrationData.total.toLocaleString() : countryImmigrationData.countrySelectedTotal.toLocaleString()}

@@ -51,17 +54,23 @@ class Card extends Component { {this.props.radioDataset === "LPR" ?

Immediate Relative: {this.formatNumber(countryImmigrationData.immediateRelative)}

+ >Immediate Relative: + {this.formatNumber(countryImmigrationData.immediateRelative)}

Family-Sponsored: {this.formatNumber(countryImmigrationData.familySponsored)}

+ >Family-Sponsored: + {this.formatNumber(countryImmigrationData.familySponsored)}

Refugee & Asylee: {this.formatNumber(countryImmigrationData.refugeeAsylee)}

+ >Refugee & Asylee: + {this.formatNumber(countryImmigrationData.refugeeAsylee)}

Employment-Based: {this.formatNumber(countryImmigrationData.employmentBased)}

+ >Employment-Based: + {this.formatNumber(countryImmigrationData.employmentBased)}

Diversity Lottery: {this.formatNumber(countryImmigrationData.diversityLottery)}

+ >Diversity Lottery: + {this.formatNumber(countryImmigrationData.diversityLottery)}

Other: {this.formatNumber(countryImmigrationData.otherLPR)}

+ >Other: + {this.formatNumber(countryImmigrationData.otherLPR)}

:
}

Temporary Visitor: {this.formatNumber(countryImmigrationData.temporaryVisitor)}

+ >Temporary Visitor: + {this.formatNumber(countryImmigrationData.temporaryVisitor)}

Temporary Worker: {this.formatNumber(countryImmigrationData.temporaryWorker)}

+ >Temporary Worker: + {this.formatNumber(countryImmigrationData.temporaryWorker)}

Student & Exchange: {this.formatNumber(countryImmigrationData.studentExchange)}

+ >Student & Exchange: + {this.formatNumber(countryImmigrationData.studentExchange)}

Diplomat & Representative: {this.formatNumber(countryImmigrationData.diplomatRep)}

+ >Diplomat & Representative: + {this.formatNumber(countryImmigrationData.diplomatRep)}

Other: {this.formatNumber(countryImmigrationData.otherNI)}

+ >Other: + {this.formatNumber(countryImmigrationData.otherNI)}

:
}
{countryImmigrationData.countryNote &&
@@ -99,7 +113,6 @@ class Card extends Component { return 'counted-category'; } else return ''; } - } export default Card; diff --git a/src/Legend.js b/src/Legend.js index 4108a9b..2948803 100644 --- a/src/Legend.js +++ b/src/Legend.js @@ -1,9 +1,7 @@ -/*Legend*/ + import React, { Component } from 'react'; import './Legend.css'; -/*const reactContainer = document.getElementById('legend-holder'); -width = reactContainer.offsetWidth;*/ let width = 30; class Legend extends Component { @@ -26,6 +24,7 @@ class Legend extends Component {
); } + componentDidMount() { const self = this; Object.keys(this.elems).forEach(function(item){ @@ -41,10 +40,10 @@ class Legend extends Component { elem.style.left=(width-(elem.offsetWidth/2))+'px'; }) } + componentWillMount() { this.elems={}; } } - export default Legend; diff --git a/src/Reusables.js b/src/Reusables.js index d651ad2..28e254d 100644 --- a/src/Reusables.js +++ b/src/Reusables.js @@ -1,3 +1,4 @@ + import React, { Component } from 'react'; import { Tooltip } from 'react-tippy'; @@ -15,7 +16,7 @@ export class Modal extends Component {
image: andrewasmith + target="_blank" rel="noopener noreferrer"> andrewasmith
@@ -34,8 +35,13 @@ export class LPRCheckbox extends Component { onChange={(event) => {changeLPRCheckboxState(event.target.checked,name)}} id={name}> - + {label} @@ -55,8 +61,13 @@ export class NICheckbox extends Component { onChange={(event) => {changeNICheckboxState(event.target.checked,name)}} id={name}> - + {label} diff --git a/src/Statics.js b/src/Statics.js index d44a0cf..fb28357 100644 --- a/src/Statics.js +++ b/src/Statics.js @@ -1,3 +1,4 @@ + export let lprStatics = [ { name: "immediateRelative", diff --git a/src/Visualizer.js b/src/Visualizer.js index 72ec331..a86a0fb 100644 --- a/src/Visualizer.js +++ b/src/Visualizer.js @@ -1,4 +1,4 @@ -/*D3 Visualizer*/ + import React, { Component } from 'react'; import './Visualizer.css'; import * as d3 from 'd3'; @@ -16,21 +16,20 @@ class Visualizer extends Component { } componentWillReceiveProps(nextProps) { - const {map, selectedDataset, radioDataset, selectedCategories, modal} = nextProps; if (this.props.map !== map && this.props.map === null) { initializeD3(map); } + //to run once when data is available if (this.props.selectedDataset !== selectedDataset && this.props.selectedDataset === null) { - setInitialFillAndBindings(g, geoPath, selectedDataset, nextProps.saveAppState); //g, geoPath,selectedDataset, saveState + setInitialFillAndBindings(g, geoPath, selectedDataset, nextProps.saveAppState); } + //to run each time after initial data is available if (!modal && selectedDataset) { readData(selectedDataset, selectedCategories); - - //restyle choropleth paths d3.select('#d3-mount-point').selectAll('path') .data(selectedDataset) .attr('fill', (d) => fillChoropleth(d, radioDataset, calcWorldSelectedTotal(selectedDataset))) @@ -55,11 +54,11 @@ function initializeD3(worldMap) { .attr('height', height) .attr('max-height','90%') .attr('width', width) - .call(d3.zoom() //begin zoom functionality + .call(d3.zoom() //zoom functionality .scaleExtent([1,12]) .on('zoom',function() { svg.attr('transform',d3.event.transform) - })).append('g'); //end zoom functionality + })).append('g'); g = svg.append('g'); @@ -129,7 +128,7 @@ function setInitialFillAndBindings(g, geoPath,selectedDataset, saveState) { function handleMouseover(d, saveState, countryDOM) { const elementBox = countryDOM.getBoundingClientRect(); - console.log(elementBox); + console.log(elementBox); //^ remove before prod saveState({hoverCountry: { id: d.id, xLeft: elementBox.left,