This repository has been archived on 2025-12-24. You can view files and clone it, but cannot push or open issues or pull requests.
site-template/docs/maps.md

7.1 KiB

StaticMap Component for Astro

Static Map Options

Provider API Key Features Limitations Example URL
Google Maps Static API Required Multiple marker styles, road/satellite/hybrid views Limited free tier https://maps.googleapis.com/maps/api/staticmap?center=-2.2697,40.9025&zoom=14&size=600x400&markers=color:red%7C-2.2697,40.9025&key=YOUR_API_KEY
Mapbox Static Maps Required Highly customizable styles, multiple layers Complex URL structure https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/pin-s+ff0000(-2.2697,40.9025)/-2.2697,40.9025,14,0/600x400?access_token=YOUR_API_KEY
OpenStreetMap Static Not required Free, simple implementation Limited styling https://staticmap.openstreetmap.de/staticmap.php?center=-2.2697,40.9025&zoom=14&size=600x400&markers=-2.2697,40.9025,red
MapTiler Required Custom styles, vector tiles Less common https://api.maptiler.com/maps/streets/static/40.9025,-2.2697,14/600x400.png?markers=40.9025,-2.2697,red&key=YOUR_API_KEY
HERE Maps Required Good international coverage Less flexible styling https://image.maps.ls.hereapi.com/mia/1.6/mapview?c=-2.2697,40.9025&z=14&w=600&h=400&poi=-2.2697,40.9025&apiKey=YOUR_API_KEY

Astro Component

Here's a complete Astro component that supports all the providers mentioned above:

---
// src/components/StaticMap.astro
export interface GeoPos {
  lon: number;
  lat: number;
}

export interface Location {
  geo: GeoPos;
  title: string;
}

export interface Options {
  zoom?: number;
  width?: number;
  height?: number;
  apiKey?: string;
  provider?: 'google' | 'mapbox' | 'openstreetmap' | 'maptiler' | 'here';
  mapType?: string;
  markerColor?: string;
}

const DEFAULT_LOCATION: Location = {
  geo: {
    lat: -2.2697, // Latitude for Lamu, Kenya
    lon: 40.9025  // Longitude for Lamu, Kenya
  },
  title: "Lamu, Kenya"
};

const DEFAULT_OPTIONS: Options = {
  zoom: 14,
  width: 600,
  height: 400,
  provider: 'google',
  mapType: 'roadmap',
  markerColor: 'red'
};

interface Props {
  locations?: Location[];
  options?: Options;
}

const { 
  locations = [DEFAULT_LOCATION],
  options = {}
} = Astro.props;

const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
const { zoom, width, height, apiKey, provider, mapType, markerColor } = mergedOptions;

// Function to build URL based on provider
function buildMapUrl(provider: string, locations: Location[], options: Options): string {
  const { zoom, width, height, apiKey, mapType, markerColor } = options;
  
  switch (provider) {
    case 'google':
      let googleUrl = 'https://maps.googleapis.com/maps/api/staticmap?';
      
      // Center map on the first location if available
      if (locations.length > 0) {
        googleUrl += `center=${locations[0].geo.lat},${locations[0].geo.lon}&`;
      }
      
      // Add zoom, size and map type
      googleUrl += `zoom=${zoom}&size=${width}x${height}&maptype=${mapType}&`;
      
      // Add markers
      locations.forEach(location => {
        googleUrl += `markers=color:${markerColor}%7C${location.geo.lat},${location.geo.lon}&`;
      });
      
      // Add API key if available
      if (apiKey) {
        googleUrl += `key=${apiKey}`;
      }
      
      return googleUrl;
      
    case 'mapbox':
      let mapboxUrl = 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/';
      
      // Add markers
      if (locations.length > 0) {
        locations.forEach((location, index) => {
          if (index > 0) mapboxUrl += ',';
          const color = markerColor.startsWith('#') ? markerColor.substring(1) : markerColor;
          mapboxUrl += `pin-s+${color}(${location.geo.lon},${location.geo.lat})`;
        });
        mapboxUrl += '/';
      }
      
      // Add center coordinates, zoom and size
      const firstLocation = locations[0];
      mapboxUrl += `${firstLocation.geo.lon},${firstLocation.geo.lat},${zoom},0/${width}x${height}`;
      
      // Add API key
      if (apiKey) {
        mapboxUrl += `?access_token=${apiKey}`;
      }
      
      return mapboxUrl;
      
    case 'openstreetmap':
      let osmUrl = 'https://staticmap.openstreetmap.de/staticmap.php?';
      
      // Add center, zoom and size
      if (locations.length > 0) {
        osmUrl += `center=${locations[0].geo.lat},${locations[0].geo.lon}&zoom=${zoom}&size=${width}x${height}&`;
      }
      
      // Add markers
      locations.forEach(location => {
        osmUrl += `markers=${location.geo.lat},${location.geo.lon},${markerColor}&`;
      });
      
      return osmUrl;
      
    case 'maptiler':
      let maptilerUrl = 'https://api.maptiler.com/maps/streets/static/';
      
      // Add center coordinates, zoom and size
      const firstLocMaptiler = locations[0];
      maptilerUrl += `${firstLocMaptiler.geo.lon},${firstLocMaptiler.geo.lat},${zoom}/${width}x${height}.png?`;
      
      // Add markers
      if (locations.length > 0) {
        locations.forEach((location, index) => {
          maptilerUrl += `markers=${location.geo.lon},${location.geo.lat},${markerColor}&`;
        });
      }
      
      // Add API key
      if (apiKey) {
        maptilerUrl += `key=${apiKey}`;
      }
      
      return maptilerUrl;
      
    case 'here':
      let hereUrl = 'https://image.maps.ls.hereapi.com/mia/1.6/mapview?';
      
      // Add center, zoom and size
      if (locations.length > 0) {
        hereUrl += `c=${locations[0].geo.lat},${locations[0].geo.lon}&z=${zoom}&w=${width}&h=${height}&`;
      }
      
      // Add markers
      locations.forEach((location, index) => {
        hereUrl += `poi=${location.geo.lat},${location.geo.lon}&`;
      });
      
      // Add API key
      if (apiKey) {
        hereUrl += `apiKey=${apiKey}`;
      }
      
      return hereUrl;
      
    default:
      return '';
  }
}

const mapUrl = buildMapUrl(provider!, locations, mergedOptions);
---

<div class="static-map w-full">
  <img 
    src={mapUrl} 
    alt="Static Map" 
    class="w-full h-auto max-w-full border border-gray-300 rounded shadow" 
    width={width} 
    height={height}
  />
</div>

Example Usage

---
import StaticMap from '../components/StaticMap.astro';

const locations = [
  {
    geo: { lat: -2.2697, lon: 40.9025 },
    title: "Lamu Old Town"
  },
  {
    geo: { lat: -2.2723, lon: 40.9018 },
    title: "Lamu Fort"
  }
];

const options = {
  zoom: 15,
  width: 800,
  height: 500,
  apiKey: import.meta.env.GOOGLE_MAPS_API_KEY,
  provider: 'google'
};
---

<div class="container mx-auto my-8 px-4">
  <h1 class="text-2xl font-bold mb-4">Map of Lamu</h1>
  <StaticMap locations={locations} options={options} />
</div>

References