王朝网络
分享
 
 
 

AJAX实现的多人协同设计

王朝学院·作者佚名  2009-10-29  
宽屏版  字体: |||超大  

Download board.zip - 39.6 KB - Old Version

Download board_2008.zip - 55.03 KB - Latest VS 2008 Version

Introduction

This is an AJAX based WhiteBoard application. Typically unlike their desktop based counterparts, web applications need to be designed to use optimal server resources. This is one of the reasons for AJAX being popular. Here I demonstrate a powerful use of AJAX to make communication possible between two or more clients.

So, What can this do?

As I said, this is a WhiteBoard Application. Users are provided with certain drawing tools, color selections, etc. The basic idea is to share the user drawings among all the clients. All the users viewing the main page can participate in the drawing and share it with all other users. Clearing local canvas, server data, etc is also possible.

Background

A couple of years ago I was assigned the task of researching the capabilities of AJAX. Being a tech freak I was hell bent on convincing the client to use the then NEW AND HOT technology. I wasted a few days thinking on my right approach to the design and GUI. I wanted the application to look something like a desktop application and yet be executed in a browser. My aim was to avoid postbacks completely.(To impress the client). I was scampering through every result on google, reading every article on AJAX so as to get the perfect Application as a demo.

I happened to see a javascript (wz_jsgraphics.js) by Walter Zorn Link . It was then that the idea of building a web based WhiteBoard struck me. I give full credit to Walter for his excellent javascript. Once I learned using his script, it was just a matter of days before my own Web based Whiteboard was up and running.

The Basics...

As in all AJAX based applications, I have a main page that is displayed to the user. A page on the server handles all the requests and responses to this page. All the drawing part is done using Walters javascript. I designed a messaging mechanism to identify the clients request and serve the client accordingly. I have divided the javascript into various files, depending on the functionality. Understanding the application flow is fairly simple.

Notice that at any point the client initiates a request of data. The server only acts as a central place to hold the data (using ArrayList). The client sends a number indicating the start position from where it is requesting the data.

Using the code

You can find a detailed explanation of the graphics library on Walters's website.

I will start with a brief explanation on the contents of every file.

Javascript Files :-

1) ajaxfunctions.js - Contains functions that send and receive data from the server. It also contains javascript functions to update the screen canvas after getting the data from the server. Functions for selection of tools and colors, sending request to clear server data, etc are also placed in this file.

2) ajaxobjects.js - Contains functions to create ajax object and send the XMLHTTP request.

3) common.js - Contains functions I thought would cramp the main page. Mostly 1 - 2 line functions which are used many times.

4) constants.js - Contains all the client side constants used for the application. Classified as Colors, tools , query string , etc.

5) drawing.js - Contains functions that will handle the drawing and also initiate contact with the server.

6) wz_jsgraphics.js - This is ofcourse the most important drawing library without which this application is a stub. It contains all the functions that actually draw the shapes on the client side canvas.

ASP.NET Files. (Server Side C#) :-

7) Constants.cs - This contains all server side constants.

8) HandleData.aspx - This is the file where all the ajax requests are posted to. It has functions to decide what the client wants and then respond with the users data.

9) index.aspx - This is the main form with all controls. It is just a service user. This page serves as a GUI which initialises the sharing process.

Putting it up all together, this is a simple explanation.

1) User "A" loads the "index.aspx" page on his screen.

2) He selects some tool and some color and starts designing on his screen.

3) One more user, User "B" visits the "index" page.

4) Since "B" is a new user he gets all the data from the server and user A's canvas is replicated on user B's screen.

5) Now AJAX comes into picture. To keep both the users in sysnc, AJAX scripts are running at regular interval.

6) When a user makes any changes in the selected tool, color or draws something on the screen, an AJAX script updates the server.

7) The steps are repeated with any number of users.

8) I think ideally in a LAN/WAN environment 15 users can be easily accomodated.

Lets begin the detailed explanation of some of the important client side functions.

Collapse Copy Code

//Function to set the drawing data on the server

function setData() {

var requestUrl;

//Get the url path

requestUrl = CONST_URL_PATH;

requestUrl += getToolString();

xmlHttp = GetXmlHttpObject(setDataHandler);

xmlHttp_Send_Request(CONST_METHOD_POST, xmlHttp, requestUrl);

}//End of setData

Collapse Copy Code

//Function to get the drawing data from server

function getData() {

var requestUrl;

//Get the url path

requestUrl = CONST_URL_PATH;

requestUrl += CONST_QUERY_PARAM + CONST_QUERY_PARAM_GETDATA;

requestUrl += '&' + CONST_QUERY_READ_FROM + getValue('ReadFrom');

xmlHttp = GetXmlHttpObject(getDataHandler);

xmlHttp_Send_Request(CONST_METHOD_POST, xmlHttp, requestUrl);

}//End of setData

Collapse Copy Code

//Function to get the query string for the current tool

