xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="container">
<h1>Il budget del comune di Torino</h1>
<form>
<label><input id="change2014" type="radio" name="dataset" value="val2014" checked="checked" /> 2014</label>
<label><input id="change2013" type="radio" name="dataset" value="val2013" /> 2013</label>
</form>
<p>Totale: <span id="total">xx</span> € - Procapite: <span id="perCapita">xx</span> €</p>
<div id="containerViz">
<div id="tooltip" class="hidden">
<p>
<strong><span id="voce"></span></strong>
</p>
<p>
<span class="tooltipTitle">Importo</span><br><span id="value"></span>
</p>
<p>
<span class="tooltipTitle">Percentuale</span><br><span id="percent"></span>
</p>
<p>
<span class="tooltipTitle">Procapite</span><br><span id="procapite"></span>
</p>
</div>
<script type="text/javascript">
//LOAD DATA
d3.json("data.json", function(error, json) {
if (error) {
console.log(error);
} else {
console.log(json);
dataset=json;
drawInner();
draw();
interactivity ();
change();
colorRanges();
}
})
//LAYOUT
var dataset;
var h = 500;
var w = 500;
var padding = 5;
var outerRadius = (w / 2)-padding;
var innerRadius = w / 3;
var innerRadiusInner = w / 4;
var greenRange = ["rgb(116,196,118)", "rgb(0,68,27)"];
var redRange = ["rgb(203,24,29)", "rgb(103,0,13)"];
var blueRange = ["rgb(33,113,181)", "rgb(8,48,107)"];
var colorInner = d3.scale.ordinal()
.domain(["funzioni", "rimborso prestiti", "altro"])
.range(["rgb(35,139,69)", "rgb(165,15,21)" , "rgb(8,81,156)"]);
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var arcInner = d3.svg.arc()
.innerRadius(innerRadiusInner)
.outerRadius(innerRadius);
var pie = d3.layout.pie()
.value(function(d) { return d.val2014; })
.sort(null)
.padAngle(.001);
var pieInner = d3.layout.pie()
.value(function(d) { return d.values; })
.sort(null)
.padAngle(.001);
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
function arcTweenInner(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arcInner(i(t));
};
}
function key(d) {
return d.data.key;
}
// Find the element in data0 that joins the highest preceding element in data1.
function findPreceding(i, data0, data1, key) {
var m = data0.length;
while (--i >= 0) {
var k = key(data1[i]);
for (var j = 0; j < m; ++j) {
if (key(data0[j]) === k) return data0[j];
}
}
}
// Find the element in data0 that joins the lowest following element in data1.
function findFollowing(i, data0, data1, key) {
var n = data1.length, m = data0.length;
while (++i < n) {
var k = key(data1[i]);
for (var j = 0; j < m; ++j) {
if (key(data0[j]) === k) return data0[j];
}
}
}
function findNeighborArc(i, data0, data1, key) {
var d;
return (d = findPreceding(i, data0, data1, key)) ? {startAngle: d.endAngle, endAngle: d.endAngle}
: (d = findFollowing(i, data0, data1, key)) ? {startAngle: d.startAngle, endAngle: d.startAngle}
: null;
}
//Add commas every three digits (tooltip)
function commafy( num ) {
var str = num.toString().split('.');
if (str[0].length >= 5) {
str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, "$1'");
}
if (str[1] && str[1].length >= 5) {
str[1] = str[1].replace(/(\d{3})/g, '$1 ');
}
return str.join('.');
}
function colorRanges () {
countFunzioni=0;
dataset.forEach (function (d) {if (d.categoria=="funzioni") { countFunzioni += 1; d.catIndex = countFunzioni;}})
countRimborso=0;
dataset.forEach (function (d) {if (d.categoria=="rimborso prestiti") { countRimborso += 1; d.catIndex = countRimborso;}})
countAltro=0;
dataset.forEach (function (d) {if (d.categoria=="altro") { countAltro += 1; d.catIndex = countAltro;}})
colorFunzioni = d3.scale.linear()
.domain([0, countFunzioni])
.range(greenRange);
colorRimborso = d3.scale.linear()
.domain([0, countRimborso])
.range(redRange);
colorAltro = d3.scale.linear()
.domain([0, countAltro])
.range(blueRange);
}
function coloring (d, i) {
colorRanges();
colorMap = {
"funzioni": colorFunzioni,
"altro": colorAltro,
"rimborso prestiti": colorRimborso
}
var scale = colorMap[d.data.categoria];
if (scale) return scale(d.data.catIndex);
}
function drawInner () {
nestCategoria = d3.nest()
.key(function (d) {return d.categoria;})
.rollup(function (d) {return d3.sum(d, function (g) {return g.val2014;});})
.entries(dataset)
chartInner = d3.select("#containerViz")
.append("svg")
.attr("id", "visualizationInner")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
pathInner = chartInner.datum(nestCategoria).selectAll("path")
.data(pieInner(nestCategoria))
.enter()
.append("path")
.attr("fill", function(d, i) { return colorInner(i); })
.style("fill-opacity", 0.8)
.attr("d", arcInner)
.each(function (d) { this._current = d; });
}
function draw () {
chart = d3.select("#visualizationInner")
.append("svg")
.attr("id", "visualization")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
path = chart.datum(dataset).selectAll("path")
.data(pie(dataset))
.enter()
.append("path")
.attr("fill", coloring)
.style("fill-opacity", 0.8)
.attr("d", arc)
.each(function (d) { this._current = d; });
var total = d3.sum(dataset.map(function(d) { return d.val2014;}));
total = commafy(total);
d3.select("#total").text(function () {return total;})
}
function interactivity () {
d3.selectAll("path").on("mouseover", function (d) {
var total = d3.sum(dataset.map(function(d) { return d.val2014;}));
var percent = Math.round(1000 * d.value / total) / 10;
var valueNew = d.value;
valueNew = commafy(valueNew);
//highlight
d3.select(this)
.style("fill-opacity", 1)
//update tooltip text
d3.select("#tooltip")
.select("#voce")
.text(d.data.key);
d3.select("#tooltip")
.select("#value")
.text(valueNew + " €");
d3.select("#tooltip")
.select("#percent")
.text(percent + " %");
//display tooltip
d3.select("#tooltip")
//.style("left", w/2 + "px")
.style("top", h/2 + "px")
.classed("hidden", false)
})
d3.selectAll("path").on("mouseout", function () {
//remove highlihgt
d3.select(this)
.style("fill-opacity", 0.8)
//hide tooltip
d3.select("#tooltip")
.classed("hidden", true)
})
d3.selectAll("path").on("click", function (d) {
//update tooltip title
d3.select("#descrTitle")
.text(d.data.descrTitle)
//update tooltip text
d3.select("#descrText")
.html(d.data.descrText)
//update tooltip image
descrImg = d3.select("#descrImg");
descrImg.select("svg").remove(); //removes previous image
d3.selectAll("path").attr("stroke-width", 0); //remove previous stroke
descrImgURI = d.data.descrImg;
fillColor = d3.select(this).attr("fill"); //extract color
d3.select(this).attr("stroke", fillColor);
d3.select(this).attr("stroke-width", 3);
d3.xml(descrImgURI, "image/svg+xml", function(error, xml) {
if (error) throw error;
var svg= xml.documentElement;
descrImg.node().appendChild(svg);
var a = document.getElementById("Ebene_1");
var b = a.getElementsByTagName("circle")[0];
var c = a.getElementsByTagName("path");
d3.select(b).attr("fill", fillColor);
d3.selectAll(c).attr("fill", "white");
});
})
}
function change() {
function newPie () {
// path.data(pie); // compute the new angles
// path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
var data0 = path.data();
path = path.data(data1, key);
path.enter().append("path")
.each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; })
.attr("fill", coloring)
path.exit()
.datum(function(d, i) { return findNeighborArc(i, data1, data0, key) || d; })
.transition()
.duration(750)
.attrTween("d", arcTween)
.remove();
path.transition()
.duration(750)
.attrTween("d", arcTween);
}
function newPieInner() {
pathInner.data(pieInner(nestCategoria)); // compute the new angles
pathInner.transition().duration(750).attrTween("d", arcTweenInner); // redraw the arcs
}
d3.select("#change2013").on("click", function() {
//change total
var total = d3.sum(dataset.map(function(d) { return d.val2013;}));
total = commafy(total);
d3.select("#total").text(function () {return total;})
data1 = pie.value(function (d) { return d.val2013; }); // change the value function
newPie();
nestCategoria = d3.nest()
.key(function (d) {return d.categoria;})
.rollup(function (d) {return d3.sum(d, function (g) {return g.val2013;});})
.entries(dataset)
newPieInner();
});
d3.select("#change2014").on("click", function() {
//change total
var total = d3.sum(dataset.map(function(d) { return d.val2014;}));
total = commafy(total);
d3.select("#total").text(function () {return total;})
data1 = pie.value(function (d) { return d.val2014; }); // change the value function
newPie();
nestCategoria = d3.nest()
.key(function (d) {return d.categoria;})
.rollup(function (d) {return d3.sum(d, function (g) {return g.val2014;});})
.entries(dataset)
newPieInner();
});
}
</script>
</div> <!-- containerViz -->
<div class="description hidden" id="funzioni">
<span id="descrImg"></span>
<p><strong><span id="descrTitle">Istruzioni</strong></span></p>
<p><span id="descrText">Clicca sulla fetta di torta per ottenere maggiori informazioni riguardo alla funzione governativa.</span></p>
</div>
</div> <!-- container -->
</body>
</html>
https://d3js.org/d3.v3.min.js