How To Add a Geofencing in Map using Laravel?

10-Jul-2023

.

Admin

How To Add a Geofencing in Map using Laravel?

Hi dev,

In this post, we will learn how to add a geofencing in map using laravel. you can see How can add a geofence or custom markers in laravel. In this article, we will implement a How to implement geofencing in map using laravel. you can understand a concept of How to use geofencing in map using laravel.

how to add a geofencing in map using laravel,How can add a geofence or custom markers in laravel,How to implement geofencing in map using laravel,How to use geofencing in map using laravel,how do you implement a geofence map in laravel,add geofencing in map using laravel

Step 1: Install Laravel


first of all we need to get fresh Laravel 10 version application using bellow command, So open your terminal OR command prompt and run bellow command:

composer create-project laravel/laravel example-app

Step 2: install package

So open your terminal OR command prompt and run bellow command:

composer require grimzy/laravel-mysql-spatial

Step 3: set config

go to config/app.php => provider and past bellow code :

Grimzy\LaravelMysqlSpatial\SpatialServiceProvider::class,

Step 4: Create "zones" table

basically, it will created "zones" table :

Migration

<?php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

class CreateZonesTable extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

Schema::create('zones', function (Blueprint $table) {

$table->id();

$table->string('name')->nullable();

$table->string('city_full_address')->nullable();

$table->string('city')->nullable();

$table->string('state')->nullable();

$table->string('city_latitude')->nullable();

$table->string('city_longitude')->nullable();

$table->string('zone_center_latitude')->nullable();

$table->string('zone_center_longitude')->nullable();

$table->polygon('map_polygon')->nullable();

$table->timestamps();

});

}

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('zones');

}

}

Step 5: Create Route

In this is step we need to create custom route. so open your routes/web.php file and add following route.

routes/web.php

<?php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\HomeController;

/*

|--------------------------------------------------------------------------

| Web Routes

|--------------------------------------------------------------------------

|

| Here is where you can register web routes for your application. These

| routes are loaded by the RouteServiceProvider within a group which

| contains the "web" middleware group. Now create something great!

|

*/

// zone

Route::get('/zone', [HomeController::class, 'index'])->name('index');

Route::get('zone/{id}/assign/map_polygon', [HomeController::class, 'assignMapPolygon'])->name('zone.assign.map_polygon');

Route::post('zone/assign/map_polygon/store', [HomeController::class, 'assignMapPolygonStore'])->name('zone.map_polygon.store');

Route::post('zone/assign/map_polygon/clear', [HomeController::class, 'assignMapPolygon'])->name('zone.map_polygon.clear');

Route::post('zone/map_polygon/clear', [HomeController::class, 'assignMapPolygonClear'])->name('zone.map_polygon.clear');

// rider

Route::get('/rider', [HomeController::class, 'createRider'])->name('rider.create');

Route::post('/rider/store', [HomeController::class, 'createRiderStore'])->name('rider.create.store');

Step 6: Create Controller

in this step, we need to create HomeController and add following code on that file:

app/Http/Controllers/HomeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Zone;

use App\Models\Rider;

use DataTables;

use DB;

use Exception;

use Throwable;

use Log;

use Grimzy\LaravelMysqlSpatial\Types\Point;

use Grimzy\LaravelMysqlSpatial\Types\Polygon;

use Grimzy\LaravelMysqlSpatial\Types\LineString;

class HomeController extends Controller

