fahiem/filament-pinpoint
Composer 安装命令:
composer require fahiem/filament-pinpoint
包简介
Google Maps location picker component for Filament 4 & 5 with search, draggable marker, and reverse geocoding
关键字:
README 文档
README
📍 A location picker component for Filament 4 & 5 supporting Google Maps and Leaflet.js (OpenStreetMap) — with search, draggable marker, and reverse geocoding support.
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, ES
- ⚙️ Fully configurable — Customize height, zoom, default location, and more
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
Install the package via Composer:
composer require fahiem/filament-pinpoint
Configuration
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
Required only when using provider = google:
GOOGLE_MAPS_API_KEY=your_api_key_here
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)
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
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)
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
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
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
Pinpoint::make('location') ->draggable(false) // Disable marker dragging ->searchable(false) // Hide search box
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.latitudefor the first item).
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
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)
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
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) |
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' => '<div style="padding: 10px;"><strong>Warehouse A</strong><br>Open 24/7</div>', // Custom HTML ], ]) ->columnSpanFull()
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
Pinpoint (Form Field)
| Method | Description | Default |
|---|---|---|
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)
| Method | Description | Default |
|---|---|---|
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 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 |
Getting a Google Maps API Key (Google provider only)
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the following APIs:
- Maps JavaScript API
- Places API
- Geocoding API
- Go to Credentials and create an API key
- (Recommended) Restrict your API key to specific domains
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
This package supports multiple languages out of the box:
| Language | Code |
|---|---|
| English | en |
| Arabic | ar |
| Dutch | nl |
| Indonesian | id |
| Spanish | es |
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
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...', ];
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security-related issues, please email amfahiem010502@gmail.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
fahiem/filament-pinpoint 适用场景与选型建议
fahiem/filament-pinpoint 是一款 基于 Blade 开发的 Composer 扩展包,目前已累计 20.82k 次下载、GitHub Stars 达 18, 最近一次更新时间为 2025 年 12 月 01 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「geocoding」 「google-maps」 「maps」 「laravel」 「location-picker」 「pinpoint」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 fahiem/filament-pinpoint 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 fahiem/filament-pinpoint 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 fahiem/filament-pinpoint 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Maps in minutes. Powered by the Google Maps API.
A Laravel Nova Google Maps Field.
Yii2 map input widget. Allows you to select geographcal coordinates via a human-friendly inteface.
GISCO Geocoding Provider for Geocoder PHP.
Harness the power of the Google Autocomplete API inside Craft. Adds an autocomplete search box to Craft entries.
Laravel package that helps to use GoogleMaps
统计信息
- 总下载量: 20.82k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 18
- 点击次数: 29
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-01

