Integração do AMap com React: Adicionando Marcadores, Polilinhas, Polígonos e Dados GeoJSON

Este artigo demonstra como utilizar a API JavaScript do AMap (Alibaba Maps) dentro de uma aplicação React para adicionar marcadores, linhas, polígonos e craregar dados no formato GeoJSON.

1. Inicialização do Mapa

A inicialização começa com a definição das coordenadas centrais e o nível de zoom. O componente useRef é usado para manter uma referência à instância do mapa.


const [mapConfig, setMapConfig] = useState({
  defaultZoom: 12,
  centerCoordinates: { lng: 120.165533, lat: 30.329062 },
});

const initializeMap = () => {
  const { centerCoordinates } = mapConfig;
  const center = [centerCoordinates.lng, centerCoordinates.lat];

  const mapInstance = new AMap.Map("mapContainer", {
    zoom: mapConfig.defaultZoom,
    zooms: [8, 19],
    disableSocket: true,
    center: center,
  });

  mapRef.current = mapInstance;
  drawRegionOutline(mapInstance);
};

2. Adicionando Marcadores (Marker)

Para cada ponto de dados, um marcador é criado com um ícone personalizado. Uma janela de informação é vinculada ao evento de clique de cada marcador.


const renderMarkers = (locations, mapInstance) => {
  const infoWindow = new AMap.InfoWindow({
    offset: new AMap.Pixel(5, -30),
    autoMove: true,
    closeWhenClickMap: true,
  });

  const markerCollection = [];

  locations.forEach(location => {
    if (location.longitude && location.latitude) {
      const position = [location.longitude, location.latitude];
      const newMarker = new AMap.Marker({
        position: position,
        icon: customIconImage,
        map: mapInstance,
      });

      markerCollection.push(newMarker);

      newMarker.on('click', () => {
        infoWindow.setContent(location.title);
        infoWindow.open(mapInstance, position);
      });
    }
  });

  setMarkersState(markerCollection);
  mapInstance.setFitView();
};

3. Desenhando Polilinhas (Polyline)

Uma função é responsável por trnasformar os dados brutos em coordenadas e criar polilinhas. Cada polilinha pode ter uma janela de informações personalizada.


const createPolyline = (routeData, mapInstance, callback) => {
  const polyline = new AMap.Polyline({
    path: routeData.coordinates,
    strokeColor: "#3366FF",
    strokeOpacity: 1,
    strokeWeight: 5,
    strokeStyle: "solid",
  });
  polyline.setMap(mapInstance);
  callback(polyline);

  if (routeData.infoContent) {
    const lineInfoWindow = new AMap.InfoWindow({
      content: routeData.infoContent,
      offset: new AMap.Pixel(5, -30),
    });
    polyline.on('click', (event) => {
      lineInfoWindow.open(mapInstance, event.lnglat);
    });
  }
};

const processAndDrawRoutes = (routeArray, mapInstance) => {
  const allPolylineInstances = [];
  const processedRoutes = routeArray.map(route => {
    const parsedPath = JSON.parse(route.pathData);
    return { ...route, coordinates: parsedPath };
  });

  processedRoutes.forEach(route => {
    createPolyline(route, mapInstance, (polylineInstance) => {
      allPolylineInstances.push(polylineInstance);
    });
  });

  setPolylinesState(allPolylineInstances);
};

4. Criando Polígonos (Polygon)

Para criar polígonos, as coordenadas são processadas e, se necessário, convertidas. Eventos de mouse são adicionados para feedback visual interativo.


const drawPolygon = (coordinates, mapInstance) => {
  const polygon = new AMap.Polygon({
    path: coordinates,
    fillColor: '#ccebc5',
    strokeOpacity: 1,
    fillOpacity: 0.5,
    strokeColor: '#2b8cbe',
    strokeWeight: 2,
  });

  polygon.on('mouseover', () => {
    polygon.setOptions({ fillOpacity: 0.7, fillColor: '#7bccc4' });
  });

  polygon.on('mouseout', () => {
    polygon.setOptions({ fillOpacity: 0.5, fillColor: '#ccebc5' });
  });

  mapInstance.add(polygon);
  mapInstance.setFitView(polygon);
};

const drawRegionOutline = (mapInstance) => {
  const regionGeoJSON = regionalJSONData;
  const outlinePoints = regionGeoJSON?.features[0]?.geometry?.coordinates[0][0].map(
    coord => new AMap.LngLat(coord[0], coord[1])
  );

  const outlinePolygon = new AMap.Polygon({
    path: outlinePoints,
    strokeColor: '#1CB9FF',
    strokeWeight: 3,
    strokeOpacity: 0.5,
    fillColor: '#1CB9FF',
    fillOpacity: 0.05,
  });

  mapInstance.add(outlinePolygon);
  mapInstance.setFitView(outlinePolygon);
};

5. Carregendo Dados GeoJSON

A classe AMap.GeoJSON é utilizada para interpretar e renderizar automaticamente dados GeoJSON, com a opção de personalizar a renderização de cada tipo de geometria.


const loadGeoJSONLayer = (mapInstance) => {
  const geoJSONLayer = new AMap.GeoJSON({
    geoJSON: sourceGeoJSONData,
    getPolygon: (geojson, lngLatArray) => {
      return new AMap.Polygon({
        path: lngLatArray,
        fillOpacity: 0,
        strokeColor: '#000',
        strokeWeight: 0.25,
      });
    },
  });

  mapInstance.add(geoJSONLayer);
};

6. Estrutura do Componente React

O componente React integra todas as funções anteriores, gerenciando o estado e os efeitos para atualizar o mapa conforme os dados mudam.


import React, { useRef, forwardRef, useEffect, useState } from 'react';
import AMap from 'AMap';
import { cloneDeep } from 'lodash';
import regionGeoJSON from './data/region.json';
import featureGeoJSON from './data/features.json';
import markerIcon from './assets/icon.png';

const MapComponent = forwardRef((props, ref) => {
  const { routeData, pointData, showPoints, onPointClick } = props;
  const mapRef = useRef(null);
  const [markers, setMarkers] = useState([]);
  const [polylines, setPolylines] = useState([]);

  // ... (Funções drawRegionOutline, renderMarkers, processAndDrawRoutes, loadGeoJSONLayer definidas aqui)

  const initializeMap = () => {
    // Inicialização do mapa
    const mapInstance = new AMap.Map("mapContainer", { ... });
    mapRef.current = mapInstance;
    drawRegionOutline(mapInstance);
    loadGeoJSONLayer(mapInstance);
  };

  useEffect(() => {
    initializeMap();
  }, []);

  useEffect(() => {
    if (mapRef.current && routeData) {
      processAndDrawRoutes(routeData, mapRef.current);
    }
  }, [routeData]);

  useEffect(() => {
    if (mapRef.current) {
      if (showPoints && pointData) {
        renderMarkers(pointData, mapRef.current);
      } else {
        mapRef.current.remove(markers);
      }
    }
  }, [showPoints, pointData]);

  return <div id="mapContainer" style={{ width: '100%', height: 640 }}></div>;
});

export default MapComponent;

Tags: AMap React javascript Mapas GeoJSON

Publicado em 6-14 19:41 por Thomas