PHP code example of cheesegrits / filament-google-maps

1. Go to this page and download the library: Download cheesegrits/filament-google-maps library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

cheesegrits / filament-google-maps example snippets


use Cheesegrits\FilamentGoogleMaps\Fields\Map
...
->schema[
    ...
    // must use the computed attribute name you used on your model
    // which must NOT exist on the table itself
    Map::make('location'),
    ...
]

GOOGLE_MAPS_API_KEY=your_map_key_here


return [
	/*
	 | Your Google Maps API key, usually set in .env (but see 'keys' section below).
	 */

    'key' => env('GOOGLE_MAPS_API_KEY'),

	/*
	 | If you need to use both a browser key (restricted by HTTP Referrer) for use in the Javascript API on the
	 | front end, and a server key (restricted by IP address) for server side API calls, you will need to set those
	 | keys here (or preferably set the appropriate .env variables)
	 */

	'keys' => [
		'web_key' => env('FILAMENT_GOOGLE_MAPS_WEB_API_KEY', env('GOOGLE_MAPS_API_KEY')),
		'server_key' => env('FILAMENT_GOOGLE_MAPS_SERVER_API_KEY', env('GOOGLE_MAPS_API_KEY')),
	    'signing_key' => env('FILAMENT_GOOGLE_MAPS_SIGNING_KEY', null),
	],
	
	/*
	 | By default the browser side Google Maps API will be loaded with just the 'places' library.  If you need
	 | additional libraries for your own custom code, just add them as a comma separated list here (or in the
	 | appropriate env key) 
	 */
	
	'libraries' => env('FILAMENT_GOOGLE_MAPS_ADDITIONAL_LIBRARIES', null),
	
	/*
	 | Region and country codes.
	 |
	 | Google STRONGLY ENCOURAGED you to set a region code (US, GB, etc) which they use to bias the results
	 |
	 | https://developers.google.com/maps/coverage
	 |
	 | Google discourage you from setting a language, as this should be controlled by the user's browser setting,
	 | and only controls localization of the UI.  So we do not apply a language code to the Javascript API.  However,
	 | we will apply any language code set here to server side API calls like static maps (as used in the Column).
	 |
	 | https://developers.google.com/maps/faq#languagesupport
	 */
	 
	'locale' => [
		'region' => env('FILAMENT_GOOGLE_MAPS_REGION_CODE', null),
		'language' => env('FILAMENT_GOOGLE_MAPS_LANGUAGE_CODE', null),
	],

	/*
	 | Rate limit for API calls, although you REALLY should also set usage quota limits in your Google Console
	 */

	'rate-limit' => env('FILAMENT_GOOGLE_MAPS_RATE_LIMIT', 150),

	/*
	 | Log channel to use, default is 'null' (no logging), set to your desired channel from logging.php if you want
	 | logs.  Typically only useful for debugging, or if you want to keep track of a scheduled geocoding task.
	 */
	'log' => [
		'channel' => env('FILAMENT_GOOGLE_MAPS_LOG_CHANNEL', 'null'),
	],

	/*
	 | Cache store and duration (in seconds) to use for API results.  Specify store as null to use the default from
	 | your cache.php config, false will disable caching (STRONGLY discouraged, unless you want a big Google
	 | API bill!).  For heavy usage, we suggest using a dedicated Redis store.  Max cache duration permitted by
	 | Google is 30 days.
	 */

	'cache' => [
		'duration' => env('FILAMENT_GOOGLE_MAPS_CACHE_DURATION_SECONDS', 60 * 60 * 24 * 30),
		'store' => env('FILAMENT_GOOGLE_MAPS_CACHE_STORE', null),
	]
	
	 /*
     | Force https for Google API calls, rather than matching the schema of the current request,
	 | may be needed if your app is behind a reverse proxy.
     */

    'force-https' => env('FILAMENT_GOOGLE_MAPS_FORCE_HTTPS', false),
];

use Cheesegrits\FilamentGoogleMaps\Fields\Map
...
->schema[
    ...
    Map::make('location'),
    ...
]

use Cheesegrits\FilamentGoogleMaps\Fields\Map

