or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-features.mdchild-components.mdgeographic-utilities.mdindex.mdmap-component.mdtile-system.md
tile.json

tile-system.mddocs/

Tile System

Functions for working with map tiles and tile coordinates. These utilities are useful for advanced map applications that need to work with Google Maps' tile system for custom overlays, caching, or tile-based operations.

Capabilities

Coordinate Conversion

Convert between geographic coordinates (lat/lng) and tile coordinates.

/**
 * Converts tile coordinates to latitude/longitude at specified zoom level
 * @param tile - Tile coordinates (x, y)
 * @param zoom - Map zoom level
 * @returns Geographic coordinates
 */
function tile2LatLng(
  tile: { x: number; y: number }, 
  zoom: number
): { lat: number; lng: number };

/**
 * Converts latitude/longitude to tile coordinates at specified zoom level
 * @param coords - Geographic coordinates
 * @param zoom - Map zoom level  
 * @returns Tile coordinates
 */
function latLng2Tile(
  coords: { lat: number; lng: number }, 
  zoom: number
): { x: number; y: number };

Usage Examples:

import { tile2LatLng, latLng2Tile } from 'google-map-react';

// Convert tile to coordinates
const tileCoords = { x: 1234, y: 5678 };
const zoom = 10;
const latLng = tile2LatLng(tileCoords, zoom);
console.log(latLng); // { lat: 40.7128, lng: -74.0060 }

// Convert coordinates to tile
const coords = { lat: 37.7749, lng: -122.4194 };
const tile = latLng2Tile(coords, zoom);
console.log(tile); // { x: 163, y: 395 }

// Round trip conversion (should match original)
const roundTrip = latLng2Tile(tile2LatLng(tileCoords, zoom), zoom);
console.log(roundTrip); // Should match tileCoords

Tile Range Operations

Get all tile IDs within a specified range for batch operations.

/**
 * Gets array of tile IDs for given tile range and zoom level
 * @param range - Tile range with from/to coordinates
 * @param zoom - Map zoom level
 * @returns Array of tile IDs as [zoom, x, y] tuples
 */
function getTilesIds(
  range: { 
    from: { x: number; y: number }; 
    to: { x: number; y: number } 
  }, 
  zoom: number
): Array<[number, number, number]>;

Usage Examples:

import { getTilesIds } from 'google-map-react';

// Get all tiles in a region
const range = {
  from: { x: 100, y: 200 },
  to: { x: 105, y: 205 }
};
const zoom = 12;

const tileIds = getTilesIds(range, zoom);
console.log(tileIds);
// Output: [[12, 100, 200], [12, 100, 201], ..., [12, 105, 205]]

// Use for tile preloading or caching
const tilesToLoad = getTilesIds(range, zoom);
tilesToLoad.forEach(([z, x, y]) => {
  const tileUrl = `https://mt1.google.com/vt/lyrs=m&x=${x}&y=${y}&z=${z}`;
  preloadTile(tileUrl);
});

Advanced Usage Patterns

Custom Tile Overlay

Create custom tile overlays using tile coordinate calculations:

import { latLng2Tile, tile2LatLng, getTilesIds } from 'google-map-react';

class CustomTileOverlay {
  constructor(map, zoom) {
    this.map = map;
    this.zoom = zoom;
  }

  // Calculate visible tiles for current map bounds
  getVisibleTiles() {
    const bounds = this.map.getBounds();
    const ne = bounds.getNorthEast();
    const sw = bounds.getSouthWest();

    // Convert bounds to tile coordinates
    const neTile = latLng2Tile({ lat: ne.lat(), lng: ne.lng() }, this.zoom);
    const swTile = latLng2Tile({ lat: sw.lat(), lng: sw.lng() }, this.zoom);

    // Get all tiles in the visible area
    return getTilesIds({
      from: { x: swTile.x, y: neTile.y },
      to: { x: neTile.x, y: swTile.y }
    }, this.zoom);
  }

  // Create overlay for specific tile
  createTileOverlay(tileId) {
    const [zoom, x, y] = tileId;
    
    // Get tile bounds
    const nw = tile2LatLng({ x, y }, zoom);
    const se = tile2LatLng({ x: x + 1, y: y + 1 }, zoom);

    // Create overlay rectangle
    const overlay = new google.maps.Rectangle({
      bounds: {
        north: nw.lat,
        south: se.lat,
        east: se.lng,
        west: nw.lng
      },
      strokeColor: '#FF0000',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: '#FF0000',
      fillOpacity: 0.35,
      map: this.map
    });

    return overlay;
  }
}