function getToolString() {

var strOut;

strOut = CONST_QUERY_PARAM + CONST_QUERY_PARAM_SETDATA;

strOut += '&' + CONST_QUERY_ACTION + CurrentTool;

strOut += '&' + CONST_QUERY_COLOR + CurrentColor;

strOut += '&' + CONST_QUERY_STROKE + CurrentStroke;

strOut += '&' + CONST_QUERY_STARTX + StartX;

strOut += '&' + CONST_QUERY_STARTY + StartY;

strOut += '&' + CONST_QUERY_EndX + EndX;

strOut += '&' + CONST_QUERY_EndY + EndY;

return strOut;

} //End of getToolString

The "setData" function calls the "getToolString" function before contacting the server. The "getToolString" function constructs a string in the required format to be sent to the server. Then the "setData" function brings the AJAX object into use and sends a string of data to the server.

The "getData" function creates a request string and requests data from the server, again using AJAX objects.

Notice that in both the functions the callback datahandler is different.(Datahandler is a function that decides what to do with the data returned from the server)

Collapse Copy Code

//Function to handle the callback for the set data ajax function

//THIS HANDLER IS USED FOR TWO AJAX FUNCTIONS

function setDataHandler() {

//readyState of 4 or 'complete' represents that data has been returned

//Check the state of the page

if (xmlHttp.readyState == CONST_INT_READY_STATE || xmlHttp.readyState == CONST_READY_STATE){

//Get the response text

var strText = xmlHttp.responseText;

//Check if error occured

if (strText.indexOf(CONST_ERROR) >= 0) {

//Error occured

errHandler(strText.split(CONST_INTERNAL_SEPERATOR)[1]);

} else {

//Reset the status bar text msg for success

errHandler(CONST_MSG_DATASET);

//Change the value in the hidden so that next

//read starts after the

//current value

setValue('ReadFrom', parseInt(getValue('ReadFrom')) + 1);

}//End of checking if error occured

//Toggle the waiting div

toggleLoading(false);

} //End of checking if the script is over

} //setDataHandler

The "setDataHandler" function first checks if the browser is in ready state. Then it reads the returned ResponseText from the AJAX object, checks for any errors and then resets the status bar message accordingly. At the end it also sets the current instruction number that it has received from the server.

Collapse Copy Code

//Function to handle the call back of the get data ajax function

function getDataHandler() {

//readyState of 4 or 'complete' represents that data has been returned

//Check the state of the page

if (xmlHttp.readyState == CONST_INT_READY_STATE || xmlHttp.readyState == CONST_READY_STATE){

//Get the response text

var strText = xmlHttp.responseText;

//Check if error occured

if (strText.indexOf(CONST_ERROR) >= 0) {

//Error occured

errHandler(strText.split(CONST_INTERNAL_SEPERATOR)[1]);

} else {

//Reset the status bar text msg for success

errHandler(CONST_MSG_DATAGET);

//Update the screen

var iNum = updateScreen(strText);

//Change the value in the hidden so that next

//read starts after the set value

setValue('ReadFrom', parseInt(getValue('ReadFrom')) + iNum);

}//End of checking if error occured

//Toggle the waiting div

toggleLoading(false);

//Set a call to the same function again after the specified time interval

window.setTimeout('getData()', CONST_DATA_TIMEOUT);

} //End of chekcing if the script is over

} //End of getDataHandler

The "getDataHandler" function also checks if the browser is in ready state. Then it reads the returned ResponseText from the AJAX object, checks for any errors and then resets the status bar message accordingly. Unlike the "setDataHandler" function, this function first updates the screen (updateScreen function call) and then sets the current instruction number.

Collapse Copy Code

//function that will handle the data that is received from the getData function

function updateScreen(strText) {

//Split the text into lines

var strLines = strText.split(CONST_LINE_SEPERATOR);

var i;

//Check the length of the lines

if (strLines.length > 0) {

//Loop on the no of lines

for (i = 0; i < strLines.length; i++) {

//Get the individual properties by splitting each string

var strMainText = strLines[i].split(CONST_INTERNAL_SEPERATOR);

//Check if CLEAR IS CALLED

if (strMainText[0] == CONST_ACTION_TOOL_CLEAR) {

//CLEAR THE CANVAS

clearCanvas();

} else {

//Set all the variables before calling the draw function

setTool(strMainText[0]);

setColor(strMainText[1]);

setStroke(parseInt(strMainText[2]));

setStart(parseInt(strMainText[3]), parseInt(strMainText[4]));

setEnd(parseInt(strMainText[5]), parseInt(strMainText[6]));

//Now call the draw function

drawPic();

} //End of checking the call for CLEAR

} //End of looping on the no of lines

//Return the count so the next search starts after this number

return i;

} //End of checking the no of lines

return 0;

} //End of updateScreen

The "updateScreen" function splits the received text based on the predefined special characters. The first split is actually the split of instructions. The second split is the inter instruction split (to get the tool, color, start and end, etc) After breaking the data it draws the required image on screen.(call to drawPic function) Now, let us have a look at the server side. The server side is handled by the "HandleData.aspx" page load event. Depending on the request the "getData" or "setData" functions are called.