...

    Map::make('location')
    ->mapControls([
        'mapTypeControl'    => true,
        'scaleControl'      => true,
        'streetViewControl' => true,
        'rotateControl'     => true,
        'fullscreenControl' => true,
        'searchBoxControl'  => false, // creates geocomplete field inside map
        'zoomControl'       => false,
    ])
    ->height(fn () => '400px') // map height (width is controlled by Filament options)
    ->defaultZoom(5) // default zoom level when opening form
    ->autocomplete('full_address') // field on form to use as Places geocompletion field
    ->autocompleteReverse(true) // reverse geocode marker location to autocomplete field
    ->reverseGeocode([
        'street' => '%n %S',
        'city' => '%L',
        'state' => '%A1',
        'zip' => '%z',
    ]) // reverse geocode marker location to form fields, see notes below
    ->debug() // prints reverse geocode format strings to the debug console 
    ->defaultLocation([39.526610, -107.727261]) // default for new forms
    ->draggable() // allow dragging to move marker
    ->clickable(false) // allow clicking to move marker
    ->geolocate() // adds a button to request device location and set map marker accordingly
    ->geolocateLabel('Get Location') // overrides the default label for geolocate button
    ->geolocateOnLoad(true, false) // geolocate on load, second arg 'always' (default false, only for new form))
    ->layers([
        'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml',
    ]) // array of KML layer URLs to add to the map
    ->geoJson('https://fgm.test/storage/AGEBS01.geojson') // GeoJSON file, URL or JSON
    ->geoJsonContainsField('geojson') // field to capture GeoJSON polygon(s) which contain the map marker


Map::make('location')
    ->autocomplete(
        fieldName: 'airport_name',
        types: ['airport'],
        placeField: 'name',
        countries: ['US', 'CA', 'MX'],
    )

    Map::make('location')
    //
        ->geoJson('jsons/MyGeoJson.geojson', 'json-disk')
    // ... or ...
        ->geoJson('https://my.site/jsons/MyGeoJson.geojson')
    // ... or ...
        ->geoJson(function () { 
            // code that builds and returns raw GeoJSON
            return $json;
        })

    Map::make('location')
        ->geoJson(function () { 
            return <<<EOT
{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [100.0, 0.0],
                    [101.0, 0.0],
                    [101.0, 1.0],
                    [100.0, 1.0],
                    [100.0, 0.0]
                ]
            },
            "properties": {
                "prop0": "value0",
                "prop1": 0.0
            }
        },
    ]
}
EOT;
        })
        ->geoJsonContainsField('geojson_contains', 'prop0')
        ->geoJsonVisible(false)

    Forms\Components\TextInput::make('latitude')
        ->reactive()
        ->afterStateUpdated(function ($state, callable $get, callable $set) {
            $set('location', [
                'lat' => floatVal($state),
                'lng' => floatVal($get('longitude')),
            ]);
        })
        ->lazy(), // important to use lazy, to avoid updates as you type
    Forms\Components\TextInput::make('longitude')
        ->reactive()
        ->afterStateUpdated(function ($state, callable $get, callable $set) {
            $set('location', [
                'lat' => floatval($get('latitude')),
                'lng' => floatVal($state),
            ]);
        })
        ->lazy(), // important to use lazy, to avoid updates as you type

    Map::make('location')
        ->reactive()
        ->afterStateUpdated(function ($state, callable $get, callable $set) {
            $set('latitude', $state['lat']);
            $set('longitude', $state['lng']);
        }),

//
use Cheesegrits\FilamentGoogleMaps\Concerns\InteractsWithMaps;

class EditLocation extends EditRecord
{
    use InteractsWithMaps;
    
    //
}

Map::make('location')
    ->reverseGeocodeUsing(function (callable $set, array $results) {
        // get whatever you need from $results, and $set your field(s)
        $set('street', $results['address_components'][1]['long_name'])
    })

Map::make('location')
    ->placeUpdatedUsing(function (callable $set, array $place) {
        // do whatever you need with the $place results, and $set your field(s)
        $set('city', 'foo wibble');
    }),

use Cheesegrits\FilamentGoogleMaps\Fields\Geocomplete
...
    Geocomplete::make('full_address'),

