Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Muli|Vollkorn" rel="stylesheet">
<link href="datastyle.css" type="text/css" media="all" rel="stylesheet">
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script src="https://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<svg width="800" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/d3-sankey@0.5"></script>
<style>
svg text {
font-size: 12px;
stroke-width: 0;
fill: black;
}
body {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Open Sans","Helvetica Neue",sans-serif;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
margin: 5px;
margin-bottom: 10px;
}
.tooltip {
line-height: 1;
padding: 12px;
border-radius: 2px;
}
</style>
<script>
var colours = {
"CDU_2015": "#000000",
"CDU_2017": "#000000",
"SPD_2015": "#E2001A",
"SPD_2017": "#E2001A",
"Gruene_2015": "#329A07",
"Gruene_2017": "#329A07",
"Linke_2015": "#8837C1",
"Linke_2017": "#8837C1",
"FDP_2015": "#FEC803",
"FDP_2017": "#FEC803",
"AfD_2015": "#1295FF",
"AfD_2017": "#1295FF",
"Nichtwaehler_2015": "#665370",
"Erstwaehler_2015": "#665370",
"Andere_2015": "#999999",
"Andere_2017": "#999999"
}
var svg = d3.select("svg"),
margin = {top: 50, right: 160, bottom: 50, left: 180},
width = +svg.attr("width") -margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background", "#fff")
.attr("class", "tooltip")
var stroke_opacity = 0.8;
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var formatNumber = d3.format(",.0f"),
color = d3.scaleOrdinal(d3.schemeCategory10);
var sankey = d3.sankey()
.nodeWidth(30)
.nodePadding(15)
.iterations(1)
.extent([[1, 1], [width - 1, height - 6]]);
var link = g.append("g")
.attr("class", "links")
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("path");
var node = g.append("g")
.attr("class", "nodes")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("g");
var indexLookup = {};
var pollNodes = {
"nodes": [],
"links": []
};
d3.json("poll.json", function(error, poll) {
if (error) throw error;
// first convert the data into a suitable format for generating a sankey diagram
// generate 2015 nodes
for (var party2017 in poll) {
if (party2017 == "CDU") {
for (var party2015 in poll[party2017]) {
if (party2015 !== "Total" && party2015 !== "Zugezogene") {
pollNodes["nodes"].push({
"name": party2015 + "_2015"
});
var currentSize = pollNodes["nodes"].length - 1;
indexLookup[party2015 + "_2015"] = currentSize;
}
}
}
if (party2017 !== "Linke" && party2017 !== "Gruene" && party2017 !== "AfD"
&& party2017 !== "ICannotVote" && party2017 !== "IWillSpoilMyBallot"
&& party2017 !== "IDoNotIntendToVote(ButIAmEligibleTo)") {
// generate 2017 nodes
pollNodes["nodes"].push({
"name": party2017 + "_2017"
});
}
var currentSize = pollNodes["nodes"].length - 1;
indexLookup[party2017 + "_2017"] = currentSize;
}
var total = 0;
for (var party2017 in poll) {
for (var party2015 in poll[party2017]) {
if (party2015 !== "Total" && party2015 !== "Zugezogene") {
if (poll[party2017][party2015] !== 0) {
pollNodes["links"].push({
"source": indexLookup[party2015 + "_2015"],
"target": indexLookup[party2017 + "_2017"],
"value": poll[party2017][party2015]
});
total += poll[party2017][party2015];
}
}
}
}
// tooltip Funktionen
function showtooltip1(d) {
d3.select(".tooltip")
.style("visibility", "visible")
.html(function() {
return d.name + "\n" + d.value;
})
}
function showtooltip(d) {
d3.select(".tooltip")
.style("visibility", "visible")
.html(function() {
if (d.source.name == "Nichtwaehler_2015" && d.target.name == "Nichtwaehler_2017") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>Nichtwähler</b> gingen 2017 ebenfalls nicht zur Wahl.";
}
if (d.source.name == "Nichtwaehler_2015") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>Nichtwähler</b> wählten 2017 die <b>" + d.target.name.slice(0, -5) + "</b>";
}
if (d.target.name == "Nichtwaehler_2017") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>" + d.source.name.slice(0, -5) + "</b>-Wähler gingen 2017 nicht wählen.";
}
if (d.source.name == "Andere_2015" && d.target.name == "Andere_2017") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>Wähler anderer kleiner Parteien</b> wählten 2017 <b>eine andere kleine Partei</b>.";
}
if (d.target.name == "Andere_2017") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>" + d.source.name.slice(0, -5) + "</b>-Wähler wählten 2017 eine andere kleine Partei.";
}
if (d.source.name == "Andere_2015") {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>Wähler anderer kleiner Parteien</b> wählten 2017 die <b>" + d.target.name.slice(0, -5) + "</b>";
}
else {
return "<b>" + d3.format(",d")(d.value).replace(',', '.').replace(',', '.') + " (" + Math.round(d.value / d.source.value * 100) + "%)</b> frühere <b>" + d.source.name.slice(0, -5) + "</b>-Wähler wählten 2017 die <b>" + d.target.name.slice(0, -5) + "</b>";
}
})
}
function hidetooltip(d) {
d3.select(".tooltip").style("visibility", "hidden")
}
// opacity Funktionen
function highlight(d) {
d3.select(d)
.style("stroke-opacity", 1)
}
function opacity(d) {
d3.select(d)
.style("stroke-opacity", 0.2)
}
function highlightall(d) {
svg.selectAll(".link")
.style("stroke-opacity", 1)
}
function colourLink(src){
//iterate through all the links for src
var link = d3.selectAll(".link")[0].filter(function(d){
return (d3.select(d).data()[0][0].name == src);
});
//for the filtered link make change stroke
d3.selectAll(link).style("stroke-opacity", 1);
}
function highlight_paths(stroke_opacity) {
return function(d,i){
d.sourceLinks.forEach(function(srcLnk){
d3.select(".links"+srcLnk.id).style("stroke-opacity", stroke_opacity);
});
d.targetLinks.forEach(function(srcLnk){
d3.select(".links"+srcLnk.id).style("stroke-opacity", stroke_opacity);
});
}
}
// generate sankey layout
sankey(pollNodes);
link = link
.data(pollNodes.links)
.enter().append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke-width", function(d) { return Math.max(1, d.dy); })
.attr("stroke", function(d) {
return colours[d.source.name];
})
.on("mouseover", function(d){
// console.log(d);
showtooltip(d);
highlight(this, d);
highlightall(d);
})
.on("mousemove", function(){
tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(d){
hidetooltip(d);
opacity(this, d);
});
node = node
.data(pollNodes.nodes)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("mouseover", function(d){
// console.log(d);
showtooltip1(d);
colourLink(d.name, name);
})
.on("mousemove", function(){
tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(d){
hidetooltip(d);
})
;
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.attr("fill", function(d) {
return colours[d.name] || "#D3D3D3";
})
.append("title");
// Beschriftung der Ströme mit Partei und Prozentzahl
node.append("text")
.attr("x", sankey.nodeWidth() + 10)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", "0.35em")
.attr("text-anchor", "start")
.attr("transform", null)
.text(function(d) { return d.name.slice(0, -5) + ": " + Math.round(d.value / total * 100) + "%"; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", sankey.nodeWidth() - 35)
.attr("text-anchor", "end");
});
</script>
Modified http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js to a secure url
https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js
https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js
https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js
https://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js
https://d3js.org/d3.v4.min.js
https://unpkg.com/d3-sankey@0.5