cheesegrits / filament-google-maps

Google Maps package for Filament PHP
234 stars 65 forks source link

Refresh loadFeaturesCollection on drawingField change #60

Open luttje opened 11 months ago

luttje commented 11 months ago

Hi, thanks for this awesome package! I'm making good use of it in two projects and it's working great.

However what would help me is the following feature when using the Map field: to make loadFeaturesCollection (in js/filament-google-maps.js) get called again when the drawingField state changes.

I would use this to limit the amount of polygons being drawn. But if it worked it would allow a lot of mutations on the PHP-side, to be reflected in the layer drawings.

Here's the code I tried in between START and END:

public static function form(Form $form): Form
{
    return $form
        ->schema([
            //...

            // Validation works fine
            Forms\Components\Hidden::make('geo_fence_json')
                ->rules([
                    function() {
                        return function (string $attribute, $value, Closure $fail) {
                            try {
                                $geoFence = Geometry::fromJson($value);

                                if (!$geoFence instanceof Polygon) {
                                    $fail('The :attribute contains too many polygons.');
                                }
                            } catch (Exception $e) {
                                $fail('The :attribute is invalid.');
                            }
                        };
                    }
                ])
                // START
                // This fails because cheesegrits/filament-google-maps only looks in the drawingField upon first load
                ->afterStateUpdated(function (?string $state, ?string $old, Set $set) {
                    $geoFence = Geometry::fromJson($state);

                    if ($geoFence instanceof MultiPolygon) {
                        $polygon = $geoFence[0];
                        $featureCollection = GeoBuilder::wrapFeatureCollectionJson($polygon);
                        $set('geo_fence_json', $featureCollection);
                    } elseif ($geoFence instanceof Polygon) {
                        //$polygon = $geoFence;
                    } else {
                        throw new Exception('The geo fence is invalid.');
                    }
                })
                // END

                // Initial load also works fine
                ->formatStateUsing(function (?Location $record) {
                    if (!$record) {
                        return '{}';
                    }

                    $geoFenceGeometry = $record->geo_fence->toJson();

                    // cheesegrits/filament-google-maps needs the property id to be a guid, we'll re-use the location id
                    $shapeId = $record->id;

                    return GeoBuilder::wrapFeatureCollectionJson($geoFenceGeometry, $shapeId);
                }),

            Map::make('location')
                ->autocomplete(
                    fieldName: 'address_line_1'
                )
                ->reverseGeocode([
                    'address_line_1' => '%S %n',
                    'city' => '%L',
                    'state' => '%A1',
                    'zip_code' => '%z',
                    'country' => '%c',
                ])
                ->defaultLocation([52.1326, 5.2913])
                ->defaultZoom(18)
                ->mapControls([
                    'mapTypeControl' => true,
                    'scaleControl' => true,
                    'streetViewControl' => false,
                    'rotateControl' => true,
                    'fullscreenControl' => false,
                    'searchBoxControl' => false,
                    'zoomControl' => true,
                ])
                ->draggable()
                ->columnSpanFull()
                ->drawingControl()
                ->drawingModes([
                    'polygon' => true,
                ])
                ->drawingField('geo_fence_json')
        ]);
}

(The Geometry, MultiPolygon and Polygon come from asanikovich/laravel-spatial)

Other than this feature request everything works fine. I can set data on initial load (as seen above) and validate (also seen above). Again: awesome package, really saves me a lot of time!

luttje commented 11 months ago

Actually, as I was typing this I realized a nice workaround:

  1. Generate a polygon on create
  2. Only allow editing the polygon by calling ->drawingModes([])
  3. This perfectly limits to a single polygon

I'll leave this issue open since I think it's still a useful feature, but feel free to close it.