La mayoría de los productos de descubrimiento local viven o mueren en una sola pantalla: el mapa. Un usuario abre tu app para responder una pregunta sencilla, qué hay cerca de mí ahora mismo, y el mapa es como la responde. Acertar con ese mapa, con los pines correctos, filtrado rápido y listados que los buscadores realmente puedan leer, es el trabajo de ingeniería central detrás de cualquier guía de eventos.
Esta guía recorre la creación de un mapa de eventos de ciudad desde cero: modelar los datos del evento, geocodificar locales a coordenadas, colocar y agrupar marcadores, filtrar por categoría y barrio, y hacer que los listados sean descubribles. Da por hecho que ya sabes renderizar un mapa base. Si no es así, empieza por nuestro tutorial sobre cómo añadir mapas interactivos a tu web y vuelve aquí para las partes específicas de eventos.
Modela el evento en torno a su local
Un evento es algo acotado en el tiempo que ocurre en un lugar. El lugar es lo que va en el mapa, así que el local es el ancla de tu modelo de datos. Un registro mínimo de evento tiene este aspecto:
const event = {
id: 'evt_8471',
title: 'Late Night Jazz at The Vortex',
category: 'live-music',
venue: 'The Vortex Jazz Club, 11 Gillett Square, London N16 8AZ',
coords: null, // se rellena con geocodificación, una vez
neighbourhood: null, // se rellena con geocodificación inversa, una vez
startsAt: '2026-07-09T20:30:00Z',
url: 'https://example.com/tickets/8471',
};
Los dos campos null importan. No quieres geocodificar un local cada vez que se carga el mapa. Geocodifica una sola vez, cuando el evento se crea o se importa, luego guarda las coordenadas y trátalas como permanentes.
Paso 1: geocodifica cada local a coordenadas
La geocodificación convierte una dirección legible por humanos en una latitud y longitud que puedes representar. Envía la cadena del local a la Geocoding API y lee las coordenadas del primer resultado:
async function geocodeVenue(address) {
const url = new URL('https://api.mapatlas.eu/geocoding/v1/search');
url.searchParams.set('text', address);
url.searchParams.set('size', '1');
const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
const data = await res.json();
const top = data.features?.[0];
if (!top) return null;
const [lon, lat] = top.geometry.coordinates;
return { lat, lon, label: top.properties.label };
}
Ejecuta esto en el momento de escritura, cuando un evento entra en tu sistema, y persiste las coordenadas devueltas en el registro. Para una explicación completa de por qué importa la ubicación exacta del pin, y de cómo las coordenadas del tejado difieren de la puerta a la que la gente realmente llega, consulta geocodificación de entradas de edificios.
Paso 2: representa los eventos como marcadores
Con coordenadas en cada evento, representarlos es un bucle. Da a cada categoría su propio color para que el mapa se lea de un vistazo:
const CATEGORY_COLORS = {
'live-music': '#E75480',
'theatre': '#006BA6',
'comedy': '#EE7C0E',
'food': '#16A34A',
'nightlife': '#7C3AED',
};
function plotEvents(map, events) {
events.forEach((evt) => {
if (!evt.coords) return;
const popup = new mapmetricsgl.Popup().setHTML(
`<strong>${evt.title}</strong><br>${new Date(evt.startsAt).toLocaleString()}` +
`<br><a href="${evt.url}">Entradas</a>`,
);
new mapmetricsgl.Marker({ color: CATEGORY_COLORS[evt.category] || '#0c3456' })
.setLngLat([evt.coords.lon, evt.coords.lat])
.setPopup(popup)
.addTo(map);
});
}
Este es el patrón que hay detrás de productos reales. Un ejemplo en vivo es OnlyHere, una guía diaria de cosas que hacer en Londres que geocodifica cada local y coloca los eventos del día en un mapa interactivo de MapAtlas, para que el usuario pueda explorar qué hay por local y por barrio en lugar de recorrer una lista plana.
Paso 3: agrupa cuando la ciudad se llena
Los marcadores individuales están bien para un puñado de eventos. Un feed de toda la ciudad no es un puñado. En cuanto pasas de unos 100 a 200 pines, mueve los eventos a una fuente GeoJSON y deja que el mapa los agrupe:
map.addSource('events', {
type: 'geojson',
cluster: true,
clusterRadius: 50,
data: {
type: 'FeatureCollection',
features: events.filter((e) => e.coords).map((e) => ({
type: 'Feature',
geometry: { type: 'Point', coordinates: [e.coords.lon, e.coords.lat] },
properties: { title: e.title, category: e.category },
})),
},
});
Ahora una noche movida en el centro muestra una única burbuja con un contador en lugar de cien pines superpuestos, y el cluster se separa a medida que el usuario acerca la vista.
Paso 4: filtra por categoría y barrio
El filtrado es donde un mapa de eventos se convierte en un producto de eventos. Mantén la lista completa en memoria y filtra el array, luego entrega el conjunto filtrado a la fuente del mapa en lugar de reconstruir los marcadores a mano:
function applyFilters(map, allEvents, { category, neighbourhood }) {
const filtered = allEvents.filter((e) =>
(!category || e.category === category) &&
(!neighbourhood || e.neighbourhood === neighbourhood),
);
map.getSource('events').setData({
type: 'FeatureCollection',
features: filtered.filter((e) => e.coords).map((e) => ({
type: 'Feature',
geometry: { type: 'Point', coordinates: [e.coords.lon, e.coords.lat] },
properties: { title: e.title },
})),
});
return filtered;
}
Para rellenar el campo neighbourhood, aplica geocodificación inversa a las coordenadas de cada local una vez y guarda el nombre del área administrativa. Ese único valor alimenta un desplegable de barrios, una vista de "qué hay en esta zona" y una página de listados más limpia, todo sin otra consulta en tiempo de ejecución.
Paso 5: haz que los listados sean descubribles
Un mapa responde la pregunta para la persona que ya está en tu app. No hace nada por el público mucho mayor que le pregunta a un buscador o a un asistente de IA "qué hay esta noche en Shoreditch". Esos sistemas leen datos estructurados, no píxeles.
Marca cada evento con campos Event de schema.org y reutiliza las coordenadas que ya tienes:
{
"@context": "https://schema.org",
"@type": "Event",
"name": "Late Night Jazz at The Vortex",
"startDate": "2026-07-09T20:30:00Z",
"location": {
"@type": "Place",
"name": "The Vortex Jazz Club",
"geo": { "@type": "GeoCoordinates", "latitude": 51.5462, "longitude": -0.0753 }
}
}
Las coordenadas que dibujan el pin también alimentan los datos estructurados, así que visualización y descubrimiento salen de una única fuente de verdad. Esta es la diferencia entre un mapa que se ve bien y un producto que se encuentra. Para más sobre por qué los datos de ubicación legibles por máquina impulsan la visibilidad en la búsqueda con IA, consulta nuestra guía sobre FAQs específicas por ubicación para la búsqueda con IA.
Poniéndolo todo junto
Un mapa de eventos de ciudad tiene cinco piezas móviles: un modelo de datos anclado en el local, geocodificación en el momento de escritura, marcadores de colores, clustering a escala y filtrado basado en arrays, todo apoyado sobre datos estructurados que mantienen los listados descubribles. Construye esas piezas sobre una única plataforma geoespacial y las coordenadas fluyen limpiamente del geocodificador al mapa y al schema, sin consultas duplicadas ni datos a la deriva.
MapAtlas te da la geocodificación, la geocodificación inversa, la búsqueda de lugares y el renderizado de mapas para construirlo todo sobre infraestructura alojada en la UE y conforme con el GDPR. Explora la Geocoding API y la Search API para empezar a mapear tu propia ciudad.
Preguntas frecuentes
¿Qué datos necesito para crear un mapa de eventos de ciudad?
Como mínimo, cada evento necesita la dirección de un local, una categoría y una hora de inicio. La dirección es lo que convierte un evento en un pin del mapa: la geocodificas una vez para obtener latitud y longitud, guardas esas coordenadas y las reutilizas cada vez que muestras el evento. Todo lo demás, como enlaces de entradas, imágenes y descripciones, son metadatos que adjuntas al popup del marcador.
¿Cómo convierto la dirección de un local en coordenadas del mapa?
Llama a una API de geocodificación con la cadena de la dirección del local y lee la latitud y longitud de la respuesta. Con la Geocoding API de MapAtlas envías la dirección como consulta de texto a https://api.mapatlas.eu/geocoding/v1/search y usas las coordenadas del primer resultado. Geocodifica cada local una sola vez al crear el evento, no en cada carga de página, para que el mapa siga siendo rápido y tu consumo de API se mantenga bajo.
¿Cuántos marcadores de eventos puede mostrar un mapa antes de ralentizarse?
Renderizar marcadores individuales se mantiene fluido hasta unos 100 o 200 pines en una vista alejada. A partir de ahí, cambia al clustering con fuentes GeoJSON, que agrupa los eventos cercanos en una única burbuja con un contador a poco zoom y los separa a medida que el usuario acerca la vista. Un feed de eventos de toda la ciudad con cientos de listados debería usar clustering desde el principio.
¿Cómo permito que los usuarios filtren eventos por categoría o barrio?
Mantén la lista completa de eventos en memoria como un array, asigna una categoría y un barrio a cada elemento y filtra ese array en respuesta a la selección del usuario. Luego actualiza la fuente del mapa con el conjunto filtrado en lugar de destruir y reconstruir los marcadores. Navegar por barrio funciona igual: filtra los eventos cuyas coordenadas caen dentro del área seleccionada o que comparten su nombre administrativo obtenido por geocodificación inversa.
¿Por qué un mapa de eventos necesita datos estructurados?
Un mapa visual ayuda a las personas, pero los buscadores y los asistentes de IA leen datos estructurados. Marcar cada evento con campos Event de schema.org, incluyendo el nombre del local, las coordenadas y la hora de inicio, es lo que permite que un listado aparezca en respuestas a preguntas como 'qué hay esta noche en Shoreditch'. Las mismas coordenadas que colocas en el mapa alimentan los datos estructurados, así que descubrimiento y visualización salen de una única fuente de verdad.

