mostafaznv / nova-map-field
Map Field for Laravel Nova
Installs: 35 219
Dependents: 0
Suggesters: 0
Security: 0
Stars: 42
Watchers: 3
Forks: 15
Open Issues: 1
Requires
- php: ^8.1
- illuminate/support: ^10.0|^11.0
- laravel/nova: ^4.0
- matanyadaev/laravel-eloquent-spatial: ^4.2
README
Using this package, you can use spatial fields in Laravel Nova.
nova-map-field.mp4
I am on an open-source journey 🚀, and I wish I could solely focus on my development path without worrying about my financial situation. However, as life is not perfect, I have to consider other factors.
Therefore, if you decide to use my packages, please kindly consider making a donation. Any amount, no matter how small, goes a long way and is greatly appreciated. 🍺
Requirements:
- PHP 8.1 or higher
- Laravel 10.* or higher
Laravel Compatibility
Installation
-
Install the package via composer:
composer require mostafaznv/nova-map-field
-
Publish config and assets:
php artisan vendor:publish --provider="Mostafaznv\NovaMapField\NovaMapFieldServiceProvider"
-
Done
Usage
-
Create table with spatial fields
<?php return new class extends Migration { public function up() { Schema::create('locations', function (Blueprint $table) { $table->id(); $table->string('title', 150); # laravel 10 $table->point('location')->nullable(); $table->polygon('area')->nullable(); $table->multiPolygon('areas')->nullable(); # laravel 11 and higher $table->geometry('location', subtype: 'point')->nullable(); $table->geometry('area', subtype: 'polygon')->nullable(); $table->geometry('areas', subtype: 'multipolygon')->nullable(); $table->timestamps(); }); } };
-
Add
HasSpatial
trait to model<?php namespace App\Models; use MatanYadaev\EloquentSpatial\Traits\HasSpatial; class Location extends Model { use HasSpatial; }
-
Define spatial columns of model
<?php namespace App\Models; use MatanYadaev\EloquentSpatial\Objects\MultiPolygon; use MatanYadaev\EloquentSpatial\Objects\Point; use MatanYadaev\EloquentSpatial\Objects\Polygon; use MatanYadaev\EloquentSpatial\Traits\HasSpatial; class Location extends Model { use HasSpatial; protected $casts = [ 'location' => Point::class, 'area' => Polygon::class, 'areas' => MultiPolygon::class ]; }
-
Add map fields to resource
<?php namespace App\Nova\Resources; use Mostafaznv\NovaMapField\Fields\MapMultiPolygonField; use Mostafaznv\NovaMapField\Fields\MapPointField; use Mostafaznv\NovaMapField\Fields\MapPolygonField; class Location extends Resource { public function fields(Request $request): array { return [ MapPointField::make('location'), MapPolygonField::make('area'), MapMultiPolygonField::make('areas'), ]; } }
-
Done
Map Field Methods
Config Properties
Capture Screenshot
Utilizing this method enables the capture of a screenshot that mirrors the current state of the map field, subsequently saving it to the filesystem. It is important to note that this feature is experimental
and its performance may vary. The underlying mechanism operates by generating an image on the client's machine each time the client/admin modifies the map field state. Subsequently, this image is transmitted to the server, where it is then stored in the filesystem.
To enable this feature, you must first add the capture
method to your map field. This method accepts a single argument, which is an instance of the Capture
class.
<?php namespace App\Nova\Resources; use App\Nova\Resource; use Illuminate\Http\Request; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Image; use App\Models\Location as Model; use Mostafaznv\NovaMapField\DTOs\Capture; use Mostafaznv\NovaMapField\Fields\MapPointField; class Location extends Resource { public static string $model = Model::class; public function fields(Request $request): array { return [ ID::make()->sortable(), MapPointField::make(trans('Location'), 'location') ->capture( Capture::make('location_screenshot', 600, 600) ->disk('location') ->maxZoom(9) ->padding([10, 10, 10, 10]) ->nearest(true) ->prunable(true) ), Image::make(trans('Location Screenshot'), 'location_screenshot') ->disk('location') ->prunable() ->exceptOnForms(), ]; } }
Note
Activating this feature is as straightforward as calling the static make
function of Capture
. Nevertheless, for those seeking to tailor the behavior of this functionality, alternative methods are available for customization.
Using Spatial Columns over Application
This package uses Laravel Eloquent Spatial under the hood. to use columns and querying them over the application, please read Laravel Eloquent Spatial documentation
Tricks
Transform Polygons
To transform polygons, You should press Alt
(Option ⌥
) button and drag that polygon everywhere you want.
Select Polygons
To select polygons (and modify them), You can press Alt
(Option ⌥
) button and then click on the polygon.
By pressing the Alt
(Option ⌥
) key, drawing mode will be disabled, and you can select every polygon you want.
Complete Example
<?php namespace App\Nova\Resources; use App\Nova\Resource; use Illuminate\Http\Request; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Text; use App\Models\Location as Model; use Mostafaznv\NovaMapField\DTOs\Capture; use Mostafaznv\NovaMapField\DTOs\PointValue; use Mostafaznv\NovaMapField\Enums\MapSearchBoxType; use Mostafaznv\NovaMapField\Enums\MapSearchProvider; use Mostafaznv\NovaMapField\Fields\MapPointField; class Location extends Resource { public static string $model = Model::class; public function fields(Request $request): array { return [ ID::make()->sortable(), Text::make('Title') ->sortable() ->rules('required', 'max:255'), MapPointField::make(trans('Location'), 'location') ->templateUrl('https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png') ->projection('EPSG:3857') ->srid(3857) ->defaultLatitude(35.6978527) ->defaultLongitude(51.4037269) ->zoom(14) ->withoutZoomControl() ->withoutZoomSlider() ->withoutUndoControl() ->withFullScreenControl() ->mapHeight(360) ->hideDetailButton(false) ->markerIcon(3) ->searchProvider(MapSearchProvider::OSM) ->searchProviderApiKey('api-key') ->withAutocompleteSearch() ->searchAutocompleteMinLength(4) ->searchAutocompleteTimeout(500) ->searchLanguage('fa-IR') ->searchPlaceholder('Placeholder ...') ->searchBoxType(MapSearchBoxType::BUTTON) ->searchResultLimit(3) ->searchResultKeepOpen(true) ->withTransformation() ->transformScale() ->transformRotate() ->transformStretch() ->required() ->requiredOnCreate() ->requiredOnUpdate() ->stacked() ->capture( Capture::make('location_screenshot', 600, 600) ->disk('location') ->maxZoom(9) ->padding([10, 10, 10, 10]) ->nearest(true) ->prunable(true) ) ->default( PointValue::make(51.5887845, 4.7760237) ), ]; } }
Deployment
The map field uses a web worker that loads data from blob values, and if you have a strict Content-Security-Policy header (e.g. with default 'none'
), you will need to give permission to load data via this method by adding a worker-src
directive to your CSP:
worker-src 'self' blob:;
Migration
From 3.* to 4.*
- Support for
matanyadaev/laravel-eloquent-spatial
versions 2 and 3 has been dropped. The package now exclusively supports version 4 and higher. - The
HasSpatialColumns
trait has been removed from the package. Instead, use theHasSpatial
trait from the laravel-eloquent-spatial package. - Both
MapSearchBoxType
andMapSearchProvider
custom enums have been refactored and are now located in theMostafaznv\NovaMapField\Enums
namespace, utilizing PHP 8.1 enums. This update affects:- The
searchBoxType
andsearchProvider
methods across all map field types (MapPointField, MapPolygonField, MapMultiPolygonField) - The configuration file properties
search.box-type
andsearch.provider
.
- The
I am on an open-source journey 🚀, and I wish I could solely focus on my development path without worrying about my financial situation. However, as life is not perfect, I have to consider other factors.
Therefore, if you decide to use my packages, please kindly consider making a donation. Any amount, no matter how small, goes a long way and is greatly appreciated. 🍺
License
This software is released under The MIT License (MIT).