Build an AJAX Based Map Viewer in ASP.NET 2.0
page 3 of 7
by Xianzhong Zhu
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 31538/ 46

Update the show part dynamically

Direct output

In correspondence with the eagle-eye result, we expect to dynamically update the related part of the map on the right hand of the web page-magnifying the corresponding part of the real image in the map view area. We want to put part of the factual map (big.jpg) into the viewing area. To output part of the map, a new ASP.NET Web form named pic.aspx should be added, which will output the corresponding image through the parameters-position and size. The crucial code snippet of code-behind for page pic.aspx is shown in listing 2.

Listing 2 –partial code for Pic.aspx.cs

//……'using' clauses omitted here
namespace MapViewer
{
      public class Pic : System.Web.UI.Page
      {
            private void Page_Load(object sender, System.EventArgs e)
            {
                  //Put the user-code here for initialization
 
                  //Give the path, output postion and size of the image
                  string strLocalPath = Server.MapPath("image/big.jpg");
                  int iLeft = 0, iTop = 0, iWidth = 100, iHeight = 100;
                  if (Request.QueryString["l"] != null)
                  {
                        iLeft = Convert.ToInt32(Request.QueryString["l"]);
                  }
                  if (Request.QueryString["t"] != null)
                  {
                        iTop = Convert.ToInt32(Request.QueryString["t"]);
                  }
                  if (Request.QueryString["w"] != null)
                  {
                        iWidth = Convert.ToInt32(Request.QueryString["w"]);
                  }
                  if (Request.QueryString["h"] != null)
                  {
                        iHeight = Convert.ToInt32(Request.QueryString["h"]);
                  }
                  //load the image
                  System.Drawing.Image image = new System.Drawing.Bitmap(strLocalPath);
 
                  //target region
                  Rectangle destRect = new Rectangle(0, 0, iWidth, iHeight);
                  //the initial image region
                  Rectangle srcRect = new Rectangle(iLeft, iTop, iWidth, iHeight);
                  //create a new Graphics object
                  Bitmap newImage = new Bitmap(iWidth, iHeight);
                  Graphics g = Graphics.FromImage(newImage);
                  g.SmoothingMode = SmoothingMode.HighSpeed;
                  //image output quality
                  g.CompositingQuality = CompositingQuality.HighSpeed;
                  //output to newImage object
                  g.DrawImage(image, destRect, srcRect, GraphicsUnit.Pixel);
                  //release graphics object
                  g.Dispose();
                  // release corresponding image resources
                  image.Dispose();
                  //output our image via binary stream
                  using (MemoryStream ms = new MemoryStream())
                  {
                        //image format is specified as Jpeg
                        newImage.Save(ms, ImageFormat.Jpeg);
                        //clear all output in the buffer stream
                        Response.ClearContent();
                        //set HTTP MIME type of the output stream to"image/Png"
                        Response.ContentType = "image/jpeg";
                        //output binary stream of the image
                        Response.BinaryWrite(ms.ToArray());
                  }
                  //release corresponding image resources
                  newImage.Dispose();
                  //Output
                  Response.Flush();
                  Response.End();
            }
//……

Here, among the parameters passed to pic.aspx, (l,t) represents the upper left of the image inside the whole big map, while (w,h) refers to the width and height of the image output.

With the dragging mouse coordinates, we can easily figure out the partial image in the viewing area. Thus, we add the following code (see Listing 3) into the client side of maps.aspx.

Listing 3

window.onload = function()
{
      if (document.all || document.getElementById)
      {
            oThang = document.all ?
 document.all["thang"] : document.getElementById("thang")
                        oHandle = document.all ?
 document.all["handle"] : document.getElementById("handle")
            Drag.init(oHandle, oThang, -250, -105, -250, -158);
            oThang.onDragEnd = function(x, y)
            {
                  refreshMap(x + 250, y + 250);
            };
      }
      // Update map show 
      function refreshMap(x, y)
      {
            oldX = x;
            oldY = y;
            //asynchronously invoke AJAX method
            MapViewer.Maps.GetMapInfo(x, y, GetMapInfo_callback);
      }
}

Well, so far, whenever we move the eagle-eye the partial area behind the web page it will be immediately updated, as well as show that area and the corresponding eagle-eye are consistent.

Rasterizing the output

The above outputting method is easy to achieve, while with even a short distance moving you have to update the whole content of the map. Then here arises a question-how to decrease the outputting quantity of the image? The approach introduced here is to divide the whole map into small square blocks and render by blocks. This way we can make full use of the buffering capacity in the server side and client site so as to reduce the quantity of repeatedly downloaded pictures with small quantities of map moving. So far, experienced readers may have realized the Buzz Word-AJAX. Quite right, but we will discuss details it later on.

First concentrate on dissecting the image, as is illustrated in Figure 3 below.

Figure 3 –The corresponding position of the viewing area in the whole map.

Seen from Figure 3, there are total four cases (illustrated by A, B, C and D respectively) to be noticed, as listed below:

Case A: The upper left corner of the show area is just the vertex of the map grid, which is the simplest case and we just need output the total block of picture.

Case B: The top edge of the show area just aligns with the horizontal line of the map grid, under which case other parts of the image are integer number of blocks except for the left and right areas.

Case C: The left edge of the show area just aligns with the vertical line of the map grid, under which case other parts of the image are integer number of blocks except for the top and bottom areas.

Case D: This is the most complex case, under which case the left edge of the show area aligns with neither the vertical nor the horizontal line of the map grid. So we need to deal with the four edge areas while internal parts of the image are integer number of blocks.

To adopt such a policy to output image by blocks is because we can optimize the performance of the system thanks to the buffering mechanism supplied by ASP.NET 2.0. According to the idea suggested above, we can put our project into action from two aspects- the server side and the client side.

Server side:

In this sample we use a famous open source framework – AjaxPro.NET. Above all, we should add reference to AjaxPro.dll to the project (for related details, see the accompanying downloaded guide titled "A Quick Guide How to Start.doc"). With this done, let us start to modify the crucial configure file for ASP.NET 2.0-Web.config, as shown below.

Listing 4

//……(omitted)
      <system.web>
            <httpHandlers>
                  <add verb="POST,GET" path="ajaxpro/*.ashx" type="AjaxPro.AjaxHandlerFactory, AjaxPro" />
            </httpHandlers>
            ……(omitted)
      </system.web>;

Moreover, we should do something to register the current page class.

Listing 5

private void Page_Load(object sender, System.EventArgs e)
{
      //Put the user-code here for initialization
      Utility.RegisterTypeForAjax(typeof(Maps));
}

To describe properties such as the position and URL of the image, we provide an ImageInfo class.

Listing 6

//ImageInfo class—responsible for small pieces of pictures
public class ImageInfo
{
      ///URL of the image
      private string _url;
      public string URL
      {
            get
            {
                  return _url;
            }
            set
            {
                  _url = value;
            }
      }
      ///x coordinate of the picture’ upper left corner 
      private int _left;
      public int LEFT
      {
            get
            {
                  return _left;
            }
            set
            {
                        _left = value;
                  }
            }
            ///y coordinate of the picture’ upper-left corner
            private int _top;
            public int TOP
            {
                  get
                  {
                        return _top;
                  }
            set
            {
                  _top = value;
            }
      }
      //ID identity to mark the small image
      private string _id;
      public string ID
      {
            get
            {
                  return _id;
            }
            set
            {
                  _id = value;
            }
      }
}

Next, on the server side we begin to create AJAX method named GetMapInfo (int x, int y) with parameters x and y representing the x and y coordinates of the eagle-eye in the thumbnail image, respectively. Here, with parameters x and y, we can easily figure out the corresponding show region inside the whole map and decide which case (i.e. Case A, B ,C and D) it belongs to and return the relevant image information. Here is the crucial code snippet for GetMapInfo.

Listing 7

///Returns URL and pos info of the small image to client side
/// </summary>
/// <param name="x">x coordinate of the eagle-eye's upper left corner in the thumbnail image</param>
/// <param name="y"> y coordinate of the eagle-eye's upper left corner in the thumbnail image </param>
/// <returns>information of the small image </returns>
[AjaxMethod()]
public ImageInfo[] GetMapInfo(int x, int y)
{
      //size of the raster grid
      int iStep = 100;
 
      //returned map info
      ImageInfo[] map = null;
 
      int iReminderX = (x * 5) % iStep;
      int iReminderY = (y * 5) % iStep;
 
      //According to the remainder, we calculate under four cases
      if (iReminderX == 0)
      {
            if (iReminderY == 0) //x and y directions are both integral
            {
                  //……(omitted)
            }
      }
      return map;
}

The code of the method GetMapInfo is so long that we have to cut it down. For detailed analysis of the whole code, please see the downloaded source code.

Client side:

Here we can make full use of the AJAX technique to update the show area in real-time via asynchronous AJAX invocation. The main idea behind this lies in the absolute location of the <img> object, with which we can piece together small scraps of images into a bigger one. Since the object ImageInfo returned from the server side has already included necessary information, such as coordinates and URL of the image, we can conveniently update the show area with methods provided by DOM. On the other hand, information of the map coordinates is also provided on the client side for quickly locating so that the user can see the absolute mouse position in real-time. Here is the main code in the client side.

Listing 8- SQL clause for creating the Mapinfo table.

// Update map show
function refreshMap(x, y)
{
      oldX = x;
      oldY = y;
      //asynchronous Ajax method
      MapViewer.Maps.GetMapInfo(x, y, GetMapInfo_callback);
}
 
// Callback, repaint the map region with returned map info
function GetMapInfo_callback(response)
{
      // Imageinfo object array
      var arImageInfo = response.value;
      
      //if successfully get ImageInfo array 
      if (arImageInfo)
      {
            // <div> object for map show region
            var div = document.getElementById("map");
            //delete the old pictures
            while (div.childNodes.length > 0)
            {
                  div.removeChild(div.childNodes[0]);
            }                             
            
            //iterate through every picture info
            for (var i = 0;i < arImageInfo.length;i++)
            {
                  //pre-buffering the picture using JavaScript's image object
                  var image = new Image();
                  image.src = arImageInfo[i].URL;
            }
            for (var i = 0;i < arImageInfo.length;i++)
            {           
                  //Create a new <img> object
                  var img = document.createElement("img");
                  
                  // URL of the image
                  img.src = arImageInfo[i].URL;
                  
                  //image show pos
                  img.style.position = "absolute";
                  img.style.left = 400 + arImageInfo[i].LEFT;
                  img.style.top = 80 + arImageInfo[i].TOP;
                  //……
                  img.onmousemove = function()
                  {
                        //Calculate mouse ordinates on the whole map
                        //Note, we should allow for page scrolling
                        var x = event.x + document.body.scrollLeft - 400 + 5 * oldX;
                        var y = event.y + document.body.scrollTop - 80 + 5 * oldY;
                        
                        //show mouse pos ordinates when moving the mouse
                        ShowPosInfo(x, y);
                  }
                  // append the image into <div>object
                  div.appendChild(img);
            }
      }
}
// show ordinates info in status bar
function ShowPosInfo(x, y)
{
      window.status = "x = " + x + ", y = " + y;
}
//……(omitted)

View Entire Article

User Comments

Title: ImageInfo   
Name: sliptnock
Date: 2008-10-08 10:45:34 AM
Comment:
In the listing 7 in public " ImageInfo [] " getmapinfo{} gives me a mistake " The type or the name of the space of names 'imageinfo' does not exist in the space of names 'MapViewer' (is reference absent of ensamblado?). To which it owes?






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 6:17:35 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search