Saltar a contenido

8.2.Visor de farmacias

Buscador de Farmacias de Barcelona ciudad

Nos han encargado realizar un mapa para poder localizar y buscar las farmacias de Barcelona y para cada farmácia poder visualizar las cinco más cercanas.

Ejemplo buscador de Farmacias

Paso 0:Visualizar datos

  • Dentro de /geoweb/datos/farmacias.geojson ya tenemos los datos descargados y convertidos a GeoJson. Podemos visualizarlos con https://geojson.io/#map=2/0/20 por ejemplo

Convertir a GeoJson

El archivo de farmacias lo hemos descargado del portal https://opendata-ajuntament.barcelona.cat/data/es/dataset/sanitat-farmacies en formato CSV y lo hemos transformado a GeoJSON

Para ver cómo transformar y reproyectar un archivo CSV a GeoJson con Qgis mira el video 10

Paso 1: Crear archivo farmacias.html dentro de /geoweb

Aprovechamos para:

  • Añadir libreria geocoder
  • Añadir utils.js
  • Variable global farmaciasGeoJSON
<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>


    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;
        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: 12,
                attributionControl: false,
                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 2: Cargamos a nivel web los datos de farmacias.json

Reutilizamos funcion:

  • enviarPeticion()
<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>


    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;

                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Paso 3: Crear archivo farmacias.js dentro de /geoweb/js

Llamamos a nuestro geojson de farmacias que está en datos/farmacias.geojson

function addFarmacias() {

    //var url = 'datos/farmacias.geojson';
    var url = farmaciasGeoJSON;
    map.addSource('farmacias', {
        type: 'geojson',
        data: url
    });

    map.addLayer({
        'id': 'farmacias',
        'type': 'circle',
        'source': 'farmacias',
        'paint': {
            'circle-color': '#00ff00',
            'circle-radius': 5,
            'circle-stroke-color': '#ffffff',
            'circle-stroke-width': 2
        }
    });


} // fin funcion

Paso 4: Llamamos a la funcion addFarmacias()

<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Visualizamos las farmacias

Paso 5: Reutilizamos la funcion addPopupToMap() de /js/utils.js

<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                    addPopupToMap("farmacias");
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Paso 6: Control geocoder como buscador interno

  • Añadimos control geocoder
<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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


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

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                    addPopupToMap("farmacias");
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Paso 7: Dentro de js/farmacias.js creamos la funcion buscarFarmacias(valor) para buscar en el GeoJson

Esta función recibirà el texto entrado por el usuario y buscarà en el geojson de faramacias.

function buscarFarmacias(valor) {

     var resultadosFarmacias = [];

    // console.info(farmaciasGeoJSON);
     for (var i = 0; i < farmaciasGeoJSON.features.length; i++) {

         var feature = farmaciasGeoJSON.features[i];

         if (feature.properties.nombre && 
             feature.properties.nombre
             .toLowerCase()
             .includes(valor.toLowerCase())
         ) {

             feature['place_name'] = `💊 ${feature.properties.nombre}`;
             feature['center'] = feature.geometry.coordinates;
             feature['place_type'] = ['place'];
             resultadosFarmacias.push(feature);
         }
     }
     return resultadosFarmacias;
 } // fin funcion

Paso 8: Llamamos a la funcion buscarFarmacias en el control Geocoder

Opcion localGeocoder

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

<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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


            map.addControl(
                new MapboxGeocoder({
                accessToken: mapboxgl.accessToken,
                mapboxgl: mapboxgl,
                localGeocoder:buscarFarmacias,
                collapsed:true
                }));

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                    addPopupToMap("farmacias");
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Visualizamos

Localizar las cinco farmacias más cercanas a una farmacia concreta

Paso 9: Añadimos libreria turf.js a farmacias.html