{

public function index(Request $request){

if ($request->ajax()) {

$data = Zone::select('*');

return Datatables::of($data)

->addIndexColumn()

->addColumn('action', function($row){

$btn = '<a href="'.route('zone.assign.map_polygon',$row->id).'" type="button" class="btn btn-primary btn-padding-fs btn-margin ml-1" data-toggle="tooltip" data-placement="bottom" data-original-title="Assign Geofencing"><b>Assign Geofencing</b></a><br>';

return $btn;

})

->rawColumns(['action'])

->make(true);

}

return view('welcome');

}

public function assignMapPolygon($id){

$zone = Zone::find($id);

if (empty($zone) || is_null($zone)) {

return redirect()->route('index');

}

$currentPolygon = $currentPolygonLatLng = [];

// check if polygon points exist than only create polygon array

if(!empty($zone->map_polygon) && method_exists($zone->map_polygon,'getLineStrings') && !empty($zone->map_polygon->getLineStrings()) && isset($zone->map_polygon->getLineStrings()[0]) && !empty($zone->map_polygon->getLineStrings()[0]) ){

foreach ($zone->map_polygon->getLineStrings()[0]->getPoints() as $value) {

$currentPolygonLatLng[] = [

'lat'=>$value->getLat(),

'lng'=>$value->getLng()

];

}

}

// if polygon points exist than create polygon object for frontend map

if(!empty($currentPolygonLatLng)){

$currentPolygon =[

"path"=> $currentPolygonLatLng,

"strokeColor"=> "#1f9d57",

"strokeOpacity"=> 0.8,

"strokeWeight"=> 2,

"fillColor"=> "#00FF00",

"fillOpacity"=> 0.4,

"city_latitude"=>$zone->city_latitude,

"city_longitude"=>$zone->city_longitude,

"zone_center_latitude"=>$zone->zone_center_latitude ?? ($zone->city_latitude ?? 28.7041),

"zone_center_longitude"=>$zone->zone_center_longitude ?? ($zone->city_longitude ?? 77.1025),

"zone_name"=>$zone->name,

"id"=>$zone->id,

"label"=>$zone->name."[$zone->city_full_address]",

];

}

// check if city is added than pick city lat long else New Delhi lat long

$mapCenter = [

'lat'=>!empty($zone->city_latitude) ? $zone->city_latitude : 28.7041,

'lng'=>!empty($zone->city_longitude) ? $zone->city_longitude : 77.1025

];

return view('mapPolygon',compact('id','zone','mapCenter','currentPolygon'));

}

public function assignMapPolygonStore(Request $request){

$input = $request->all();

//DB Transaction start

DB::beginTransaction();

$zone = Zone::find($input['zone_id']);

// declare a point array to assign in linestring

$polygon_points = [];

foreach ($input['map_polygon'] as $value) {

// create a new point array for each polygon points

$polygon_points[] = new Point($value['lat'], $value['lng']);

}

// pass first position value as last to complete the polygon

$polygon_points[] = new Point($input['map_polygon'][0]['lat'], $input['map_polygon'][0]['lng']);

// create a polygon from linestring and point array & assign polygon to zone object

$zone->map_polygon = new Polygon([new LineString($polygon_points)]);

$zone_center = isset($input['polygon_center']) && !empty($input['polygon_center']) ? $input['polygon_center'] : [];

$zone->zone_center_latitude = $zone_center['lat'] ?? NULL;

$zone->zone_center_longitude = $zone_center['lng'] ?? NULL;

// save updated polygon

$zone->save();

DB::commit();

return response()->json(['success'=>'Zone Geofencing saved successfully']);

try {

}catch (Exception $e) {

DB::rollback();

Log::error($e);

report($e);

return response()->json(['dberror'=>config('celcius.operation_dbtransaction_message')]);

} catch (Throwable $e) {

DB::rollback();

Log::error($e);

report($e);

return response()->json(['dberror'=>config('celcius.operation_dbtransaction_message')]);

//throw $e;

}

//DB Transaction End

}

public function assignMapPolygonClear(Request $request){

$input = $request->all();

$zone = Zone::find($input['zone_id']);

//DB Transaction start

DB::beginTransaction();

try {

$zone->map_polygon = NULL;

$zone->zone_center_latitude = NULL;

$zone->zone_center_longitude = NULL;

$zone->save();

DB::commit();

return response()->json(['success'=>'Zone Geofencing cleared successfully']);

} catch (Exception $e) {

DB::rollback();

Log::error($e);

report($e);

return response()->json(['dberror'=>config('celcius.operation_dbtransaction_message')]);

} catch (Throwable $e) {

DB::rollback();

Log::error($e);

report($e);

return response()->json(['dberror'=>config('celcius.operation_dbtransaction_message')]);

//throw $e;

}

//DB Transaction End

}

public function createRider(){

return view('riderCreate');

}

public function createRiderStore(Request $request){

$input = $request->all();

$latitude = $input['from_latitude'];

$longitude = $input['from_longitude'];

$location = findZoneByLatLng($latitude,$longitude);

if(!empty($location)){

$input['zone_id'] = $location->id;

Rider::create($input);

return redirect()->route('index');

}else{

return "<center><h1>No Location Found</h1></center>";

}

}

}

