Carte de France en SVG

La démonstration utilise essentiellement les technologies SVG et CSS (et 3 lignes de javascript).
Le fichier SVG a été en partie généré par un programmme PHP.

Densité de population en France de 1975 à 2015

Paris Lyon Marseille Toulouse Grand-Est - 1975 5 187 204 habs 90 hab/km2 Grand-Est - 1980 5 210 823 habs 91 hab/km2 Grand-Est - 1985 5 263 949 habs 92 hab/km2 Grand-Est - 1990 5 274 064 habs 92 hab/km2 Grand-Est - 1995 5 353 077 habs 93 hab/km2 Grand-Est - 2000 5 400 871 habs 94 hab/km2 Grand-Est - 2005 5 475 270 habs 95 hab/km2 Grand-Est - 2010 5 532 530 habs 96 hab/km2 Grand-Est - 2015 5 559 313 habs 97 hab/km2 Nouvelle Aquitaine - 1975 4 821 082 habs 57 hab/km2 Nouvelle Aquitaine - 1980 4 915 636 habs 58 hab/km2 Nouvelle Aquitaine - 1985 5 021 742 habs 60 hab/km2 Nouvelle Aquitaine - 1990 5 114 287 habs 61 hab/km2 Nouvelle Aquitaine - 1995 5 191 946 habs 62 hab/km2 Nouvelle Aquitaine - 2000 5 296 850 habs 63 hab/km2 Nouvelle Aquitaine - 2005 5 526 990 habs 66 hab/km2 Nouvelle Aquitaine - 2010 5 745 486 habs 68 hab/km2 Nouvelle Aquitaine - 2015 5 914 024 habs 70 hab/km2 Auvergne Rhône-Alpes - 1975 6 111 379 habs 88 hab/km2 Auvergne Rhône-Alpes - 1980 6 267 442 habs 90 hab/km2 Auvergne Rhône-Alpes - 1985 6 457 905 habs 93 hab/km2 Auvergne Rhône-Alpes - 1990 6 668 168 habs 96 hab/km2 Auvergne Rhône-Alpes - 1995 6 837 322 habs 98 hab/km2 Auvergne Rhône-Alpes - 2000 7 000 751 habs 100 hab/km2 Auvergne Rhône-Alpes - 2005 7 295 515 habs 105 hab/km2 Auvergne Rhône-Alpes - 2010 7 578 078 habs 109 hab/km2 Auvergne Rhône-Alpes - 2015 7 884 096 habs 113 hab/km2 Bourgogne Franche-Comté - 1975 2 632 357 habs 55 hab/km2 Bourgogne Franche-Comté - 1980 2 664 007 habs 56 hab/km2 Bourgogne Franche-Comté - 1985 2 696 050 habs 56 hab/km2 Bourgogne Franche-Comté - 1990 2 705 826 habs 57 hab/km2 Bourgogne Franche-Comté - 1995 2 727 049 habs 57 hab/km2 Bourgogne Franche-Comté - 2000 2 734 330 habs 57 hab/km2 Bourgogne Franche-Comté - 2005 2 771 934 habs 58 hab/km2 Bourgogne Franche-Comté - 2010 2 813 878 habs 59 hab/km2 Bourgogne Franche-Comté - 2015 2 821 712 habs 59 hab/km2 Bretagne - 1975 2 596 379 habs 95 hab/km2 Bretagne - 1980 2 672 575 habs 98 hab/km2 Bretagne - 1985 2 738 485 habs 101 hab/km2 Bretagne - 1990 2 794 317 habs 103 hab/km2 Bretagne - 1995 2 840 680 habs 104 hab/km2 Bretagne - 2000 2 927 612 habs 108 hab/km2 Bretagne - 2005 3 066 585 habs 113 hab/km2 Bretagne - 2010 3 199 066 habs 118 hab/km2 Bretagne - 2015 3 295 145 habs 121 hab/km2 Centre Val-de-Loire - 1975 2 152 234 habs 55 hab/km2 Centre Val-de-Loire - 1980 2 227 750 habs 57 hab/km2 Centre Val-de-Loire - 1985 2 307 725 habs 59 hab/km2 Centre Val-de-Loire - 1990 2 369 808 habs 61 hab/km2 Centre Val-de-Loire - 1995 2 418 315 habs 62 hab/km2 Centre Val-de-Loire - 2000 2 450 121 habs 63 hab/km2 Centre Val-de-Loire - 2005 2 507 246 habs 64 hab/km2 Centre Val-de-Loire - 2010 2 548 065 habs 65 hab/km2 Centre Val-de-Loire - 2015 2 583 705 habs 66 hab/km2 Corse - 1975 226 991 habs 26 hab/km2 Corse - 1980 235 733 habs 27 hab/km2 Corse - 1985 244 455 habs 28 hab/km2 Corse - 1990 249 645 habs 29 hab/km2 Corse - 1995 258 416 habs 30 hab/km2 Corse - 2000 264 539 habs 30 hab/km2 Corse - 2005 289 092 habs 33 hab/km2 Corse - 2010 309 693 habs 36 hab/km2 Corse - 2015 327 374 habs 38 hab/km2 Île-de-France - 1975 9 873 663 habs 822 hab/km2 Île-de-France - 1980 9 992 276 habs 832 hab/km2 Île-de-France - 1985 10 238 860 habs 852 hab/km2 Île-de-France - 1990 10 644 665 habs 886 hab/km2 Île-de-France - 1995 10 858 975 habs 904 hab/km2 Île-de-France - 2000 11 019 991 habs 917 hab/km2 Île-de-France - 2005 11 442 143 habs 953 hab/km2 Île-de-France - 2010 11 786 234 habs 981 hab/km2 Île-de-France - 2015 12 088 695 habs 1 006 hab/km2 Occitanie - 1975 4 060 465 habs 56 hab/km2 Occitanie - 1980 4 186 069 habs 58 hab/km2 Occitanie - 1985 4 375 084 habs 60 hab/km2 Occitanie - 1990 4 546 249 habs 63 hab/km2 Occitanie - 1995 4 703 840 habs 65 hab/km2 Occitanie - 2000 4 900 326 habs 67 hab/km2 Occitanie - 2005 5 240 791 habs 72 hab/km2 Occitanie - 2010 5 518 106 habs 76 hab/km2 Occitanie - 2015 5 782 691 habs 80 hab/km2 Hauts-de-France - 1975 5 595 291 habs 176 hab/km2 Hauts-de-France - 1980 5 637 664 habs 177 hab/km2 Hauts-de-France - 1985 5 706 937 habs 179 hab/km2 Hauts-de-France - 1990 5 770 671 habs 181 hab/km2 Hauts-de-France - 1995 5 832 496 habs 183 hab/km2 Hauts-de-France - 2000 5 860 802 habs 184 hab/km2 Hauts-de-France - 2005 5 904 641 habs 186 hab/km2 Hauts-de-France - 2010 5 953 001 habs 187 hab/km2 Hauts-de-France - 2015 6 021 160 habs 189 hab/km2 Normandie - 1975 2 902 584 habs 97 hab/km2 Normandie - 1980 2 971 205 habs 99 hab/km2 Normandie - 1985 3 058 731 habs 102 hab/km2 Normandie - 1990 3 126 859 habs 105 hab/km2 Normandie - 1995 3 179 350 habs 106 hab/km2 Normandie - 2000 3 211 503 habs 107 hab/km2 Normandie - 2005 3 259 102 habs 109 hab/km2 Normandie - 2010 3 310 448 habs 111 hab/km2 Normandie - 2015 3 340 717 habs 112 hab/km2 Pays de la Loire - 1975 2 766 891 habs 86 hab/km2 Pays de la Loire - 1980 2 878 179 habs 90 hab/km2 Pays de la Loire - 1985 2 986 459 habs 93 hab/km2 Pays de la Loire - 1990 3 055 197 habs 95 hab/km2 Pays de la Loire - 1995 3 145 757 habs 98 hab/km2 Pays de la Loire - 2000 3 248 994 habs 101 hab/km2 Pays de la Loire - 2005 3 415 391 habs 106 hab/km2 Pays de la Loire - 2010 3 571 495 habs 111 hab/km2 Pays de la Loire - 2015 3 719 510 habs 116 hab/km2 Provence Alpes Côte-d'Azur - 1975 3 673 480 habs 117 hab/km2 Provence Alpes Côte-d'Azur - 1980 3 872 028 habs 123 hab/km2 Provence Alpes Côte-d'Azur - 1985 4 060 921 habs 129 hab/km2 Provence Alpes Côte-d'Azur - 1990 4 257 244 habs 136 hab/km2 Provence Alpes Côte-d'Azur - 1995 4 405 312 habs 140 hab/km2 Provence Alpes Côte-d'Azur - 2000 4 541 508 habs 145 hab/km2 Provence Alpes Côte-d'Azur - 2005 4 768 564 habs 152 hab/km2 Provence Alpes Côte-d'Azur - 2010 4 899 155 habs 156 hab/km2 Provence Alpes Côte-d'Azur - 2015 5 005 806 habs 159 hab/km2
1975

