This is an advanced version of my own block: Global Corporate Tax Rates in 2015. Now we can select the year of data by using the drop-down menu.
And this is forked from the "Object Constancy" tutorial written by Mike Bostock.
Also Proudly Built with blockbuilder.org
Fetch from KPMG in June 2016.
For more information please visit Wikipedia and read: "List of countries by tax rates".
forked from VioletVivirand's block: Global Corporate Tax Rates from 2006 to 2016: /violetvivirand/88867d3fb2f50d13e00a0113280848b4
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style>
/*@import url(./style.css);*/
div#menu {
margin-left: 60px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
svg {
font: 10px sans-serif;
}
/*.bar rect {
fill: steelblue;
}*/
.bar:hover rect {
fill: #90EE90 !important;
}
.value {
fill: steelblue;
}
.axis {
shape-rendering: crispEdges;
}
.axis path {
stroke: none;
}
.x.axis line {
stroke: #fff;
stroke-opacity: .8;
}
.y.axis path {
stroke: black;
}
</style>
</head>
<body>
<div id="menu">
<h2>Global Corporate Tax Rate</h2>
<br>Data Source: <a href="https://home.kpmg.com/xx/en/home/services/tax/tax-tools-and-resources/tax-rates-online/corporate-tax-rates-table.html">KPMG</a>, fetched in June, 2016.
<br>For more information please visit Wikipedia and read: <a href="https://en.wikipedia.org/wiki/List_of_countries_by_tax_rates">"List of countries by tax rates"</a>
<br>Year Selection:
<select></select>
</div>
<div id="chart">
<script>
var margin = {
top: 20,
right: 60,
bottom: 10,
left: 160
},
width = 960,
height = 2000 - margin.top - margin.bottom,
textLabelDistance = 5; // Text Label 跟 Bar 的 Rect Element 之間的距離
// var format = d3.format(".1%"); // 原本範例中,資料是介於 0~1 的值,所以用這個方法做成百分比
// Format 的寫法 可以參考:
// https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3_format
var taxData;
var year;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .1);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top")
.tickSize(-height - margin.bottom)
.tickFormat(function(d) {
return d + '%';
});
// .tickFormat(format);
var svg = d3.select("div#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
// .style("margin-left", margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var color = d3.scale.linear()
.range(["#FFC0CB", "#C71585"]);
svg.append("g")
.attr("class", "x axis");
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("class", "domain")
.attr("y2", height);
var menu = d3.select("div#menu select")
.on("change", change);
d3.csv("global-tax.csv", function(data) {
taxData = data;
// 把資料 CSV 檔的第一列讀取出來(也就是texData[0]),
// 並且把不是年份的欄位名稱排除
// (在這個例子裡,id, country, footnotes 三個欄位不是)
var years = d3.keys(taxData[0]).filter(function(key) {
return key != "id" && key != "country" && key != "footnotes";
}).sort(function(a, b) { // 將年份依大小遞減排序
return b - a;
});;
// 將年份資料寫入下拉式選單中
menu.selectAll("option")
.data(years)
.enter().append("option")
.text(function(d) {
return d;
});
// 指定網頁開啟時,下拉式選單預設的選項
menu.property("value", "2016"); // First time selection
// 開始繪圖
redraw();
});
// var altKey;
// d3.select(window)
// .on("keydown", function() {
// altKey = d3.event.altKey;
// })
// .on("keyup", function() {
// altKey = false;
// });
function change() {
// clearTimeout(timeout);
d3.transition()
// .duration(altKey ? 7500 : 750)
// .duration(750)
.duration(0) // 要出現漸變效果的動畫,要修改為較大的數值
.each(redraw);
}
function redraw() {
var selectedYear = menu.property("value"); // 下拉式選單裡面選的年份,用這個方法來擷取
// 因為這筆資料裡面,有些稅率值為空(可能沒有資料),
// 為了要讓圖表顯示正常,我要先把空資料轉為 "-1",
// 連帶的,等一下圖表 Rect Element 的長度、顯示的 Text Label,
// 也要依照這個規則做些修改
taxData.forEach(function(element, index, array) {
if (array[index][selectedYear] == "") {
array[index][selectedYear] = "-1";
}
});
var sortedData = taxData.sort(function(a, b) { // 把該年度的資料依照數字大小遞減排序
return b[selectedYear] - a[selectedYear];
}); // 想取排行前 n 名的資料,可以加上 .slice(0,n)
x.domain([0, sortedData[0][year = selectedYear]]);
y.domain(sortedData.map(function(d) {
return d["country"];
}));
color.domain([0, sortedData[0][year = selectedYear]]);
// 1: 每次執行繪圖時,都先重新綁定所選擇的資料
var bar = svg.selectAll(".bar")
.data(sortedData, function(d) {
// console.log("1"); // Debug
return d["country"];
});
// 2
var barEnter = bar.enter().insert("g", ".axis")
.attr("class", "bar")
.attr("transform", function(d) {
// console.log("2"); // Debug
return "translate(0," + (y(d["country"]) + height) + ")";
})
.style("fill-opacity", 0);
// 3
barEnter.append("rect")
.attr("width", year && function(d) {
// console.log("3"); // Debug
// 因為空資料的值被改為 "-1",所以要下一個判斷:
// 如果資料為 "-1",就把 width 直接訂為 0
return d[year] == "-1" ? 0 : x(d[year]);
})
.attr("height", y.rangeBand())
.style("fill", function(d) {
return color(d[year])
});
// 4
barEnter.append("text")
.attr("class", "label")
.attr("x", -3)
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.attr("text-anchor", "end")
.text(function(d) {
// console.log("4"); // Debug
return d["country"];
});
// 5
barEnter.append("text")
.attr("class", "value")
// .attr("x", year && function(d) { // 看不懂原本的範例裡加上 year && 的原因
.attr("x", function(d) {
// console.log("5"); // Debug
// 因為空資料的值被改為 "-1",所以要下一個判斷:
// 如果資料為 "-1",就把位移值 x 直接訂為 textLabelDistance
return d[year] == "-1" ? textLabelDistance : x(d[year]) + textLabelDistance;
})
.attr("y", y.rangeBand() / 2)
.attr("dy", ".35em")
.attr("text-anchor", "start");
// 6
var barUpdate = d3.transition(bar)
.attr("transform", function(d) {
// console.log("6"); // Debug
return "translate(0," + (d.y0 = y(d["country"])) + ")";
})
.style("fill-opacity", 1);
// 7
barUpdate.select("rect")
.attr("width", function(d) {
// console.log("7"); // Debug
// 因為空資料的值被改為 "-1",所以要下一個判斷:
// 如果資料為 "-1",就把 width 直接訂為 0
return d[year] == "-1" ? 0 : x(d[year]);
})
.style("fill", function(d) {
return color(d[year])
});
// 8
barUpdate.select(".value")
.attr("x", function(d) {
// console.log("8"); // Debug
// 如果資料為 "-1",就把位移值 x 直接訂為 textLabelDistance
return d[year] == "-1" ? textLabelDistance : x(d[year]) + textLabelDistance;
})
.text(function(d) {
// return format(d[age]);
// 空資料被轉為 "-1" 了,所以值為 "-1" 的資料,
// 就顯示 "No Data."
return d[year] == "-1" ? "No Data." : d[year] + " %";
});
// 9
var barExit = d3.transition(bar.exit())
.attr("transform", function(d) {
// console.log("9"); // Debug
return "translate(0," + (d.y0 + height) + ")";
})
.style("fill-opacity", 0)
.remove();
// 10
barExit.select("rect")
.attr("width", function(d) {
// console.log("10"); // Debug
// 因為空資料的值被改為 "-1",所以要下一個判斷:
// 如果資料為 "-1",就把 width 直接訂為 0
return d[year] == "-1" ? 0 : x(d[year]);
});
// 11
barExit.select(".value")
.attr("x", function(d) {
// console.log("11"); // Debug
// 如果資料為 "-1",就把位移值 x 直接訂為 textLabelDistance
return d[year] == "-1" ? textLabelDistance : x(d[year]) + textLabelDistance;
})
.text(function(d) {
return d[year] == "-1" ? "No Data." : d[year] + " %";
});
// 12
d3.transition(svg).select(".x.axis")
.call(xAxis);
// console.log("12 end."); // Debug
}
// change();
// var timeout = setTimeout(function() {
// menu.property("value", "65 Years and Over").node().focus();
// change();
// }, 5000);
</script>
</div>
</body>
https://d3js.org/d3.v3.min.js