// Usage with GoogleMapReact
function MapWithTileOverlay() {
  const [overlays, setOverlays] = useState([]);

  const handleApiLoaded = ({ map }) => {
    const tileOverlay = new CustomTileOverlay(map, 10);
    const visibleTiles = tileOverlay.getVisibleTiles();
    
    const newOverlays = visibleTiles.slice(0, 10).map(tileId => 
      tileOverlay.createTileOverlay(tileId)
    );
    
    setOverlays(newOverlays);
  };

  return (
    <GoogleMapReact
      defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
      defaultZoom={10}
      onGoogleApiLoaded={handleApiLoaded}
      yesIWantToUseGoogleMapApiInternals
    />
  );
}

Tile-Based Data Loading

Load data based on visible map tiles:

import { latLng2Tile, getTilesIds } from 'google-map-react';

function useMapTileData(center, zoom, mapBounds) {
  const [tileData, setTileData] = useState({});

  useEffect(() => {
    if (!mapBounds) return;

    // Calculate current tile range
    const ne = mapBounds.ne;
    const sw = mapBounds.sw;
    
    const neTile = latLng2Tile(ne, zoom);
    const swTile = latLng2Tile(sw, zoom);
    
    const tileIds = getTilesIds({
      from: { x: swTile.x, y: neTile.y },
      to: { x: neTile.x, y: swTile.y }
    }, zoom);

    // Load data for each tile
    tileIds.forEach(async ([z, x, y]) => {
      const tileKey = `${z}-${x}-${y}`;
      
      if (!tileData[tileKey]) {
        try {
          const data = await fetchTileData(x, y, z);
          setTileData(prev => ({
            ...prev,
            [tileKey]: data
          }));
        } catch (error) {
          console.error(`Failed to load tile ${tileKey}:`, error);
        }
      }
    });
  }, [center, zoom, mapBounds]);

  return tileData;
}

// Usage
function DataDrivenMap() {
  const [mapBounds, setMapBounds] = useState(null);
  const [zoom, setZoom] = useState(10);
  const [center, setCenter] = useState({ lat: 37.7749, lng: -122.4194 });
  
  const tileData = useMapTileData(center, zoom, mapBounds);

  return (
    <GoogleMapReact
      center={center}
      zoom={zoom}
      onChange={({ center, zoom, bounds }) => {
        setCenter(center);
        setZoom(zoom);
        setMapBounds({
          ne: { lat: bounds[0], lng: bounds[3] },
          sw: { lat: bounds[2], lng: bounds[1] }
        });
      }}
    >
      {Object.entries(tileData).map(([tileKey, data]) => (
        <TileDataMarkers key={tileKey} data={data} />
      ))}
    </GoogleMapReact>
  );
}

Tile Coordinate Validation

Validate and normalize tile coordinates:

import { tile2LatLng, latLng2Tile } from 'google-map-react';

class TileUtils {
  static isValidTile(x, y, zoom) {
    const maxTile = Math.pow(2, zoom);
    return x >= 0 && x < maxTile && y >= 0 && y < maxTile;
  }

  static normalizeTile(x, y, zoom) {
    const maxTile = Math.pow(2, zoom);
    return {
      x: ((x % maxTile) + maxTile) % maxTile,
      y: Math.max(0, Math.min(y, maxTile - 1))
    };
  }

  static getTileUrl(x, y, zoom, server = 'mt1') {
    if (!this.isValidTile(x, y, zoom)) {
      const normalized = this.normalizeTile(x, y, zoom);
      x = normalized.x;
      y = normalized.y;
    }
    
    return `https://${server}.google.com/vt/lyrs=m&x=${x}&y=${y}&z=${zoom}`;
  }
}

// Usage
const tileCoords = { x: 1000000, y: -50 }; // Invalid coordinates
const zoom = 10;

if (!TileUtils.isValidTile(tileCoords.x, tileCoords.y, zoom)) {
  const normalized = TileUtils.normalizeTile(tileCoords.x, tileCoords.y, zoom);
  console.log('Normalized:', normalized);
}