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.
-
Los datos de farmacias se pueden obtener de la web de Datos Abiertos de Barcelona https://opendata-ajuntament.barcelona.cat/data/es/dataset/sanitat-farmacies
-
Podemos transformar los datos GeoJson y cargarlos como un source en Mapbox GlJs
-
Podemos utilizar el control de mapbox-gl-geocoder para buscar en GeoJson de forma local
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
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*