PHPackages                             fahiem/filament-pinpoint - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. fahiem/filament-pinpoint

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

fahiem/filament-pinpoint
========================

Google Maps location picker component for Filament 4 &amp; 5 with search, draggable marker, and reverse geocoding

v1.1.5(3mo ago)136.5k↓15%10MITBladePHP ^8.1

Since Dec 1Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/fahiem152/filament-pinpoint)[ Packagist](https://packagist.org/packages/fahiem/filament-pinpoint)[ Docs](https://github.com/fahiem152/filament-pinpoint)[ RSS](/packages/fahiem-filament-pinpoint/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (9)Dependencies (4)Versions (11)Used By (0)

Filament Pinpoint
=================

[](#filament-pinpoint)

[![Latest Version on Packagist](https://camo.githubusercontent.com/8b94c7740cabe0ec502cbef75e4cf92f21b4c2bc471e06bcab77a4e78ff8ae90/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f66616869656d2f66696c616d656e742d70696e706f696e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/fahiem/filament-pinpoint)[![Total Downloads](https://camo.githubusercontent.com/4110be227cde8fe8fa9bb0ea0f2dd575ef596871e17b559d73a855d7ccc99585/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f66616869656d2f66696c616d656e742d70696e706f696e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/fahiem/filament-pinpoint)[![License](https://camo.githubusercontent.com/8f930da98bb2d507a0e33f3e744239a949a29babe035cea9cdcabf31443f485c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f66616869656d2f66696c616d656e742d70696e706f696e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/fahiem/filament-pinpoint)

📍 A location picker component for **Filament 4 &amp; 5** supporting **Google Maps** and **Leaflet.js (OpenStreetMap)** — with search, draggable marker, and reverse geocoding support.

[![Screenshot](https://raw.githubusercontent.com/fahiem152/filament-pinpoint/main/images/screenshot-3.png)](https://raw.githubusercontent.com/fahiem152/filament-pinpoint/main/images/screenshot-3.png)

[![Infolist View](https://raw.githubusercontent.com/fahiem152/filament-pinpoint/main/images/screenshot-3-viewer.png)](https://raw.githubusercontent.com/fahiem152/filament-pinpoint/main/images/screenshot-3-viewer.png)

Features
--------

[](#features)

- 🗺️ **Two map providers** — Google Maps (default) or Leaflet.js / OpenStreetMap (free, no API key)
- 🔍 **Search location** — Google Places Autocomplete (Google) or Nominatim (Leaflet)
- 📍 **Click to set marker** — Click anywhere on the map to place a marker
- ✋ **Draggable marker** — Drag the marker to fine-tune the location
- 📱 **Current location** — Get user's current device location
- ⭕ **Radius support** — Display and edit radius around the location
- 🏠 **Reverse geocoding** — Auto-fill address fields from coordinates
- 🌙 **Dark mode support** — Fully compatible with Filament's dark mode
- 🌐 **Multi-language support** — Translations for EN, AR, NL, ID
- ⚙️ **Fully configurable** — Customize height, zoom, default location, and more

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10+ / 11+ / 12+
- Filament 4.0+ / 5.0+
- **Google Maps provider** (default): API Key with Maps JavaScript API, Places API, and Geocoding API enabled
- **Leaflet provider**: No API key required

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require fahiem/filament-pinpoint
```

Configuration
-------------

[](#configuration)

### 1. Choose a map provider

[](#1-choose-a-map-provider)

The default provider is **Google Maps**. To use **Leaflet.js (OpenStreetMap)** instead, set in your `.env`:

```
PINPOINT_PROVIDER=leaflet
```

You can also override the provider per field instance:

```
Pinpoint::make('location')->provider('leaflet')
```

### 2. Google Maps — set your API Key

[](#2-google-maps--set-your-api-key)

Required only when using `provider = google`:

```
GOOGLE_MAPS_API_KEY=your_api_key_here
```

### 3. Leaflet — optional configuration

[](#3-leaflet--optional-configuration)

Leaflet works out of the box with OpenStreetMap tiles. Optionally customize:

```
# Custom tile server (default: OpenStreetMap)
LEAFLET_TILE_URL=https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png

# Optional dark mode tile URL (e.g. CartoDB Dark)
LEAFLET_TILE_URL_DARK=https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png

# Nominatim base URL for search & reverse geocoding (default: nominatim.openstreetmap.org)
NOMINATIM_URL=https://nominatim.openstreetmap.org
```

### 4. Publish the config file (optional)

[](#4-publish-the-config-file-optional)

```
php artisan vendor:publish --tag="filament-pinpoint-config"
```

You can also set default map values via environment variables:

```
GOOGLE_MAPS_DEFAULT_LAT=-6.200000
GOOGLE_MAPS_DEFAULT_LNG=106.816666
GOOGLE_MAPS_DEFAULT_ZOOM=15
GOOGLE_MAPS_DEFAULT_HEIGHT=500
```

Usage
-----

[](#usage)

### Basic Usage (Google Maps)

[](#basic-usage-google-maps)

```
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(),
        ]);
}
```

### Using Leaflet (Free / No API Key)

[](#using-leaflet-free--no-api-key)

Set the provider globally via `.env`:

```
PINPOINT_PROVIDER=leaflet
```

Or per field instance:

```
Pinpoint::make('location')
    ->provider('leaflet')
    ->latField('lat')
    ->lngField('lng')
    ->addressField('address')
    ->draggable()
    ->searchable()
```

Same API, same methods — Leaflet uses **OpenStreetMap tiles** and **Nominatim** for search and reverse geocoding. No API key needed.

For `PinpointEntry` (infolist):

```
PinpointEntry::make('location')
    ->provider('leaflet')
    ->latField('lat')
    ->lngField('lng')
    ->columnSpanFull()
```

### Full Example with All Options

[](#full-example-with-all-options)

```
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()
```

### Radius Support

[](#radius-support)

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:

- **Resize the radius** by dragging the small white handle on the circle's edge
- **View the radius** visually on the map
- The radius value (in meters) is automatically saved to your database field in real-time
- The circle uses proper z-index layering so the marker always appears on top

**Visual hierarchy:**

- Marker (pin): zIndex 200 - always on top
- Circle (radius): zIndex 100 - below the marker

### Disable Features

[](#disable-features)

```
Pinpoint::make('location')
    ->draggable(false)  // Disable marker dragging
    ->searchable(false) // Hide search box
```

### Using with Repeater

[](#using-with-repeater)

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.latitude` for the first item).

### Infolist Entry (Read-Only Display)

[](#infolist-entry-read-only-display)

For displaying locations in infolists (view mode), use the `PinpointEntry` component. It displays a clean, read-only map with a marker at the specified coordinates.

#### Single Marker

[](#single-marker)

```
use Fahiem\FilamentPinpoint\PinpointEntry;

public static function infolist(Infolist $infolist): Infolist
{
    return $infolist
        ->schema([
            PinpointEntry::make('location')
                ->label('Location')
                ->latField('lat')
                ->lngField('lng')
                ->columnSpanFull(),
        ]);
}
```

#### Multiple Markers (New in v1.1.3)

[](#multiple-markers-new-in-v113)

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()
```

#### Pin Customization Options

[](#pin-customization-options)

Each pin in the `pins()` array supports:

OptionTypeDescription`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)#### Custom Marker Icons

[](#custom-marker-icons)

```
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' => 'Warehouse AOpen 24/7', // Custom HTML
        ],
    ])
    ->columnSpanFull()
```

#### Customization Options

[](#customization-options)

```
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:

- A read-only map (Google Maps or Leaflet) with single or multiple markers
- Optional info windows / popups with labels or custom HTML content
- Auto-fit bounds to display all markers
- Full dark mode support

Available Methods
-----------------

[](#available-methods)

### Pinpoint (Form Field)

[](#pinpoint-form-field)

MethodDescriptionDefault`provider(string $provider)`Map provider: `'google'` or `'leaflet'`config value`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`### PinpointEntry (Infolist Entry)

[](#pinpointentry-infolist-entry)

MethodDescriptionDefault`provider(string $provider)`Map provider: `'google'` or `'leaflet'`config value`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 recordReturns field value or default`getLng()`Get longitude from recordReturns field value or default`getPins()`Get pins arrayReturns pins or null`hasPins()`Check if pins are setReturns booleanGetting a Google Maps API Key (Google provider only)
----------------------------------------------------

[](#getting-a-google-maps-api-key-google-provider-only)

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the following APIs:
    - Maps JavaScript API
    - Places API
    - Geocoding API
4. Go to **Credentials** and create an API key
5. (Recommended) Restrict your API key to specific domains

Database Migration
------------------

[](#database-migration)

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();
});
```

Translations
------------

[](#translations)

This package supports multiple languages out of the box:

LanguageCodeEnglish`en`Arabic`ar`Dutch`nl`Indonesian`id`### Publishing Translations

[](#publishing-translations)

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/`.

### Adding New Languages

[](#adding-new-languages)

Create a new folder in `lang/vendor/filament-pinpoint/{locale}/` with a `pinpoint.php` file:

```
