|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<!-- Latest compiled and minified CSS --> |
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> |
|
|
|
|
|
<!-- Optional theme --> |
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> |
|
|
|
|
|
<style> |
|
body { text-align: center;} |
|
p, button { text-align: center; } |
|
path { display: none} |
|
line { stroke: lightGrey } |
|
#next-button { background-color: #2E8B57; background-image: linear-gradient(to bottom,#8FBC8F 0,#2E8B57 100%) } |
|
text { fill: Black } |
|
rect { shape-rendering: crispEdges; stroke: white; stroke-width: 1px; } |
|
.industry-label { font-size: 14px } |
|
|
|
</style> |
|
</head> |
|
|
|
<body> |
|
|
|
<div class="container-fluid"> |
|
<div class="row"> |
|
<div class="col-xs-12"> |
|
<p id="headline" class="text-center lead"> |
|
</p> |
|
|
|
<div id="chart"></div> |
|
<p id="source-link">More information and analysis is available in the PwC report: <a href="http://www.pwc.co.uk/services/economics-policy/insights/uk-economic-outlook.html">UK Economic Outlook March 2017</a></p> |
|
<button id="next-button" type="button" class="btn btn-primary btn-lg btn-block"> |
|
Next |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
|
|
<script> |
|
var data = [ |
|
{ |
|
"industry": "Wholesale and retail trade", |
|
"employmentShare": 0.15, |
|
"jobAutomation": 0.44 |
|
}, |
|
{ |
|
"industry": "Manufacturing", |
|
"employmentShare": 0.08, |
|
"jobAutomation": 0.46 |
|
}, |
|
{ |
|
"industry": "Administrative and support services", |
|
"employmentShare": 0.08, |
|
"jobAutomation": 0.37 |
|
}, |
|
{ |
|
"industry": "Transportation and storage", |
|
"employmentShare": 0.05, |
|
"jobAutomation": 0.56 |
|
}, |
|
{ |
|
"industry": "Professional, scientific and technical", |
|
"employmentShare": 0.09, |
|
"jobAutomation": 0.26 |
|
}, |
|
{ |
|
"industry": "Human health and social work", |
|
"employmentShare": 0.12, |
|
"jobAutomation": 0.17 |
|
}, |
|
{ |
|
"industry": "Accommodation and food services", |
|
"employmentShare": 0.07, |
|
"jobAutomation": 0.26 |
|
}, |
|
{ |
|
"industry": "Construction", |
|
"employmentShare": 0.064, |
|
"jobAutomation": 0.24 |
|
}, |
|
{ |
|
"industry": "Public administration and defence", |
|
"employmentShare": 0.043, |
|
"jobAutomation": 0.32 |
|
}, |
|
{ |
|
"industry": "Information and communication", |
|
"employmentShare": 0.041, |
|
"jobAutomation": 0.27 |
|
}, |
|
{ |
|
"industry": "Financial and insurance", |
|
"employmentShare": 0.032, |
|
"jobAutomation": 0.32 |
|
}, |
|
{ |
|
"industry": "Education", |
|
"employmentShare": 0.087, |
|
"jobAutomation": 0.09 |
|
}, |
|
{ |
|
"industry": "Arts and entertainment", |
|
"employmentShare": 0.029, |
|
"jobAutomation": 0.22 |
|
}, |
|
{ |
|
"industry": "Other services", |
|
"employmentShare": 0.027, |
|
"jobAutomation": 0.19 |
|
}, |
|
{ |
|
"industry": "Real estate", |
|
"employmentShare": 0.017, |
|
"jobAutomation": 0.28 |
|
}, |
|
{ |
|
"industry": "Water, sewage and waste management", |
|
"employmentShare": 0.006, |
|
"jobAutomation": 0.63 |
|
}, |
|
{ |
|
"industry": "Agriculture, forestry and fishing", |
|
"employmentShare": 0.011, |
|
"jobAutomation": 0.19 |
|
}, |
|
{ |
|
"industry": "Electricity and gas supply", |
|
"employmentShare": 0.004, |
|
"jobAutomation": 0.32 |
|
}, |
|
{ |
|
"industry": "Mining and quarrying", |
|
"employmentShare": 0.002, |
|
"jobAutomation": 0.23 |
|
}, |
|
{ |
|
"industry": "Domestic personnel and self-subsistence", |
|
"employmentShare": 0.003, |
|
"jobAutomation": 0.08 |
|
} |
|
] |
|
|
|
var vWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; |
|
|
|
var vHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; |
|
|
|
const width = vWidth * 0.35; |
|
const height = vHeight * 0.8; |
|
|
|
const margin = {"top": 25, "left": vWidth * 0.3, "right": vWidth * 0.1, "bottom": 25}; |
|
|
|
var xScale = d3.scaleLinear().range([0,width]).domain([0,1]); //jobAutomation |
|
var yScale = d3.scaleLinear().range([0,height]); //employmentShare |
|
|
|
var totalOffset = 0; |
|
|
|
const rowGap = 20; |
|
const dataLength = data.length; |
|
const expandedHeight = height + (dataLength * rowGap); |
|
|
|
const jobs = 34766667; |
|
const overallPercent = 0.3; |
|
|
|
var chartNo = 2; |
|
const duration = 1000; |
|
const mainColour = "SeaGreen"; |
|
const backgroundColour = "PaleGoldenRod"; |
|
|
|
var sourceLink = d3.select("#source-link").style("display", "none"); |
|
|
|
data.forEach(function(d){ |
|
d.offset = totalOffset; |
|
totalOffset = d.offset + d.employmentShare; |
|
}); |
|
|
|
yScale.domain([0,totalOffset]); |
|
|
|
var select = d3.select("button").on("click", updateChart) |
|
var xAxis = d3.axisTop(xScale).tickFormat(formatPercentage); |
|
|
|
var defaultHeadline = "There are currently " + roundMillions(jobs) + " million jobs in the UK:"; |
|
|
|
var defaultRectText = "All " + roundMillions(jobs) + " million jobs:"; |
|
|
|
///////////////////////////////////////////////////////////////////// |
|
|
|
var headline = d3.select("#headline").text(defaultHeadline); |
|
|
|
var svg = d3.select("#chart").append("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
|
|
var chart = svg.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") |
|
|
|
chart.append("rect") |
|
.attr("id", "base-rect") |
|
.attr("x", 0) |
|
.attr("y", 0) |
|
.attr("width", width) |
|
.attr("height", height) |
|
.style("fill", backgroundColour); |
|
|
|
chart.append("rect") |
|
.attr("class", "overall-automation") |
|
.attr("x", 0) |
|
.attr("y", 0) |
|
.attr("width", 0) |
|
.attr("height", height) |
|
.style("fill", mainColour); |
|
|
|
chart.append("text") |
|
.attr("id", "initial-text") |
|
.text(defaultRectText) |
|
.attr("x", -5) |
|
.attr("y", height/2) |
|
.style("text-anchor", "end"); |
|
|
|
var gAxis = svg.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") |
|
.call(xAxis); |
|
|
|
gAxis.selectAll("text") |
|
.style("fill", mainColour) |
|
.style("opacity", 0); |
|
|
|
gAxis.selectAll("line").remove(); |
|
|
|
|
|
var industries = chart.selectAll(".industry") |
|
.data(data) |
|
.enter() |
|
.append("g") |
|
.attr("class", "industry") |
|
.attr("transform", function(d) { return "translate(0," + yScale(d.offset) + ")"; }); |
|
|
|
industries.append("text") |
|
.text(function(d) { return formatPercentage(d.employmentShare * d.jobAutomation); }) |
|
.attr("x", width + 5) |
|
.attr("y", function(d) { return (yScale(d.employmentShare)/2) + 5; }) |
|
.style("opacity", 0); |
|
|
|
var all = industries.append("rect") |
|
.attr("class", "all") |
|
.attr("x", 0) |
|
.attr("y", 0) |
|
.attr("width", width) |
|
.attr("height", function(d) { return yScale(d.employmentShare) < 3 ? 3 : yScale(d.employmentShare); }) |
|
.style("fill", backgroundColour) |
|
.style("opacity",0); |
|
|
|
industries.append("text") |
|
.attr("class", "all-text") |
|
.text(function(d){ return formatMillions(d.employmentShare * jobs) + " (" + formatPercentage(d.employmentShare) + ")" }) |
|
.attr("x", width/2) |
|
.attr("y", function(d) { return 5 + yScale(d.employmentShare)/2; }) |
|
.style("opacity",0) |
|
.style("text-anchor", "middle"); |
|
|
|
var automation = industries.append("rect") |
|
.attr("class", "automation") |
|
.attr("x", 0) |
|
.attr("y", 0) |
|
.attr("width", 0) |
|
.attr("height", function(d) { return yScale(d.employmentShare) < 3 ? 3 : yScale(d.employmentShare); }) |
|
.style("fill", mainColour); |
|
|
|
industries.append("text") |
|
//.filter(function(d){ return d.industry != "Domestic personnel and self-subsistence" && d.industry != "Mining and quarrying" && d.industry != "Agriculture, forestry and fishing"; }) |
|
.attr("class", "automation-text") |
|
//.text(function(d){ return formatPercentage(d.jobAutomation)}) |
|
.text(function(d){ return formatMillions((d.employmentShare * jobs) * d.jobAutomation) + " (" + formatPercentage(d.jobAutomation) + ")" }) |
|
//.attr("x", function(d){ return xScale(d.jobAutomation) + 5 }) |
|
.attr("x", width + 5 ) |
|
.attr("y", function(d) { return 5 + yScale(d.employmentShare)/2; }) |
|
.style("fill", mainColour) |
|
.style("opacity",0); |
|
|
|
var industryLabel = industries.append("text") |
|
//.filter(function(d){ return d.industry != "Domestic personnel and self-subsistence" && d.industry != "Mining and quarrying" && d.industry != "Agriculture, forestry and fishing"; }) |
|
.attr("class", "industry-label") |
|
.text(function(d) { return d.industry }) |
|
.attr("x", -5) |
|
.attr("y", function(d) { return (yScale(d.employmentShare)/2) + 5; }) |
|
.style("text-anchor", "end") |
|
.style("opacity", 0); |
|
|
|
|
|
function updateChart() { |
|
|
|
if (chartNo === 1) { |
|
|
|
headline.text(defaultHeadline); |
|
|
|
sourceLink.style("display", "none"); |
|
|
|
var t1 = d3.transition().duration(duration); |
|
|
|
svg.transition(t1) |
|
.attr("height", height + margin.top + margin.bottom); |
|
|
|
industries.transition(t1) |
|
.attr("transform", function(d, i) { return "translate(0," + yScale(d.offset) + ")"; }); |
|
|
|
automation.transition(t1) |
|
.attr("width", 0) |
|
.style("opacity",1); |
|
|
|
d3.selectAll("#base-rect, #initial-text").transition(t1) |
|
.style("opacity", 1); |
|
|
|
d3.select("#initial-text") |
|
.text(defaultRectText) |
|
.style("fill", "black"); |
|
|
|
all.transition(t1) |
|
.style("opacity", 0); |
|
|
|
industryLabel.transition(t1) |
|
.style("opacity", 0); |
|
|
|
d3.selectAll(".automation-text").transition(t1) |
|
.style("opacity", 0); |
|
|
|
gAxis.selectAll("text").transition(t1) |
|
.style("opacity", 0); |
|
|
|
select.text("Next") |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 2) { |
|
|
|
headline.text("By 2030, " + formatPercentage(overallPercent) + " (" + roundMillions(jobs * overallPercent) + " million) of these jobs may be replaced by automation:"); |
|
|
|
var t2 = d3.transition().duration(duration) |
|
|
|
d3.select("#initial-text").text(roundMillions(jobs * overallPercent) + " million job losses:") |
|
.style("fill", mainColour); |
|
|
|
d3.select(".overall-automation").transition(t2) |
|
.attr("width", xScale(0.3)); |
|
|
|
gAxis.selectAll("text").transition(t2) |
|
.delay(function(d){ return d * 700; }) |
|
.style("opacity", function(d) { return d < 0.4 ? 1 : 0; }) |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 3) { |
|
|
|
headline.text("However the affect of automation will vary across industries."); |
|
|
|
var t3 = d3.transition().duration(duration); |
|
|
|
d3.select(".overall-automation").transition(t3) |
|
.attr("width", 0); |
|
|
|
d3.select("#initial-text").transition(t3) |
|
.style("opacity", 0); |
|
|
|
gAxis.selectAll("text").transition(t3) |
|
.style("opacity", 0) |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 4) { |
|
|
|
headline.text("The current number of jobs are divided across these industries:"); |
|
|
|
var t4 = d3.transition().duration(duration); |
|
|
|
|
|
|
|
d3.selectAll(".all, .industry-label, .all-text").transition(t4) |
|
.style("opacity", 1); |
|
|
|
d3.select("#base-rect").transition(t4) |
|
.style("opacity", 0); |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 5) { |
|
|
|
headline.text("The estimated job losses due to automation per industry will vary:"); |
|
|
|
var t5 = d3.transition().duration(duration); |
|
|
|
d3.selectAll(".all-text").transition(t5) |
|
.style("opacity", 0 ) |
|
|
|
gAxis.selectAll("text").transition(t5) |
|
.delay(function(d){ return d * 700; }) |
|
.style("opacity", 1 ) |
|
|
|
automation.transition(t5) |
|
.attr("width", function(d) { return xScale(d.jobAutomation); }); |
|
|
|
d3.selectAll(".automation-text").transition(t5) |
|
.style("opacity", 1 ) |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 6) { |
|
|
|
headline.text("Over 2 million (40%) jobs in 'wholesale and retail trade' may be affected by automation:"); |
|
|
|
var t6 = d3.transition().duration(duration); |
|
|
|
industries.selectAll(".industry-label, .automation-text").transition(t6) |
|
.style("opacity", function(d) { return d.industry == "Wholesale and retail trade" ? 1 : 0; }); |
|
|
|
industries.selectAll(".automation").transition(t7) |
|
.style("opacity", function(d) { return d.industry == "Wholesale and retail trade" ? 1 : 0.2; }); |
|
|
|
chartNo = chartNo + 1 |
|
|
|
} else if (chartNo === 7) { |
|
|
|
headline.text("60% of 'water, sewage and waste management' may jobs may be affected:"); |
|
|
|
var t7 = d3.transition().duration(duration); |
|
|
|
industries.selectAll(".industry-label, .automation-text").transition(t7) |
|
.style("opacity", function(d) { return d.industry == "Water, sewage and waste management" ? 1 : 0; }); |
|
|
|
industries.selectAll(".automation").transition(t7) |
|
.style("opacity", function(d) { return d.industry == "Water, sewage and waste management" ? 1 : 0.2; }); |
|
|
|
chartNo = chartNo + 1; |
|
|
|
} else if (chartNo === 8) { |
|
|
|
headline.text("Over half of these potential job losses are in four key industry sectors: wholesale and retail trade, manufacturing, administrative and support services, and transport and storage."); |
|
|
|
var t8 = d3.transition().duration(duration); |
|
|
|
svg.transition(t8) |
|
.attr("height", expandedHeight + margin.top + margin.bottom); |
|
|
|
industries.transition(t8) |
|
.attr("transform", function(d, i) { return "translate(0," + (yScale(d.offset) + (i * rowGap)) + ")"; }); |
|
|
|
industries.selectAll(".industry-label, .automation, .automation-text").transition(t8) |
|
.style("opacity", 1); |
|
|
|
sourceLink.style("display", "inherit"); |
|
|
|
select.text("Restart"); |
|
|
|
chartNo = 1; |
|
|
|
}; |
|
|
|
}; |
|
|
|
function formatPercentage(n) { |
|
var roundedN = Math.round(n * 1000); |
|
return roundedN/10 + "%"; |
|
}; |
|
|
|
function roundMillions(n) { |
|
var roundedN = Math.round(n/10000)/100; |
|
return roundedN; |
|
}; |
|
|
|
function formatMillions(n) { |
|
return roundMillions(n) + "M"; |
|
}; |
|
|
|
|
|
</script> |
|
</body> |