Atlas uniforme, placement des feuilles Using geoShape
TODO:
xxxxxxxxxx
<meta charset="utf-8">
<div id="legend">
Feuilles de l'Atlas uniforme
</div>
<svg width="960" height="600">
<defs>
<style type="text/css">
text {
font-family: Arial;
}
#sphere {
fill: #fff;
stroke: #444;
stroke-width: 2;
}
.polygons {
stroke: #444;
}
.links {
stroke: #aaa;
stroke-width: 0.5;
fill: none;
}
.links .secondary {
stroke-width: .5;
stroke-dasharray: 3 1;
}
.sites {
stroke: black;
fill: white;
}
.countries {
fill: #999;
opacity: 0.3;
}
text {
font-size: 12px;
}
</style>
</defs>
</svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script src="d3-geo.js"></script>
<script>
const pi = Math.PI;
feuilles = [
[1, "Arctide … Pôle Nord", 0,90, -90 + 25], // rotation de maniere a avoir le golfe de Botnie à droite
[2, "Europe", 20,54],
[3, "Oural et Yenissei", 90, 61],
[4, "Amour et Lena", 141, 57],
[5, "Alaska", -161, 57],
[6, "Mackenzie et Hudson", -98, 61],
[7, "Atlantique boréal", -39, 57],
[8, "Méditerranée et Sahara", 12, 32],
[9, "Caspienne", 58, 40],
[10, "Euphrate et Gange", 65, 24],
[11, "Chine", 113, 27],
[12, "Japon", 160, 29],
[13, "Hawaï", -146, 29],
[14, "Mississippi et Saint-Laurent", -94, 35],
[15, "Antilles", -80, 20],
[16, "Atlantique, de Lisbonne à la Trinidad", -40, 29],
[17, "Nil", 29, 13],
[18, "Océan Indien Asiatique", 70, 7],
[19, "Insulasie", 118, 1],
[20, "Mélanésie", 160, 0],
[21, "Polynésie", -152, 0],
[22, "Galapagos", -104, 0],
[23, "Amazone", -59, 0],
[24, "Atlantique équatorial", -14, 0],
[25, "Zambèze et Cap", 33, -20],
[26, "Océan Indien, de Maurice à Perth", 84, -24],
[27, "Australie", 134, -26],
[28, "Nouvelle Zélande", 178, -30],
[29, "Pomotou", -123, -24],
[30, "Paraná", -68, -24],
[31, "Atlantique, de Rio au Cap", -13, -24, 0], // CORRECTIF ? PAUL RECLUS DIT 17°W AU LIEU DE 13°W
[32, "Kerguelen, Enderby", 48, -55],
[33, "Océan Indien Austral", 108, -55],
[34, "Antipodes", 168, -55],
[35, "Pacifique Austral", -132, -55],
[36, "Cap Horn", -72, -55],
[37, "Atlantique austral", -12, -55],
[38, "Pôle Sud", 0, -88.7, 90 - 102],
// idem pole nord, sur l'angle 102° (-78° si on préfère retourner)
// ajout petit décalage Philippe Rivière à -88.5° pour avoir toute la masse continentale
]
oreilles = {
1: [],
2: [],
3: [ (pi + 0.2) /* Tchoumikan, inutile ?? */, (3 * pi/4 + 0.28) /* Beijing, inutile ?? */],
4: [ (3 * pi /2) /* Nouvelle-Sibérie, oreille indiquée à droite pas à gauche */],
5: [ (3 * pi/4 + 0.4) /* Seattle */],
6: [ (3 * pi/4 + 0.6) /* Terre-Neuve */],
31: [(3 * pi/4 + 0.28) /* Le Cap */],
32: [],
}
/*
* renvoie le contour d'une feuille sous forme d'un Polygon geojson
*/
const l = 55/2, h = 38/2, g = 28.5;
const mx = l/g, my = h/g;
function contour(feuille) {
let c = [+feuille[2], +feuille[3], feuille[4]||0];
let polygon = d3.geoShape()
.generator(
t => {
// cercle g = 28.5°
let x = Math.cos(t), y = Math.sin(t);
// extent
let f = 1.05; // renflement
if (x > mx) x -= (x-mx) * f;
if (x < -mx) x -= (x+mx) * f;
if (y > my) y -= (y-my) * f;
if (y < -my) y -= (y+my) * f;
// oreille(s)
(oreilles[feuille[0]]||[]).forEach(oreille => {
let a = t - oreille,
e = 0.28,
h = .1;
if (Math.abs(a)<e){
let f = 1 + h * Math.pow((1+a/e) * (1-a/e),2);
x *= f;
y *= f;
}
})
// rotation
var r = (feuille[4]||0) * Math.PI/180, c = Math.cos(r), s = Math.sin(r);
return [x * c - y * s, y * c + x * s];
}
)
.center(c)
.precision(0.2)
.radius(g)()
return polygon;
}
var points = {
type: "FeatureCollection",
features: feuilles.map(d => {
return {
type: "Point",
coordinates: [ d[2], d[3] ],
properties: { name: `${d[0]}. ${d[1]}` }
}
})
}
var projection = d3.geoEquirectangular().rotate([-175,0]), //d3.geoOrthographic(),
path = d3.geoPath().projection(projection);
var svg = d3.select("svg");
svg.append('path')
.attr('id', 'sphere')
.datum({ type: "Sphere" })
.attr('d', path);
svg.append('g')
.attr('class', 'polygons')
.selectAll('path')
.data(feuilles.map(contour))
.enter()
.append('path')
.attr('d', path)
.attr('stroke', function(_,i) { return d3.schemeCategory10[i%10]; })
.attr('fill', function(_,i) { return d3.schemeCategory10[i%10]; })
.attr('fill-opacity', 0.1)
.append('title').text((d,i) => `${feuilles[i][0]}. ${feuilles[i][1]}`);
countries = svg.append('g')
.attr('class', 'countries')
svg.append('g')
.attr('class', 'sites')
.selectAll('path')
.data(points.features)
.enter()
.append('path')
.attr('d', path);
svg.append('g')
.attr('class', 'labels')
.selectAll('text')
.data(points.features)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.attr('x', d => Math.max(70,projection(d.coordinates)[0]))
.attr('y', d => Math.max(45,projection(d.coordinates)[1]-8))
.text(d => d.properties.name.length > 23 ? d.properties.name.substring(0,18)+'…' : d.properties.name)
;
// gentle animation
if (false)
d3.interval(function(elapsed) {
projection.rotate([ elapsed / 150, 0 ]);
svg.selectAll('path')
.attr('d', path);
}, 50);
d3.queue()
.defer(d3.json, 'countries.topo.json')
.await(function (err, wjson) {
countries
.selectAll('path')
.data(topojson.feature(wjson, wjson.objects.countries).features)
.enter()
.append('path')
.attr('d', path);
});
</script>
https://d3js.org/d3.v4.min.js
https://d3js.org/topojson.v1.min.js