A responsive (and label-less) version of Laris Karklis's Ukraine's language divide map using D3.
Original language data from the Ukraine Census. Spatial data from Natural Earth.
A responsive (and label-less) version of Laris Karklis's Ukraine's language divide map using D3.
Original language data from the Ukraine Census. Spatial data from Natural Earth.
<!DOCTYPE html> | |
<meta charset='utf-8'> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, minimum-scale=1.0, maximum-scale=1.0"> | |
<style> | |
body { | |
width: 100%; | |
max-width: 600px; | |
margin: auto; | |
} | |
.country { | |
fill: #E7E7E7; | |
stroke: none; | |
} | |
.country-boundary { | |
fill: none; | |
stroke: #999; | |
} | |
.region { | |
stroke: none; | |
} | |
.region-boundary { | |
fill: none; | |
stroke: #424242; | |
stroke-dasharray: 2 2; | |
stroke-linejoin: round; | |
opacity: 0.5; | |
} | |
.ukraine-boundary { | |
fill: none; | |
stroke: #333; | |
} | |
.river { | |
fill: none; | |
stroke: #fff; | |
} | |
.lake { | |
fill: #fff; | |
stroke: none; | |
} | |
</style> | |
<body> | |
<div id='map'></div> | |
<script src='http://d3js.org/d3.v3.min.js'></script> | |
<script src='http://d3js.org/topojson.v1.min.js'></script> | |
<script> | |
var mapScale = 4.35; | |
var mapRatio = .65; | |
var width = parseInt(d3.select('#map').style('width')); | |
var height = width * mapRatio; | |
var projection = d3.geo.albers() | |
.center([0, 48.5]) | |
.rotate([-31.5, 0]) | |
.parallels([45, 50]) | |
.scale(width * mapScale) | |
.translate([width / 2, height / 2]); | |
var color = d3.scale.threshold() | |
.domain([10, 20, 30, 50]) | |
.range(['#F7CB6D', '#C4AA73', '#899BAD', '#739AC4', '#2E5C8A']) | |
var svg = d3.select('#map').append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
var countriesPath; | |
var regionsPath; | |
var riversPath; | |
var lakesPath; | |
d3.json('ukraine.json', function(error, data) { | |
var countries = topojson.feature(data, data.objects.countries); | |
countriesPath = d3.geo.path() | |
.projection(projection); | |
svg.selectAll('.country') | |
.data(countries.features) | |
.enter().append('path') | |
.attr('class', 'country') | |
.attr('d', countriesPath) | |
var countryBoundaries = topojson.mesh(data, data.objects.countries, | |
function(a, b) { return a !== b }); | |
svg.append('path') | |
.datum(countryBoundaries) | |
.attr('class', 'country-boundary') | |
.attr('d', countriesPath) | |
var regions = topojson.feature(data, data.objects['ukraine-regions']); | |
regionsPath = d3.geo.path() | |
.projection(projection); | |
svg.selectAll('.region') | |
.data(regions.features) | |
.enter().append('path') | |
.attr('class', 'region') | |
.attr('d', regionsPath) | |
.style('fill', function(d) { return color(d.properties.percent); }) | |
var rivers = topojson.feature(data, data.objects['rivers_lake_centerlines']); | |
riversPath = d3.geo.path() | |
.projection(projection); | |
svg.selectAll('.river') | |
.data(rivers.features) | |
.enter().append('path') | |
.attr('class', 'river') | |
.attr('d', riversPath) | |
var lakes = topojson.feature(data, data.objects.lakes); | |
lakesPath = d3.geo.path() | |
.projection(projection); | |
svg.selectAll('.lake') | |
.data(lakes.features) | |
.enter().append('path') | |
.attr('class', 'lake') | |
.attr('d', lakesPath) | |
var ukraineRegionBoundaries = topojson.mesh(data, | |
data.objects['ukraine-regions'], function(a, b) { return a !== b }); | |
svg.append('path') | |
.datum(ukraineRegionBoundaries) | |
.attr('d', regionsPath) | |
.attr('class', 'region-boundary') | |
var ukraineBoundaries = topojson.mesh(data, | |
data.objects['ukraine-regions'], function(a, b) { return a === b }); | |
svg.append('path') | |
.datum(ukraineBoundaries) | |
.attr('d', regionsPath) | |
.attr('class', 'ukraine-boundary') | |
d3.select(window).on('resize', resize); | |
}); | |
function resize() { | |
width = parseInt(d3.select('#map').style('width')); | |
height = width * mapRatio; | |
svg | |
.style('width', width + 'px') | |
.style('height', height + 'px'); | |
svg.selectAll('.country,.country-boundary').attr('d', countriesPath); | |
svg.selectAll('.region,.region-boundary,.ukraine-boundary').attr('d', regionsPath); | |
svg.selectAll('.lake').attr('d', lakesPath); | |
svg.selectAll('.river').attr('d', riversPath); | |
projection | |
.scale(width * mapScale) | |
.translate([width / 2, height / 2]); | |
} | |
</script> |
GENERATED_FILES = \ | |
build/ne_10m_admin_1_states_provinces.shp \ | |
build/ne_10m_admin_0_countries.shp \ | |
public/ukraine.json | |
LIBRARY_FILES = \ | |
public/lib/d3.v3.min.js \ | |
public/lib/topojson.v1.min.js \ | |
BOUNDS = 19.0 43.2 42.3 53.3 | |
all: $(GENERATED_FILES) $(LIBRARY_FILES) | |
clean: | |
rm -rf build | |
rm -rf $(GENERATED_FILES) $(LIBRARY_FILES) | |
build/ne_10m_admin_1_states_provinces.zip: | |
mkdir -p build | |
curl -o $@.download "http://www.nacis.org/naturalearth/10m/cultural/ne_10m_admin_1_states_provinces.zip" | |
mv $@.download $@ | |
build/ne_10m_admin_1_states_provinces.shp: build/ne_10m_admin_1_states_provinces.zip | |
unzip -d build $< | |
touch build/ne_10m_admin_1_states_provinces.* | |
build/ne_10m_admin_0_countries.zip: | |
mkdir -p build | |
curl -o $@.download "http://www.nacis.org/naturalearth/10m/cultural/ne_10m_admin_0_countries.zip" | |
mv $@.download $@ | |
build/ne_10m_admin_0_countries.shp: build/ne_10m_admin_0_countries.zip | |
unzip -d build $< | |
touch build/ne_10m_admin_0_countries.* | |
build/ne_10m_lakes.zip: | |
mkdir -p build | |
curl -o $@.download "http://www.nacis.org/naturalearth/10m/physical/ne_10m_lakes.zip" | |
mv $@.download $@ | |
build/ne_10m_rivers_lake_centerlines.zip: | |
mkdir -p build | |
curl -o $@.download "http://www.nacis.org/naturalearth/10m/physical/ne_10m_rivers_lake_centerlines.zip" | |
mv $@.download $@ | |
build/ne_10m_lakes.shp: build/ne_10m_lakes.zip | |
unzip -d build $< | |
touch build/ne_10m_lakes.* | |
build/ne_10m_rivers_lake_centerlines.shp: build/ne_10m_rivers_lake_centerlines.zip | |
unzip -d build $< | |
touch build/ne_10m_rivers_lake_centerlines.* | |
build/ukraine-regions.json: build/ne_10m_admin_1_states_provinces.shp | |
mkdir -p build | |
rm -f $@ | |
ogr2ogr -f GeoJSON -where "ADM0_A3 IN ('UKR')" -clipsrc $(BOUNDS) $@ $< | |
build/countries.json: build/ne_10m_admin_0_countries.shp | |
mkdir -p build | |
rm -f $@ | |
ogr2ogr -f GeoJSON -clipsrc $(BOUNDS) $@ $< | |
build/lakes.json: build/ne_10m_lakes.shp | |
mkdir -p build | |
rm -f $@ | |
ogr2ogr -f GeoJSON -clipsrc $(BOUNDS) $@ $< | |
build/rivers_lake_centerlines.json: build/ne_10m_rivers_lake_centerlines.shp | |
mkdir -p build | |
rm -f $@ | |
ogr2ogr -f GeoJSON -clipsrc $(BOUNDS) $@ $< | |
public/ukraine.json: build/ukraine-regions.json build/countries.json build/lakes.json build/rivers_lake_centerlines.json data/regions-speaking-russian.csv | |
topojson -o $@ -q 1e4 -e data/regions-speaking-russian.csv \ | |
--id-property adm1_code -p +percent,name \ | |
-- build/ukraine-regions.json build/countries.json build/lakes.json \ | |
build/rivers_lake_centerlines.json | |
public/lib/d3.v3.min.js: | |
mkdir -p public/lib | |
curl -o $@ "http://d3js.org/d3.v3.min.js" | |
public/lib/topojson.v1.min.js: | |
mkdir -p public/lib | |
curl -o $@ "http://d3js.org/topojson.v1.min.js" |
adm1_code | Region | percent | |
---|---|---|---|
Ukraina | 29.59 | ||
UKR-283 | Avtonomna Respublika Krym | 76.55 | |
UKR-323 | Vinnytska oblast | 4.74 | |
UKR-318 | Volynska oblast | 2.51 | |
UKR-326 | Dnipropetrovska oblast | 31.91 | |
UKR-327 | Donetska oblast | 74.92 | |
UKR-324 | Zhytomyrska oblast | 6.57 | |
UKR-293 | Zakarpatska oblast | 2.90 | |
UKR-331 | Zaporizka oblast | 48.19 | |
UKR-289 | Ivano-Frankivska oblast | 1.78 | |
UKR-321 | Kyivska oblast | 7.17 | |
UKR-320 | Kirovohradska oblast | 10.02 | |
UKR-329 | Luhanska oblast | 68.84 | |
UKR-291 | Lvivska oblast | 3.77 | |
UKR-284 | Mykolaivska oblast | 29.26 | |
UKR-322 | Odeska oblast | 41.95 | |
UKR-330 | Poltavska oblast | 9.47 | |
UKR-286 | Rivnenska oblast | 2.73 | |
UKR-325 | Sumska oblast | 15.50 | |
UKR-292 | Ternopilska oblast | 1.19 | |
UKR-328 | Kharkivska oblast | 44.29 | |
UKR-4827 | Khersonska oblast | 24.86 | |
UKR-290 | Khmelnytska oblast | 4.09 | |
UKR-319 | Cherkaska oblast | 6.66 | |
UKR-288 | Chernivetska oblast | 5.27 | |
UKR-285 | Chernihivska oblast | 10.26 | |
UKR-4826 | m. Kyiv | 25.27 | |
UKR-5482 | m. Sevastopol | 90.56 |