Tag Archive: programming


In the world of gaming, SDL provides the entire necessary infrastructure. This would have become clear from the past parts of the series. But infrastructure is to a game what skeleton is to a human body. But without muscles, no locomotion is possible. So working with the analogy of body, SDL provides the skeletal structure to build up the game whereas the flesh, blood and skin are provided by 2D and 3D graphics libraries. In the current plethora of 3D libraries, OpenGL stands out on various accounts. The most significant of them is its compatibility with almost all the platforms and graphics cards. This even reflects in the architecture of SDL as SDL can create and use OpenGL contexts on several platforms. Such architecture helps the game programmer to use all the sub-systems of SDL seamlessly in conjunction with OpenGL to provide most effective games and gaming environments. In this article I will discuss how to use SDL and OpenGL together where gaming infrastructure is provided by SDL and animation as well as rendering is being handled by OpenGL. The first section would discuss the steps required to integrate OpenGL with SDL. The second section would utilize the pointers provided in the first section to create an application having animation(basic) using OpenGL. That is the agenda for the current discussion.

Initialization- Bringing OpenGL into Picture:

 

In SDL all the sub-systems are initialized via SDL_Init(). OpenGL, being a part of graphics subsystem, is not directly initialized in this manner. For initializing OpenGL following are the steps:

1. Set OpenGL Attributes

2. Specify use of Double Buffering

3. Set the Video Mode

Of these second one is optional as it is used only when double buffering is a requirement. Lets have a detailed look at all of them.

1. Setting the OpenGL Attributes:

Before initializing the video, it is better to set up the OpenGL. These attributes are passed to the OpenGL via SDL calling the SDL_GL_SetAttribute() function. The parameters are the OpenGL attribute and their values. The most common attributes passed to this function are:

i. SDL_GL_RED_SIZE:

It sets the size of the red component of the frame buffer. The value is in bits. The commonly used value is 5. Similar parameters exist for blue and green components which are SDL_GL_BLUE_SIZE and SDL_GL_GREEN_SIZE respectively. To set green component to a bit value of 4 the code would be:

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 4 );

ii. SDL_GL_BUFFER_SIZE:

To set the size of the frame buffer this attribute is passed with the required Buffer size in bits. It is greater than or equal to the combined value i.e. sum of the red, green, blue and alpha components. If the requirement is 24 bit color depth and alpha channel of 32-bits then each color component must be given the size value as 8 and frame buffer must be given size as 32. In code it would be:

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

iii. SDL_GL_DEPTH_SIZE:

This attribute controls the size of depth buffer or Z buffers. Normally the graphics cards provide 16-bit or 24-bit depth. If the value is set more than what is available, the operation will fail. To make it more clear following is the code:

SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);

iv. SDL_GL_ACCUM_RED_SIZE:

To set the size of red component of accumulation buffer, this attribute is used.

The value is specified in bits. SDL_GL_ACCUM_BLUE_SIZE, SDL_GL_ACCUM_GREEN_SIZE controls the size of blue and green component of accumulation buffer. In code it would be:

SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,5);

The question that would be arising in your mind would be that whether these attributes could be set after initializing the video mode. The answer is no. The reason is that these settings have to be initialized before invoking and configuring video mode. Next we have to setup the video mode.

2. Setting up double buffering:

This aspect has also to be covered before setting up the video mode as this     attribute goes as a flag parameter to the SDL_GL_SetAttribute. The attribute is     SDL_GL_DOUBLEBUFFER and the value is either 1 or 0. The point to be kept in     mind is that when working in conjunction with OpenGL, the flag specifying double     buffer must be passed as an attribute to the SDL_GL_SetAttribute function and not to the SDL_Set_VideoMode(). In code this would be:

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

would set the double buffering to one state.

3. Setting the Video Mode:

Once the OpenGL attributes are set, setting the video mode is similar to the     setting of video mode as described in last tutorials. For more details have a look     at Part-II of the tutorial. The only difference comes in flags being sent to the     SDL_Set_VideoMode(). Apart from other required flags the SDL_OPENGL would     also be set i.e.

int flags=0;

flags= SDL_OPENGL | SDL_FULLSCREEN;

setting the SDL_OPENGL flag is a must.

That’s all there about the required steps. Now let the OpenGL play.

OpenGL in Action:

The theory is over. Its now time to see some real action. The example application would render a rotating triangle. The includes will contain one more header file.

#include <SDL/SDL.h>

#include <gl/gl.h>

 

gl.h contains function declarations necessary to work with OpenGL.

Next comes the main() and OpenGL attributes.

int main(int argc, char *argv[])

{

  SDL_Event event;

  float theta = 0.0f;

  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );       

  SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

 

:

:

}

Next initialize the video and video mode

 

int main(int argc, char *argv[])

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

  SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE | 

                               SDL_NOFRAME);

:

:

}

 

The video is initialized to 600×300 resolutions. And the hardware rendering mode is being used. This is done by SDL_HWSURFACE flag. Hence OpenGL would write on the graphic card’s memory instead of mapping it to software memory. After this step, the territory of OpenGL starts.

 

int main(int argc, char *argv[])

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

  glClearDepth(1.0);

  glDepthFunc(GL_LESS);

  glEnable(GL_DEPTH_TEST);

  glShadeModel(GL_SMOOTH);

  glMatrixMode(GL_PROJECTION);

  glMatrixMode(GL_MODELVIEW);

:

:

}

to start working with OpenGL, the view port is initialized. Then the screen is cleared or rendered with the specified background color. Since the triangle would be rotating in 3D space hence the depth has to be set and depth testing has to be enabled. If smooth shading is not used, then the edges would seem jagged. Hence smooth shading model is used. This completes the setting up of OpenGL parameters after SDL video initialization. Drawing and rotation is taken care by the following code in bold:

int main(int argc, char *argv[])

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

  for(done = 0; !done;)

 {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

    glLoadIdentity();

    glTranslatef(0.0f,0.0f,0.0f);

    glRotatef(theta, 0.0f, 0.0f, 1.0f);

   :

:

}

}

