Texan78
Texan78

Reputation: 687

Place markers from JSON data for Google MAPS API v3

I have a MySQL DB that I have created a PHP script to pull that data into JSON format. I know need to take that JSON output and create markers on a Google Map. Seems simple but, I only need the markers to show if one of the values from the JSON output returns true. I will outline how the markers should display.

JSON Output

gpsStatus": "true", = Show streamOffline.png icon/marker

If gpsStatus & "streamStatus": "true", Then show the streamOnine.png icon/marker

If gpsStatus": "false" the show or remove from map the streamOffline.png icon/marker

So basically the only time a icon/maker should be shown is if gpsStatus": "true" but depending on the status of streamStatus determines if it shows streamOffline.png icon/marker or streamOnline.png icon/marker.gpsStatus": "false" removes or doesn't show a marker regardless of the streamStatus value.

Another twist is I am trying to have the markers to update/refresh without reloading the map based on that data from the lat/lng values from the JSON output. If am also trying to pull the other values from the JSON output so I can put the data in infowidows etc.

I have been searching for months on how to do this both on Stack, Google searches and YouTube and trying different things (too many things to list and post here) but, most of the examples ether don't apply to me or are outdated and I cannot get working for my needs. I am horrible when it comes to JavaScript and Google Maps.

So is there anyone who could give me an example based on my situation of how to take that JSON data and loop through it to plot dynamic markers on the map based on the value/s of some of the objects and refresh/update them when the lat/lng values change and then remove the marker when the "gpsStatus" shows false as well as know what keys to to use in other areas?

Here is my JSON output.

http://stream.dfwstormforce.com/test/api.php

Here is my test map with a static marker and what it should look like with populated data that I am trying to accomplish.

http://stream.dfwstormforce.com/test/test.html

Upvotes: 5

Views: 3290

Answers (3)

Risan Bagja Pradana
Risan Bagja Pradana

Reputation: 4674

Here's the fully working example of your page. On this simplified version, your JSON API http://stream.dfwstormforce.com/test/api.php will be fetched periodically every 10 seconds, and the qualified data (gpsStatus = true) will be displayed on the map.

The displayed marker icon will depend on the streamStatus value.

<!doctype html>
<html>
<head>
    <title>Google Map Test Page</title>
    <style>
        html, body, .map {
            width: 100%;
            height: 100%;
            background-color: #eee;
        }
    </style>
</head>
<body>
    <div id="map" class="map"></div>

    <script>
        var map = null;
        var markers = [];

        // Reload interval in milliseconds.
        var reloadInterval = 10000;

        var intervalId = window.setInterval(loadData, reloadInterval);

        function initMap() {
            var northTexasPosition = { lat: 32.836, lng: -96.995 };

            map = new google.maps.Map(document.getElementById('map'), {
                center: northTexasPosition,
                zoom: 7,
                mapTypeControl: true,
                mapTypeControlOptions: {
                    style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
                    position: google.maps.ControlPosition.TOP_RIGHT
                },
            });

            loadData();
        }

        // Load the markers data from API and display them on the map.
        function loadData() {
            $.getJSON('http://stream.dfwstormforce.com/test/api.php', function(responsedata) {
                clearMarkers();

                $.each(responsedata.streamers, function (key, item) {
                    item.lat = parseCoordinateNumber(item.lat);
                    item.lng = parseCoordinateNumber(item.lng);
                    item.gpsStatus = parseBoolean(item.gpsStatus);
                    item.streamStatus = parseBoolean(item.streamStatus);

                    if (shouldAddToMap(item)) {
                        addToMap(item);
                    }
                });
            });
        }

        // Clear all markers from the map.  
        function clearMarkers() {
            $.each(markers, function (key, marker) {
                marker.setMap(null);
            });

            markers = [];
        }

        // Add marker to the map.
        function addToMap(item) {
            var marker = new google.maps.Marker({
                position: { lat: item.lat, lng: item.lng },
                title: item.DisplayName + ', ' + item.ChaserLocation,
                icon: getIcon(item.streamStatus),
                map: map
            });

            markers.push(marker);
        }

        // Get the appropiate image url for marker icon.
        function getIcon(streamStatus) {
            if (! streamStatus) {
                return 'http://stream.dfwstormforce.com/images/icons/streamOffline.png';
            }

            return 'http://stream.dfwstormforce.com/images/icons/streamOnline.png';
        }

        // Should we add the marker to the map?
        function shouldAddToMap(item) {
            if ($.type(item.lat) === 'null' || $.type(item.lng) === 'null') {
                return false;
            }

            return item.gpsStatus === true;
        }

        // Parse coordinate number like 'W96.38188' to appropiate decimal value: -96.38188
        // return null if it's invalid.
        function parseCoordinateNumber(val) {
            if ($.type(val) === 'number') {
                return parseFloat(val);
            }

            if ($.type('val') !== 'string') {
                return null;
            }

            val = val.trim();

            if (val.length === 0) {
                return null;
            }

            var directionPart = val.substr(0, 1).toUpperCase();
            var valuePart = parseFloat(val.substring(1));

            if ($.inArray(directionPart, ['N', 'E']) >= 0) {
                return isNaN(valuePart) ? null : valuePart;
            }

            if ($.inArray(directionPart, ['S', 'W']) >= 0) {
                return isNaN(valuePart) ? null : -valuePart;
            }

            val = parseFloat(val);

            return isNaN(val) ? null : val;
        }

        // Parse boolean value.
        function parseBoolean(val) {
            if ($.type(val) === 'boolean') {
                return val;
            }

            if (val === 1) {
                return true;
            }

            if (val === 0) {
                return false;
            }

            if ($.type('val') !== 'string') {
                return null;
            }

            val = val.trim().toUpperCase();

            if (val === 'TRUE') {
                return true;
            }

            if (val === 'FALSE') {
                return false;
            }

            return null;
        }
    </script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async="defer"></script>
