PHPackages                             jamesil/nova-google-polygon - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. jamesil/nova-google-polygon

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

jamesil/nova-google-polygon
===========================

A Laravel Nova Google polygon field.

V2.1.1(1mo ago)0517↑181%[1 issues](https://github.com/jamesil/nova-google-polygon/issues)[6 PRs](https://github.com/jamesil/nova-google-polygon/pulls)MITPHPPHP ^8.2CI passing

Since Aug 11Pushed 2w agoCompare

[ Source](https://github.com/jamesil/nova-google-polygon)[ Packagist](https://packagist.org/packages/jamesil/nova-google-polygon)[ Docs](https://github.com/jamesil/nova-google-polygon)[ RSS](/packages/jamesil-nova-google-polygon/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (6)Dependencies (24)Versions (26)Used By (0)

Nova Google Polygon Field
=========================

[](#nova-google-polygon-field)

[![Latest Stable Version](https://camo.githubusercontent.com/26951320b494dbccbcb1adc7bf08a0f60f41bb7472c45fb5ad462cb8d8869cd0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a616d6573696c2f6e6f76612d676f6f676c652d706f6c79676f6e3f6c6162656c3d5061636b6167697374)](https://packagist.org/packages/jamesil/nova-google-polygon)[![Total Downloads](https://camo.githubusercontent.com/8d9a314b14b3ac0e656a81054bbe48b04420d720e436148325e9f0d895756288/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a616d6573696c2f6e6f76612d676f6f676c652d706f6c79676f6e)](https://packagist.org/packages/jamesil/nova-google-polygon)[![Tests](https://github.com/jamesil/nova-google-polygon/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/jamesil/nova-google-polygon/actions/workflows/tests.yml)[![License](https://camo.githubusercontent.com/e462c28f3dbcf00b79ac500b02c6a3d56cdf50c24be47c20aab5602e8ba99a6c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a616d6573696c2f6e6f76612d676f6f676c652d706f6c79676f6e)](LICENSE.md)

Draw and edit map areas — coverage zones, delivery boundaries, geofences — directly in your Laravel Nova admin, then query them in PHP. Polygons are stored as plain `{lat, lng}` JSON, so your data stays simple and portable.

 [![A polygon coverage area drawn on a Google Map inside a Nova form field, with draggable vertex handles and a Clear shape button](https://raw.githubusercontent.com/jamesil/nova-google-polygon/main/art/coverage-area.png)](https://raw.githubusercontent.com/jamesil/nova-google-polygon/main/art/coverage-area.png)

Features
--------

[](#features)

- ✏️ Draw and edit polygons on an interactive Google Map, right inside Nova
- 📍 Add, move, and delete vertices — mouse or touch
- 🗄️ Stored as plain `{lat, lng}` JSON; cast to a rich `Polygon` object with Eloquent
- 📐 Geofencing helpers: point-in-polygon (`contain()`), bounding box, and coordinate bounds
- 🌍 Configurable default map centre

Requirements
------------

[](#requirements)

PackageLaravelLaravel NovaPHP`2.x`12.x5.0+8.2+`2.x`13.x5.8+8.3+`1.x`9.x – 11.x4.x or 5.x8.1+You also need a Google Maps API key with the **Maps JavaScript API** enabled.

The `main` branch tracks the `2.x` line (Laravel 12/13). The `1.x` branch is the maintenance line for Laravel 9–11. Laravel 13 requires Nova 5.8.0 or newer.

Important

Versions **≤ 2.0.1** and **≤ 1.1.0** no longer work — Google removed the Maps JavaScript API drawing library they relied on ([details](https://github.com/jamesil/nova-google-polygon/issues/40)). Use **2.1+** (Laravel 12/13) or **1.2+** (Laravel 9–11), which draw with [Terra Draw](https://terradraw.io) instead. Your stored data is unchanged, so upgrading is drop-in.

Installation
------------

[](#installation)

```
composer require jamesil/nova-google-polygon:^2.0
```

For Laravel 9–11, require the `1.x` line instead:

```
composer require jamesil/nova-google-polygon:^1.0
```

Configuration
-------------

[](#configuration)

Add your Google Maps API key to `.env`. The default map centre is optional (it only sets where a brand-new, empty map opens):

```
NOVA_GOOGLE_POLYGON_API_KEY=your-google-maps-api-key
NOVA_GOOGLE_POLYGON_CENTER_LAT=48.858361
NOVA_GOOGLE_POLYGON_CENTER_LNG=2.336164
```

To change the defaults in code, publish the config file (optional):

```
php artisan vendor:publish --provider="Jamesil\NovaGooglePolygon\FieldServiceProvider"
```

Warning

**Restrict your API key.** It is sent to the browser to load the map, so anyone can read it. In the [Google Cloud Console](https://console.cloud.google.com), add HTTP-referrer restrictions (your Nova domain) and enable only the *Maps JavaScript API*.

Usage
-----

[](#usage)

### 1. Add the field

[](#1-add-the-field)

```
use Jamesil\NovaGooglePolygon\GooglePolygon;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Name'),

        GooglePolygon::make('Coverage Area', 'coverage_area'),
    ];
}
```

The field is shown on forms and detail views (it is hidden on the resource index).

### 2. Store the data

[](#2-store-the-data)

The polygon is saved as JSON, so give the attribute a JSON column:

```
Schema::create('locations', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->json('coverage_area')->nullable();
    $table->timestamps();
});
```

Add the `AsPolygon` cast so the attribute reads and writes as a `Polygon` object:

```
use Jamesil\NovaGooglePolygon\Casts\AsPolygon;

class Location extends Model
{
    protected $casts = [
        'coverage_area' => AsPolygon::class,
    ];
}
```

The column holds an array of points:

```
[
  { "lat": 48.858361, "lng": 2.336164 },
  { "lat": 48.859361, "lng": 2.337164 },
  { "lat": 48.857361, "lng": 2.338164 }
]
```

### 3. Draw and edit on the map

[](#3-draw-and-edit-on-the-map)

**Drawing** (empty map):

- **Click** to place each vertex.
- **Finish** by clicking the first point again, or pressing **Enter**.
- **Escape** cancels the shape you're drawing.

**Editing** (a polygon exists):

- **Drag** a vertex to move it.
- **Click a midpoint** — the fainter handle on an edge — to insert a vertex.
- **Right-click** a vertex to remove it (a polygon keeps at least 3).
- **Clear shape** (the button on the map) removes the polygon so you can start over.

Touch devices work the same way — tap to place vertices and drag the handles. If the handles vanish after you click elsewhere on the map, click the polygon to select it again.

### 4. Work with a polygon in PHP

[](#4-work-with-a-polygon-in-php)

With the cast in place, the attribute is a `Polygon` you can query — ideal for geofencing:

```
use Jamesil\NovaGooglePolygon\Support\Point;

$location = Location::find(1);

// Is a coordinate inside the zone?
$location->coverage_area->contain(new Point(48.8585, 2.3370)); // true / false

// Bounds
$location->coverage_area->getBoundingBox();
$location->coverage_area->getMinLatitude();
$location->coverage_area->getMaxLatitude();
```

You can also build a polygon directly:

```
use Jamesil\NovaGooglePolygon\Support\Polygon;

$polygon = new Polygon([
    ['lat' => 48.858361, 'lng' => 2.336164],
    ['lat' => 48.859361, 'lng' => 2.337164],
    ['lat' => 48.857361, 'lng' => 2.338164],
]);
```

Example: taxi pickup zones
--------------------------

[](#example-taxi-pickup-zones)

Store a drawable pickup area per zone, then find which zone a rider falls in:

```
use Jamesil\NovaGooglePolygon\Casts\AsPolygon;
use Jamesil\NovaGooglePolygon\Support\Point;

class PickupZone extends Model
{
    protected $casts = [
        'pickup_area' => AsPolygon::class,
        'active' => 'boolean',
    ];

    public function covers(float $latitude, float $longitude): bool
    {
        return $this->active
            && $this->pickup_area
            && $this->pickup_area->contain(new Point($latitude, $longitude));
    }

    public static function forLocation(float $latitude, float $longitude): ?self
    {
        return static::where('active', true)->get()
            ->first(fn (self $zone) => $zone->covers($latitude, $longitude));
    }
}
```

API reference
-------------

[](#api-reference)

### `Polygon`

[](#polygon)

MethodDescription`contain(Point|array $point): bool`Whether the point is inside the polygon (even-odd ray casting). A point on a vertex is inside; points on an edge follow a half-open convention (the minimum-latitude and minimum-longitude edges are inclusive, the opposite edges exclusive).`pointOnVertex(Point|array $point): bool`Whether the point sits exactly on a vertex.`getBoundingBox(): array`The four `[lat, lng]` corners of the bounding box.`getMinLatitude() / getMaxLatitude(): float`Latitude bounds.`getMinLongitude() / getMaxLongitude(): float`Longitude bounds.`getPoints(): Point[]`All vertices.`setPoints(array $points): Polygon`Replace the vertices.### `Point`

[](#point)

MethodDescription`new Point(float $lat, float $lng)`Create a point.`Point::fromArray(array $input): Point`From `['lat' => …, 'lng' => …]` or `[$lat, $lng]`.`toArray(): array` / `toJson(): string`Serialise the point.Limitations
-----------

[](#limitations)

- One polygon per field — no multi-polygons or holes.
- The map is a fixed 500px tall and auto-fits to an existing polygon; zoom is automatic.

Testing
-------

[](#testing)

```
composer test
```

Credits
-------

[](#credits)

- [James Embling](https://github.com/jamesil)
- Based on the original work by [YieldStudio](https://github.com/YieldStudio/nova-google-polygon)

License
-------

[](#license)

The MIT License (MIT). See [LICENSE.md](LICENSE.md).

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance94

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 60% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~41 days

Recently: every ~0 days

Total

9

Last Release

43d ago

Major Versions

V1.1.0 → V2.0.02026-04-15

V1.2.0 → V2.1.12026-07-05

PHP version history (2 changes)V1.0.0PHP ^8.1

V2.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/12300c4c70c36ea468cb86f1d81504b00b3bda35e5cc43b1a4d8219b334a7285?d=identicon)[jamesil](/maintainers/jamesil)

---

Top Contributors

[![jamesil](https://avatars.githubusercontent.com/u/7086382?v=4)](https://github.com/jamesil "jamesil (21 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (14 commits)")

---

Tags

laravelgooglePolygonnovaareajamesil

###  Code Quality

TestsPest

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/jamesil-nova-google-polygon/health.svg)

```
[![Health](https://phpackages.com/badges/jamesil-nova-google-polygon/health.svg)](https://phpackages.com/packages/jamesil-nova-google-polygon)
```

###  Alternatives

[outl1ne/nova-sortable

This Laravel Nova package allows you to reorder models in a Nova resource's index view using drag &amp; drop.

2852.2M9](/packages/outl1ne-nova-sortable)[spatie/nova-backup-tool

A Laravel Nova tool to backup your application.

361588.6k1](/packages/spatie-nova-backup-tool)[mostafaznv/nova-map-field

Map Field for Laravel Nova

46116.1k](/packages/mostafaznv-nova-map-field)[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17930.8k](/packages/markwalet-nova-modal-response)[advoor/nova-editor-js

A Laravel Nova field bringing EditorJs magic to Nova.

92254.5k3](/packages/advoor-nova-editor-js)[emargareten/inertia-modal

Inertia Modal is a Laravel package that lets you implement backend-driven modal dialogs for Inertia apps.

90157.6k](/packages/emargareten-inertia-modal)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
