{"id":23338830,"url":"https://github.com/mostafaznv/nova-map-field","last_synced_at":"2025-04-04T18:05:24.514Z","repository":{"id":39410869,"uuid":"506645402","full_name":"mostafaznv/nova-map-field","owner":"mostafaznv","description":"Spatial Map Fields for Laravel Nova","archived":false,"fork":false,"pushed_at":"2025-02-28T16:51:01.000Z","size":8917,"stargazers_count":46,"open_issues_count":1,"forks_count":15,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-28T17:06:35.933Z","etag":null,"topics":["laravel","map","map-marker","nova","openlayers","polygon","spatial-columns"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mostafaznv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-23T13:10:31.000Z","updated_at":"2025-03-24T03:34:22.000Z","dependencies_parsed_at":"2024-09-05T23:50:18.280Z","dependency_job_id":"412a932a-3ca3-475d-8744-4c68f56a985b","html_url":"https://github.com/mostafaznv/nova-map-field","commit_stats":{"total_commits":38,"total_committers":2,"mean_commits":19.0,"dds":"0.052631578947368474","last_synced_commit":"b8f4cf0d883320835de520f969cfccf2250df4c8"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mostafaznv%2Fnova-map-field","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mostafaznv%2Fnova-map-field/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mostafaznv%2Fnova-map-field/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mostafaznv%2Fnova-map-field/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mostafaznv","download_url":"https://codeload.github.com/mostafaznv/nova-map-field/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226213,"owners_count":20904465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","map","map-marker","nova","openlayers","polygon","spatial-columns"],"created_at":"2024-12-21T03:16:57.232Z","updated_at":"2025-04-04T18:05:24.487Z","avatar_url":"https://github.com/mostafaznv.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Map Field for Laravel Nova\n\n[![License](https://img.shields.io/github/license/mostafaznv/nova-map-field?style=flat-square)](https://github.com/mostafaznv/nova-map-field/blob/master/LICENSE)\n[![Packagist Downloads](https://img.shields.io/packagist/dt/mostafaznv/nova-map-field?style=flat-square\u0026logo=packagist)](https://packagist.org/packages/mostafaznv/nova-map-field)\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/mostafaznv/nova-map-field.svg?style=flat-square\u0026logo=composer)](https://packagist.org/packages/mostafaznv/nova-map-field)\n\n\nUsing this package, you can use spatial fields in Laravel Nova.\n\n\nhttps://github.com/mostafaznv/nova-map-field/assets/7619687/08ca878b-1bfc-4a11-b30b-44350b57cf69\n\n\n----\n\nI 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.\n\nTherefore, 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. 🍺\n\n[![Donate](https://mostafaznv.github.io/donate/donate.svg)](https://mostafaznv.github.io/donate)\n\n----\n\n\n## Requirements:\n\n- PHP 8.1 or higher\n- Laravel 10.* or higher\n\n\n## Laravel Compatibility\n\n| Laravel       | PHP    | Nova Map Field                                                  |\n|---------------|--------|-----------------------------------------------------------------|\n| ^8.0 - ^9.0   | ^8.0.2 | [^3.0](https://github.com/mostafaznv/nova-map-field/tree/3.2.0) |\n| ^10.0 - ^11.0 | ^8.1   | ^4.0 (latest)                                                   |\n\n\n\n## Installation\n\n1. ##### Install the package via composer:\n    ```shell\n    composer require mostafaznv/nova-map-field\n    ```\n\n2. ##### Publish config and assets:\n    ```shell\n    php artisan vendor:publish --provider=\"Mostafaznv\\NovaMapField\\NovaMapFieldServiceProvider\"\n    ```\n\n3. ##### Done\n\n\n## Usage\n\n1. ##### Create table with spatial fields\n    ```php\n    \u003c?php\n\n    return new class extends Migration\n    {\n        public function up()\n        {\n            Schema::create('locations', function (Blueprint $table) {\n                $table-\u003eid();\n                $table-\u003estring('title', 150);\n                \n                # laravel 10\n                $table-\u003epoint('location')-\u003enullable();\n                $table-\u003epolygon('area')-\u003enullable();\n                $table-\u003emultiPolygon('areas')-\u003enullable();\n                \n                # laravel 11 and higher\n                $table-\u003egeometry('location', subtype: 'point')-\u003enullable();\n                $table-\u003egeometry('area', subtype: 'polygon')-\u003enullable();\n                $table-\u003egeometry('areas', subtype: 'multipolygon')-\u003enullable();\n   \n                $table-\u003etimestamps();\n            });\n        }\n    };\n    ```\n\n2. ##### Add `HasSpatial` trait to model\n    ```php\n    \u003c?php\n    \n    namespace App\\Models;\n    \n    use MatanYadaev\\EloquentSpatial\\Traits\\HasSpatial;\n   \n    \n    class Location extends Model\n    {\n        use HasSpatial;\n    }\n    ```\n\n3. ##### Define spatial columns of model\n    ```php\n    \u003c?php\n   \n    namespace App\\Models;\n   \n    use MatanYadaev\\EloquentSpatial\\Objects\\MultiPolygon;\n    use MatanYadaev\\EloquentSpatial\\Objects\\Point;\n    use MatanYadaev\\EloquentSpatial\\Objects\\Polygon;\n    use MatanYadaev\\EloquentSpatial\\Traits\\HasSpatial;\n    \n   \n    class Location extends Model\n    {\n        use HasSpatial;\n\n        protected $casts = [\n            'location' =\u003e Point::class,\n            'area'     =\u003e Polygon::class,\n            'areas'    =\u003e MultiPolygon::class\n        ];\n    }\n    ```\n\n4. ##### Add map fields to resource\n    ```php\n    \u003c?php\n    \n    namespace App\\Nova\\Resources;\n    \n    use Mostafaznv\\NovaMapField\\Fields\\MapMultiPolygonField;\n    use Mostafaznv\\NovaMapField\\Fields\\MapPointField;\n    use Mostafaznv\\NovaMapField\\Fields\\MapPolygonField;\n    \n   \n    class Location extends Resource\n    {\n        public function fields(Request $request): array\n        {\n            return [\n                MapPointField::make('location'),\n                MapPolygonField::make('area'),\n                MapMultiPolygonField::make('areas'),\n            ];\n        }\n    }\n    ```\n\n5. ##### Done\n\n\n## Map Field Methods\n\n| method                      | Arguments                                | description                                                                                                                        |\n|-----------------------------|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|\n| templateUrl                 | url \u003cbr\u003e `string`                        | Specifies template of map                                                                                                          |\n| projection                  | projection \u003cbr\u003e `string`                 | Specifies projection of map                                                                                                        |\n| srid                        | srid \u003cbr\u003e `integer` `default: 0`         | Specifies SRID of map                                                                                                              |\n| defaultLatitude             | latitude \u003cbr\u003e `float`                    | Specifies latitude of map on page load                                                                                             |\n| defaultLongitude            | longitude \u003cbr\u003e `float`                   | Specifies longitude of map on page load                                                                                            |\n| zoom                        | zoom \u003cbr\u003e `integer`                      | Specifies default map zoom                                                                                                         |\n| withoutZoomControl          | status \u003cbr\u003e `bool` `default: true`       | Specifies whether zoom in/out button should display on map or not                                                                  |\n| withoutZoomSlider           | status \u003cbr\u003e `bool` `default: true`       | Specifies whether zoom slider should display on map or not                                                                         |\n| withFullScreenControl       | status \u003cbr\u003e `bool` `default: true`       | Specifies whether full screen button should display on map or not                                                                  |\n| mapHeight                   | height \u003cbr\u003e `integer` `default: 400`     | Map's height                                                                                                                       |\n| hideDetailButton            | status \u003cbr\u003e `bool` `default: true`       | Specifies whether **Show Details** button should appear on detail pages or not                                                     |\n| markerIcon                  | icon \u003cbr\u003e `integer` `available: 1, 2, 3` | Marker icon                                                                                                                        |\n| withSearchBox               | `boolean`                                | Specifies whether map has search box or not                                                                                        |\n| searchProvider              | provider `MapSearchProvider`             |                                                                                                                                    |\n| searchProviderApiKey        | apiKey `string`                          | Specifies api key for search provider, if needed                                                                                   |\n| withAutocompleteSearch      | status `bool` `default: true`            | Specifies whether search results should load immediately or not                                                                    |\n| searchAutocompleteMinLength | minLength `int`                          | Specifies the minimum number of characters to trigger search action                                                                |\n| searchAutocompleteTimeout   | timeout `int`                            | Specifies the minimum number of ms to wait before triggering search action                                                         |\n| searchLanguage              | language `string`                        | Specifies preferable language                                                                                                      |\n| searchPlaceholder           | placeholder `string`                     |                                                                                                                                    |\n| searchBoxType               | type `MapSearchBoxType`                  | Using this item, you can specify type of search box (button, or text-field                                                         |\n| searchResultLimit           | limit `int`                              | Specifies limit of results                                                                                                         |\n| searchResultKeepOpen        | status `boolean`                         | Specifies whether the results keep opened                                                                                          |\n| withTransformation          | status `boolean`                         | Specifies whether transport feature should be enable on polygons                                                                   |\n| transformScale              | status `boolean`                         | Using this method, you can enable/disable scaling features                                                                         |\n| transformRotate             | status `boolean`                         | Using this method, you can enable/disable rotating features                                                                        |\n| transformStretch            | status `boolean`                         | Using this method, you can enable/disable stretch option                                                                           |\n| requiredOnCreate            | status \u003cbr\u003e `bool` `default: true`       | Makes field required on creation                                                                                                   |\n| requiredOnUpdate            | status \u003cbr\u003e `bool` `default: true`       | Makes field required on update                                                                                                     |\n| default                     | $callback \u003cbr\u003e `PointValue`              | Set default value for map field. \u003cbr\u003e**Note:** Only works in `MapPointField`                                                       |\n| capture                     | capture \u003cbr\u003e `Capture` `experimental`    | By employing this method, you can capture a screenshot reflecting the current state of the map field and save it to the filesystem |\n\n## Config Properties\n\n| Method                         | Type              | Default                                                | Description                                                                                                             |\n|--------------------------------|-------------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|\n| template-url                   | string            | `https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png` | Default Template URL. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.                                      |\n| projection                     | string            | `EPSG:3857`                                            | Default projection of map                                                                                               |\n| srid                           | int               | 0                                                      | Default SRID of map                                                                                                     |\n| default-latitude               | bool              | 0                                                      | Default latitude of map                                                                                                 |\n| default-longitude              | bool              | 0                                                      | Default longitude of map                                                                                                |\n| zoom                           | int               | 12                                                     | Default zoom of map                                                                                                     |\n| controls.zoom-control          | bool              | true                                                   | Specifies if map should display zoom controls (zoom in/out buttons) or not                                              |\n| controls.zoom-slider           | bool              | true                                                   | Specifies if map should display zoom slider or not                                                                      |\n| controls.full-screen-control   | bool              | false                                                  | Specifies if map should display full screen button or not                                                               |\n| controls.undo-control          | bool              | true                                                   | Specifies if map should display undo control or not (Only for `Polygon` and `MultiPolygon`)                             |\n| controls.clear-map-control     | bool              | true                                                   | Specifies if map should display clear map control or not (Only for `Polygon` and `MultiPolygon`)                        |\n| map-height                     | int               | 400                                                    | Specifies map height                                                                                                    |\n| icon                           | int               | 1                                                      | Specifies marker icon. available values: `1, 2, 3`                                                                      |\n| style.stroke-color             | string            | red                                                    | Using this property, you can specify stroke color of polygons or other shapes. Either in hexadecimal or as RGBA array   |\n| style.stroke-width             | int               | 2                                                      | Width of the stroke (px)                                                                                                |\n| style.fill-color               | string            | rgba(255, 0, 0, 0.4)                                   | Using this property, you can specify filling color of polygons or other shapes. Either in hexadecimal or as RGBA array. |\n| show-detail-button             | bool              | true                                                   | Specifies whether **Show Details** button should appear on detail pages or not                                          |\n| search.enable                  | bool              | true                                                   | Using this item, you can toggle displaying search box on maps                                                           |\n| search.provider                | MapSearchProvider | OSM                                                    | Specifies search provider available providers: `OSM, MAPQUEST, PHOTON, PELIAS, BING, OPENCAGE`                          |\n| search.api-key                 | string            | ''                                                     | Specifies API key if required                                                                                           |\n| search.autocomplete            | bool              | false                                                  | Using this item, you can toggle autocomplete feature for search box                                                     |\n| search.autocomplete-min-length | int               | 2                                                      | The minimum number of characters to trigger search                                                                      |\n| search.autocomplete-timeout    | int               | 200                                                    | The minimum number of ms to wait before triggering search action                                                        |\n| search.language                | string            | en-US                                                  | Specifies preferable language                                                                                           |\n| search.placeholder             | string            | Search for an address                                  | Specifies placeholder for text input                                                                                    |\n| search.box-type                | MapSearchBoxType  | TEXT_FIELD                                             | Specifies type of search box. available types: `BUTTON, TEXT_FIELD`                                                     |\n| search.limit                   | int               | 5                                                      | Specifies limit of results                                                                                              |\n| search.keep-open               | bool              | false                                                  | Specifies whether the results keep opened                                                                               |\n| transform.enable               | bool              | true                                                   | Using this item, you can toggle transforming polygons maps                                                              |\n| transform.scale                | bool              | true                                                   | Using this property, you can toggle scaling features                                                                    |\n| transform.scale                | bool              | true                                                   | Using this property, you can toggle rotating features                                                                   |\n| transform.stretch              | bool              | true                                                   | Using this property, you can enable/disable stretch option                                                              |\n\n\n## Capture Screenshot\nUtilizing 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.\n\nTo 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.\n```php\n\u003c?php\n\nnamespace App\\Nova\\Resources;\n\nuse App\\Nova\\Resource;\nuse Illuminate\\Http\\Request;\nuse Laravel\\Nova\\Fields\\ID;\nuse Laravel\\Nova\\Fields\\Image;\nuse App\\Models\\Location as Model;\nuse Mostafaznv\\NovaMapField\\DTOs\\Capture;\nuse Mostafaznv\\NovaMapField\\Fields\\MapPointField;\n\nclass Location extends Resource\n{\n    public static string $model = Model::class;\n\n    public function fields(Request $request): array\n    {\n        return [\n            ID::make()-\u003esortable(),\n\n            MapPointField::make(trans('Location'), 'location')\n                -\u003ecapture(\n                     Capture::make('location_screenshot', 600, 600)\n                        -\u003edisk('location')\n                        -\u003emaxZoom(9)\n                        -\u003epadding([10, 10, 10, 10])\n                        -\u003enearest(true)\n                        -\u003eprunable(true)\n                ),\n\n            Image::make(trans('Location Screenshot'), 'location_screenshot')\n                -\u003edisk('location')\n                -\u003eprunable()\n                -\u003eexceptOnForms(),\n        ];\n    }\n}\n```\n\n\u003e [!NOTE]  \n\u003e 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.\n\n\n## Using Spatial Columns over Application\n\nThis package uses [Laravel Eloquent Spatial](https://github.com/MatanYadaev/laravel-eloquent-spatial/) under the hood. to use columns and querying them over the application, please read **Laravel Eloquent Spatial** documentation\n\n\n## Tricks\n\n### Transform Polygons\n\nTo transform polygons, You should press `Alt` (Option `⌥`) button and drag that polygon everywhere you want.\n\n### Select Polygons\n\nTo select polygons (and modify them), You can press `Alt` (Option `⌥`) button and then click on the polygon. \nBy pressing the `Alt` (Option `⌥`) key, drawing mode will be disabled, and you can select every polygon you want.\n\n----\n\n## Complete Example\n```php\n\u003c?php\n\nnamespace App\\Nova\\Resources;\n\nuse App\\Nova\\Resource;\nuse Illuminate\\Http\\Request;\nuse Laravel\\Nova\\Fields\\ID;\nuse Laravel\\Nova\\Fields\\Text;\nuse App\\Models\\Location as Model;\nuse Mostafaznv\\NovaMapField\\DTOs\\Capture;\nuse Mostafaznv\\NovaMapField\\DTOs\\PointValue;\nuse Mostafaznv\\NovaMapField\\Enums\\MapSearchBoxType;\nuse Mostafaznv\\NovaMapField\\Enums\\MapSearchProvider;\nuse Mostafaznv\\NovaMapField\\Fields\\MapPointField;\n\nclass Location extends Resource\n{\n    public static string $model = Model::class;\n\n    public function fields(Request $request): array\n    {\n        return [\n            ID::make()-\u003esortable(),\n\n            Text::make('Title')\n                -\u003esortable()\n                -\u003erules('required', 'max:255'),\n                \n            MapPointField::make(trans('Location'), 'location')\n                -\u003etemplateUrl('https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png')\n                -\u003eprojection('EPSG:3857')\n                -\u003esrid(3857)\n                -\u003edefaultLatitude(35.6978527)\n                -\u003edefaultLongitude(51.4037269)\n                -\u003ezoom(14)\n                -\u003ewithoutZoomControl()\n                -\u003ewithoutZoomSlider()\n                -\u003ewithoutUndoControl()\n                -\u003ewithFullScreenControl()\n                -\u003emapHeight(360)\n                -\u003ehideDetailButton(false)\n                -\u003emarkerIcon(3)\n                -\u003esearchProvider(MapSearchProvider::OSM)\n                -\u003esearchProviderApiKey('api-key')\n                -\u003ewithAutocompleteSearch()\n                -\u003esearchAutocompleteMinLength(4)\n                -\u003esearchAutocompleteTimeout(500)\n                -\u003esearchLanguage('fa-IR')\n                -\u003esearchPlaceholder('Placeholder ...')\n                -\u003esearchBoxType(MapSearchBoxType::BUTTON)\n                -\u003esearchResultLimit(3)\n                -\u003esearchResultKeepOpen(true)\n                -\u003ewithTransformation()\n                -\u003etransformScale()\n                -\u003etransformRotate()\n                -\u003etransformStretch()\n                -\u003erequired()\n                -\u003erequiredOnCreate()\n                -\u003erequiredOnUpdate()\n                -\u003estacked()\n                -\u003ecapture(\n                    Capture::make('location_screenshot', 600, 600)\n                        -\u003edisk('location')\n                        -\u003emaxZoom(9)\n                        -\u003epadding([10, 10, 10, 10])\n                        -\u003enearest(true)\n                        -\u003eprunable(true)\n                    \n                )\n                -\u003edefault(\n                    PointValue::make(51.5887845, 4.7760237)\n                ),\n        ];\n    }\n}\n```\n\n----\n## Deployment\n\nThe 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src) to your CSP:\n\n    worker-src 'self' blob:;\n----\n## Migration\n\n#### From 3.* to 4.*\n- Support for `matanyadaev/laravel-eloquent-spatial` versions 2 and 3 has been dropped. The package now exclusively supports version 4 and higher.\n- The `HasSpatialColumns` trait has been removed from the package. Instead, use the `HasSpatial` trait from the laravel-eloquent-spatial package.\n- Both `MapSearchBoxType` and `MapSearchProvider` custom enums have been refactored and are now located in the `Mostafaznv\\NovaMapField\\Enums` namespace, utilizing PHP 8.1 enums. This update affects:\n  - The `searchBoxType` and `searchProvider` methods across all map field types (MapPointField, MapPolygonField, MapMultiPolygonField)\n  - The configuration file properties `search.box-type` and `search.provider`.\n\n----\nI 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.\n\nTherefore, 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. 🍺\n\n[![Donate](https://mostafaznv.github.io/donate/donate.svg)](https://mostafaznv.github.io/donate)\n\n----\n\n\n\n## License\n\nThis software is released under [The MIT License (MIT)](LICENSE).\n\n\n\n-----\n### Sponsors\n\n[![JetBrains Logo (Main) logo](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://jb.gg/OpenSourceSupport)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmostafaznv%2Fnova-map-field","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmostafaznv%2Fnova-map-field","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmostafaznv%2Fnova-map-field/lists"}