Skip to content
Snippets Groups Projects
Select Git revision
  • master
1 result

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);
        })
    }