Les données

Les données proviennent:

  1. la carte SVG du site AMCHARTS Free SVG Maps - France 2016
  2. les données de population par région, d'un fichier excel de l'INSEE: Estimation de la population au 1 er janvier 2016
  3. la superficie des régions de wikipédia Classements des régions françaises

La carte

La carte provenant du site AMCHARTS est une carte au format SVG.

La viewBox

Il nous faut déterminer le plus petit rectangle (xmin, ymin, width, height) contenant toutes les régions de la carte.
Il est possible de l'obtenir avec un éditeur de SVG tel Illustrator.
Une autre possibilité est en insérant le svg dans une page HTML, d'accéder à ces valeurs via javascript:

// Le svg est inclus dans une page HTML5
var svg = document.querySelector('svg');
var bbox = svg.getBBox();
// -
Le résultat est ici bbox = { x: 16.8203125, y: 0, width: 595.13671875, height: 583.9453125}.

Pour afficher la “scéne” entière, il convient de définir l'attribut viewBox du svg avec ces valeurs (arrondies):

<svg viewBox="17 0 596 584">
<!--- etc ->
</svg>

Les régions

Chaque région est définie par un path auquel j'ai ajouté une classe spécifique à la région:

<path id="FR-A" title="Alsace-Champagne-Ardenne-Lorraine" class="land FR_A" d="M544.492,131.018l....149,0.435L544.492,131.018z"/>
<!---etc...->

