Mapas — d3-geo¶
Para generar mapas en D3 seguimos los siguientes pasos:
Generamos un objeto path
con la función d3.geoPath() añadiéndole una proyección de las tantas existentes en d3-geo. Un ejemplo sería:
var path = d3.geoPath().projection(geoAzimuthalEquidistant());
O también:
var projection = geoAzimuthalEquidistant(),
path = d3.geoPath(projection);
Podemos optar por renderizar el mapa con svg
o con canvas
, vamos a explorar ambas opciones.
SVG¶
Obtenemos el elemento svg
donde queremos representar el mapa. A este le añadimos los datos con data() o datum() y mediante el atributo "d"
insertamos el path
que hemos creado anteriormente:
<svg width="100%" height="500" id="example_map"></svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script>
var url = "https://unpkg.com/world-atlas@1.1.4/world/110m.json";
d3.json(url, function(error, world){
if (error) throw error;
var svg = d3.select("#example_map")
.datum(topojson.feature(world, world.objects.land))
.attr("d", path);
})
</script>
Nota
Lee este artículo para entender la diferencia entre data() o datum().
Input
<style>
#map-1 {
background-color: skyblue;
}
.province {
fill: royalblue;
stroke: #FFF;
stroke-width: .5px;
stroke-dasharray: 3 3;
}
.province:hover {
fill: crimson;
stroke: orange;
stroke-width: 2px;
stroke-dasharray: none;
}
.graticule {
fill: none;
stroke: #FFF;
stroke-width: .6px;
stroke-opacity: 0.5;
}
</style>
<svg id="map-1" width="748" height="500"></svg>
<script>
var svg = d3.select("#map-1"),
width = +svg.attr("width"),
height = +svg.attr("height");
// Creamos la proyección (ver Proyecciones abajo)
var projection = d3.geoMercator()
.scale(2200)
.center([0, 40])
.translate([width / 1.7, height / 2]);
//.translate([350, 200]); // Otros atributos
//.rotate([122.4194, -37.7749])
//.clipAngle(180 - 1e-3)
//.precision(0.1);
// Creamos el path añadiendo la proyección
var path = d3.geoPath(projection),
// Creamos una rejilla que se repita cada 2 grados tanto
// en direcciones norte-sur como este-oeste
var graticule = d3.geoGraticule().step([2, 2]);
// Añadimos la rejilla
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
// Obtenemos las provincias de España en formato geojson
var url = "https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/spain-provinces.geojson";
d3.json(url, function(error, spain){
if (error) throw error; // Manejamos cualquier posible error
var group = svg.selectAll("g") // Creamos un grupo para cada provincia
.data(spain.features)
.enter()
.append("g");
// Para cada grupo añadimos el path correspondiente
var areas = group.append("path")
.attr("d", path)
.attr("class", "province");
});
</script>
Output
Como puedes observar en este ejemplo, básicamente son 6 pasos.
- Crear una proyección (ver Proyecciones).
- Crear un
path
con la función d3.geoPath() y añadirle la proyección. - [Opcional] Crear una rejilla con la función d3.geoGraticule(). Añadir un elemento
path
al svg, enlazar los datos de la cuadrícula con la función datum() y añadir elpath
del paso anterior al atributod
. - Obtener los datos geográficos del mapa.
- Enlazar los datos al contenedor
svg
por medio de grupos. - Añadir a cada grupo un elemento
path
, cuyo atributod
será el path que hemos creado en el paso 2.
Canvas¶
Para crear un mapa usando elementos canvas
habría que escribir algo como esto:
Input
<canvas width="680" width="480"></canvas>
<script src="https://unpkg.com/topojson-client@3"></script>
<script>
var context = d3.select("canvas").node().getContext("2d");
var projection = d3.geoMercator()
.scale(2200)
.center([0, 40])
.translate([width / 1.7, height / 2]);
var path = d3.geoPath(projection).context(context);
var url = "https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/spain-provinces.geojson";
d3.json(url, function(error, spain) {
if (error) throw error;
// Comenzamos a dibujar en el lienzo
context.beginPath();
// Añadimos el path con los datos del archivo .json
path(topojson.mesh(spain));
// Dibujamos el contenido
context.stroke();
});
</script>
Output
En este ejemplo, mucho más simple, hemos usado topojson para cargar los datos del archivo en json e insetarlos en el canvas.
Proyecciones¶
D3 provee muchas proyecciones dentro de los módulos d3-geo y d3-geo-projection. Cada proyección puede ser controlada mediante métodos.
Métodos¶
- projection.scale([scale]): El factor de escalado corresponde linealmente a la distancia entre los puntos projectados; sin embargo, mismos factores de escalado no son equivalentes entre diferentes proyecciones.
- projection.center([center]): Array de dos elementos con las coordenadas longitud y latitud en grados (por defecto
[0, 0]
). - projection.translate([translate]): si se especifica el parámetro
translate
, el la proyección será trasladada en los ejes[x, y]
según los valores introducidos (por defecto[480, 250]
). - projection.rotate([angles]): Si él parámetro
angles
es introducido, establece la rotación esférica sobre los tres ejes a los ángulos especificado, el cual debe ser un array de dos ó tres números[lambda, phi, gamma]
, especificando los ángulos de rotación en grados sobre cada eje esférico (por defecto[0, 0, 0]
.
Rejillas¶
d3.geoGraticule()¶
Con esta función creamos una rejilla. Para añadir una rejilla simplemente hemos de insertarla en el contenedor svg
con la función datum():
var graticule = d3.geoGraticule().step([2, 2]);
svg.append("path")
.datum(graticule)
.attr("d", path);
Métodos¶
- graticule.step([step]): Acepta un array de dos números que indican los grados de distancia entre cada filamento de la rejilla. El primero indica diferencia entre longitudes y el segundo latitudes.