Select Git revision
tab4.js
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tab4.js 9.43 KiB
/**
* @file Archivo sobre la pestaña 4, el mapa
* @author David Población Criado
*/
// Definimos area de dibujo
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
// Creamos zona para el mapa
var svgWidth = WIDTH - 50;
var svgHeight = HEIGHT - 50;
/**
* Dibuja el gráfico de la pestaña 4, correspondiente al mapa que muestra el consumo per cápita
* en cada provincia para un mes determinado
* @param {String} mes Mes del que queremos pintar el consumo en cada provincia
*/
function dibujarGrafico4(mes) {
// cambiar título
document.getElementById("titulo4").textContent = 'Consumo per cápita a ' + mes;
// Leemos los datos, son Promise
var datos = d3.csv("data/d1.csv");
var datosMapa = d3.json("data/provincias-CastillaYLeon.json");
// Cuando se han leído ambos datos
Promise.all([datos, datosMapa])
.then((data) => {
// Inicializamos el desplegable
opcionesDesplegable(data[0]);
// Filtramos datos
var datosSelec = seleccionarDatosMes(data[0], mes);
// Colores
var colorScale = d3.scaleThreshold()
.domain([100, 200, 300, 400, 500, 600, 700])
.range(d3.schemeOranges[8]);
var mapData = data[1];
// Añadimos el svg al HTML
var svg = d3.select("#mapa")
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
//Para ver los tipos de proyecciones predefinidas en D3 acceder a:
// https://d3-wiki.readthedocs.io/zh_CN/master/Geo-Projections/
// https://github.com/d3/d3-geo-projection/
// var projection = d3.geoMercator().scale(5000).translate([1000,4000]);
var projection = d3.geoMercator();
var geoPath = d3.geoPath(projection);
// Calculo tamaño original, calculando los valores maximos y minimos de las coordenadas x e y del mapa
// Se muestra por consola cada valor calculado.
var Xmax = 0;
var Xmin = WIDTH;
var Ymax = 0;
var Ymin = HEIGHT;
numPaths = mapData.features.length;
mapData.features.forEach(function(data2, i) {
var bordeInfX = geoPath.bounds(data2)[0][0];
if (bordeInfX < Xmin) {
Xmin = bordeInfX;
}
var bordeInfY = geoPath.bounds(data2)[0][1];
if (bordeInfY < Ymin) {
Ymin = bordeInfY;
}
var bordeSupX = geoPath.bounds(data2)[1][0];
if (bordeSupX > Xmax) {
Xmax = bordeSupX;
}
var bordeSupY = geoPath.bounds(data2)[1][1];
if (bordeSupY > Ymax) {
Ymax = bordeSupY;
}
});
// Calculo aumento escala, ajustando a las dimensiones del cuadro svg
// El problema es ajustar un mapa con coordenadas longitud-latitud a pixeles en la pantalla
// Ajustamos usando la proporcion (ancho/alto) "mas estrecha", para no desbordar.
var porcentajeAjuste = 0.8; // se ajusta el grafico a este porcentaje de la ventana
var proporcionX = svgWidth / (Xmax - Xmin); // se ve cuantas veces puedo aumentar en esta dimension
var proporcionY = svgHeight / (Ymax - Ymin); // idem para Y
if (proporcionX < proporcionY) { // ajusto al porcentaje maximo en la dimension X
var escala = Math.floor((svgWidth * porcentajeAjuste) / (Xmax - Xmin));
} else { // ajust al porcentaje maximo en la dimension Y
var escala = Math.floor((svgHeight * porcentajeAjuste) / (Ymax - Ymin));
}
escala = escala * projection.scale(); // multiplico el aumento por la escala ya aplicada
// Aplico Escala
projection = d3.geoMercator().scale(escala);
geoPath = d3.geoPath(projection);
// Al ajustar la escala, como d3 lo escala usando longitud y latitud, el mapa se puede
//ir de la pantalla. Se puede ver esto, comentando el codigo que esta a continuacion
//y viendo los valores del path en el "Inspector" de las herramientas de administracion.
//Se dejan los calculos de los bordes de cada provincia para poder ver el efecto indicado
//por consola
// Se calcula el centro de cada path (provincia), y con estos el del centro del mapa,
//ajustando este al centro del elemento svg
var centroX = 0;
var centroY = 0;
var numPaths = mapData.features.length;
mapData.features.forEach(function(data2, i) {
centroX = centroX + geoPath.centroid(data2)[0];
centroY = centroY + geoPath.centroid(data2)[1];
var bordeInfX = geoPath.bounds(data2)[0][0];
var bordeInfY = geoPath.bounds(data2)[0][1];
var bordeSupX = geoPath.bounds(data2)[1][0];
var bordeSupY = geoPath.bounds(data2)[1][1];
});
centroX = centroX / numPaths;
centroY = centroY / numPaths;
var offsetX = projection.translate()[0]; // offset que se aplica por defecto y que hay que sumar para "quitarlo"
var offsetY = projection.translate()[1];
var transX = Math.floor((svgWidth / 2) - centroX) + offsetX;
var transY = Math.floor((svgHeight / 2) - centroY) + offsetY;
projection = projection.translate([transX, transY]);
geoPath = d3.geoPath(projection);
// Tooltip, para mostrar info cuando pasamos el ratón
var div = d3.select('#mapa').append('div')
.attr('class', 'tooltip')
.style('display', 'none');
// Añadimos el mapa
svg.selectAll("path")
.data(mapData.features)
.enter()
.append("path")
.attr("class", "provincia")
.attr("d", geoPath)
// Cambio de colores dependiendo del consumo según la paleta
.attr("fill", function(d) {
let x;
datosSelec.forEach(function(s) {
if (d.properties.provincia == s.Provincia) {
x = s;
return;
}
})
return colorScale(x.ConsumoHab)
})
// Cuando pasamos por encima el ratón, desvanecemos las demás provincias y coloreamos
// la que tiene el ratón
.on("mouseover", function(d) {
// desvanecer
d3.selectAll(".provincia")
.transition()
.duration(200)
.style("opacity", .5);
// colorear
d3.select(this)
.transition()
.duration(200)
.style("opacity", 1);
// tooltip
div.style('display', 'inline');
})
// Volvemos al estado inicial cuando quitamos ratón
.on("mouseleave", function(d) {
d3.selectAll(".provincia")
.transition()
.duration(200)
.style("opacity", 1)
d3.select(this)
.transition()
.duration(200);
div.style('display', 'none');
})
// Mostrar el tooltip con la provincia y su consumo
.on("mousemove", function(event) {
var d = d3.select(this).data()[0]
let x;
datosSelec.forEach(function(s) {
if (d.properties.provincia == s.Provincia) {
x = s;
return;
}
})
div
.html(x.Provincia + "<br>" + d3.format(".2f")(x.ConsumoHab) + " kWh/hab")
.style('left', (event.pageX - 24) + 'px')
.style('top', (event.pageY - 24) + 'px');
});
})
// Errores
.catch((e) => {
d3.select("#mapa").append("svg").append("text").attr("x", 30).attr("y", 30).text("ERROR al cargar los datos");
console.error(e);
});
}
/**
* Selecciona los datos de un mes en concreto
* @param {JSON} data Datos a filtrar
* @param {String} mes Año-mes del que se quieren filtrar los datos
*/
function seleccionarDatosMes(data, mes) {
var dataSelec = [];
data.forEach(function(d) {
if (d.Mes == mes) {
dataSelec.push(d);
}
})
return dataSelec;
}
/**
* Inicializa el desplegable con los meses que tenemos en los datos
* @param {JSON} data
*/
function opcionesDesplegable(data) {
var seleccionable = document.getElementById("fechasMapa");
// si ya está creado, salimos
if (seleccionable[0] != undefined)
return;
// Para que no haya duplicados
var data2 = seleccionarDatosProvincias(data, "Valladolid");
data2.forEach(function(d) {
var option = document.createElement("option");
option.text = d.Mes;
seleccionable.add(option);
})
}