| Install | |
|---|---|
composer require fahiem/filament-pinpoint |
|
| Latest Version: | v1.1.5 |
| PHP: | ^8.1 |
📍 A Google Maps location picker component for Filament 4 & 5 with search, draggable marker, and reverse geocoding support.


Install the package via Composer:
composer require fahiem/filament-pinpoint
Add your Google Maps API key to your .env file:
GOOGLE_MAPS_API_KEY=your_api_key_here
php artisan vendor:publish --tag="filament-pinpoint-config"
This will publish the config file to config/filament-pinpoint.php:
return [
'api_key' => env('GOOGLE_MAPS_API_KEY'),
'default' => [
'lat' => env('GOOGLE_MAPS_DEFAULT_LAT', -0.5050),
'lng' => env('GOOGLE_MAPS_DEFAULT_LNG', 117.1500),
'zoom' => env('GOOGLE_MAPS_DEFAULT_ZOOM', 13),
'height' => env('GOOGLE_MAPS_DEFAULT_HEIGHT', 400),
],
];
You can also set default values via environment variables:
GOOGLE_MAPS_API_KEY=your_api_key_here
GOOGLE_MAPS_DEFAULT_LAT=-6.200000
GOOGLE_MAPS_DEFAULT_LNG=106.816666
GOOGLE_MAPS_DEFAULT_ZOOM=15
GOOGLE_MAPS_DEFAULT_HEIGHT=500
use Fahiem\FilamentPinpoint\Pinpoint;
public static function form(Form $form): Form
{
return $form
->schema([
Pinpoint::make('location')
->label('Location')
->latField('lat')
->lngField('lng'),
TextInput::make('lat')
->label('Latitude')
->readOnly(),
TextInput::make('lng')
->label('Longitude')
->readOnly(),
]);
}
use Fahiem\FilamentPinpoint\Pinpoint;
Pinpoint::make('location')
->label('Business Location')
->defaultLocation(-6.200000, 106.816666) // Jakarta
->defaultZoom(15)
->height(400)
->draggable()
->searchable()
->latField('lat')
->lngField('lng')
->addressField('address') // Auto-fill address field
->shortAddressField('short_address') // Auto-fill short address field (exclude province, city, district, village, and postal code)
->provinceField('province') // Auto-fill province field
->cityField('city') // Auto-fill city/county field
->districtField('district') // Auto-fill district field
->villageField('village') // Auto-fill village/district field
->postalCodeField('postal_code') // Auto-fill postal/zip code field
->countryField('country') // Auto-fill country field
->streetField('street') // Auto-fill street field
->streetNumberField('street_number') // Auto-fill street number field
->columnSpanFull()
You can enable radius support by using radiusField():
Pinpoint::make('location')
->radiusField('radius') // 'radius' is the column name in your database
->defaultRadius(500) // Default 500 meters
When radiusField is configured, an interactive blue circle will appear on the map. You can:
Visual hierarchy:
Pinpoint::make('location')
->draggable(false) // Disable marker dragging
->searchable(false) // Hide search box
Pinpoint fully supports Filament's Repeater component. Each repeater item gets its own independent map and fields:
use Fahiem\FilamentPinpoint\Pinpoint;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
Repeater::make('branches')
->schema([
TextInput::make('branch_name')
->label('Branch Name')
->required(),
Pinpoint::make('location')
->label('Location')
->latField('latitude')
->lngField('longitude')
->addressField('address')
->draggable()
->searchable()
->height(300),
TextInput::make('latitude')
->label('Latitude')
->readOnly(),
TextInput::make('longitude')
->label('Longitude')
->readOnly(),
TextInput::make('address')
->label('Address')
->readOnly()
->columnSpanFull(),
])
->columns(2)
->columnSpanFull()
Note: When using with Repeater, the field paths are automatically calculated (e.g.,
data.branches.0.latitudefor the first item).
For displaying locations in infolists (view mode), use the PinpointEntry component. It displays a clean, read-only Google Map with a marker at the specified coordinates.
use Fahiem\FilamentPinpoint\PinpointEntry;
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
PinpointEntry::make('location')
->label('Location')
->latField('lat')
->lngField('lng')
->columnSpanFull(),
]);
}
Display multiple locations on a single map:
PinpointEntry::make('branches')
->label('Branch Locations')
->pins([
[
'lat' => -6.200000,
'lng' => 106.816666,
'label' => 'Jakarta Office',
'color' => 'red',
],
[
'lat' => -6.914744,
'lng' => 107.609810,
'label' => 'Bandung Office',
'color' => 'blue',
],
[
'lat' => -7.797068,
'lng' => 110.370529,
'label' => 'Yogyakarta Office',
'color' => 'green',
],
])
->fitBounds() // Auto-zoom to show all markers
->height(500)
->columnSpanFull()
Each pin in the pins() array supports:
| Option | Type | Description |
|---|---|---|
lat |
float |
Required. Latitude coordinate |
lng |
float |
Required. Longitude coordinate |
label |
string |
Optional. Marker title (shows on hover and in info window) |
color |
string |
Optional. Predefined color: red, blue, green, yellow, purple, pink, orange, ltblue |
icon |
string |
Optional. Custom marker icon URL (overrides color) |
info |
string |
Optional. Custom HTML content for info window (overrides default label) |
PinpointEntry::make('locations')
->pins([
[
'lat' => -6.200000,
'lng' => 106.816666,
'label' => 'Main Office',
'icon' => 'https://example.com/custom-marker.png', // Custom icon URL
],
[
'lat' => -6.914744,
'lng' => 107.609810,
'label' => 'Warehouse',
'info' => '<div style="padding: 10px;"><strong>Warehouse A</strong><br>Open 24/7</div>', // Custom HTML
],
])
->columnSpanFull()
PinpointEntry::make('location')
->label('Business Location')
->defaultLocation(-6.200000, 106.816666) // Jakarta
->defaultZoom(15)
->height(400)
->latField('lat')
->lngField('lng')
->fitBounds(false) // Disable auto-fit bounds
->columnSpanFull()
The PinpointEntry displays:
| Method | Description | Default |
|---|---|---|
defaultLocation(float $lat, float $lng) |
Set default center location | -0.5050, 117.1500 |
defaultZoom(int $zoom) |
Set default zoom level | 13 |
height(int $height) |
Set map height in pixels | 400 |
latField(string $field) |
Field name for latitude | 'lat' |
lngField(string $field) |
Field name for longitude | 'lng' |
addressField(string $field) |
Field name for auto-fill address | null |
shortAddressField(string $field) |
Field name for auto-fill short address | null |
provinceField(string $field) |
Field name for auto-fill province | null |
cityField(string $field) |
Field name for auto-fill city/county | null |
districtField(string $field) |
Field name for auto-fill district | null |
villageField(string $field) |
Field name for auto-fill village/sub-district | null |
postalCodeField(string $field) |
Field name for auto-fill postal/zip code | null |
countryField(string $field) |
Field name for auto-fill country | null |
streetField(string $field) |
Field name for auto-fill street | null |
streetNumberField(string $field) |
Field name for auto-fill street number | null |
radiusField(string $field) |
Field name for auto-fill radius | null |
defaultRadius(int $radius) |
Set default radius in meters | 500 |
draggable(bool $draggable) |
Enable/disable marker dragging | true |
searchable(bool $searchable) |
Enable/disable search box | true |
| Method | Description | Default |
|---|---|---|
defaultLocation(float $lat, float $lng) |
Set default center location | -0.5050, 117.1500 |
defaultZoom(int $zoom) |
Set default zoom level | 13 |
height(int $height) |
Set map height in pixels | 400 |
latField(string $field) |
Field name for latitude | 'lat' |
lngField(string $field) |
Field name for longitude | 'lng' |
radiusField(string $field) |
Field name for radius | null |
pins(array $pins) |
Set array of multiple markers with lat, lng, label, color, icon, info | null |
fitBounds(bool $fit) |
Auto-zoom map to show all markers | true |
getLat() |
Get latitude from record | Returns field value or default |
getLng() |
Get longitude from record | Returns field value or default |
getPins() |
Get pins array | Returns pins or null |
hasPins() |
Check if pins are set | Returns boolean |
Make sure your table has columns for latitude and longitude:
Schema::create('locations', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('lat', 10, 7)->nullable();
$table->decimal('lng', 10, 7)->nullable();
$table->text('address')->nullable();
$table->text('short_address')->nullable();
$table->string('province')->nullable();
$table->string('city')->nullable();
$table->string('district')->nullable();
$table->string('village')->nullable();
$table->string('postal_code')->nullable();
$table->string('country')->nullable();
$table->string('street')->nullable();
$table->string('street_number')->nullable();
$table->timestamps();
});
This package supports multiple languages out of the box:
| Language | Code |
|---|---|
| English | en |
| Arabic | ar |
| Dutch | nl |
| Indonesian | id |
To customize the translations, publish them to your application:
php artisan vendor:publish --tag="filament-pinpoint-translations"
This will publish the translation files to lang/vendor/filament-pinpoint/.
Create a new folder in lang/vendor/filament-pinpoint/{locale}/ with a pinpoint.php file:
<?php
return [
'search' => 'Your translation...',
'use_my_location' => 'Your translation...',
'instructions' => 'Your translation...',
'loading_map' => 'Your translation...',
];
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security-related issues, please email amfahiem010502@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.