Librería: Leaflet
Descripción: Contiene las 10 funcionalidades más importantes y básicas que debe tener un mapa interactivo.
Archivo HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="<https://unpkg.com/leaflet@1.9.4/dist/leaflet.css>">
<link rel="stylesheet" href="style.css">
<title>10 Funcionalidades</title>
</head>
<body>
<div id="map"></div>
<script src="<https://unpkg.com/leaflet@1.9.4/dist/leaflet.js>"></script>
<script src="script.js"></script>
</body>
</html>
Archivo JavaScript
//Crear el mapa
const map = L.map('map').setView([4.65, -74.1],12);
// Agregar capa base
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// Agregar marcadores
fetch('data/Cines.geojson')
.then(res => res.json())
.then(data => {
data.features.forEach(feature => {
const [lon,lat] = feature.geometry.coordinates;
const nombre = feature.properties.NOMBRE;
L.marker ([lat,lon])
.addTo(map)
.bindPopup(`<strong>${nombre}<strong/>`);
});
});
// Control de capas
let barriosLayer, viasLayer;
// Hover interactivo
fetch('data/Barrios_bogota.geojson')
.then(res=> res.json())
.then(data => {
barriosLayer = L.geoJSON(data, {
style: {
color: "#3388ff",
weight: 1,
fillOpacity: 0.3
},
onEachFeature: function (feature, layer){
const nombreBarrio = feature.properties.BARRIO;
layer.on({
mouseover: function (e){
e.target.setStyle({
weight: 3,
color: "#FFD700",
fillOpacity: 0.5
});
},
mouseout: function(e){
barriosLayer.resetStyle(e.target);
}
});
layer.bindTooltip(nombreBarrio,{
permanent: false,
direction: 'center',
className: 'tooltip-barrio'
});
}
});
barriosLayer.addTo(map);
agregarControlCapas();
});
// Cargar capas geojson con popups
fetch('data/Vias_principales_bogota.geojson')
.then(res=> res.json())
.then(data => {
viasLayer = L.geoJSON(data, {
onEachFeature: function (feature,layer){
const nombreVia = feature.properties.LABEL;
layer.bindPopup(`<strong>${nombreVia}<strong/>`)
}
});
viasLayer.addTo(map);
agregarControlCapas();
});
function agregarControlCapas(){
if(barriosLayer && viasLayer){
L.control.layers(null, {
"Barrios": barriosLayer,
"Vías": viasLayer
}).addTo(map);
}
}
// Detectar clicks en el mapa
map.on('click', function(e) {
L.popup()
.setLatLng(e.latlng)
.setContent("Coordenadas: " + e.latlng.toString())
.openOn(map);
});
// Dibujar Geometrías
L.circle([4.564105, -74.052143],{
radius: 1000,
color: 'red'
}).addTo(map).bindPopup("Radio de 1000 metros");
L.polygon([
[4.655,-74.11],
[4.66,-74.1],
[4.65,-74.09],
[4.645,-74.1]
], {
color: 'green'
}
).addTo(map).bindPopup("Zona de interés");
L.polyline([
[4.64, -74.12],
[4.645, -74.115],
[4.65, -74.11],
[4.655, -74.105]
],{
color: 'yellow',
weight: 5
}
).addTo(map).bindPopup("Ruta trazada");
// Control personalizado y zoom animado
const BtnCines = L.Control.extend({
onAdd: function(){
const btn = L.DomUtil.create('button');
btn.innerHTML = 'Cines';
btn.onclick = () => map.flyTo([4.65,-74.1],14);
return btn;
}
});
map.addControl(new BtnCines({position: 'topright'}));
// Escala
L.control.scale({
position: 'bottomleft',
metric: true,
imperial: false,
maxWidth: 200,
updateWhenIdle: true
}).addTo(map);
Archivo CSS
#map {
position: absolute;
width: 100%;
height: 100%;
}
.leaflet-control-scale {
background-color: azure;
padding: 2px 6px;
border-radius: 4px;
font-size: 18px;
box-shadow: 0 0 5px rgba(0,0,0,0.3);
color: black;
}