Thursday, 31 December 2009

iPhone - Serialize this

Just implemented saving and loading. It's really really really simple to do.

The basic concept is the following.


// Grab the default archive

NSUserDefaults *archive = [NSUserDefaults standardUserDefaults];


// Create a magic key for the value you're about to load or save

NSString *key = [[NSString alloc] initWithFormat:@"myData"];


// To save

[archive setFloat:vector->x forKey:vectorKeyX];


// To load

vector->x = [archive floatForKey:vectorKeyX];


// Don't forget to release the key

[key release];


Armed with these tools I went with the approach to save out as much of the game state required to re-launch the game back into same state. To do this I set up the engine to process a number of scenes. Each scene is responsible for a number of objects. When I save out the game data, I go through all the objects and save out what scene they're in, so on launch, I reload all the scenes that were currently loaded, which will then create all the required objects. I then pass through all the objects and load in the required data to get them working the way they were.

I organised my objects to create unique keys depending on their object index and the internal data index I was processing. Enough talk, here's the code.

// Creates the unique key for our object

+(NSString*)getSerializeKey:(uint)index key:(NSString*)key

{

if( key == nil )

{

return [[NSString alloc] initWithFormat:@"Obj%i", index];

}

else

{

return [[NSString alloc] initWithFormat:@"[email protected]%i", key, index];

}

}


// Creates our key and passes it into the serializeInternals function for saving the internal data

-(void)serialize:(NSUserDefaults*)archive saving:(BOOL)saving key:(NSString*)key index:(uint)index

{

NSString *objectKey = [ObjectBase getSerializeKey:index key:(NSString*)key];

// The internal index will aid the creation of unique keys for our internal data

uint internalIndex = 0;

[self serializeInternals:archive saving:saving key:key index:&internalIndex];

[objectKey release];

}


// Overridden by child classes to save more data

-(void)serializeInternals:(NSUserDefaults*)archive saving:(BOOL)saving key:(NSString*)key index:(uint*)index

{

// Save our object position by default

[self serializeVector:&position archive:archive saving:saving key:key index:index];

}


// Save/load our scenes with a unique scene key

+(void)serializeScene:(SceneBase*)scene archive:(NSUserDefaults*)archive saving:(BOOL)saving key:(NSString*)key

{

NSString *sceneKey = [[NSString alloc] initWithFormat:@"[email protected]", key];

if( saving )

{

[archive setInteger:scene ? scene->index : -1 forKey:sceneKey];

}

else

{

NSInteger sceneIndex = [archive integerForKey:sceneKey];

[gEngine addScene:sceneIndex];

}

[sceneKey release];

}


// The keys for the objects internal vectors are concatenated by the object key and the internal index key

-(void)serializeVector:(Vector3*)vector archive:(NSUserDefaults*)archive saving:(BOOL)saving key:(NSString*)key index:(uint*)index

{

NSString *vectorKeyX = [[NSString alloc] initWithFormat:@"[email protected]%iX", key, *index];

NSString *vectorKeyY = [[NSString alloc] initWithFormat:@"[email protected]%iY", key, *index];

NSString *vectorKeyZ = [[NSString alloc] initWithFormat:@"[email protected]%iZ", key, *index];

if( saving )

{

[archive setFloat:vector->x forKey:vectorKeyX];

[archive setFloat:vector->y forKey:vectorKeyY];

[archive setFloat:vector->z forKey:vectorKeyZ];

}

else

{

vector->x = [archive floatForKey:vectorKeyX];

vector->y = [archive floatForKey:vectorKeyY];

vector->z = [archive floatForKey:vectorKeyZ];

}

[vectorKeyX release];

[vectorKeyY release];

[vectorKeyZ release];

(*index)++;

}


That's the basic jist of it, create unique keys for saving and loading the data.

Monday, 28 December 2009

iPhone - Posix Threads for the win