The focus is brought to the point of origin by translating it. Then rotation function is provided the theta value through which the triangle has to be rotated.

int main(int argc, char *argv[])

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

for(done = 0; !done;)

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0f,0.0f,0.0f);

glRotatef(theta, 0.0f, 0.0f, 1.0f);

glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);

    glVertex2f(0.0f, 1.0f);

    glColor3f(0.0f, 1.0f, 0.0f);

    glVertex2f(0.87f, -0.5f);

    glColor3f(0.0f, 0.0f, 1.0f);

    glVertex2f(-0.87f, -0.5f);

    glEnd();

 

    theta += .5f;

    SDL_GL_SwapBuffers();

   :

:

}

}

The triangle is drawn by specifying the vertices. Then the theta value is increased. Next event handling part cometh.

int main(int argc, char *argv[])

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

for(done = 0; !done;)

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0f,0.0f,0.0f);

glRotatef(theta, 0.0f, 0.0f, 1.0f);

 glBegin(GL_TRIANGLES);

glColor3f(1.0f, 0.0f, 0.0f);

glVertex2f(0.0f, 1.0f);

glColor3f(0.0f, 1.0f, 0.0f);

glVertex2f(0.87f, -0.5f);

glColor3f(0.0f, 0.0f, 1.0f);

glVertex2f(-0.87f, -0.5f);

glEnd();

theta += .5f;

SDL_GL_SwapBuffers();

SDL_PollEvent(&event);

    if(event.key.keysym.sym == SDLK_ESCAPE)

      done = 1;

}

}

That’s it. This is how SDL and OpenGL work together. The only piece missing in this puzzle is sound. It will be tackled in the next part which incidentally is the last part of this series. So till next time.

Graphics and handling user inputs- the combination that creates the symphony called game. A world (of game) where these two are out of phase ends in cacophony. In the last article I discussed about the various parameters that goes into creating a screen and loading bitmapped images on to the screen. That was pretty high-level as the work was done on structures that represent the actual screen and maps or sprites. But there are times when one has to get his/her hand dirty by working directly upon pixels. The creators of SDL had already anticipated this requirement and built the capacities to work at raw graphics level into the core itself. Thus developer is redeemed from understanding system, platform and architecture specific nitty-gritty about manipulating the pixels. The other aspect of gaming that gives sleepless nights to developers is handling the user input, as the handling of input devices changes from system to system. To remove this burden from the minds of the developers, SDL provides object-oriented approach in handling the events. In this article, I would be discussing these two aspects of SDL. In the first section, the discussion would focus on using pixel manipulation functions and their usages and the second section would focus on input handling. So now that the agenda for this article have been laid down lets get started.   Raw Graphics-Writing Directly onto the Display:  Though the SDL Graphics APIs provide pretty high level functionality abstracting off all the low-level details, yet, there are times when abstraction is not required. For this purpose also there are ways. These ways doesn’t exist as a library function but as separate functions that has to be embedded into your program. The functions are freely available. But for the completeness I am including them here. These functions are:

  1. getpixel():

This function is useful if pixel value have to be obtained from a given coordinates represented by X and Y values on the display. It works on a single pixel at a time. The first parameter is the surface from which the value has to be obtained. This is represented by a pointer to the SDL_Surface. The next two integer parameters represent the x and y coordinates from where the pixel value has to be obtained. The return value is an Uint32 representing the value of the pixel. Following is the code:   /*  * Return the pixel value at (x, y)  * NOTE: The surface must be locked before calling this!  */ Uint32 getpixel(SDL_Surface *surface, int x, int y) {     int bpp = surface->format->BytesPerPixel;     /* Here p is the address to the pixel we want to retrieve */     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;       switch(bpp) {     case 1:         return *p;       case 2:         return *(Uint16 *)p;       case 3:         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)             return p[0] << 16 | p[1] << 8 | p[2];         else             return p[0] | p[1] << 8 | p[2] << 16;       case 4:         return *(Uint32 *)p;       default:         return 0;       /* shouldn’t happen, but avoids warnings */     } }   The first thing to be done is to obtain the depth represented by BytesPerPixel. It is done by the first statement: int bpp = surface->format->BytesPerPixel;   Next statement is self explanatory. To get the address of the pixel, the pitch of the of the passed surface is multiplied by the value of Y- coordinate, the depth is multiplied by the X- coordinate and the resulting values are added with pixel data of the surface represented by pixels member of SDL_Surface. This calculation provides the actual address of the pixel. The SDL_Surface could be thought of as multi dimensional array. Hence the value could be accessed as row-major and column-major format. That is done in the second statement: Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;  As the value returned by BytesPerPixels ranges from 1-4 according to the bytes needed to represent the pixel, it can be used for returning the values in the corresponding format i.e. 8, 16, 24 or 32. this is achieved by the switch-case block. That’s all about getpixel function.

  1. putpixel():