Step 7: Create models

here, we need to create models. so let's create one by one files:

app/models/User.php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Foundation\Auth\User as Authenticatable;

use Illuminate\Notifications\Notifiable;

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable

{

use HasApiTokens, HasFactory, Notifiable;

/**

* The attributes that are mass assignable.

*

* @var array

*/

protected $fillable = [

'name',

'email',

'password',

];

/**

* The attributes that should be hidden for serialization.

*

* @var array

*/

protected $hidden = [

'password',

'remember_token',

];

/**

* The attributes that should be cast.

*

* @var array

*/

protected $casts = [

'email_verified_at' => 'datetime',

];

}

app/models/Zone.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;

use Grimzy\LaravelMysqlSpatial\Types\Point;

use Grimzy\LaravelMysqlSpatial\Types\Polygon;

use Grimzy\LaravelMysqlSpatial\Types\LineString;

class Zone extends Model

{

use HasFactory;

use SpatialTrait;

protected $fillable = [

'name',

'city_full_address',

'city',

'state',

'city_latitude',

'city_longitude',

'zone_center_latitude',

'zone_center_longitude',

'map_polygon',

];

//geofancing related table fields needs to declare here

protected $spatialFields = [

//data type: polygon , default null

'map_polygon'

];

public function scopeIsDelete($query)

{

return $query->where('deleted', '0');

}

public function scopeContainsLatLng($query,$lat,$lng){

return $query->contains('map_polygon', new Point($lat, $lng));

}

}

app/models/Rider.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

class Rider extends Model

{

use HasFactory;

protected $fillable = [

'name',

'mobile_number',

'zone_id'

];

}

Step 8: Create Helper Files

here, we need to create Helper files. so let's create files:

app/Http/helpers.php

use App\Models\Zone;

function getAllZoneLatLngForGmap($city=NULL,$state=NULL,$dcHubId = NULL){

$latLongs = [];

$allZoneQuery = Zone::isDelete()->whereNotNull('map_polygon');

!empty($city) && $allZoneQuery->where('city',$city);

!empty($state) && $allZoneQuery->where('state',$state);

!empty($dcHubId) && $allZoneQuery->where('dc_hub_id',$dcHubId);

$allZone = $allZoneQuery->cursor();

if(!empty($allZone)){

foreach($allZone as $zone){

if(!empty($zone->map_polygon) && method_exists($zone->map_polygon,'getLineStrings') && !empty($zone->map_polygon->getLineStrings()) && isset($zone->map_polygon->getLineStrings()[0]) && !empty($zone->map_polygon->getLineStrings()[0]) ){

$currentPolygonLatLng = [];

foreach ($zone->map_polygon->getLineStrings()[0]->getPoints() as $value) {

$currentPolygonLatLng[] = [

'lat'=>$value->getLat(),

'lng'=>$value->getLng()

];

}

if(!empty($currentPolygonLatLng)){

$latLongs[$zone->id] = [

"id"=>$zone->id,

"city_latitude"=>$zone->city_latitude,

"city_longitude"=>$zone->city_longitude,

"zone_center_latitude"=>$zone->zone_center_latitude??$zone->city_latitude,

"zone_center_longitude"=>$zone->zone_center_longitude??$zone->city_longitude,

"zone_name"=>$zone->name,

"label"=>$zone->name." [$zone->city]",

"path"=> $currentPolygonLatLng,

"strokeColor"=> "#FF0000",

"strokeOpacity"=> 0.8,

"strokeWeight"=> 2,

"fillColor"=> "#FF0000",

"fillOpacity"=> 0.35

];

}

}

}

}

return $latLongs;

}

function findZoneByLatLng($lat = NULL, $lng = NULL){

return (!empty($lat) && !empty($lng)) ? Zone::isDelete()->containsLatLng($lat, $lng)->first() : [];

}

?>

Step 9: Create Blade Files

here, we need to create blade files. so let's create one by one files:

resources/views/welcome.blade.php

<!DOCTYPE html>

<html>

<head>

<title>Laravel 8 Datatables Tutorial - ItSolutionStuff.com </title>

<meta name="csrf-token" content="{{ csrf_token() }}">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />

<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">

<link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.js"></script>

<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

<script src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>

</head>

<body>

<div class="container">

<br><br><h1>Laravel 8 Datatables Tutorial ItSolutionStuff.com</h1><br><br>