So I've been looking into multithreading my iphone engine. Switching from using a timer to threads bumped up my frame rate by about 10% instantly. I found that using Posix threads were slightly (1-2%) faster than NSThreads. Currently, I've set my engine up to have 2 additional threads. One to handle the game updating and rendering, and a second to handling job loading, with jobs being streaming in audio and textures. To handle synchronisation I'm using spin locks, which are basically while loops.

Things to note
  • When setting up your thread you must always, start and release an NSAutoRelease pool.
  • The pool should be restarted every now and then to release the objects released during the runtime of the thread.
  • When using Posix threads it's recommended you run an empty NSThread just to let the OS know that the app will be multithreaded.
  • Setting up an OpenAL context stalls the engine by around half a second on start up, so I tend to launch it in the jobs thread to avoid stalls.
  • Bumping up the priority of the render thread does improve performance slightly.

Sample code
When called the start function will launch a dummy thread which does nothing, so the thread will terminate immediately. It then launches two threads, a game thread and a jobs thread. The game thread is given a higher priority than the jobs thread.

-(void)start

{

// iPhone SDK recommends launching an empty NSThread when using POSIX threads with Cocoa applications

[NSThread detachNewThreadSelector:@selector( emptyThread ) toTarget:self withObject:nil];

// Create the game thread using POSIX routines.

createThread( &PosixGameThread, self, 0, +2 );

// Create the jobs thread

createThread( &PosixJobsThread, self, 0, -2 );

}

Empty thread does nothing, so the thread will terminate naturally upon launching.

-(void)emptyThread

{

}


Create Thread wraps the PSIOX routines required to launch a thread with a set priority.

void createThread(void *(*start_routine)(void*), void *restrict arg, int prioritySet, int priorityAdj)

{

// Create the game thread using POSIX routines.

pthread_attr_t attr;

pthread_t posixThreadID;

int returnVal;

returnVal = pthread_attr_init( &attr );

assert( !returnVal );

returnVal = pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );

assert( !returnVal );

returnVal = pthread_create( &posixThreadID, &attr, start_routine, arg );

assert( !returnVal );

struct sched_param param;

int policy;

pthread_getschedparam( posixThreadID, &policy, &param );

assert( !returnVal );

if( prioritySet != 0 )

{

param.sched_priority = prioritySet;

}

else if( priorityAdj != 0 )

{

param.sched_priority += priorityAdj;

}

assert( param.sched_priority > 0 && param.sched_priority < 100 );

returnVal = pthread_setschedparam( posixThreadID, policy, &param );

assert( !returnVal );

returnVal = pthread_attr_destroy( &attr );

assert( !returnVal );

}


The game thread owns the OpenGL context and spins around the while loop updating the frames while the game is running, while making a call lazily to refreshReleasePool to restart the pool.

void* PosixGameThread(void* data)

{

// Note: autorelease pools should be created and released more frequentley if using this feature

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

uint poolRefreshCounter = 0;

EAGLView *view = (EAGLView*)data;

[view setupGameThread];

[pool release];

pool = [[NSAutoreleasePool alloc] init];

view->runningGame = YES;

while( view->runningGame )

{

if( view->paused == NO )

{

[view update];

#if DEBUGON && TARGET_IPHONE_SIMULATOR

// 20 frames a second in debug

usleep( 50000 );

#endif

}

refreshReleasePool( &pool, &poolRefreshCounter, 100 );

}

[view shutdown];

[pool release];

return NULL;

}


The jobs thread works the same way as the game thread, but owns the OpenAL context instead and starts the file I/O operations requested by the game thread.

void* PosixJobsThread(void* data)

{

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

uint poolRefreshCounter = 0;

EAGLView *view = (EAGLView*)data;

while( view->runningGame == NO )

{

usleep( 1000000 );

}

[view->audioManager load];

usleep( 200000 );

while( view->runningGame )

{

if( [view startJobs] )

{

// 5 jobs a second

usleep( 200000 );

}

else

{

usleep( 1000000 );

}

refreshReleasePool( &pool, &poolRefreshCounter, 10 );

}

[pool release];

return NULL;

}


Refresh Release Pool handles, reseting the NSAutoreleasePool lazily for both threads.

