<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jeff Mesnil &#187; iphone</title>
	<atom:link href="http://jmesnil.net/weblog/category/apple/iphone/feed/" rel="self" type="application/rss+xml" />
	<link>http://jmesnil.net/weblog</link>
	<description>Thoughts about Java, Web and Software Development</description>
	<lastBuildDate>Wed, 25 Jan 2012 10:23:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Matias Duarte on the philosophy of Android, and an in-depth look at Ice Cream Sandwich &#9755;</title>
		<link>http://thisismynext.com/2011/10/18/exclusive-matias-duarte-ice-cream-sandwich-galaxy-nexus/</link>
		<comments>http://jmesnil.net/weblog/2011/10/19/matias-duarte-on-the-philosophy-of-android-and-an-in-depth-look-at-ice-cream-sandwich/#comments</comments>
		<pubDate>Wed, 19 Oct 2011 15:17:44 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1808</guid>
		<description><![CDATA[The concept of an address book or contacts feels so lame and dated, it’s like ‘an address book is this little thing with this faux leather cover! &#8212; Matias Duarte Touch&#233;! The Address Book app is a sore point in the iOS (and Mac OS X) experience. Address Book on iOS It is a chore [...]<a href="http://jmesnil.net/weblog/2011/10/19/matias-duarte-on-the-philosophy-of-android-and-an-in-depth-look-at-ice-cream-sandwich/" rel="bookmark" title="Permanent link to 'Matias Duarte on the philosophy of Android, and an in-depth look at Ice Cream Sandwich'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>The concept of an address book or contacts feels so lame and dated, it’s like ‘an address book is this little thing with this faux leather cover!<br />
  &mdash; <cite>Matias Duarte</cite></p>
</blockquote>

<p><em>Touch&eacute;</em>! The Address Book app is a sore point in the iOS (and Mac OS X) experience.</p>

<p><figure>
<img src="http://www.apple.com/iphone/built-in-apps/images/contacts_everywhere.jpg" alt="Address Book on iOS">
<figcaption>Address Book on iOS</figcaption>
</figure></p>

<p>It is a chore to use this application to update contacts information and the &#8220;real life&#8221; user interface makes it even more frustrating.</p>
<p><a href="http://jmesnil.net/weblog/2011/10/19/matias-duarte-on-the-philosophy-of-android-and-an-in-depth-look-at-ice-cream-sandwich/" rel="bookmark" title="Permanent link to 'Matias Duarte on the philosophy of Android, and an in-depth look at Ice Cream Sandwich'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/10/19/matias-duarte-on-the-philosophy-of-android-and-an-in-depth-look-at-ice-cream-sandwich/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Sensor and Lens in iPhone 4S Camera &#9755;</title>
		<link>http://arstechnica.com/apple/news/2011/10/why-the-improve-camera-in-the-iphone-4s-is-good-news-for-shutterbugs.ars</link>
		<comments>http://jmesnil.net/weblog/2011/10/06/new-sensor-and-lens-in-iphone-4s-camera/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 08:03:11 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[photo]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1804</guid>
		<description><![CDATA[The improved camera is the single reason I will replace my iPhone 3GS by an iPhone 4S as soon as it is available. It&#8217;s too bad that James Duncan Davidson announced they shut down the Daily Shoot when I finally have a good camera in my pocket all the time everyday. &#9873;<a href="http://jmesnil.net/weblog/2011/10/06/new-sensor-and-lens-in-iphone-4s-camera/" rel="bookmark" title="Permanent link to 'New Sensor and Lens in iPhone 4S Camera'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<p>The improved camera is the single reason I will replace my iPhone 3GS by an iPhone 4S as soon as it is available.</p>

<p>It&#8217;s too bad that <a href="http://duncandavidson.com/blog/2011/10/dailyshoot_retired">James Duncan Davidson announced they shut down the Daily Shoot</a> when I finally have a good camera in my pocket all the time everyday.</p>
<p><a href="http://jmesnil.net/weblog/2011/10/06/new-sensor-and-lens-in-iphone-4s-camera/" rel="bookmark" title="Permanent link to 'New Sensor and Lens in iPhone 4S Camera'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/10/06/new-sensor-and-lens-in-iphone-4s-camera/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An RSS-feed and location-based iOS application &#9755;</title>
		<link>http://cocoawithlove.com/2011/06/process-of-writing-ios-application.html</link>
		<comments>http://jmesnil.net/weblog/2011/06/19/an-rss-feed-and-location-based-ios-application/#comments</comments>
		<pubDate>Sun, 19 Jun 2011 18:22:54 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1637</guid>
		<description><![CDATA[Cocoa With Love&#8216;s Matt Gallagher: The purpose of this post is so that I will have a link to give people when they ask: how do I write an iOS application that pulls data from an RSS feed, displays it pretty and can put things on a map. I&#8217;ll show you all of that and [...]<a href="http://jmesnil.net/weblog/2011/06/19/an-rss-feed-and-location-based-ios-application/" rel="bookmark" title="Permanent link to 'An RSS-feed and location-based iOS application'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<p><a href="http://cocoawithlove.com">Cocoa With Love</a>&#8216;s Matt Gallagher:</p>

<blockquote>
  <p>The purpose of this post is so that I will have a link to give people when they ask: how do I write an iOS application that pulls data from an RSS feed, displays it pretty and can put things on a map. I&#8217;ll show you all of that and more as I rewrite my oldest iOS application from scratch: FuelView.</p>
</blockquote>

<p>A recommended article which explains how to design and write a simple but <em>not too simple</em> iOS application.</p>
<p><a href="http://jmesnil.net/weblog/2011/06/19/an-rss-feed-and-location-based-ios-application/" rel="bookmark" title="Permanent link to 'An RSS-feed and location-based iOS application'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/06/19/an-rss-feed-and-location-based-ios-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; Review of gps4cam &#8211; iPhone GPS Tool for Cameras</title>
		<link>http://jmesnil.net/weblog/2011/02/20/review-of-gps4cam-iphone-gps-tool-for-cameras/</link>
		<comments>http://jmesnil.net/weblog/2011/02/20/review-of-gps4cam-iphone-gps-tool-for-cameras/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 15:33:31 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[photo]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1568</guid>
		<description><![CDATA[I want to have GPS data for pictures taken with my Nikon camera and I looked at different tools to achieve that. At first, I was using Aperture&#8216;s Places to manually locate the pictures but this is a long and tedious process. Sometime, I shot a picture with my iPhone (which contains GPS data) and [...]]]></description>
			<content:encoded><![CDATA[<p>I want to have GPS data for pictures taken with my Nikon camera and I looked at different tools to achieve that.</p>

<p>At first, I was using <a href="http://www.apple.com/aperture/">Aperture</a>&#8216;s Places to manually locate the pictures but this is a long and tedious process.
Sometime, I shot a picture with my iPhone (which contains GPS data) and import them in Aperture to geotag my camera pictures. But more often than not, I forget to do that and have to do it manually.</p>

<p>I could add a GPS device to my camera directly but they are expensive, bulky, and drain the battery. Why buy another GPS device when I always have my iPhone with me?</p>

<p>After some research, I settled on using <a href="http://gps4cam.com/">gps4cam</a> and I am very happy with it.</p>

<p>gps4cam comes in two parts:</p>

<ul>
<li>an iPhone app (<a href="http://itunes.apple.com/us/app/gps4cam/id325917531?mt=8&amp;uo=6">App Store link</a>)</li>
<li>a free Mac or PC application (available from their <a href="http://gps4cam.com/">web site</a>)</li>
</ul>

<p>When I go outside and start shooting, I just need to run the iPhone app and start a new <em>trip</em>. The app supports multitasking, so I can exit the app, put the phone in my pockets and not worry about it anymore. I can focus on shooting instead.</p>

<p>Periodically, the app will capture my GPS location. The app is configurable and you can specify the frequency, to use GSM to triangulate the position instead of GPS (useful when abroad), etc.</p>

<p>At the end of the trip, when I am done shooting, I <em>export</em> the trip which generates a <a href="http://en.wikipedia.org/wiki/QR_Code">QR Code</a>.</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2011/02/photo.png" alt="" title="Example of QR code " width="320" height="480" class="aligncenter size-full wp-image-1569" /></p>

<p>I then <em>shoot this QR code with my DSLR</em>. This picture contains all the GPS information captured during my trip. The fantastic idea of using QR codes is that there is no need to synchronize the iPhone and camera clocks: the QR code <em>generated by the iPhone</em> and <em>shot with the other camera</em> allows to know the clock difference between the two devices and deduce where the camera photography were taken.</p>

<p>The last step to do is to use the desktop application which reads the QR code and put the GPS data in the other pictures&#8217; EXIF metadata<a id="fnr1-2011-02-20" href="#fn1-2011-02-20"><sup>1</sup></a>.</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2011/02/real.png" alt="" title="gps4cam Desktop Application" width="500" height="185" class="aligncenter size-full wp-image-1574" /></p>

<p>Finally, I can import the pictures in Aperture or any other software and voila! My pictures are (almost automatically) geotagged.</p>

<p>The iPhone is simple, non-obtrusive and a steal at 1.59€ (or $1.99). It is a pleasure to use it and I haven&#8217;t noticed a specific battery drain.</p>

<p>On the opposite, the desktop application needs more spit and polish.
It is a Java application, I use it on my MacBook and it does not feel at home.
The UI is not consistent with the OS (the progress is shown with a modal dialog window instead of a sheet or a progress bar) and it is too slow.</p>

<p>As I understand it, the desktop applications takes 3 steps:</p>

<ul>
<li>analyze the pictures (to find which one contains a QR code)</li>
<li>retrieve the GPS data from the QR code picture</li>
<li>copy the pictures and store the GPS data in their EXIF metadata</li>
</ul>

<p>I don&#8217;t understand why it should take several minutes to perform these 3 steps (for a trip where I took only 40+ pictures).
I suppose the performance could be improved by identifying faster the QR code picture.
One way could be to let the user chooses the QR code picture (as I propose in the mock screenshot below by using an Image Well):</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2011/02/mock.png" alt="" title="Mock of gps4cam Desktop Application" width="480" height="271" class="aligncenter size-full wp-image-1570" /></p>

<p>This would work fine if there is only one &#8220;trip&#8221; (i.e. one QR code) in the pictures but this will not work if there are many of them&#8230;</p>

<p>The desktop application also needs to improve the user experience. I put GPS data directly in the pictures on my SD card before I import them. Every time, the application asks me if I am sure to do that and I must confirm.<br />
Instead, the application should let me check a box to say that I don&#8217;t want to be warned next time and remember it. If anything bad happens, it is my fault, I explicitly told the application to not warn me anymore.</p>

<p>Pros:</p>

<ul>
<li>unobtrusive and configurable iPhone application</li>
<li>trips can be exported as GPX (and visualized in Google Maps, Google Earth, etc.)</li>
<li>inexpensive</li>
</ul>

<p>Cons:</p>

<ul>
<li>desktop application&#8217;s UI needs more attention (I would prefer a native Mac application)</li>
<li>desktop application takes too long to process pictures and store GPS data</li>
</ul>

<p>I hope that the cons will be fixed in future releases.<br />
But as it stands now, I heartily recommend gps4cam to any iPhone user who wants to geotag automatically their pictures taken with another camera.</p>

<hr />

<ol>
<li><a id="fn1-2011-02-20"></a> I specify the same directories as input and output to store GPS data directly on the pictures on the SD card.&nbsp;<a href="#fnr1-2011-02-20">&#8617;</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/02/20/review-of-gps4cam-iphone-gps-tool-for-cameras/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; Offline Support and Standalone Mode for HTML5 Web Application</title>
		<link>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/</link>
		<comments>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 20:54:28 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1376</guid>
		<description><![CDATA[Let&#8217;s continue working on the HTML5 Web Application for the iPhone with node.js Last time, I created the first version of the Web application to move a piece when the user moves the iPhone and coded a simple Web server on top of node.js. The Web application works fine but it is not pretty and [...]]]></description>
			<content:encoded><![CDATA[<p>Let&#8217;s continue working on the HTML5 Web Application for the iPhone with node.js</p>

<p><a href="http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/">Last time</a>, I created the first version of the Web application to move a piece when the user moves the iPhone and coded a simple Web server on top of node.js.</p>

<p>The Web application works fine but it is not pretty and there are a few things we can improve.
Before looking at Web Sockets and other fancy code, let&#8217;s make the Web application prettier.</p>

<h2>iPhone Standalone Web Application</h2>

<p>The major annoyance is that Safari chrome takes a lot of space and hides the bottom of the board:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2010/11/chrome.png" alt="" title="chrome" width="320" height="155" class="aligncenter size-full wp-image-1383" /></p>

<p>To display a Web application without Safari chrome, we can make it a <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW2">standalone Web application</a>.</p>

<p>In <code>index.html</code>, we add some <code>&lt;meta&gt;</code> information to the <code>&lt;head&gt;</code> part:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  ...
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;viewport&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;width=device-width, user-scalable=0&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;apple-mobile-web-app-capable&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;yes&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;apple-mobile-web-app-status-bar-style&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;black&quot;</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span></pre></div></div>


<p>The <a href="http://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html#//apple_ref/doc/uid/TP40006509-SW1"><code>viewport</code></a> meta ensures that the Web page will be sized to the device width and prevents the user to change the page scale (by pinching it).</p>

<p>The <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW2"><code>apple-mobile-web-app-capable</code></a> will launch the Web application in full-screen mode (without Safari chrome) to look like a native application. The Web application must be added to the iPhone home screen and start from there to appear in full-screen mode.</p>

<p>Last thing is to render the iPhone status bar in black by setting the <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW1"><code>apple-mobile-web-app-status-bar-style</code></a> to black.</p>

<p>With these 3 meta information, the Web application looks better and display the whole board</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2010/11/Board-2nd-version.jpg" alt="" title="Board - 2nd version" width="320" height="480" class="aligncenter size-full wp-image-1380" /></p>

<h2>Offline Support</h2>

<p>At the moment, node.js serves only static pages. When the iPhone has loaded the Web application, it no longer connects to the Web server.</p>

<p>Let&#8217;s add offline support so that we can run the Web application even when the server is down (or unreachable).</p>

<p>HTML5 supports <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html">offline</a> applications through the cache manifest. The best introduction on the subject is the <a href="http://diveintohtml5.org/offline.html">Offline chapter in Dive into HTML5</a>.</p>

<p>For this Web application this means that we must write a <code>cache.manifest</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="manifest" style="font-family:monospace;">CACHE MANIFEST
&nbsp;
CACHE:
/screen.css
/client.js
/jquery.min.js</pre></div></div>


<p>This cache manifest tells the Web browsers to call all these files to run the Web application offline.</p>

<p>This cache manifest must be declared in the entry point of the Web application (<code>index.html</code> in this case) with the <code>manifest</code> attribute of the <code>html</code> element:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;!doctype html&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span> manifest<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;/cache.manifest&quot;</span>&gt;</span>
...</pre></div></div>


<p>Finally, we need to update <code>server.js</code> to send the <code>cache.manifest</code> file with the correct HTTP <code>Content-Type</code>.
Only the <code>getContentType()</code>function needs to be modified:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.js$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.css$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/css&quot;</span><span style="color: #339933;">;</span>           
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.manifest$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/cache-manifest&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>  <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/html&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>With this modification, <code>cache.manifest</code> will be sent to the Web browser with the correct <code>text/cache-manifest</code> Content-Type.</p>

<p>We must restart the server to take into account the <code>server.js</code> modification:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ node.js server.js
HTTP server running at htpp:<span style="color: #000000; font-weight: bold;">//</span>0.0.0.0:<span style="color: #000000;">8080</span></pre></div></div>


<p>I can then reload the Web application and add it to the iPhone home screen.
With offline support, I will be able to use the Web application even if the server is not running or unreachable.</p>

<p>Here is a small video of the result with the updated Web application:</p>

<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/yoJAC2Qc0uo?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/yoJAC2Qc0uo?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>

<p>Note the black status bar and the full screen mode after I started the Web application from the iPhone home screen. It is indistinguishable from a native application but runs on the Web (it’s not obvious from the video but the camera was recording from above: the iPhone was held horizontally)</p>

<h2>Source Code</h2>

<p>I have pushed the application on <a href="http://github.com/jmesnil/board-node">Github</a>. You can clone it with Git:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> clone <span style="color: #c20cb9; font-weight: bold;">git</span>:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>jmesnil<span style="color: #000000; font-weight: bold;">/</span>board-node.git</pre></div></div>


<h2>Conclusion</h2>

<p>By adding a few <code>meta</code> information to the Web application, it is possible to make it look better integrated to the iPhone.<br />
Offline support is trickier than this simple example make it look like but it gives the right idea to start dealing with it.</p>

<p>Next step is to add Web Sockets support to the node.js to display the moving pieces of <em>other users</em> on the Web application.</p>

<h2>Further Reading</h2>

<ul>
<li><a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/Introduction/Introduction.html">Safari Web Content Guide</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html">HTML5 Offline Web applications</a> (and its corresponding <a href="http://diveintohtml5.org/offline.html">&#8220;Dive into HTML5&#8243; chapter</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; HTML5 Web Application for iPhone and iPad With node.js</title>
		<link>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/</link>
		<comments>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/#comments</comments>
		<pubDate>Wed, 24 Nov 2010 21:38:55 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1333</guid>
		<description><![CDATA[Update: I have written another post about adding offline support to the Web application and making it look like a native iPhone application. On the server, I want to learn more about node.js which is an interesting way to develop server-side applications. On the client-side, I also wanted to check what can be done with [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> <em>I have written <a href="/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/">another post</a> about adding offline support to the Web application and making it look like a native iPhone application.</em></p>

<p>On the server, I want to learn more about <a href="http://nodejs.org/">node.js</a> which is an interesting way to develop server-side applications.
On the client-side, I also wanted to check what can be done with HTML5 on iPhone and iPad with the release of iOS 4.2.1.</p>

<p>I will write a simple web application to do both at the same time. The idea is simple enough but will allow me to dive into node.js and HTML5 quite extensively.</p>

<p>The idea is to write a web application that display a piece moving on a board when the user moves its device. 
Later on, I will expand it so that the user will also see the pieces of all others users connected to the server.</p>

<p>But the first iteration will be enough to familiarize with:</p>

<ul>
<li>node.js (to serve static content at first)</li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">Canvas API</a> (to draw the board and the piece)</li>
<li><a href="http://dev.w3.org/geo/api/spec-source-orientation.html">DeviceOrientation Event API</a> (to detect the orientation of the mobile, it was added in iOS 4.2.1)</li>
</ul>

<h1>Web Server</h1>

<p>I will use node.js as my Web server (I installed it from Git by following the <a href="http://nodejs.org/#build">build instructions</a> on its web site).</p>

<p>The first version of the server needs to serve static files with the correct HTTP <code>Content-Type</code>.
At first, it will serve only HTML pages, CSS stylesheets and JavaScript files.</p>

<p>The whole <code>server.js</code> code is:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> http <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'http'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> url <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'url'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> fs <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'fs'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> sys <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'sys'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// the HTTP server</span>
<span style="color: #003366; font-weight: bold;">var</span> server<span style="color: #339933;">;</span>
<span style="color: #006600; font-style: italic;">// the HTTP port</span>
<span style="color: #003366; font-weight: bold;">var</span> port <span style="color: #339933;">=</span> <span style="color: #CC0000;">8080</span><span style="color: #339933;">;</span>
&nbsp;
server <span style="color: #339933;">=</span> http.<span style="color: #660066;">createServer</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> path <span style="color: #339933;">=</span> url.<span style="color: #660066;">parse</span><span style="color: #009900;">&#40;</span>req.<span style="color: #660066;">url</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">pathname</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path <span style="color: #339933;">==</span> <span style="color: #3366CC;">'/'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     path <span style="color: #339933;">=</span> <span style="color: #3366CC;">'/index.html'</span>
  <span style="color: #009900;">&#125;</span>
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;serving &quot;</span> <span style="color: #339933;">+</span> path<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  fs.<span style="color: #660066;">readFile</span><span style="color: #009900;">&#40;</span>__dirname <span style="color: #339933;">+</span> path<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>err<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
     <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        res.<span style="color: #660066;">writeHead</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">404</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #660066;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>        
     <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
        res.<span style="color: #660066;">writeHead</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">200</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">'Content-Type'</span><span style="color: #339933;">:</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #000066; font-weight: bold;">write</span><span style="color: #009900;">&#40;</span>data<span style="color: #339933;">,</span> <span style="color: #3366CC;">'utf8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #660066;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.js$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.css$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/css&quot;</span><span style="color: #339933;">;</span>           
   <span style="color: #009900;">&#125;</span>  <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/html&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
server.<span style="color: #660066;">listen</span><span style="color: #009900;">&#40;</span>port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;HTTP server running at htpp://0.0.0.0:&quot;</span> <span style="color: #339933;">+</span> port <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>The code is straightforward: when a request is handled by the server, it looks in the current directory (where <code>server.js</code> is) for a file with the given path and writes its content in the HTTP response body.<br />
The <code>contentType(path)</code> function checks the file suffix to use the correct HTTP <code>Content-Type</code> for the response.</p>

<p>It will serve files from <code>http://&lt;server-name&gt;:8080/</code>.<br />
For the rest of the example, I will use the name of my machine, <code>blackbook.local</code>: to access the Web application from my iPhone, I am using <a href="http://blackbook.local:8080">http://blackbook.local:8080</a>.</p>

<p>In future iterations, I will add more interesting code to node.js (to use WebSockets for example) but for the moment this simple server is enough.</p>

<h1>Web Application</h1>

<p>Let&#8217;s now focus on the client-side part of the Web application.</p>

<h2>index.html</h2>

<p>The Web application is loaded from a single HTML5 page, <code>index.html</code>:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;!doctype html&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">charset</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;viewport&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;width=device-width, user-scalable=0&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">title</span>&gt;</span>Board<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">title</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">link</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span>stylesheet <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span>screen.css&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
  <span style="color: #009900;">&lt;canvas <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;board&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;320&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;460&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>canvas&gt;</span>
&nbsp;
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'jquery.min.js'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>  
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;client.js&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></div></div>


<p>The page contains a single &lt;canvas> element named <code>board</code>. All the code to draw on the canvas is in <code>client.js</code> JavaScript file.</p>

<h2>client.js</h2>

<p><code>client.js</code> contains code to:</p>

<ul>
<li>get orientation information from the device (using the DeviceOrientation Event API)</li>
<li>draw the board and the piece based on the orientation information (using the Canvas API)</li>
</ul>

<p>First, it defines a few constants used to draw the board and the piece:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> kBoardWidth <span style="color: #339933;">=</span> <span style="color: #CC0000;">320</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> kBoardHeight <span style="color: #339933;">=</span> <span style="color: #CC0000;">460</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> kCircleRadius <span style="color: #339933;">=</span> <span style="color: #CC0000;">32</span><span style="color: #339933;">;</span></pre></div></div>


<p>The <code>piece</code> object is defined literally:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> piece <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
   center <span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
      x<span style="color: #339933;">:</span> kBoardWidth <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span>
      y<span style="color: #339933;">:</span> kBoardHeight <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span>
      xShift <span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span>
      yShift <span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
   color<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;#000&quot;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>


<p>The piece has a center position with its coordinates (initially at the center of the board) and its acceleration on the x and y axes, and its color is black.</p>

<p>I use <a href="http://jquery.com/">jQuery</a> to bootstrap the application when the document is ready:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #003366; font-weight: bold;">var</span> board <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;board&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #003366; font-weight: bold;">var</span> context <span style="color: #339933;">=</span> board.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   window.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;devicemotion&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #003366; font-weight: bold;">var</span> accel <span style="color: #339933;">=</span> event.<span style="color: #660066;">accelerationIncludingGravity</span><span style="color: #339933;">;</span>
      piece.<span style="color: #660066;">center</span> <span style="color: #339933;">=</span> computeCenter<span style="color: #009900;">&#40;</span>piece.<span style="color: #660066;">center</span><span style="color: #339933;">,</span> accel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      drawGrid<span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      drawPiece<span style="color: #009900;">&#40;</span>context<span style="color: #339933;">,</span> piece<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>First we keep a reference on the <code>board</code> canvas that was declared in the HTML page and its associated 2D context.
The <code>context</code> will be used to draw the piece and the board on the canvas.</p>

<p>We use the DeviceOrientation API (supported by the iPhone and the iPad since iOS 4.2.1) to detect the acceleration of the device.
Periodically, the browser will call the handler associated to the <code>devicemotion</code> event.<br />
When that happens, the handler retrieves the <code>accelerationIncludingGravity</code> property, compute the new center position of the piece and draw the board and the piece on the canvas.</p>

<p>The method to draw the board is using the 2D context (the board is displayed as a grid):</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> drawBoard<span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   context.<span style="color: #660066;">clearRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> kBoardWidth<span style="color: #339933;">,</span> kBoardHeight<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> x <span style="color: #339933;">=</span> <span style="color: #CC0000;">0.5</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> kBoardWidth<span style="color: #339933;">;</span> x <span style="color: #339933;">+=</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       context.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       context.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> kBoardHeight<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> y <span style="color: #339933;">=</span> <span style="color: #CC0000;">0.5</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;</span> kBoardHeight<span style="color: #339933;">;</span> y <span style="color: #339933;">+=</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      context.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      context.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>kBoardWidth<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   context.<span style="color: #660066;">strokeStyle</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;#eee&quot;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">stroke</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>The code to draw the piece is also using the 2D context to draw a circle from the piece&#8217;s center and its color:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> drawPiece<span style="color: #009900;">&#40;</span>context<span style="color: #339933;">,</span> piece<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   context.<span style="color: #660066;">fillStyle</span> <span style="color: #339933;">=</span> piece.<span style="color: #660066;">color</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">beginPath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">arc</span><span style="color: #009900;">&#40;</span>piece.<span style="color: #660066;">center</span>.<span style="color: #660066;">x</span><span style="color: #339933;">,</span> piece.<span style="color: #660066;">center</span>.<span style="color: #660066;">y</span><span style="color: #339933;">,</span> kCircleRadius<span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">PI</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">closePath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">fill</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Finally, we need to compute the updated position of the piece&#8217;s center based on its current position and the acceleration information from the browser:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> computeCenter <span style="color: #009900;">&#40;</span>oldCenter<span style="color: #339933;">,</span> acceleration<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   newCenter <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">x</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">y</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">+</span> oldCenter.<span style="color: #660066;">xShift</span><span style="color: #339933;">;</span>
   <span style="color: #006600; font-style: italic;">// use *minus* to compute the center's new y</span>
   newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">-</span> oldCenter.<span style="color: #660066;">yShift</span><span style="color: #339933;">;</span>
   <span style="color: #006600; font-style: italic;">// do not go outside the boundaries of the canvas</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">&lt;</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">&gt;</span> kBoardWidth <span style="color: #339933;">-</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> kBoardWidth <span style="color: #339933;">-</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">&lt;</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">&gt;</span> kBoardHeight <span style="color: #339933;">-</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> kBoardHeight <span style="color: #339933;">-</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">return</span> newCenter<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>To smooth the movement and increase the acceleration when the mobile is moved, I applied a low-pass filter:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">newCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">x</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
newCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">y</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span></pre></div></div>


<p>The rest of the method ensures that the piece will remain in the boundaries of the board.</p>

<h1>screen.css</h1>

<p>Last thing is to make sure that the canvas fills the whole Web page by removing the margin and padding on the <code>body</code> element. This is done through CSS in the <code>screen.css</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">body <span style="color: #00AA00;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>


<p>All these files are located in the same directory than <code>server.js</code>.</p>

<h1>Run the example</h1>

<p>Let&#8217;s start the node.js server:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ node server.js
HTTP server running at htpp:<span style="color: #000000; font-weight: bold;">//</span>0.0.0.0:<span style="color: #000000;">8080</span></pre></div></div>


<p>Now, from my iPhone, I go to the Web page on <a href="http://blackbook.local:8080">http://blackbook.local:8080</a> (if you go on the Web application from your machine, nothing will happen since the <code>devicemotion</code> event is not available on desktop browsers).</p>

<p>As I have not found a way to prevent the iPhone to change the screen orientation when it is moved, I have locked the iPhone in portrait mode before running the Web application.</p>

<p>Here is a small video of the result:</p>

<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/hqVcLpsO728?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/hqVcLpsO728?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>

<p>It&#8217;s not obvious from the video but the camera was recording from above: the iPhone was held horizontally.</p>

<h2>Source Code</h2>

<p>I have pushed the application on <a href="https://github.com/jmesnil/board-node">Github</a>. You can clone it with Git:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> clone <span style="color: #c20cb9; font-weight: bold;">git</span>:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>jmesnil<span style="color: #000000; font-weight: bold;">/</span>board-node.git</pre></div></div>


<p>The code is slightly different as I have already started the next iteration but the main idea remains the same.</p>

<h2>Conclusion</h2>

<p>With a few lines of JavaScript on both the client and server sides, it is possible to:</p>

<ul>
<li>use node.js to write a Web server returning files</li>
<li>use the Canvas API to draw things on a Web page</li>
<li>use the DeviceOrientation Event API orientation to have interaction between the device and the Web page </li>
</ul>

<p>Next steps will be to improve the user experience:</p>

<ul>
<li>make the application appear as a standalone application on the iPhone home screen and remove Safari chrome</li>
<li>support offline mode to use the Web application even when the server is not running</li>
</ul>

<h1>Further Reading</h1>

<ul>
<li><a href="http://nodejs.org/">node.js</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">Canvas API</a> (and its corresponding <a href="http://diveintohtml5.org/canvas.html">&#8220;Dive into HTML5&#8243; chapter</a>)</li>
<li><a href="http://dev.w3.org/geo/api/spec-source-orientation.html">DeviceOrientation Event API</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>&#9873; Cocoa Programming</title>
		<link>http://jmesnil.net/weblog/2010/05/20/cocoa-programming/</link>
		<comments>http://jmesnil.net/weblog/2010/05/20/cocoa-programming/#comments</comments>
		<pubDate>Thu, 20 May 2010 18:09:08 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[macosx]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1077</guid>
		<description><![CDATA[I just received my copy of Cocoa Programming. At first glance, the book seems a good update for Mac OS X development. It has been quite a few months since I did Mac (and iPhone) programming. I have not looked deeply at Core Data and Grand Central Dispatch yet. I also want to experiment with [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://pragprog.com/titles/dscpq/cocoa-programming"><img src='http://assets3.pragprog.com/images/covers/190x228/dscpq.jpg?1236205159'  /></a></p>

<p>I just received my copy of <a href="http://pragprog.com/titles/dscpq/cocoa-programming">Cocoa Programming</a>. At first glance, the book seems a good update for Mac OS X development.</p>

<p>It has been quite a few months since I did Mac (and iPhone) programming. I have not looked deeply at <a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CoreData/cdProgrammingGuide.html">Core Data</a> and <a href="http://developer.apple.com/mac/library/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html">Grand Central Dispatch</a> yet. I also want to experiment with Objective-C blocks.</p>

<p>I need to find a suitable idea for a Mac application to prototype and experiment. Any idea or suggestion is welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/05/20/cocoa-programming/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; 0.0002% of the App Store</title>
		<link>http://jmesnil.net/weblog/2008/12/01/00002-of-the-app-store/</link>
		<comments>http://jmesnil.net/weblog/2008/12/01/00002-of-the-app-store/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 20:52:26 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[tangtouch]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=402</guid>
		<description><![CDATA[TangTouch and TangTouch Lite are displayed in the grey area at the top of the iPhone shell, below the last two 0 of 10,000+ [via Daniel Jalkut]]]></description>
			<content:encoded><![CDATA[<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/icon1.png" alt="icon.png" class="alignleft" /></p>

<p><a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=292658907&amp;mt=8">TangTouch</a> and <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=292657700&amp;mt=8">TangTouch Lite</a> are displayed in the grey area at the top of the iPhone shell, below the last two <strong>0</strong>  of <strong>10,000+</strong></p>

<p><a href="http://www.flickr.com/photos/tap-tap-tap/3074199062/"><img src="http://farm4.static.flickr.com/3250/3074199062_1761f0412f.jpg?v=0" alt="icon.png" class="centered" /></a></p>

<p>[via <a href="http://www.red-sweater.com/blog/648/10000-apps">Daniel Jalkut</a>]</p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2008/12/01/00002-of-the-app-store/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#9873; TangTouch Paper Prototypes</title>
		<link>http://jmesnil.net/weblog/2008/10/24/tangtouch-paper-prototypes/</link>
		<comments>http://jmesnil.net/weblog/2008/10/24/tangtouch-paper-prototypes/#comments</comments>
		<pubDate>Fri, 24 Oct 2008 16:09:54 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[tangtouch]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=375</guid>
		<description><![CDATA[For the posterity, the paper prototype for TangTouch&#8216;s main view: and the 1.0 release available from the App Store: The Preferences paper prototype: and the 1.0 version:]]></description>
			<content:encoded><![CDATA[<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/icon1.png" alt="icon.png" class="alignleft" /></p>

<p>For the posterity, the paper prototype for <a href="http://iphone.jmesnil.net/tangtouch.html">TangTouch</a>&#8216;s main view:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/img-00111.png" alt="IMG_0011.png" class="centered" /></p>

<p>and the 1.0 release available from the App Store:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/img-6.png" alt="img-6.png" class="centered" /></p>

<p>The Preferences paper prototype:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/img-00091.png" alt="IMG_0009.png" class="centered" /></p>

<p>and the 1.0 version:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/img-3.png" alt="img-3.png" class="centered" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2008/10/24/tangtouch-paper-prototypes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; TangTouch: Tangram for the iPhone and the iPod Touch</title>
		<link>http://jmesnil.net/weblog/2008/10/24/tangtouch-tangram-for-the-iphone-and-the-ipod-touch/</link>
		<comments>http://jmesnil.net/weblog/2008/10/24/tangtouch-tangram-for-the-iphone-and-the-ipod-touch/#comments</comments>
		<pubDate>Fri, 24 Oct 2008 11:58:02 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[tangtouch]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=383</guid>
		<description><![CDATA[TangTouch is now available on the App Store. It is a Tangram puzzle game for the iPhone or the iPod Touch. I wrote this game as a way to learn more about Objective-C and Mac/iPhone development. The bulk of the application was written months ago but I waited until I had an iPhone 3G to [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2008/10/icon1.png" alt="icon.png" class="alignleft" /></p>

<p><a href="http://iphone.jmesnil.net/tangtouch.html">TangTouch</a> is now available on the <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=292658907&amp;mt=8">App Store</a>.<br />
It is a <a href="http://en.wikipedia.org/wiki/Tangram">Tangram</a> puzzle game for the iPhone or the iPod Touch.</p>

<p>I wrote this game as a way to learn more about Objective-C and Mac/iPhone development.
The bulk of the application was written <a href="http://jmesnil.net/weblog/2008/03/15/iphone-sdk/">months ago</a> but I waited until I had an iPhone 3G to finish it and test it <em>in situ</em>.</p>

<p>It&#8217;s a very simple game but I find it quite fun to play (being the author, it&#8217;s possible I&#8217;m biased&#8230;)</p>

<p>I released 2 versions:</p>

<ul>
<li>a <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=292658907&amp;mt=8">commercial version</a> with more than 200 puzzles</li>
<li>a <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=292657700&amp;mt=8">free version</a> with 32 puzzles</li>
</ul>

<p>This way you can download the free version with no strings attached. And if you like it, you can buy the commercial version.</p>

<p><img src="http://iphone.jmesnil.net/img/img-1.png" class="centered" /></p>

<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2008/10/24/tangtouch-tangram-for-the-iphone-and-the-ipod-touch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

