![]() |
Web Development »
Ajax and Atlas »
Atlas
Intermediate
License: The Code Project Open License (CPOL)
Atlas Tutorial: Creating an AJAX Scribble applicationBy Rama Krishna VavilalaA tutorial on creating an AJAX version of the popular MFC sample. The tutorial utilizes ASP.NET Atlas framework. |
C#, Javascript, XML, HTML, Windows, .NET, ASP.NET, WebForms, Ajax, VS2005, Dev
|
|
Advanced Search |
|
|
||||||||||||||||||
Please read instructions at the end of article on how to run the application after downloading the source.
ASP.NET Atlas is a rich set of client side and server side libraries to develop AJAX-style applications using ASP.NET. This tutorial (and probably more in this series) attempts to provide a general view of the features available in Atlas. Since, Atlas is a very vast library this very first tutorial concentrates on two most important features of Atlas:
MFC Scribble application was one of the first application that I used to learn MFC. Therefore, I decided to base this tutorial on Scribble. Scribble application allows users to draw freehand sketches using the mouse. I first saw a similar application on the web, utilizing AJAX technologies, at the JavaScript Draw website. The JavaScript draw website works only on Mozilla Firefox. This article describes how to build a cross-browser version of the application. We will build on the application in each article in this series to demonstrates more features of Atlas.
At the time of writing of this article, December CTP of Atlas can be downloaded by clicking this link. If this link does not work you can always go to the Atlas website to get the correct link. The Atlas library is available as a Visual Studio 2005 template (VSI). The download site has instructions on how to install the template.
Once the Atlas template is installed you can create a blank Atlas project by clicking selecting the menu option: File -> New -> Web Site. This brings up the New Web Site dialog box as shown.