<a href="{{ route('rider.create') }}" type="button" style="float:right;" class="btn btn-success mb-2">Create Rider</a><br>

<table class="table table-bordered data-table">

<thead>

<tr>

<th>No</th>

<th>Name</th>

<th>City Full Address</th>

<th width="100px">Action</th>

</tr>

</thead>

<tbody>

</tbody>

</table>

</div>

</body>

<script type="text/javascript">

$(function () {

var table = $('.data-table').DataTable({

processing: true,

serverSide: true,

ajax: "{{ route('index') }}",

columns: [

{data: 'id', name: 'id'},

{data: 'name', name: 'name'},

{data: 'city_full_address', name: 'city_full_address'},

{data: 'action', name: 'action', orderable: false, searchable: false},

]

});

});

</script>

</html>

resources/views/mapPolygon.blade.php

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<title></title>

<style type="text/css">

#map {

height: 100%;

}

#map-canvas {

height: 750px;

margin: 0px;

padding: 0px

}

.pac-card {

background-color: #fff;

border: 0;

border-radius: 2px;

box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);

margin: 10px;

padding: 0 0.5em;

font: 400 18px Roboto, Arial, sans-serif;

overflow: hidden;

font-family: Roboto;

padding: 0;

}

#pac-container {

padding-bottom: 12px;

margin-right: 12px;

}

.pac-controls {

display: inline-block;

padding: 5px 11px;

}

.pac-controls label {

font-family: Roboto;

font-size: 13px;

font-weight: 300;

}

#searchMapCityOnly {

background-color: #fff;

font-family: Roboto;

font-size: 15px;

font-weight: 300;

margin-left: 12px;

padding: 0 11px 0 13px;

text-overflow: ellipsis;

width: 400px;

margin-bottom: 15px;

}

#searchMapCityOnly:focus {

border-color: #4d90fe;

}

#floating-panel {

position: absolute;

top: 50px;

right: 9%;

z-index: 5;

background-color: #ffffffd1;

padding: 5px;

text-align: center;

font-family: "Roboto", "sans-serif";

line-height: 30px;

}

#floating-panel #save_polygon{

display: none;

}

#floating-panel #clear_polygon{

display: none;

}

</style>

</head>

<body>

<div class="content-body">

<div class="card">

<div class="card-header border-bottom mx-2 px-0">

<h4 class="card-title pb-1">{{!empty($zone->map_polygon) ? 'Update' : 'Assign'}} Zone Geofencing : {{$zone->name}} {{!empty($zone->city_full_address) ? "[".$zone->city_full_address."]" : ""}}</h4>

</div>

<div class="card-body">

<input type="hidden" name="zone_id" id="zone_id" value="{{ $id }}">

<input type="hidden" name="map_polygon" id="polygon" value="">

<input type="hidden" id="city" value="">

<input type="hidden" id="state" value="">

<input type="hidden" id="latitude" value="">

<input type="hidden" id="longitude" value="">

<div class="row">

<div class="col-md-12 text-center mt-1">

<input id="searchMapCityOnly" class="controls" type="text" placeholder="Search Cities" />

<div id="floating-panel">

<button type="button" id="save_polygon" onclick="save_polygon()" class="btn btn-icon btn-success waves-effect waves-light" data-toggle="tooltip" data-placement="top" data-original-title="Save Zone Geofencing">Save</button>

<button type="button" id="clear_polygon" onclick="clear_polygon()" class="btn btn-icon btn-danger waves-effect waves-light" data-toggle="tooltip" data-placement="top" data-original-title="Remove Zone Geofencing">Clear</button>

</div>

<div id="map-canvas" class="google_map_initialize"></div>

</div>

</div>

</div>

</div>

</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

<script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAP_API_KEY') }}&libraries=places,drawing,geometry&callback=initMap" async defer></script>

<script type="text/javascript">

var map; // Global declaration of the map

var drawingManager;

var newPolygon = [];

var newPolygonCenter = {};

let allZonePolygon = @json(getAllZoneLatLngForGmap($zone->city,$zone->state,$zone->dc_hub_id));

var map_center = { lat:"{{$mapCenter['lat']}}",lng:"{{$mapCenter['lng']}}" };

// NOTE: DO NOT CHANGE FUNCTION NAME, this function name is set in

