Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Pinpoint Laravel Package

fahiem/filament-pinpoint

Filament Pinpoint adds a location picker for Filament 4/5 with Google Maps or free Leaflet/OpenStreetMap. Includes search/autocomplete, click-to-set and draggable marker, current location, radius editing, reverse geocoding to fill address fields, dark mode, and translations.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the package**:
   ```bash
   composer require fahiem/filament-pinpoint
  1. Configure provider (.env):
    PINPOINT_PROVIDER=google  # or 'leaflet'
    GOOGLE_MAPS_API_KEY=your_api_key_here  # Required for Google Maps
    
  2. Basic usage in a Filament form:
    use Fahiem\FilamentPinpoint\Pinpoint;
    
    Pinpoint::make('location')
        ->latField('lat')
        ->lngField('lng')
    

First Use Case: Adding a Location Field

For a Location model with lat and lng fields:

public static function form(Form $form): Form
{
    return $form->schema([
        Pinpoint::make('location')
            ->label('Business Address')
            ->latField('lat')
            ->lngField('lng')
            ->searchable()
            ->draggable(),
        TextInput::make('lat')->readOnly(),
        TextInput::make('lng')->readOnly(),
    ]);
}

Key first steps:

  • Choose provider (Google/Leaflet) via .env
  • Map latField()/lngField() to your model fields
  • Add read-only fields for debugging (optional but recommended)

Implementation Patterns

Common Workflows

1. Form Integration with Address Auto-Fill

Pinpoint::make('location')
    ->latField('lat')
    ->lngField('lng')
    ->addressField('full_address')
    ->streetField('street')
    ->cityField('city')
    ->countryField('country')
    ->columnSpanFull();

Pattern: Chain address-related fields to auto-populate from geocoding.

2. Repeater with Multiple Locations

Repeater::make('stores')
    ->schema([
        Pinpoint::make('store_location')
            ->latField('latitude')
            ->lngField('longitude')
            ->addressField('address')
            ->height(300),
        TextInput::make('store_name'),
    ])
    ->columns(2);

Pattern: Use Repeater for dynamic location collections (e.g., store chains).

3. Infolist Display

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

Pattern: Use PinpointEntry for read-only displays in resource views.

4. Radius-Based Search

Pinpoint::make('search_area')
    ->latField('center_lat')
    ->lngField('center_lng')
    ->radiusField('radius_meters')
    ->defaultRadius(1000)
    ->height(500);

Pattern: Combine with a whereRaw query in your query scope:

->whereRaw("ST_DWithin(
    ST_MakePoint(lng, lat),
    ST_MakePoint({$centerLng}, {$centerLat}),
    {$radius}
)")

Integration Tips

  1. Validation Rules: Add to your model:

    protected static function rules(): array
    {
        return [
            'lat' => 'required|numeric|between:-90,90',
            'lng' => 'required|numeric|between:-180,180',
        ];
    }
    
  2. Database Storage: Use decimal(10,8) for lat/lng fields to preserve precision.

  3. Caching API Keys: Store GOOGLE_MAPS_API_KEY in Laravel's .env or use config('services.google_maps.key').

  4. Leaflet Optimization: For high-traffic apps, preload Leaflet tiles or use a CDN for LEAFLET_TILE_URL.

  5. Dark Mode: Leaflet's dark mode works out-of-the-box. For Google Maps, ensure your API key has dark mode support.


Gotchas and Tips

Pitfalls

  1. Google Maps API Quotas:

    • Free tier has $200 monthly credit and 40,000 daily requests.
    • Monitor usage in Google Cloud Console.
    • Fix: Use Leaflet for non-critical locations or implement caching.
  2. Reverse Geocoding Delays:

    • Google's geocoding API has rate limits (50 requests/sec).
    • Fix: Debounce user input or use Leaflet's Nominatim (slower but free).
  3. Leaflet Performance:

    • OpenStreetMap tiles may lag at high zoom levels.
    • Fix: Limit zoom range or use a tile provider like https://{s}.tile.openstreetmap.fr/.
  4. Repeater Field Paths:

    • Nested Repeater paths (e.g., data.items.0.location.lat) can break if not handled.
    • Fix: Use ->getRecord() in custom logic to access nested data.
  5. Dark Mode Inconsistencies:

    • Google Maps dark mode may not match Filament's theme.
    • Fix: Override CSS or use Leaflet for consistency.

Debugging Tips

  1. API Key Errors:

    • Check browser console for Google Maps API error: RefererNotAllowed.
    • Fix: Restrict API key referrers in Google Cloud Console to your domain.
  2. Marker Not Showing:

    • Verify latField/lngField values are valid (e.g., -6.200000, 106.816666).
    • Fix: Add ->defaultLocation() as fallback.
  3. Search Not Working:

    • For Leaflet, ensure NOMINATIM_URL is accessible (Nominatim may block bots).
    • Fix: Use a custom Nominatim instance or fall back to Google.
  4. Radius Circle Missing:

    • Ensure radiusField is configured and the field exists in the model.
    • Fix: Add ->defaultRadius(500) for testing.

Extension Points

  1. Custom Geocoding Logic: Override reverse geocoding by extending the component:

    use Fahiem\FilamentPinpoint\Pinpoint;
    
    class CustomPinpoint extends Pinpoint
    {
        protected function getAddressFromCoordinates(): string
        {
            // Custom logic (e.g., call a local geocoding service)
            return 'Custom Address';
        }
    }
    
  2. Marker Icons: Dynamically set icons based on record data:

    Pinpoint::make('location')
        ->latField('lat')
        ->lngField('lng')
        ->iconField('icon_type') // Field with 'restaurant', 'store', etc.
        ->iconMap([
            'restaurant' => 'https://example.com/restaurant-marker.png',
            'store' => 'https://example.com/store-marker.png',
        ]);
    
  3. Event Listeners: Listen for marker changes:

    Pinpoint::make('location')
        ->listen('marker-moved', function (array $data) {
            // $data['lat'], $data['lng'], $data['address']
            Log::info('Marker moved to:', $data);
        });
    
  4. Custom Providers: Add support for Mapbox or other providers by extending the base class and publishing a new config.

  5. Localization: Extend translations for multi-language support:

    // config/filament-pinpoint.php
    'translations' => [
        'nl' => [
            'search_placeholder' => 'Zoek naar een locatie...',
        ],
    ];
    

Configuration Quirks

  1. Environment Overrides: Per-field provider settings override global .env:

    Pinpoint::make('location')->provider('leaflet'); // Overrides global setting
    
  2. Default Values:

    • defaultLocation() uses Jakarta coordinates by default (-6.200000, 106.816666).
    • Set globally via .env:
      GOOGLE_MAPS_DEFAULT_LAT=-33.8688
      GOOGLE_MAPS_DEFAULT_LNG=151.2093
      
  3. Height Units: height() accepts pixels (e.g., 400) or percentages (e.g., 50%), but percentages may not work in all Filament layouts.

  4. Radius Units: Always use meters for radiusField() and defaultRadius().

  5. Dark Mode: Leaflet's dark mode requires LEAFLET_TILE_URL_DARK to be set in .env for full compatibility.

Performance Tips

  1. Lazy Loading: For large repeaters, lazy-load maps:
    Pinpoint::make('location')
        ->height(0) // Hide initially
        ->listen('
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle