Skip to content

Instantly share code, notes, and snippets.

@jgaffuri
Last active November 10, 2020 20:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jgaffuri/71d130bf5963c5ffe0a436399f401af3 to your computer and use it in GitHub Desktop.
Save jgaffuri/71d130bf5963c5ffe0a436399f401af3 to your computer and use it in GitHub Desktop.
NUTS regions
license: EUPL-1.1
height: 900
scrolling: no
border: no

This is an advanced example of Nuts2json API showing NUTS regions.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NUTS overview</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://d3js.org/d3-request.v1.min.js"></script>
<script src="https://d3js.org/topojson.v3.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/eurostat/eurostat.js@0.1/js/lib.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<style>
body {
font-family: "Myriad Pro", Myriad, MyriadPro-Regular, 'Myriad Pro Regular', MyriadPro, 'Myriad Pro', "Liberation Sans", "Nimbus Sans L", "Helvetica Neue", vegur, Vegur, Helvetica, Arial, sans-serif;
font-size: 80%;
}
.ui-widget { font-size: 90% !important; }
</style>
</head>
<body>
<div><svg id="map"></svg></div>
<div id="but">
<div id="lvl">
<div>NUTS level</div>
<input type="radio" name="lvl" id="0" value="0"><label for="0">0</label>
<input type="radio" name="lvl" id="1" value="1"><label for="1">1</label>
<input type="radio" name="lvl" id="2" value="2"><label for="2">2</label>
<input type="radio" name="lvl" id="3" value="3"><label for="3">3</label>
</div>
<div id="scale" style="margin-top: 10px;">
<div>Simplification level</div>
<input type="radio" name="scale" id="10M" value="10M"><label for="10M">1:10M</label>
<input type="radio" name="scale" id="20M" value="20M"><label for="20M">1:20M</label>
<input type="radio" name="scale" id="60M" value="60M"><label for="60M">1:60M</label>
</div>
<div id="proj" style="margin-top: 10px;">
<div>Projection</div>
<input type="radio" name="proj" id="3035" value="3035"><label for="3035">LAEA Europe (3035)</label>
<input type="radio" name="proj" id="3857" value="3857"><label for="3857">Web mercator (3857)</label>
<input type="radio" name="proj" id="4258" value="4326"><label for="4326">WGS 84 (4326)</label>
</div>
<div id="year" style="margin-top: 10px;">
<div>NUTS version</div>
<input type="radio" name="year" id="2010" value="2010"><label for="2010">2010</label>
<input type="radio" name="year" id="2013" value="2013"><label for="2013">2013</label>
<input type="radio" name="year" id="2016" value="2016"><label for="2016">2016</label>
<input type="radio" name="year" id="2021" value="2021"><label for="2021">2021</label>
</div>
</div>
<div id="tooltip"></div>
<script>
//hide buttons
$("#but").hide();
//show loading message
var loadingDiv = EstLib.loadingImage({imgsrc:"https://raw.githubusercontent.com/eurostat/eurostat.js/master/img/loading.png"});
//get option values
var opts = {};
opts.lvl = EstLib.getParameterByName("lvl") || "3";
opts.scale = EstLib.getParameterByName("s") || "20M";
opts.proj = EstLib.getParameterByName("proj") || 3035;
opts.year = EstLib.getParameterByName("y") || 2016;
var width = EstLib.getParameterByName("w") || 800;
//build tooltip element
var tooltip = EstLib.tooltip();
d3.select("#tooltip").style("font-family", "Myriad Pro, Myriad, MyriadPro-Regular, 'Myriad Pro Regular', MyriadPro, 'Myriad Pro', 'Liberation Sans', 'Nimbus Sans L', 'Helvetica Neue', vegur, Vegur, Helvetica, Arial, sans-serif");
//options
Object.keys(opts).forEach(function(opt) {
var cb = $("#"+opt);
$("input[name='"+opt+"']").change(function () {
opts[opt] = $("input:radio[name="+opt+"]:checked").val();
refresh();
});
$("input:radio[name="+opt+"][value="+opts[opt]+"]").prop('checked',true);
cb.buttonset();
});
var refresh = function(){
//get data
d3.json("https://raw.githubusercontent.com/eurostat/Nuts2json/master/pub/v1/"+opts.year+"/"+opts.proj+"/"+opts.scale+"/"+opts.lvl+".json", function(error, nuts) {
if (error) return console.error(error);
loadingDiv.hide();
$("#but").show();
//prepare SVG element
var height = width*(nuts.bbox[3]-nuts.bbox[1])/(nuts.bbox[2]-nuts.bbox[0]),
svg = d3.select("#map").attr("width", width).attr("height", height),
path = d3.geoPath().projection(d3.geoIdentity().reflectY(true).fitSize([width,height], topojson.feature(nuts, nuts.objects.gra)))
;
//clear SVG element
svg.selectAll("*").remove()
//define test filters for regions
//var f1 = svg.append("filter").attr("id","reglight");
//f1.append("feSpecularLighting").attr("result","specOut").attr("specularExponent","20").attr("lighting-color","#bbbbbb")
// .append("fePointLight").attr("x","50").attr("y","75").attr("z","200");
//f1.append("feComposite").attr("in","SourceGraphic").attr("in2","specOut").attr("operator","arithmetic").attr("k1","0").attr("k2","1").attr("k3","1").attr("k4","0")
//var f1 = svg.append("filter").attr("id","dispfil");
//f1.append("feTurbulence").attr("type","turbulence").attr("baseFrequency","0.05").attr("numOctaves","2").attr("result","turbulence")
//f1.append("feDisplacementMap").attr("in2","turbulence").attr("in","SourceGraphic").attr("scale","50").attr("xChannelSelector","R").attr("yChannelSelector","G")
/*
<defs>
<pattern id="pattern1" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" />
</pattern>
</defs>
.style("fill","url(#pattern)")
*/
var pattS=3, patt = svg.append("pattern").attr("id","patt_cntrg").attr("x","0").attr("y","0").attr("width",pattS).attr("height",pattS).attr("patternUnits","userSpaceOnUse");
patt.append("rect").attr("x","0").attr("y","0").attr("width",pattS).attr("height",pattS).style("stroke","none").style("fill","white")
patt.append("circle").attr("cx",pattS/2).attr("cy",pattS/2).attr("r",pattS/2*0.3).style("stroke","none").style("fill","gray")
pattS=3, patt = svg.append("pattern").attr("id","patt_nutsrg").attr("x","0").attr("y","0").attr("width",pattS).attr("height",pattS).attr("patternUnits","userSpaceOnUse");
patt.append("rect").attr("x","0").attr("y","0").attr("width",pattS).attr("height",pattS).style("stroke","none").style("fill","#fdbf6f")
patt.append("circle").attr("cx",pattS/2).attr("cy",pattS/2).attr("r",pattS/2*0.3).style("stroke","none").style("fill","white")
;
pattS=7, patt = svg.append("pattern").attr("id","patt_sea").attr("x","0").attr("y","0").attr("width",pattS).attr("height",pattS).attr("patternUnits","userSpaceOnUse");
patt.append("rect").attr("x",0).attr("y",0).attr("width",pattS).attr("height",pattS).style("stroke","none").style("fill","#b3cde3")
patt.append("circle").attr("cx",pattS/2).attr("cy",0).attr("r",pattS/2).style("fill","#b3cde3").style("stroke","white").style("stroke-width",0.7)
;
//define filter for coastal margin
svg.append("filter").attr("id","blur").attr("x","-200%").attr("y","-200%").attr("width","400%").attr("height","400%")
.append("feGaussianBlur").attr("in","SourceGraphic").attr("stdDeviation","4")
;
//prepare drawing group
var g = svg.append("g").attr("transform","translate(0,0)");
//add zooming function
var zoom;
svg.call(zoom=d3.zoom().scaleExtent([0.25,6]).on("zoom", function() { g.attr("transform", d3.event.transform); }));
//draw background rectangle
g.append("rect").attr("id","bck").attr("x",0).attr("y",0).attr("width", width).attr("height", height)
//.style("fill","#b3cde3");
.style("fill","url(#patt_sea)");
//draw coastal margin
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.cntbn).features).enter()
.append("path").attr("d", path)
.style("fill","none").style("stroke-width","8px").style("filter","url(#blur)").style("stroke-linejoin","round").style("stroke-linecap","round")
.style("stroke",function(bn){ if(bn.properties.co==="T") return "white"; return "none"; })
;
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.nutsbn).features).enter()
.append("path").attr("d", path)
.style("fill","none").style("stroke-width","8px").style("filter","url(#blur)").style("stroke-linejoin","round").style("stroke-linecap","round")
.style("stroke",function(bn){ if(bn.properties.co==="T") return "white"; return "none"; })
;
//draw graticule
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.gra).features).enter()
.append("path").attr("d", path)
.style("fill","none").style("stroke-width","1px").style("stroke","gray");
//draw country regions
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.cntrg).features).enter()
.append("path").attr("d", path)
.on("mouseover", function(rg) { d3.select(this).style("fill", "#ddd"); tooltip.mouseover("<b>"+rg.properties.na+"</b><br>"+rg.properties.id); })
.on("mousemove", function() { tooltip.mousemove(); })
.on("mouseout", function() { d3.select(this).style("fill","url(#patt_cntrg)"); tooltip.mouseout(); })
//.style("fill","#f2f2f2")
.style("fill","url(#patt_cntrg)")
//.style("filter","url(#dispfil)")
;
//draw nuts regions
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.nutsrg).features).enter()
.append("path").attr("d", path)
.on("mouseover", function(rg) { d3.select(this).style("fill", "#ff7f00"); tooltip.mouseover("<b>"+rg.properties.na+"</b><br>"+rg.properties.id); })
.on("mousemove", function() { tooltip.mousemove(); })
.on("mouseout", function() { d3.select(this).style("fill","url(#patt_nutsrg)"); tooltip.mouseout(); })
//.style("fill","#fdbf6f")
.style("fill","url(#patt_nutsrg)")
//.style("filter","url(#dispfil)")
;
//draw country boundaries
g.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.cntbn).features).enter()
.append("path").attr("d", path)
.style("fill","none")
.style("stroke",function(bn){ if(bn.properties.co==="T") return "#1f78b4"; return "gray"; })
.style("stroke-width","1.2px")
.style("stroke-linejoin","round").style("stroke-linecap","round")
;
//draw nuts boundaries
var bn = topojson.feature(nuts, nuts.objects.nutsbn).features;
bn.sort(function(bn1,bn2){ return bn2.properties.lvl - bn1.properties.lvl; });
g.append("g").selectAll("path").data(bn).enter()
.append("path").attr("d", path)
.style("fill","none")
.style("stroke",function(bn){
if(bn.properties.co==="T") return "#1f78b4";
if(bn.properties.oth==="T") return "#666";
if(bn.properties.lvl==0) return "#444";
return "#666";
})
.style("stroke-width",function(bn){
if(bn.properties.co==="T") return "1px";
if(bn.properties.lvl==0) return "1.5px";
if(bn.properties.lvl==1) return "1.1px";
if(bn.properties.lvl==2) return "1.1px";
if(bn.properties.lvl==3) return "0.6px";
return "1.1px";
})
.style("stroke-linejoin","round").style("stroke-linecap","round")
;
});
}
refresh();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment