I'm shooting for at least one post a month and I'm on a two month roll. This month's entry is about a feature not available to all. Those of you on IE, Firefox and Opera can move along. Those with Safari and Chrome can hang around. Unfortunately, this cool feature doesn't work with Safari on the iphone, at least not v2.0.

One of the new cool things that comes with HTML5 support is canvas. Using canvas you can write graphics directly to the browser. The chart image was made using canvas and a little chart api I wrote a while back in .net. I converted the api to javascript. I only moved over the bar chart though there are a few other charts still in .net. I'll move them over when I get a chance. I'm thinking of changing up holeytwit to track and cache the top searches over time and use the chart canvas api to chart out the results.

To see iCanChart and canvas in action click on the image or this link.

To get started with canvas, you need to create a ..... you guessed it a ..... canvas tag.


<body onload="draw()">
<canvas id="canvas1" width="500" height="300"></canvas>
</body>

To use the chart api just build a set of data points with labels and pass them in to the chart init method along with the canvas id, size, and title. Don't forget to import the iCanChart.js script file.

<script type="text/javascript" src="../script/iCanChart.js"></script>
<script type="text/javascript">
function draw(){
var bc = new BarChart;
var dataPoints = new Array();
// build out the data points
for(var i=0;i<10;i ){
dataPoints[i] = new Object();
dataPoints[i].Label = 'day ' (i 1);
dataPoints[i].Value = Math.random()*100;
}

// create the chart
bc.initBarChart('canvas1',300,500,dataPoints,'Hits per Day','hits');
}

</script>


The charts scale automatically to the height and width passed into the init. The x and y axis will scale based on the values passed in as data points. You can reset the round up value to adjust how far the y axis will round up, the next 100, the next 1000, so on. All colors can be modified and a threshold can be set to what every you like. There's a two series bar chart (still only in .net) that i've found useful for comparing site activity with errors encountered. Both of the y axes scale to their own data points. I'll convert the two series chart class next.

back to canvas....

To create these charts, I had to draw lines, write text, and a rectangle. You're probably thinking that this doesn't sound too hard. You would be correct. With canvas you set your attributes, like line width, font, color, alignment, a bunch of others on the fill or stroke. You then open the path (canvas), perform the action )stroke or fill, and then close the path (canvas). I wrote a few helper methods to ease the move from .net. The code is below and can be found in iCanChart.js.

function canvasElement(){
return document.getElementById(this.canvasId).getContext('2d');
}
function drawLine(_color,_width,_x1,_y1,_x2,_y2){
var ctx = this.canvasElement();
ctx.beginPath();
ctx.strokeStyle = _color;
ctx.lineWidth = _width;
ctx.moveTo(_x1,_y1);
ctx.lineTo(_x2,_y2);
ctx.stroke();
ctx.closePath();
}
function drawRectangle(_color,_x,_y,_height,_width){
var ctx = this.canvasElement();
ctx.beginPath();
ctx.fillStyle = _color;
ctx.fillRect(_x,_y,_width,_height);
ctx.fill();
ctx.closePath();
}
function drawText(_color,_align,_font,_text,_x,_y){
var ctx = this.canvasElement();
ctx.beginPath();
ctx.font = _font;
ctx.textAlign = _align;
ctx.fillStyle = _color;
ctx.fillText(_text, _x, _y);
ctx.fill();
ctx.closePath();
}

Ok this is a different topic entirely... In my last post I mentioned that my wife and I fight over the macbook. Well we will fight no longer. No, I didn't get rid of my wife. I love her and need her and its in my best interest to keep her happy. Instead, I just gave up the fight and let her have her macbook back. I didn't give up on mac, I just won't use her mac any longer. This weekend I ordered a refurb macbook of the apple online store. With the refurb price and the fact that TN had a sales tax free weekend, I saved quite a few bucks. I mentioned in the last post that I'm also running a notebook with kubuntu. I like it alright, but honestly it's just not as polished as mac osx. I even got the right wireless drives installed but it's still not as responsive as the mac. The eclipse install isn't quite right either. Only the old version of Eclipse works and I had to play around with it to get the font sizes right. It also crashes quite often. By the way, I run opera on Kubuntu. I like opera much better than firefox. The only reason I ever use firefox now is for firebug. I installed opera on my son's Xubuntu (Celeron 1.2GHz w/ 256MB) and it's fine. Although he complains that the warrior cats games are a little slow in flash. All he does is look up the occasional pokemon hint. He doesn't need much more.

Sorry, I don't have a decent name for this yet.

My wife picked up a new learning math cartridge for my son's DS last week. I'm not sure why we thought we could trick my son into thinking that a DS cartridge that teaches math would be cooler than the upteenmillion Pokemon games he owns. Predictably, he only played it for the first 10 minutes right after he cracked it open. Once he discovered that there was no shooting or spells or attacks involved, it was never seen again. We got the game mainly to build up his speed in answering questions. He gets stressed out when we time him, so we thought it would be better if the DS took the heat.

But all is not lost. One of the games on this cartridge was a grid that you had to complete. The little Japanese scientist in the game says that all the Japanese kids are doing it. It's the latest fad. The game goes like this...You choose the operation and how many cells you want to fill out and go. It's timed and you can compete with up to 15 other people (As we all know 15 is the magical size limit for all Japanese classrooms and of course all Japanese students are issued a gameboy as soon as they enter preschool). I wanted to impress the Japanese with my skills, so this weekend I created a copy of the grid game matrix thing. It's not quite complete, but is good enough to show.

The limitations are:

1. Only multiplication
2. Not working on Safari or iPod (yet...more below)
2a. Only tested on IE, so Patrick it probably won't work on firefox

3. Timer not yet available - Next, should be pretty easy
4. 15 school children cannot play together (interesting, might add and make it 42 so American classmates can play)
5. Always 100 cells
6. No score or fireworks when you finish, works like flashcards

To play click mathMatrix or click on the picture.

Update: Safari now works. I reworked the game to store the values of the display in an array of numbers. Originally we were trying to manipulate the display cell values. It works on the iPod as well. I'm going to rework the keypad to make the numbers easier to hit on the ipod.

Updated 3/9:fixed the innerText problem with Firefox and added something at the end

Take a look at the clock that tells time in a not very friendly way. Here's a link to the clock. A description of the code is below.

You can view the page source to see all of the style and script. It should be pretty easy to reduce the size of the blocks and put this in the corner of a page. It might look like one of those stupid animated gifs from the 90's.

The time is 20:11 in the clock to the right.

It's been almost a month since I last made a post. Sorry but I've been busy, mainly with work. I can only spend a few hours a week working on this. I'll make up for it with two posts in one day. The first post is to talk a little more about the asynchronous library I originally created for this blog. It's called SimpleAsynch. I't's been enhanced a bit and I'm now using it on a new application that I'll talk about a later. (Sorry Patrick, I haven't been writing games where things blow up. I promise to do that next.)




The world doesn't really need another asynchronous library, but this one is different. I created it. That doesn't make it better just different. Something else that might make this different is how the requests and responses are constructed and used.

1.Construct a request and submit it to the application server through a post action using XMLHttpRequest.
2.On the application server treat the request as any standard post request, parse the parameter list and perform an action, database update, reach out to a web service, etc.
3.When we're ready to return a response, use the asynchronous library to construct a XML document. In the document is a list of action node. Each action node is made up of an action (duh), the action recipient which could be an element id or JavaScript function, and finally a value to either store in the element or pass to a callback.
4.The response is then returned to the browser where the asynchronous library loops through and executes all of the actions.




There are several actions available:

input - populate an input field, if it doesn't exist create a hidden input field and store the value
div - replace the innerHTML of the div with the value supplied
options - replace all options in a select with the comma delimented option list stored in the value
select - set the selected option in a select to the value supplied
tab - if we use the tabber.js library, we can use this action to activate the tab named in the value parameter
delayCallback - we can use this to execute a callback function on the client, I can't remember why I needed this, I had a reason
callback - use the callback to execute yes a callback, the callback function could build another asynchronous request, we actually do this on the admin piece for the blog and on the project application that I'll talk about later
alert - the alert action will display an alert with the name and value concatenated, useful for reporting errors or for debugging

Now the first version of SimpleAsynch did not construct a XML response, but returned a pipe delimented set of actions, ids, and values. While the delimented response was initially easier to construct and prove out, it was a pain to manage and debug once more complex actions were performed. The project application uses the XML version, while the blog and Salesforce applications use the old delimited version.

The current library accommodates the most important of all browsers, IE6. There are no other browsers. That's wrong. It actually supports all browsers that I have access to IE6, IE7, Firefox 3 on Windows and Linux, Safari 3 on Mac and iPod. I've not downloaded Safari 4 yet nor I have I tried it on Chrome.

Now for some sample code...
The event handler on the browser constructs the request using SimpleAsynch.


function updateProject(){
var request = ""
request = addRequestFunction(request,"updateProject",false);
request = addRequestParameter(request,"projectId",false);
request = addRequestParameter(request,"projectName",false)
request = addRequestParameter(request,"projectStatus",false)
request = addRequestParameter(request,"projectDescription",false)
request = addRequestParameter(request,"projectScheduledStart",false)
request = addRequestParameter(request,"projectScheduledStop",false)
request = addRequestParameter(request,"projectActualStart",false)
request = addRequestParameter(request,"projectActualStop",false)
request = addRequestParameterAndValue(request,"projectAccessList",getAccessList(),false)
request = addCallback(request,"clearProjectForm",true);
postRequest("/updateProject",request);
}

There are a few functions that can be used to add parameters, addRequestFunction, addRequestParameter, addRequestParameterAndValue, and addCallback. The addRequestParameter function will locate the element by the id passed and will populate the value of that element in the parameter list. The addRequestParameterAndValue will let you add parameters to the request for elements that may not exist on the page. The addCallback function will be returned back to the client by the application server in the action list. Finally, postRequest will send the request off to the server.

I won't pull up all of the SimpleAsynch.js code here. You can get it from the site.

On the server you would process the request and build a response. Here's an example where we're trying to populate the screen with the details of a requirement. This example shows the construction of the xml using the SimpleAsynch ResponseXml class. ResponseXml uses a django template to construct the XML for the response.


class LoadRequirement(webapp.RequestHandler):
def post(self):
requirementId = self.request.get('requirementId')
requirements_query = db.GqlQuery("SELECT * FROM Requirement where requirementId = :1",
int(requirementId))
requirements = requirements_query.fetch(1)

rx = ResponseXml()

for requirement in requirements:
rx.addAction("input","requirementIdHidden",str(requirement.requirementId))
rx.addAction("input","requirementNumber",str(requirement.requirementNumber))
rx.addAction("input","listRequirementNumber",str(requirement.requirementNumber))
rx.addAction("input","requirementSubNumber",str(requirement.subNumber))
rx.addAction("input","requirementVersion",str(requirement.version))
rx.addAction("input","requirementMaxVersionHidden",str(requirement.maxVersion))
rx.addAction("input","requirementSummary",requirement.summary)
rx.addAction("input","requirementDescription",requirement.description)
rx.addAction("input","requirementComments",requirement.comments)
rx.addAction("input","requirementStatus",requirement.status)
labelString = ""
for label in requirement.labels:
labelString = label " "
rx.addAction("input","requirementLabels",labelString)
rx.addAction("input","requirementAuthor",str(requirement.requirementAuthor))
rx.addAction("input","requirementEntered",requirement.entered.strftime("%m/%d/%y %H:%M"))
rx.addAction("callback",self.request.get("callback"),"")
if rx.getLength()==0:
rx.addAction("alert","Requirement was not found.","")
self.response.out.write(rx.getXml())

 
 User
top comments
 
top views
 
top tags
 
favorite sites