This is same as getpixel(). Apart from the parameters accepted by getpixel() function, this accepts one parameter extra- the address where the value has to be put. Following is the code for putpixel():   /*  * Set the pixel at (x, y) to the given value  * NOTE: The surface must be locked before calling this!  */ void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {     int bpp = surface->format->BytesPerPixel;     /* Here p is the address to the pixel we want to set */     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;       switch(bpp) {     case 1:         *p = pixel;         break;       case 2:         *(Uint16 *)p = pixel;         break;       case 3:         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {             p[0] = (pixel >> 16) & 0xff;             p[1] = (pixel >> 8) & 0xff;             p[2] = pixel & 0xff;         } else {             p[0] = pixel & 0xff;             p[1] = (pixel >> 8) & 0xff;             p[2] = (pixel >> 16) & 0xff;         }         break;       case 4:         *(Uint32 *)p = pixel;         break;     } }   The working of putpixel() is almost opposite to that of getpixel(). In case of later, the returned value is pixel value corresponding to the coordinates whereas the later places the pixel value according the coordinates. For this first the BytesPerPixel of the passed SDL_Suface is extracted just like before. Then pixel’s address (or pixel value) is calculated and according to the value returned by BytesPerPixels the value is placed. Since the calculated value is address of the pixel, hence the passed pixel value can be directly assigned and the display will be getting the new value.   Now that both the functions have been explained, lets see how to put one them to use i.e. putpixel(). For this I am defining a method called putyellowpixel() that places a yellow pixel at the center of the screen. It doesn’t accept any parameter nor does it returns any value.   void putyellowpixel() {     int x, y;     Uint32 yellow;       /* Map the color yellow to this display (R=0xff, G=0xFF, B=0×00)        Note:  If the display is palettized, you must set the palette first.     */     yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0×00);       x = screen->w / 2;     y = screen->h / 2;       /* Lock the screen for direct access to the pixels */     if ( SDL_MUSTLOCK(screen) ) {         if ( SDL_LockSurface(screen) < 0 ) {             fprintf(stderr, “Can’t lock screen: %s\n”, SDL_GetError());             return;         }     }       putpixel(screen, x, y, yellow);       if ( SDL_MUSTLOCK(screen) ) {         SDL_UnlockSurface(screen);     }     /* Update just the part of the display that we’ve changed */     SDL_UpdateRect(screen, x, y, 1, 1);       return;   }   To get the yellow color, the SDL_MapRGB() has to be used. The SDL_PixelFormat is the first parameter. It stores surface format information. Next three parameters correspond to the red, blue and green components of the color. The return value is the actual color corresponding to the passed color components in hexadecimal format as follows: yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0×00);   Once the color has been retrieved, the next step is to get the required x and y coordinates which is achieved by the following statement: x = screen->w / 2; y = screen->h / 2; then screen surface is locked. If this is not done, then corruption of the SDL_Surface structure could get corrupted causing instability of the game as putpixel works on the address of pixel directly. This is done by:   SDL_MUSTLOCK(screen);   The next step is to call the putpixel. Once putpixel has returned, then unlock the surface and update the surface. That completes placing a pixel directly on to the surface. Next section would focus on even handling with reference to keyboard.   Handling the Key Board- the SDL way:Whatever has been discussed till now completes only one aspect of providing interactivity. Even now the application doesn’t have the ability to handle user gestures provided through different input devices such as keyboard, joy stick etc. So now the focus would be on the input handling. Two of the most common input devices are mouse and keyboard. SDL has wrappers for each of these. In this section I would be discussing about keyboard handling. Before entering the world of keyboard events, it is better to understand the most recurring structures in keyboard handling jargon. They are:

  1. SDLKey:

It is an enumerated type that represents various keys. For example SDLK_a represents lowercase ‘a’, SDLK_DELETE is for ‘delete’ key and so on.

  1. SDLMod:

SDLKey enumeration represents only keys. To represent key modifiers such as Shift and Ctrl, SDLMod enumeration is provided by the SDL. The KMOD_CAPS is one of the enumeration that can be used to find out whether caps key is down or not. Other modifiers also have representations in SDLMod.

  1. SDL_keysym:

It is a structure that contains the information of a key-press. The members of this structure include scan code in hardware dependent format, SDLKey value of the pressed key in sym field, the value of modifier key in mod field and the Unicode representation of the key in Unicode field.

  1. SDL_KeyboardEvent:

From the name itself it is obvious that this structure describes a keyboard event. The first member, type, tells that the event is key release or key press event. The second member gives the same info as the first but uses different values. The last member is a structure itself- the SDL_keysym structure.   Now that the structures have been brought into the picture, the next step is to use these in handling the keyboard events. For this the logic is simple. The SDL_PollEvent is used to read the events. This is placed within the while loop. Then the value of type member of SDL_Event variable, passed as the parameter to SDL_PollEvent, is checked to find the type of event and then event processing can be done. In code it is thus:   SDL_Event event;   .   .   /* Poll for events. SDL_PollEvent() returns 0 when there are no  */   /* more events on the event queue, our while loop will exit when */   /* that occurs.                                                  */   while( SDL_PollEvent( &event ) ){     /* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */     switch( event.type ){       case SDL_KEYDOWN:         printf( “Key press detected\n” );         break;         case SDL_KEYUP:         printf( “Key release detected\n” );         break;         default:         break;     }   }   .   .   If this is used this in the program developed in last article, the exit condition of the program can be controlled. The new version would exit only at key press.     void display_bmp(char *file_name) { SDL_Surface *image;   /* Load the BMP file into a surface */ image = SDL_LoadBMP(file_name); if (image == NULL) { fprintf(stderr, “Couldn’t load %s: %s\n”, file_name, SDL_GetError()); return; }   /* * Palettized screen modes will have a default palette (a standard * 8*8*4 colour cube), but if the image is palettized as well we can * use that palette for a nicer colour matching */ if (image->format->palette && screen->format->palette) { SDL_SetColors(screen, image->format->palette->colors, 0, image->format->palette->ncolors); }   /* Blit onto the screen surface */ if(SDL_BlitSurface(image, NULL, screen, NULL) < 0) fprintf(stderr, “BlitSurface error: %s\n”, SDL_GetError());   SDL_UpdateRect(screen, 0, 0, image->w, image->h);   /* Free the allocated BMP surface */ SDL_FreeSurface(image); }   int main(int argc,char* argv[]) { /*variable to hold the file name of the image to be loaded *In real world error  handling  code would precede this                                                                          */ char* filename=”Tux.bmp”; /*The following code does the initialization for Audio and Video*/ int i_error=SDL_Init(SDL_INIT_VIDEO); /*If initialization is unsuccessful, then quit */ if(i_error==-1) exit(1); atexit(SDL_Quit); /* * Initialize the display in a 640×480 8-bit palettized mode, * requesting a software surface */ screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE); if ( screen == NULL ) { fprintf(stderr, “Couldn’t set 640x480x8 video mode: %s\n”, SDL_GetError()); exit(1); }   /*Handle the keyboards events here. Catch the SDL_Quit event to exit*/ done = 0;              while (!done)             {                SDL_Event event;                 /* Check for events */         while (SDL_PollEvent (&event))              {             switch (event.type)             {                           case SDL_KEYDOWN:                 break;                           case SDL_QUIT:                             done = 1;                            break;             default:                           break;             }         } /* Now call the function to load the image and copy it to the screen surface*/ load_bmp(filename); }   If you run the above code the window wont be closed until the close button is pressed. Though, this code does nothing much in area of interactivity but it’s a beginning. So as you can see, it is really easy to handle keyboard events using SDL. It totally removes the dependence of developer on Operating System for event handling. Also working at raw graphics level is not that difficult.   This brings us to the end of the third part of SDL programming. The next part would cover using OpenGL with SDL. Also using timers would be covered. Till next time.

