Os aplicativos da Web se beneficiaram muito com a inclusão de mapas, fornecendo aos usuários informações valiosas baseadas em localização. Os mapas transformaram a nossa interação com o mundo, desde navegar em lugares desconhecidos até descobrir restaurantes próximos. Como resultado, a integração de mapas em websites tornou-se cada vez mais popular nos últimos tempos. No entanto, conceber mapas que sejam funcionais e fáceis de utilizar pode representar um desafio, especialmente para aqueles que não têm experiência neste domínio. Neste artigo, compartilharei dicas úteis sobre como criar mapas eficazes em seu navegador.
Vamos discutir tecnologias. Ao trabalhar com mapas, normalmente usamos três camadas:
Renderização da interface do usuário, que inclui botões e formulários. Em nossa pilha, o React desempenha essa função;
Renderizando o mapa e permitindo a interação do usuário. Usamos Mapbox para isso;
Buscando dados do servidor, como informações sobre marcadores ou polígonos. Para recuperar dados, usamos o recurso de busca integrado do navegador.
Vamos revisar cada item para entender melhor nossa pilha de tecnologia ao trabalhar com mapas.
O
Como alterar elementos de uma página é a operação mais cara para um navegador, é essencial fazê-lo da forma mais eficiente possível. Para resolver esse problema, os engenheiros do Facebook desenvolveram a biblioteca React, que permite alterações rápidas e diretas nos elementos de uma página. Além de fornecer mudanças rápidas de estado em uma página, o React nos permite fazer isso de forma declarativa, sem trabalhar diretamente com elementos DOM. Em vez disso, usamos uma abstração, geralmente
// 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> )
É possível aninhar componentes com elementos DOM comuns, como formulários, botões e entradas na parte inferior da hierarquia. Ao montar esses elementos simples, podemos criar outros mais complexos, como um formulário completo:
const Form = () => ( <form> <input name="Email"/> <input name="Password"/> </form> ) const App = () => ( <main> <h1>My form!</h1> <Form /> </main> )
Como o React nos auxilia no contexto dos mapas? Como o mapa da página é interativo, semelhante a um botão ou formulário, pretendemos otimizar sua renderização e interação por meio de eventos como cliques no mapa. O React pode ajudar a alcançar essa otimização. Aqui está um exemplo de como 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> )
Ao trabalhar com React, é fundamental lembrar que ele permite a manipulação eficiente dos elementos da página, mudanças rápidas e interação com eles por meio de eventos. Isso é conseguido por meio de uma abstração semelhante ao HTML, facilitando a criação de componentes complexos a partir de componentes mais simples.
Agora, vamos discutir o mapa em si. Criar e usar mapas pode ser um desafio, e apenas algumas empresas de produtos conseguem projetar mapas do zero. Normalmente, a maioria das pessoas confia em bibliotecas pré-fabricadas com uma API fácil de usar que foi experimentada e testada.
Vários provedores de mapas dinâmicos estão disponíveis, incluindo Google Maps, Leaflet, Bing Maps, Mapbox e muito mais. No entanto, vamos nos concentrar em
Ofertas de caixa de mapas
Além disso, Mapbox fornece um
Mapbox oferece uma variedade de
Vamos revisitar os mapas do Mapbox. O que faz o
Inicializa o mapa em um elemento HTML da página;
Carrega e renderiza imagens que compõem o mapa;
Ele desenha elementos adicionais, como marcadores, usando GeoJson como dados de entrada;
Ele gera eventos, como cliques ou alterações de zoom, que podem ser manipulados.
Vamos dar uma olhada em cada um desses itens.
Mapbox é especializado em renderização de mapas usando blocos. Os blocos são pequenas imagens quadradas que constituem o mapa maior. O tamanho padrão de um bloco é 512x512 pixels e pode ser
Só para você saber, o Mapbox Studio nos permite escolher os dados específicos que queremos incluir nos blocos do mapa. Essas peças são então colocadas em um
<canvas width="100" height="100" />
Mapbox cuida do carregamento, inserção e atualização de blocos. Basta especificar onde queremos que o mapa seja exibido e as condições iniciais, como o nível de zoom ou as coordenadas do mapa. Para usar o Mapbox, você precisará de um
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 });
Depois disso, obteremos um mapa na página em um elemento com o id ‘map’.
Para fornecer mais informações aos usuários no mapa, muitas vezes exibimos a localização de um determinado estabelecimento ou os limites de uma área específica. Para conseguir isso, usamos um formato de dados específico chamado
GeoJSON é o formato padrão para armazenar estruturas geográficas em mapas. Ele pode armazenar vários tipos primitivos que descrevem objetos geográficos, como endereços, locais, ruas, rodovias, fronteiras, países, estados e combinações destes, conhecidos como multipartes. GeoJSON foi introduzido em 2008 e é representado assim:
{ "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" } }
Vamos falar sobre o sistema de coordenadas usado no Mapbox. Por padrão, o Mapbox empregamap.setProjection
.
Agora, discutiremos como exibir GeoJSON no mapa. Mapbox oferece duas entidades que consideraremos úteis:
Para exibir polígonos ou marcadores no mapa, devemos recuperar os dados no formato GeoJson do servidor. Em seguida, criamos uma fonte, inserimos os dados nela e conectamos à camada necessária.
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 } });
Depois de executar este código, obtemos o resultado:
Para saber mais sobre este tópico, você pode consultar oon
com o tipo de evento que desejamos, semelhante à forma como trabalhamos com elementos DOM.
map.on('mousemove', (e) => { console.log(JSON.stringify(e.point)); }); // Result: {"x":330,"y":49}
Em resumo, o que precisamos lembrar? Mapbox nos permite exibir um mapa, desenhar nossos dados sobre ele e processar eventos do mapa. Ao mesmo tempo, o Mapbox se encarrega de carregar e exibir imagens (tiles).
Uma palavra sobre
O que lembrar? Recuperamos dados do servidor e existem muitas bibliotecas para isso, mas usaremos fetch. A seguir, veremos como fazemos isso especificamente ao trabalhar com mapas, pois existem nuances.
Agora vamos ver como as tecnologias descritas acima funcionam juntas. Primeiro, recuperaremos os dados para exibir o polígono usando fetch. Em seguida declararemos a inicialização do mapa e, após carregá-lo, adicionaremos o polígono ao mapa.
Você também pode encontrar um exemplo prático no
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} />; }
Analisamos a pilha de tecnologia que sustenta nossa arquitetura futura. No artigo a seguir, discutiremos os princípios que ajudam a projetar uma arquitetura de mapas, como obter o máximo baixo acoplamento e alta coesão de módulos e como manter e desenvolver um sistema de mapas escalável.
Muito obrigado pela sua atenção! Tenha um ótimo dia.