Saltar a contenido

3.3.Visor catastro

Descripción

Nos han encargado realizar un mapa para visualizar edificios de Barcelona

Paso 1: Preparamos datos

Descargamos archivo ya convertido contrucciones.zip

No guardeís el archivo dentro de /geoweb

Si quisieramos preparar los datos o descargar otro municipio

Paso 2:Entramos en MapbBox.com i cargamos los datos

  • Lo cargamos como Tileset dentro de MapBox, añadimos contrucciones.zip SIN DESCOMPRIMIR

  • Entramos en MapBox.com Studio --> Tilesets -->New tileset Arrastramos contrucciones.zip*

  • Copiamos ID y nombre de la capa

alt text

Paso 3:Crear edificios.html

En este ejemplo y en adelante vamos a reutilizar el archivo css /geoweb/css/estilobase.css" que existe ya en nuestro proyecto

El archivo estilobase.css es este

            body {
                margin: 0;
            }

            #map {
                height: 100%;
                width: 100%;
                background-color: #ffffff
            }
* Vamos a VSCode y creamos el archivo edificios.html dentro de /geoweb

    <html>
    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
    <link href='css/estilobase.css' rel='stylesheet' />


    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

        } // final init
    </script>
    </head>

    <body onload="init()">

        <div id="map"></div>
    </body>

    </html>

Paso 4: Creamos archivo JS

  • Dentro de nuestro directorio /geoweb/js/ creamos el archivo edificios.js, dónde crearemos funciones especificas de nuestro proyecto

  • Creamos la función addEdificiosCapa()

Necesitamos saber mapbox://nuestro ID i "source-layer": nombre de Tileset en Mapbox Studio!!

Para añadir datos a nuestros mapas

En mapbox tendremos que especificar siempre :

map.addSource() el tipo de dato fuente

map.addLayer() dónde se va a denifir como renderizar los datos

https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/ https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/

  function addEdificiosCapa() {

    map.addSource("edificios_source", {
        "type": "vector",
        "url": "mapbox://gismasterm2.500eaqlm"  // mapbox://Nuestor ID Tileset

    }); //fin map source


    map.addLayer({
    "id": "edificios",
    "type": "fill-extrusion",
    "source": "edificios_source",
    "source-layer": "construcciones-3f5iwq", // Nuestro nombre Tileset
    "maxzoom": 21,
    "minzoom": 15,
   // "filter": [">", "numberOfFl", 0],
    "paint": {
        "fill-extrusion-color": [
            "interpolate", ["linear"], ["number", ["get", "numberOfFl"]],
            0, "#FFFFFF",
            1, "#e6b03d",
            3, "#e6b03d",
            6, "#3de66d",
            9, "#3de6b1",
            12, "#22ecf0",
            15, "#14b1fd",
            20, "#3d73e6",
            40, "#123a8f",
            80, "#ce2f7e",
            100, "transparent"

        ],
        "fill-extrusion-height": ["*", 2, ["to-number", ["get", "numberOfFl"]]],
        "fill-extrusion-opacity": 0.9
    }
}
//,"road-label"
);  

} //fin funcion

Paso 4: Llamamos funciones en el evento load de map

  • Llamamos al archivo javascript js/edificios.js

  • Llamamos a la función addEdificiosCapa() dentro del evento map.on("load")

    <html>

    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
    <link href='css/estilobase.css' rel='stylesheet' />

    <script src='js/edificios.js'></script>
    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

            map.on('load', function () {

                addEdificiosCapa();


             }); //fin onload

        } // final init
    </script>
    </head>

    <body onload="init()">

    <div id="map"></div>
    </body>

    </html>

visualizamos el mapa

Descomentamos filtro y orden de capas para una mejor visualización en edificios.js ¿Que ha cambiado?

  function addEdificiosCapa() {

    map.addSource("edificios_source", {
        "type": "vector",
        "url": "mapbox://gismasterm2.500eaqlm"  // mapbox://Nuestor ID Tileset

    }); //fin map source


    map.addLayer({
    "id": "edificios",
    "type": "fill-extrusion",
    "source": "edificios_source",
    "source-layer": "construcciones-3f5iwq", // Nuestro nombre Tileset
    "maxzoom": 21,
    "minzoom": 15,
    "filter": [">", "numberOfFl", 0],
    "paint": {
        "fill-extrusion-color": [
            "interpolate", ["linear"], ["number", ["get", "numberOfFl"]],
            0, "#FFFFFF",
            1, "#e6b03d",
            3, "#e6b03d",
            6, "#3de66d",
            9, "#3de6b1",
            12, "#22ecf0",
            15, "#14b1fd",
            20, "#3d73e6",
            40, "#123a8f",
            80, "#ce2f7e",
            100, "transparent"

        ],
        "fill-extrusion-height": ["*", 2, ["to-number", ["get", "numberOfFl"]]],
        "fill-extrusion-opacity": 0.9
    }
}
,"road-label"
);  

} //fin funcion

