Visualization of European FIRs (those starting w/ 'E', 'L' or 'UK', 'UG', 'UD', 'BK', 'GC'.
Click on FIR to zoom in/out.
Geometries from the Network Manager and available in this repo.
Built with blockbuilder.org
Visualization of European FIRs (those starting w/ 'E', 'L' or 'UK', 'UG', 'UD', 'BK', 'GC'.
Click on FIR to zoom in/out.
Geometries from the Network Manager and available in this repo.
Built with blockbuilder.org
| .background { | |
| fill: none; | |
| pointer-events: all; | |
| } | |
| .fab { | |
| fill: #ddd; | |
| opacity: 0.5; | |
| } | |
| .fir { | |
| fill: #ddc; | |
| opacity: 0.5; | |
| cursor: pointer; | |
| } | |
| .fir-boundary { | |
| fill: none; | |
| stroke: #888; | |
| /*stroke-dasharray: 2,2;*/ | |
| stroke-linejoin: round; | |
| stroke-linecap: round; | |
| /*stroke-width: .5px;*/ | |
| } | |
| .fir-boundary.ECTRL { | |
| stroke: #8BF63D; | |
| /*stroke-width: .5px;*/ | |
| } | |
| .graticule { | |
| fill: none; | |
| stroke: #333; | |
| /*stroke-width: .5px;*/ | |
| stroke-opacity: .5; | |
| } | |
| .land { | |
| fill: none; | |
| /*stroke-width: .5px;*/ | |
| stroke-opacity: .5; | |
| } | |
| .boundary { | |
| fill: none; | |
| stroke: #fff; | |
| /*stroke-width: .5px;*/ | |
| } | |
| .country { | |
| fill: #ccc; | |
| } | |
| #tooltip { | |
| position: absolute; | |
| width: auto; | |
| height: auto; | |
| padding: 2px 2px; | |
| -webkit-border-radius: 3px; | |
| -moz-border-radius: 3px; | |
| border-radius: 3px; | |
| -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); | |
| -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); | |
| box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4); | |
| pointer-events: none; | |
| background-color: #bbb; | |
| } | |
| #tooltip.hidden { | |
| display: none; | |
| } | |
| #tooltip p { | |
| margin: 0 0 0 0; | |
| padding: 2px 2px; | |
| font-family: sans-serif; | |
| font-size: 11px; | |
| } | |
| .hidden{ | |
| display: none; | |
| } | |
| svg { | |
| background: #eee; | |
| } |
| /*jslint browser: true, devel: true */ | |
| var d3, queue, vis, params, topojson; | |
| (function () { | |
| "use strict"; | |
| vis = {}; | |
| var width, height, | |
| chart, svg, g, active, background, | |
| path, | |
| defs, style, | |
| slider, step, maxStep, running, sv, timer, | |
| button; | |
| // general design from | |
| // http://www.jeromecukier.net/blog/2013/11/20/getting-beyond-hello-world-with-d3/ | |
| vis.init = function (params) { | |
| console.log("in init, params: " + JSON.stringify(params)); | |
| vis.params = params || {}; | |
| chart = d3.select(vis.params.chart || "#chart"); // placeholder div for svg | |
| width = vis.params.width || 960; | |
| height = vis.params.height || 500; | |
| active = d3.select(null); | |
| svg = chart.selectAll("svg") | |
| .data([{width: width, height: height}]).enter() | |
| .append("svg"); | |
| svg.attr({ | |
| width: function (d) { return d.width; }, | |
| height: function (d) { return d.height; } | |
| }); | |
| background = svg.selectAll("rect.background") | |
| .data([{}]).enter() | |
| .append("rect") | |
| .classed("background", true); | |
| g = svg.selectAll("g.all") | |
| .data([{}]).enter() | |
| .append("g") | |
| .classed("all", true); | |
| // vis.init can be re-ran to pass different height/width values | |
| // to the svg. this doesn't create new svg elements. | |
| style = svg.selectAll("style") | |
| .data([{}]).enter() | |
| .append("style") | |
| .attr("type", "text/css"); | |
| // this is where we can insert style that will affect the svg directly. | |
| defs = svg.selectAll("defs").data([{}]).enter() | |
| .append("defs"); | |
| // this is used if it's necessary to define gradients, patterns etc. | |
| // the following will implement interaction around a slider and a | |
| // button. repeat/remove as needed. | |
| // note that this code won't cause errors if the corresponding elements | |
| // do not exist in the HTML. | |
| slider = d3.select(vis.params.slider || ".slider"); | |
| if (slider[0][0]) { | |
| maxStep = slider.property("max"); | |
| step = slider.property("value"); | |
| slider.on("change", function () { | |
| vis.stop(); | |
| step = this.value; | |
| vis.draw(vis.params); | |
| }); | |
| running = vis.params.running || 0; // autorunning off or manually set on | |
| } else { | |
| running = -1; // never attempt auto-running | |
| } | |
| button = d3.select(vis.params.button || ".button"); | |
| if (button[0][0] && running > -1) { | |
| button.on("click", function () { | |
| if (running) { | |
| vis.stop(); | |
| } else { | |
| vis.start(); | |
| } | |
| }); | |
| } | |
| vis.loaddata(vis.params); | |
| }; | |
| function ready(error, firs, world, wnames) { | |
| if (error) { | |
| console.error(error); | |
| } | |
| vis.firs = firs; | |
| vis.world = world; | |
| vis.wnames = wnames; | |
| if (running > 0) { | |
| vis.start(); | |
| } else { | |
| vis.draw(vis.params); | |
| } | |
| } | |
| vis.loaddata = function (params) { | |
| console.log("in loaddata, params: " + JSON.stringify(params)); | |
| if (!params) { params = {}; } | |
| // if `params.refresh` is set/true forces the browser to reload the file | |
| // and not use the cached version due to URL being different (but the filename is the same) | |
| var topo = (params.topo || "ectrl-firs.json") + (params.refresh ? ("#" + Math.random()) : ""); | |
| var world = (params.world || "world-50m.json") + (params.refresh ? ("#" + Math.random()) : ""); | |
| var names = (params.worldnames || "world-country-names.tsv") + (params.refresh ? ("#" + Math.random()) : ""); | |
| queue() | |
| .defer(d3.json, topo) | |
| .defer(d3.json, world) | |
| .defer(d3.tsv, names) | |
| .await(ready); | |
| }; | |
| vis.play = function () { | |
| if (i === maxStep && !running) { | |
| step = -1; | |
| vis.stop(); | |
| } | |
| if (i < maxStep) { | |
| step = step + 1; | |
| running = 1; | |
| d3.select(".stop").html("Pause").on("click", vis.stop(params)); | |
| slider.property("value", sv); | |
| vis.draw(params); | |
| } else { | |
| vis.stop(); | |
| } | |
| }; | |
| vis.start = function (params) { | |
| timer = setInterval(function () { vis.play(params); }, 50); | |
| }; | |
| vis.stop = function (params) { | |
| clearInterval(timer); | |
| running = 0; | |
| d3.select(".stop").html("Play").on("click", vis.start(params)); | |
| }; | |
| var zoom = d3.behavior.zoom() | |
| .scaleExtent([1, 8000]) | |
| .on("zoom", zoomed); | |
| function zoomed() { | |
| g.style("stroke-width", 1.5 / d3.event.scale + "px"); | |
| g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); | |
| } | |
| // If the drag behavior prevents the default click, | |
| // also stop propagation so we don’t click-to-zoom. | |
| function stopped() { | |
| if (d3.event.defaultPrevented) d3.event.stopPropagation(); | |
| } | |
| function reset() { | |
| active.classed("active", false); | |
| active = d3.select(null); | |
| svg.transition() | |
| .duration(750) | |
| .call(zoom.translate([0, 0]).scale(1).event); | |
| } | |
| function clicked(d) { | |
| if (active.node() === this) { | |
| return reset(); | |
| } | |
| active.classed("active", false); | |
| active = d3.select(this).classed("active", true); | |
| var bounds = path.bounds(d), | |
| dx = bounds[1][0] - bounds[0][0], | |
| dy = bounds[1][1] - bounds[0][1], | |
| x = (bounds[0][0] + bounds[1][0]) / 2, | |
| y = (bounds[0][1] + bounds[1][1]) / 2, | |
| scale = .9 / Math.max(dx / width, dy / height), | |
| translate = [width / 2 - scale * x, height / 2 - scale * y]; | |
| svg.transition() | |
| .duration(750) | |
| .call(zoom.translate(translate).scale(scale).event); | |
| } | |
| vis.draw = function (params) { | |
| // make stuff here! | |
| console.log("in draw, params: " + JSON.stringify(params)); | |
| var pars = params || {}, | |
| scale = pars.scale || 600, | |
| cLon = pars.centerLon || 0, | |
| cLat = pars.centerLan || 55.4, | |
| projection = d3.geo.albers() | |
| .center([cLon, cLat]) | |
| .rotate([4.4, 0]) | |
| .parallels([50, 60]) | |
| .scale(scale) | |
| .translate([width / 2, height / 2]), | |
| fff = vis.firs.objects.firs, | |
| firs = topojson.feature(vis.firs, fff), | |
| tooltip = d3.select("#tooltip").classed("hidden", true), | |
| countryname = d3.select("#countryname"), | |
| graticule = d3.geo.graticule(), | |
| land = topojson.feature(vis.world, vis.world.objects.land), | |
| countries = topojson.feature(vis.world, vis.world.objects.countries).features, | |
| borders = topojson.mesh(vis.world, vis.world.objects.countries, function (a, b) { return a.id !== b.id; }), | |
| country, | |
| fir, | |
| uir; | |
| path = d3.geo.path() | |
| .projection(projection); | |
| countries.forEach(function (d) { | |
| vis.wnames.some(function (n) { | |
| if (+d.id === +n.id) { | |
| d.name = n.name; | |
| return d.name; | |
| } | |
| }); | |
| }); | |
| svg.on("click", stopped, true); | |
| background.on("click", reset); | |
| g.style("stroke-width", "0.5px"); | |
| svg | |
| .call(zoom) // delete this line to disable free zooming | |
| .call(zoom.event); | |
| svg.on("mousemove", function () { | |
| // update tooltip position | |
| tooltip.style("top", (event.pageY + 16) + "px").style("left", (event.pageX + 10) + "px"); | |
| return true; | |
| }); | |
| svg.selectAll(".path.graticule") | |
| .data([graticule]).enter() | |
| .append("path") | |
| .classed("graticule", true) | |
| .attr("d", path); | |
| country = g.selectAll(".country") | |
| .data(countries) | |
| .enter().insert("path", ".graticule") | |
| .attr("class", function (d) {return "country country" + d.id; }) | |
| .attr("d", path) | |
| .text(function (d) { return d.id; }) | |
| .on("mouseover", function (d, i) { | |
| d3.select(this).style({'stroke-opacity': 1, 'stroke': '#F00'}); | |
| // http://stackoverflow.com/questions/17917072/#answer-17917341 | |
| // d3.select(this.parentNode.appendChild(this)).style({'stroke-opacity':1,'stroke':'#F00'}); | |
| if (d.id) { | |
| tooltip.classed("hidden", false); | |
| countryname.text(d.name); | |
| } | |
| }) | |
| .on("mouseout", function () { | |
| this.style.stroke = "none"; | |
| tooltip.classed("hidden", true); | |
| }) | |
| .on("mousedown.log", function (d) { | |
| console.log("id=" + d.id + "; name=" + d.name + "; centroid=[" + path.centroid(d) + "] px."); | |
| }); | |
| // FIRs | |
| fir = g.selectAll(".fir") | |
| .data(firs.features) | |
| .enter().insert("path", ".graticule") | |
| .attr("class", function (d) { return "fir " + d.id; }) | |
| .attr("d", path) | |
| .on("click", clicked) | |
| .on("mouseover", function (d) { | |
| d3.select(this).style("fill", "red"); | |
| tooltip.classed("hidden", false); | |
| countryname.html("<h4>" + (d.properties.name || "- no name -") + "</h4>" + | |
| "<b>ID</b>: " +d.properties.id + "<br>" + | |
| "<b>FL</b>: [" + d.properties.minfl + ", " + d.properties.maxfl + "]<br>" + | |
| "<b>Fab</b>: " + (d.properties.fab || "-" ) + "</p>"); | |
| }) | |
| .on("mouseleave", function () { | |
| d3.select(this).style("fill", "#ddc"); | |
| tooltip.classed("hidden", true); | |
| }); | |
| // intra FIR borders | |
| g.selectAll(".fir-boundary") | |
| .data([topojson.mesh(vis.firs, fff, function (a, b) { | |
| return a !== b; | |
| })]) | |
| .enter().insert("path", ".graticule") | |
| .attr("d", path) | |
| .attr("class", "fir-boundary"); | |
| // external borders | |
| g.selectAll("fir-boundary ECTRL") | |
| .data([topojson.mesh(vis.firs, fff, function (a, b) { | |
| return a === b; | |
| })]) | |
| .enter().insert("path", ".graticule") | |
| .attr("d", path) | |
| .attr("class", "fir-boundary ECTRL"); | |
| }; | |
| }()); |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <body> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://d3js.org/topojson.v1.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js" type="text/javascript"></script> | |
| <link href="fir.css" rel="stylesheet"> | |
| <script src="firs.js"></script> | |
| <div id="tooltip" class="hidden"> | |
| <p id="countryname"></p> | |
| </div><div id="chart"></div> | |
| <script type="text/javascript"> | |
| (function () { | |
| // general design from | |
| // http://www.jeromecukier.net/blog/2013/11/20/getting-beyond-hello-world-with-d3/ | |
| var params = { | |
| refresh: false, // REMOVE, i.e. `false`, for production | |
| width: 960, | |
| height:500, | |
| scale: 470, | |
| centerLat:65.4, | |
| centerLon: 0, | |
| topo: "euctrl-firs.json", | |
| world: "world-110m.json", | |
| worldnames: "world-country-names.tsv" | |
| }; | |
| var query = window.location.search.substring(1); | |
| var vars = query.split("&"); | |
| vars.forEach(function(v) { | |
| var p = v.split("="); | |
| params[p[0]] = p[1]; | |
| }) | |
| console.log("params: " + JSON.stringify(params)); | |
| vis.init(params); | |
| }()); | |
| </script> |
| id | name | |
|---|---|---|
| -1 | Northern Cyprus | |
| -2 | Kosovo | |
| -3 | Somaliland | |
| 4 | Afghanistan | |
| 8 | Albania | |
| 10 | Antarctica | |
| 12 | Algeria | |
| 16 | American Samoa | |
| 20 | Andorra | |
| 24 | Angola | |
| 28 | Antigua and Barbuda | |
| 31 | Azerbaijan | |
| 32 | Argentina | |
| 36 | Australia | |
| 40 | Austria | |
| 44 | Bahamas | |
| 48 | Bahrain | |
| 50 | Bangladesh | |
| 51 | Armenia | |
| 52 | Barbados | |
| 56 | Belgium | |
| 60 | Bermuda | |
| 64 | Bhutan | |
| 68 | Bolivia, Plurinational State of | |
| 70 | Bosnia and Herzegovina | |
| 72 | Botswana | |
| 74 | Bouvet Island | |
| 76 | Brazil | |
| 84 | Belize | |
| 86 | British Indian Ocean Territory | |
| 90 | Solomon Islands | |
| 92 | Virgin Islands, British | |
| 96 | Brunei Darussalam | |
| 100 | Bulgaria | |
| 104 | Myanmar | |
| 108 | Burundi | |
| 112 | Belarus | |
| 116 | Cambodia | |
| 120 | Cameroon | |
| 124 | Canada | |
| 132 | Cape Verde | |
| 136 | Cayman Islands | |
| 140 | Central African Republic | |
| 144 | Sri Lanka | |
| 148 | Chad | |
| 152 | Chile | |
| 156 | China | |
| 158 | Taiwan, Province of China | |
| 162 | Christmas Island | |
| 166 | Cocos (Keeling) Islands | |
| 170 | Colombia | |
| 174 | Comoros | |
| 175 | Mayotte | |
| 178 | Congo | |
| 180 | Congo, the Democratic Republic of the | |
| 184 | Cook Islands | |
| 188 | Costa Rica | |
| 191 | Croatia | |
| 192 | Cuba | |
| 196 | Cyprus | |
| 203 | Czech Republic | |
| 204 | Benin | |
| 208 | Denmark | |
| 212 | Dominica | |
| 214 | Dominican Republic | |
| 218 | Ecuador | |
| 222 | El Salvador | |
| 226 | Equatorial Guinea | |
| 231 | Ethiopia | |
| 232 | Eritrea | |
| 233 | Estonia | |
| 234 | Faroe Islands | |
| 238 | Falkland Islands (Malvinas) | |
| 239 | South Georgia and the South Sandwich Islands | |
| 242 | Fiji | |
| 246 | Finland | |
| 248 | Åland Islands | |
| 250 | France | |
| 254 | French Guiana | |
| 258 | French Polynesia | |
| 260 | French Southern Territories | |
| 262 | Djibouti | |
| 266 | Gabon | |
| 268 | Georgia | |
| 270 | Gambia | |
| 275 | Palestinian Territory, Occupied | |
| 276 | Germany | |
| 288 | Ghana | |
| 292 | Gibraltar | |
| 296 | Kiribati | |
| 300 | Greece | |
| 304 | Greenland | |
| 308 | Grenada | |
| 312 | Guadeloupe | |
| 316 | Guam | |
| 320 | Guatemala | |
| 324 | Guinea | |
| 328 | Guyana | |
| 332 | Haiti | |
| 334 | Heard Island and McDonald Islands | |
| 336 | Holy See (Vatican City State) | |
| 340 | Honduras | |
| 344 | Hong Kong | |
| 348 | Hungary | |
| 352 | Iceland | |
| 356 | India | |
| 360 | Indonesia | |
| 364 | Iran, Islamic Republic of | |
| 368 | Iraq | |
| 372 | Ireland | |
| 376 | Israel | |
| 380 | Italy | |
| 384 | Côte d'Ivoire | |
| 388 | Jamaica | |
| 392 | Japan | |
| 398 | Kazakhstan | |
| 400 | Jordan | |
| 404 | Kenya | |
| 408 | Korea, Democratic People's Republic of | |
| 410 | Korea, Republic of | |
| 414 | Kuwait | |
| 417 | Kyrgyzstan | |
| 418 | Lao People's Democratic Republic | |
| 422 | Lebanon | |
| 426 | Lesotho | |
| 428 | Latvia | |
| 430 | Liberia | |
| 434 | Libya | |
| 438 | Liechtenstein | |
| 440 | Lithuania | |
| 442 | Luxembourg | |
| 446 | Macao | |
| 450 | Madagascar | |
| 454 | Malawi | |
| 458 | Malaysia | |
| 462 | Maldives | |
| 466 | Mali | |
| 470 | Malta | |
| 474 | Martinique | |
| 478 | Mauritania | |
| 480 | Mauritius | |
| 484 | Mexico | |
| 492 | Monaco | |
| 496 | Mongolia | |
| 498 | Moldova, Republic of | |
| 499 | Montenegro | |
| 500 | Montserrat | |
| 504 | Morocco | |
| 508 | Mozambique | |
| 512 | Oman | |
| 516 | Namibia | |
| 520 | Nauru | |
| 524 | Nepal | |
| 528 | Netherlands | |
| 531 | Curaçao | |
| 533 | Aruba | |
| 534 | Sint Maarten (Dutch part) | |
| 535 | Bonaire, Sint Eustatius and Saba | |
| 540 | New Caledonia | |
| 548 | Vanuatu | |
| 554 | New Zealand | |
| 558 | Nicaragua | |
| 562 | Niger | |
| 566 | Nigeria | |
| 570 | Niue | |
| 574 | Norfolk Island | |
| 578 | Norway | |
| 580 | Northern Mariana Islands | |
| 581 | United States Minor Outlying Islands | |
| 583 | Micronesia, Federated States of | |
| 584 | Marshall Islands | |
| 585 | Palau | |
| 586 | Pakistan | |
| 591 | Panama | |
| 598 | Papua New Guinea | |
| 600 | Paraguay | |
| 604 | Peru | |
| 608 | Philippines | |
| 612 | Pitcairn | |
| 616 | Poland | |
| 620 | Portugal | |
| 624 | Guinea-Bissau | |
| 626 | Timor-Leste | |
| 630 | Puerto Rico | |
| 634 | Qatar | |
| 638 | Réunion | |
| 642 | Romania | |
| 643 | Russian Federation | |
| 646 | Rwanda | |
| 652 | Saint Barthélemy | |
| 654 | Saint Helena, Ascension and Tristan da Cunha | |
| 659 | Saint Kitts and Nevis | |
| 660 | Anguilla | |
| 662 | Saint Lucia | |
| 663 | Saint Martin (French part) | |
| 666 | Saint Pierre and Miquelon | |
| 670 | Saint Vincent and the Grenadines | |
| 674 | San Marino | |
| 678 | Sao Tome and Principe | |
| 682 | Saudi Arabia | |
| 686 | Senegal | |
| 688 | Serbia | |
| 690 | Seychelles | |
| 694 | Sierra Leone | |
| 702 | Singapore | |
| 703 | Slovakia | |
| 704 | Viet Nam | |
| 705 | Slovenia | |
| 706 | Somalia | |
| 710 | South Africa | |
| 716 | Zimbabwe | |
| 724 | Spain | |
| 728 | South Sudan | |
| 729 | Sudan | |
| 732 | Western Sahara | |
| 740 | Suriname | |
| 744 | Svalbard and Jan Mayen | |
| 748 | Swaziland | |
| 752 | Sweden | |
| 756 | Switzerland | |
| 760 | Syrian Arab Republic | |
| 762 | Tajikistan | |
| 764 | Thailand | |
| 768 | Togo | |
| 772 | Tokelau | |
| 776 | Tonga | |
| 780 | Trinidad and Tobago | |
| 784 | United Arab Emirates | |
| 788 | Tunisia | |
| 792 | Turkey | |
| 795 | Turkmenistan | |
| 796 | Turks and Caicos Islands | |
| 798 | Tuvalu | |
| 800 | Uganda | |
| 804 | Ukraine | |
| 807 | Macedonia, the former Yugoslav Republic of | |
| 818 | Egypt | |
| 826 | United Kingdom | |
| 831 | Guernsey | |
| 832 | Jersey | |
| 833 | Isle of Man | |
| 834 | Tanzania, United Republic of | |
| 840 | United States | |
| 850 | Virgin Islands, U.S. | |
| 854 | Burkina Faso | |
| 858 | Uruguay | |
| 860 | Uzbekistan | |
| 862 | Venezuela, Bolivarian Republic of | |
| 876 | Wallis and Futuna | |
| 882 | Samoa | |
| 887 | Yemen | |
| 894 | Zambia |