void refreshReleasePool(NSAutoreleasePool **pool, uint *count, const uint target)

{

if( (*count)++ > target )

{

[*pool release];

*pool = [[NSAutoreleasePool alloc] init];

*count = 0;

}

}


Any questions? Feel free to ask.

Wednesday, 23 December 2009

Stock market listings bug

Just patched a lingering stock market listing bug. The API we get the latest stock market lists and news feeds from have been modified.

I've patched the market lists today, so you should now have the correct stock market listing (in case any new companies have been added/removed from the markets) and I'll get the news feed fixed soon.

Sunday, 15 November 2009

Stock news date search

Finally got some spare time to devote back on this project. Noticed that the stock news date search wasn't working any more, so quickly patched it up.



Wednesday, 9 September 2009

iPhone - It's been one week

So I spent the last week working on modelling, lighting, cartoon rendering and animations...


Modelling has been the most interesting part, rather than using a 3D modelling tool, I decided to generate it all in code using helper primitive classes, which handle drawing cubes and pyramids of differenet skews.

Lighting comes free with OpenGL, so that was easy to set up, still need to provide better normals for the models, but will work on that later.

I decided to go for a cartoon styled look by drawing lines around the edges of the primitives, had some issues with z fighting depending on the thickness of the lines, but instead of battling with it, I went with a line thickness that just worked.

Animations was fun, I hooked in a model/primitive heichreichy and created a simple controller class to handle interpolating between frames. So when the character starts running, I just pass in the rotations that I want to occur and interpolate between them using the running speed, and the controller class handles the interpolation of all the rotations for all the frames. Next challenge will be prioiritising animations, so say when doing a shooting animation while running, the shooting animation will override the arm parts of the general running animation.

But for now, I have a basic character on the screen that can run around, so the next step is tying in basic collisions so he has a world he can interact with.

iPhone - Week One

Spent the last week working on modelling, lighting, cartoon rendering and animations.


I now have a basic character on the screen that can run around. Next step is tying in more objects and colliding them.

Sunday, 30 August 2009

iPhone - Project Malaks

Last week I finally got round to purchasing a macbook air, so now I have the chance to jump in and do some iphone programming.

After spending about a week orienting myself to the new environment, OS X and xcode, I started working on creating a 3d game engine. So far it's early stages, implementing simple engine code to handle 3D third person camera and object movement. ( I'll try to post a video soon )

The plan is to have something presentable by the end of the year, I'll try to keep you posted with how the engine delopment goes regulary inbetween code thrashing sessions.

Saturday, 1 August 2009

Mortgage Calculator

Just came back from holiday and remembered that the "Super Sexy" Mortgage Calculator Contest was coming to a close. So I quickly knocked up an entry.

Check it out at http://igrapher.com/iMortgage.

There's lot's of features I'd still like to implement, but for 15 hours work over 3 days, I'm content with the outcome. Positive things about this calculator is that it doesn't use flash (so the charts work on mobiles), and does all the calculations asynchronously client side, so there's no wasted server interactions.

iGrapher

Tuesday, 14 July 2009

v1.93 News platform demo

Hey, just finished implementing the stock headlines feature. Just double click on the graph and the headlines for the stock graphed on the date hovered will be displayed.

Here's a quick video demonstrating how to use it. Enjoy.



iGrapher

Thursday, 2 July 2009

News Aggregation Update

Just a quick update on the progress of the news platform development. Currently we're working on aggregating more news sources together into the new news headlines table.

We're also looking to display the news graphed from the scan news activity feature. Meaning that soon you'll beable to graph a stock, then double click on a date, and the news for the stock released on that date will be displayed in the headlines table.

We've also started work on porting this engine to scan and chart sports news and data. This will make our engine more portable to meet our long term goal of providing an API, for our users to scan and chart their own news/data feeds.

iGrapher

Tuesday, 16 June 2009

v1.9 News Feed

The main new feature in this release is the first first step towards the new news aggregation plaform. For the moment you should notice a simple bar at the bottom of the charts displaying the latest news headlines. Coming soon will be the rest of the framework, which'll allow you to expand the news bar to see the relevant stories. As well as be able to see the news headlines of the charts as you're scrolling through the dates.