Paso 5: Opciones de filtro

  • Vamos a crear una funcionalidad para filtrar edificios según su número de pisos

  • Creamos un elementos HTML de tipo input:range para poder filtrar

Programamos funciones fuera del mapa!!

    <html>

    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
    <link href='css/estilobase.css' rel='stylesheet' />

    <script src='js/edificios.js'></script>
    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

            map.on('load', function () {

                addEdificiosCapa();


             }); //fin onload

        } // final init
    </script>
    </head>

    <body onload="init()">
    <div class="panelTopIzquierda">

        <label id="altura">Más de 0 pisos</label>
        <input id="slider" type="range" min="1" max="50" step="1" value="0" />
    </div>
    <div id="map"></div>
    </body>

    </html>
  • Añadimos a estilobase.css las siguientes clases
.panelTopIzquierda {
    position: absolute;
    top: 18px;
    left: 20px;
    width: 200px;
    z-index: 1000;
    background-color: rgba(255,255,255,0.9);
    padding: 10px;
    font-size: 20px;
    color: #33333;
    border-radius: 5px;
}

.panelTopIzquierda label{
    font-size:0.85em;
}

.panelTopIzquierda input[type=range]{
    cursor:pointer;
    width: 95%;
}

Paso 6: Función de filtro

  • Añadimos a edificios.js la funcion filtrarEdificios()
    function filtrarEdificios(valor) {
        map.setFilter("edificios", [">", "numberOfFl", parseInt(valor)]);

        document.getElementById("altura").innerHTML = "Más de  <b>" + valor + "</b> pisos";

    }

Paso 7: Evento onChange

  • LLamamos a la función de desde el evento onChange del objeto input de HTML
    <html>

    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
    <link href='css/estilobase.css' rel='stylesheet' />
    <script src='js/utils.js'></script>
    <script src='js/edificios.js'></script>
    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

            map.on('load', function () {

                addEdificiosCapa();

                addPopupToMap("edificios");
             }); //fin onload

        } // final init
    </script>
    </head>

    <body onload="init()">
    <div class="panelTopIzquierda">

       <label id="altura">Más de 0 pisos</label>
        <input  onChange="filtrarEdificios(this.value)" id="slider" type="range" min="1" max="50" step="1" value="0" />
    </div>
    <div id="map"></div>
    </body>

    </html>

Paso 8: Eventos Click i popup

Añadir funcion Popup personalizado dentro de edificios.js

function addPopupToMapEdificios(nombreCapa) {

    map.on('click', nombreCapa, function (e) {

        var text = "";
        //console.info(e);
        for (key in e.features[0].properties) {

            if (key == "numberOfFl") {
                text += "<b>Numero de plantas</b>:" + e.features[0].properties[key] + "<br>";
            }
            if (key == "localId") {
                //localId 0004702DF3800C_part1
                //http://ovc.catastro.meh.es/OVCServWeb/OVCWcfLibres/OVCFotoFachada.svc/RecuperarFotoFachadaGet?ReferenciaCatastral=0004701DF3800C
                //https://www1.sedecatastro.gob.es/CYCBienInmueble/OVCListaBienes.aspx?rc1=0004701&rc2=DF3800C

                var localId = e.features[0].properties[key];

                var localIdSplit = localId.split("_"); // 0004702DF3800C  part1
                var parte1 = localIdSplit[0].substring(0, 7);
                var parte2 = localIdSplit[0].substring(7, localIdSplit[0].length);
                text += "<img width=200 src=http://ovc.catastro.meh.es/OVCServWeb/OVCWcfLibres/OVCFotoFachada.svc/RecuperarFotoFachadaGet?ReferenciaCatastral=" + localId + "><br>";
                text += "<a target=blank href=https://www1.sedecatastro.gob.es/CYCBienInmueble/OVCListaBienes.aspx?rc1=" + parte1 + "&rc2=" + parte2 + ">Ficha</a><br>";

            }


        }
        new mapboxgl.Popup()
            .setLngLat(e.lngLat)
            .setHTML(text)
            .addTo(map);

    });

    map.on('mouseenter', nombreCapa, function () {
        map.getCanvas().style.cursor = 'pointer';
    });

    map.on('mouseleave', nombreCapa, function () {
        map.getCanvas().style.cursor = '';
    });

}

Paso 9: Llamamos función addPopupToMapEdificios

  • LLamamos a la función de desde el evento load del mapa
    <html>

    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
    <link href='css/estilobase.css' rel='stylesheet' />
    <script src='js/utils.js'></script>
    <script src='js/edificios.js'></script>
    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

            map.on('load', function () {

                addEdificiosCapa();

                addPopupToMapEdificios("edificios");
             }); //fin onload

        } // final init
    </script>
    </head>

    <body onload="init()">
    <div class="panelTopIzquierda">

       <label id="altura">Más de 0 pisos</label>
        <input  onChange="filtrarEdificios(this.value)" id="slider" type="range" min="1" max="50" step="1" value="0" />
    </div>
    <div id="map"></div>
    </body>

    </html>