“Code less ..Achieve more” is the prime philosophy behind the development of all the Very High Level Languages (or VHLL in short). But less no. of lines should not mean reduced flexibility in terms of choosing an approach in solving a problem. Though many of the VHLL or Scripting Languages as they are popularly known, does not keep in mind the flexibility, yet there area few that have the logic of flexibility and choice as their core. Python is one of them. This fact is evident if one tries to do network programming in Python. The choices are aplenty for the programmer. The choices range from low-level sockets or raw-sockets to a completely extensible and functional web-server. In this tutorial I will be discussing how to use raw sockets to create network oriented applications in Python. The first section will cover the basics of the socket module and by the end of the section a simple echo server will be coded. In the second section the echo server would be enhanced by making it capable of serving multiple clients using the concepts introduced in the first section.

 

Sockets and Ports- Doing it the Python way:

Sockets and ports form the core of any network oriented application. According to the formal definition a socket is “An endpoint of communication to which a name may be bound”. The concept (as well as implementation) comes from the BSD community. The 4.3BSD implementation defines three domains for the sockets:

  1. Unix Domain/ File-system Domain:

The sockets under this domain are used when two or more processes within a system have to communicate with each other. In this domain, the sockets are created within the file system. They are represented as strings that contains local path such as /var/lock/sock or /tmp/sock.

 

  1. Internet Domain:

This domain represents the processes that communicate over the TCP/IP. The sockets created for this domain are represented using a (host, port) tuple. Here host is a fully qualified Internet host name that can be represented using a string or in the dotted decimal format (or IP address).

  1. NS Domain:

This domain is the one used by the processes communicating over Xerox protocol which is now obsolete.

 

Of these only the first two are the most commonly used. Python supports all of these. My discussion would be limited to the Internet Domain. To create an application that uses TCP/IP sockets following are the steps:

 

  1. Creating a socket
  2. Connecting the socket
  3. Binding the socket to an address
  4. Listening and accepting connections
  5. Transferring data/receiving data.

 

But before creating a socket libraries have to be imported. The socket module contains all that is needed to work with sockets. The imports can be done in two ways:

import socket or from socket import *. If the first form is used then to access the methods of socket module, socket.methodname() would have to be used. If the later format is used, then the methods could be called without the fully qualified name. I will be using the second format for clarity of the code and ease. Now lets see the various provisions within socket module for the programmers.

 

  1. Creating a socket:

A socket can be created by making call to the socket() function. The socket() function returns a socket in the domain specified. The parameters to the function are:

 

a. family:

The family parameter specifies in which domain the socket has to be created.  The valid values are AF_UNIX for UNIX domain and AF_INET for internet domain.

b. type:

Type defines the type of the protocol to be used. The type can be                   connection oriented like TCP or connection less like UDP. These are defined by the constants SOCK_STREAM for TCP, SOCK_DGRAM for UDP. Other valid parameters are SOCK RAW, SOCK SEQPACKET and SOCK RDM.

c. protocol:

This generally left for default value. The default is 0.

 

So a socket for Internet domain is created thus:

testsocket=socket(AF_INET,SOCK_STREAM)

 

  1. Connecting the Socket:

Sockets thus created can be used on the server-side or client-side. To use the socket as client-socket it needs to be connected to a host. That can be done using the connect() method of the socket object. The connect() method accepts either the host name as the parameter or a tuple containing host name/address and port number as parameter. For example to connect to a host whose address is 192.168.51.100 and the port number 8080 the statement would be:

 

testsocket.connect((‘192.168.51.100’,8080))

 

  1. Binding the socket to an address:

If the socket has to be used on the server side, then the socket has to be bound to an address and a port, thus naming it. To bind a socket to an address, the bind() method of the socket object has to be used. The valid parameter is a tuple containing the address to which the socket has to be bound and the port at which it has to listen for incoming requests. To use the same socket i.e. testsocket on the server side the statement would be:

 

testsocket.bind((‘192.168.51.100’,8080))

  1. Listening and accepting connections:

Once a socket has been named, then it has to be instructed to listen at the given port for incoming requests. This can be done using the listen() method. The listen accepts a no. representing the maximum queued connection. The argument should be atleast 1. for example the following code sets the max queued connection to 2:

 

testsocket.listen(2)

The next thing to be done is to accept the incoming connection requests. This can be done by the accept() function. This function returns a tuple containing a new socket object representing the client and the address of the client. For example:

clientsock,address= testsocket.accept()

in the above statement clientsock would contains a new socket object and address would contain the address of the client.

 

  1. Transferring data/receiving data:

Data can be transferred using recv() and send() methods of socket object. Socket’s recv() method is used to receive the data send from the server or from the client. The parameters are a buffer size for the data , and flags. The flags parameter is optional. So to receive data the code would be:

buff=1024

testsocket.recv(buff)

 

To send the data, a call to the send method is in order. The parameters are the data to be send and the flags. To elucidate  further:

data=raw_input(‘>>’)

testsocket.send(data)