Also in this version, we've put in a lot of under the hood work in the form refactoring and optimising the engine, with a lot of niggly bugs being fixed along the way. So now it should be more dynamic and extensible from a development point of view.

iGrapher

Saturday, 30 May 2009

Chart Stock News Activity

Ever wanted to chart the news activity for a stock? Well, now you can.

To try this feature out, simply select a stock from the right menu, then click the legend button on the top left after the stock's graph displays, then select the Scan News Activity button.




We honestly don't know how useful this feature will become, but I imagine it'll has a lot of potential.

Next, we're going to be actually displaying the news that's charted on the graph, so you can easily jump to a particular date and see the news headlines with links to the actual articles. Further ahead, we'll be including more news sources and parsing the news data to judge the bias of the author of an article and how relevant it was to the stock's movement. Watch this space.

iGrapher

Saturday, 16 May 2009

Swiss SMI Market

Just finished updating the new market selection menus. Split the markets up into continental regions so we can fit in more markets per region. Added the Swiss SMI market into the European category.



Since we have more space, we're going to start charting a lot more markets very soon.

iGrapher

Wednesday, 13 May 2009

Forex Trend Shift Analysis and Predictions

Going on a big drive at the moment to get more and more features in. The latest addition to the engine giving the ability to run the trend shift analysis and predictions on currency market data. We're going to be adding in some more algorithms in the near future, so watch this space. In the mean time, here's an example of it running for the Yen.



Remember, to run analysis and predictions of your own, simple click the graph legend button on the top left, then select Analyse Trend Shifts from the menu that appears.

iGrapher

Sunday, 10 May 2009

National Stock Exchange of India Graphed

Just implemented the national stock exchange of India and the US S&P 500 markets, so you can have a play with those markets too now. Also patched a few bugs here and there mainly to do with conversion rates. Next will be to split up the different markets into regions as well as get the lastest price data pumping for the Egyptian and Indian stock markets.

Have a play.




iGrapher

Saturday, 9 May 2009

Egyptian Stock Markets

Just finished implementing the egyptian stock markets into iGrapher. Still have to feed in the latest stock movements as they occur during the day, but all the history data is now live. Going to fix up a few bugs next before implementing the latest movement and more markets.

Have a play.




iGrapher

Monday, 4 May 2009

Reddit love




iGrapher was recently featured on one of the posts in the programming section of Reddit and recieved a lot of community support. In fact, at the peak we recieved over 65,000 hits. One of the most highly suggested improvements was support for more markets. So that's what's currently in development. Feel free to suggest any particular markets you'd like to see added.

iGrapher

Thursday, 2 April 2009

3D Visualisations in the works

Just a little update on what's going on, after releasing the trend shifts analysis platform for iGrapher, our focus shifted towards bug fixing and solidifying the platform we've built up.

In the mean time we started development on a side project engine to render 3D polygons fast inside a web browser. The plan is to get it running as fast as possible so we can have 3D graphics in a web browser on the iPhone.

After having success on the initial proof of concept work, we're aiming to have a robust plug-able engine demonstrable very soon.

Here's a video of the initial proof of concept work.


Music provided by AndyT - Wagons Roll.

So hopefully soon, you'll be seeing 3D visualisations popping up in the near future.

iGrapher

Sunday, 22 March 2009

v1.71 iPhone Creature Feature

Just finished porting the trend shifts platform over to the iPhone. I've also compiled a quick features usage video to help demonstrate how to use the software.



Music provided by AndyT - Creature Feature.

iGrapher

Friday, 20 March 2009

v1.7 Trend Shifts Implemented

We just released the intial implementation of the trend shifts analysis and prediction tools, it works pretty well. I've quickly mocked up a video demonstration on how to use the new tools, just in case it's not so obvious.



Next up, we have to port it over for use on the iPhone, enable it to work off forex data (only minor tweaks required), and then go ahead and put in some more complicated trend analysis, for example as discussed before, differentiating between major/minor trends.

iGrapher

Sunday, 8 March 2009

Prediciton platform coming soon in v1.7

We have finally reached a stage where we can now work towards a providing various analysis and prediction algorithms. The first batch of tasks have been designed and are now in development.

So, in the next release you'll have the ability to:
  • Draw graphs based on the shifts in price momentum.
  • Get statistics on how often the price momentum shifts weekly, monthly, yearly breakdowns.
  • Distinguish between the types of shifts occurring (major/minor).
  • Estimate the type of the current shift currently occurring and how long it's expected to last.
It's basic analysis, however it'll be a great first step towards a more dynamic analysis tool.

iGrapher

Monday, 2 March 2009

Hacking the Heart

"If open bracket love equal equals true, my heart's pointer is forever assigned to you".

The only way to be forever assigned to someone, is by using a const pointer.
So say we had a heart inside of us..

 class Heart  
 {  
 }; 
 class Us  
 {  
 public:  
      Us()  
      {  
           myHeart = new Heart();  
      }  
      ~Us()  
      {  
           delete myHeart;  
      }  
      const Heart* GetConstHeartPtr()  
      {  
           return myHeart;  
      }  
 private:  
      Heart* myHeart;  
 };  


In our main function, since our hearts are constant, there would be no legal way to fill them. With the only solution being to hack our hearts with memcpy, and write over our heart with their heart.

 int _tmain(int argc, _TCHAR* argv[])  
 {  
      Us *me = new Us();  
      Us *you = new Us();  
      if( me != NULL && you != NULL )  
      {  
           memcpy( me, you, sizeof( Heart ) );  
           if( me->GetConstHeartPtr() == you->GetConstHeartPtr() )  
           {  
                printf( "Love" );  
           }  
      }  
 }  


Hacky but, it still doesn't work. Why? Because our hearts are empty to start with.
Now, if we go back to the start and fill our hearts with something.

 class Heart  
 {  
 public:  
      Heart(const char *name) : name( name )  
      {}  
 private:  
      const char *name;  
 }; 
 class Us  
 {  
 public:  
      Us(const char *name)  
      {  
           myHeart = new Heart( name );  
      }  
      ~Us()  
      {  
           delete myHeart;  
      }  
      const Heart* GetConstHeartPtr()  
      {  
      return myHeart;  
      }  
 private:  
      Heart* myHeart;  
 };  


We'd have something to allocate, because our heart would point to a memory location which contains a name, which can be created with malloc and filled.

 int _tmain(int argc, _TCHAR* argv[])  
 {  
      Us *me = new Us( "me" );  
      Us *you = new Us( "you" );  
      if( me != NULL && you != NULL )  
      {  
           memcpy( me, you, sizeof( Heart ) );  
           if( me->GetConstHeartPtr() == you->GetConstHeartPtr() )  
           {  
                printf( "Love" );  
           }  
      }  
 }  


So what's the lesson to be learned?
Don't try to love a girl that's heartless.

Thursday, 26 February 2009

Price Scanning With HTML Tables


In the next release of iGrapher the main new feature will be a much needed hovering price scanner. So as you scroll over the chart, it'll give you an indication of the price of the stock on that date, as seen in the image above.

To implement this we would need to create a table the size of a point, colour it, then moved it along the position of the mouse while over the graph.

So we first create a class to encapsulate the scanners function so we can easily iterate it's functionality over as many stocks currently drawn on the graph.

function PriceScanner(index)
{
this.table = document.createElement( 'table' );
this.td = document.createElement( 'td' );
this.border = "4px solid " + graphColours[index];

this.table.cellPadding = 0;
this.table.cellSpacing = 0;
this.table.style.position = 'absolute';
this.table.style.left = 1;
this.table.style.top = 1;

var priceScannerTBody = document.createElement( 'tbody' );
var priceScannerTR = document.createElement( 'tr' );

this.table.appendChild( priceScannerTBody );
priceScannerTBody.appendChild( priceScannerTR );
priceScannerTR.appendChild( this.td );

canvasParent.appendChild( this.table );
}
var priceScanners;