function google_map_initialize() {

var myLatlng = new google.maps.LatLng({{$mapCenter['lat']}},{{$mapCenter['lng']}});

var myOptions = {

zoom: 12,

center: myLatlng,

streetViewControl: false,

mapTypeId: google.maps.MapTypeId.ROADMAP

}

//This custom function get's bound pincodes by polygon area

google.maps.Polygon.prototype.getBoundingBox = function() {

var bounds = new google.maps.LatLngBounds();

this.getPath().forEach(function(element,index) {

bounds.extend(element)

});

return(bounds);

};

//This custom function calculates center of polygon

google.maps.Polygon.prototype.getApproximateCenter = function() {

var boundsHeight = 0,

boundsWidth = 0,

centerPoint,

heightIncr = 0,

maxSearchLoops,

maxSearchSteps = 10,

n = 1,

northWest,

polygonBounds = this.getBoundingBox(),

testPos,

widthIncr = 0;

// Get polygon Centroid

centerPoint = polygonBounds.getCenter();

if (google.maps.geometry.poly.containsLocation(centerPoint, this)) {

// Nothing to do Centroid is in polygon use it as is

return centerPoint;

} else {

maxSearchLoops = maxSearchSteps / 2;

// Calculate NorthWest point so we can work out height of polygon NW->SE

northWest = new google.maps.LatLng(polygonBounds.getNorthEast().lat(), polygonBounds.getSouthWest().lng());

// Work out how tall and wide the bounds are and what our search increment will be

boundsHeight = google.maps.geometry.spherical.computeDistanceBetween(northWest, polygonBounds.getSouthWest());

heightIncr = boundsHeight / maxSearchSteps;

boundsWidth = google.maps.geometry.spherical.computeDistanceBetween(northWest, polygonBounds.getNorthEast());

widthIncr = boundsWidth / maxSearchSteps;

// Expand out from Centroid and find a point within polygon at 0, 90, 180, 270 degrees

for (; n <= maxSearchLoops; n++) {

// Test point North of Centroid

testPos = google.maps.geometry.spherical.computeOffset(centerPoint, (heightIncr * n), 0);

if (google.maps.geometry.poly.containsLocation(testPos, this)) {

break;

}

// Test point East of Centroid

testPos = google.maps.geometry.spherical.computeOffset(centerPoint, (widthIncr * n), 90);

if (google.maps.geometry.poly.containsLocation(testPos, this)) {

break;

}

// Test point South of Centroid

testPos = google.maps.geometry.spherical.computeOffset(centerPoint, (heightIncr * n), 180);

if (google.maps.geometry.poly.containsLocation(testPos, this)) {

break;

}

// Test point West of Centroid

testPos = google.maps.geometry.spherical.computeOffset(centerPoint, (widthIncr * n), 270);

if (google.maps.geometry.poly.containsLocation(testPos, this)) {

break;

}

}

return(testPos);

}

};

map = new google.maps.Map(document.getElementById("map-canvas"), myOptions);

setCurrentPolygon();

// setAllZonePolygon();

var autocomplete_options = {

componentRestrictions: {country: "IN"}

};

var searchMapCityOnly = document.getElementById('searchMapCityOnly');

var autocompleteCities = new google.maps.places.Autocomplete(searchMapCityOnly,autocomplete_options);

google.maps.event.addListener(autocompleteCities, 'place_changed', function () {

var place = this.getPlace();

if(place.geometry !== undefined){

if(place.geometry.location !== undefined){

map.fitBounds(place.geometry.viewport);

}else{

map.setCenter(place.geometry.location);

map.setZoom(12);

}

latFrom = place.geometry.location.lat();

lngFrom = place.geometry.location.lng();

// empty the value once selected from dropdown

document.getElementById('latitude').value ='';

document.getElementById('longitude').value ='';

document.getElementById('city').value='';

document.getElementById('state').value ='';

// set latitude longitude from geometry

document.getElementById('latitude').value = place.geometry.location.lat();

document.getElementById('longitude').value = place.geometry.location.lng();

for (const component of place.address_components) {

const addressType = component.types[0];

if (componentForm[addressType]) {

if (addressType == 'locality') {

const val = component[componentForm[addressType]];

document.getElementById('city').value = val;

}

if (addressType == 'administrative_area_level_1') {

const val = component[componentForm[addressType]];

document.getElementById('state').value = val;

}

}

}

}

});

$('.searchMapCityOnly').on('focus', function() {

selected = false;

}).on('blur', function() {

if (!selected) {

$(this).val('');

}

});

}