Now that the steps are clear, lets create a simple echo server. First the imports

from socket import *

Then the constants that defines the host, port, buffer size and the address tuple to be used with bind().

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

 

Then create the server side socket and bind it to the host and the port. Then comes the max queue size to 2:

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

Now to make it listen for incoming requests continuously place the accept() method in a while loop. This is not the most preferable mode. The preferable way will be discussed in next section:

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

:

:

Next  receive the data from the client and echo it back. This has to continue till the client doesn’t send the null data or ctrl+c. to achieve this again use a while loop and then close the connection when done.

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

 

while 1:

data = clientsock.recv(BUFSIZ)

if not data: break

clientsock.send(‘echoed’, data)

 

clientsock.close()

serversock.close()

 

That’s all for the server. Now for the client. The only exception is that there is no bind(), accept() and listen().

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

tcpCliSock = socket(AF_INET, SOCK_STREAM)

tcpCliSock.connect(ADDR)

while 1:

data = raw_input(‘> ‘)

if not data: break

tcpCliSock.send(data)

data = tcpCliSock.recv(1024)

if not data: break

print data

tcpCliSock.close()

Multi-Threaded Echo Server- Other Approach in Creating a Server:

 

In the above example the uses while loop to service different clients. For elucidations it is ok. But in the real world, it won’t work well. The reason is that more than one client cannot be served simultaneously by just while constructs. To overcome the limitations there are several strategies. One of them is making the server multi-threaded. There are two parts in the creation of a multi threaded server:

 

  1. Create threads for each accepted  connections:

This is the core of the multi-threaded server. For each accepted connection request, a different thread is created and the serving that particular client is carried out by an independent thread. Thus quick response time can be achieved.

 

  1. Create a handler:

It is the handler where the whole processing goes on. In our case transferring a file.

 

To make the echo server some changes have to be made. It starts with the accept part as shown below:

 

from socket import *

from threading import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

thread.start_new_thread(handler, (clientsock, addr))

 

 

 

serversock.close()

 

After accepting the request a new thread is created for the client. This is done for each connection request. The logic of handling the client is defined within the handler which goes thus:

 

from socket import *

from threading import *

def handler(clientsock,addr):

while 1:

data = clientsock.recv(BUFSIZ)

if not data: break

clientsock.send(‘echoed:..’, data)

 

clientsock.close()

if __name__==’__main__’:

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

thread.start_new_thread(handler, (clientsock, addr))

#some other cleanup code if necessary

 

The handler has to be defined before calling it. The handler contains the same code that was contained in the inner while loop previously. This example is not optimized. But it serves the purpose of providing a different approach for serving multiple clients. This brings us to the end of this section.

 

Parting Thoughts:

  1. The low level sockets can be mixed and matched with other modules such as threads and forks to create a server capable of serving multiple clients simultaneously.
  2. While using threading approach the locking and synchronization issues must be kept in mind.
  3. The security measures must be taken care of when creating FTP kind of servers.

 

This brings us to the end of this discussion. In the introductory section I mentioned flexibility as one of the core aspects of Python. Ability to work with low-level sockets is one of them. But at the other end of the spectrum are the pre-built yet extensible web-servers. These will be discussed in the near future. Till then…

The arrangement of data within the memory forms the basis of computing. The arrangement of data is known as data-structure. Every language provides variety of built-in data-structures. Languages such as C provide basic data-structure mechanisms using which complex structures can be built whereas languages such as Java use full-blown object-oriented approach for almost all types of data-structures. Then there are languages like Python which takes a middle approach. In this article I would be discussing the middle path used by Python using two of its built-in data-structures – Lists and Tuples. The first section would focus on functionalities of Lists and Tuples. In the second section I would develop a real world application which makes use of Lists and/or Tuples. That’s the agenda for this discussion.

 

List and Tuple – More About Them:

List and Tuple are two of the basic built-in data-structures. As with all other features of Python, these in-built data-structures provide both flexibility and power. The answer to how flexible and powerful they are is what I am going to discuss now. First lets look at List data-structure.

 

1. List:

By definition a List is “An instance of an abstract data type (ADT), formalizing the concept of an ordered collection of entities”. In other words, a List is a collection of objects. In contrast with Array, List contains different objects. That’s how Python also views Lists. Data types (that’s what Python calls built-in data-structures too) such as List is known as compound data type in Python. The operations that can be performed on a List are:

 

a. Creation

b. Addition of elements

c. Accessing and Searching

d. Deletion

 

Many of the library functions essentially create Lists. These functions may be working on Lists themselves such as during accessing and searching. Here are the details:

 

a. Creation:

A List is defined as list of coma separated values between square brackets thus:

 

a = ['spam', 'eggs', 100, 1234]

 

where the items of the List a are of different data types.  This is the most common method of creating a list. The other technique is to use the range() function. The range() function provides a List of consecutive integers. The range() function takes two arguments. The List returned contains all the integers from the first to the second, including the first but not including the second. For example,

>>range(1, 5)

Gives

[1,2,3,4]

Since List itself is a data type, so a List can contain another List. For example,

 

[1,”a”,[2,3]]

 

is perfectly valid List.

 

b. Addition of elements:

There are three ways to add elements to an existing List using member functions of the List which are:

 

i. append adds a single element to the end of the List. For example, let li be

a List, then

>>> li

['a', 'b', 'mpilgrim', 'z', 'example']

>>> li.append(“new”)

>>> li

['a', 'b', 'mpilgrim', 'z', 'example', 'new']

 

ii. insert method inserts a single element into the List. The numeric argument

is the index of the first element that gets shifted out of position. Also there can be two elements of same value at two different positions.

 

>>> li.insert(2, “new”)

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']

iii. extends concatenates the List passed as argument with the existing List.

For example,

>>> li.extend(["two", "elements"])

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

 

c. Accessing and Searching:

For accessing and searching, one of the following techniques can be used:

 

i. Slicing:

Slice is a sub-list of a List. Slicing is done using the [n : m] which