Next in our mousemove event we run the scanner update function if it's over the graph canvas, after recording our mouse x and y coordinates.

Then in our scanner update function for all the stocks drawn on the graph, we pick out the price index that's closest to the mouse coordinate, work out the draw point and set the table's left and top attributes to point to the same point. Then set the border of the table to be it's "this.border" property. When the mouse goes off the chart we stop calling the update function and the border back to "" so it disappears from our view.

Also in the next release
we've freshed up the design a little throwing in some outset tables and buttons, fixed a few niggly bugs todo with scrolling and resizing at unusual occasions and included the minute to minute data to the graph slider at the bottom, so when you slide it to the right it'll go to today's movements.

iGrapher

Friday, 6 February 2009

From x to i


A few days ago, when we tried logging into the ftp account to roll out a new update, we'd got a password incorrect error. We emailed the host, but there was no reply. Then we noticed that the site was gradually being re-branded... We'd been hijacked!

The thing is, since we started this project as a self-development exercise to extend our knowledge on the financial sector. We never actually considered it branching out and becoming popular (at least so soon). But, ever since we gained recognition on the internets (mostly thanks to apple), we immediately began being targeted for a takeover.

We still saw this project as in it's infancy, and refused to consider any offers. However, our web hosting company saw otherwise. Since it had let us use it's web space and domain for free (thanks), it also meant that they owned the legal rights to it. Well, on that day, they decided to hold us for ransom.

So...

Out with the old and in with the new? Development on this financial visualisation project will now continue on iGrapher.com, hope you like the name, it's very apple-centric, but, I guess it works.

In our next update we'll be implementing history downloading optimisations and extending currency exchange history data.

iGrapher

Thursday, 29 January 2009

RBS ♥ You


While looking through various charts, my friend noticed a cute little pattern in the graph for Royal Bank of Scotland's stock history.



What does this mean? Well, it's conclusive proof that the Royal Bank of Scotland loves you... or that it's bragging about a new boob job? or quiet possibly that it's flashing you it's butt right before it's stock crashes?

More mysteries coming as soon as I implement the cute shape stock matching algorithm.

iGrapher

Wednesday, 28 January 2009

Streaming Javascript

One of my favourite features of Javascript is the ability to write more source code on the fly. Usually in most languages I've used before in the past, you'd have to write the code, compile it, link it, then run. In Javascript you can write source code which writes source code and runs it ON-THE-FLY.

So for example I could do this in my code.

// Create a new script element
var bamScript = document.createElement( 'script' );

// Fill in the script element with more source code
bamScript.text = 'function bam() { alert("aahh"); }';

// Add our script to the document
document.body.appendChild( bamScript );

// Run our newly added script.
bam();


This piece of code, would add in a new script element with a function called bam, which we can run right after it's added to our document. AMAZING!

(Note: A few gotchas I came across. Make sure you use the text parameter and not the innerHTML one. InnerHTML will work fine in Firefox, however in Internet Explorer it'll go boom, and on the iPhone's safari, it'll go boom depending on the complexity of the source code you're writing.)

Since the beginning of iGrapher I've been meaning to use this feature of Javascript, however with the use of gzip, my javascript has been small enough to avoid needed to split the program into separate downloadable components. However, since porting to the iPhone, I've found that it takes a good few seconds to load, so I finally pushed ahead the usage of self-writing source code.

So now in v1.56 iGrapher will load in a small script which dynamically streams in more source code using the XMLHttpRequest object. At the moment the source code is split in two, however I plan on breaking it up into further components so at first the necessary components download first, then the non-essentials (top menu, data spanner, etc.)


iGrapher

Tuesday, 20 January 2009

My iPhone Gesture Dilemma

Currently in Safari, if you touch the screen with more than one finger, then rotate the phone. Safari will crash in a very perverse way.

The program will still be on the screen however all javascript will not function, the status bar buttons will not function, and you will no longer be able to navigate the Internet, it'll just hang.

The only way around this state is to turn off the phone, then turn it back on.

