Adding multiple tweets into an InfoWindow bubble

So far, in our interactive social map, we added markers in each location that we clicked on and opened up an InfoWindow with the tweet information. Our next step will be to enable multiple tweets to live inside our InfoWindow by adding a pagination system into our window.

Adding multiple tweets into an InfoWindow bubble

Getting ready

To get through this recipe you must be knee deep into our holistic chapter. If you dropped in just now, it would be a good idea to go back to the start of this chapter as we are going to continue from where we left off in the previous recipe.

How to do it...

We are still in our JavaScript file and we will continue to add code and adjust our code to get multiple Twitter posts into our social map.

  1. Let's start by changing our Twitter search to return up to 100 values per search. We are doing this because there is a limit on how many times we can call the Twitter API. So, we will try to grab as much as we can in one hit (this code should be around line 30).
    var searchLink = 'http://search.twitter.com/search.json?q='+ searchKeyWord+ '&geocode=' + geocode +"&result_type=recent&rpp=100";
    
  2. As we are now going to treat all the tweets that come back, we will need to change our references to send to our TwitterMaker marker the full array (changes highlighted in the code snippet).
      google.maps.event.addListener(map, 'click', function(e) {
        //console.log(e.latLng);
          var searchKeyWord = 'html5';
          var geocode=e.latLng.lat() + "," + e.latLng.lng()+",50km";
          var searchLink = 'http://search.twitter.com/search.json?q='+ searchKeyWord+ '&geocode=' + geocode +"&result_type=recent&rpp=100";
      
      
          $.getJSON(searchLink, function(data) {
            showTweet(data.results,e.latLng);
        });
        
        });
    
    
      function showTweet(a,latLng){
          if(!a) a = [{text:'No tweet found in this area for this topic'}];
          //console.log(obj);	
    
          var marker = new TwitterMarker({
                map: map,
                position: latLng,
                tweet: a,
                title:a[0].text    });			
    
      }
    }
  3. We want to update the TwitterMarker constructor to include our array and quick information on it, such as the total tweets and the current tweet we are in. We will need a way to identify our object, and as such, we will give it an ID as well (more on that in a few steps).
     function TwitterMarker(opt){
      this.count = opt.tweet.length;
      this.crnt = 0;
      this.id = TwitterMarker.aMarkers.push(this);
      this.aTweets = opt.tweet;
      var strTweet = this.buildTwitterHTML(opt.tweet[0])
      this.infoWindow = new google.maps.InfoWindow({
          maxWidth:300,
          content:strTweet
      });
    
        
      this.setValues(opt);
      this.infoWindow.open(this.map,this);
      google.maps.event.addListener(this, 'click', this.onMarkerClick);
    }
  4. We want to store, in a static array that can be accessed from any place in our code, all the markers created. To do that, we will add a new status array to our TwitterMarker class:
    TwitterMarker.prototype = new google.maps.Marker();
    TwitterMarker.aMarkers= [];
    
  5. In the buildTwitterHTML method, we want to add in back/next links that will be visible to users from InfoWindow:
    TwitterMarker.prototype.buildTwitterHTML = function(twt){
      var str;
      if(twt.from_user_name){
       str =	  "<span><img style='float: left' src='"+twt.profile_image_url+"' />"+
             "<b>" +twt.from_user_name + "</b><br/><a href ='http://twitter.com/"
            + twt.from_user + "'>@"+twt.from_user+"</a><br/> "
            + twt.location + "</span>"
            + "<p>"+twt.text+"</p>";
      
        if(this.count>1){
          str+="<span style='absolute; bottom: 0;
              right: 0px; width:80px'>";
          if(this.crnt!=0) str+="<a href='javascript:TwitterMarker.aMarkers["+(this.id-1)+"].prev();'>&lt;</a> ";
          str+= (this.crnt+1) + " of " + this.count;
          if(this.crnt<(this.count-1)) str+= "<a href='javascript:TwitterMarker.aMarkers["+(this.id-1)+"].next();'>&gt;</a> ";
          str+= "</span>"	
        }
      }else{
        str="The 50 Kilometer radius around this point did not message this value";
      }
      return str;
    }
  6. Let's now add the next and prev methods.
    TwitterMarker.prototype.next =function(){
      this.infoWindow.close();
      this.infoWindow.content = this.buildTwitterHTML(this.aTweets[++this.crnt]);
      this.infoWindow.open(this.map,this);
      return false;	
    }
    
    TwitterMarker.prototype.prev =function(){
      this.infoWindow.close();
      this.infoWindow.content = this.buildTwitterHTML(this.aTweets[--this.crnt]);
      this.infoWindow.open(this.map,this);
      return false;	
    }