function checkMapLoaded() {

if (typeof google === "undefined") {

setTimeout(checkMapLoaded, 1000);

} else {

// do some work here

google_map_initialize();

}

}

checkMapLoaded();

// google.maps.event.addDomListener(window, 'load', google_map_initialize);

function setCurrentPolygon() {

const currentPolygon = @json($currentPolygon);

if(currentPolygon.path !== undefined){

const existingPolygon = new google.maps.Polygon(currentPolygon);

existingPolygon.setMap(map);

const marker = new google.maps.Marker({

position:new google.maps.LatLng(currentPolygon.zone_center_latitude, currentPolygon.zone_center_longitude),

map,

label: {

text: currentPolygon.zone_name,

color: "#203334",

fontWeight: "bold",

fontSize: "16px",

className: "badge badge-warning"

},

optimized: false,

});

map.setCenter(new google.maps.LatLng(currentPolygon.zone_center_latitude, currentPolygon.zone_center_longitude));

map.setZoom(13);

// newPolygon.push(existingPolygon);

$('#floating-panel').show();

$('#save_polygon').hide();

$('#clear_polygon').show();

setAllZonePolygon(currentPolygon.id);

}else{

$('#floating-panel').hide();

$('#save_polygon').hide();

$('#clear_polygon').hide();

drawingManager = new google.maps.drawing.DrawingManager({

drawingMode: google.maps.drawing.OverlayType.POLYGON,

drawingControl: true,

drawingControlOptions: {

position: google.maps.ControlPosition.TOP_CENTER,

drawingModes: [google.maps.drawing.OverlayType.POLYGON]

},

polygonOptions: {

editable: false

}

});

drawingManager.setMap(map);

google.maps.event.addListener(drawingManager, "overlaycomplete", function(event) {

var newShape = event.overlay;

newShape.type = event.type;

});

google.maps.event.addListener(drawingManager, "overlaycomplete", function(event) {

newPolygon = [];

newPolygonCenter = {};

var polygon_center = event.overlay.getApproximateCenter();

newPolygonCenter.lat = polygon_center.lat();

newPolygonCenter.lng = polygon_center.lng();

event.overlay.getPath().forEach(function(x){

newPolygon.push({'lat':x.lat(),'lng':x.lng()});

});

$('#save_polygon').show();

$('#clear_polygon').show();

$('#floating-panel').show();

// newPolygon

// $('#polygon').val(newPolygon);

});

setAllZonePolygon();

}

}

function setAllZonePolygon(exceptId){

if(allZonePolygon){

Object.values(allZonePolygon).forEach(function(newPolygon) {

if(exceptId !== undefined && exceptId != '' && exceptId == newPolygon.id){

}else{

new google.maps.Polygon(newPolygon).setMap(map);

new google.maps.Marker({

position:new google.maps.LatLng(newPolygon.zone_center_latitude, newPolygon.zone_center_longitude),

map,

label: {

text: newPolygon.zone_name,

color: "#ffffff",

fontWeight: "normal",

fontSize: "14px",

className: "badge badge-danger"

},

optimized: false,

});

}

});

}

}

function save_polygon(){

$('#floating-panel').hide();

$('#save_polygon').hide();

$('#clear_polygon').hide();

//iterate polygon vertices?

$.ajax({

type: "POST",

dataType: "json",

headers : {'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content')},

url: "{{route('zone.map_polygon.store')}}",

data: {"_token": "{{ csrf_token() }}",polygon_center:newPolygonCenter,map_polygon:newPolygon,zone_id: $('#zone_id').val()},

success: function(data){

if(!$.isEmptyObject(data.dberror)){

location.href = ($('#back_url').length && $('#back_url').val() != '') ? $('#back_url').val() : window.location;

}else{

location.href = ($('#back_url').length && $('#back_url').val() != '') ? $('#back_url').val() : window.location;

}

}

});

}

function clear_polygon(){

$('#floating-panel').hide();

$('#save_polygon').hide();

$('#clear_polygon').hide();

$.ajax({

type: "POST",

dataType: "json",

url: "{{route('zone.map_polygon.clear')}}",

data: {_token:'{{ csrf_token() }}',zone_id: $('#zone_id').val()},

success: function(data){

if(!$.isEmptyObject(data.dberror)){

location.reload(true);

}else{

location.reload();

}

}

});

}

