# Map Tiles Component for LVGL 9.x
A comprehensive map tiles component for ESP-IDF projects using LVGL 9.x. This component provides functionality to load and display map tiles with GPS coordinate conversion, designed for embedded applications requiring offline map display capabilities.
## Features
- **LVGL 9.x Compatible**: Fully compatible with LVGL 9.x image handling
- **GPS Coordinate Conversion**: Convert GPS coordinates to tile coordinates and vice versa
- **Dynamic Tile Loading**: Load map tiles on demand from file system
- **Configurable Grid Size**: Support for different grid sizes (3x3, 5x5, 7x7, etc.)
- **Multiple Tile Types**: Support for up to 8 different tile types (street, satellite, terrain, hybrid, etc.)
- **Memory Efficient**: Configurable memory allocation (SPIRAM or regular RAM)
- **Multiple Zoom Levels**: Support for different map zoom levels
- **Error Handling**: Comprehensive error handling and logging
- **C API**: Clean C API for easy integration
## Requirements
- ESP-IDF 5.0 or later
- LVGL 9.3
- File system support (FAT/SPIFFS/LittleFS)
- Map tiles in binary format (RGB565, 256x256 pixels)
## Installation
### Using ESP-IDF Component Manager
You can easily add this component to your project using the idf.py command or by manually updating your idf_component.yml file.
#### Option 1: Using the idf.py add-dependency command (Recommended)
From your project's root directory, simply run the following command in your terminal:
```bash
idf.py add-dependency "0015/map_tiles^1.2.0"
```
This command will automatically add the component to your idf_component.yml file and download the required files the next time you build your project.
#### Option 2: Manual idf_component.yml update
Add to your project's `main/idf_component.yml`:
```yaml
dependencies:
map_tiles:
git: "https://github.com/0015/map_tiles.git"
version: "^1.2.0"
```
### Manual Installation
1. Copy the `map_tiles` folder to your project's `components` directory
2. The component will be automatically included in your build
## Usage
### Basic Setup
```c
#include "map_tiles.h"
// Configure the map tiles with multiple tile types and custom grid size
const char* tile_folders[] = {"street_map", "satellite", "terrain", "hybrid"};
map_tiles_config_t config = {
.base_path = "/sdcard", // Base path to tile storage
.tile_folders = {tile_folders[0], tile_folders[1], tile_folders[2], tile_folders[3]},
.tile_type_count = 4, // Number of tile types
.default_zoom = 10, // Default zoom level
.use_spiram = true, // Use SPIRAM if available
.default_tile_type = 0, // Start with street map (index 0)
.grid_cols = 5, // Grid width (tiles)
.grid_rows = 5 // Grid height (tiles)
};
// Initialize map tiles
map_tiles_handle_t map_handle = map_tiles_init(&config);
if (!map_handle) {
ESP_LOGE(TAG, "Failed to initialize map tiles");
return;
}
```
### Loading Tiles
```c
// Set center position from GPS coordinates
map_tiles_set_center_from_gps(map_handle, 37.7749, -122.4194); // San Francisco
// Get grid dimensions
int grid_cols, grid_rows;
map_tiles_get_grid_size(map_handle, &grid_cols, &grid_rows);
int tile_count = map_tiles_get_tile_count(map_handle);
// Load tiles for the configured grid size
for (int row = 0; row < grid_rows; row++) {
for (int col = 0; col < grid_cols; col++) {
int index = row * grid_cols + col;
int tile_x, tile_y;
map_tiles_get_position(map_handle, &tile_x, &tile_y);
bool loaded = map_tiles_load_tile(map_handle, index,
tile_x + col, tile_y + row);
if (!loaded) {
ESP_LOGW(TAG, "Failed to load tile %d", index);
}
}
}
```
### Displaying Tiles with LVGL
```c
// Get grid dimensions and tile count
int grid_cols, grid_rows;
map_tiles_get_grid_size(map_handle, &grid_cols, &grid_rows);
int tile_count = map_tiles_get_tile_count(map_handle);
// Create image widgets for each tile
lv_obj_t** tile_images = malloc(tile_count * sizeof(lv_obj_t*));
for (int i = 0; i < tile_count; i++) {
tile_images[i] = lv_image_create(parent_container);
// Get the tile image descriptor
lv_image_dsc_t* img_dsc = map_tiles_get_image(map_handle, i);
if (img_dsc) {
lv_image_set_src(tile_images[i], img_dsc);
// Position the tile in the grid
int row = i / grid_cols;
int col = i % grid_cols;
lv_obj_set_pos(tile_images[i],
col * MAP_TILES_TILE_SIZE,
row * MAP_TILES_TILE_SIZE);
}
}
```
### Switching Tile Types
```c
// Switch to different tile types
map_tiles_set_tile_type(map_handle, 0); // Street map
map_tiles_set_tile_type(map_handle, 1); // Satellite
map_tiles_set_tile_type(map_handle, 2); // Terrain
map_tiles_set_tile_type(map_handle, 3); // Hybrid
// Get current tile type
int current_type = map_tiles_get_tile_type(map_handle);
// Get available tile types
int type_count = map_tiles_get_tile_type_count(map_handle);
for (int i = 0; i < type_count; i++) {
const char* folder = map_tiles_get_tile_type_folder(map_handle, i);
printf("Tile type %d: %s\n", i, folder);
}
```
### GPS Coordinate Conversion
```c
// Convert GPS to tile coordinates
double tile_x, tile_y;
map_tiles_gps_to_tile_xy(map_handle, 37.7749, -122.4194, &tile_x, &tile_y);
// Check if GPS position is within current tile grid
bool within_tiles = map_tiles_is_gps_within_tiles(map_handle, 37.7749, -122.4194);
// Get marker offset for precise positioning
int offset_x, offset_y;
map_tiles_get_marker_offset(map_handle, &offset_x, &offset_y);
```
### Memory Management
```c
// Clean up when done
map_tiles_cleanup(map_handle);
```
## Tile File Format
The component expects map tiles in a specific binary format:
- **File Structure**: `{base_path}/{map_tile}/{zoom}/{tile_x}/{tile_y}.bin`
- **Format**: 12-byte header + raw RGB565 pixel data
- **Size**: 256x256 pixels
- **Color Format**: RGB565 (16-bit per pixel)
### Example Tile Structure
```
/sdcard/
├── street_map/ // Tile type 0
│ ├── 10/
│ │ ├── 164/
│ │ │ ├── 395.bin
│ │ │ ├── 396.bin
│ │ │ └── ...
│ │ └── ...
│ └── ...
├── satellite/ // Tile type 1
│ ├── 10/
│ │ ├── 164/
│ │ │ ├── 395.bin
│ │ │ └── ...
│ │ └── ...
│ └── ...
├── terrain/ // Tile type 2
│ └── ...
└── hybrid/ // Tile type 3
└── ...
```
## Configuration Options
| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `base_path` | `const char*` | Base directory for tile storage | Required |
| `tile_folders` | `const char*[]` | Array of folder names for different tile types | Required |
| `tile_type_count` | `int` | Number of tile types (max 8) | Required |
| `default_zoom` | `int` | Initial zoom level | Required |
| `use_spiram` | `bool` | Use SPIRAM for tile buffers | `false` |
| `default_tile_type` | `int` | Initial tile type index | Required |
| `grid_cols` | `int` | Number of tile columns (max 10) | 5 |
| `grid_rows` | `int` | Number of tile rows (max 10) | 5 |
## API Reference
### Initialization
- `map_tiles_init()` - Initialize map tiles system
- `map_tiles_cleanup()` - Clean up resources
### Tile Management
- `map_tiles_load_tile()` - Load a specific tile
- `map_tiles_get_image()` - Get LVGL image descriptor
- `map_tiles_get_buffer()` - Get raw tile buffer
### Grid Management
- `map_tiles_get_grid_size()` - Get current grid dimensions
- `map_tiles_get_tile_count()` - Get total number of tiles in grid
### Coordinate Conversion
- `map_tiles_gps_to_tile_xy()` - Convert GPS to tile coordinates
- `map_tiles_set_center_from_gps()` - Set center from GPS
- `map_tiles_is_gps_within_tiles()` - Check if GPS is within current tiles
### Position Management
- `map_tiles_get_position()` - Get current tile position
- `map_tiles_set_position()` - Set tile position
- `map_tiles_get_marker_offset()` - Get marker offset
- `map_tiles_set_marker_offset()` - Set marker offset
### Tile Type Management
- `map_tiles_set_tile_type()` - Set active tile type
- `map_tiles_get_tile_type()` - Get current tile type
- `map_tiles_get_tile_type_count()` - Get number of available types
- `map_tiles_get_tile_type_folder()` - Get folder name for a type
### Zoom Control
- `map_tiles_set_zoom()` - Set zoom level
- `map_tiles_get_zoom()` - Get current zoom level
### Error Handling
- `map_tiles_set_loading_error()` - Set error state
- `map_tiles_has_loading_error()` - Check error state
## Performance Considerations
- **Memory Usage**: Each tile uses ~128KB (256×256×2 bytes)
- **Grid Size**: Larger grids use more memory (3x3=9 tiles, 5x5=25 tiles, 7x7=49 tiles)
- **SPIRAM**: Recommended for ESP32-S3 with PSRAM for better performance
- **File System**: Ensure adequate file system performance for tile loading
- **Tile Caching**: Component maintains tile buffers until cleanup
## Example Projects
See the `examples` directory for complete implementation examples:
- Basic map display
- GPS tracking with map updates
- Interactive map with touch controls
## License
This component is released under the MIT License. See LICENSE file for details.
## Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
## Support
For questions and support, please open an issue on the GitHub repository.
idf.py add-dependency "0015/map_tiles^1.2.0"