use Cheesegrits\FilamentGoogleMaps\Fields\Geocomplete
...
    Geocomplete::make('location') // field name must be the computed attribute name on your model
        ->isLocation()
        ->geocodeOnLoad(), // server side geocode of lat/lng to address when form is loaded

    Geocomplete::make('location')
        ->types(['car_dealer', 'car_rental', 'car_repair'])
        ->placesField('name')

    Geocomplete::make('location')
        ->isLocation()
        ->reverseGeocode([
            'city'   => '%L',
            'zip'    => '%z',
            'state'  => '%A1',
            'street' => '%n %S',
        ])
        ->countries(['us']) // restrict autocomplete results to these countries
        ->debug() // output the results of reverse geocoding in the browser console, useful for figuring out symbol formats
        ->updateLatLng() // update the lat/lng fields on your form when a Place is selected
        ->maxLength(1024)
        ->prefix('Choose:')
        ->placeholder('Start typing an address ...')
        ->geolocate() // add a suffix button which requests and reverse geocodes the device location
        ->geolocateIcon('heroicon-o-map'), // override the default icon for the geolocate button

use Cheesegrits\FilamentGoogleMaps\Infolists\MapEntry;

//

    public function infolist(Infolist $infolist): Infolist
    {
        return $infolist->schema([
            TextEntry::make('street'),
            TextEntry::make('city'),
            TextEntry::make('state'),
            TextEntry::make('zip'),
            MapEntry::make('location')
                ->columnSpan(2),
        ]);
    }

WidgetMap::make('widget_map')
    ->mapControls([
        'zoomControl' => true,
    ])
    ->markers(function () {
        // retrieve and display all records from the Geocode model
        $markers = [];
        Geocode::all()->each(function (Geocode $record) use (&$markers) {
            $markers[] = [
                'location' => [
                    'lat' => $record->lat ? round(floatval($record->lat), 8) : 0,
                    'lng' => $record->lng ? round(floatval($record->lat), 8) : 0,
                ],
                'label' => $record->name,
            ];
        });

        return $markers;
    })
    ->columnSpan(2)

[
    [
       'location' = > [ 'lat' => 12.34, 'lng' => -12.34 ],
       'label' => 'Foo bar', // optional
       'icon' => [ 'url' => 'path/to/foo.svg', 'type' => 'svg', 'scale' = [35,35] ] // optional
    ],
    //
]

use Cheesegrits\FilamentGoogleMaps\Columns\MapColumn;
...
MapColumn::make('location')
    ->extraAttributes([
      'class' => 'my-funky-class'
    ]) // Optionally set any additional attributes, merged into the wrapper div around the image tag
    ->extraImgAttributes(
        fn ($record): array => ['title' => $record->latitude . ',' . $record->longitude]
    ) // Optionally set any additional attributes you want on the img tag
    ->height('150') // API setting for map height in PX
    ->width('250') // API setting got map width in PX
    ->type('hybrid') // API setting for map type (hybrid, satellite, roadmap, tarrain)
    ->zoom(15) // API setting for zoom (1 through 20)
    ->ttl(60 * 60 * 24 * 30), // number of seconds to cache image before refetching from API

use Cheesegrits\FilamentGoogleMaps\Filters\RadiusFilter;
...
    RadiusFilter::make('radius')
        ->latitude('lat')  // optional lat and lng fields on your table, default to the getLatLngAttributes() method
        ->longitude('lng') // you should have one your model from the fgm:model-code command when you installed
        ->selectUnit() // add a Kilometer / Miles select
        ->kilometers() // use (or default the select to) kilometers (defaults to miles)
        ->section('Radius Search') // optionally wrap the filter in a section with heading

RadiusFilter::make('radius')
    ->attribute('place.location') // the relationship, with the computed location attribute
    ->color('primary')
    ->icon('heroicon-m-map'),

use Cheesegrits\FilamentGoogleMaps\Actions\RadiusAction;

//

    protected function getTableActions(): array
    {
        return [
            //
            RadiusAction::make(),
        ];
    }

use Cheesegrits\FilamentGoogleMaps\Actions\RadiusAction;

//

    protected function getTableActions(): array
    {
        return [
            //
            RadiusAction::make()
                ->relationship('location')
                ->color('primary')
                ->icon('heroicon-m-map'),
        ];
    }