returns the part of the List from the n-eth character to the m-eth

character, including the first but excluding the last. For example if a_list is

a List of alphabets from a to f, then

 

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']

>>> a_list[1:3]

['b', 'c']

>>> a_list[:4]

['a', 'b', 'c', 'd']

>>> a_list[3:]

['d', 'e', 'f']

>>> a_list[:]

['a', 'b', 'c', 'd', 'e', 'f']

 

ii. Indexing:

Index of a given element can be found using the index() function of List. It returns the first occurrence of the element supplied as argument. That means even if the element occurs twice, only the position of the first element would be returned. If  the element is not found an exception is raised. For example

>>>li=['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>> li.index(“example”)

5

>>> li.index(“new”)

2

>>> li.index(“c”)

Traceback (innermost last):

File “<interactive input>”, line 1, in ?

ValueError: list.index(x): x not in list

 

Apart from these, a List can be accessed as one access an array by specifying index thus:

>>>li=['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>>li[0]

‘a’

d. Deletion:

To delete an element from a List, one can us del. It removes an element from the specified List. For example:

>>> a = ['one', 'two', 'three']

>>> del a[1]

>>> a

['one', 'three']

 

del also can have slice thus:

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']

>>> del a_list[1:5]

>>> print a_list

['a', 'f']

That’s all about the operations on Lists. The way the operations are implemented shows the flexibility of Python’s middle path approach. The flexibility doesn’t just stop here. Though strings are immutable and Lists are mutable yet they are inter-convertible. Two of the most useful functions in the string module involve Lists of strings – split and join. The former returns a List composed of individual elements of string separated by the delimiter passed as argument. While the latter creates a string out of supplied List. Following are the examples:

 

>>> import string

>>> song = “The rain in Spain…”

>>> string.split(song)

['The', 'rain', 'in', 'Spain...']

 

Here the string is split on the basis of space as delimiter which is the default delimiter. Next example shows the reverse of the above functionality – string from a List:

 

>>> lst = ['The', 'rain', 'in', 'Spain...']

>>> string.join(lst)

‘The rain in Spain…’

where the joining is done on the basis of space delimiter which again is default delimiter. That’s all about Lists at present. Next lets look at the other compound data-type – Tuple.

 

2. Tuple:

According to definition, “A tuple is a finite sequence (also known as an “ordered list”) of objects, each of a specified type”. In other words, a Tuple is an ordered collection of  objects of different types. In Python, a Tuple is a list of comma separated values but immutable unlike List. So the operations on a Tuple are restricted to the ones that don’t affect its immutability. Accordingly following are the operations that can be performed on a Tuple are:

 

a. Creation

b. Accessing

 

Due to immutability, deletion and addition of new elements are not possible.

 

a. Creation:

Creating or defining a Tuple is as simple as giving a list of values within parenthesis. For example

 

>>> tup = (2, 4, 6, 8, 10)

 

is a Tuple. If a Tuple is having only one element, then, it would be defined as follows:

>>> tup = (5,)

 

b. Accessing:

Since Lists and Tuples are almost same, so the accessing mechanisms also works in similar fashion. Elements of a Tuple can be accessed in two ways:

 

i. Index based:

The elements of a  Tuple can be accessed using their indices. The

index starts at 0. For example to access an element at index 0 of a Tuple

tup, the statement would be:

 

>>> tup = (‘a’, ‘b’, ‘c’, ‘d’, ‘e’)

>>> tup[0]

‘a’

 

ii. Slicing:

As in List, slice operator can be used to access elements of a Tuple. It selects a range of elements. For example the following statement selects elements between 1 and 3 (excluding 3):

>>> tup[1:3]

(‘b’, ‘c’)

That’s about operations on a Tuple. So the question arises, when to use List and when to use Tuple. List can be used almost in all the cases. However, there are certain contexts where Tuple is more useful which are:

 

  • Tuples are faster than lists. If you’re defining a constant set of values and all you’re ever going to do with it is iterate through it, use a tuple instead of a list.
  • It makes your code safer if you “write-protect” data that does not need to be changed. Using a Tuple instead of a list is like having an implied assert statement that this data is constant, and that special thought (and a specific function) is required to override that.

 

In all other contexts, Lists can be used. That brings us to the next section – a real world example using List.

 

Lists And Tuples – In Real World:

The example application would implement a ring buffer or a bounded buffer using List. In a bounded buffer, once the capacity is full, then the first element i.e. the oldest element is replaced with newest element. The implementation uses class switch pattern. Here is the code:

 

class RingBuffer(object):

“”" class that implements a not-yet-full buffer “”"

def __init__(self, size_max):

self.max = size_max

self.data = [  ]

class __Full(object):

“”" class that implements a full buffer “”"

def append(self, x):

“”" Append an element overwriting the oldest one. “”"

self.data[self.cur] = x

self.cur = (self.cur+1) % self.max

def tolist(self):

“”" return list of elements in correct order. “”"

return self.data[self.cur:] + self.data[:self.cur]

def append(self, x):

“”" append an element at the end of the buffer. “”"

self.data.append(x)

if len(self.data) == self.max:

self.cur = 0

# Permanently change self’s class from non-full to full

self.__class__ = __Full

def tolist(self):

“”" Return a list of elements from the oldest to the newest. “”"

return self.data

The class defines an empty List as a buffer. The nested class __Full implements the logic to overwrite the oldest element if the buffer is full. The tolist method returns the List in correct order. Next the append method of the outer class i.e. RingBuffer appends a new item to the end of the List. It also checks whether the length of the buffer is equal to  the max size. If it is equal, then buffer’s state is changed to full. The tolist method returns the buffer. Following is sample implementation that shows how to use the RingBuffer class:

 

if __name__ == ‘__main__’:

x = RingBuffer(5)

x.append(1); x.append(2); x.append(3); x.append(4)

print x.__class__, x.tolist( )

x.append(5)

print x.__class__, x.tolist( )

x.append(6)

print x.data, x.tolist( )

x.append(7); x.append(8); x.append(9); x.append(10)

print x.data, x.tolist( )

That brings us to the end of this discussion. List and Tuple are the basic data-structures found in Python. On the basis of these more complex structures such as trees can be developed. How to implement them would be the topic for discussion in the future. Till then…

Maps are becoming ubiquitous in web applications. They are being used as an effective and non-intrusive way of gathering geo-specific data from the user or to present geo-specific information to the user including tracking report of shipments et al. However even two years ago, embedding a map within an application was considered a specialized area requiring good understanding of Geographical Information System or GIS. But the arrival of Google Maps and its corresponding set of APIs, incidentally known as Google Map API, have changed the scenario. Now a developer having a good grasp on JavaScript, can without much ado embed an interactive map in a web-application using Google Map API. The questions that arise next is what exactly is Google Map API and what are the steps to be followed in using Google Map API. The answer to these questions is the focus of this discussion. The first section would deal with the whys and wherefores of Google Map API. In the second section I would detail the steps to use Google Map API. The last section would focus on a real world example based on the steps discussed in second section. That is the outline of the discussion.

Google Map API – What is it:

Google Map provides not only the map, satellite image or a hybrid of both but also an extensive range of operations on the map such as zooming, panning, information pop-ups, overlays etc. Google Map API provides interface into these operation through JavaScript objects. The beauty of the setup is that the functionalities work in the same non-intrusive way as the original Google Maps without developer needing to know the details of AJAX or how it is implemented in Google Maps. The developer has to just know the classes and their methods to access the services of Google Maps. The functionalities exposed by the Google Map API can be categorized as follows:

1. Configuration

2. Controls

3. Map Types

4. Map State

5. Overlays

6. Information Window

7. Map Navigation

8. Events

The accesses to most of the group of functionalities mentioned above are through the methods of GMap2 class. GMap2 class forms the basis of map creation, display and manipulation.

1. Configuration:

All the aspects of any map provided by Google Maps are configurable -be it the enabling of dragging and information windows or continuous zooming. The methods of GMap2 class sectioned under configuration enables configuration of the map. Following are the most oft used methods for configuring maps:

i. enableDragging() – enables the dragging of map. Dragging is enabled by

default.

ii. disableDragging() – disables the dragging of map.

iii. enableInfoWindow() – enables the information window

iv. disableInfoWindow() – disables the displaying of information window.

2. Controls:

The UI elements using which user controls the map and its functionalities come under controls category. There are two main methods related to controls which are:

i. addControl(control, [position]) – adds the specified control to the map at the

place specified by position parent. The position

parameter is optional.

ii. removeControl(control) – removes the specified control from the map.

Both the above functions takes instance of GControl class. There are four existing instances of GControl class – GSmallMapControl, GLargeMapControl, GSmallZoomControl, GScaleControl and GMapTypeControl. These can be passed to the addControl() method to add controls to the map.

3. Map Types:

Google Maps provide three types of map – simple map that provides outline based map, satellite map that streams the satellite imaged maps and hybrid map which is a combination of both aforementioned maps. The map types provided by Google Maps is controlled by the following methods:

i. setMapType(type) – sets the type of map to be displayed.

ii. removeMapType(type)- removes a already set map type.

The type parameter is specified using the constants provided by GMapType class. It can be G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP corresponding to maps of type simple, satellite image based or combination of both.

4. Map State:

The methods that provide information about the state of the map comes under it. The information provided by map state methods include whether the map is loaded or not, the current focus point or center of the map etc. The commonly used methods are:

i. isLoaded() – it tells whether the map is loaded on to client browser or not

ii. getCenter() – this method provides the latitude and longitude of the center of

current viewport of the map.

5. Overlays:

By definition “A map overlay refers to a point or polyline that is added on top of the Google Map”. In essence an overlay means a point or line that is placed on the map to distinguish it from rest of the map. Mostly used methods in this category are:

i. addOverlay(overlay) – it adds an overlay presented by the overlay object

passed as parameter.

ii. removeOverlay(overlay) – it removes an overlay already added and

represented by the overlay object passed as

parameter.

The overlay object can be of type GPoint or GPolyline.

6. Information Window:

When an overlay is clicked, a window containing detailed information can be displayed. It is called the Information window or info window in short. Following are the main methods to control an info window:

i. openInfoWindow(latlng,dom,[opts]) – opens an information window at the

point specified by latlang and with the

data specified as dom which is a DOM

node.

ii. showMapBlowup(latlng,[opts]) – opens a info window at the specified as

specified latlng containing the close-up view of

the latlng specified as parameter.

The parameter latlng is of the type GLatLng.

7. Map Navigation:

The navigation of map can be controlled using the methods provided under this category. The commonly used methods are:

i. setCenter(center,[zoom],[type]) – loads the map with focus on the point

specified by center with an optional level of

zoom and type of the map.

ii. panTo(center) – it navigates to the point on the map specified by center.

iii. setZoom(level) – it zooms into or magnifies the current center to the level

specified with the parameter level.

8. Events:

Google Map API provide methods to intercept any event taking placing on the map. The common events supported by Google Map API are:

i. click – it is generated when user clicks on any point within the boundaries of the

map.

ii. move – it is fired when the map is moving or panning. During the panning it

may be fired many times.

iii. moveend – it is fired when the panning is completed.

That brings us to the end of first section. In the next section I would detail the steps required to work with Google Map API.

Using Google Map API – Step By Step:

Now that the services provided by Google Map API have been discussed, lets see the steps to use the API. To use Google Map API, two main steps have to be followed:

1. Acquiring the Registration Key

2. Setting-up the map

The second step again consists of sub-steps that actually deals with the setting up of HTML and Google Map API library.

1. Acquiring the Registration Key:

It is through the registration key that one can access the API. A key can be used within a web directory i.e. files within that directory and its subdirectories can make use of the key. To get the key, go to the site and provide the URL of the site for which the key has to be generated. The key alongwith an example would be provided which can be used as base for further developments.

2. Setting-up the map:

The Google Map API library is a JavaScript library. So its focus would be HTML and JavaScript based applications. In other words, Google Map API targets the UI for the web-applications. To set-up the page to display map the required steps can be enumerated as follows:

i. Set-up the HTML page:

The first step in displaying the map is by providing the required placeholder within the page where the map has to be shown. To do this <div> tag has to be used. It creates a logical block for the map to be displayed. For example following statement creates a placeholder named ‘map’:

<div id=”map” style=”width: 500px; height: 500px”></div>

ii. Importing/Including the Google Map API:

To use the API, its library has to be referenced. In case of JavaScript importing or including of the library (other terms for referencing a library) is done using the src attribute of <script> tag. So to include Google Map API library, the src of the <script> tag would be as follows:


<script src=”http://maps.google.com/maps?file=api&v=2&key=[yourkey]“

type=”text/javascript”></script>

The value of src attribute tells us two important points about Google Map API. First is the location of the API which is the Google’s site itself. So even for testing purpose, availability of internet is required. Second the is usage of the key provided after registration. The key is passed along with the URL in the src to tell Google that the site trying to access the API library is authorized site. Next step is to implement a function that would be called when the document is loaded. That is done by calling a function in the <body> tag’s onload handler. the statements would be :

<script type=”text/javascript”>

//<![CDATA[

function load() {

}

//]]>

</script>

For defining the function and it would be called from the body thus:

<body onload=”load()” >

:

:

</body>

The first step in implementation of logic within the function is to check whether the client browser is capable of displaying map or not. That can be done using GBrowserIsCompatible(). It return a Boolean value specifying whether the browser is capable of displaying map or not. The code block using it would be thus:

if (GBrowserIsCompatible()) {

//…

}

To display the map what we need is an object of GMap2 class. To get it, GMap2 constructor with the id of the <div> serving as placeholder, is required. For example the following code creates an instance of GMap2 class and assigns it to the variable named map:

var map = new GMap2(document.getElementById(“map”));

The last step in displaying the map is to set its focus on a particular point. That can be accomplished by calling the setCenter() method on map variable. The argument passed is of type GLatLng which, in turn accepts latitude and longitude as its parameter. The following sets the focus on the point defined by latitude 31.122027 and longitude 77.111664:

map.setCenter(new GLatLng(31.122027, 77.111664), 13);

The map object can be used to manipulate map by using the methods enumerated in first section. The last but not least point is to call GUnload() through onunload handler of body tag to prevent memory leak:

<body onload=”load()” onunload=”GUnload()”>

:

</body>

That brings us to the end of the second section. In the next section I would develop a small application that would show the different functionalities discussed in first section using the steps detailed in this section.

Google Map API – In Real World:

Now I will be building a small application that displays map using Google Map API. It does the following:

1. Display the map with Shimla (India) as its center.

2. Provide zoom and pan controls for navigation.

3. Provide map type control to change between the three map types

4. Handle the click event and display information window showing the current focus

point on click upon the map.

So lets get going. First the HTML setup:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>

<head>

</head>

<body onload=”load()” onunload=”GUnload()”>

<div id=”map” style=”width: 500px; height: 500px”></div>

</body>

</html>

The onload handler calls the load function which is as follows:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>

<head>

<script src=”http://maps.google.com/maps?file=api&amp;v=2&amp;key=[yourkey]“

type=”text/javascript”></script>

<script type=”text/javascript”>

//<![CDATA[

function load() {

}

</head>

<body onload="load()" onunload="GUnload()">

<div id="map" style="width: 500px; height: 500px"></div>

</body>

</html>

Place the key you received in place of [yourkey]. This sets up the link to Google Map API and declares the load function. Next comes the creating the map instance and setting the center.

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>

<head>

<script src=”http://maps.google.com/maps?file=api&amp;v=2&amp;key=[yourkey]“

type=”text/javascript”></script>

<script type=”text/javascript”>

//<![CDATA[

function load() {

if (GBrowserIsCompatible()) {

var map = new GMap2(document.getElementById("map"));

map.setCenter(new GLatLng(31.122027, 77.111664), 13);

}

}

</head>

<body onload="load()" onunload="GUnload()">

<div id="map" style="width: 500px; height: 500px"></div>

</body>

</html>

Next lets add the controls:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[yourkey]“

type=”text/javascript”></script>

<script type=”text/javascript”>

//<![CDATA[

function load() {

if (GBrowserIsCompatible()) {

var map = new GMap2(document.getElementById("map"));

map.addControl(new GSmallMapControl());

map.addControl(new GMapTypeControl());

map.addControl(new GScaleControl());

map.setCenter(new GLatLng(31.122027, 77.111664), 13);

}

}

</head>

<body onload="load()" onunload="GUnload()">

<div id="map" style="width: 500px; height: 500px"></div>

</body>

</html>

The controls have to be added before setting the center. The last part is to handle the click event and show the current focus point on a information window:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=[yourkey]“

type=”text/javascript”></script>

<script type=”text/javascript”>

//<![CDATA[

function load() {

if (GBrowserIsCompatible()) {

var map = new GMap2(document.getElementById(“map”));

map.addControl(new GSmallMapControl());

map.addControl(new GMapTypeControl());

map.addControl(new GScaleControl());

map.setCenter(new GLatLng(31.122027, 77.111664), 13);

GEvent.addListener(map,”click”, function(){

map.openInfoWindow(map.getCenter(), document.createTextNode(map.getCenter()));

}

);

}

}

</head>

<body onload=”load()” onunload=”GUnload()”>

<div id=”map” style=”width: 500px; height: 500px”></div>

</body>

</html>

That completes the application. In just few lines it does a lot. This was just a teaser of what Google Map API can do. In the next articles I would discuss about advanced features such as communicating with servers and geo-encoding. Till then….

Follow

Get every new post delivered to your Inbox.