Las aplicaciones web se han beneficiado enormemente de la inclusión de mapas, que proporcionan a los usuarios información valiosa basada en la ubicación. Los mapas han transformado nuestra interacción con el mundo, desde navegar por lugares desconocidos hasta descubrir restaurantes cercanos. Como resultado, la integración de mapas en sitios web se ha vuelto cada vez más popular en los últimos tiempos. Sin embargo, diseñar mapas que sean funcionales y fáciles de usar puede presentar un desafío, especialmente para quienes carecen de experiencia en este ámbito. En este artículo, compartiré consejos útiles sobre cómo crear mapas efectivos en su navegador.
Hablemos de tecnologías. Cuando trabajamos con mapas, normalmente utilizamos tres capas:
Representación de la interfaz de usuario, que incluye botones y formularios. En nuestra pila, React desempeña esta función;
Representar el mapa y permitir la interacción del usuario. Usamos Mapbox para esto;
Obteniendo datos del servidor, como información sobre marcadores o polígonos. Para recuperar datos, utilizamos la función de recuperación integrada del navegador.
Repasemos cada elemento para comprender mejor nuestra tecnología al trabajar con mapas.
El
Como cambiar elementos en una página es la operación más costosa para un navegador, es esencial hacerlo de la manera más eficiente posible. Para abordar este problema, los ingenieros de Facebook desarrollaron la biblioteca React, que permite cambios de elementos rápidos y sencillos en una página. Además de proporcionar cambios rápidos de estado en una página, React nos permite hacer esto de forma declarativa sin trabajar directamente con elementos DOM. En su lugar, utilizamos una abstracción, normalmente
// It's our state. Is the user our friend or not? // false by default const [isFriend, setIsFriend] = useState(false) // Depending on the state, we show the text on the button const buttonText = isFriend ? 'Your my Friend' : 'Add as Friend' // There is JSX, syntax for UI // In this case, we display a button, when clicked, we change the state return ( <button onClick={() => setIsFriend(true)}>{buttonText}</button> )
Es posible anidar componentes con elementos DOM ordinarios como formularios, botones y entradas en la parte inferior de la jerarquía. Al ensamblar estos elementos simples, podemos crear otros más complejos, como por ejemplo un formulario completo:
const Form = () => ( <form> <input name="Email"/> <input name="Password"/> </form> ) const App = () => ( <main> <h1>My form!</h1> <Form /> </main> )
¿Cómo nos ayuda React en el contexto de los mapas? Como el mapa de la página es interactivo, similar a un botón o formulario, nuestro objetivo es optimizar su representación e interacción a través de eventos como clics en el mapa. React puede ayudar a lograr esta optimización. Aquí hay un ejemplo de cómo funciona:
// Use React to render the map with different event handlers // and render markers return ( <BaseMap onInitMap={() => console.log('I am alive!')} onClickMap={() => console.log('Click!')} onDestroyMap={() => console.log('Oh no!')} > <ClustersMarkers /> <PostsMarkers /> <ListingsMarkers /> </BaseMap> )
Al trabajar con React, es fundamental recordar que permite la manipulación eficiente de los elementos de la página, cambios rápidos e interacción con ellos a través de eventos. Esto se logra mediante una abstracción que se asemeja a HTML, lo que facilita la creación de componentes complejos a partir de otros más simples.
Ahora, analicemos el mapa en sí. Crear y utilizar mapas puede ser un desafío y sólo unas pocas empresas de productos pueden diseñar mapas desde cero. Por lo general, la mayoría de las personas confían en bibliotecas prediseñadas con una API fácil de usar que ha sido probada y comprobada.
Hay numerosos proveedores de mapas dinámicos disponibles, incluidos Google Maps, Leaflet, Bing Maps, Mapbox y más. Sin embargo, nos centraremos en
Ofertas de Mapbox
Además, Mapbox proporciona una
Mapbox proporciona una variedad de
Revisemos los mapas de Mapbox. Lo que hace el
Inicializa el mapa en un elemento HTML de la página;
Carga y renderiza imágenes que componen el mapa;
Dibuja elementos adicionales, como marcadores, utilizando GeoJson como datos de entrada;
Genera eventos, como clics o cambios de zoom, que se pueden manejar.
Echemos un vistazo más de cerca a cada uno de estos elementos.
Mapbox se especializa en la representación de mapas mediante mosaicos. Los mosaicos son pequeñas imágenes cuadradas que forman el mapa más grande. El tamaño predeterminado de un mosaico es 512x512 píxeles y puede ser
Para que lo sepas, Mapbox Studio nos permite elegir los datos específicos que queremos incluir en los mosaicos del mapa. Estas baldosas luego se colocan sobre un
<canvas width="100" height="100" />
Mapbox maneja la carga, inserción y actualización de mosaicos. Lo único que tenemos que hacer es especificar dónde queremos que se muestre el mapa y las condiciones iniciales, como el nivel de zoom o las coordenadas del mapa. Para utilizar Mapbox, necesitará un
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN'; const map = new mapboxgl.Map({ container: 'map', // we can use an Id or an element style: 'mapbox://styles/mapbox/streets-v11', // URL for styles center: [-74.5, 40], // initial coordinates [lng, lat] zoom: 9, // initial zoom });
Después de esto, obtendremos un mapa en la página en un elemento con el ID 'mapa'.
Para ofrecer a los usuarios más información en el mapa, muchas veces mostramos la ubicación de un determinado establecimiento o los límites de un área específica. Para lograr esto, utilizamos un formato de datos específico llamado
GeoJSON es el formato estándar para almacenar estructuras geográficas en mapas. Puede almacenar varios tipos primitivos que describen objetos geográficos como direcciones, ubicaciones, calles, carreteras, fronteras, países, estados y combinaciones de estos, lo que se conoce como multiparte. GeoJSON se introdujo en 2008 y se representa así:
{ "type": "Feature", // also can be FeatureCollection, it's collection of Feature "geometry": { "type": "Point", // also can be LineString, Polygon, MultiPolygon "coordinates": [125.6, 10.1] // for other types you can use Array with coordinates }, "properties": { // it's metadata, we can you that to show something on the map "name": "Dinagat Islands" } }
Hablemos del sistema de coordenadas utilizado en Mapbox. Por defecto, Mapbox empleamap.setProjection
.
Ahora, discutiremos cómo mostrar GeoJSON en el mapa. Mapbox ofrece dos entidades que nos resultarán útiles:
Para mostrar polígonos o marcadores en el mapa, debemos recuperar los datos en formato GeoJson del servidor. Luego, creamos una fuente, ingresamos los datos en ella y la conectamos a la capa requerida.
const geoJsonFeature = { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ [-67.13734, 45.13745], [-66.96466, 44.8097], [-68.03252, 44.3252], [-67.13734, 45.13745] ] } } // Create source with our data map.addSource('ourSource', { 'type': 'geojson', 'data': geoJsonFeature }); // Add layer for background map.addLayer({ 'id': 'background', 'type': 'fill', 'source': 'ourSource', // название нашего source 'layout': {}, 'paint': { 'fill-color': '#0080ff', 'fill-opacity': 0.5 } }); // Add layer for border map.addLayer({ 'id': 'border', 'type': 'line', 'source': 'ourSource', 'layout': {}, 'paint': { 'line-color': '#000', 'line-width': 3 } });
Después de ejecutar este código, obtenemos el resultado:
Para obtener más información sobre este tema, puede consultar elon
con el tipo de evento que queremos, de manera similar a como trabajamos con elementos DOM.
map.on('mousemove', (e) => { console.log(JSON.stringify(e.point)); }); // Result: {"x":330,"y":49}
En resumen, ¿qué debemos recordar? Mapbox nos permite mostrar un mapa, dibujar nuestros datos encima de él y procesar eventos del mapa. Al mismo tiempo, Mapbox se encarga de cargar y mostrar imágenes (mosaicos).
Una palabra sobre
¿Qué recordar? Recuperamos datos del servidor y hay muchas bibliotecas para esto, pero usaremos fetch. A continuación, veremos cómo hacemos esto específicamente cuando trabajamos con mapas, ya que hay matices.
Ahora veamos cómo funcionan juntas las tecnologías descritas anteriormente. Primero, recuperaremos los datos para mostrar el polígono usando fetch. Luego declararemos la inicialización del mapa y, después de que se cargue, agregaremos el polígono al mapa.
También puede encontrar un ejemplo práctico en el
const useFetch = () => { /* Our data { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ [ [-67.13734, 45.13745], [-68.03252, 44.3252], [-68.90478, 47.18479], [-67.13734, 45.13745], ] ] } } */ const [data, setData] = useState(null) useEffect(() => { fetch('https://our-api.com/polygon') .then(response => response.json()) .then(setData) .catch(e => { console.error(e) }) }, [setData]) return { data } } const BaseMap = () => { // Use the hook to fetch data const { data } = useFetch(GET_REGION); // Map instance const map = useRef(null); // DOM element const mapContainer = useRef(null); // Main logic - init the map and add the event useEffect(() => { if (map.current) { return; // initialize map only once } mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN'; map.current = new mapboxgl.Map({ container: mapContainer.current, style: 'mapbox://styles/mapbox/light-v10', // style URL (it's Mapbox's core style) center: [-68.137343, 45.137451], // starting position zoom: 5 // starting zoom }); // Handle event map.on('load', () => { const sourceId = 'source-region' // Add a data source containing GeoJSON data map.addSource(sourceId, { 'type': 'geojson', 'data': data.region // our data from Apollo }); // Add a new layer to visualize the polygon map.addLayer({ 'id': 'background', 'type': 'fill', 'source': sourceId, // reference the data source 'paint': { 'fill-color': '#0080ff', // blue color fill 'fill-opacity': 0.5 } }); // Add a black outline around the polygon map.addLayer({ 'id': 'outline', 'type': 'line', 'source': sourceId, 'paint': { 'line-color': '#000', 'line-width': 3 } }); }); }); return <div ref={mapContainer} />; }
Analizamos la pila de tecnología que sustenta nuestra arquitectura futura. En el siguiente artículo, analizaremos los principios que ayudan a diseñar una arquitectura de mapas, cómo lograr el máximo acoplamiento bajo y alta cohesión de los módulos, y cómo mantener y desarrollar un sistema de mapas escalable.
¡Muchas gracias por su atención! Qué tengas un lindo día.