lbcdev/filament-map-field
Filament Map Field adds Leaflet-powered map components for Filament v3/v4: MapField and MapEntry to pick/display coordinates, plus MapBoundsField/Entry for rectangular areas. Supports reactive updates, separate lat/lng fields, and nested JSON paths.
Un paquete de Filament que proporciona componentes de campo de mapa para formularios e infolists, utilizando el componente Livewire lbcdev-map.
✨ Compatible con Filament v3 y v4 - Actualiza sin preocupaciones, sin cambios en tu código.
'ubicacion.latitud'Nota: Este paquete es compatible con Filament v3 y v4. No necesitas hacer cambios en tu código al actualizar de Filament v3 a v4.
composer require lbcdev/filament-map-field
El paquete depende de lbcdev/livewire-map-component, que requiere Leaflet.js. Agrega estos scripts en el <head> de tu layout principal:
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- Leaflet Draw (solo si usas MapBoundsField) -->
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css" />
<script src="https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js"></script>
Nota: Leaflet Draw solo es necesario si vas a usar
MapBoundsFieldpara seleccionar áreas rectangulares. Si solo usasMapFieldpara puntos, no es necesario incluirlo.
Con Filament v4 puedes usar un hook para incluir los tags de Leaflet. Agrega el siguiente código a tu archivo app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel{
return $panel
...
->renderHook(
'panels::head.end',
fn(): string => view('filament.hooks.leaflet-assets')->render()
)
...
}
Si deseas personalizar las vistas del componente:
php artisan vendor:publish --tag=filament-map-field-views
Las vistas se publicarán en resources/views/vendor/filament-map-field/.
El componente MapField permite a los usuarios seleccionar coordenadas de forma interactiva en un formulario.
use Lbcdev\FilamentMapField\Forms\Components\MapField;
MapField::make('location')
->latitude('latitude')
->longitude('longitude');
MapField::make('location')
->latitude('latitude') // Campo donde se guardará la latitud
->longitude('longitude') // Campo donde se guardará la longitud
->height(500) // Altura del mapa en píxeles (default: 400)
->zoom(15) // Nivel de zoom inicial (default: 15)
->showPasteButton() // Mostrar botón para pegar coordenadas
->showLabel() // Mostrar etiqueta con coordenadas
->interactive(); // Permitir interacción (default: true)
// Usando readOnly() - Compatible con la API estándar de Filament
MapField::make('location')
->latitude('latitude')
->longitude('longitude')
->readOnly();
// O usando interactive(false) - Mismo resultado
MapField::make('location')
->latitude('latitude')
->longitude('longitude')
->interactive(false);
<?php
namespace App\Filament\Resources;
use App\Models\Location;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Lbcdev\FilamentMapField\Forms\Components\MapField;
class LocationResource extends Resource
{
protected static ?string $model = Location::class;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\TextInput::make('address')
->maxLength(255),
Forms\Components\Grid::make(2)
->schema([
Forms\Components\TextInput::make('latitude')
->numeric()
->required(),
Forms\Components\TextInput::make('longitude')
->numeric()
->required(),
]),
MapField::make('map')
->latitude('latitude')
->longitude('longitude')
->height(500)
->zoom(15)
->showPasteButton()
->columnSpanFull(),
]);
}
}
Cuando uses notación de punto para campos JSON anidados, el primer parámetro de make() debe coincidir con el campo padre:
// ✅ CORRECTO: make() usa el campo padre 'ubicacion'
MapField::make('ubicacion')
->latitude('ubicacion.latitud')
->longitude('ubicacion.longitud')
->columnSpanFull();
// ❌ INCORRECTO: make() usa 'map' pero los campos son 'ubicacion.latitud'
// Esto causará error "The ubicación field is required" en modo create
MapField::make('map')
->latitude('ubicacion.latitud')
->longitude('ubicacion.longitud')
->columnSpanFull();
Modelo con campo JSON:
class Store extends Model
{
protected $fillable = ['name', 'ubicacion'];
protected $casts = [
'ubicacion' => 'array', // Campo JSON
];
}
Migración:
Schema::create('stores', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->json('ubicacion')->nullable(); // Campo JSON
$table->timestamps();
});
El componente MapEntry muestra las coordenadas en un mapa de solo lectura en infolists.
use Lbcdev\FilamentMapField\Infolists\Entries\MapEntry;
MapEntry::make('location')
->latitude('latitude')
->longitude('longitude');
MapEntry::make('location')
->latitude('latitude')
->longitude('longitude')
->height(400)
->zoom(15)
->showLabel();
<?php
namespace App\Filament\Resources;
use App\Models\Location;
use Filament\Infolists;
use Filament\Infolists\Infolist;
use Filament\Resources\Resource;
use Lbcdev\FilamentMapField\Infolists\Entries\MapEntry;
class LocationResource extends Resource
{
protected static ?string $model = Location::class;
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Infolists\Components\TextEntry::make('name'),
Infolists\Components\TextEntry::make('address'),
Infolists\Components\Grid::make(2)
->schema([
Infolists\Components\TextEntry::make('latitude')
->numeric(decimalPlaces: 6),
Infolists\Components\TextEntry::make('longitude')
->numeric(decimalPlaces: 6),
]),
MapEntry::make('map')
->latitude('latitude')
->longitude('longitude')
->height(400)
->zoom(15)
->columnSpanFull(),
]);
}
}
El componente MapBoundsField permite a los usuarios seleccionar áreas rectangulares de forma interactiva en un formulario.
use Lbcdev\FilamentMapField\Forms\Components\MapBoundsField;
MapBoundsField::make('area')
->southWestLat('sw_lat')
->southWestLng('sw_lng')
->northEastLat('ne_lat')
->northEastLng('ne_lng');
MapBoundsField::make('area')
->southWestLat('sw_lat') // Campo para latitud suroeste
->southWestLng('sw_lng') // Campo para longitud suroeste
->northEastLat('ne_lat') // Campo para latitud noreste
->northEastLng('ne_lng') // Campo para longitud noreste
->height(500) // Altura del mapa en píxeles
->zoom(13) // Nivel de zoom inicial
->showLabel() // Mostrar etiqueta con coordenadas
->defaultCenter(40.4168, -3.7038); // Centro por defecto (Madrid)
// ✅ CORRECTO: make() usa el campo padre 'bounds'
MapBoundsField::make('bounds')
->southWestLat('bounds.sw_lat')
->southWestLng('bounds.sw_lng')
->northEastLat('bounds.ne_lat')
->northEastLng('bounds.ne_lng')
->height(500)
->zoom(13);
Nota: Al igual que con
MapField, cuando uses notación de punto, el primer parámetro demake()debe coincidir con el campo padre JSON. Ver la sección "⚠️ Importante: Uso con Notación de Punto" arriba para más detalles.
El componente MapBoundsEntry muestra áreas rectangulares en un mapa de solo lectura en infolists.
use Lbcdev\FilamentMapField\Infolists\Entries\MapBoundsEntry;
MapBoundsEntry::make('area')
->southWestLat('sw_lat')
->southWestLng('sw_lng')
->northEastLat('ne_lat')
->northEastLng('ne_lng');
MapBoundsEntry::make('area')
->southWestLat('sw_lat')
->southWestLng('sw_lng')
->northEastLat('ne_lat')
->northEastLng('ne_lng')
->height(400)
->zoom(13)
->showLabel();
| Método | Descripción | Default |
|---|---|---|
latitude(string $field) |
Campo donde se guardará la latitud. Soporta notación de punto para JSON: 'ubicacion.latitud' |
null |
longitude(string $field) |
Campo donde se guardará la longitud. Soporta notación de punto para JSON: 'ubicacion.longitud' |
null |
height(int $height) |
Altura del mapa en píxeles | 400 |
zoom(int $zoom) |
Nivel de zoom inicial (1-20) | 15 |
showPasteButton(bool $show = true) |
Mostrar botón para pegar coordenadas | false |
showLabel(bool $show = true) |
Mostrar etiqueta con coordenadas | true |
interactive(bool $interactive = true) |
Permitir interacción con el mapa | true |
readOnly(bool $condition = true) |
Hacer el mapa de solo lectura (alias de interactive(false)) |
false |
| Método | Descripción | Default |
|---|---|---|
latitude(string $field) |
Campo de donde leer la latitud. Soporta notación de punto para JSON: 'ubicacion.latitud' |
null |
longitude(string $field) |
Campo de donde leer la longitud. Soporta notación de punto para JSON: 'ubicacion.longitud' |
null |
height(int $height) |
Altura del mapa en píxeles | 300 |
zoom(int $zoom) |
Nivel de zoom inicial (1-20) | 15 |
showLabel(bool $show = true) |
Mostrar etiqueta con coordenadas | true |
| Método | Descripción | Default |
|---|---|---|
southWestLat(string $field) |
Campo para latitud suroeste. Soporta notación de punto: 'bounds.sw_lat' |
null |
southWestLng(string $field) |
Campo para longitud suroeste. Soporta notación de punto: 'bounds.sw_lng' |
null |
northEastLat(string $field) |
Campo para latitud noreste. Soporta notación de punto: 'bounds.ne_lat' |
null |
northEastLng(string $field) |
Campo para longitud noreste. Soporta notación de punto: 'bounds.ne_lng' |
null |
height(int $height) |
Altura del mapa en píxeles | 400 |
zoom(int $zoom) |
Nivel de zoom inicial (1-20) | 13 |
showLabel(bool $show = true) |
Mostrar etiqueta con coordenadas de los límites | true |
defaultCenter(float $lat, float $lng) |
Centro por defecto del mapa | [36.9990019, -6.5478919] |
| Método | Descripción | Default |
|---|---|---|
southWestLat(string $field) |
Campo de donde leer latitud suroeste. Soporta notación de punto: 'bounds.sw_lat' |
null |
southWestLng(string $field) |
Campo de donde leer longitud suroeste. Soporta notación de punto: 'bounds.sw_lng' |
null |
northEastLat(string $field) |
Campo de donde leer latitud noreste. Soporta notación de punto: 'bounds.ne_lat' |
null |
northEastLng(string $field) |
Campo de donde leer longitud noreste. Soporta notación de punto: 'bounds.ne_lng' |
null |
height(int $height) |
Altura del mapa en píxeles | 300 |
zoom(int $zoom) |
Nivel de zoom inicial (1-20) | 13 |
showLabel(bool $show = true) |
Mostrar etiqueta con coordenadas de los límites | true |
Los componentes MapField y MapBoundsField soportan el método ->required() de forma nativa. Cuando se marca un campo como requerido, automáticamente valida que todos los campos anidados (latitud, longitud, límites) tengan valores.
// Ejemplo 1: MapField con validación requerida
MapField::make('ubicacion')
->latitude('ubicacion.latitud')
->longitude('ubicacion.longitud')
->height(500)
->zoom(15)
->showPasteButton()
->required() // ✅ Valida que latitud y longitud tengan valores
->label('Ubicación'),
// Ejemplo 2: MapBoundsField con validación requerida
MapBoundsField::make('limites')
->southWestLat('limites.latitud_min')
->southWestLng('limites.longitud_min')
->northEastLat('limites.latitud_max')
->northEastLng('limites.longitud_max')
->height(500)
->zoom(13)
->required() // ✅ Valida que todos los límites tengan valores
->label('Límites del área'),
// Ejemplo 3: Validación con campos separados (modo tradicional)
Forms\Components\Grid::make(2)
->schema([
Forms\Components\TextInput::make('latitude')
->numeric()
->required()
->minValue(-90)
->maxValue(90)
->step(0.000001),
Forms\Components\TextInput::make('longitude')
->numeric()
->required()
->minValue(-180)
->maxValue(180)
->step(0.000001),
]),
MapField::make('map')
->latitude('latitude')
->longitude('longitude')
->height(600)
->zoom(12)
->showPasteButton()
->columnSpanFull(),
Nota: El método
->required()funciona tanto en modo Create como Edit. La validación se aplica automáticamente a los campos anidados configurados con notación de punto.
Forms\Components\Tabs::make('Locations')
->tabs([
Forms\Components\Tabs\Tab::make('Origen')
->schema([
Forms\Components\Grid::make(2)
->schema([
Forms\Components\TextInput::make('origin_latitude')
->numeric()
->required(),
Forms\Components\TextInput::make('origin_longitude')
->numeric()
->required(),
]),
MapField::make('origin_map')
->latitude('origin_latitude')
->longitude('origin_longitude')
->height(400)
->showPasteButton(),
]),
Forms\Components\Tabs\Tab::make('Destino')
->schema([
Forms\Components\Grid::make(2)
->schema([
Forms\Components\TextInput::make('destination_latitude')
->numeric()
->required(),
Forms\Components\TextInput::make('destination_longitude')
->numeric()
->required(),
]),
MapField::make('destination_map')
->latitude('destination_latitude')
->longitude('destination_longitude')
->height(400)
->showPasteButton(),
]),
]),
El paquete soporta guardar coordenadas en campos JSON anidados usando notación de punto. Esto es útil cuando quieres almacenar las coordenadas en una estructura JSON en lugar de campos separados.
// Migración
Schema::create('locations', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('latitude', 10, 8)->nullable();
$table->decimal('longitude', 11, 8)->nullable();
});
// Formulario
MapField::make('map')
->latitude('latitude')
->longitude('longitude');
// Resultado en BD:
// latitude: 40.416775
// longitude: -3.703790
// Migración
Schema::create('locations', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->json('ubicacion')->nullable();
});
// Modelo
class Location extends Model
{
protected $casts = [
'ubicacion' => 'array',
];
}
// Formulario
MapField::make('ubicacion')
->latitude('ubicacion.latitud')
->longitude('ubicacion.longitud')
->height(500)
->zoom(15)
->showPasteButton();
// Resultado en BD (campo JSON):
// ubicacion: {"latitud": "40.416775", "longitud": "-3.703790"}
<?php
namespace App\Filament\Resources;
use App\Models\Store;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Lbcdev\FilamentMapField\Forms\Components\MapField;
class StoreResource extends Resource
{
protected static ?string $model = Store::class;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\TextInput::make('address')
->maxLength(255),
MapField::make('ubicacion')
->label('Ubicación en el mapa')
->latitude('ubicacion.latitud')
->longitude('ubicacion.longitud')
->height(500)
->zoom(15)
->showPasteButton()
->columnSpanFull(),
]);
}
}
php artisan vendor:publish --tag=filament-map-field-views
Las vistas estarán disponibles en:
resources/views/vendor/filament-map-field/forms/components/map-field.blade.phpresources/views/vendor/filament-map-field/infolists/entries/map-entry.blade.phpEste paquete es totalmente compatible con Filament v3 y v4 sin necesidad de cambios en tu código.
Si estás actualizando tu proyecto de Filament v3 a v4:
Actualiza Filament siguiendo la guía oficial de actualización
Actualiza las dependencias:
composer update
¡Listo! El paquete filament-map-field seguirá funcionando sin cambios
No necesitas:
MapField o MapEntrySi usas un tema personalizado en Filament, necesitarás actualizar Tailwind CSS de v3 a v4 al migrar a Filament v4. Esto es un requisito de Filament, no de este paquete específicamente.
Consulta la guía de actualización de Tailwind CSS v4 para más detalles.
Para actualizar el paquete a una versión específica usando tags de GitHub:
# Actualizar a la última versión
composer update lbcdev/filament-map-field
# O instalar una versión específica por tag
composer require lbcdev/filament-map-field:1.0.0
Puedes especificar la versión exacta en tu composer.json:
{
"require": {
"lbcdev/filament-map-field": "^1.0"
}
}
O usar un tag específico:
{
"require": {
"lbcdev/filament-map-field": "1.0.0"
}
}
composer show lbcdev/filament-map-field
Después de actualizar, es recomendable limpiar las cachés:
php artisan filament:cache-components
php artisan view:clear
php artisan cache:clear
Si encuentras problemas al usar el paquete, consulta la Guía de Solución de Problemas que incluye:
Este paquete utiliza:
Este paquete es software de código abierto licenciado bajo la Licencia MIT.
Si encuentras algún problema o tienes sugerencias:
Desarrollado por Luinux81
How can I help you explore Laravel packages today?