function initMap() {

var mapProp= {

center:new google.maps.LatLng(51.508742,-0.120850),

zoom:5,

};

var map = new google.maps.Map(document.getElementById("googleMap"),mapProp);

}

</script>

</body>

</html>

resources/views/riderCreate.blade.php

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

<title></title>

</head>

<body>

<div class="container">

<br>

<center><h3>Create Rider</h3></center>

<form method="POST" action="{{ route('rider.create.store') }}">

@csrf

<div class="form-group">

<label>Rider Name</label>

<input type="text" name="name" class="form-control">

</div>

<div class="form-group">

<label>Rider Mobile Number</label>

<input type="text" name="mobile_number" class="form-control">

</div>

<div class="form-group">

<label>Assign Address</label>

<input type="text" id="searchMapInput" autocomplete="off" prevent-blank="1" class="form-control rm-r-br address_input" name="from_loc" placeholder="">

<input type="hidden" name="from_latitude" id="from_latitude" placeholder="">

<input type="hidden" name="from_longitude" id="from_longitude" placeholder="">

<input type="hidden" name="from_city" id="from_city" placeholder="">

<input type="hidden" name="from_state" id="from_state" placeholder="">

<input type="hidden" name="from_state_short" id="from_state_short" placeholder="">

<input type="hidden" name="from_pincode" id="from_pincode" placeholder="">

<input type="hidden" name="from_loc_transporter" id="from_loc_transporter" placeholder="">

</div>

<button type="submit" class="btn btn-primary">Submit</button>

</form>

</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

<script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAP_API_KEY') }}&libraries=places,drawing,geometry&callback=initMap" async defer></script>

<script type="text/javascript">

function initMap() {

var options = {

//types: ['(regions)'],

//types: ['(cities)'],

componentRestrictions: {country: "IN"}

};

var selected = false;

var input = document.getElementById('searchMapInput');

if (input) {

var autocompleteTo = new google.maps.places.Autocomplete(input,options);

//document.getElementById('searchMapInput1').value ='';

google.maps.event.addListener(autocompleteTo, 'place_changed', function () {

var place = this.getPlace();

document.getElementById('from_latitude').value ='';

document.getElementById('from_longitude').value ='';

document.getElementById('from_city').value='';

document.getElementById('from_state').value ='';

document.getElementById('from_state_short').value ='';

document.getElementById('from_pincode').value ='';

document.getElementById('from_loc_transporter').value ='';

latTo = place.geometry.location.lat();

lngTo = place.geometry.location.lng();

document.getElementById('from_latitude').value = latTo;

document.getElementById('from_longitude').value = lngTo;

for (const component of place.address_components) {

const addressType = component.types[0];

if (componentForm[addressType]) {

if (addressType == 'locality') {

const val = component[componentForm[addressType]];

document.getElementById('from_city').value = val;

}

if (addressType == 'administrative_area_level_1') {

const val = component[componentForm[addressType]];

document.getElementById('from_state').value = val;

}

if (addressType == 'administrative_area_level_1') {

const val = component[componentForm['administrative_area_level_2']];

document.getElementById('from_state_short').value = val;

}

if (addressType == 'postal_code') {

const val = component[componentForm[addressType]];

document.getElementById('from_pincode').value = val;

}

}

}

document.getElementById('from_loc_transporter').value =document.getElementById('from_city').value+', '+document.getElementById('from_state').value;

});

}

$('#searchMapInput').on('focus', function() {

selected = false;

}).on('blur', function(e) {

if (!selected) {

if($(this).attr('prevent-blank') == '1'){

setTimeout(function(){

if(autocompleteTo.getPlace().address_components !== undefined){}else{$('#searchMapInput').val('');}

},400);

}else{

$(this).val('');

}

}

});

var options = {

//types: ['(regions)'],

//types: ['(cities)'],

componentRestrictions: {country: "IN"}

};

}

</script>

</body>

</html>

Now we are ready to run our example so run bellow command so quick run:

php artisan serve

Now you can open bellow URL on your browser:

localhost:8000/zone

zone :

rider :

map_polygon :

I hope it can help you...

#Laravel 10