Now the problem is, I wanted to add the zooming feature to the graphs and I wanted it to make use of the famous pinch technique. Should I disallow multi-touch gestures and use a different technique or just allow pinching in hope no one would rotate their phone?

I decided to allow pinching, but display a warning message, informing the user that if they rotated their phone, it will go boom!

Sigh..

Monday, 19 January 2009

iPhone v1.5 Preview

Work on the iPhone version of iGrapher has been on-going all week and we have hit a few milestones this past weekend. The shares menu is much more usable, XML has been ditched for a custom .xg format which is half the size of XML meaning faster data downloads and work on scrolling the graph canvas has started.

Here's a little preview of the iPhone version in action.


iGrapher

Friday, 16 January 2009

My iPhone Web App Experience

So I submitted my grapher program to the apple web app directory the other day. Not expecting much of it, I decided to give it a little test run to make sure it all still worked. I had been making sure it functioned on the iPhone, feature by feature as I implemented them on the desktop, however I had never actually tried using it from an end-users point to view.

Needless to say, it was too buggy, with several crashes and annoyances. I wasn't happy! I frantically spent the night fixing bug after bug. The clock hit 4:30am and I had patched it up enough for it to be barely functional.

You couldn't scroll the charts, but at least you could just about click on some buttons without it reacting erratically and be able to rotate the phone, without it crashing.

I uploaded the new version, then checked my e-mail to find a welcome note from apple. So I figured I'd check their web directory...
Woah... Featured with a staff pick. I have no idea how!?

I was pretty sure, I'd get rejected with perhaps some useful advice on how to improve the app, but wow!

The worst problems faced when porting to the iPhone?
Viewport - Don't experiment with different width's and height's, when you do so, it randomly jumps from dimension to dimension when rotating.
I found it best for me to set the scale to be 1.0 for all the scale options..

content="minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0"

So I could always have the same dimension when rotating.

Multi-touch - It's strange this one, if you use a multi-touch gesture (very very fun to do so) and rotate the iPhone at the same time, it goes boom! I tried every permutation possible to get round this issue, but I found it crashes regular websites, and it doesn't just crash in a close down safari friendly way. It keeps Safari running, however the internet becomes unusable, it just hangs forever trying to connect to a website. The only way I found around it was to turn off the phone then turn it back on again. My coding solution was to override the gesturestart event, then fire off an alert if the user tried using multi-touch. I'm defiantly not happy with this, but it's the only way I could get round this issue. Maybe it's just my phone, I'll have to look more into this. Would be nice to hear if anyone else has experienced this?

OnResize - On a desktop PC, by default I had used the onresize event to inform me when I needed to resize my grapher to fit the screen. On the iPhone... BIG MISTAKE! It kept firing the onresize event randomly and relentlessly (probably because my viewport size wasn't set as advised above). However, once I found out that this was the cause of my app crashing, I simply switched over to orientationchange for the iPhone. That event would fire (as long as you never had two fingers on the screen) and you could get the viewport rotation from the window.orientation variable.

Adsense - A quick final tip for adsense users. I'm not a fan of irritating in your face adverts, so I specifically had only used a 468x15 text ad for the non-iPhone version. However, because of the viewport size limitation, I had to switch over to the next smallest thing for the iPhone.

To get a different advert on a different device for the same page, I had originally tried asking google for what to do. However, no one ever got back to me, so I came to the realisation that php was my friend.

[?php
$ua = $_SERVER['HTTP_USER_AGENT'];
if( strpos( $ua, 'iPhone' ) == false )
{
echo '
DESKTOP CODE
';
}
else
{
echo '
iPHONE CODE
';
}
php?
]

Simple huh?

We'll anyway, I'll try coming back here to post some more tips later, but it's 6am here and my alarm clocks going off.

Thanks for reading.

iGrapher

Friday, 2 January 2009

Turnaround for the pound?

Analysts have been prediciting the EURO to ascend to the heights of £1.50 per EURO within 6 months. However looking at the latest trades, has the rally for the EURO come to an end?



iGrapher