Visualizamos mapa

alt text

    <html>

    <head>
    <meta charset='utf-8' />
    <title>Edificios</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
   <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css" type="text/css">
    <link href='css/estilobase.css' rel='stylesheet' />

    <script src='js/edificios.js'></script>
    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        function init() {
            mapboxgl.accessToken =
                'pk.eyJ1IjoiZ2lzbWFzdGVybTIiLCJhIjoiY2plZHhubTQxMTNoYzMza3Rqa3kxYTdrOCJ9.53B1E6mKD_EQOVb2Y0-SsA';
             map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/dark-v10',
                center: [2.16859, 41.3954],
                zoom: 15,
                attributionControl: false,
                pitch: 45,
                hash: true
            });

            map.addControl(new mapboxgl.AttributionControl({ compact: true }));
            map.addControl(new mapboxgl.NavigationControl());

            map.addControl(
                new MapboxGeocoder({
                accessToken: mapboxgl.accessToken,
                mapboxgl: mapboxgl
                }));

            map.on('load', function () {

                addEdificiosCapa();

                addPopupToMapEdificios("edificios");
             }); //fin onload

        } // final init
    </script>
    </head>

    <body onload="init()">
   <div class="panelTopIzquierda">

       <label id="altura">Más de 0 pisos</label>
        <input  onChange="filtrarEdificios(this.value)" id="slider" type="range" min="1" max="50" step="1" value="0" />
    </div>
    <div id="map"></div>
    </body>

    </html>

Miramos opciones de Geocoder. ¿Limitámos búsquedas del geocoder por caja de coordenadas de Barcelona?

https://github.com/mapbox/mapbox-gl-geocoder/blob/main/API.md

bbox:[2.1066 , 41.3000 , 2.2536 , 41.4468]

¿Ponemos título?

¿Editamos index.html y subimos el ejemplo al GitHub?

    git pull
    git add .
    git commit -m "visor catastro"
    git push

Saber más..

Forma reactiva de hacer lo mismo en el evento onchange

 document.getElementById("slider").onchange = function() {

                filtrarEdificios(this.value)
            }

Activar/ desactivar capa via código

    map.setLayoutProperty("edificios", "visibility", "visible");
    map.setLayoutProperty("edificios", "visibility", "none");

desactivar capas cuyo id contenga 'label'

            for (var i=0; i < map.getStyle().layers.length;i++){

                    if(map.getStyle().layers[i].id.indexOf("label")!=-1){

                        map.setLayoutProperty(map.getStyle().layers[i].id, "visibility", "none");
                    }

                }

Nivel avanzado..

  • Podemos programas el evento click sobre el mapa y no sobre una capa conresta, obtener los vectores de todas las capas y filtrar por la capa que nos interesa.
  • La función addPopupToMapEdificios quedaria así y funcionaria en 2d cómo en 3d
    function addPopupToMapEdificios(nombreCapa) {

    map.on('click', function (e) {

        var text = "";
        var bbox = [[e.point.x - 10, e.point.y - 10], [e.point.x + 10, e.point.y + 10]];
        var features = map.queryRenderedFeatures(bbox, { layers: [nombreCapa] });

        if (features.length > 0) {
            for (key in features[0].properties) {

                if (key == "numberOfFl") {
                    text += "<b>Numero de plantas</b>:" + features[0].properties[key] + "<br>";
                }
                if (key == "localId") {
                    //localId 0004702DF3800C_part1
                    //http://ovc.catastro.meh.es/OVCServWeb/OVCWcfLibres/OVCFotoFachada.svc/RecuperarFotoFachadaGet?ReferenciaCatastral=0004701DF3800C
                    //https://www1.sedecatastro.gob.es/CYCBienInmueble/OVCListaBienes.aspx?rc1=0004701&rc2=DF3800C

                    var localId = features[0].properties[key];

                    var localIdSplit = localId.split("_"); // 0004702DF3800C  part1
                    var parte1 = localIdSplit[0].substring(0, 7);
                    var parte2 = localIdSplit[0].substring(7, localIdSplit[0].length);
                    text += "<img width=200 src=http://ovc.catastro.meh.es/OVCServWeb/OVCWcfLibres/OVCFotoFachada.svc/RecuperarFotoFachadaGet?ReferenciaCatastral=" + localId + "><br>";
                    text += "<a target=blank href=https://www1.sedecatastro.gob.es/CYCBienInmueble/OVCListaBienes.aspx?rc1=" + parte1 + "&rc2=" + parte2 + ">Ficha</a><br>";

                }


            }
            new mapboxgl.Popup()
                .setLngLat(e.lngLat)
                .setHTML(text)
                .addTo(map);
        }

    });

    map.on('mouseenter', nombreCapa, function () {
        map.getCanvas().style.cursor = 'pointer';
    });

    map.on('mouseleave', nombreCapa, function () {
        map.getCanvas().style.cursor = '';
    });

}