Under location you can either select File System or HTTP. Selecting HTTP will allow you to create a web site on an IIS server and selecting File System will allow you to create a web site on your local file system (which you can debug and test using the ASP.NET development web server). You can select either option but I have found the application to work better with Internet Explorer on IIS.
The newly created Atlas web site has the following directory structure.
The December release of Atlas has the following client scripts.
Atlas adds the following files to the root directory of the web site.
The Scribble application allows users to draw freehand sketches by clicking on the left mouse button and moving mouse around. A sketch stroke ends when the user releases the mouse button or moves outside the drawing area. There are ways to draw using JavaScript by utilizing VML, but we are not going to use VML in this sample.
The default web page in Scribble will have an image (a regular HTML image - the IMG tag). The user mouse events over the image are captured using JavaScript event handlers. The JavaScript functions send the series of points in a sketch stroke to a web service. The web service updates and image object saved in a session variable by drawing lines through all the points sent by the client. Finally, the client requests an updated image from the server. The image source is an HTTP handler which streams the image stored in the session variable to the client. Here are the main components of the application.
Session_Start and the Session_End events are handled in Global.asax. The Session_Start creates the session variable and Session_End disposes the image stored in the session variable. We begin our coding process from Global.asax.
System.Drawing namespace. Insert the following line of code just after the first line.<%@ Import Namespace="System.Drawing" %>
Session_Start function. void Session_Start(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(200, 200);
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(new SolidBrush(Color.White),
new Rectangle(0, 0, bmp.Width, bmp.Height));
g.Flush();
}
Session["Image"] = bmp;
} The code creates a simple bitmap 200 pixels by 200 pixels white, paints the entire background white and assigns it to the session variable named Image.
Session_End function should dispose the image stored in the session variable. Bitmap bmp = (Bitmap)Session["Image"];
bmp.Dispose();
System.Drawing in the Add Reference dialog box and click OK
This web handler is supposed to stream the image stored in the session variable back to the client.
IRequiresSessionState. This is only marker interface and has no methods to override. Edit the class declaration to look like the following.public class ScribbleImage : IHttpHandler,
System.Web.SessionState.IRequiresSessionState
ProcessRequest method. public void ProcessRequest (HttpContext context)
{
context.Response.ContentType = "image/png";
context.Response.Cache.SetNoStore();
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetExpires(DateTime.Now);
context.Response.Cache.SetValidUntilExpires(false);
System.Drawing.Bitmap bmp =
(System.Drawing.Bitmap)context.Session["Image"];
lock(bmp)
{
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Png);
ms.Flush();
context.Response.BinaryWrite(ms.GetBuffer());
}
}
}
}
ContentType header in the response to image/png. This make sure that the browser identifies the response to be a png image instead of HTML.
BinaryWrite function is used, as the image is binary data. We have means of initializing the session image and to stream the image contents as response. Now we need some method to add content to the image itself. We expect the clients to call on ScribbleService.asmx web service to add lines to the image.
using System.Drawing;
System.Drawing.Point class as it is not XML serializable. In a later tutorial we will see how we can use System.Drawing.Point instead of the custom class. Add the following code just before the ScribbleService class declarationpublic class Point
{
public int X;
public int Y;
};
Draw to our web service. [WebMethod(EnableSession = true)]
public void Draw(Point[] points)
{
Image scribbleImage = (Image)Session["Image"];
lock(scribbleImage)
{
using (Graphics g = Graphics.FromImage(scribbleImage))
using(Pen p = new Pen(Color.Black, 2))
{
if (points.Length > 1)
{
int startX = points[0].X;
int startY = points[0].Y;
for (long i = 1; i < points.Length; i++)
{
g.DrawLine(p, startX, startY,
points[i].X, points[i].Y);
startX = points[i].X;
startY = points[i].Y;
}
}
}
}
}
WebMethod(EnableSession = true) ensures that the session variables are accessible from the web service.
points array. We have the server side image handler and the server side web service to update the image. Now we need the client side script in scribble application that will send the points from mouse events to the server web service.
//The HTML image element that is to be drawn
var image;
//The source of the image
var originalSrc;
//The number of iteration
var iter = 0;
//The array of points
var points = null;The comments above the variable declaration describe the purpose behind each variable. The iter variable is used to modify the source of the image after a draw request is sent to the server. In case of Internet Explorer setting image.src = image.src does refresh the image but the same code does not work for Firefox. To work around this problem we maintain the variables iter which is incremented every time we send a Draw request to the Webservice. We add the iteration number to the originalSrc variable so that the browser thinks that the it needs to request the server to get fresh data as opposed to using the cached image.
startStroke which starts a stroke in response to the mousedown event. function startStroke()
{
points = new Array();
window.event.returnValue = false;
}When a new stroke starts we create a fresh set of points as indicated by the first line. The second line cancels the default behavior of the event. This is necessary as the default behavior of the mousedown event for an image is to start a drag operation which prevents any further events from being fired.
mouseup event or mouseout event, we need to make the actual call to the webservice. This is done in the endStroke function. function endStroke()
{
if (!points || points.length < 2)
return true;
//Send the points to the webservice
ScribbleService.Draw(points, onWebMethodComplete,
onWebMethodTimeout, onWebMethodError);
points = null;
window.event.returnValue = false;
}The only interesting line in the function is ScribbleService.Draw(points, onWebMethodComplete, onWebMethodTimeout, onWebMethodError); , which invokes the web service method Draw in ScribbleService.asmx asynchronously. The function is automatically made available to us by the Atlas framework.
onWebMethodError is a function which gets invoked by Atlas framework when an error occurs in the web service method and onWebMethodTimeout gets invoked when the web method call exceeds a configurable timeout defined in the Atlas framework. In this version we just show the user a message box with the error text. function onWebMethodError(fault)
{
alert("Error occured:\n" + fault.get_message());
}
function onWebMethodTimeout()
{
alert("Timeout occured");
}
onWebMethodComplete function is called when the web method call is successful. The image needs to be reloaded when this happens. function onWebMethodComplete(result, response, context)
{
//We need to refresh the image
var shimImage = new Image(200, 200);
shimImage.src = originalSrc + "?" + iter++;
shimImage.onload = function()
{
image.src = shimImage.src;
}
}
Image object shimImage and set its source to the original source of the image we are drawing on. When the image object loads we set the source of the actual HTML image element on the page to the source of the temporary image object. This is done to avoid flicker when replacing the image.
points array during the mousemove event. This is done in the addPoints function. function addPoints()
{
if (points)
{
var point = { X : window.event.offsetX,
Y : window.event.offsetY};
points.push(point);
if (points.length == 3)
{
endStroke();
points = new Array();
points.push(point);
}
window.event.returnValue = false;
}
}
offsetX and offsetY properties of the event object and then it is appended to the points array. The offsetX and offsetY properties give the relative mouse position with respect to the HTML element causing the event.
points array. This is done so that the user can see the drawing before he releases the mouse button. pageLoad function. function pageLoad()
{
var surface = document.getElementById("drawingSurface");
image = surface.getElementsByTagName("IMG")[0];
originalSrc = image.src;
surface.attachEvent("onmousedown", startStroke);
surface.attachEvent("onmouseup", endStroke);
surface.attachEvent("onmouseout", endStroke);
surface.attachEvent("onmousemove", addPoints);
}
pageLoad function is a special function which gets invoked when the Atlas framework has finished loading. We use this instead of the regular window or body load events so that we can be sure that Atlas has finished loading.
div tag with an id of drawingSurface. The size of the element is same as the size of the image so we can safely attach to the events to the drawingSurface div. The individual components of the application need to be assembled in the Default.aspx page. Here is the code of this page.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"
Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Atlas Scribble Sample</title>
</head>
<body>
<form id="form1" runat="server">
<Atlas:ScriptManager ID="AtlasScriptManager" runat="server"
EnableScriptComponents="False" >
<Services>
<Atlas:ServiceReference Path="ScribbleService.asmx" />
</Services>
<Scripts>
<Atlas:ScriptReference Path="ScriptLibrary/Scribble.js" />
</Scripts>
</Atlas:ScriptManager>
<div id="drawingSurface"
style="border:solid 1px black;height:200px;width:200px">
<img alt="Scribble" src="ScribbleImage.ashx"
style="height:200px;width:200px" galleryimg="false" />
</div>
</form>
</body>
</html>
The most important aspect of this page is the atlas:ScriptManager server control. The ScriptManager server control is responsible for generating client side script blocks for Atlas and for any web service proxy scripts. Lets examine the usage of the ScriptManager control in the Default.aspx page.
EnableScriptComponents property is set to false. This generates a client side script block referring to AtlasRuntime.js instead of Atlas.js. We prefer the lightweight version of Atlas Framework in this version of scribble as we are not using any Atlas components or controls.
This brings all the pieces together and now you can compile and run the project. I encourage you to see the actual client html generated by the Atlas Script Manager.
Here is what Atlas framework did for us.
attachEvent and event.offsetX and event.offsetY are made available to Firefox. You can look at AtlasCompat.js file to see how this is done.
We have seen how to call web services and how to write cross browser applications with ease using Atlas. In an upcoming tutorial we see more of Atlas client side controls and declarative programming (depending on user feedback!). If you liked the tutorial please free to write a comment. If you did not like it please write a comment on how to improve it.
As Atlas is not yet redistributable, I have not included the Atlas files in the source download. Here are the steps you need to get the downloaded source to work.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Feb 2006 Editor: Heath Stewart |
Copyright 2006 by Rama Krishna Vavilala Everything else Copyright © CodeProject, 1999-2009 Web16 | Advertise on the Code Project |