Hi my friends, in the last week I have an awesome task I liked to share, the client asked me to build a reservation service form which using google map service to find the closest providers to client location by detecting his location and search in the database by latitude and longtuide ,it was in this scenario :

1- User opens the form, once he did, Geolocation API will detect his location, send latitude and longitude to Google map and set it to hidden inputs.

2- Then Google map displays his location with information window with the sentence (Your Location Is Here), after this draw a circle around your location with 30 kilometers.

3- Under Google map, there's a (show positions) button related to a RelatedLocationAjax() function by onclick() event, when the user clicks the button the Ajax function will be fired to call a closest_locations() function in the controller.

4- closest_locations () function will call get_closest_locations() function in the model which has a query to select all providers by ServiceId and about 30 kilometers distance around current latitude and longitude to the user.

5- closest_locations() will take all results as array and Output to JSON array.

6- In the view, you will take the ajax result from RelatedLocationAjax() function and pass to add_markers(result) function which responsible to push all providers to the map as markers with their information

7-After drawing all markers you will see the count of providers around your location displays above the map, as example (10 Providers Available), and the map will reset position again to fit to your location with all markers to sure that all markers displayed on the map.

What Will You Learn In This Tutorial?

-Find Your Location with Geolocation API

-Integrate Geolocation with Google Map To Display Your Location On Google Map

-Store get coordinates from google maps in database MySQL Nearest Locations to Your Location With Mysql

-Display locations dynamically with google markers

-Draw circle around all markers

-Use info window dynamically to display users information

-Pick up latitude and longitude from markers and geolocation to input form or ajax request

-Integrate all these features with codeigniter

This is the theory side, let’s do it practically my friends to describe it step by step as we always do.

1- Create Database Schema :

Import Services Table and Providers to Your database "demo"