Collapse Copy Code

//Function to get the data and set it to the page

private void getData()

{

string strReadFrom = Request.QueryString.Get(Constants.CONST_QUERY_READ_FROM);

//Check the read value

if (strReadFrom != null && strReadFrom.Length > 0)

{

StringBuilder strText = new StringBuilder("");

int iFrom = Int32.Parse(strReadFrom);

//Get the array list from the application object

ArrayList arrData = (ArrayList)Application[Constants.CONST_APP_DATA_ARRAY_NAME];

//Check if ifrom is equal to the length of the arraylist

//Means no new data to read

if (iFrom >= arrData.Count)

{

//Screen is already updated

//Write the error with the first word set to identify as error

Response.Write(Constants.CONST_ERROR +

Constants.CONST_INTERNAL_SEPERATOR +

Constants.CONST_ERROR_ALREADY_UPDATED);

return;

} //End of checking the length

//Add the first element

strText.Append(arrData[iFrom]);

//Do the process to create a response string

for (int i = iFrom + 1; i < arrData.Count; i++)

{

strText.Append(Constants.CONST_LINE_SEPERATOR + arrData[i]);

} //End of appending the data to the string builder

//Write the string builder to the page

Response.Write(strText.ToString());

}

else

{

//Write the error with the first word set to identify as error

Response.Write(Constants.CONST_ERROR +

Constants.CONST_INTERNAL_SEPERATOR +

Constants.CONST_ERROR_PARAM);

}//End of checking the read value

} //End of getData

This "getData" function first reads the COUNTER from where the client is requesting data. It then loops on the serverside ArrayList that stores the instructions. Here it also checks for existence of new data. In case new data exists, only then the output string is created and then returned using the "Response.Write" statement. (This is the string that is returned to the calling AJAX function).

Collapse Copy Code

//Function to set the data on the server

private void setData()

{

//Get the array list from the application object

ArrayList arrData = (ArrayList)Application

[Constants.CONST_APP_DATA_ARRAY_NAME];

//Get all the drawing values from the request querstring

string strAction = Request.QueryString.Get(Constants.CONST_QUERY_ACTION);

string strColor = Request.QueryString.Get(Constants.CONST_QUERY_COLOR);

string strStroke = Request.QueryString.Get(Constants.CONST_QUERY_STROKE);

string strStartX = Request.QueryString.Get(Constants.CONST_QUERY_STARTX);

string strStartY = Request.QueryString.Get(Constants.CONST_QUERY_STARTY);

string strEndX = Request.QueryString.Get(Constants.CONST_QUERY_ENDX);

string strEndY = Request.QueryString.Get(Constants.CONST_QUERY_ENDY);

if (strAction != null && strAction.Length > 0)

{

if (strAction.Equals(Constants.CONST_ACTION_TOOL_CLEAR))

{

arrData.Add(strAction + Constants.CONST_INTERNAL_SEPERATOR);

}

else

{

//Check if all are present

if (strColor != null && strStroke != null &&

strStartX != null && strStartY != null &&

strEndX != null && strEndY != null &&

strColor.Length > 0 && strStroke.Length > 0 &&

strStartX.Length > 0 && strStartY.Length > 0 &&

strEndX.Length > 0 && strEndY.Length > 0)

{

//Set the data in the application array

arrData.Add(strAction + Constants.CONST_INTERNAL_SEPERATOR +

strColor + Constants.CONST_INTERNAL_SEPERATOR +

strStroke + Constants.CONST_INTERNAL_SEPERATOR +

strStartX + Constants.CONST_INTERNAL_SEPERATOR +

strStartY + Constants.CONST_INTERNAL_SEPERATOR +

strEndX + Constants.CONST_INTERNAL_SEPERATOR +

strEndY);

//Write a blank string as an identification that no error occured

Response.Write("");

}

else

{

//Write the error with the first word set to identify as error

Response.Write(Constants.CONST_ERROR +

Constants.CONST_INTERNAL_SEPERATOR +

Constants.CONST_ERROR_PARAM);

}//End of Checking if all querystrings are valid

}

}

else

{

//Write the error with the first word set to identify as error

Response.Write(Constants.CONST_ERROR +

Constants.CONST_INTERNAL_SEPERATOR +

Constants.CONST_ERROR_PARAM);

}//Check if the action is not null

} //End of setData

The "setData" function does exactly the opposite task. It gets all the parameters from the request and makes a string out of it. It then adds the string to the serverside ArrayList. In case of errors it writes the error using the "Response.Write" statement. Other places of concern are the function calls that are set on the "index.aspx" page. You can easily add new colors and new functionality. Just add the relevant constants and incorporate the required functions. The messaging architecture remains the same.

Points of Interest

A simple messaging architecture can be used to linkup many computers. When the application is running it seems to be a very huge task. Since we are doing bulk of the task on the client side the user experience is also great.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有