Skip to content
Permalink
10c93fb291
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
160 lines (135 sloc) 5.1 KB
import React, { Component } from 'react';
import * as d3 from 'd3';
import * as topojson from 'topojson-client';
import _ from 'lodash';
function migrationSources(data, centroids, nameIdMap) {
return Object.keys(data.sources)
.filter(name => centroids[nameIdMap[name]])
.filter(name => data.sources[name] !== 0)
}
const Map = ({ topology, projection, data, nameIdMap, focusCountry }) => {
const D = d3.geoPath(projection),
countries = topojson.feature(topology, topology.objects.countries),
centroids = _.fromPairs(countries.features
.map(country => [country.id,
D.centroid(country)])),
idNameMap = _.invert(nameIdMap);
let sources = [],
focusData = data.find(({ id }) => id === focusCountry),
colorScale = _.noop;
if (focusData) {
console.log(focusData);
sources = migrationSources(focusData,
centroids, nameIdMap);
colorScale = d3.scaleLog()
.domain(d3.extent(sources.map(name => focusData.sources[name])))
.range([0, 1]);
}
const isSource = (country) => sources.includes(idNameMap[country.id]),
color = (country) => {
if (isSource(country) && focusData){
return d3.interpolateWarm(colorScale(
focusData.sources[idNameMap[country.id]]
));
}else{
return 'grey';
}
};
return (
<g>
{countries.features.map((country, i) => (
<path d={D(country)}
key={`${country.id}-${i}`}
style={{stroke: 'white',
strokeWidth: '0.25px',
fillOpacity: isSource(country) ? 1 : 0.5,
fill: color(country)}} />
))}
</g>
);
};
const Curve = ({ start, end, color }) => {
const line = d3.line()
.curve(d3.curveBasis),
[x1, y1] = start,
[x2, y2] = end,
middle = [(x1 + x2)/2, (y1 + y2)/2-200];
return (
<path d={line([start, middle, end])}
style={{stroke: color,
strokeWidth: '1.6px',
strokeOpacity: '0.7',
fillOpacity: 0}} />
);
};
const CountryMigrations = ({ data, nameIdMap, centroids }) => {
const destination = centroids[data.id];
const sources = migrationSources(data, centroids, nameIdMap),
color = d3.scaleLog()
.domain(d3.extent(sources.map(name => data.sources[name])))
.range([0, 1]);
console.log(d3.extent(sources.map(name => data.sources[name])));
return (
<g>
{sources.map((name, i) => (
<Curve start={centroids[nameIdMap[name]]} end={destination}
color={d3.interpolateWarm(color(data.sources[name]))}
key={`${data.id}-${i}`} />
))}
</g>
)
};
const Migrations = ({ topology, projection, data, nameIdMap, focusCountry }) => {
if (!data) {
return null;
}
const countries = topojson.feature(topology, topology.objects.countries),
path = d3.geoPath(projection),
centroids = _.fromPairs(countries.features
.map(country => [country.id,
path.centroid(country)]));
const dataToDraw = data.filter(({ id }) => id === focusCountry)
.filter(({ id }) => !!centroids[id]);
return (
<g>
{dataToDraw.map(data => (
<CountryMigrations data={data} nameIdMap={nameIdMap}
centroids={centroids}
key={`migrations-${data.id}`} />
))}
</g>
);
};
class World extends Component {
state = {
topology: null
}
projection = d3.geoEquirectangular()
.center([-50, 40])
.scale(200)
componentWillMount() {
d3.json('data/world-110m.v1.json',
(err, topology) => {
this.setState({
topology: topology
});
});
}
render() {
const { width, height } = this.props,
{ topology } = this.state;
if (!topology) {
return null;
}
return (
<svg width={width} height={height}>
<Map topology={topology} projection={this.projection} data={this.props.data}
nameIdMap={this.props.nameIdMap} focusCountry={this.props.focusCountry} />
<Migrations topology={topology} projection={this.projection}
data={this.props.data} nameIdMap={this.props.nameIdMap}
focusCountry={this.props.focusCountry} />
</svg>
)
}
}
export { World };