use Cheesegrits\FilamentGoogleMaps\Actions\StaticMapAction;

        //
            ->bulkActions([
                //
                StaticMapAction::make(),
                //
            ]);
        //



namespace App\Http\Livewire\Widgets;

use App\Models\Dealerships;
use Cheesegrits\FilamentGoogleMaps\Widgets\MapWidget;

class DealershipMap extends MapWidget
{
    protected static ?string $heading = 'Dealership Locations';

    protected static ?bool $clustering = true;

    protected function getData(): array
    {
        $dealerships = Dealerships::all();

        $data = [];

        foreach ($dealerships as $dealership)
        {
            if ($dealership->latitude && $dealership->longitude)
            {
                /**
                 * Each element in the returned data must be an array
                 * containing a 'location' array of 'lat' and 'lng',
                 * and a 'label' string.
                 * 
                 * You should also aan 'id' attribute for internal use by this plugin. 
                 */
                $data[] = [
                    'location'  => [
                        'lat' => $dealership->latitude,
                        'lng' => $dealership->longitude,
                    ],
                    
                    'label' => $dealership->name,
                    
                    'id' => $dealership->getKey(),
                    
                    /**
                     * Optionally you can provide custom icons for the map markers,
                     * either as scalable SVG's, or PNG, which doesn't support scaling.
                     * If you don't provide icons, the map will use the standard Google marker pin.
                     */
                    'icon' => [
                        'url' => url('images/dealership.svg'),
                        'type' => 'svg',
                        'scale' => [35,35],
                    ],
                ];               
            }
        }

        return $data;
    }
}

                $data[] = [
                    // ...
                    'label'     => view(
                        'widgets.dealership-label',
                        [
                            'dealershipId'   => $dealership->id,
                            'dealershipName' => $dealership->name,
                            'dealershipIcon' => $dealership->icon,
                        ]
                    )->render(),
                    // ...
                ]; 

use Filament\Actions\Action;
use Filament\Infolists\Components\Card;
use Filament\Infolists\Components\TextEntry;

class DealershipMap extends MapWidget
{
    // must be the name of both the Action and your method that returns the Action
	protected static ?string $markerAction = 'markerAction';

    //
    
	public function markerAction(): Action
	{
		return Action::make('markerAction')
			->label('Details')
			->infolist([
				Card::make([
					TextEntry::make('name'),
					TextEntry::make('street'),
					TextEntry::make('city'),
					TextEntry::make('state'),
					TextEntry::make('zip'),
					TextEntry::make('formatted_address'),
				])
				->columns(3)
			])
			->record(function (array $arguments) {
				return array_key_exists('model_id', $arguments) ? Location::find($arguments['model_id']) : null;
			})
			->modalSubmitAction(false);
	}

    //
}

    public function getConfig(): array
    {
        $config = parent::getConfig();

        // Disable points of interest
        $config['mapConfig']['styles'] = [
            [
                'featureType' => 'poi',
                'elementType' => 'labels',
                'stylers' => [
                    ['visibility' => 'off'],
                ],
            ],
        ];

        return $config;
    }

    protected function getTableFilters(): array
    {
        return [
            MapIsFilter::make('map'),
        ];
    }

    protected function getTableActions(): array
    {
        return [
            GoToAction::make()
                ->zoom(14),
        ];
    }

use Cheesegrits\FilamentGoogleMaps\Widgets\MapTableWidget;

// ...

class DealershipMap extends MapTableWidget
{
    // ...
    protected function getTableQuery(): Builder
    {
        return Dealer::all();
    }

    protected function getTableColumns(): array
    {
        return [
            Tables\Columns\TextColumn::make('name'),
            Tables\Columns\TextColumn::make('state.name'),
            Tables\Columns\TextColumn::make('phone')
                ->searchable(),
            Tables\Columns\TextColumn::make('email')
                ->searchable(),
        ];
    }

    protected function getTableFilters(): array
    {
        return [
            Tables\Filters\SelectFilter::make('state')
                ->label('State')
                ->relationship('state','state_name'),
            MapIsFilter::make('map'),
        ];
    }
    // ...
}
shell
php artisan filament-google-maps:model-code
sh
php artisan filament-google-maps:model-code
sh
php artisan vendor:publish --tag="filament-google-maps-config"
shell
php artisan filament-google-maps:geocode-table