Projection

Très utile, pour ajouter des éléments géographiques sur la carte, la projection utilisée pour obtenir ces contours est donnée dans la balise amcharts:ammap:

<amcharts:ammap projection="mercator" leftLongitude="-4.778054" topLatitude="51.089278" rightLongitude="9.560176" bottomLatitude="41.363005"></amcharts:ammap>

<!-->

Nous avons aussi besoin de la bbox pour reconstituer la projection.
Attention elle peut être modifier par l'ajout d'éléments au SVG.
Pour les calculs de projection, il est donc nécessaire d'utiliser la bbox de départ et de ne plus utiliser la méthode getBBox

Reconstitution de la projection de Mercator

La projection de Mercator est explicitée sur Wikipédia : Projection de Mercator.
Les formules ne sont pas hyper-explicites, elles convertiraient dans notre cas:
La position de (lat, lng) en sa position (X, Y) dans un repère centré sur la position latitude=0, longitude=0 avec une largeur de 360 et une orientation anti-trigonométrique (comme le repère SVG) donnerait:
mercatorLngToX: lng right lng avec -180<= lng <= 180
mercatorLatToY: lat right   - {360/{2 pi}}*({1/2}* ln( {1+sin(lat)}/{1-sin(lat)})) avec -90 < lat < 90

Ensuite, on change de repère en utilisant les données de la bbox et de la projection amcharts:
delim{lbrace}{matrix{4}{1}{{leftLongitude=-4.778054}{topLatitude=51.089278}{rightLongitude=9.560176} {bottomLatitude=41.363005}}}{}

