var votes = [];
var quartiles = [[0.25,0.5,0.75],[0.25,0.5,0.75],[0.25,0.5,0.75],[0.25,0.5,0.75]];
var ranges = [[0.0,1.0],[0.0,1.0],[0.0,1.0],[0.0,1.0]];
var x_axis = [0,0,0,0];
var x = [0,0,0,0];
var width = 0;
var height = 0;
$(document).ready(initMaps);
/**
* Initializes all maps, legends and boxplots and and starts aynchronous loading of map data
*/
function initMaps(){
for (var i = 0; i < 4; i++) {
votes.push(d3.map());
// get map properties
var svg = d3.select(".map"+i);
width = $(".map"+i).width();
height = $("#svgWrapper").height()/2-10;
$(".map"+i).attr("height", height);
// add scale
var g = svg.append("g")
.attr("class", "key")
.attr("transform", "translate(30,14) scale(0.9,0.9)");
// create scale variable x
x[i] = d3.scaleLinear()
.domain([0, 1])
.rangeRound([0, width]); // size of scale top right
// plot scale
x_axis[i] = d3.axisBottom(x[i]);
g.call(x_axis[i])
.select(".domain")
.remove();
// plot boxplot
var boxplot = g.append("g")
.attr("class", "boxplot")
.attr("transform", "translate(0,20)");
var boxheight = 12;
boxplot.append("line")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", 0)
.attr("y2", boxheight);
boxplot.append("line")
.attr("x1", width)
.attr("x2", width)
.attr("y1", 0)
.attr("y2", boxheight);
boxplot.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", boxheight/2)
.attr("y2", boxheight/2);
boxplot.append("rect")
.attr("id", "lbox")
.attr("x", width*0.25)
.attr("y", 0)
.attr("width", width*0.25)
.attr("height", boxheight);
boxplot.append("rect")
.attr("id","rbox")
.attr("x", width*0.5)
.attr("y", 0)
.attr("width", width*0.25)
.attr("height", boxheight);
g.append("text")
.attr("class", "caption")
.attr("x", x[i].range()[0])
.attr("y", -6)
.attr("fill", "#000")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("font-size", "14")
.text("Van der Bellen");
// Plot color scale
values = [];
for (let i=0; i<width; i++){
var legenditem = {};
legenditem.index = i;
legenditem.value = i/width;
legenditem.color = valueToColor(legenditem.value, i);
values.push(legenditem);
}
var legend = g.selectAll("rect").data(values).enter().append("rect")
.attr("fill", (d) => d.color)
.attr("x", (d) => d.index)
.attr("width", 1)
.attr("height", 6);
// load map async
d3.queue()
.defer(d3.json, $(".map"+i).data("geo"))
.defer(d3.csv, $(".map"+i).data("csv"), setVotes(i))
.defer(d3.json, $(".map"+i).data("geo"))
.await(readyMap(i, svg));
/**
* Returns a map construction function which should be called for every submap with the asynchronously loaded map data
*
* @param {integer} i - the mapindex for which the vote should be set
* @param {d3.Selection<SVGElement>} svg - the maps svg object selected via d3 selection
* @returns {function} the map constuction function
*/
function readyMap(i, svg) {
return (error, json) => {
if (error) throw error;
// create projection
var projection = d3.geoMercator().translate([0, 0]).scale(1);
var path = d3.geoPath().projection(projection);
// create temp geojson to get boundingbox for view bounds
var boundsCollection = { type: "FeatureCollection", features: []}
for (var key in json.objects) {
if (json.objects.hasOwnProperty(key)) {
var layer = json.objects[key]; // Topojson unpacks one layer at a time
var geojson = topojson.feature(json, layer);
boundsCollection.features = boundsCollection.features.concat( geojson.features );
};
}
// Calculate bounding box transforms for entire collection
var b = path.bounds(boundsCollection),
s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height * 1.20),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2 + 20];
projection.scale(s).translate(t); // Update the projection for view bounds
// add element per map-part
svg.append("g")
.attr("class", "counties")
.selectAll("path")
.data(topojson.feature(json, json.objects.gemeinden).features)
.enter().append("path")
.attr("fill", (d) => valueToColor(d.vote = votes[i].get(+d.properties.iso), i))
.attr("d", path)
.append("title")
.text((d) => +(d.vote*100).toFixed(2) + "%");
}
}
}
}
/**
* Returns a function to set votes of a specific submap referenced by the mapindex i
*
* @param {integer} i - the mapindex for which the vote should be set
* @returns {function} the votes setting function
*/
function setVotes(i) {
return (d) => {
let returnValue = votes[i].set(d.iso, d.vdb / d.gueltig);
return returnValue;
};
}
/**
* Initiates a color update and shows a waiting spinner in the meantime
*/
function updateColors(){
// Show spinner and call fill()
console.log("Updating Colors");
setTimeout("document.getElementById(\"svgSpinner\").style.display='initial'",0);
setTimeout("fill()",100);
}
/**
* Fills all maps and color scales with a new color and updates the boxplots as well
*/
function fill(){
for (i = 0; i < 4; i++) {
map = d3.select(".map"+i);
q = quartiles[i];
r = ranges[i];
// Update scale number values
x[i].domain(ranges[i]);
map.selectAll(".key").transition().call(x_axis[i]);
// Update scale color values
map.selectAll(".key rect").attr("fill", (d) => valueToColor(d.value*(r[1]-r[0])+r[0], i));
// Update boxplot
map.select(".boxplot #lbox").transition()
.attr("x", width*q[0])
.attr("width", width*(q[1]-q[0]));
map.select(".boxplot #rbox").transition()
.attr("x", width*quartiles[i][1])
.attr("width", width*(q[2]-q[1]));
// Update map colors
map.selectAll(".counties path").attr("fill", (d) => valueToColor(d.vote, i));
}
document.getElementById("svgSpinner").style.display='none';
}