<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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">

    <script src="https://cdn.jsdelivr.net/npm/@turf/turf@6.5.0/turf.min.js"></script>

    <link href='css/estilobase.css' rel='stylesheet' />
    <script src='js/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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


            map.addControl(
                new MapboxGeocoder({
                accessToken: mapboxgl.accessToken,
                mapboxgl: mapboxgl,
                localGeocoder:buscarFarmacias,
                collapsed:true
                }));

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                    addPopupToMap("farmacias");
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

Paso 10: Dentro de js/farmacias.js creamos funcion addFarmaciasCercanas()

function addFarmaciasCercanas() {

    map.addSource('farmacias_sel', {
        type: 'geojson',
        data: {
            'type': 'FeatureCollection',
            'features': []
        }
    });

    map.addLayer({
        'id': 'farmacias_sel',
        'type': 'circle',
        'source': 'farmacias_sel',
        'paint': {
            'circle-color': '#f909b5',
            'circle-radius': 8,
            'circle-stroke-color': '#ffffff',
            'circle-stroke-width': 2
        }
    });

   map.addLayer({
        "id": "farmacias_sel_text",
        "type": "symbol",
        "source": "farmacias_sel",
        "layout": {
          'text-field': ['concat',['get', 'distancia'],' m'],
          "text-size": 15,
          'text-offset': [0, 1.3],
          'text-anchor': 'left'
        },
        'paint': {
            'text-color': '#f909b5',
            'text-halo-color': '#333333',
            'text-halo-width': 1
        }
      });

    map.on("click", "farmacias", function (e) {

        var puntoClick = turf.point([e.lngLat.lng, e.lngLat.lat]);
        var ff = farmaciasGeoJSON;

        for (var i = 0; i < ff.features.length; i++) {

            var puntoFarmacia = turf.point(ff.features[i].geometry.coordinates);
            var distancia = turf.distance(puntoClick, puntoFarmacia, { units: 'meters' });
            ff.features[i].properties.distancia = parseInt(distancia);

        }

        ff.features.sort(function (a, b) {
            return a.properties.distancia - b.properties.distancia
        });

        map.getSource('farmacias_sel').setData(turf.featureCollection(ff.features.slice(1, 6)));

    })



} // fin funcion

Paso 10: Llamamos función addFarmaciasCercanas()

<html>

<head>
    <meta charset='utf-8' />
    <title>Farmacias</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.js'></script>
    <link href='https://api.mapbox.com/mapbox-gl-js/v2.11.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">

    <script src="https://cdn.jsdelivr.net/npm/@turf/turf@6.5.0/turf.min.js"></script>

    <link href='css/estilobase.css' rel='stylesheet' />
    <script src='js/utils.js'></script>
    <script src='js/farmacias.js'></script>

    <script>
        //Añadir vuestor token y/o estilo !!
        var map;
        var farmaciasGeoJSON;

        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: 12,
                attributionControl: false,
                hash: true
            });

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


            map.addControl(
                new MapboxGeocoder({
                accessToken: mapboxgl.accessToken,
                mapboxgl: mapboxgl,
                localGeocoder:buscarFarmacias,
                collapsed:true
                }));

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

                // reutilizamos funcion de utils para obtener geojson
                enviarPeticion("datos/farmacias.geojson").then(function (datos) {
                    farmaciasGeoJSON = datos;
                    addFarmacias();
                    addPopupToMap("farmacias");
                    addFarmaciasCercanas();
                }); //fin peticio


            }); //fin load

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

<body onload="init()">
    <div id="map"></div>
</body>

</html>

¿Ponemos un título?

Editamos index.html y subimos el ejemplo al GitHub

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

Saber más ....

Podríamos hacer este mismo mapa pero con otras la farmacias de otros muchos paises del mundo con humdata.org

https://data.humdata.org/dataset?ext_geodata=1&q=healthsites&sort=if(gt(last_modified%2Creview_date)%2Clast_modified%2Creview_date)%20desc&ext_page_size=25

Probamos con tadas las farmacias de España

datos/farmacias-spain.geojson.zip

Para crear este geojson se han filtrado amenity=pharmacy y cambiado la propiedad name por nombre*