on a alors à partir d'un point (lat, lng):
x= {{lng - leftLongitude} / {rightLongitude - leftLongitude}}* bbox.width + bbox.x
y= {{mercatorLatToY(lat) - mercatorLatToY( topLatitude)} / {mercatorLatToY( bottomLatitude)-mercatorLatToY( topLatitude)}}*bbox.height+bbox.y

Quand on implémente, il faut faire attention de bien convertir les latitudes en radians avant de les injecter dans les fonctions trigonométriques.

On peut ainsi ajouter par exemple un rond sur Paris après avoir converti ses coordonnées gps (48.866667, 2.333333) dans le repère du SVG :

<circle cx="312.41" cy="144.43" r="3" stroke="black" stroke-width="1" fill="red"></circle>
<!-->

Insertion des données dans le SVG

Les éléments ajoutés dans le svg

Les données sont extraites du fichier excel avec la merveilleuse classe PHPExcel.
Elles sont écrites dans le svg après les paths comme ci-dessous:

<!-- pour la région FR_A de centre (464 = 404 + 60, 154 = 134 + 20) -->
<g transform="translate(404,134)" class="FR_A">

    <!-- le rectangle derrière le texte -->
    <rect  width="120" height="40"></rect>
    
    <!-- Pour l'année 1975 -->
    <text class="year1975" x="5" y="9">Grand-Est - 1975   
        <tspan x="5" y="28">5 187 204 habs</tspan>
        <tspan x="5" y="37">90 hab/km2</tspan>
    </text>
    <!------....etc ---->
    
    <!-- Pour l'année 2015 -->
    <text class="year2015" x="5" y="9" >Grand-Est - 2015   
        <tspan x="5" y="28">5 559 313 habs</tspan>
        <tspan x="5" y="37">97 hab/km2</tspan>
    </text>
</g>

En SVG2, il existe un attribut z-index pour passer les éléments devant/derrière. Ce n'est pas le cas pour le SVG1, les derniers éléments écrits sont sur le dessus. L'ordre dans lequel sont déclarés les éléments est donc important.
Dans notre cas, ils sont déclarés dans l'ordre suivant:
  • les paths des régions
  • les circles des villes
  • le rectangle suivi des textes pour chaque région.

On peut toujours avec un peu de javascript modifier l'ordre des éléments.

Les styles

Ensuite, le CSS fait tout le travail:
→ L'opacité des régions est proportionnelle (échelle logarithmique en fait) à la densité de population,

  /** la densité de population dépend de l'année sélectionnée et de la région */
  svg.year1975 path.FR_A{
      fill-opacity:0.373;
      transition: all 1s;
  }
  /** ...etc .....*/
  svg.year1975 path.FR_H{
      fill-opacity:0.947;
      transition: all 1s;
  }
→ Sur le survol, les régions changent de couleur:
path{
    fill:#616161;
    stroke: #f5f5f5;
    stroke-width:1px;
    transition: all 1s;
}
  
path:hover{
    fill:#cb3609;
}

→ Au survol des régions les données sont affichées

/** textes et rectangles sont cachés */
rect{
    /* important de mettre pointer-events à none, 
    ainsi si la souris se trouve sur le rectangle, c'est la région située en-dessous qui recevra l'événement 'hover'*/
     pointer-events : none;
     visibility:hidden;
     stroke:grey;
     fill:#fffaf0;
     transition: all .6s;
}

text
{
     pointer-events : none;
     text-anchor: start;
     visibility: hidden;
     transition: all .5s;
}

/** au survol de la région, le rectangle est visible et
 le texte de l'année sélectionnée est visible */
path.FR_A:hover ~ g.FR_A rect,
svg.year1975 path.FR_A:hover ~ g.FR_A text.year1975,
svg.year1980 path.FR_A:hover ~ g.FR_A text.year1980,
/** ...etc .........................................*/
{
     visibility: visible;
     transition: all .5s;
}

Le javascript

Il n'est utilisé que pour modifier la classe du svg quand l'année change: year1975, year1980, …., year2015.

Elisabeth Pointal 28/06/2017 07:44