</body>
</html>

As pointed out by @Dawood Awan, the main problem is your lat and lng data used a degree's direction (N, S, E, W). You have to parse these data into an appropiate coordinate value in decimal. Here's part of my code above that will parse the lat and lng:

function parseCoordinateNumber(val) {
    if ($.type(val) === 'number') {
        return parseFloat(val);
    }

    if ($.type('val') !== 'string') {
        return null;
    }

    val = val.trim();

    if (val.length === 0) {
        return null;
    }

    var directionPart = val.substr(0, 1).toUpperCase();
    var valuePart = parseFloat(val.substring(1));

    if ($.inArray(directionPart, ['N', 'E']) >= 0) {
        return isNaN(valuePart) ? null : valuePart;
    }

    if ($.inArray(directionPart, ['S', 'W']) >= 0) {
        return isNaN(valuePart) ? null : -valuePart;
    }

    val = parseFloat(val);

    return isNaN(val) ? null : val;
}

It will allow the coordinate value in number or a string with the direction (N,S,E, or W). I did not handle the correct latitude or longitude range, but you can add that as well. The function will return null if the given coordinate is invalid.

Also don't forget to replace the google maps API with yours:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async="defer"></script>

Hope this help you!

Upvotes: 1

Dawood Awan
Dawood Awan

Reputation: 7338

The problem is when you are plotting your latitude and longitude as a Marker, after getting the response from the $.getJSON you are converting them using parseFloat only - but the lat/lng contain N,E,W and S characters so the parseFloat method is failing.

i.e. you lat/lng are like this

        "lat": "N32.95421",
        "lng": "W96.38196",

So when you use parseFloat in this part of the code - the result is NaN

$.each(responsedata.streamers, function(i, value) {
  if (value.lat != "" && value.lng != "") {

    var myLat = parseFloat(value.lat);

    // HERE on this line check in your CONSOLE the result is NaN
    console.log(myLat);

    var marker = new google.maps.Marker({
      position: {
        lat: value.lat,
        lng: value.lng
      },
      animation: google.maps.Animation.DROP,
      title: value.DisplayName + ',' + value.ChaserLocation,
      map: map
    });
  }
});

So what you need to do is convert the latitude and longitude to decimal formats first:

$.each(responsedata.streamers, function(i, value) {
  if (value.lat != "" && value.lng != "") {
    var myLat = ConvertPoint(value.lat); //parseFloat(value.lat);

    var myLng = ConvertPoint(value.lng);

    var marker = new google.maps.Marker({
      position: {
        lat: myLat,
        lng: myLng
      },
      animation: google.maps.Animation.DROP,
      title: value.DisplayName + ',' + value.ChaserLocation,
      //icon: getcustomicons(value),
      map: map
    });

    //marker.addlistener('click', function() {
    //      infowindow.open(map, marker);
    //   });
  }
});

Add this function to your JS code

  function ConvertPoint(stringVal) {
  // This function will convert you lat, lng - instead of using parseFloat

    var direction = stringVal.substring(0, 1);

    var withOutChar = stringVal.substring(1);

    var point = parseFloat(withOutChar);

    if (direction == "S" || direction == "W") {
      point = point * -1;
    } // Don't do anything for N or E

    return point;
  }

Try this let me know if the Markers plot correctly.

Related to multiple markers and info windows and then refresh them if they change you will have to do some more work - but first get the marker to plot - try without custom icon for now. keep it simple then move on to the next step.

Upvotes: 1

Dharminder Singh
Dharminder Singh

Reputation: 64

I have tried to change the code by what i understood from above description, you may extend it now.

            var customIcons = {
                  offline: {
                    icon: 'http://stream.dfwstormforce.com/images/icons/gpsOffline.png'
                  },
                  online: {
                    icon: 'http://stream.dfwstormforce.com/images/icons/gpsOnline.png'
                  }
                };

            var getCustomIcons= function (streamdata){
                    var iconUrl=customIcons.online;
                      if(streamdata.gpsStatus=='false')
                      {
                        iconUrl=customIcons.offline.icon;
                      }else
                      {
                        iconUrl=customIcons.online.icon;
                      }
                      return iconUrl;
                }


               $.getJSON('http://stream.dfwstormforce.com/inc/api.php', function(responsedata) { 
                        $.each( responsedata.streamers, function(i, value) {
                             if(value.lat!="" && value.lng!="" )
                             {
                                  var marker = new google.maps.Marker({
                                      position: {lat: parseFloat(value.lat), lng: parseFloat(value.lng)},
                                      animation: google.maps.Animation.DROP,
                                      title: value.DisplayName+','+ value.ChaserLocation,
                                      icon: getCustomIcons(value),
                                      map: map
                                    });

                                  marker.addListener('click', function() {
                                          infowindow.open(map, marker);
                                        });
                            }
                         });
            });

Upvotes: 3

Related Questions