|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
<title>EU Dashboard</title> |
|
|
|
<link href="https://fonts.googleapis.com/css?family=Lato&display=swap" rel="stylesheet" /> |
|
<link href="/d/45855280509edd73300af7240de3524a/styles.css" rel="stylesheet" /> |
|
|
|
<!-- DO NOT DO THIS IN PRODUCTION --> |
|
<!-- github.io IS NOT A CDN --> |
|
<link href="https://visual.js.org/visual.css" rel="stylesheet" type="text/css" /> |
|
<script src="https://visual.js.org/lazyvisualsetup.js"></script> |
|
<!-- /DO NOT DO THIS IN PRODUCTION --> |
|
|
|
<script src="https://cdn.jsdelivr.net/npm/jsonstat@0.13.13"></script> |
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/jquery-sparkline@2.4.0/jquery.sparkline.min.js"></script> |
|
|
|
<script> |
|
/* Include your preferred indicators here */ |
|
const sources=[ |
|
{ |
|
id: "gdp", |
|
label: "GDP per capita (€)", |
|
descr: "Gross domestic product at current market prices, euro per capita", |
|
dataset: "tec00001?na_item=B1GQ&precision=1&unit=CP_EUR_HAB", |
|
isPercent: false |
|
}, |
|
{ |
|
id: "prices", |
|
label: "HICP (2015=100)", |
|
descr: "Harmonised Indices of Consumer Prices, annual average index", |
|
dataset: "tec00027?precision=1&unit=INX_A_AVG&coicop=CP00", |
|
isPercent: false |
|
}, |
|
{ |
|
id: "employ", |
|
label: "Employment rate (%)", |
|
descr: "Total employment (resident population concept) from 20 to 64 year, percentage of total population", |
|
dataset: "tesem010?precision=1&sex=T&indic_em=EMP_LFS&unit=PC_POP&age=Y20-64", |
|
isPercent: true |
|
}, |
|
{ |
|
id: "unemploy", |
|
label: "Unemployment rate (%)", |
|
descr: "Unemployed persons aged 15 to 74, percentage of active population", |
|
dataset: "tps00203?precision=1&sex=T&unit=PC_ACT&age=Y15-74", |
|
isPercent: true |
|
}, |
|
{ |
|
id: "berd", |
|
label: "BERD (€/inh.)", |
|
descr: "Business expenditure on R&D, euro per inhabitant", |
|
dataset: "rd_e_berdindr2?precision=1&unit=EUR_HAB&nace_r2=TOTAL", |
|
isPercent: false |
|
}, |
|
{ |
|
id: "internet", |
|
label: "Internet access (% of hh.)", |
|
descr: "Percentage of households with internet access", |
|
dataset: "isoc_ci_in_h?hhtyp=TOTAL&precision=1&unit=PC_HH", |
|
isPercent: true |
|
}, |
|
{ |
|
id: "ecommerce", |
|
label: "Online purchases (% of indv.)", |
|
descr: "Last online purchase in the last 3 months, percentage of individuals", |
|
dataset: "isoc_ec_ibuy?ind_type=IND_TOTAL&precision=1&unit=PC_IND&indic_is=I_BUY3", |
|
isPercent: true |
|
}, |
|
{ |
|
id: "airpol", |
|
label: "Greenhouse gases (grams/€)", |
|
descr: "Grams per euro (current prices value added, gross)", |
|
dataset: "env_ac_aeint_r2?airpol=GHG&na_item=B1G&precision=1&unit=G_EUR_CP&nace_r2=TOTAL", |
|
isPercent: false |
|
} |
|
]; |
|
</script> |
|
</head> |
|
<body> |
|
<main></main> |
|
<div id="visual" class="visual"> |
|
<p id="msg">Click on an indicador’s title to see its distribution by EU countries. Then click on a map area to see the indicador’s sparkline for the selected country. To retrieve the EU sparkline, click on the country (brown) code.</p> |
|
</div> |
|
|
|
<script> |
|
if(typeof fetch!=="function"){ |
|
window.alert("Sorry, a modern browser is required!"); |
|
} |
|
|
|
const |
|
main=document.querySelector("main"), |
|
sparkOptions={lineColor: "#548ac3", width: "150px", height: "60px", fillColor: false, lineWidth: 2, spotRadius: 3, highlightSpotColor: "#000", spotColor: "#900", maxSpotColor: "#900", minSpotColor: "#900", highlightLineColor: "#c00"} |
|
; |
|
|
|
function nonNull(d){ |
|
const |
|
values=d.map(e=>e.value), |
|
len=values.length, |
|
first=values.findIndex(e=>e!==null); |
|
last=len-values.reverse().findIndex(e=>e!==null), |
|
filtered=d.slice(first, last) |
|
; |
|
|
|
return { |
|
time: filtered.map(e=>e.time), |
|
value: filtered.map(e=>e.value) |
|
}; |
|
} |
|
|
|
function indic(i, country){ |
|
const |
|
source=sources[i], |
|
id=source.id, |
|
ds=source.jsonstat, |
|
series=nonNull( ds.toTable({type: "arrobj", content: "id"}).filter(e=>e.geo===country) ), |
|
first=series.time.slice(0,1)[0], |
|
last=series.time.slice(-1)[0], |
|
geo=ds.Dimension("geo"), |
|
countries=geo.id, |
|
data=series.value, |
|
$id=$("#"+id), |
|
$ref=$id.children(".ref"), |
|
change=(function(d){ |
|
const |
|
two=d.slice(-2), |
|
dif=Math.abs(two[1]-two[0]), |
|
plus=two[1]<two[0] ? "↓" : "↑" |
|
; |
|
|
|
$id.addClass(plus==="↑" ? "up" : "down"); |
|
return (source.isPercent) ? "<strong>"+plus+"</strong>" + dif.toFixed(1) : "<strong>"+plus+"</strong>" + ((dif*100)/two[0]).toFixed(1) + " %"; |
|
}(data)) |
|
; |
|
|
|
$id.children(".change").html( change ); |
|
|
|
$id.children(".value").text(data.slice(-1).toLocaleString("en-EN")); |
|
$id.children(".viz").sparkline(data, sparkOptions); |
|
$id.children(".ref").html('<abbr title="'+geo.Category(country).label+'">' + (country==="EU27_2020"? "EU27" : country) + "</abbr> " + first + "–" + last); |
|
if(country!=="EU27_2020"){ |
|
const callback=function(){ |
|
indic(i, "EU27_2020"); |
|
$ref |
|
.removeClass("changed") |
|
.attr("tabindex", "-1") |
|
; |
|
}; |
|
|
|
$ref |
|
.addClass("changed") |
|
.attr("tabindex", "0") |
|
.trigger("focus") |
|
.click(callback) |
|
.keypress(e=>{ |
|
if(e.which===13){ |
|
callback(); |
|
} |
|
}) |
|
; |
|
} |
|
|
|
const callback=function(){ |
|
if(!$id.hasClass("sel")){ |
|
$(".indic.sel").removeClass("sel"); |
|
$id.addClass("sel"); |
|
|
|
visual({ |
|
fixed: [450, 525], |
|
lang: "en", |
|
legend: true, |
|
range: 0, |
|
|
|
type: "cmap", |
|
by: "eu27", |
|
data: ds.Data( { "time": last } ).map( (e, i)=>({ id: countries[i], val: e.value })), |
|
click: function(area){ |
|
indic(i, area.id); |
|
} |
|
}) |
|
} |
|
}; |
|
|
|
$id.children("h2") |
|
.text(source.label) |
|
.attr("title", source.descr) |
|
.click(callback) |
|
.keypress(e=>{ |
|
if(e.which===13){ |
|
callback(); |
|
} |
|
}) |
|
; |
|
} |
|
|
|
sources.forEach(async (source, i)=>{ |
|
main.innerHTML=main.innerHTML+'<div class="indic" id="'+source.id+'"><h2 tabindex="0"></h2><span class="viz"></span><span class="value"></span><p class="change"></p><p class="ref"></p></div>'; |
|
|
|
const |
|
service="https://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/", |
|
time="&lastTimePeriod=10", |
|
geo="&geo=AT&geo=BE&geo=BG&geo=CY&geo=CZ&geo=DE&geo=DK&geo=EE&geo=EL&geo=ES&geo=FI&geo=FR&geo=HR&geo=HU&geo=IE&geo=IT&geo=LT&geo=LU&geo=LV&geo=MT&geo=NL&geo=PL&geo=PT&geo=RO&geo=SE&geo=SI&geo=SK&geo=EU27_2020", |
|
res=await fetch(service+source.dataset+time+geo), |
|
json=await res.json() |
|
; |
|
|
|
source.jsonstat=JSONstat(json); |
|
indic(i, "EU27_2020"); |
|
}); |
|
</script> |
|
</body> |
|
</html> |