Load the HTML file, and you should find a working InfoWindow that can accommodate up to 100 tweets per click.

How it works...

Our first change was to change the number of results coming back from the Twitter search API. This change forced us to change the references in our code from referring directly to the first object returned to focus on the full results object and sending it to our TwitterMarker constructor. This change created a few smaller changes in the flow of the information within the constructor as well.

Our goals are to create two buttons that will update our InfoWindow. This is an issue as we need a two-way connection between our marker and its InfoWindow. Until now, all our communication with the InfoWindow was one way. The easiest way for us to solve this problem and bypass the Google interface is to create a static array that will store all markers and refer to our static marker when we trigger buttons inside the InfoWindow object. All we need to do is add a variable direction to our class name.

TwitterMarker.aMarkers= [];

By adding our variable directly into the TwitterMarker class, we can now refer to it directly at any point and it will not get duplicated in our objects (as it's not part of the prototype). Now that we have an array, it's time for us to go back into our TwitterMarker constructor and send a new reference to this array each time we create a new TwitterMarker object. Another benefit we get out of doing this is that we automatically get a unique identifier (ID) for each marker as the returned number will always be a unique number for our needs.

this.id = TwitterMarker.aMarkers.push(this);

In this one line of code, we perform all of the tasks we talked about in the previous paragraph. The array push method returns the new length of the array.

Now that we have a way to refer to our marker and have got an identifier, it's time for us to go back into the buildTwitterHTML method and add into the rendered HTML two href buttons that will trigger the right marker when the next/previous selections are clicked.

Before we delve into that, we want to check and validate that we have more than one Twitter message that came back; if there is none, there is no point in adding the new logic, and we would be introducing a bug if we had next/previous logic for an item that has only one item.

if(this.count>1){

}

By the following if statement, we figure out whether we are currently in the first Twitter message, and if not we shall add the back button:

if(this.crnt!=0) str+="<a href='javascript:TwitterMarker.aMarkers["+(this.id-1)+"].prev();'>&lt;</a> ";

This might look like a huge mess but, if we ignore the HTML and focus on the actual JavaScript that will be triggered when the button is pressed, this is what we will get:

TwitterMarker.aMarkers["+(this.id-1)+"].prev();

The this.id-1 parameter will be replaced with the actual current number:

As this is rendered into a string to be parsed as HTML, the value that will be integrated into the HTML will be hardcoded. Let's see this in a real case to make it clear. The first array ID would be 0, and as such the prev button would look like this code statement:

TwitterMarker.aMarkers[0].prev();

Now the logic is starting to reveal itself. By grabbing the marker from the array that is our current element, all that is left for us to do is trigger the prev method and let it take over.

The same logic happens for our other end. The only condition is that we are not in the last Twitter result and if not we call the next method:

if(this.crnt<(this.count-1)) str+= "<a href='javascript:TwitterMarker.aMarkers["+(this.id-1)+"].next();'>&gt;</a> ";

There you have it! The core of our logic is in place.

If we wanted we could have created our InfoWindow by wrapping a <div> tag with a unique ID and just called it and made direct updates to our content (try doing that by yourself as that would be a better solution). Instead, we are working with the limitations of the InfoWindow. As we cannot update the full bucket container while it's open, we need to close it to update it and then open it again. Thus our logic in both the next and prev methods is similar; both have a limitation on the change of the actual value that is being rendered.

TwitterMarker.prototype.next =function(){
  this.infoWindow.close();
  this.infoWindow.content = this.buildTwitterHTML(this.aTweets[++this.crnt]);
  this.infoWindow.open(this.map,this);
  return false;	
}

TwitterMarker.prototype.prev =function(){
  this.infoWindow.close();
  this.infoWindow.content = this.buildTwitterHTML(this.aTweets[--this.crnt]);
  this.infoWindow.open(this.map,this);
  return false;	
}

All the logic is the same and limited to the highlighted code snippet. If you aren't familiar with this shortcut, the ++ and -- operators when set before a variable, enable us to add/subtract 1 from it and update it before its value is sent on. Thus in one line, we can both change the number in the variable and send that newly created number to continue its tasks.

In the case of the next method, we want to grab the next tweet, while for the prev method, we want to grab the previous tweet.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.174.95