-- -- Table structure for table `ci_providers` -- CREATE TABLE `ci_providers` ( `user_id` int(11) NOT NULL, `fullname` varchar(40) NOT NULL, `lat` float(10,6) NOT NULL, `lng` float(10,6) NOT NULL, `email` varchar(254) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `ci_providers` -- INSERT INTO `ci_providers` (`user_id`, `fullname`, `lat`, `lng`, `email`) VALUES (1, 'ahmed', 29.956051, 30.913300, 'webeasystep@gmail.com'), (2, 'fakhr', 29.957001, 30.914499, 'info@webeasystep.com'); -- -- Table structure for table `ci_services` -- CREATE TABLE `ci_services` ( `ServiceId` int(11) NOT NULL, `user_id` int(11) NOT NULL, `ServiceName` varchar(50) DEFAULT NULL, `ServiceDesc` varchar(255) DEFAULT NULL, `CreatedAt` int(11) NOT NULL, `Order` int(11) NOT NULL, `Status` tinyint(1) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Services Table'; -- -- Dumping data for table `ci_services` -- INSERT INTO `ci_services` (`ServiceId`, `user_id`, `ServiceName`, `ServiceDesc`, `CreatedAt`, `Order`, `Status`) VALUES (1, 1, 'Service Name', 'Service Describtion', 1488098862, 1, 1), (2, 2, 'Service Name', 'Service Describtion', 1488098862, 1, 1);

2- Create Services.php Controller with three functions

book_service() function to load the book_service view and index to auto redirect when open the services controller

// this function will redirect to book service page function index() { $this->book_service(); } // this function to load service book page function book_service() { $this->view('content/book_service'); }

closest_locations() function to receive ajax request and return closest providers as json output , we use foreach loop to change result by adding link in the info window (optionally)

// this function receive ajax request and return closest providers function closest_locations(){ $location =json_decode( preg_replace('/\\\"/',"\"",$_POST['data'])); $lan=$location->longitude; $lat=$location->latitude; $ServiceId=$location->ServiceId; $base = base_url(); $providers= $this->services_model->get_closest_locations($lan,$lat,$ServiceId); $indexed_providers = array_map('array_values', $providers); // this loop will change retrieved results to add links in the info window for the provider $x = 0; foreach($indexed_providers as $arrays => &$array){ foreach($array as $key => &$value){ if($key === 1){ $pieces = explode(",", $value); $value = "$pieces[1]<a href='$base$pieces[0]'>More..</a>"; } $x++; } } echo json_encode($indexed_providers,JSON_UNESCAPED_UNICODE); }

Data returned as json will be like this :

var locations = [ ["Ahmed Fakhr","Do this service 1 <a href=''>more</a>", "29.957051,30.914529", "http://maps.google.com/mapfiles/ms/icons/blue.png"], ["Ali", "Do this service 1 <a href=''>more</a>", "29.956051,30.913529", "http://maps.google.com/mapfiles/ms/icons/green.png"], ["Mahmoud","Do this service 1 <a href=''>more</a>","29.955051,30.912529", "http://maps.google.com/mapfiles/ms/icons/red.png"], ];

3- Create Services_model.php Controller with one function

This function will select the only closeset providers in 30 kilometers distance around current latitude and longitude by using Haversine Formula , and filter results by service type

class Services_model extends CI_Model { // get closest providers // around 30 kilo meters from your location // by using latitude , longtuide and service id // function get_closest_locations($lng,$lat,$ServiceId){ $results= $this->db->query("SELECT fullname,CONCAT(ci_providers.user_id,',',ServiceDesc) AS dscr,CONCAT(lat,',', lng) as pos,'http://maps.google.com/mapfiles/ms/icons/green.png' AS icon, ( 6371 * acos( cos( radians({$lat}) ) * cos( radians( `lat` ) ) * cos( radians( `lng` ) - radians({$lng}) ) + sin( radians({$lat}) ) * sin( radians( `lat` ) ) ) ) AS distance FROM ci_providers INNER JOIN ci_services ON ci_services.user_id = ci_providers.user_id AND ci_services.ServiceId = $ServiceId HAVING distance <= 30 ORDER BY distance ASC ")->result_array(); return $results; } } 4- Create book_service.php in views directory First, add the form that collect servce id , available providers counter , display map, and fill the hidden inputs for current latitude and longtuide

you will also notice click event related to show closest providers button

<form id="ServiceRequest" action="<?= current_url() ?>" method='post'> <!-- dropdown service id !--> <div class="form-group"> <label class="control-label">ServiceType:</label> <select name="Service_type" class="form-control" id="ServiceId"> <option>--all--</option> <option value="1" selected>Service One</option> <option value="2">Service Two</option> </select> </div> <div class="form-group"> <!-- provider_counter service id !--> <label for="provider_counter" class="control-label">Closest Providers :</label> <div class="text-lg-center alert-danger"id="info"></div> <!-- display map !--> <div id="map" style="height: 600px; width:800px;"></div> <!-- current latituide and longtuide !--> <input id="lat" type="hidden" value="" /> <input id="lng" type="hidden" value="" /> <button type="button" onclick="RelatedLocationAjax();">show_closest_providers</button> </div> <div id='submit_button'> <input class="btn btn-success" type="submit" name="submit" value="add comment"/> </div> </form>

The second part of this file is the most important part which do all the process in javascript to google map api 3 and with ajax requests, i describe all code with comments, so i recommended to read all comments to understand what we do here , i made i readable as much possible

<script> var lat = document.getElementById("lat"); // this will select the input with id = lat var lng = document.getElementById("lng"); // this will select the input with id = lng var info = document.getElementById("info"); // this will select the current div with id = info var ServiceId = document.getElementById("ServiceId"); // this will select the input with id = ServiceId var locations = []; var km = 30; // this kilometers used to specify circle wide when use drawcircle function var Crcl ; // circle variable var map; // map variable var mapOptions = { zoom: 11, center: {lat:24.774265, lng:46.738586} }; // map options var markers = []; // markers array ,we will fill it dynamically var infoWindow = new google.maps.InfoWindow(); // information window ,we will use for our location and for markers // this will initiate when load the page and have all function initialize() { // set the map to the div with id = map and set the mapOptions as defualt map = new google.maps.Map(document.getElementById('map'), mapOptions); var infoWindow = new google.maps.InfoWindow({map: map}); // get current location with HTML5 geolocation API. if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position) { var pos = { lat: position.coords.latitude, lng: position.coords.longitude }; lat.value = position.coords.latitude ; lng.value = position.coords.longitude; info.nodeValue = position.coords.longitude; // set the current posation to the map and create info window with (Here Is Your Location) sentense infoWindow.setPosition(pos); infoWindow.setContent('Here Is Your Location.'); // set this info window in the center of the map map.setCenter(pos); // draw circle on the map with parameters DrowCircle(mapOptions, map, pos, km); }, function() { // if user block the geolocatoon API and denied detect his location handleLocationError(true, infoWindow, map.getCenter()); }); } else { // Browser doesn't support Geolocation handleLocationError(false, infoWindow, map.getCenter()); } } // to handle user denied function handleLocationError(browserHasGeolocation, infoWindow, pos) { infoWindow.setPosition(pos); infoWindow.setContent(browserHasGeolocation ? 'Error: User Has Denied Location Detection.' : 'Error: Your browser doesn\'t support geolocation.'); } // to draw circle around 30 kilometers to current location function DrowCircle(mapOptions, map, pos, km ) { var populationOptions = { strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#FF0000', fillOpacity: 0.35, map: map, center: pos, radius: Math.sqrt(km*500) * 100 }; // Add the circle for this city to the map. this.Crcl = new google.maps.Circle(populationOptions); } // this function to get providers with ajax request function RelatedLocationAjax() { $.ajax({ type: "POST", url: "<?= base_url() ?>services/closest_locations", dataType: "json", data:"data="+ '{ "latitude":"'+ lat.value+'", "longitude": "'+lng.value+'", "ServiceId": "'+ServiceId.value+'" }', success:function(data) { // when request is successed add markers with results add_markers(data); } }); } // this function to will draw markers with data returned from the ajax request function add_markers(data){ var marker, i; var bounds = new google.maps.LatLngBounds(); var infowindow = new google.maps.InfoWindow(); // display how many closest providers avialable document.getElementById('info').innerHTML = " Available:" + data.length + " Providers<br>"; for (i = 0; i < data.length; i++) { var coordStr = data[i][2]; var coords = coordStr.split(","); var pt = new google.maps.LatLng(parseFloat(coords[0]), parseFloat(coords[1])); bounds.extend(pt); marker = new google.maps.Marker({ position: pt, map: map, icon: data[i][3], address: data[i][1], title: data[i][0], html: data[i][0] + "<br>" + data[i][1] }); markers.push(marker); google.maps.event.addListener(marker, 'click', (function (marker, i) { return function () { infowindow.setContent(marker.html); infowindow.open(map, marker); } }) (marker, i)); } // this is important part , because we tell the map to put all markers inside the circle, // so all results will display and centered map.fitBounds(this.Crcl.getBounds()); } google.maps.event.addDomListener(window, 'load', initialize); </script> <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDNyLsAhFt4hIZKeNJYC244jPPayM0GhrY&callback=initialize"> </script>

The Finall result will be Like his

Download Link