Search code examples
google-mapscoldfusionmultidimensional-arraycfquery

Coldfusion + Google Map API v3 — info window and set bounds


Simply, I seem to be able to write code that either creates a clickable marker for a pop-up infoWindow OR gets the bounds of the returned markers and resets the map extent and zoom levels. I can't seem to combine the two. My example below will nicely set the extent of the map to the results of the query. But I don't quite know how to include the addListener event to the marker given how my loop is structured, and that in the var mapOptions, I set center: gbounds.getCenter(). These two issues seem to complicate my ability to add events to the map or marker.

    <cfquery name="myquery" datasource="xxxx">
       SELECT name, lat, long
       FROM tblMain
    </cfquery>

    <cfset bridgeCoord=arrayNew(1)>

    <cfloop query="myquery">
   <cfset bridge[CurrentRow] = structNew()>
   <cfset bridge[CurrentRow].lat=lat>
       <cfset bridge[CurrentRow].long=longX>
          <cfset bridge[CurrentRow].name=name>
     </cfloop>



     <script>
       $(document).ready(function() {
       var gbounds = new google.maps.LatLngBounds();
        var markers = [];


       <cfloop index="mi" array="#bridge#">
           <cfoutput> 
               //make the point
               var point = new google.maps.LatLng(#mi.lat#,#mi.long#);
               gbounds.extend(point);
               //make the marker
               var marker = new google.maps.Marker({position: point, title:"#mi.name#"});
               markers[markers.length] = marker; 
            </cfoutput>
       </cfloop>

              var mapOptions = {
                    zoom:3,
                    mapTypeControl: true,
                    mapTypeControlOptions: {
                    style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
                       },
                     mapTypeId:google.maps.MapTypeId.ROADMAP,
                     center:gbounds.getCenter()
                        };



        var map = new google.maps.Map(document.getElementById('myMap'), mapOptions);

           map.fitBounds(gbounds);

           for(var i=0; i<markers.length; i++) markers[i].setMap(map);

      });

fyi, I've also tried organizing part of the code, like below. this works great for adding the click event to the marker but then I can't seem to use my center:gbounds.getCenter() or map.fitBounds() elements b/c the mapOptions get set first and passed to the new map variable and gbounds hasn't been defined by that point. Hardcoding lat/long to center: seems to just keep it there.

       function initialize() {

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


  var myOptions = {
    zoom: 4,
    center: new google.maps.LatLng(39.0,-94.1),
    mapTypeControl: true,
    mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
    navigationControl: true,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  }
  map = new google.maps.Map(document.getElementById("myMap"),
                                myOptions);

  google.maps.event.addListener(map, 'click', function() {
        infowindow.close();
        });

  // Add markers to the map
  // Set up three markers with info windows 

    <cfloop index="mi" array="#bridge#">
        <cfoutput>

             //make the point
               var point = new google.maps.LatLng(#mi.lat#,#mi.long#);
            gbounds.extend(point);
            //make the marker
               var marker = createMarker(point, "#mi.name#", "#mi.name#")

        </cfoutput>
    </cfloop>


}
 map.fitBounds(gbounds);;

function createMarker(latlng, tip, html) {
    var contentString = html;
    var marker = new google.maps.Marker({
        position: latlng,
        title: tip,
        map: map,
        });

    google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(contentString); 
        infowindow.open(map,marker);
        });
}


var infowindow = new google.maps.InfoWindow(
  { 
    size: new google.maps.Size(150,50)
  });

UPDATE 10/12: Got it to work. There is indeed a typo in Tyler's code but it's minor. I'm not sure how well I can take this code and expand on it since I'm not very versed in jQuery but this is a start. One thing it doesn't do that I'm struggling with is how to deal w/the map when zero markers are returned. It is possible in my query that no records can be returned. What happens is that the map draws but it is centered and zoomed in the middle of the ocean. I figured it should default to the center I set up (center: new google.maps.LatLng(39, -94.1) but it doesn't.

Replace: 

var $markers = $container.find(".map-marker");

with

var $markers = $container.find(".mapMarker");

Solution

  • EDIT

    I actually just dealt with this a month or so ago, here is some modified code from what worked for me to make it more like yours.

    Google Maps API v3 and jQuery 1.4.2 (though this should prolly work with any version of jQuery, and porting it to strait javascript or another library should be cake)

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
    <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
    
    <cfquery name="mi" datasource="xxxx">
    SELECT name, lat, long, content
    FROM tblName
    </cfquery>
    
    <ul id="mapMarkers">
    <cfoutput query="mi">
        <li class="mapMarker" data-latitude="#mi.lat#" data-longitude="#mi.long#">
            <div class="info-window">
            <h1 class="name">#mi.name#</a></h1>
            <div class="content">#mi.content#</div>
            </div>
        </li>
    </cfoutput>
    </ul>
    <div id="map"></div>
    
    <script type="text/javascript">
    $(function() {
        var $container = $("#mapMarkers");
    
        var $map = $("#map");
        var $markers = $container.find(".map-marker");
    
        var bounds = new google.maps.LatLngBounds();
        var infowindow = new google.maps.InfoWindow({
            maxWidth: 300
        });
    
        var gmap = new google.maps.Map($map[0], {
            zoom: 8
            , mapTypeId: google.maps.MapTypeId.ROADMAP
        });
    
        $markers.each(function(){
            $this = $(this);
            var latitude = $this.attr("data-latitude");
            var longitude = $this.attr("data-longitude");
            var content = $this.find(".info-window").remove().html();
            var latlng = new google.maps.LatLng(latitude, longitude);
    
            bounds.extend(latlng);
    
            var marker = new google.maps.Marker({
                position: latlng
                , map: gmap
            });
    
            google.maps.event.addListener(marker, 'click', function() {
                infowindow.setContent(content);
                infowindow.open(this.map, this);
            });
    
            google.maps.event.addListener(gmap, 'click', function() {
                infowindow.close();
            });
    
            $this.click(function(e, el) {
                e.preventDefault();
    
                infowindow.setContent(content);
                infowindow.open(gmap, marker);
            })
        });
    
        if($markers.length > 1)
            gmap.fitBounds(bounds);
        else
            gmap.setCenter(bounds.getCenter());
    
        $container.hide();
    });
    </script>
    

    END EDIT

    First you have to move the map and mapOptions to the top. Then inside your loop just add the addListener to the map for the marker:

    <cfloop index="mi" array="#bridge#">
       <cfoutput> 
           //make the point
           var point = new google.maps.LatLng(#mi.lat#,#mi.long#);
           gbounds.extend(point);
           //make the marker
           var marker = new google.maps.Marker({position: point, title:"#JSStringFormat(mi.name)#", map:map});
           google.maps.event.addListener(marker, 'click', function() {
               infowindow.setContent("#JSStringFormat(mi.content)#");
               infowindow.open(this.map, this);
           });
           markers[markers.length] = marker; 
        </cfoutput>
    </cfloop>
    

    Things to note:

    I added JSStringFormat to the name and content variables.

    There is a map option in the marker creation that you can just add "map:map" to it so you don't have to run the for loop at the bottom.

    Also, since you are now creating the map ahead of the markers you will move the zoom and center options to the bottom.

    if(markers.length > 1)  
        map.fitBounds(gbounds);  
    else  
        map.setCenter(gbounds.getCenter());  
    

    Also once last thing:

    Instead of

    markers[markers.length] = marker;
    

    You can use this

    markers.push(marker);