Google Maps API v3 Practical Implementation

Image Tutorials

In our new tutorial I would like to give you one interesting example of Google Maps API (v3) implementation. Let assume, that you have website with own members. And, you need to add possibility to save map positions of your members at your website. Or, you have to store map coordinates for something else (as example – business locations). I think that this is one of usual tasks in webdevelopment. For our practical realization I took the base of our chat system (I removed everything unnecessary except registration). Now, I will add here next features: index page block with map of 20 recent locations of members, profile page map (with single marker), and page to set coordinates at map.

Live Demo
download in package

Now – download the source files and lets start coding !


Step 1. SQL

If you have already had `cs_profiles` table in your database (due of tests), you don’t need remove previous version, keep it, and add second one new table `latlng268`:

01 CREATE TABLE `cs_profiles` (
02   `id` int(10) unsigned NOT NULL auto_increment,
03   `namevarchar(255) NOT NULL default '',
04   `first_name` varchar(255) NOT NULL default '',
05   `last_name` varchar(255) NOT NULL default '',
06   `email` varchar(255) NOT NULL default '',
07   `passwordvarchar(40) NOT NULL default '',
08   `salt` varchar(10) NOT NULL default '',
09   `status` enum('active','passive'NOT NULL default 'active',
10   `role` tinyint(4) unsigned NOT NULL default '1',
11   `about` varchar(255) NOT NULL,
12   `date_reg` datetime NOT NULL default '0000-00-00 00:00:00',
13   `date_nav` datetime NOT NULL default '0000-00-00 00:00:00',
14   `color` varchar(6) NOT NULL,
15   `rate` float NOT NULL,
16   `rate_count` int(11) NOT NULL,
17   PRIMARY KEY  (`id`)
18 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
19 CREATE TABLE `latlng268` (
20   `id` int(11) unsigned NOT NULL auto_increment,
21   `profile` int(11) unsigned NOT NULL,
22   `namevarchar(255) NOT NULL default '',
23   `lat` double NOT NULL,
24   `lng` double NOT NULL,
25   PRIMARY KEY (`id`)
26 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Step 2. HTML

This is Login / Join form template:

templates/login_form.html

01 <div class="column">
02     <h3>Google Maps API v3 Practical Implementation</h3>
03     <p>Our demonstration contains next features: member registration, and possibility to add own custom marker at google map.</p>
04 </div>
05 <div class="column">
06     <div class="tabs_container">
07         <ul class="tabs">
08             <li class="active"><h3>Log In</h3></li>
09             <li><h3>Join</h3></li>
10         </ul>
11     </div>
12     <div class="nav_container">
13         <form class="login_form" action="index.php" method="post" id="1">
14             <label>Username:</label><input type="text" name="username">
15             <label>Password:</label><input type="password" name="password">
16             <input type="submit" name="Login" value="Login">
17         </form>
18         <form class="join_form" action="index.php" method="post" id="2" style="display: none;">
19             <label>Full name:</label>
20             <input type="text" id="username" name="username" placeholder="Your name" maxlength="128" title="Your name" required>
21             <label>First name:</label>
22             <input type="text" id="firstname" name="firstname" placeholder="Your first name" maxlength="128" title="Your first name">
23             <label>Last name:</label>
24             <input type="text" id="lastname" name="lastname" placeholder="Your last name" maxlength="128" title="Your last name">
25             <label>Email:</label>
26             <input type="text" id="email" name="email" placeholder="Your email" maxlength="128" title="Format: *@gmail.com" pattern=".*@gmail\.com" required>
27             <label>Password:</label>
28             <input type="text" id="password" name="password" maxlength="128" title="Password" required>
29             <label>Repeat Password:</label>
30             <input type="text" id="password" name="password" maxlength="128" title="Repeat password" required oninput="checkpass(this)">
31             <input type="submit" name="Join" value="Join">
32         </form>
33     </div>
34     <div>Powered by <a href="https://www.script-tutorials.com/" target="_blank" title="Script Tutorials">Script Tutorials</a>
35     </div>
36 </div>
37 <script>
38 $(document).ready(function(){
39     $('.tabs li h3').click(function () {
40       $('.tabs li').removeClass('active');
41       $(this).parent().addClass('active');
42       $('.nav_container form').hide();
43       var index = $('.tabs li h3').index(this);
44       $('.nav_container form').eq(index).show();
45       return false;
46     });
47 });
48 function checkpass(input) {
49     if (input.value != document.getElementById('password').value) {
50         input.setCustomValidity('Password must match.');
51     } else {
52         input.setCustomValidity('');
53     }
54 }
55 </script>

Very easy form, isn’t it? Next template – small logout template (with link to page to set position):

templates/logout_form.html

1 <div class="column">
2     <span style="float:right"><a href="index.php?logout">Log Out</a></span>
3     <h3>Hello {name}</h3>
4     <h3>Your status:</h3>
5     <div>{status}</div>
6     <h3><a href="setpos.php">Set my position</a></h3>
7 </div>

Again – very easy template. Next template – index (main) page template:

templates/main_page.html

01 <!DOCTYPE html>
02 <html lang="en" >
03 <head>
04     <title>Google Maps API v3 Practical Implementation</title>
05     <link href="css/main.css" rel="stylesheet" type="text/css" />
06     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
07     <script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
08     <script src="js/update.js"></script>
09 </head>
10 <body>
11     <header>
12         <h2>Google Maps API v3 Practical Implementation</h2>
13         <a href="https://www.script-tutorials.com/google-maps-api-v3-practical-implementation/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
14     </header>
15     <div class="clear"></div>
16     <div class="container" id="con1">
17         {form}
18     </div>
19     <div class="container" id="con2">
20         <h2>Main Map</h2>
21         <div class="gmap">
22             <div id='gmap_canvas' style="position:relative; width:100%; height:550px;"></div>
23         </div>
24     </div>
25     <div class="sidebar">
26         <div>
27             <h2>Online Members Block</h2>
28             {online_members}
29         </div>
30         <div>
31             <h2>Last Members</h2>
32             {profiles}
33         </div>
34     </div>
35     <script type="text/javascript">
36         var map;
37         function initialize() {
38             var iCoordX = 40;
39             var iCoordY = -75;
40             var myLatlng = new google.maps.LatLng(iCoordX, iCoordY);
41             var myOptions = {
42                 zoom: 6,
43                 center: myLatlng,
44                 mapTypeId: google.maps.MapTypeId.ROADMAP
45             };
46             map = new google.maps.Map(document.getElementById('gmap_canvas'), myOptions);
47             var aMarkers = new Array();
48             var aMarkerInfos = new Array();
49             {add_markers}
50         }
51         google.maps.event.addDomListener(window, 'load', initialize);
52     </script>
53 </body>
54 </html>

Here you can see google maps initialization – this is very easy JS script, where we need prepare map options and initialize map object, and then – we need to add 20 (optonal) recent positions. Next template – profile page template:

templates/profile_page.html

01 <!DOCTYPE html>
02 <html lang="en" >
03 <head>
04     <title>Google Maps API v3 Practical Implementation</title>
05     <link href="css/main.css" rel="stylesheet" type="text/css" />
06     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
07     <script src="js/update.js"></script>
08 </head>
09 <body>
10     <header>
11         <h2>Google Maps API v3 Practical Implementation</h2>
12         <a href="https://www.script-tutorials.com/google-maps-api-v3-practical-implementation/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
13     </header>
14     <div class="clear"></div>
15     <div class="container">
16         <div class="column">
17             <h3>Name: {name}</h3>
18             <h3>First name: {fname}</h3>
19             <h3>Last name: {lname}</h3>
20             <h3>About: {about}</h3>
21             <h3>Date Reg: {datereg}</h3>
22         </div>
23         <div class="column">
24             <p><a href="index.php">Back to main page</a></p>
25         </div>
26     </div>
27     {map}
28     <div class="sidebar">
29         <div>
30             <h2>Online Members Block</h2>
31             {online_members}
32         </div>
33         <div>
34             <h2>Last Members</h2>
35             {profiles}
36         </div>
37     </div>
38 </body>
39 </html>

At this page, we will see single profile view page, and, if he (that member) has set his coordinates, we will see google map at his page. Next template – html template of that profile’s map:

templates/profile_map.html

02 <div class="clear"></div>
03 <div class="container">
04     <div id='gmap_canvas' style="position:relative; width:100%; height:400px;"></div>
05 </div>
06 <script type="text/javascript">
07     var map;
08     var marker;
09     function initialize() {
10         // set profile coordinates
11         var myLatlng = new google.maps.LatLng({lat}, {lng});
12         var myOptions = {
13             zoom: 6,
14             center: myLatlng,
15             mapTypeId: google.maps.MapTypeId.ROADMAP
16         };
17         map = new google.maps.Map(document.getElementById('gmap_canvas'), myOptions);
18         // prepare info window
19         var infowindow = new google.maps.InfoWindow({
20             content: "{name}"
21         });
22         // prepare new marker
23         marker = new google.maps.Marker({
24             position: myLatlng,
25             map: map,
26             title: "{name}",
27             animation: google.maps.Animation.DROP
28         });
29         google.maps.event.addListener(marker, 'click', function() {
30             infowindow.open(map,marker);
31         });
32     }
33     // initialization
34     google.maps.event.addDomListener(window, 'load', initialize);
35 </script>

You can see here new google map initialization in certain coordinates with marker, and we add event listener (when we click at marker) to display popup info (InfoWindow). And finally, we should prepare last one template file – for page where member can setup own coordinates:

templates/setpos_page.html

01 <!DOCTYPE html>
02 <html lang="en" >
03 <head>
04     <title>Google Maps API v3 Practical Implementation</title>
05     <link href="css/main.css" rel="stylesheet" type="text/css" />
06     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
07     <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
08 </head>
09 <body>
10     <header>
11         <h2>Google Maps API v3 Practical Implementation</h2>
12         <a href="https://www.script-tutorials.com/google-maps-api-v3-practical-implementation/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
13     </header>
14     <div class="clear"></div>
15     <div class="container">
16         <h3><a href="index.php">Back to main page</a></h3>
17         <div style="margin:10px;">Type full street address into field and click on FIND to center map on location.</div>
18         <div style="margin:10px;"><input id="gmap_where" type="text" name="gmap_where" /><input id="find" type="button" value="Find" name="find" onclick="findAddress(); return false;" /></div>
19         <div id='gmap_canvas' style="position:relative; width:100%; height:400px;margin-bottom:25px;"></div>
20         <hr />
21         <h3>Please confirm your position</h3>
22         <form class="login_form" action="setpos.php" method="post" name="setpos_form">
23             <input type="text" name="lat" value="{lat}" />
24             <input type="text" name="lng" value="{lng}" />
25             <input type="submit" name="Confirm" value="Confirm positions" />
26         </form>
27     </div>
28     <script type="text/javascript">
29         var geocoder;
30         var map;
31         var marker;
32         function initialize() {
33             geocoder = new google.maps.Geocoder();
34             // set initial coordinates
35             var myLatlng = new google.maps.LatLng({lat}, {lng});
36             var myOptions = {
37                 zoom: 6,
38                 center: myLatlng,
39                 mapTypeId: google.maps.MapTypeId.ROADMAP
40             };
41             map = new google.maps.Map(document.getElementById('gmap_canvas'), myOptions);
42             // prepare info window
43             var infowindow = new google.maps.InfoWindow({
44                 content: 'My position'
45             });
46             // prepare new marker
47             marker = new google.maps.Marker({
48                 position: myLatlng,
49                 map: map,
50                 title: 'My position',
51                 draggable:true,
52                 animation: google.maps.Animation.DROP
53             });
54             google.maps.event.addListener(marker, 'click', function() {
55                 infowindow.open(map,marker);
56             });
57             google.maps.event.addListener(marker, 'dragstart', function() {
58                 infowindow.close();
59             });
60             google.maps.event.addListener(marker, 'dragend', function(obj) {
61                 map.setCenter(obj.latLng);
62                 $('form[name=setpos_form] input[name=lat]').val( obj.latLng.$a );
63                 $('form[name=setpos_form] input[name=lng]').val( obj.latLng.ab );
64             });
65         }
66         // initialization
67         google.maps.event.addDomListener(window, 'load', initialize);
68         // find custom address function
69         function findAddress() {
70             var address = document.getElementById("gmap_where").value;
71             geocoder.geocode( { 'address': address}, function(results, status) {
72             if (status == google.maps.GeocoderStatus.OK) {
73                 map.setCenter(results[0].geometry.location);
74                 marker.position = results[0].geometry.location;
75                 $('form[name=setpos_form] input[name=lat]').val( results[0].geometry.location.$a );
76                 $('form[name=setpos_form] input[name=lng]').val( results[0].geometry.location.ab );
77             } else {
78                 alert("Geocode was not successful for the following reason: " + status);
79             }
80             });
81         }
82     </script>
83 </body>
84 </html>

This Javascript is more complicated, I added here possibility to drag marker, and also I added search panel, so now we can search by exact names.

Step 3. CSS

Now, it’s time to apply styles:

css/main.css

001 /* page layout */
002 *{
003     margin:0;
004     padding:0;
005 }
006 body {
007     background-color:#eee;
008     color:#fff;
009     font:14px/1.3 Arial,sans-serif;
010 }
011 header {
012     background-color:#212121;
013     box-shadow: 0 -1px 2px #111111;
014     display:block;
015     height:70px;
016     position:relative;
017     width:100%;
018     z-index:100;
019 }
020 header h2{
021     floatleft;
022     font-size:22px;
023     font-weight:normal;
024     margin-left:10px;
025     margin-right:20px;
026     padding:22px 0;
027 }
028 header a.stuts,a.stuts:visited{
029     floatleft;
030     text-decoration:none;
031     color:#fcfcfc;
032     font-size:14px;
033     height:70px;
034     line-height:70px;
035 }
036 header .stuts span {
037     font-size:22px;
038     font-weight:bold;
039     margin-left:5px;
040 }
041 /* main styles */
042 a {
043     color#333;
044     outlinenone;
045     text-decorationnone;
046 }
047 a:hover,a:active {
048     outline0;
049     text-decorationnone;
050 }
051 .container {
052     background-color#F2F4F8;
053     border1px solid rgba(0000.4);
054     box-shadow: 2px 0 2px -2px #B2B9C9 inset;
055     color#333333;
056     margin20px;
057     overflowhidden;
058     padding20px;
059     positionrelative;
060     width70%;
061     float:left;
062 }
063 #con1.container {
064     width300px;
065 }
066 #con2.container {
067     width500px;
068 }
069 .container h2 {
070     margin-bottom10px;
071 }
072 .column {
073 }
074 .column:first-child {
075 }
076 .column > * {
077     margin-bottom10px;
078 }
079 .clear {
080     clearboth;
081     font-size1px;
082 }
083 .sidebar {
084     background-color#F2F4F8;
085     border-left1px solid rgba(0000.4);
086     box-shadow: 2px 0 2px -2px #B2B9C9 inset;
087     color#333333;
088     displayblock;
089     height100%;
090     padding10px;
091     positionfixed;
092     right0;
093     top0;
094     width250px;
095     z-index101;
096 }
097 .sidebar > div {
098     margin-bottom30px;
099 }
100 /* tabs section */
101 .tabs_container {
102     margin0;
103 }
104 .tabs {
105     overflowhidden;
106 }
107 .tabs li {
108     floatleft;
109     list-stylenone;
110 }
111 .tabs li h3:first-child {
112     margin-left10px
113 }
114 .tabs li h3 {
115     border1px solid #ddd;
116     border-bottom-width0;
117     displayblock;
118     margin0 2px 0 0;
119     padding6px 10px 4px
120 }
121 .tabs li.active h3 {
122     background-color#ccc;
123     border1px solid #ddd;
124     border-bottom-width0;
125     -moz-border-radius: 4px 4px 0 0;
126     -ms-border-radius: 4px 4px 0 0;
127     -o-border-radius: 4px 4px 0 0;
128     -webkit-border-radius: 4px 4px 0 0;
129     border-radius: 4px 4px 0 0;
130 }
131 .tabs li h3:hover {
132     background-color#bbb;
133     cursorpointer;
134 }
135 .tabs li.active h3:hover {
136     background-color#ccc;
137     cursornormal;
138 }
139 .nav_container form {
140     background-color#ccc;
141     displayblock;
142     padding15px;
143 }
144 .login_form input,.login_form label,
145 .join_form input,.join_form label {
146     displayblock;
147     margin-bottom10px;
148 }
149 input[type=text], input[type=password], input[type=submit] {
150     -moz-border-radius: 5px;
151     -ms-border-radius: 5px;
152     -o-border-radius: 5px;
153     -webkit-border-radius: 5px;
154     border-radius: 5px;
155     border-stylegroove;
156 }
157 input[type=text], input[type=password] {
158     border-stylegroove;
159     font-size16px;
160     height25px;
161     margin-right10px;
162     width200px;
163 }
164 input[type=submit],
165 input[type=file]{
166     cursorpointer;
167     font-size16px;
168     font-weightbold;
169     height35px;
170     padding5px;
171 }
172 /* profiles */
173 .profiles {
174     overflowhidden;
175 }
176 .profiles a {
177     displayblock;
178 }
179 .profiles div {
180     overflowhidden;
181 }
182 .profiles div a {
183     color#333333;
184     displayblock;
185     padding2px 22px 2px 10px;
186     positionrelative;
187 }
188 .profiles div a:hover {
189     background-color#E0E4EE;
190     box-shadow: 2px 0 2px -2px #B2B9C9 inset;
191 }
192 .profiles div img {
193     border0;
194     floatleft;
195     height48px;
196     margin-right8px;
197     width48px;
198 }
199 .profiles div p {
200     displayblock;
201     line-height28px;
202     overflowhidden;
203     text-overflow: ellipsis;
204     white-spacenowrap;
205 }
206 .profiles div img.status_img {
207     border0;
208     displayblock;
209     height7px;
210     margin-top-6px;
211     positionabsolute;
212     right5px;
213     top50%;
214     width7px;
215 }

Step 4. PHP

Our PHP files are separated into two types: action files and classes. I think that you have already saw sources of most of classes of chat project. So, first two files are same:

classes/CLogin.php

classes/CMySQL.php

We don’t need to re-publish sources of both files again. Both are available in our package. But I updated Profiles class file (I removed all unnecessary here, now it contains only registration and few other functions):

classes/CProfiles.php

01 <?php
02 define('PROFILE_TIMEOUT', 5); // 5 mins
03 // Profiles class
04 class CProfiles {
05     // constructor
06     function CProfiles() {}
07     // profile registration
08     function registerProfile() {
09         $sUsername $GLOBALS['MySQL']->escape($_POST['username']);
10         $sFirstname $GLOBALS['MySQL']->escape($_POST['firstname']);
11         $sLastname $GLOBALS['MySQL']->escape($_POST['lastname']);
12         $sEmail $GLOBALS['MySQL']->escape($_POST['email']);
13         $sPassword $GLOBALS['MySQL']->escape($_POST['password']);
14         if ($sUsername && $sEmail && $sPassword) {
15             // check if already exist
16             $aProfile $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `email`='{$sEmail}'");
17             if ($aProfile['id'] > 0) {
18                 $sErrors '<h2>Another profile with same email already exist</h2>';
19             else {
20                 // generate Salt and Cached password
21                 $sSalt $this->getRandCode();
22                 $sPass = sha1(md5($sPassword) . $sSalt);
23                 // add new member into database
24                 $sSQL = "
25                     INSERT INTO `cs_profiles` SET
26                     `name` = '{$sUsername}',
27                     `first_name` = '{$sFirstname}',
28                     `last_name` = '{$sLastname}',
29                     `email` = '{$sEmail}',
30                     `password` = '{$sPass}',
31                     `salt` = '{$sSalt}',
32                     `status` = 'active',
33                     `role` = '1',
34                     `date_reg` = NOW();
35                 ";
36                 $GLOBALS['MySQL']->res($sSQL);
37                 // autologin
38                 $GLOBALS['CLogin']->performLogin($sUsername$sPassword);
39             }
40         }
41     }
42     // get random code (for salt)
43     function getRandCode($iLen = 8) {
44         $sRes '';
45         $sChars "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
46         for ($i = 0; $i $iLen$i++) {
47             $z = rand(0, strlen($sChars) -1);
48             $sRes .= $sChars[$z];
49         }
50         return $sRes;
51     }
52     // get profiles block
53     function getProfilesBlock($iLim = 20, $bOnlineOnly = false) {
54         $iPLimit = PROFILE_TIMEOUT;
55         $sOnlineSQL = ($bOnlineOnly) ? 'AND (`date_nav` > SUBDATE(NOW(), INTERVAL ' $iPLimit ' MINUTE))' '';
56         $sSQL = "
57             SELECT `cs_profiles`.*,
58             if (`date_nav` > SUBDATE(NOW(), INTERVAL {$iPLimit} MINUTE ), 1, 0) AS `is_online`
59             FROM `cs_profiles`
60             WHERE `status` = 'active'
61             {$sOnlineSQL}
62             ORDER BY `date_reg` DESC
63             LIMIT {$iLim}
64         ";
65         $aProfiles $GLOBALS['MySQL']->getAll($sSQL);
66         // create list of messages
67         $sCode '';
68         foreach ($aProfiles as $i => $aProfile) {
69             $sName $aProfile['name'];
70             $iPid $aProfile['id'];
71             $sOnline = ($aProfile['is_online'] == 1) ? '<img alt="Google Maps API v3 Practical Implementation" src="images/online.png" class="status_img" />' '';
72             $sCode .= '<div id="'.$iPid.'" title="'.$sName.'"><a href="profile.php?id='.$iPid.'"><p>'.$sName.'</p>'.$sOnline.'</a></div>';
73         }
74         $sClass = ($bOnlineOnly) ? 'profiles online_profiles' 'profiles';
75         return '<div class="'.$sClass.'">' $sCode '</div>';
76     }
77     // get profile info
78     function getProfileInfo($i) {
79         $sSQL = "
80             SELECT *
81             FROM `cs_profiles`
82             WHERE `id` = '{$i}'
83         ";
84         $aInfos $GLOBALS['MySQL']->getAll($sSQL);
85         return $aInfos[0];
86     }
87 }
88 $GLOBALS['CProfiles'] = new CProfiles();

Now lets review our main files:

index.php

01 <?php
02 // set error reporting level
03 if (version_compare(phpversion(), '5.3.0''>=') == 1)
04   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
05 else
06   error_reporting(E_ALL & ~E_NOTICE);
07 require_once('classes/CMySQL.php'); // service class to work with database
08 require_once('classes/CLogin.php'); // service class to work with login processing
09 require_once('classes/CProfiles.php'); // service class to work with profiles
10 // join processing
11 if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
12     $GLOBALS['CProfiles']->registerProfile();
13 }
14 // login system init and generation code
15 $sLoginForm $GLOBALS['CLogin']->getLoginBox();
16 if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active') {
17     if ($_GET['action'] == 'update_last_nav') { // update last navigate time
18         $iPid = (int)$_SESSION['member_id'];
19         if ($iPid) {
20             $GLOBALS['MySQL']->res("UPDATE `cs_profiles` SET `date_nav` = NOW() WHERE `id` = '{$iPid}'");
21         }
22         exit;
23     }
24 }
25 // get profiles lists
26 $sProfiles $GLOBALS['CProfiles']->getProfilesBlock();
27 $sOnlineMembers $GLOBALS['CProfiles']->getProfilesBlock(10, true);
28 // prepare set of markers for global map
29 $sMarkers '';
30 $aRecentMarkers $GLOBALS['MySQL']->getAll("SELECT * FROM `latlng268` ORDER BY `id` DESC LIMIT 20");
31 foreach ($aRecentMarkers as $i => $sMInfo) {
32     if ($sMInfo['lat'] != 0 && $sMInfo['lng'] != 0) {
33         $sUnitLocation str_replace('"'''$sMInfo['name']);
34         $sMarkers .= <<<EOF
35 aMarkerInfos[{$sMInfo['id']}] = new google.maps.InfoWindow({content: "{$sUnitLocation}"});
36 aMarkers[{$sMInfo['id']}] = new google.maps.Marker({position: new google.maps.LatLng({$sMInfo['lat']}, {$sMInfo['lng']}), map: map, title: "{$sUnitLocation}"});
37 google.maps.event.addListener(aMarkers[{$sMInfo['id']}], 'click'function() {
38     aMarkerInfos[{$sMInfo['id']}].open(map,aMarkers[{$sMInfo['id']}]);
39 });
40 EOF;
41     }
42 }
43 // draw common page
44 $aKeys array(
45     '{form}' => $sLoginForm,
46     '{profiles}' => $sProfiles,
47     '{online_members}' => $sOnlineMembers,
48     '{add_markers}' => $sMarkers
49 );
50 echo strtr(file_get_contents('templates/main_page.html'), $aKeys);

Pay attention to code where we add markers for map. By default, there are only 20 last markers. You always can play with that limit. Our next file – profile page:

profile.php

01 <?php
02 // set error reporting level
03 if (version_compare(phpversion(), '5.3.0''>=') == 1)
04   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
05 else
06   error_reporting(E_ALL & ~E_NOTICE);
07 require_once('classes/CMySQL.php'); // service class to work with database
08 require_once('classes/CLogin.php'); // service class to work with login processing
09 require_once('classes/CProfiles.php'); // service class to work with profiles
10 // get basic info about profile
11 $iPid = (int)$_GET['id'];
12 $aInfo $GLOBALS['CProfiles']->getProfileInfo($iPid);
13 $sName $aInfo['name'];
14 $sFName $aInfo['first_name'];
15 $sLName $aInfo['last_name'];
16 $sAbout $aInfo['about'];
17 $sDate $aInfo['date_reg'];
18 // get map block
19 $sMap '';
20 $aPosInfo $GLOBALS['MySQL']->getRow("SELECT * FROM `latlng268` WHERE `profile` = '{$iPid}'");
21 if ($aPosInfo['id']) {
22     $aPosKeys array(
23         '{lat}' => $aPosInfo['lat'],
24         '{lng}' => $aPosInfo['lng'],
25         '{name}' => str_replace('"'''$sName)
26     );
27     $sMap strtr(file_get_contents('templates/profile_map.html'), $aPosKeys);
28 }
29 // get profiles listings
30 $sProfiles $GLOBALS['CProfiles']->getProfilesBlock();
31 $sOnlineMembers $GLOBALS['CProfiles']->getProfilesBlock(10, true);
32 // draw common page
33 $aKeys array(
34     '{id}' => $iPid,
35     '{name}' => $sName,
36     '{fname}' => $sFName,
37     '{lname}' => $sLName,
38     '{about}' => $sAbout,
39     '{datereg}' => $sDate,
40     '{profiles}' => $sProfiles,
41     '{online_members}' => $sOnlineMembers,
42     '{map}' => $sMap
43 );
44 echo strtr(file_get_contents('templates/profile_page.html'), $aKeys);

As you can see – most of the code are already commented. So I hope that this code are pretty understandable. And, in the long run – our new file which we use to set our coordinates:

setpos.php

01 <?php
02 // set error reporting level
03 if (version_compare(phpversion(), '5.3.0''>=') == 1)
04   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
05 else
06   error_reporting(E_ALL & ~E_NOTICE);
07 require_once('classes/CMySQL.php'); // service class to work with database
08 require_once('classes/CLogin.php'); // service class to work with login processing
09 require_once('classes/CProfiles.php'); // service class to work with profiles
10 $iPid = (int)$_SESSION['member_id'];
11 // save coordinates
12 if ($_POST && $_POST['Confirm']) {
13     $dLat = (double)$_POST['lat'];
14     $dLng = (double)$_POST['lng'];
15     if ($iPid && $dLat && $dLng) {
16         $aInfo $GLOBALS['MySQL']->getRow("SELECT * FROM `latlng268` WHERE `profile` = '{$iPid}'");
17         if ($aInfo['id']) {
18             $GLOBALS['MySQL']->res("UPDATE `latlng268` SET `lat` = '{$dLat}', `lng` = '{$dLng}' WHERE `profile` = '{$iPid}'");
19         else {
20             $aPInfo $GLOBALS['CProfiles']->getProfileInfo($iPid);
21             $sName $GLOBALS['MySQL']->escape($aPInfo['name']);
22             $GLOBALS['MySQL']->res("INSERT INTO `latlng268` SET `lat` = '{$dLat}', `lng` = '{$dLng}', `profile` = '{$iPid}', `name` = '{$sName}'");
23         }
24         header('Location: profile.php?id=' $iPid);
25     }
26 }
27 // find profile coordinates
28 $aPosInfo $GLOBALS['MySQL']->getRow("SELECT * FROM `latlng268` WHERE `profile` = '{$iPid}'");
29 $dLat = 40;
30 $dLng = -75;
31 if ($aPosInfo['id']) {
32     $dLat $aPosInfo['lat'];
33     $dLng $aPosInfo['lng'];
34 }
35 // draw page
36 $aKeys array(
37     '{lat}' => $dLat,
38     '{lng}' => $dLng
39 );
40 echo strtr(file_get_contents('templates/setpos_page.html'), $aKeys);

Step 5. Javascript

I added that simple script in order to update (periodically) time of our last navigation (simulation of online status)

js/update.js

01 $(function() {
02     // Update last navigation time feature
03     updateLastNav = function() {
04         $.getJSON('index.php?action=update_last_nav'function() {
05             // refresh last nav time
06             setTimeout(function(){
07                updateLastNav();
08             }, 180000); // 3 mins
09         });
10     }
11     updateLastNav();
12 });

Live Demo
download in archive

Conclusion

I hope that our new tutorial was very useful and interesting for you. If you want to share your ideas, or you noticed any weakness – don’t hesitate to contact us. Good luck and welcome back!

Rate article