tag:blogger.com,1999:blog-72394471299188826272024-03-19T11:56:05.182+01:00O.C.A.SJT on computers and stuffAnonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.comBlogger63125tag:blogger.com,1999:blog-7239447129918882627.post-76715442744652842542012-11-07T21:26:00.000+01:002013-06-21T09:59:25.678+02:00Retina sprites with SCSS and Compass<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTZc87HI6jcny1nv34ylO4i2tRQWbemNJGM0UDQ_RdaYTGB8bsikcZgpZLTQ0e7XpcM6yPAQqP70DRTl9TBWK3zdxrRLSHVS6twOHUQTnO_ow4Rfi3ZWY61FWe_4ioCVnXF392jB2Z_S0/s1600/css_is_awesome.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTZc87HI6jcny1nv34ylO4i2tRQWbemNJGM0UDQ_RdaYTGB8bsikcZgpZLTQ0e7XpcM6yPAQqP70DRTl9TBWK3zdxrRLSHVS6twOHUQTnO_ow4Rfi3ZWY61FWe_4ioCVnXF392jB2Z_S0/s200/css_is_awesome.gif" width="200" /></a></div>
<br />
First of all, if you haven't used <a href="http://sass-lang.com/" target="_blank">SCSS</a> and <a href="http://compass-style.org/" target="_blank">Compass</a> you have been missing out. Don't get me wrong, there's nothing wrong with CSS per se, it's only that SCSS is better. Compass adds additional yum yum to SCSS making it my (and many other way smarter peoples) preferred solution for styling web-projects.<br />
<br />
Compass has an <a href="http://compass-style.org/help/tutorials/spriting/" target="_blank">excellent solution</a> for creating a so called "spritemap" - in short, it creates it for you. However, Compass does not provide an option for using "retina" or "HIDPI" sprites, which translated into human speech means images which are displayed at half their size. However, Compass gives you an insane amount of control over your sprites, so using some Compass functions I was able (with the help of the Internet) to create a simple mixin which will output a retina sprite (code below, if the gist is not showing up you can also find it here: <a href="https://gist.github.com/jornki/4034013">https://gist.github.com/jornki/4034013</a>).<br />
<br />
To use it, simply pass the name of the sprite into the mixin. Let's say that one of the images in the "icons/" folder is named "liara.png". You want to display this image in a div called "hot-alien". The code for this would simply be "@include retina-sprite(liara);" Cool ey!?<br />
<br />
<script src="https://gist.github.com/jornki/4034013.js"></script><br />
<i>Comments or questions? <a href="https://alpha.app.net/jornki" target="_blank">Ping me over at ADN..</a></i>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com2tag:blogger.com,1999:blog-7239447129918882627.post-30008086775064302812012-06-17T15:23:00.000+02:002012-06-17T15:35:04.547+02:00Nifty stuff #1<blockquote class="tr_bq">
<i>Nifty stuff is a series of blog post delving into nifty stuff I have made and or discovered. Since I'm kinda shary I share my discoveries, for your benefit I hope..</i></blockquote>
In this first «nifty stuff» I take a look at 4 (four) quite different nifty things, this time in the world of web-development.<br />
<br />
<ol>
<li><b><a href="http://www.chipwreck.de/blog/software/coda-php/" target="_blank">Coda 2 Web Toolkit plugin</a></b>. Last month Panic released <a href="http://panic.com/coda/" target="_blank">Coda 2</a>, their all in one window web-development platform/editor. Almost instantly a flurry of plugins and syntax modes appeared for this awesome editor. One of them is "<a href="http://www.chipwreck.de/blog/software/coda-php/" target="_blank">Coda PHP & Web Toolkit</a>", which is what the name implies an extension for Coda 2 which allows you to tidy, minify and lint you HTML, CSS and JavaScript code. It can also do a bunch of crap with PHP, so I guess it would be great for that as well. I use it primarily for linting JavaScript and tidying CSS...and it's awesome!</li>
<li><b><a href="http://jquerypp.com/" target="_blank">jQuery ++</a></b>. This is an extension to jQuery which adds some cool features like comparison helpers and better event handling. Most of all I like that the animate method will support <a href="https://developer.mozilla.org/en/CSS/CSS_transitions" target="_blank">CSS transitions</a> after adding this library (it's not CSS animations which the doc actually say). This alone makes it worth using this if you are dependent on jQuery.</li>
<li><b>Printing and HTML 5 elements.</b> Since there are a lot of old shitty browsers like Internet Explorer 8 or worse out there and these does not support HTML structural elements, we need libraries like <a href="http://modernizr.com/" target="_blank">Modernizr</a> with HTML5Shiv. This makes it so that the older crap shit browsers don't fall over and flop around like a slimy fish on land when they encounter something groundbreaking like a "section" tag. However, the regular HTML5Shiv does not fix this issue for printing, you need to use HTML5Shiv with printshiv for this...so remember that..okay</li>
<li><b>Native query selectors</b>. You have probably used jQuery to select DOM elements right? But did you know that jQuery actually uses a native (built into the browser) method for selecting the element if this method is available? There are two methods called "<a href="http://www.webkit.org/blog/156/queryselector-and-queryselectorall/" target="_blank">querySelector</a>" and "<a href="http://www.webkit.org/blog/156/queryselector-and-queryselectorall/" target="_blank">querySelectorAll</a>". Like jQuery, these methods take CSS style selector strings and returns either the first or all elements as a NodeList (kinda like an Array). These methods are supported in all modern browsers and even in IE 8 or newer!!! So if you're not supporting below IE 8 (which you shouldn't!) you might not need the overhead of jQuery at all.</li>
</ol>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-72036632683708929772012-02-19T16:35:00.000+01:002012-02-19T16:47:11.053+01:00JavaScript tap event for touch devices<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQinheHLXk0c-rO76KaL5U_RC1Ye9D4D7sbdsQulZrQflsiN1DhCMtvE5QSJ-0BBSUz7UOHaVhUMixPj_1uM_uNmAhaDqCKTcWjEIFC8Wr8IugD84Brk4RrCG8mfii1IeRfuqMpgoxdY/s1600/small.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQinheHLXk0c-rO76KaL5U_RC1Ye9D4D7sbdsQulZrQflsiN1DhCMtvE5QSJ-0BBSUz7UOHaVhUMixPj_1uM_uNmAhaDqCKTcWjEIFC8Wr8IugD84Brk4RrCG8mfii1IeRfuqMpgoxdY/s200/small.jpg" width="200" /></a></div>
JavaScript <a href="https://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html" target="_blank">touch events</a> are awesome and they are <a href="http://www.w3.org/TR/touch-events/" target="_blank">standardized</a> (Candidate recommendation) by the W3C, making them safe to use for building your touch enabled web-apps. There are 4 touch events:<br />
<br />
<ol>
<li>"touchstart" - When a finger in placed on the screen</li>
<li>"touchmove" - When a finger moves on the screen</li>
<li>"touchend" - When a finger is lifted from the screen</li>
<li>"touchcancel" - When touch is canceled, like when an alert appears or a call comes in.</li>
</ol>
<div>
But, what constitutes a "tap", like a "click" in the mouse model you might wonder. There a several answers to this. A tap might be simply a "touchend". But, what if the user places a finger on a button and then flicks the screen up so that the button goes off screen, now the button will fire a "touchend" when it's off screen. And what if the user holds a button for a long time and then lets go, should that fire an event?</div>
<div>
<br /></div>
<div>
To combat these issues I've created a <a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">Javascript library</a> (and a <a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">jQuery plugin</a>) which will handle all of this for you. You simply add the <a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">library</a> or <a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">plugin</a> to your project and then you add the spanking new "tap" event to your button or what have you. The "tap" library will then try to take care of the issues mentioned above.</div>
<div>
<br /></div>
<div>
Using it is simple:</div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0x1r2QOY5C9N8aY30i7TU6bgl-9qjeOfZkX4GKwPqpkqmrXB1hyphenhyphenzjd47LmMamSMYxCCcgLCmdfTdXmjMF_EjWb1bDwK1dwwWFrViZV2Gt7bU4NYRYUW8UZYcbJGkSThCHEpcOwz1Qh76/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> var tapHandler = function(e){
//Do something
}
document.getElementById('aDiv').<b>tap</b>(tapHandler);
</code></pre>
<br />
Take a look at the documentation inside of the <a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">source files</a> and of course, look at <a href="http://web.kinderas.com/demos/touch_tap/" target="_blank">the demo</a>.<br />
<br />
<br />
<ul>
<li><a href="https://github.com/jornki/Demos/tree/master/libs/touchevents" target="_blank">Get the source</a></li>
<li><a href="http://web.kinderas.com/demos/touch_tap/" target="_blank">Checkout the demo</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com1tag:blogger.com,1999:blog-7239447129918882627.post-24199094274699262552012-02-12T20:04:00.001+01:002012-02-12T20:10:09.129+01:00Form input placeholder shiv<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5GGeFOcsxb7iotanlzXqbYn6w15PuVeDoAX05kC6EOLO8kesgK1iHcvp5Vn8ofjwRYoQSVXnhGteDHWWd6GpXzfeW8DsV7R9x4Y5u3HgmpLklaSIihZsA2PrfbfRW6lYjXI9C9TnOtPo/s1600/Screen+Shot+2012-02-12+at+19.36.17.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5GGeFOcsxb7iotanlzXqbYn6w15PuVeDoAX05kC6EOLO8kesgK1iHcvp5Vn8ofjwRYoQSVXnhGteDHWWd6GpXzfeW8DsV7R9x4Y5u3HgmpLklaSIihZsA2PrfbfRW6lYjXI9C9TnOtPo/s1600/Screen+Shot+2012-02-12+at+19.36.17.png" /></a></div>
As part of the HTML 5 form features, the attribute "placeholder" was introduced for input elements supporting text input (including password). This is awesome and does indeed make form input elements not only more accessible, but it also paves the way for "label less" UI on devices with no so much screen real-estate. However, as with all new things HTML 5 this too is not fully supported on every major browser. Enter the not so elegantly named "<a href="https://github.com/jornki/Demos/tree/master/libs/placeholderShiv" target="_blank">placeholderShiv</a>".<br />
<br />
I wrote this library to enable the "placeholder" feature in every browser. It will basically grab all the valid input elements and append to them functionality which will mimic the native placeholder feature. All you need to do is to assign values to the input elements and add the library of your choice. This value will be turned into a placeholder text. <a href="http://web.kinderas.com/demos/placeholder/" target="_blank">Try the demo</a> to see it in action.<br />
<br />
«<a href="https://github.com/jornki/Demos/tree/master/libs/placeholderShiv" target="_blank">PlaceholderShiv</a>» comes in three versions, a Coffeescript version, a JavaScript version and a jQuery plugin. The Coffeescript and the JavaScript ones does not have any dependencies on any other libraries and they are somewhat faster than the jQuery plugin. However, the jQuery version will support browsers which does not implement "addEventListener" and it is somewhat easier to use if you're already using jQuery.<br />
<br />
<br />
<ul>
<li><a href="http://web.kinderas.com/demos/placeholder/" target="_blank">Check out the demo</a></li>
<li><a href="https://github.com/jornki/Demos/tree/master/libs/placeholderShiv" target="_blank">Download the source</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-54239856249418967752012-01-08T18:59:00.000+01:002012-01-08T18:59:20.437+01:00Extending the Modernizr.prefixed method<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBUpGAq3tFoyZ158yVmVPU_yQ73wAMY5AZsx1AMqIi2eTLY76-FudvIUJ4Gux_EtRFjQHPHh7x7dMsWBw1yvjOmLtS-VNJ-RqjL0HKV0r7eI5ZE-WA_WVBWPRjz_IXVc01xaCrKp9ZMKw/s1600/modernizr.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="97" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBUpGAq3tFoyZ158yVmVPU_yQ73wAMY5AZsx1AMqIi2eTLY76-FudvIUJ4Gux_EtRFjQHPHh7x7dMsWBw1yvjOmLtS-VNJ-RqjL0HKV0r7eI5ZE-WA_WVBWPRjz_IXVc01xaCrKp9ZMKw/s200/modernizr.png" width="200" /></a></div>
Starting with version 2.0 the awesome feature detection js library <a href="http://www.modernizr.com/" target="_blank">Modernizr</a> includes a method called "<a href="http://www.modernizr.com/docs/#prefixed" target="_blank">prefixed</a>". In short, this method will give you the correct prefixed version of a CSS 3 property which still requires this. E.g: -webkit, -moz and so on. Used in conjunction with the jQuery library you can use <a href="http://www.modernizr.com/docs/#prefixed" target="_blank">Modernizr.prefixed</a> for typical tasks like adding a transition to an element in script without having to clutter up your CSS with a gazillion lines of vendor prefixes.<br />
<br />
However, the <a href="http://www.modernizr.com/docs/#prefixed" target="_blank">Modernizr.prefixed</a> method will always return the JavaScript version of the style property. Modernizr.prefixed('transform') will return "WebkitTransform" in a Webkit browser. If you are using <a href="http://api.jquery.com/css/" target="_blank">jQuery.css()</a> this might not be a problem as <a href="http://api.jquery.com/css/" target="_blank">jQuery.css()</a> understands this format as well, if it's passed as the property (first parameter). However the prefixes might also be needed as the actual value of an style property. Consider the following:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0x1r2QOY5C9N8aY30i7TU6bgl-9qjeOfZkX4GKwPqpkqmrXB1hyphenhyphenzjd47LmMamSMYxCCcgLCmdfTdXmjMF_EjWb1bDwK1dwwWFrViZV2Gt7bU4NYRYUW8UZYcbJGkSThCHEpcOwz1Qh76/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> $('#myDiv').css(Modernizr.prefixed('transition'),Modernizr.prefixed('transform') + ' 1s linear');
</code></pre>
<br />
This snippet will attempt to set a transition on the "myDiv" HTML element using jQuerys´ "css" method and the <a href="http://www.modernizr.com/docs/#prefixed" target="_blank">Modernizr.prefixed</a> method, but it will fail to do so. Why? Well, since jQuery is awesome it will allow us to pass "WebkitTransition" or "-webkit-transition" (if in a webkit browser) as the first parameter to the "css" method. For the second parameter <a href="http://api.jquery.com/css/" target="_blank">jQuery.css()</a> expects a CSS formatted string «-webkit-transform 1s linear», however the code above will generate «WebkitTransform 1s linear», which is not valid CSS and hence the entire method fails. What is needed is a Modernizr method which spits out a CSS formatted and prefixed string, let's call it "Modernizr.cssprefixed". Sadly this is not a part of Modernizr as of today, but the solution is given in the <a href="http://www.modernizr.com/docs/#prefixed" target="_blank">Modernizr.prefixed</a> documentation, we only need a more convenient version of the RegExp given in the docs.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0x1r2QOY5C9N8aY30i7TU6bgl-9qjeOfZkX4GKwPqpkqmrXB1hyphenhyphenzjd47LmMamSMYxCCcgLCmdfTdXmjMF_EjWb1bDwK1dwwWFrViZV2Gt7bU4NYRYUW8UZYcbJGkSThCHEpcOwz1Qh76/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> Modernizr.cssprefixed = function(str)
{
return this.prefixed(str).replace(/([A-Z])/g,function(str,m1){
return '-' + m1.toLowerCase();
}).replace(/^ms-/,'-ms-');
}
</code></pre>
<br />
Now that we have this spanking new method we can update our line of code to:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0x1r2QOY5C9N8aY30i7TU6bgl-9qjeOfZkX4GKwPqpkqmrXB1hyphenhyphenzjd47LmMamSMYxCCcgLCmdfTdXmjMF_EjWb1bDwK1dwwWFrViZV2Gt7bU4NYRYUW8UZYcbJGkSThCHEpcOwz1Qh76/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> $('#myDiv').css(Modernizr.prefixed('transition'),Modernizr.<strong>css</strong>prefixed('transform') + ' 1s linear');
</code></pre>
<br />
Voila, it works!Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-45619992409566196852011-10-23T20:46:00.000+02:002011-10-23T20:46:57.441+02:00Getting you bearings with JavaScript on iOS<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJt2qqCq8UE-fPW2G3ULTJ-tlV0YMh52ihYwB_EiwmCsWy64Y7SicHHbsaMaJVcT-10U8haJ5ohUl2tbJfMYZkkIqgVqerf9jH0Wq9oKrT2W7R-FEb6dAjnvNJvtzWcaE0VgSVGwLZaEE/s1600/compass.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJt2qqCq8UE-fPW2G3ULTJ-tlV0YMh52ihYwB_EiwmCsWy64Y7SicHHbsaMaJVcT-10U8haJ5ohUl2tbJfMYZkkIqgVqerf9jH0Wq9oKrT2W7R-FEb6dAjnvNJvtzWcaE0VgSVGwLZaEE/s200/compass.png" width="160" /></a></div>
This post is an extension of my <a href="http://kinderas.blogspot.com/2011/06/accessing-gyroscope-and-accelerometer.html">previous post</a> on accessing the gyroscope in your iOS device from JavaScript for a web application. So be sure to read <a href="http://kinderas.blogspot.com/2011/06/accessing-gyroscope-and-accelerometer.html">that one</a> first or you'll probably get squat.<br />
<br />
New in iOS 5 is the ability to access the compass using JavaScript. This is done precisely in the same way as with all other «orientation data». The «deviceorientation» event on the window object will (on iPhone 4 or newer running iOS 5 and newer) contain two properties related to the compass, these are:<br />
<br />
<ul>
<li>«webkitCompassHeading» [0-360°] - Where 0 is magnetic north</li>
<li>«webkitCompassAccuracy» - How many degrees the heading is off (-1 if error)</li>
</ul>
So for the <a href="http://web.kinderas.com/demos/compass/index.html">demo</a> I'm using the same arrow as in the gyroscope post, except now with gorgeous «north» and «south» indicators added. The goal of the <a href="http://web.kinderas.com/demos/compass/index.html">demo</a> is to make the arrow point towards north. When you're done playing with it, take a look at the <a href="http://web.kinderas.com/demos/compass/main.js">source</a> and amaze at its simplicity.<br />
<br />
Further reading:<br />
<br />
<ul>
<li><a href="http://web.kinderas.com/demos/compass/index.html">The amazing demo</a></li>
<li><a href="http://developer.apple.com/library/safari/#documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html">DeviceOrientationEvent Class Reference</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-89427047644629548032011-10-09T18:04:00.000+02:002011-10-09T18:18:02.492+02:00The HTML 5 History API<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifWPo9NOcLRE6H97SdFWhIu5J5pVn-6lQLRFgE30u4WUWn2xBdLF8CuzmoUfn3IDHTM8eHhcFZaUlSG-qeSICWKOTfbfe4OpdxROJc3Pu7Qubvq38bGu7eZ0kT2SVPtjYSGrBlJp1GSRw/s1600/34337.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifWPo9NOcLRE6H97SdFWhIu5J5pVn-6lQLRFgE30u4WUWn2xBdLF8CuzmoUfn3IDHTM8eHhcFZaUlSG-qeSICWKOTfbfe4OpdxROJc3Pu7Qubvq38bGu7eZ0kT2SVPtjYSGrBlJp1GSRw/s1600/34337.png" /></a></div>
The <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#the-history-interface">HTML 5 History API</a> will allow us to update the browser history and keep the all so important functionality of the back and forward browser buttons when the site is loading content dynamically using <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>.<br />
<br />
You want to use XMLHttpRequests (AJAX) to avoid unnecessary page loads, hence reducing network traffic and therefore speeding up you web-app, you probably already do this in your web-apps. However, before the advent of the HTML 5 History API there was a problem with this otherwise smart approach to building web-apps. When a page updated it's content this would not be reflected in the browser history and you had to do a lot of work to make the back and forward buttons work as expected. Thanks to the HTML 5 History API this is now much simpler. In this article I'll explain an approach to "mimicking" a common server-side approach to "dynamic" page loading using parameters in the url, while retaining the functionality of the browser history. <a href="http://web.kinderas.com/demos/history/index.html">Take a look at the demo</a>.<br />
<br />
What this typical AJAX demo does is pretty basic:<br />
<br />
<ul>
<li>At startup it loads a page depending upon the presence of a parameter.</li>
<li>When you click a link (at the top), it fetches and swaps the content of the "content" holder of the main page.</li>
</ul>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn6kejHDaGvIhZkD0-fmvtI9UnuyZD7SpjwExNKjILiRYli8XyALI3KdqiZzEQLMBbOg0Mtyg2LSXtX6w3Duzi6DwikgX4wdXfCee_6DVJ4HvHPIZQvQItke-BeXWa_3uemv-sXReWziQ/s1600/history.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn6kejHDaGvIhZkD0-fmvtI9UnuyZD7SpjwExNKjILiRYli8XyALI3KdqiZzEQLMBbOg0Mtyg2LSXtX6w3Duzi6DwikgX4wdXfCee_6DVJ4HvHPIZQvQItke-BeXWa_3uemv-sXReWziQ/s320/history.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Pushed history items</td></tr>
</tbody></table>
<div>
However, after having clicked the links you'll also notice that the back and forward buttons are working, without actually navigating you away from the main page, like the're integrated with the app. Also, items are "pushed" onto the browser history, making it possible to navigate directly to a previously loaded page. It's just updating the content of the content box when you click a link, not the entire page. This is what happens:</div>
<div>
<ul>
<li>When a link is clicked the new content is fetched using a XMLHttpRequest.</li>
<li>The current content is replaced and the browser history is updated.</li>
</ul>
<div>
All of these operations are accomplished using only three (3) API calls:</div>
</div>
<div>
<ul>
<li>The «<a href="https://developer.mozilla.org/en/DOM/window.onpopstate">onpopstate</a>» event allows us to listen to events fired when the history is being navigated, like when using the back button. (see line 57'ish in the <a href="http://web.kinderas.com/demos/history/main.js">demo code</a> for how this is handled).</li>
<li>The «<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#dom-history-replacestate">replaceState</a>» method allows us to replace the current state in the browser history. This is used to create a state when for example on initial page load.</li>
<li>The «<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#dom-history-pushstate">pushState</a>» method allows us to add things to the history stack (it's a stack, hence push and pop).</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwXn2dkEtvPa9EFWSuymT5Y6nKJG03FY0P9yaJWwlB0GRrqjXR2-X4eoysJGIJUCDHGgPpgWqHnx2xdZ2a9PR9_SYN_LbvoI0BPuftArbDEG0lGlAVKDbrLJngdXlQisXgXbTKu5h5vBE/s1600/browsers.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwXn2dkEtvPa9EFWSuymT5Y6nKJG03FY0P9yaJWwlB0GRrqjXR2-X4eoysJGIJUCDHGgPpgWqHnx2xdZ2a9PR9_SYN_LbvoI0BPuftArbDEG0lGlAVKDbrLJngdXlQisXgXbTKu5h5vBE/s200/browsers.png" width="200" /></a></div>
<div>
Now, this does not work in all browsers (IE..duh!) and as of writing this post still has «<a href="http://whatis.techtarget.com/definition/0,,sid9_gci491373,00.html">Working Draft</a>» status. However, <a href="http://caniuse.com/#search=history">support</a> is pretty good and when Microsoft finally adds support in IE 10, all major browsers will support the History API.</div>
<div>
<br /></div>
<div>
Take a look at the <a href="http://web.kinderas.com/demos/history/index.html">demo</a> and the <a href="http://web.kinderas.com/demos/history/main.js">source code</a> (which is heavily commented) and feel free to use the source freely.</div>
<div>
<br /></div>
<div>
Bye!</div>
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-3653403099596825412011-07-03T18:29:00.000+02:002014-02-18T19:31:02.657+01:00Creating a simple WYSIWYG editor with HTML and JavaScript<br />
<blockquote class="tr_bq">
<span style="background-color: white;">An updated and better version of this post with a new and better demo can be found here: <a href="http://www.kinderas.com/technology/2014/2/18/a-simple-rich-text-editor">http://www.kinderas.com/technology/2014/2/18/a-simple-rich-text-editor</a></span></blockquote>
<br />
Wouldn't it be nice to provide the users of your website with a WYSIWYG rich text editor instead of boring forms and a bunch of textfields? Enter «contenteditable». This is a simple property which can be set on any DOM element, like divs, sections and so on. What it does it making the element writable for the user, directly inline with all your predefines styles and content.<br />
<code>contenteditable="true"</code><br />
To get set up, set the «contenteditable» property of your selected element to "true". In my <a href="http://web.kinderas.com/demos/contenteditable/index.html">demo</a> I'm using a «section» element, but as noted above, you can use any DOM element. And that is it actually. You now have a working rich text editor running on you web-page. You can use the keyboard shortcuts like «cmd+b» to make selected text bold and so on. But wait, there's more.<br />
<div class="highlight">
<pre><code><span style="color: green;">document</span>.execCommand(<span style="color: #ba2121;">'bold'</span><span style="color: #666666;">,</span><span style="color: green; font-weight: bold;">false</span><span style="color: #666666;">,</span><span style="color: green; font-weight: bold;">null</span>);
</code></pre>
</div>
This simple JavaScript command will allow you to programmatically make text bold and thats not all, there are a dozen of built in commands which can be executed on the selected text, for an overview take a look at the <a href="http://blog.whatwg.org/the-road-to-html-5-contenteditable">WHATWG specification</a>.<br />
<br />
When combining «contenteditable» with the HTML 5 storage APIs you can pretty easily make a powerful rich text editor for your users. Take a look at my simple <a href="http://web.kinderas.com/demos/contenteditable/index.html">demo</a> to see how you can accomplish this. As a side note, iOS 5 brings support for «contenteditable» on mobile platforms as well.Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com1tag:blogger.com,1999:blog-7239447129918882627.post-70742349874478718772011-06-26T17:06:00.001+02:002011-06-26T17:52:23.628+02:00Accessing the gyroscope and accelerometer using JavaScript<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEgaWK4iDVKafyrNpBDCWfOnfN0PBkDCnK1X-c_LR7nH8Ehz9BDJ3MlECD9TngS4ipDKjc7NuYwYdI11jL-MSgqFFv8uHUwf704p0onorPrIfpbcLvUfYha3qiJkQ-4dzlCj_Osa3vNtM/s1600/Gyroscope2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEgaWK4iDVKafyrNpBDCWfOnfN0PBkDCnK1X-c_LR7nH8Ehz9BDJ3MlECD9TngS4ipDKjc7NuYwYdI11jL-MSgqFFv8uHUwf704p0onorPrIfpbcLvUfYha3qiJkQ-4dzlCj_Osa3vNtM/s200/Gyroscope2.png" width="200" /></a></div>With the advent of "mobile" devices such as the iPad, iPhone and all the gazillion Android devices, an increasing demand for browser-applications to sport the features and functionality native applications arises. In this article I'll have a quick look at one of these features, namely «device orientation». First of all, take a look at the <a href="http://web.kinderas.com/demos/orientation/index.html">demo</a>. In this demo I'm using the "deviceorientation" event listener of the «window» object to listen for orientation events. Orientation events are in short events triggered when your device is twisting and turning, sort of. In my iPhone, these events originate in the accelerometer and the gyroscope. For your phone this might be different, but it doesn't matter as the API's for accessing the data are pretty much the same and part of the «<a href="http://dev.w3.org/geo/api/spec-source-orientation">DeviceOrientation Event Specification</a>». Note that this demo is only tested on the iPhone 4, so if you have something else it might not work. Let's get to it then.<br />
<div class="highlight"><pre><code><span style="color: green;">window</span>.addEventListener(<span style="color: #ba2121;">'deviceorientation'</span><span style="color: #666666;">,</span> orientationHandler<span style="color: #666666;">,</span> <span style="color: green; font-weight: bold;">false</span>);
</code></pre></div><br />
First of all we need to add an event listener for the «device orientation» event. This event is fired by the «window» object as mentioned above. We then simply set up our event handler.<br />
<br />
<div class="highlight"><pre><code><span style="color: green; font-weight: bold;">function</span> orientationHandler(e)
{
image.style.webkitTransform <span style="color: #666666;">=</span> <span style="color: #ba2121;">"perspective(500)
rotateZ("</span><span style="color: #666666;">+</span>e.alpha<span style="color: #666666;">+</span><span style="color: #ba2121;">"deg)
rotateX("</span><span style="color: #666666;">+</span>e.beta<span style="color: #666666;">+</span><span style="color: #ba2121;">"deg)
rotateY("</span><span style="color: #666666;">+</span>e.gamma<span style="color: #666666;">+</span><span style="color: #ba2121;">"deg)"</span><span style="color: #666666;">;</span>
}
</code></pre></div><br />
There are three properties of the «orientation event» we want to get at.<br />
<br />
<ul><li>«alpha» - This is rotation about the Z axis. In other words left and right rotation.</li>
<li>«beta» - This is rotation about the X axis. This means how much you are tilting the device towards you.</li>
<li>«gamma» - This is the rotation about the Y axis, or the angle of the device screen if you may.</li>
</ul><div>There are also two other properties present in iOS 5 which gives you access to the compass and it's accuracy, but those are not used in this example.</div><div><br />
</div><div>The «perspective(500)» transform simply defines how "far away" from the object you are when it's rotated, or the depth if you like. Since the properties of the «device orientation» event correlates to the values handled by the CSS transform properties, no calculation is needed. <a href="http://web.kinderas.com/demos/orientation/index.html">Try it out</a>! (Should work on iPhone 4 and iPad 2)</div><div><br />
</div><div>References:</div><div><ul><li><a href="http://dev.w3.org/geo/api/spec-source-orientation">W3C - DeviceOrientation Event Specification</a></li>
</ul></div>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-30685269698912467782011-06-05T19:08:00.003+02:002011-06-11T13:51:46.911+02:00HTML 5 Web Workers and image processing<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi9j-GXcndT6n8i59EPZKsB9SNun_gX733J9UzxSoiYfTUxiiNQoSV0LvhFYuaMkheUTIX-E01nncOATTa_RmmbL1arcTUoh1SBAt3f5fhXuiTKu5hmX5FD89BQBanztRfAfeH4_jgQgk/s1600/Lego-construction-workers.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi9j-GXcndT6n8i59EPZKsB9SNun_gX733J9UzxSoiYfTUxiiNQoSV0LvhFYuaMkheUTIX-E01nncOATTa_RmmbL1arcTUoh1SBAt3f5fhXuiTKu5hmX5FD89BQBanztRfAfeH4_jgQgk/s320/Lego-construction-workers.jpeg" width="320" /></a></div>One of the more exiting things we are getting via the new <a href="http://www.whatwg.org/specs/web-apps/current-work/">HTML</a> specification is <a href="http://www.whatwg.org/specs/web-workers/current-work/">Web Workers</a>. If you have no idea what Web Workers (lets call them Worker from now on) are you can basically think of them as "sandboxed" <a href="http://en.wikipedia.org/wiki/Thread_(computer_science)">threads</a>. By threads I do refer to threads as in «<a href="http://en.wikipedia.org/wiki/Multithreading_(computer_architecture)">multithreading</a>», an architectural feature of modern CPUs and operating systems. Workers allow us to run tasks separately from the main thread where all the drawing, animation and DOM manipulation is going on. This allows us to do calculations without leaving the impression on the user that the browser is "hanging". If you have worked with other "thread wrapping" technologies like <a href="http://en.wikipedia.org/wiki/Grand_Central_Dispatch">Grand Central Dispatch (GCD)</a> you will get Workers without fuzz, however Workers do have some limitations that other similar technologies don't have.<br />
<br />
<b>Workers limitations and usage</b><br />
First of all, Workers are separate code blocks of JavaScript not found in the spawning script, kinda.. In most cases a Worker is a separate JavaScript file which you DO NOT refer to in you HTML script tags in the HTML document. However, Workers can also be defined inline through the <a href="http://code.google.com/apis/gears/api_blobbuilder.html">BlobBuilder</a> interface. In this post I will use only external Workers. Also, there are two kinds of Workers, «<a href="http://www.whatwg.org/specs/web-workers/current-work/#sharedworker">Shared</a>» and «<a href="http://www.whatwg.org/specs/web-workers/current-work/#dedicated-workers-and-the-worker-interface">Dedicated</a>». I will only use «Dedicated Workers» in this post.<br />
<br />
Workers cannot access the following:<br />
<ul><li>The DOM or the DOM APIs</li>
<li>The window object</li>
<li>The document and the parent object. </li>
</ul>A worker can access:<br />
<ul><li>The «navigator» object</li>
<li>«XMLHttpRequest»</li>
<li>A read-only version of the «location» object</li>
<li>The Application cache</li>
<li>setTimeout(), clearTimeout() and setInterval(), clearInterval()</li>
</ul>A Worker can also spawn other Workers and import external scripts via «importScripts()».<br />
<br />
<b>The demo (aka. the fun part)</b><br />
For the <a href="http://web.kinderas.com/demos/web_workers_images/">demo</a> this time I have created a simple web-app which loads and displays 3 pictures n times. You can randomize the position of the images by clicking the randomize button. You can pick the number of images displayed as well as their size. The two image manipulation buttons will grayscale and invert the images, if you check the checkbox the images will perform the randomize animation concurrently with the image processing. It's this latter part which calls for the usage of Workers.<br />
<br />
The <a href="http://web.kinderas.com/demos/web_workers_images/">demo</a> will show you how to spawn a separate Worker for each of the images, thereby allowing for concurrent processing and animation without much degradation in performance. I won't explicitly go through all the layout and animation code here, rather focusing on the usage of the Workers.<br />
<br />
<div class="highlight"><pre><code><span style="color: green; font-weight: bold;">var</span> worker <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">new</span> Worker(<span style="color: #ba2121;">'DWGrayscale.js'</span>);
worker.addEventListener(<span style="color: #ba2121;">'message'</span><span style="color: #666666;">,</span> <span style="color: green; font-weight: bold;">function</span>(e){
ctxAr[e.data.index].context.putImageData(e.data.imagedata<span style="color: #666666;">,0,0</span>);
});
worker.postMessage(...imagedata...);
</code></pre></div><br />
On line <a href="http://web.kinderas.com/demos/web_workers_images/">126 - 133 within the grayscale function</a> we create a Worker for each of the images, then we add a listener for the «onmessage» event allowing the Worker to communicate with the main thread. We finish off by posting a message to the worker using «postMessage» and passing the image data. These messages are the only way to communicate with a Worker. This means that we also need to implement this interface in the Worker itself.<br />
<div class="highlight"><pre><code>addEventListener(<span style="color: #ba2121;">'message'</span><span style="color: #666666;">,</span> <span style="color: green; font-weight: bold;">function</span>(e){
<span style="color: green; font-weight: bold;">var</span> imageData <span style="color: #666666;">=</span> e.data.imagedata<span style="color: #666666;">;</span>
<span style="color: #408080; font-style: italic;">//....process image data....</span>
postMessage(...imagedata...);
});
</code></pre></div>In the Worker «<a href="http://web.kinderas.com/demos/web_workers_images/DWGrayscale.js">DWGrayscale.js</a>» we grab the passed image data from the «data» property of the event. We then go on processing the image data, when done we post a message back to the main thread passing the image data which then in turn can be used to update the canvas element on screen.<br />
<br />
<b>Why not pass the Canvas element or at least the Canvas context?</b><br />
Workers do not have access to the DOM, because it would not be thread safe. Workers are limited to passing object which can be serialized into JSON, which does not support cyclic objects. The Canvas element is a DOM element and the context is a cyclic object, hence we need to get the actual pixel array which we can pass back and forth to the Worker.<br />
<br />
Take a look at the <a href="http://web.kinderas.com/demos/web_workers_images/">demo</a> and the <a href="http://web.kinderas.com/demos/web_workers_images/main.js">source code</a> to learn in more detail how the demo was created.<br />
<i>Note also that you should probably run the demo in Safari as it has no limitation on the number of Workers concurrently running like Chrome has, also the animations uses the WebKit prefix and will not work in non WebKit browsers. So, please don't use this code in an production environment!</i><br />
<br />
References:<br />
<br />
<ul><li><a href="http://www.html5rocks.com/tutorials/workers/basics/">The basics of Web Workers - HTML 5 Rocks</a></li>
<li><a href="http://www.whatwg.org/specs/web-workers/current-work/">WHATWG - Web Workers</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com4tag:blogger.com,1999:blog-7239447129918882627.post-38260796003805841582011-05-01T20:14:00.000+02:002011-05-01T20:14:11.783+02:00Quicktip: Skewing an image with JavaScript and CSS3<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtc0gFJ2gD0UIPsCXT0xcCH6j9g9Vp83fyHBUCaI1w7PE1LwQn-vNF1fx_YMCYUzG6zgVb5gbfe1rfQa7AROzLfwZVbcOGYq5c5QKoB6flihUQ5fFSEAwTYHIKoA0vXIu_4RAw25FXEdE/s1600/skew_rabbit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtc0gFJ2gD0UIPsCXT0xcCH6j9g9Vp83fyHBUCaI1w7PE1LwQn-vNF1fx_YMCYUzG6zgVb5gbfe1rfQa7AROzLfwZVbcOGYq5c5QKoB6flihUQ5fFSEAwTYHIKoA0vXIu_4RAw25FXEdE/s200/skew_rabbit.png" width="200" /></a></div>Have you ever found yourself in a situation where you needed to skew a rabbit? If you haven't, you'll probably enter this place soon, so here I am to prepare you. The task is to skew an image on a HTML page using CSS and JavaScript. This could be attached to for instance a button click event. This is a one liner..<br />
<code>document.getElementById('myImage').style.transform = "skew(-15deg)"</code><br />
The «skew» property of the «transform» CSS method takes degrees of skew as an input. Negative numbers will skew the image top right, bottom left and positive numbers..the other way around.<br />
Note that in order for this to actually work, you will need to use vendor prefixes as the time of writing this post. For Safari (desktop and iOS) and Chrome (and Android) you would use «webkitTransform» for FireFox «mozTransform» and so on.Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-58211088305105511982011-04-11T20:21:00.000+02:002011-04-11T20:21:39.479+02:00The Peacekeeper<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYAcWEmF_2_SslLi30AUxno_fuWYuGYgkEKU7Aw2Gh8z_f-rsxtDWedgiQgb8V3_-o1jT7BtaPOpI2lDccNb9S75zfJ62zHXg4h3pxf47X8o0lmKHiAnVlfPx6Bhw1rLsNj-U4yGujC8/s1600/results.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYAcWEmF_2_SslLi30AUxno_fuWYuGYgkEKU7Aw2Gh8z_f-rsxtDWedgiQgb8V3_-o1jT7BtaPOpI2lDccNb9S75zfJ62zHXg4h3pxf47X8o0lmKHiAnVlfPx6Bhw1rLsNj-U4yGujC8/s640/results.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Peacekeeper on an iMac 3.0 Ghz</td></tr>
</tbody></table>I decided to try out <a href="http://www.futuremark.com/">Futuremaks</a> spanking "new" <a href="http://clients.futuremark.com/peacekeeper">Peacekeeper</a> browser tester today. In contrast to other more "nerdy" tests like <a href="http://acid3.acidtests.org/">Acid3</a> and <a href="http://www.webkit.org/perf/sunspider/sunspider.html">SunSpider</a> which are useful for people like me, Peacekeepers tests are more targeted at actual normal usage of a browser, making it slightly more interesting for users without a degree in computer science.<br />
<br />
On the other hand, if you want to understand the six test, well.. it gets a bit technical. The first test «rendering» is a test of how fast the browser can draw stuff to the screen, while doing other calculations and operations at the same time. The second test which Futuremark calls «social networking» is actually a test in how fast the browser can create a SHA1 hash, parse some XML and filtering and sorting the elements of an array. Thirdly we arrive at the «complex graphics» test, which is a test on canvas drawing operations, canvas being part of the new HTML 5 standard. The «data» test which I have renamed to "arrays" does work on exactly that, array manipulation. The «DOM manipulation» test, is one of the most important tests as this tests the browsers ability to look up elements in the DOM fast. This should be of particular interest to jQuery fans. The last test «text parsing», is what its name suggests, parsing and searching in strings. To get a full detailed explanation of what the individual test entails, see <a href="http://clients.futuremark.com/peacekeeper/faq.action">Futuremarks FAQ site</a>.<br />
<br />
My testcomputer was an iMac 3.06 GHz, with 8GB of RAM and an ATI Radeon HD 4670 graphics card running OS X 10.6.7. It matters, because these tests will very, much, depending on your computer and OS.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OT5X6wsv2XGAIQ1j5ywfgK9k1qAAPQrD3XcyciAkcX8L9fqqg0z3tal7_KLXgGVVvuUo8k5eXLOhjExPLt7V-K9Y__t4nW0mmH5lwal6N9T_bJqDlRFgplvrvkU4htpKDEQb7vzZKbI/s1600/google-chrome-logo1.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OT5X6wsv2XGAIQ1j5ywfgK9k1qAAPQrD3XcyciAkcX8L9fqqg0z3tal7_KLXgGVVvuUo8k5eXLOhjExPLt7V-K9Y__t4nW0mmH5lwal6N9T_bJqDlRFgplvrvkU4htpKDEQb7vzZKbI/s1600/google-chrome-logo1.jpeg" /></a></div>As for the results one can clearly see that the WebKit browsers beat the snot out of Firefox. Chrome is clearly the fastest browser overall, however for DOM manipulation Safari is slightly faster than Chrome. Again, beware of this one jQuery fans because this is where all those selectors come into play. Chrome is ruling the array manipulation speed, this might be due to the <a href="http://code.google.com/p/v8/">V8 JavaScript engine</a>. All the browsers basically suck when it comes to rendering HTML 5 Canvas graphics.<i> As a side-note, I observed a test that was run on a Windows based computer as well. To our surprise, both Chrome and Opera beat Internet Explorer 9 into the slippers when it came to canvas performance. <a href="http://www.beautyoftheweb.com/">Beauty of the web</a> my <a href="http://www.animalinfo.org/image/equuafri6%2033%20j.jpg">ass</a>, in your own tests internally made tests perhaps.</i><br />
<br />
<b>Conclusion</b><br />
So, judging from this Google Chrome is the browser your should go for. And in my opinion, it is. For me, I'm sticking with Safari for my day to day use, but I'm using Chrome when writing this blog post.Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-41426046237328706842011-04-03T19:40:00.006+02:002011-04-03T19:54:00.161+02:00Scaling and rotating an elephant using JavaScript<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSxC7sQMdPjhECPDK95VDB13MxwFQrNw83JlKI01mIx3C4YysISLdLDlqrjC1Q7gzi-ZIxGZJnu3mdzi4hTRqxk3tHgZqNv8BOBhESzNxULsU7q63kVcdMFQab02e1U7LGwDjyF8Yh97U/s1600/Screen+shot+2011-04-03+at+18.31.46.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSxC7sQMdPjhECPDK95VDB13MxwFQrNw83JlKI01mIx3C4YysISLdLDlqrjC1Q7gzi-ZIxGZJnu3mdzi4hTRqxk3tHgZqNv8BOBhESzNxULsU7q63kVcdMFQab02e1U7LGwDjyF8Yh97U/s320/Screen+shot+2011-04-03+at+18.31.46.png" width="320" /></a></div>This second post about «touch» is somewhat an extension to my previous post «<a href="http://kinderas.blogspot.com/2011/03/drawing-by-touching-using-javascript.html">Drawing by touching using JavaScript</a>». However in this post the focus will be on «gesture events». A <a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">gesture event</a> is an event which will fire when more than one finger is present on the screen. Due to the somewhat complex nature of the accompanying <a href="http://web.kinderas.com/demos/touch_gestures/">demo</a>, I will not walk through it line by line, but rather focus on some key ares which are important when dealing with touches and gestures.<br />
Step 1 is to take a look at the <a href="http://web.kinderas.com/demos/touch_gestures/">demo</a> and read through my comments. To understand this you will need a basic understanding of object oriented JavaScript and I will not walk through that part of the demo in this post. What I will explain in some detail is how the gesture events work (to see how touch events work, refer to my previous post) and some nifty tricks you can do with event handlers and transforms. Oh..and you will be needing a touch device to test this thing. Let's get cracking then.<br />
<br />
The basic functionality of this <a href="http://web.kinderas.com/demos/touch_gestures/">demo</a> is to place images on the page which have some <a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">touch</a> and <a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">gesture</a> events applied to them. This will allow us to move, scale and rotate the images using gestures. An array «elephants» is used to keep track of all the images on the page. On <u><a href="http://web.kinderas.com/demos/touch_gestures/main.js">line 70</a></u> (in the <a href="http://web.kinderas.com/demos/touch_gestures/main.js">demo JavaScript file</a>) an Object called «TouchImage» is defined. This object will keep track of all events and transforms associated with one image. We create a new «TouchImage» on <u><a href="http://web.kinderas.com/demos/touch_gestures/main.js">line 52</a></u>. This happens for every time you hit the «Create elephant» button. Then on <u>line <a href="http://web.kinderas.com/demos/touch_gestures/main.js">99 - 104</a></u>:<br />
<code>tImage.image.addEventListener('gesturestart', tImage, false);<br />
tImage.image.addEventListener('gesturechange', tImage, false);<br />
tImage.image.addEventListener('gestureend', tImage, false);<br />
tImage.image.addEventListener('touchcancel', tImage, false);<br />
tImage.image.addEventListener('touchstart', tImage, false);<br />
tImage.image.addEventListener('touchend', tImage, false);</code><br />
Now, this might look a bit strange, we're passing «this» («tImage» is a closure for «this») as the event handler for the listeners. This is because at <u><a href="http://web.kinderas.com/demos/touch_gestures/main.js">line 117</a></u> we define a method called «<a href="http://www.java2s.com/Tutorial/JavaScript/0200__Form/SelecthandleEvent.htm">handleEvent</a>» on the «TouchImage». This is a magical method in JavaScript which will basically handle any event passed to it's object. Within this method we check to see if the caller is a function and if it is, we simply call it.<br />
<div class="highlight"><pre><code>TouchImage.prototype.handleEvent <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">function</span>(event)
{
<span style="color: green; font-weight: bold;">if</span>(<span style="color: green; font-weight: bold;">typeof</span>(<span style="color: green; font-weight: bold;">this</span>[event.type]) <span style="color: #666666;">===</span> <span style="color: #ba2121;">"function"</span>){
<span style="color: green; font-weight: bold;">return</span> <span style="color: green; font-weight: bold;">this</span>[event.type](event);
}
}
</code></pre></div>This way we can extend the «TouchImage» object with methods called «gesturesstart» and so on, the same names as the events. An additional plus is that we stay within scope of the object, avoiding to pass closures around like rag dolls. Now to the gesture handlers. In contrast to «touch» handlers, there are only three «gesture» handlers: «<a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">getsurestart</a>», «<a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">gesturechange</a>» and «<a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">gestureend</a>». Each of these will trigger only if there are more than one finger on the screen.<br />
<div class="highlight"><pre><code>TouchImage.prototype.gesturestart <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">function</span>(event)
{
event.preventDefault();
<span style="color: green; font-weight: bold;">this</span>.startRotation <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">this</span>.rotation<span style="color: #666666;">;</span>
<span style="color: green; font-weight: bold;">this</span>.startScale <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">this</span>.scale<span style="color: #666666;">;</span>
}
</code></pre></div>In «gesturestart» which triggers when a second finger is placed on screen, we capture the current scale and rotation values of the «TouchImage» in question.<br />
<div class="highlight"><pre><code>TouchImage.prototype.gesturechange <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">function</span>(event)
{
event.preventDefault();
<span style="color: green; font-weight: bold;">this</span>.scale <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">this</span>.startScale <span style="color: #666666;">*</span> event.scale<span style="color: #666666;">;</span>
<span style="color: green; font-weight: bold;">this</span>.rotation <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">this</span>.startRotation <span style="color: #666666;">+</span> event.rotation<span style="color: #666666;">;</span>
<span style="color: green; font-weight: bold;">this</span>.applyTransforms();
}
</code></pre></div>In «gesturechange» we calculate the scale and rotation by using the start values and the changed values. The <a href="http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html#//apple_ref/javascript/cl/TouchEvent">scale</a> is multiplied with the new scale and the <a href="http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html#//apple_ref/javascript/cl/TouchEvent">rotation</a> is calculated by adding the start rotation to the current rotation. This works because both values in the change handler will give us the amount changed since the start event. Then we call the «applyTransforms()» method where the actual transform is done.<br />
<div class="highlight"><pre><code>TouchImage.prototype.applyTransforms <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">function</span>()
{
<span style="color: green; font-weight: bold;">var</span> transform <span style="color: #666666;">=</span> <span style="color: #ba2121;">'translate3d('</span> <span style="color: #666666;">+</span> <span style="color: green; font-weight: bold;">this</span>.posX <span style="color: #666666;">+</span> <span style="color: #ba2121;">'px,'</span> <span style="color: #666666;">+</span> <span style="color: green; font-weight: bold;">this</span>.posY <span style="color: #666666;">+</span> <span style="color: #ba2121;">'px, '</span><span style="color: #666666;">+</span><span style="color: green; font-weight: bold;">this</span>.posZ<span style="color: #666666;">+</span><span style="color: #ba2121;">'px)'</span><span style="color: #666666;">;</span>
transform <span style="color: #666666;">+=</span> <span style="color: #ba2121;">' rotate('</span> <span style="color: #666666;">+</span> <span style="color: green; font-weight: bold;">this</span>.rotation <span style="color: #666666;">+</span> <span style="color: #ba2121;">'deg)'</span><span style="color: #666666;">;</span>
transform <span style="color: #666666;">+=</span> <span style="color: #ba2121;">' scale('</span> <span style="color: #666666;">+</span> <span style="color: green; font-weight: bold;">this</span>.scale <span style="color: #666666;">+</span> <span style="color: #ba2121;">')'</span><span style="color: #666666;">;</span>
<span style="color: green; font-weight: bold;">this</span>.image.style.webkitTransform <span style="color: #666666;">=</span> transform<span style="color: #666666;">;</span>
}
</code></pre></div>The <a href="http://developer.apple.com/library/safari/#documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Transforms/Transforms.html#//apple_ref/doc/uid/TP40008032-CH5-SW1">transform</a> is done on all properties at the same time. You cannot separate them from each other, because we are in effect overwriting the entire transform style element each time something is changing. Do also note that we are in fact using «<a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariCSSRef/Articles/Functions.html#//apple_ref/doc/uid/TP40007955-SW2">transform3d</a>», which is quite different from the regular «transform». The reason for this is twofold. First, the «transform3d» will render the image on it's own 3D layer, at times triggering hardware rendering. This will yield a significant performance increase. Secondly, the «transform3d» allow us to stack elements in the «z-axis», hence we can move the active element to the front. We do this sorting by calling the «sortDepth» method, which only sorts the «elephants» array.<br />
<br />
That's the gesture events. Now, there are regular <a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">touch events</a> in this application as well. These are used to move the «TouchImage» objects around the screen. I won't cover how this is done in detail here because it's much the same as in the <a href="http://kinderas.blogspot.com/2011/03/drawing-by-touching-using-javascript.html">previous post.</a> However one thing to notice is that an offset is calculated in the «touchstart» handler. This is done so that when moving the image it tracks from the point where the user places her finger on the image. If we didn't do this the image would snap to 0,0 under the users finger when moved, making for an unexpected user experience. That's it and that's that!Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com2tag:blogger.com,1999:blog-7239447129918882627.post-55794910017572807852011-03-19T18:46:00.001+01:002014-03-13T22:31:40.912+01:00Drawing by touching using JavaScript<div class="separator" style="clear: both; text-align: center;">
<a href="http://web.kinderas.com/demos/touch_draw_simple/"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTSbZQE9bXbNH03cHRIhyphenhyphenxjdLiQIFS2Soheu39b6H6c9030dMcyUzBMYyBJ3-dgwf8uYReNm95vWqI7QDq78qXtikuem99ycvx1UckZ41h88H0n2Ald2LMvQKYhJYbI7UekOlbEuwPNzI/s1600/Screen+shot+2011-03-19+at+16.24.31.png" /></a></div>
<br />
<blockquote class="tr_bq">
<a href="http://www.kinderas.com/technology/2014/3/13/a-drawing-application">An updated version of this post and demo is available here: http://www.kinderas.com/technology/2014/3/13/a-drawing-application</a></blockquote>
<br />
<br />
The web is no longer exclusive for desktop and laptop computers. With the introduction of the iPhone and the iPad Apple changed how we interact with the web. In the wake of Apples success with iOS devices we see the emergence of a slew of "handheld" devices. They are all different, some are small, others bigger and more powerful, however most of them utilize touch as a means of input. In this article I take a look at how we can create a simple touch enabled drawing application using only JavaScript and a tinsy-winsy bit of HTML 5.<br />
<br />
First, you can try the finished app (with comments) and download the source code from <a href="http://web.kinderas.com/demos/touch_draw_simple/">here</a>.<br />
<br />
The first thing we need to do is to make sure that the user visiting our web-app is on a device which can understand touch events. This is pretty straight forward. We accomplish this by asking the «window» DOM element if is knows about one of the touch events.<br />
<div class="highlight">
<pre><code><span style="color: green; font-weight: bold;">if</span>(<span style="color: #ba2121;">'ontouchstart'</span> <span style="color: green; font-weight: bold;">in</span> <span style="color: green;">window</span> <span style="color: #666666;">==</span> <span style="color: green; font-weight: bold;">false</span>){
alert(<span style="color: #ba2121;">'Sorry, you need a touch enabled device to use this app'</span>);
<span style="color: green; font-weight: bold;">return</span><span style="color: #666666;">;</span>
}
</code></pre>
</div>
If this does not stop our script, we know that the current device supports the touch events we need. The next step is to prevent the screen itself from scrolling when you drag your finger across it. We need to do this because touch events «bubbles» in JavaScript. This means that all the parent elements will get a chance to handle the touch event after we have handled it in our function. So after we have handled the «touchmove» event in our canvas element it will bubble right up to the window element where the browser will try to scroll the window. PS: Sometimes you might want this behavior, for example when you're scrolling a page. For our demo, we don't need it. To disable page scrolling we listen for the «touchmove» event on the document element, then we flag the event as handled using «event.preventDefault()».<br />
<br />
Now to the construction part. We need to create a canvas element.<br />
<div class="highlight">
<pre><code><span style="color: green; font-weight: bold;">var</span> canvas <span style="color: #666666;">=</span> <span style="color: green;">document</span>.createElement(<span style="color: #ba2121;">'canvas'</span>);
canvas.width <span style="color: #666666;">=</span> <span style="color: green;">window</span>.innerWidth<span style="color: #666666;">;</span>
canvas.height <span style="color: #666666;">=</span> <span style="color: green;">window</span>.innerHeight<span style="color: #666666;">;</span>
<span style="color: green;">document</span>.body.appendChild(canvas);
</code></pre>
</div>
We now have a «canvas» element which is the same size as our entire page. Next up we need to create a context in which to draw for the canvas. A context is kinda like a page within a drawing pad. The context can receive JavaScript drawing commands as we will see later on.<br />
<div class="highlight">
<pre><code>ctx <span style="color: #666666;">=</span> canvas.getContext(<span style="color: #ba2121;">'2d'</span>);
ctx.strokeStyle <span style="color: #666666;">=</span> <span style="color: #ba2121;">"rgba(255,0,0,1)"</span><span style="color: #666666;">;</span>
ctx.lineWidth <span style="color: #666666;">=</span> <span style="color: #666666;">5;</span>
ctx.lineCap <span style="color: #666666;">=</span> <span style="color: #ba2121;">'round'</span><span style="color: #666666;">;</span>
</code></pre>
</div>
The context is now set up using the color red with a 5 pixel wide stroke and rounded ends. You can change these values as you like of course.<br />
<br />
In order for our fingers to be able to produce wonderful line drawings, we need to tell our application to listen for touch events. We'll need three of them. The «touchstart» event is where we set our starting position for the drawing operation. This event fires when a finger is added to the screen. The «touchmove» is where we draw the lines, this event fires when we move a finger on the screen. The «touchcancel» is where we handle exceptions, like what happens if you receive a call in the middle of your art creation extravaganza. This event fires whenever it needs to.<br />
<div class="highlight">
<pre><code>canvas.addEventListener(<span style="color: #ba2121;">"touchstart"</span><span style="color: #666666;">,</span>touchstartHandler<span style="color: #666666;">,</span><span style="color: green; font-weight: bold;">false</span>);
canvas.addEventListener(<span style="color: #ba2121;">"touchmove"</span><span style="color: #666666;">,</span> touchmoveHandler<span style="color: #666666;">,</span><span style="color: green; font-weight: bold;">false</span>);
canvas.addEventListener(<span style="color: #ba2121;">"touchcancel"</span><span style="color: #666666;">,</span> touchcancelHandler<span style="color: #666666;">,</span><span style="color: green; font-weight: bold;">false</span>);
</code></pre>
</div>
<br />
Now we'll need to handle those events as well, here is where the real fun begins! Let's have a look a the «touchstart» handler first.<br />
<div class="highlight">
<pre><code><span style="color: green; font-weight: bold;">function</span> touchstartHandler(event)
{
ctx.moveTo(event.touches[<span style="color: #666666;">0</span>].pageX<span style="color: #666666;">,</span> event.touches[<span style="color: #666666;">0</span>].pageY);
}
</code></pre>
</div>
It's just one line, but do take notice in the «touches» object contained within the event. This is an array (well, kind of) of touches. The reason for this is that most humans have more than one finger, so the «touches» object could actually contain several values. We only need one, so we refer to the first (0) element in the «touches» object. Now that we have found the first finger we get it's location on the screen by asking for the «pageX/Y» values. We then continue to move the canvas context pointer to the coordinates for this finger using the «moveTo» method. This happens every time we place a finger on the screen. But, only for the first finger.<br />
<div class="highlight">
<pre><code><span style="color: green; font-weight: bold;">function</span> touchmoveHandler(event)
{
ctx.lineTo(event.touches[<span style="color: #666666;">0</span>].pageX<span style="color: #666666;">,</span> event.touches[<span style="color: #666666;">0</span>].pageY);
ctx.stroke();
}
</code></pre>
</div>
In the «thouchmove» handler we do the actual work of telling the canvas context to draw a line from where it's last location was to where the finger is now. The first time this is called the line is drawn from where we placed the finger on to the screen, set in the «touchstart» handler. After that, the canvas context will update it's starting position to the location of the last drawing operation. Like the «moveTo» command in «touchstart» the «lineTo» will update the coordinate position, but it will also issue a drawing command which is rendered to the screen when we call the «stroke» method.<br />
<br />
That's it. Try it out on your iPad, iPhone or any other touch device which understands the new HTML 5 APIs by clicking this <a href="http://web.kinderas.com/demos/touch_draw_simple/">magical link</a>.<br />
<br />
Recommended further reading:<br />
<br />
<ul>
<li><a href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/HandlingEvents/HandlingEvents.html">Safari web-content guide - Handling events</a></li>
</ul>
Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com8tag:blogger.com,1999:blog-7239447129918882627.post-60868402172002589852011-03-16T18:46:00.003+01:002011-03-17T13:37:57.277+01:00Quicktip: Flipping an image with JavaScript<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVaiV5BemsMA6dNn5ZqC0_OJnzc1QuBtU-CNtziensrj2lrQ5Q7VdWBV0rZNeW1RfFhMSmDy_nuzDUlCPZpe2S0vqqyTNgPy4kGqIs3-p2VnMDfgsNb6DAkiQPkX1Spi2zcwZH5jHYrbs/s1600/flipped.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVaiV5BemsMA6dNn5ZqC0_OJnzc1QuBtU-CNtziensrj2lrQ5Q7VdWBV0rZNeW1RfFhMSmDy_nuzDUlCPZpe2S0vqqyTNgPy4kGqIs3-p2VnMDfgsNb6DAkiQPkX1Spi2zcwZH5jHYrbs/s1600/flipped.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div>Let's say you wanted to flip an image in you web-app horizontally or vertically. By using a tiny bit of JavaScript and CSS 3 this is really easy.<br />
<br />
<code><span style="color: #408080; font-style: italic;">//Get the image</span><br />
<span style="color: green; font-weight: bold;">var</span> img <span style="color: #666666;">=</span> <span style="color: green;">document</span>.getElementById(<span style="color: #ba2121;">'myimage'</span>);<br />
<span style="color: #408080; font-style: italic;">//Flip it horizontally</span><br />
img.style.webkitTransform <span style="color: #666666;">=</span> <span style="color: #ba2121;">'scaleX(-1)'</span><span style="color: #666666;">;</span><br />
</code><br />
<br />
And you're done! Note that this will only work in webkit browsers. The equivalent for Mozilla browsers would be «img.style.MozTransform». To flip the image vertically you could use: «scaleY(-1)». And to flip both horizontally and vertically at the same time: «scale(-1,-1)».<br />
<br />
<i>[edit 17.03.2011]</i><br />
You can of course do this in other browsers besides Gecko or WebKit based browsers, as pointed out in the comments. Safari will actually support both the «webkit» and the «Moz» prefix, but this will most likely go away soon. So what you'll need to use is feature detection. This will still not work in ALL browsers, but the usable ones will most likely support it.<br />
<code><div class="highlight"><pre><span style="color: #008000; font-weight: bold">if</span>(img.style.webkitTransform){
img.style.webkitTransform <span style="color: #666666">=</span> <span style="color: #BA2121">'scaleX(-1)'</span><span style="color: #666666">;</span>
}<span style="color: #008000; font-weight: bold">else</span> <span style="color: #008000; font-weight: bold">if</span>(img.style.MozTransform){
img.style.MozTransform <span style="color: #666666">=</span> <span style="color: #BA2121">'scaleX(-1)'</span><span style="color: #666666">;</span>
}<span style="color: #008000; font-weight: bold">else</span> <span style="color: #008000; font-weight: bold">if</span>(img.style.OTransform){
img.style.OTransform <span style="color: #666666">=</span> <span style="color: #BA2121">'scaleX(-1)'</span><span style="color: #666666">;</span>
}<span style="color: #008000; font-weight: bold">else</span> <span style="color: #008000; font-weight: bold">if</span>(img.style.msTransform){
img.style.msTransform <span style="color: #666666">=</span> <span style="color: #BA2121">'scaleX(-1)'</span><span style="color: #666666">;</span>
}<span style="color: #008000; font-weight: bold">else</span>{
img.style.transform <span style="color: #666666">=</span> <span style="color: #BA2121">'scaleX(-1)'</span><span style="color: #666666">;</span>
}
</pre></div></code>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com2tag:blogger.com,1999:blog-7239447129918882627.post-78391060936431762442011-02-28T22:21:00.000+01:002011-02-28T22:21:09.784+01:00HTML 5 Offline data storage<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqS7eEcNd2s-mzICYBGkgLMmoVVZtpktQYtZ3vGgFSw65BkUFVrezIyYh10E2g5U4dgv-mCPt-8JTz1xfbM_R06AxoVoOfa14Q6GvT3WHqX2COE2Q7RAC7yZegIx95VJu9IoTWBnExG90/s1600/data2.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqS7eEcNd2s-mzICYBGkgLMmoVVZtpktQYtZ3vGgFSw65BkUFVrezIyYh10E2g5U4dgv-mCPt-8JTz1xfbM_R06AxoVoOfa14Q6GvT3WHqX2COE2Q7RAC7yZegIx95VJu9IoTWBnExG90/s200/data2.jpeg" width="200" /></a></div>One of the most anticipated features of HTML 5 and all it's consequential technologies and APIs are the «offline storage» APIs. In this post I'll take a "real world" approach to using the <a href="http://www.w3.org/TR/webdatabase/">HTML 5 Web-Database</a> and the «<a href="http://www.w3.org/TR/offline-webapps/">HTML 5 Offline application cache</a>». I will take you through an example where a complete elephant gets stored on your computer. That's right! A pink one as well! The point of this demo is to investigate how to store both static data as well as dynamic data which might not be known at design time. For this occasion I have created a <a href="http://web.kinderas.com/demos/dynamic_offline/">demo</a> which you are free to download and inspect. It is fully commented and somewhat verbose for easier reading. What this application does in essence is to store a HTML and a <a href="http://web.kinderas.com/demos/dynamic_offline/main.js">JavaScript file</a> on your computer, then it will go on to store a picture (which could be dynamic data) in a local database, hence making the application usable when not online. Let's have a look!<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4iIOymMbT9GL4-wY4yyUS2X1rTTJ9NTyKOKk77X336rtQlXnzsi6YlEcVdMzPVv9Pp3RlEcHllH9l2Drmvmu4F8Vq53lNo_w1noyft7OodwiUHFc73jrUR7WDonxI1xMeUeOUTKWAet4/s1600/self-storage-closet.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4iIOymMbT9GL4-wY4yyUS2X1rTTJ9NTyKOKk77X336rtQlXnzsi6YlEcVdMzPVv9Pp3RlEcHllH9l2Drmvmu4F8Vq53lNo_w1noyft7OodwiUHFc73jrUR7WDonxI1xMeUeOUTKWAet4/s1600/self-storage-closet.png" /></a></div>So, our goal is to store both static data and some dynamic data. To achieve this we'll need to use two approaches as mentioned above. The first one, called «HTML 5 Offline Application Storage» is almost automatic once you have it configured. We will utilize this method to store our main JavaScript file so that it will work when you're not online. Cool!<br />
This approach uses a simple text file, called a «manifest file» which tells the browser which data to store locally. In order for this file to be interpreted by the browser correctly you'll need to (1) configure your web-server to serve this file with the «text/cache-manifest» mime-type. It doesn't matter what kind of extension you use, but I prefer either «.manifest» or «.cache». Now that thats out of the way we need to create the «manifest file». Mine looks something like this.<br />
<code><br />
CACHE MANIFEST<br />
# Cache manifest version 1.0.5<br />
# If you change the version number in this comment,<br />
# the cache manifest is no longer byte-for-byte<br />
# identical.<br />
<br />
main.js<br />
<br />
NETWORK:<br />
# All URLs that start with the following lines<br />
# are whitelisted.<br />
<br />
http://web.kinderas.com/<br />
</code><br />
The first line MUST be the text «CACHE MANIFEST». After that you'll go on to specify the files you'll like to be cached. Here you'll put stuff like JavaScript files, HTML pages, CSS files and so on. Mine only has the one «main.js». Note that you do NOT need to specify the HTML file which declares the manifest file. This will typically be your «index.html» file or something like that. More on that later. The next section is the «NETWORK:» section. In this section you specify a "white list" containing URL's from where your application is allowed to get it's data. If you don't specify this your app will not download any data, not from the server it's hosted on or from anywhere else. I have specified my own domain since this is where the elephant is hosted.<br />
You declare the manifest file in your HTML file like so:<br />
<code><html manifest="cache.manifest"></code><br />
That is it for the manifest file actually. If you are simply going to host a static site, a game or something like that, this will work just file as is. Note that to update your files, you do need to make a change in the manifest file itself, like incrementing the version number.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAscHY-ZUNqMtKxoPZ5RsGAwGR9zwzWT3Wck-HUA4MZwy0fV-DQX9gvvtV5OzeEAO9yD0p8GymuXjniU5QAaf9qYfKgTwbY-kJOwwHHs5XXD75SKkqoPfBKibox0skIVkgE1tUTOLeL50/s1600/js.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAscHY-ZUNqMtKxoPZ5RsGAwGR9zwzWT3Wck-HUA4MZwy0fV-DQX9gvvtV5OzeEAO9yD0p8GymuXjniU5QAaf9qYfKgTwbY-kJOwwHHs5XXD75SKkqoPfBKibox0skIVkgE1tUTOLeL50/s1600/js.jpg" /></a></div>Next we need to add some <a href="http://web.kinderas.com/demos/dynamic_offline/main.js">sexy JavaScript</a> in order to make the pink elephant available for your viewing pleasure in locations the WiFi gods have forsaken. There are three main steps to this: (1) Opening and creating the database and the table if it's not already present. (2) Reading the image from the database or saving it to the database if it's not already in there. (3) Displaying the image. I will not be explaining every line of the code in this post, you'd rather <a href="http://web.kinderas.com/demos/dynamic_offline/main.js">take a look at the JavaScript file</a> and read the comments. However I will discuss some of the more important points briefly.<br />
Not all browsers will support the HTML 5 database APIs, so we need to check for this before we can do anything. To do this we check for the existence of the «openDatabase» method on the «window» object, like so:<br />
<code><br />
if(!window.openDatabase){<br />
// No support for HTML 5 db<br />
return;<br />
}<br />
</code><br />
This will detect if the browser has support for the methods we need. If not, give the user a message or some alternative content.<br />
Then, to open / create the database we would we simply write:<br />
<code>db = openDatabase('testdb','1.0','Offline Elephant DB',1024*1024);</code><br />
We have just created a 1MB database or opened one if it already existed. Now it's ready to execute SQL queries using transactions.<br />
<br />
<div class="highlight"><pre><code><span style="color: green; font-weight: bold;">var</span> sql <span style="color: #666666;">=</span> <span style="color: #ba2121;">'CREATE TABLE IF NOT EXISTS offline_image (id INTEGER ....);'</span><span style="color: #666666;">;</span>
db.transaction(
<span style="color: green; font-weight: bold;">function</span>(transaction){
transaction.executeSql(sql<span style="color: #666666;">,</span>[]<span style="color: #666666;">,</span>
<span style="color: green; font-weight: bold;">function</span>(transaction<span style="color: #666666;">,</span> result){
<span style="color: #408080; font-style: italic;">//The table was created</span>
}<span style="color: #666666;">,</span>
errorHandler);
}
);
</code></pre></div><br />
The database table has now been created if it wasn't already there. We now need to check if there is an image already saved in the database, this happens on line 56 in the «readImage()» function. If there is an image with the matching filename saved, we use that, if not we go on to loading and serializing the image, as follows.<br />
<br />
<div class="highlight"><pre><code><span style="color: green; font-weight: bold;">var</span> canvas <span style="color: #666666;">=</span> <span style="color: green;">document</span>.createElement(<span style="color: #ba2121;">'canvas'</span>);
<span style="color: green; font-weight: bold;">var</span> ctx <span style="color: #666666;">=</span> canvas.getContext(<span style="color: #ba2121;">'2d'</span>);
<span style="color: green; font-weight: bold;">var</span> img <span style="color: #666666;">=</span> <span style="color: green;">document</span>.createElement(<span style="color: #ba2121;">'img'</span>);
img.onload <span style="color: #666666;">=</span> <span style="color: green; font-weight: bold;">function</span>(){
canvas.width <span style="color: #666666;">=</span> img.width<span style="color: #666666;">;</span>
canvas.height <span style="color: #666666;">=</span> img.height<span style="color: #666666;">;</span>
ctx.drawImage(img<span style="color: #666666;">,0,0,</span>img.width<span style="color: #666666;">,</span>img.height);
<span style="color: green; font-weight: bold;">var</span> base64Image <span style="color: #666666;">=</span> canvas.toDataURL();
showImage(base64Image);
}
img.src <span style="color: #666666;">=</span> sImgURL<span style="color: #666666;">;</span>
</code></pre></div><br />
To be able to save the image we need to create a text version of it's data. We can accomplish this by loading the image and then rendering it in a <a href="http://www.w3.org/TR/html5/the-canvas-element.html">canvas element</a>. The Canvas element has a method called «<a href="http://www.w3.org/TR/html5/the-canvas-element.html#dom-canvas-todataurl">toDataURL</a>» which will create a <a href="http://en.wikipedia.org/wiki/Data_URI_scheme">base64 representation</a> of the Canvas content. Base64 images, also referred to as data urls can easily be saved to the database. Base64 data can also be read directly by the «img» element, so there is no need to decode the base64 string again once it's encoded. But, do note that the canvas element will give you the png base64 version of the image, and it's quite a bit larger than the original binary file.<br />
<br />
That's the gist of it, but you do need to take a look at the <a href="http://web.kinderas.com/demos/dynamic_offline/">demo</a> and the <a href="http://web.kinderas.com/demos/dynamic_offline/main.js">JavaScript</a> in order to really understand what it going on here. Once you get the hang of it, this is a really powerful approach to making web-applications much more accessible and more interesting.<br />
<br />
Further reading:<br />
<br />
<ul><li><a href="http://web.kinderas.com/demos/dynamic_offline/">The Dynamic Offline Demo application- with pink elephant</a></li>
<li><a href="http://developer.apple.com/library/safari/#documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007256-CH1-SW1">Safari Client-Side Storage and Offline Applications Programming Guide</a></li>
<li><a href="http://www.w3.org/TR/html5/the-canvas-element.html">The Canvas Element - W3C</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com3tag:blogger.com,1999:blog-7239447129918882627.post-13479404942604097752011-02-09T22:37:00.004+01:002011-02-14T09:23:32.703+01:009 things I've learned about web-development<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3dptIW4PvWeo2mLhlFdmmznQQFhmJ73tXb0uCokund_u6I9cyp8GorOVk9kxvX0LUoKhJ_XUNxPjX7yNija_ufJLDqjWqzA-DObD4hKFOg8b3v1SQqK9yp34d6-aYw8d7b-B2IqvEce8/s1600/puzzle-cufflinks.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3dptIW4PvWeo2mLhlFdmmznQQFhmJ73tXb0uCokund_u6I9cyp8GorOVk9kxvX0LUoKhJ_XUNxPjX7yNija_ufJLDqjWqzA-DObD4hKFOg8b3v1SQqK9yp34d6-aYw8d7b-B2IqvEce8/s200/puzzle-cufflinks.jpg" width="200" /></a></div>I've been a developer for quite some time now, meddling with both the web-centric and the native side of things. As of lately, that is for the last 3 months or so I have focused more in depth on "standards" based web development. Meaning HTML, CSS and JavaScript. Even if I've been writing HTML since 1996 (yeah, I'm getting old), I have never really bothered to really focus in depth on the basic building blocks of HTML, CSS and JavaScript, until now. 4 books and many many hours of training videos later I feel that I've learned something, which is that an iPad make for a lousy pillow if you keep trying to sleep on it! But more than that, I found 9 things that I have learned, which may be blatantly obvious to you if you are a fancy pantsy web-developer, but then again, maybe you'll learn something new?<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguoSHXkn4fYzQkywwwwkq3F74k-2AFWuMnabi2K37Mdki2H4NVort0N09NzzqmpbmDyAF4YSErKD0yqNfQS67tfkJi7WVgEzQSRGDIf4SnBKBI087rZmKpx48l3wRsrDbD2BQLyVEO-J4/s1600/webdesign.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguoSHXkn4fYzQkywwwwkq3F74k-2AFWuMnabi2K37Mdki2H4NVort0N09NzzqmpbmDyAF4YSErKD0yqNfQS67tfkJi7WVgEzQSRGDIf4SnBKBI087rZmKpx48l3wRsrDbD2BQLyVEO-J4/s1600/webdesign.jpg" /></a></div><b>1. Web-designers and web-developers think differently.</b><br />
What do I mean by that? Consider of how you're tagging your HTML with classes and id's. The designer approach to this would be classes all the way, then using the clever selector syntax of CSS to reach the nested areas of the document. This makes sense when working with formatting. Developers tend to view the HTML as a framework with components. Classes are used for formatting while id's are used to identify areas of the markup one would need to reach via JavaScript. Designers will prioritize the "flow" of the «document» whilst developers don't consider it a document at all. I don't think either approach is «correct» or «wrong», it's just two ways of approaching the same challenge.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI1ZEXMNjVtvOA75vFVmotArYt7onIJCGCpacayT_asffR9jqHUUKw0aNRiCMbYJoDLKam3RqDiESSnw53VKV-MGQbG6m2sRKZ7DztlflbbeHINc3Rz3J8mJ_kFjxd4TK92B2tEQDvcGA/s1600/CSSEditLogo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjI1ZEXMNjVtvOA75vFVmotArYt7onIJCGCpacayT_asffR9jqHUUKw0aNRiCMbYJoDLKam3RqDiESSnw53VKV-MGQbG6m2sRKZ7DztlflbbeHINc3Rz3J8mJ_kFjxd4TK92B2tEQDvcGA/s1600/CSSEditLogo.png" /></a></div><b>2. CSS is not a layout language.</b><br />
Almost all layout in modern HTML based webpages are done using <a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a>, so how can anybody claim that it's <a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets#Limitations">not a layout language</a>? I too was somewhat surprised when time and time again the "people who knew what they are talking about" kept repeating this. From the <a href="http://www.whatwg.org/">WHATWG</a> to <a href="http://www.w3.org/">W3C</a> and several books on the topic kept driving this home..«not a layout language». Turns out, CSS is a formatting language with some layout features. Semantics? Well, not really. If you compare CSS 2.1 to a "real" layout language like <a href="http://en.wikipedia.org/wiki/MXML">MXML</a> you'll soon notice a big difference. Layout languages, or UI markup languages have special layout components to group element, flow elements, sort elements both horizontally and vertically. CSS 2.1 does not have this, it's totally reliant on either floats or absolute positioning. This will better with the introduction of the f<a href="http://www.w3.org/TR/css3-flexbox/">lexible box model</a> in CSS3, but still it will remain a formatting language at heart.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi88JICt7SeddRpVpIeU11E5pXmbOOXCQ2FW9FVgpsNGZl_-MXMlCGZsz5dcxpCyrFcwP2pIMzDKvT61bammNy0clKEFElIwzYt4QHSbYZ5Uo0LOfDex38WsUSvMA0AHDBCBXgpIziB6K0/s1600/Awesome%255B1%255D.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi88JICt7SeddRpVpIeU11E5pXmbOOXCQ2FW9FVgpsNGZl_-MXMlCGZsz5dcxpCyrFcwP2pIMzDKvT61bammNy0clKEFElIwzYt4QHSbYZ5Uo0LOfDex38WsUSvMA0AHDBCBXgpIziB6K0/s1600/Awesome%255B1%255D.jpg" /></a></div><b>3. CSS selectors are incredible powerful...stuff</b><br />
This is one of the areas on which I have discovered most new stuff. CSS 2.1 embodies most of them, but with the introduction of the <a href="http://www.w3.org/TR/css3-selectors/">CSS 3 standard</a>, selectors can now do some amazing stuff. Conditional child selection, substrings within attributes while traversing child elements are just some examples. And the best part is that they are <a href="http://caniuse.com/">largely supported</a> in all modern browsers, including Internet Explorer 8. If I where to recommend one area on with to focus you attention, if you don't already know this, it would be CSS selectors. It's not complicated or hard to understand, there are just so much under the hood which can make your CSS writing a lot more enjoyable.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja9c-TBbfJkNODNzHL4eXgTFCZa3zPNYPy726zVzCE9dP9p9AbwVp5VATnZXLBlu288j9EEJ3ReLqJylQUU_TSrlUx5pAumjnhtkAbykALruP5pDIFk-aS367g7LOyxixZRltvyFPK-_c/s1600/computer_frustration1.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja9c-TBbfJkNODNzHL4eXgTFCZa3zPNYPy726zVzCE9dP9p9AbwVp5VATnZXLBlu288j9EEJ3ReLqJylQUU_TSrlUx5pAumjnhtkAbykALruP5pDIFk-aS367g7LOyxixZRltvyFPK-_c/s1600/computer_frustration1.jpg" /></a></div><b>4. Things will look different in different places.</b><br />
If you try to create pixel perfect designs across all browsers and platforms you will go bonkers, that is unless you are a technophile machochist whom derives enjoyment from banging your head up against the gigantic wall of Internet Explorer inconsistency. You're much better off using either the <a href="http://kinderas.blogspot.com/2011/01/graceful-degradation-vs-progressive.html">progressive enhancement or the graceful degradation</a> approach where you serve different users the same content, only wrapped in a slightly different presentation. This way Internet Explorer users can sit and stare at that black and white page of rich text all day long, while us WebKit fanboys can swim in the loveliness that is a modern browser with animations and shit.<br />
<br />
<b>5. A position is not the same position elsewhere, or everywhere</b>.<br />
Since this is more or less an extension of point 4, I can't be bothered to find a pretty picture for this one. (<i><span class="Apple-style-span" style="font-size: x-small;">As a side note, if you use Google image search for the term "position", turn safe search on!</span></i>) What this point is concerning, what I've found is: Firefox and Chrome (or any other browsers) does not have the same interpretation when it comes to rendering a point at, say x: 100, y: 100. Since it's up to the user agent (browser) to parse your CSS and HTML and then draw it on the screen, you will at certain points end up in a situation where an absolute point in the top left coordinate system will differ from user agent to user agent and even on the same user agent on different operating systems. This can be avoided by using floats and containers instead of using absolute positioning. But, it's better to accept that things might not look exactly the same everywhere.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE4NiSJDKb3gEfV5KIGbzoiqXGhhcNW9ZkXVe1e7vYy6qiUvW5ED3kijgtN_zM9LkshBN9tpMG8JDtQiEAZlBC5-C0fArTDstIF-yolOlxioyFE4Ak7YeXuex9oWUg2CZLI9QT9wI8ieY/s1600/modernizer_50817324.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE4NiSJDKb3gEfV5KIGbzoiqXGhhcNW9ZkXVe1e7vYy6qiUvW5ED3kijgtN_zM9LkshBN9tpMG8JDtQiEAZlBC5-C0fArTDstIF-yolOlxioyFE4Ak7YeXuex9oWUg2CZLI9QT9wI8ieY/s1600/modernizer_50817324.png" /></a></div><b>6. Modernizer Rocks!</b><br />
If you ever need to use conditional CSS 3 or HTML 5, <a href="http://www.modernizr.com/">Modernizer</a> is by far the best solution I've found. The way Modernizer works is actually twofold. You can first use it with CSS directly. Lets say you want to take advantage of the RGBA color model found in CSS 3, but you also need to support those pesky Internet Explorer users. All you need to do in your stylesheet is to prefix your class or id selector with ".rgba". Let's say I wanted to apply a style via the selector «h2[class*="onkey"]», but only for browsers supporting RGBA. It would look like this: «.rgba h2[class*="onkey"]». The RGBA class simply adds itself as a ascendant class. This style would then only apply if RGBA was supported. The other way of using Modernizer is with JavaScript. To check for support for H.264 video playback abilities, simply use «Modernizer.video.h264» and it'll return false, "maybe" or "probably". Yep, that is the HTML 5 spec for video format detection..<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnvtfeZc-B5wxkEWKB0l0JWLQX27dqKOZ6bYh8jiCAPeIq3oBY0vF5AVFQ-Q0lEZ1NEnuvo4avrEme1t9NBVk6jGDswPEm8qvDgpmmDEZS5Iac_raE_wPPsFhCY6lizWhjoCDX8uJCdzg/s1600/jquery-logo1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnvtfeZc-B5wxkEWKB0l0JWLQX27dqKOZ6bYh8jiCAPeIq3oBY0vF5AVFQ-Q0lEZ1NEnuvo4avrEme1t9NBVk6jGDswPEm8qvDgpmmDEZS5Iac_raE_wPPsFhCY6lizWhjoCDX8uJCdzg/s1600/jquery-logo1.png" /></a></div><b>7. jQuery selectors are convenient, JavaScript is fast!</b><br />
If you don't know what <a href="http://jquery.com/">jQuery</a> is, you should go find out! Someone once wrote that <a href="http://jquery.com/">jQuery</a> is Gods gift to JavaScript. Where God is of course <a href="http://ejohn.org/">John Resig</a> and I was the one that wrote that, just now in fact. jQuery is seriously awesome, it allows for fast and easy cross browser development. Underscoring <u>cross browser</u>, which is what it does really really well. It is just a JavaScript framework, a tiny one at that, but crammed with neat functionality, from animations, ajax loading and the usage of CSS selectors to get a hold of <a href="http://en.wikipedia.org/wiki/Document_Object_Model">DOM</a> elements. You can say things like: «jQuery('div.donkey')» which would give you all the donkey divs in the page. This is really convenient, because you can find stuff in the DOM with the same syntax used in the CSS. There is a downside however. When using CSS selectors in a CSS file or in the HTML file, the user agent takes care of all the heavy lifting required to traverse the DOM and find those elements. This is fast because the user agent does this natively using a compiled language such as C. However, jQuery is not written into the native part of the browser and will therefore need to use JavaScript to traverse the DOM to find the elements based on the CSS selector. Hence using the build in JavaScript functions «getElementById», «getElementsByTagName» or the spanking new «<a href="https://developer.mozilla.org/En/DOM/Document.getElementsByClassName">getElementsByClassName</a>» is much faster than using the jQuery selectors. What you can do is combine them like so «jQuery(getElementById('id-name'))». Then you would get the speed of the native JavaScript functions while keeping all the jQuery goodness as well.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFdjmIbWWRB2o5en7_hGCdu3mzYU5eICOM8CZczGW-15O2cBl-6tH73pYQ6BMVCde5-QgQbUY1cwYPryuuQrcFflHSjKd3gunkgH8_nc0K-VJRHIXBRW8Y6NvOwp2zycMyn3yJmKMSpRg/s1600/ConvertDatatype-48.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFdjmIbWWRB2o5en7_hGCdu3mzYU5eICOM8CZczGW-15O2cBl-6tH73pYQ6BMVCde5-QgQbUY1cwYPryuuQrcFflHSjKd3gunkgH8_nc0K-VJRHIXBRW8Y6NvOwp2zycMyn3yJmKMSpRg/s1600/ConvertDatatype-48.png" /></a></div><b>8. There are datatypes in JavaScript!</b><br />
!!Nerd alert!! Even if you don't explicitly declare datatypes in JS, there is a difference between for example «"2"» and «2». If you where to add these two values together «"2" + 2», you'd get «"22"», while «2 + 2» returns «4». Now, what if «a = [2,3,"a"]» and «b = 2». What would «a + b» give you? That's right «a + b => "2,3,a2"». JS has a lot of functions for dealing with this. You have «toString()» to convert a number to a string, «parseInt(strNum)» to convert a string into a whole number and so on. The important thing is to be astutely aware of it, even if you can't declare a strict datatype.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoWOKn6aTmSD09u9QgWzKYdlMEOqWxirVXnGpKg1ldfIfghugtJxsOAw9NbA7hPhSN0NLztaCULC7LfjkPs4x3J4Y76D9mhyphenhyphenpEohpkL3GRmYlxrotZbndSYO6VyNbwslzf92IRXs0uniY/s1600/171944-webkit_logo180_original.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoWOKn6aTmSD09u9QgWzKYdlMEOqWxirVXnGpKg1ldfIfghugtJxsOAw9NbA7hPhSN0NLztaCULC7LfjkPs4x3J4Y76D9mhyphenhyphenpEohpkL3GRmYlxrotZbndSYO6VyNbwslzf92IRXs0uniY/s1600/171944-webkit_logo180_original.png" /></a></div><b>9. The WebKit Web Inspector is your most important tool</b><br />
If you're in any WebKit browser, Safari, Chrome so on you have access to the build in "<a href="http://trac.webkit.org/wiki/WebInspector">Web Inspector</a>". This tool is your best friend when working with HTML, CSS and JavaScript. It will do anything the more famous <a href="http://getfirebug.com/">Firebug</a> does and more. Don't get me wrong, I'm not railing on Firebug which is an awesome tool, I am however highly recommending the WebKit Web Inspector because of it's speed, advanced profiling tools and unsurpassed JavaScript debugger. Try it and you'll see why I'm praising it!<br />
<br />
So that's it, or more likely, that's some of it. If you have actually read all the text down to this I truly hope that this post have contributed in some small way to your blah blah blah blah..you know the drill. Now get back to work, those recursive functions won't be creating themselves ;-)Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-34101365028452748942011-01-18T23:15:00.000+01:002011-01-18T23:15:00.166+01:00The truth about Google and H.264<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div> If you leave this post remembering only one thing, let it be this: <i>Making something Open Source does not automatically make it better, it just makes it Open Source.</i> How's that for flamebait?<br />
<br />
Unless you have been living in a box buried underground lately, you have probably noticed the shitstorm surrounding <a href="http://blog.chromium.org/2011/01/html-video-codec-support-in-chrome.html">Googles decision</a> to drop support for the <a href="http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC">H.264 codec</a> in it's Chrome web-browser. Of course, as a web-developer I do indeed have some thoughts on why this happened and whether it's a smart move. However, before sharing from my goldmine of biased opinion we'll need to get the REAL facts straight, so you can judge for yourself.<br />
<br />
<b>Open vs. Free</b><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNyAHcfnBlzhSvrfaAVZ7LuY-IwRKLN6R-tjuQgJ34tNMxsCfOr7gUi22kzr8cAnZzACFx6FL0voX477f7K9zd5GxcCOEbE3L1ReRvEiZ5fhhFp7btyxe1GGyWYdeMrrIb77zpBSIyfkk/s1600/h264-1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNyAHcfnBlzhSvrfaAVZ7LuY-IwRKLN6R-tjuQgJ34tNMxsCfOr7gUi22kzr8cAnZzACFx6FL0voX477f7K9zd5GxcCOEbE3L1ReRvEiZ5fhhFp7btyxe1GGyWYdeMrrIb77zpBSIyfkk/s1600/h264-1.png" /></a></div>H.264 is a codec constructed from a bunch of patented technologies and it's developed by the «<a href="http://en.wikipedia.org/wiki/Video_Coding_Experts_Group">Video Coding Experts Group</a>» and the «<a href="http://en.wikipedia.org/wiki/Moving_Picture_Experts_Group">MPEG Group</a>». H.264 is a video standard (ISO/IEC 14496-10) handled by the «<a href="http://en.wikipedia.org/wiki/International_Organization_for_Standardization">International Organization for Standardization</a>». H.264 is an open standard, however it is not a free standard. All the patents included in H.264 are handled by <a href="http://en.wikipedia.org/wiki/MPEG-LA">MPEG-LA</a>, not to be confused with the MPEG Group. Microsoft and Apple are some of the minor patent holders of H.264. H.264 is free to use for non-commercial usage, for end users for it's lifetime. For commercial usage (e.g. iTunes Store) and for usage in decoders (e.g. in browsers) one will have to pay a <a href="http://www.zdnet.com/blog/bott/a-closer-look-at-the-costs-and-fine-print-of-h264-licenses/2884">license fee</a> capped at $6.5M. H.264 sports a bunch of hardware decoders, from iOS devices to Televisions and DVD/BlueRay players. To create H.264 files you can use everything from <a href="http://www.apple.com/quicktime/download/">Apple QuickTime</a> to <a href="http://ffmpeg.org/">FFMPEG</a>. H.264 is supported by Apple Safari, Internet Explorer 9 and Google Chrome via the Mpeg4 container.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCLbYoEmsE1t394hswqR9HM38tspYm-w2BWnDnz08eZ_yy7e1muUSYnPQelA2hjS8l50Ra_qbyG9psGMGlc1GU2oMTDBYjbJOTTfZG0ZWtIT-YimPdjz-pFnDEuGVR0avCz86YRiPJqIE/s1600/webm.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCLbYoEmsE1t394hswqR9HM38tspYm-w2BWnDnz08eZ_yy7e1muUSYnPQelA2hjS8l50Ra_qbyG9psGMGlc1GU2oMTDBYjbJOTTfZG0ZWtIT-YimPdjz-pFnDEuGVR0avCz86YRiPJqIE/s1600/webm.png" /></a></div><a href="http://en.wikipedia.org/wiki/VP8">VP8</a>, the codec within the <a href="http://en.wikipedia.org/wiki/Webm">WebM</a> container, was developed as a proprietary product by a company called <a href="http://en.wikipedia.org/wiki/On2_Technologies">On2 Technologies</a>. In 2010 On2 Technologies was acquired by Google, whom continued to release the patents within VP8 under a <a href="http://en.wikipedia.org/wiki/Creative_Commons_licenses">Creative Commons License</a>. VP8 is free to use and free to implement. As of today there are slim to none hardware support for VP8 decoding. To decode/encode VP8 today you'll most likely use Google own software based «<a href="http://www.webmproject.org/code/">libvpx</a>» library or the FFMPEG(<a href="http://x264dev.multimedia.cx/archives/499">ffvp8</a>) implementation. VP8 is today supported by Opera and Firefox 4 via the WebM container.<br />
<br />
<span class="Apple-style-span" style="font-family: sans-serif; font-size: 13px; line-height: 19px;"><span class="Apple-style-span" style="font-family: Times;"><span class="Apple-style-span" style="font-size: small; line-height: normal;"></span></span></span>The thing to notice here is that H.264 is indeed an open standard, developed by an independent companies and approved as a standard by ISO, but it's not free to implement. VP8 was developed as a proprietary product by one company, later released into the public domain as Open Source. VP8 is free to implement.<br />
<div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZainG53CdYWPE0w33Eeq1ivjVoSo-tc_9Ib_La4mYUa2JZIK37nWDtAtLlMZirXD_YzBN8h6lpFeRX7ne__bISj8eH0nh70JEMNL_QVsrJGtvLkhn5j21YjkKbIROuM7274Qsq_r_Kaw/s1600/571.ExclamationMark.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZainG53CdYWPE0w33Eeq1ivjVoSo-tc_9Ib_La4mYUa2JZIK37nWDtAtLlMZirXD_YzBN8h6lpFeRX7ne__bISj8eH0nh70JEMNL_QVsrJGtvLkhn5j21YjkKbIROuM7274Qsq_r_Kaw/s200/571.ExclamationMark.jpg" width="200" /></a></div><b>What does it all mean?</b><br />
In my opinion Googles move has nothing to do with being open, it might have something to do with being free however. For companies like Mozilla, which develops a truly Open Source product it totally makes sense to not implement a video codec for which you have to pay patent royalties. Note that <a href="https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements">Mozilla does not support MP3</a> either, which also contains commercial patents. It's not that Mozilla can't pay the license fees, it is more the fact that you cannot freely distribute as Open Source a product which implements a patent encumbered video decoder. Mozilla (Firefox) has never had support for H.264, which is a decision I completely support on the basis of their completely open approach in other areas of the implementation as well.<br />
Google on the other hand made the rather strange decision to remove it's already existing support for a widely used codec in a browser littered with other patented technologies. Under the flag of being "open". It's this "being open" part which rubs me the wrong way. Google Chrome is NOT an open browser in the same sense as Firefox is, it implements mp3 and it's own embedded FlashPlayer to mention a few things. As far as I can see, the only logical explanation for Googles move is that this is a business decision. They don't want to pay for a license partly under the control of Apple and Microsoft and would rather control their own codec, namely VP8, which is under Googles control, even if it's Open Source. VP8 has never been through any independent standards organization like H.264 has, it was developed as a proprietary product, in sharp contrast to the independent development of H.264 which was a joint operation shared by many companies. Codec developers also<a href="http://x264dev.multimedia.cx/archives/377"> claim the superiority in quality of H.264 over VP8</a>. It's estimated that about 60-70% of all web video is encoded in H.264 already, a large part of that is YouTube owned by Google. The reason you can watch video for hours on your Android. Microsoft or iOS device is the H.264 hardware encoder which sits inside of it. Despite all of this Google chooses to exclude H.264 from it's web-browser.. to be open.. yea right!</div>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-13656231715232426332011-01-09T18:38:00.000+01:002011-01-09T18:38:42.678+01:00Graceful degradation vs. Progressive enhancement<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSVOHuOapDB7wIod_cwE04FlRJtKfLuuUfqXsaYi-8J3d0ykqh5ZfLQlpU756PeH7hOE0OB96zB2-CAfj2agjp3CF21LPZWBH8AlXRyXdFo9NxASyNREbr2t0j1obGeAqb56AKMMtygfQ/s1600/confused-man.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSVOHuOapDB7wIod_cwE04FlRJtKfLuuUfqXsaYi-8J3d0ykqh5ZfLQlpU756PeH7hOE0OB96zB2-CAfj2agjp3CF21LPZWBH8AlXRyXdFo9NxASyNREbr2t0j1obGeAqb56AKMMtygfQ/s1600/confused-man.png" /></a></div>There are three possible things you might be feeling after seeing that header. (1) No interest at all (confused?), (2) somewhat intrigued and curious (and confused?) or (3) already in the trenches ready to defend your position.<br />
<br />
First of all, I know that this is somewhat of a "controversial" area, but in the end you do not need to agree with what I have to say, it's just my point of view. But, before we get to the subjective part, let's take an objective look at what is involved when considering these two approaches to (in this case) making web-applications.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-OfeQCzy1qzh9Ckzilk0BoDJcPUb6ppP0vzRqUozLbw_HaBGk64jN9U0rORQom3ufn088u4lbMnThg-2FD_HnKyHZH3LAp0q0Xa2LyoKdiIxCse-ZSCu8n10qODNt-rHcTzimngA3mCM/s1600/graceful.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-OfeQCzy1qzh9Ckzilk0BoDJcPUb6ppP0vzRqUozLbw_HaBGk64jN9U0rORQom3ufn088u4lbMnThg-2FD_HnKyHZH3LAp0q0Xa2LyoKdiIxCse-ZSCu8n10qODNt-rHcTzimngA3mCM/s200/graceful.png" width="200" /></a></div><b><a href="http://en.wikipedia.org/wiki/Graceful_degradation">Graceful degradation</a> </b><i>(or fault-tolerant system).</i><br />
In web design, this is the basic idea that we design and write code for the most capable browsers first, then we add support for less capable browsers. An example of this is the "alt" attribute of the «img» tag. Most users will get the image, while those that browsers that do not support (or choose not to display) images gets the "degraded" text representation. The «noscript» tag is another example.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg42_cszArCBZSxj90oa6GRiP-pGsUQ6Xm5x3ZU1IKrzQjKsiZ5SxglzP2KoSS4spQ5tTjnEaFhhNn7hNgPV5H4ZtMrdfS_3P0AKMVqpptzeto10M46mg7oxmvMtJ3PppjW-QD2xiql5z0/s1600/progressive-enhancement_sh.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg42_cszArCBZSxj90oa6GRiP-pGsUQ6Xm5x3ZU1IKrzQjKsiZ5SxglzP2KoSS4spQ5tTjnEaFhhNn7hNgPV5H4ZtMrdfS_3P0AKMVqpptzeto10M46mg7oxmvMtJ3PppjW-QD2xiql5z0/s200/progressive-enhancement_sh.png" width="200" /></a></div><b><a href="http://en.wikipedia.org/wiki/Progressive_enhancement">Progressive enhancement.</a></b><br />
When subscribing to «progressive enhancement», you will first design and write code for the least capable browsers (like <a href="http://www.ie6nomore.com/">Internet Explorer</a>). Then you'll add in functionality to enhance the experience for users with more capable browsers (like Opera, Firefox, Chrome and Safari). The linked stylesheet is a much used example of this. First you create the web-app in pure HTML (works almost everywhere), then you link a stylesheet to the page (which is ignored by old browsers), making the experience better for more up to date users. The FlashPlugin based «<a href="http://www.mikeindustries.com/blog/sifr">SIFR</a>» method is also an example of «progressive enhancement». <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgorwJ1i6Bkq5CDLlj7AMAmM8T1IrxMnN2lblbf9Z1Put6jgd4qFnAXm-y44oCq_NLZ-c6iczI4utD8mRwj972fvRY10oVo5QswOGlcaFUpafZSOi7lBHdtDSIox95i3I9CdCyCNE4DroE/s1600/fact_or_opinion.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgorwJ1i6Bkq5CDLlj7AMAmM8T1IrxMnN2lblbf9Z1Put6jgd4qFnAXm-y44oCq_NLZ-c6iczI4utD8mRwj972fvRY10oVo5QswOGlcaFUpafZSOi7lBHdtDSIox95i3I9CdCyCNE4DroE/s200/fact_or_opinion.png" width="192" /></a></div><b>Aren't those two identical</b> <i>(or the subjective part)</i>?<br />
Both of these practices will lead to the same result in most cases. That is, the goal of both approaches is to give the best user experience no matter what browser might be trying to display the web-application. The difference is the starting point. Where as «progressive enhancement» assumes the lowest common denominator as a starting point, «graceful degradation» assumes the opposite, starting at the newest and adding in support for less capable browsers later.<br />
<br />
It is my opinion that the starting point of the lowest common denominator is a not such a good idea, because this line of thought will slow down the progress of new technology adaptation, especially within large enterprise environments. I don't think people in general will catch up on anything unless there is an incentive to do so. A "degraded" experience is a great incentive. Also, web-developers should in my opinion be allowed to adapt new technology as early as possible. A bunch of pig headed Internet Explorer users should not stand in the way of that. There is also the issue of security, speed and support for assistive devices. I would highly recommend the online book "<a href="http://www.20thingsilearned.com/old-vs-new-browsers/1">20 things I have learned about browsers and the Internet</a>" from the Google Chrome team, where you can read about why up to date browsers are important for the Internet itself.<br />
<br />
I know what you are thinking. "Wouldn't both approaches allow for rapid technology adaptation?". The answer is of course yes...and no. You can use «progressive enhancement» and still push the limits of technology, forcing the world forward. However, to put it bluntly, that is not the intention of this approach, it's intention is to first support the slackers, then new technology. «Graceful degradation» aims at first supporting new technology, then give the slackers the content, but with a lesser experience. There's a subtle, but important difference here.<br />
<br />
Note that «graceful degradation» has it's drawbacks as well. It is somewhat more complicated to add in "old technology" to a "new technology" project, rather than building "new technology" on top of "old technology" like «progressive enhancement» does it. But, as time goes by, a «progressive enhancement» approach will have more and more of it's foundation deprecated, while the root building blocks of a «graceful degradation» based project will become more and more relevant.Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com1tag:blogger.com,1999:blog-7239447129918882627.post-23981428082216039742010-12-28T22:47:00.001+01:002011-01-02T14:28:44.500+01:00Web-apps vs Native-apps<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.nerdstickers.net/wp-content/uploads/2010/08/fight-cartoon.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="188" src="http://www.nerdstickers.net/wp-content/uploads/2010/08/fight-cartoon.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div>There is a world, a nerdy world occupied by people living in a private bubble called "IT". In this world "new" things are created, things that "ordinary" people couldn't care less about until they are publicized and popularized. Things like Facebook, Twitter, the iPad, gMail, the AppStore and the Internet are things created by the people in this nerdy world. Right now an imagined war is raging in this world, a war between the "by god we will cram everything into a browser" people and the "browsers are cool but slow" people. I'm of course talking about web-apps vs native-apps, or Google vs Apple as some have come to believe. So, is there a war? And who's winning?<br />
<br />
When contemplating the differences inherently present in the not so wide crevasse between web-apps and native apps there are four main areas I want to examine:<br />
<br />
<ol><li>Performance</li>
<li>Accessibility</li>
<li>Data persistence and security</li>
<li>The browser</li>
</ol><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6XwHLhHrfrfuqKxOJjWtUz7H3_T4Km36AIpFsvF-GTUGn7JhdxyTe3uPguraUjBxEVj19nXipvVXFlTqtZ3MI8xhZ-4_zwevk8UYqjiv_TFpDCd94rdDXX71FCtBlUxPF_VhVFJCaocY/s1600/dt-improved-performance.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6XwHLhHrfrfuqKxOJjWtUz7H3_T4Km36AIpFsvF-GTUGn7JhdxyTe3uPguraUjBxEVj19nXipvVXFlTqtZ3MI8xhZ-4_zwevk8UYqjiv_TFpDCd94rdDXX71FCtBlUxPF_VhVFJCaocY/s200/dt-improved-performance.png" width="200" /></a></div><div><b>Performance</b></div><div>The first thing that springs to mind when taking the classical approach to this age long tiresome debate is the issue of performance. Native apps perform better than web-apps, hence the end user gets a smoother and better experience when using the app. This is true, in most cases. However, performance is more than just the smoothness of animations and the speed of which data is read. Consider the process of installing Adobe Photoshop on your trusty Windows laptop, then activating it, then figuring out how to navigate the god awful interface just to adjust the contrast of an image. Compare that workflow to opening the image with <a href="http://www.picnik.com/">Picnik</a> and the choice is pretty clear. Web-apps rule! But, wait. What if you want to edit the movie you shot during the holiday with your FlipMino HD, can you do that in a web-app? Well, sort of, with services like <a href="http://jaycut.com/">JayCut</a> and the likes. However, you will get a much better result using iMovie, which is already on you Mac. What about Skype, code compiling, 3D games and so on..? To make a long story short, native apps will outperform web-apps when it comes to pure performance and as long as web-apps are based on a document oriented language (HTML). It will always be a catchup game for web-apps. But, web-apps have another kind of performance advantage, accessibility.</div><div><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.ehaus.co.uk/images/accessibility_280.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="http://www.ehaus.co.uk/images/accessibility_280.png" width="200" /></a></div><div><b>Accessibility</b></div><div>A web-app is always up to date, most of them are easy to use, requires no installation and can be used from almost any computer. That is, except when you're not connected to a network. A statement with modifications indeed, some web-apps do work when in offline mode as well, however a pure offline web-app would be pretty pointless. Consider Google Docs versus Microsoft Office. If you're an author (a brave one) you might want to use MS Word, or if you need some crazy ass pivot tables or other super advanced stuff you would perhaps also need MS Excel. However if you just want to calculate stuff, create and produce formatted text, spreadsheets and presentations, Google Docs is far superior to MS Office. Oh, have you tried to collaborate in real time on a MS Word document, doesn't work does it?! Also, Google Docs keeps your documents on the server so you can access them from anywhere and they are always backed up. Does it work offline, well, not yet.</div><div><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG8qbmvVcldZzz0Q_sdDZE4Fbbkp0w3u2thcBf8Rt5rt2TUMCjNQzzAF0wz4bNbBV0j0EGFeiuaRlbzYFMIMD04CabxdsHyGskYwG0fthBzfsTsTX986j6isccJ2wFzYkmaL3yTadXO2Q/s1600/network-security-lock.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG8qbmvVcldZzz0Q_sdDZE4Fbbkp0w3u2thcBf8Rt5rt2TUMCjNQzzAF0wz4bNbBV0j0EGFeiuaRlbzYFMIMD04CabxdsHyGskYwG0fthBzfsTsTX986j6isccJ2wFzYkmaL3yTadXO2Q/s200/network-security-lock.png" width="200" /></a></div><div><b>Data persistence and security</b></div><div>With a native-app your data is always available to you, online or offline, provided that your computer is with you of course, or that you have synced the data to the cloud. What happens if (God forbid) your house (containing your laptop) is leveled by aliens? Where did all your native-app data go? It's history! Your e-mail and Google Docs data is safe at Google. That is, if you are okay with Google searching through your e-mails and documents in order to give you targeted advertisements? And what happens if, say you have saved all your links and bookmarks at a cloud service (lets call it Delicious) and then out of the blue Yahoo! suddenly decides to fire all the people working at that service and let it die a slow death. What about all those years worth of bookmarks then? This is somewhat complicated isn't it?</div><div><br />
</div><div class="separator" style="clear: both; text-align: center;"></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAcx-jlOFqctdRmSCh3X-hUELlSqXmaZmxmXQngX8ihuKrVJiyFc_IIy2FX4f1heHDgkP11BYFlYmLeRsD4qrqt1Aeqi4k5Dxv3-gbYx8UcAk65gvqDCPRjE2lRA_8CWj_XHUmzH-nXL4/s1600/google-chrome-store.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAcx-jlOFqctdRmSCh3X-hUELlSqXmaZmxmXQngX8ihuKrVJiyFc_IIy2FX4f1heHDgkP11BYFlYmLeRsD4qrqt1Aeqi4k5Dxv3-gbYx8UcAk65gvqDCPRjE2lRA_8CWj_XHUmzH-nXL4/s200/google-chrome-store.png" width="200" /></a></div><div><b>The browser</b></div><div>How awesome do you think it would be to play Halo: Reach in Google Chrome? Not so much? What about programming a movie-editor that has to work within the browser sandbox and is only allowed to cache 10MB of data, how would that go down you think? It wouldn't you say? Last one: Let's say we want to persuade ReSpawn Studios or Epic Games to work with WebGL on an unknown amount of browsers and computers instead of writing their engines based directly on a familiar platform. No dice? This is because the browser isn't a gaming platform, it isn't a good platform for handling a lots of files or large files. But, it does add another layer of security and it make everything accessible everywhere, plus if you're using Facebook and gMail what more do you need.. The average time a user spends in a web-page is about 10 seconds, this makes the "browser experience" kinda ..volatile..and short lived. Native app sessions are more persistent and have a longer lifespan, hence more suitable for playing games, editing movies and so on. The browser can do many things, not everything and yes, native apps will continue to be perform better for some time.</div><div><br />
</div><div>There is no war. The browser with it's web-apps is an awesome platform for some things, just as native apps do better on other things. I for one enjoy both web-apps and native-apps and will continue to do so for a long time I suspect.</div>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-80759346472588057382010-10-11T21:46:00.004+02:002010-12-17T07:00:52.853+01:00Scrolling a div on multitouch devices using JavaScript<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEEtpAUsVw1PUCihHYQlyupb0QC8nOmv-BCqoGx6ICdEDo16wJex6lTsOOUt7Ix8PomP8k_lfjQ7xyb4gEQTy7RE_GjbdGSYUgUeOrTr8myIjcshoe85jzqnaf7zR_pUqUhyphenhyphenyGrDY2aFU/s1600/Screen+shot+2010-10-11+at+21.16.51.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEEtpAUsVw1PUCihHYQlyupb0QC8nOmv-BCqoGx6ICdEDo16wJex6lTsOOUt7Ix8PomP8k_lfjQ7xyb4gEQTy7RE_GjbdGSYUgUeOrTr8myIjcshoe85jzqnaf7zR_pUqUhyphenhyphenyGrDY2aFU/s200/Screen+shot+2010-10-11+at+21.16.51.png" width="107" /></a></div>With the emergence of touch devices and the slow but steady tendency of replacing the mouse as an input device, this leaves us with fingers. Both the iOS platform and the Android platform sports APIs for dealing with touches from fingers, for native apps that is. But what about web-apps? Enter the <a href="http://en.wikipedia.org/wiki/DOM_events#Touch_events">JavaScript touch DOM events.</a> In this post I'll discuss how to use the touch events to scroll a container (a div) using a finger, e.g. on an iPhone.<br />
<br />
<b>What you'll need</b><br />
First of all you need a touch device or a simulator like the iPhone simulator to test your code. The code itself can be written in any text editor, however it is recommended to use an editor with a build in debugger or a test environment that supports debugging JavaScript touch events. You might be thinking that <a href="http://getfirebug.com/">Firebug</a> or <a href="http://webkit.org/blog/61/introducing-drosera/">Drosera</a> is great for debugging, but how exactly would you trigger the touch events in your desktop browser? Well, you can't. This is why I'm using <a href="http://en.wikipedia.org/wiki/Dashcode">Dashcode</a> from the iOS SDK for my JavaScript coding. More on using Dashcode in a later post.<br />
<i>Note that this code is written for WebKit based browsers, but should work in principle on other touch browsers as well.</i><br />
<br />
<b>The HTML</b><br />
<div><code> <div id="holder"><br />
<div class="content"><br />
your content here<br />
</div><br />
</div><br />
</code><br />
<br />
Notice that the content is inside of a div within the holder div, this is because you can't scroll the div in which the touch event is attached to.<br />
<br />
<b>The CSS</b><br />
<code><br />
#holder{<br />
width: 300px;<br />
height: 200px;<br />
background-color: blue;<br />
-webkit-box-shadow: 3px 3px 5px #000;<br />
padding: 10px;<br />
}<br />
<br />
#holder div{<br />
width:100%;<br />
height:100%;<br />
color: white;<br />
overflow: auto;<br />
-webkit-user-select: none;<br />
}</code><br />
<br />
Not much revolutionary here, but do note that we set the "overflow" property to auto on the content div, not the holder itself. Also, we set the "-webkit-user-select" to "none" on the content div, thereby preventing the user of selecting the content. This is optional.<br />
<br />
<b>The JavaScript</b><br />
There are three main touch events:<br />
<ul><li>touchstart - Called when a finger touches the listening container (finger down)</li>
<li>touchmove - Called repeatedly when a finger moves (finger down and moving)</li>
<li>touchend - Called when a finger leaves the listening container (finger up)</li>
</ul><div>Each of these methods gives us an event with a <u>touches</u> array. Remember, there might be more than one finger since these APIs are made to handle multitouch devices. To get a hold of the vertical position of one finger you would query the <u>touches</u> array for one finger and get it's <u>pageY</u> property, like this: <code>event.touches[0].pageY</code></div><div><br />
From this we can calculate and set the scrollTop property of the content container. But, wait! If you try this the rest of the page will also scroll, not what we wanted. The reason why this happens is because the touch event bubbles all the way up to the window, making the browser think it needs to scroll the window because you have dragged your finger on it. We need to tell the event to stop bubbling, we will handle the event ourselves. We do this by calling: <code>event.preventDefault()</code><br />
<br />
The complete JavaScript code will then look something like this:<br />
<br />
<code>var startPos;<br />
function init()<br />
{<br />
var scrollArea = document.getElementById('holder');<br />
scrollArea.addEventListener('touchstart', function(event){<br />
touchstartHandler(event);<br />
}, false);<br />
<br />
scrollArea.addEventListener('touchmove', function(event){<br />
touchmoveHandler(event);<br />
}, false);<br />
<br />
scrollArea.addEventListener('touchend', function(event){<br />
touchendHandler(event);<br />
}, false);<br />
}<br />
<br />
function touchstartHandler(e)<br />
{<br />
startPos = e.touches[0].pageY;<br />
}<br />
<br />
function touchmoveHandler(e)<br />
{<br />
var touch = e.touches[0];<br />
var targetBox = e.currentTarget.getElementsByTagName("div")[0];<br />
e.preventDefault();<br />
<br />
var fingerMoved = startPos - touch.pageY;<br />
startPos = touch.pageY;<br />
<br />
targetBox.scrollTop = targetBox.scrollTop + fingerMoved;<br />
<br />
}</code><br />
This is just a simple example, but it's something you'll probably end up using a lot. Speaking of...<br />
<br />
<b>When should you override the default window scroll</b><br />
On an iPhone there is not as much need for this method as you'll probably scroll the entire screen in most cases anyway. However, the iPad is a different story. Take a look at the iPad version of gMail created by Google. They are using this method with success, and they have added inertia scrolling as well. This can be accomplished using the last touch event we did not implement, <u>touchend.</u> Maybe more on this in a later post. Anyway, you should use you own scrolling when it's appropriate to scroll only a part of the app, like a spilt view list or something like that.<br />
<div></div></div></div>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com5tag:blogger.com,1999:blog-7239447129918882627.post-32320030047915232482010-10-02T15:24:00.000+02:002010-10-02T15:24:25.388+02:00Downscaling images in Flash applications<div class="separator" style="clear: both; text-align: center;"><a href="http://upload.wikimedia.org/wikipedia/commons/1/1d/Scaling.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="148" src="http://upload.wikimedia.org/wikipedia/commons/1/1d/Scaling.png" width="200" /></a></div>The other day I ended up in an interesting discussion regarding how to downscale a large image in a Flash based application. What we figured out was that even though the FlashPlayer can do <a href="http://en.wikipedia.org/wiki/Bilinear_interpolation">bilinear</a> smoothing on scaled images automatically, this will fail when the scaling factor is more than 2 times of the source image. Hence a custom method is needed.<br />
<br />
<b>The simple approach (scaling down less than 2 times the size)</b><br />
If the loaded image is to be scaled less than 2 times (400 -> 200) simply use the build in "<a href="http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/Bitmap.html#smoothing">smoothing</a>" property of the <a href="http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/Bitmap.html">Bitmap Clas</a>s. This can be set directly on the Bitmap itself or via different DisplayElements such as the mx:Image in Flex. If you set this property to true the Bitmap will use bilinear scaling, achieving quite good results.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.blogger.com/goog_912792194"><img border="0" height="200" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Bilin2.png" width="199" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><a href="http://en.wikipedia.org/wiki/Bilinear_interpolation">Grayscale bilinear interpolation</a></td></tr>
</tbody></table>Now, if you need to do actual resampling of an image, in other words create a new smaller image, then you need to do this manually using the "<a href="http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/BitmapData.html#draw()">draw()</a>" method of the <a href="http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/display/BitmapData.html">BitmapData Class</a>. Use the bitmapData.draw() method and set the "smoothing" property to true. This will give you the same result as setting the smoothing property on an Bitmap container, however it uses less memory as only the pixels for the resulting image is stored (if you remember to dispose of the original data!).<br />
<br />
<b>Scaling down more than 2 times</b><br />
Let's say that you have an image that is quite large and you want to create a thumbnail from it. A thumbnail is often way smaller than 2 times smaller than the original image. It would be quite nice to use the above method to just scale the image, or better resample the image with the "smoothing" property set to true. However, if you try to do this the FlashPlayer will simply fail and default back to using the <a href="http://tech-algorithm.com/articles/nearest-neighbor-image-scaling/">"nearest neighbor</a>" algorithm. If you try it you'll soon discover that this will give you a horrible result.<br />
<br />
What you'll need to do in this case is to do an iterative or recursive resampling of the image at hand. In layman terms this means resampling the image several times, each time no more than 2 times downscaling factor. You could call this a multi pass resampler (actually it would be a multi-multi pass resampling as the draw() method is also multi pass). You would still use the build in "BitmapData.draw()" method to accomplish this, you only divide the work into multiple jobs. This will give you a much better result. Note that in my experience, function calls in ActionsScript 3 are quite expensive, hence a iterative approach would maybe be preferable to a recursive one.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><b>Using PixelBender</b><br />
If you have decided to go for the manual approach of resampling the picture, you can use a PixelBender shader to do the job. In this case the actual resampling will be a lot faster (as the PB language is based on C), however applying the PB shader and passing the image back and forth takes time. See the speed section..<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><b>Combining the two</b><br />
So, what if you have an application and you don't know in advance the downscale factor. Well, then you'll need to use both of the approaches like so:<br />
<br />
<ol><li>Calculate the scale factor</li>
<li>If the scale factor is less than 2, set "smoothing" to true on the container or do a singe pass resampling.</li>
<li>If the scale factor is more than two, use the multi pass scaling approach. And set the "smoothing" property of the container to false (else it will be blurry).</li>
</ol><div><div class="separator" style="clear: both; text-align: center;"><a href="http://www.aykew.com/images/aboutwork/speed.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="144" src="http://www.aykew.com/images/aboutwork/speed.jpg" width="200" /></a></div><b>What about speed?</b></div><div>Let's say that you have an image that is 1200 x 1200 pixels and you're resampling it to 200 x 200. This is a 6 times resample and will look like ass using only the "smoothing" property, but it is faster.<br />
<br />
Let look at some hard results. In this test we see how much time is used extra compared to no "nearest neighbor" scaling (default in Bitmaps if smoothing is off).<br />
<br />
</div><div><table border="1"><tbody>
<tr><th>Method</th><th>Time in ms</th></tr>
<tr><td>Smoothing property on</td><td><div style="text-align: right;">0 ms</div></td></tr>
<tr><td>Multi pass resample</td><td><div style="text-align: right;">9 ms</div></td></tr>
<tr><td>Multi pass PixelBender</td><td><div style="text-align: right;">32 ms</div></td></tr>
</tbody></table></div><div>Using the smoothing property takes no extra time, because it fails and defaults back to nearest neighbor. The other two are both pretty fast, however even though the PB algorithm is way faster than the others, we see that the applying of the shader eats a lot of time, thereby making the multi pass resampler method the way to go on a large rescaling operation.</div>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com2tag:blogger.com,1999:blog-7239447129918882627.post-77502837529247027012010-07-05T20:09:00.002+02:002010-07-05T20:16:58.731+02:00Shifting the attention - facing forward.<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPsZQhprf9NebovCCo4-0UaM4cKDoWLiTBGDfbCAsUFiqcf3_6cPqPpZ2dd9s8VqbFtCEjwPa2Ual0S5ynJQHt2a9Sr9cnr9ZdPSPYYJGZT9GYDAnChP4viag6kj-0N_cRaIHkZ2Fy5oQ/s1600/html5.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPsZQhprf9NebovCCo4-0UaM4cKDoWLiTBGDfbCAsUFiqcf3_6cPqPpZ2dd9s8VqbFtCEjwPa2Ual0S5ynJQHt2a9Sr9cnr9ZdPSPYYJGZT9GYDAnChP4viag6kj-0N_cRaIHkZ2Fy5oQ/s320/html5.png" /></a></div><span class="Apple-style-span" style="font-size: small;">“</span><i><span class="Apple-style-span" style="font-size: small;">Innovation is the ability to see change as an opportunity - not a threat</span></i><span class="Apple-style-span" style="font-size: small;">”. - <i>Unknown</i></span><br />
<br />
This is not where I'm going to announce to the world that I'm leaving the FlashPlayer platform behind all together. Nor is this where I'll tell you to forget everything you know, gather you wits about you and start over. No, this is where I'll tell you what I've learned, how I've learned this and why this is.<br />
<br />
Like Borland Delphi back in the days, the Adobe FlashPlayer architecture is dying without itself being aware of it. It's not because Flash content is evil, nor because the FlashPlayer is particularity crappy. Still, many sites, like <a href="http://apiblog.youtube.com/2010/06/flash-and-html5-tag.html">YouTube are heavily dependent</a> on the FlashPlayer in order to display their content. This will be true for quite some time. However, at the same time, all these sites still depending on the FlashPlayer do not express enthusiasm for it, it's seen more as a necessary evil in order to get the job done while we are waiting for something better. Well, change has come to the interwebs..and it's called HTML 5.<br />
<br />
<a href="http://dev.w3.org/html5/spec/Overview.html">HTML 5</a> is acctually a standard being developed by <a href="http://www.w3.org/">the World Wide Web Consortium</a>. Like HTML 4 it's a specification used by browser vendors to integrate the support into their browsers. This by it self means that individual browser vendors are responsible for the performance of HTML content in their browsers, effectively launching a race to be the fastest browser. This is a win for HTML 5 over Flash, seeing as Flash Player has no real competitors, because Adobe is the sole vendor. However, HTML 5 and it's companions CSS 3 and JavaScript cannot accomplish the same as the content you create using Adobe Flash, or so many people think. Actually, it can. Both 2D animations, 3D animations, advanced text layout and so on is readily available using HTML 5. So is advanced interactions. What HTML 5 does not have, that Flash do have, is an advanced authoring tool. Using HTML 5 may require more development skills, longer production time and more work to achieve the same result as using Flash authoring, today. This will change in time as HTML 5 skills grow more common amongst web-developers and the marked for great tools enlarges.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZHnGFq_TtMY9m4pQMf1nQww71yoq9UHqTmiQG4oOBqUYdOln_W52ReK0bRKWeZJELJWKPxMI772-7udxu7ldcwDpN8KddVmfIuIJ06PNHKelXz6d-3EjjRgU0Sq1YIGvOiVziYu8ItA/s1600/ipad.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKZHnGFq_TtMY9m4pQMf1nQww71yoq9UHqTmiQG4oOBqUYdOln_W52ReK0bRKWeZJELJWKPxMI772-7udxu7ldcwDpN8KddVmfIuIJ06PNHKelXz6d-3EjjRgU0Sq1YIGvOiVziYu8ItA/s200/ipad.png" width="130" /></a></div><i><span class="Apple-style-span" style="font-size: small;">“Innovation distinguishes between a leader and a follower.” - Steve Jobs</span></i><br />
<br />
Let's not forget the devices. The iPad, the iPhone, Android devices and the Google Chrome OS. These are the platforms of the future, the PC is not. Yeah, PCs will still be around, we as developers will still adhere like superglue to our Macs and Chrome computers. But, the normal users, aka. "most people" will not. Flash belongs to the PC era, HTML 5 is build for the touchscreen generation. This is kinda hard to see if you don't look closely, but think about it. How many iPads and iPhones does Apple sell? A lot! How many Android devices are there? A lot! Granted, Android phones do have a FlashPlayer, but have you tried it? Yes, it really sucks. And that is the most devastating blow to the FlashPlayer, the experience on future devices sucks or it simply isn't supported like on iOS devices.<br />
<br />
Change is one of the most difficult things for humans to endure. We don't play well with it at all, but sometimes it's for the better. Remember, there is nothing wrong with plugin based technologies like FlashPlayer or Silverlight, like there was nothing wrong with the horse and carriage. But, now we drive cars, even if they can't do everything horses can do. This does not, however, mean that we hate horses, does it?<br />
<br />
Resulting from my contemplation is an understanding that my attention will focus on the utilization of standard based technologies in the foreseeable future. I believe HTML 5 and all its companions will be the way of future web-based solutions. Flash is not dead, will perhaps never die, but if you're starting out today as a greenhorn developer, go for the future. And if you are a seasoned web-developer like myself, embrace this opportunity to learn new things, to start from "scratch".<br />
<br />
Some great HTML 5 demos can be found here:<br />
<br />
<ul><li><a href="http://developer.apple.com/safaridemos/">Safari demos from Apple</a></li>
<li><a href="http://html5demos.com/">HTML 5 Demo</a></li>
<li><a href="http://www.youtube.com/html5">YouTube HTML 5 version</a></li>
<li><a href="http://slides.html5rocks.com/#slide1">HTML 5 Presentation</a></li>
</ul>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com0tag:blogger.com,1999:blog-7239447129918882627.post-78652601932097579892010-02-21T20:54:00.000+01:002010-02-21T20:54:59.714+01:00Do we need Flash anyway? Apple says hell no!Unless you have been living in a box for the last couple of months or so, you're probably noticed that there's somewhat of a controversy dealing in the subject of Adobe Flash and Apple Inc.'s not so new policy to not support this widely used content type in their mobile devices.<br />
In short, Apple cry fault on several things like CPU usage and instability, using these as the foundation for it's "no Flash content on our devices" policy. But, is it really that simple? Here's my take on this soon to be "greek tragedy".<br />
<b><br />
</b><br />
<span class="Apple-style-span" style="font-weight: bold;">What is Flash?</span><br />
First of all, Flash is a type of media content, like images, movies and so on. Flash by itself doesn't do diddly-squat, it's just a description and a file format. In order to view Flash content you'll need an interpreter, in others words a player. What Apple is calling "the great evil" is (hopefully) the Adobe FlashPlayer, not the content type which is actually Flash.<br />
<b><br />
</b><br />
<span class="Apple-style-span" style="font-weight: bold;">Is Flash crashing my browser?</span><br />
No! As described above, Flash all by itself can't do anything. If anything related to Flash is crashing your browser, it is the Adobe FlashPlayer. So you may ask, is the FlashPlayer the reason (most of the time) my browser is suddenly crashing? In my opinion it probably is. The Adobe FlashPlayer is quite unstable and buggy and slow. Why? Read on..<br />
<b><br />
</b><br />
<span class="Apple-style-span" style="font-weight: bold;">Is the FlashPlayer a "CPU hog"?</span><br />
Yes it is. The Adobe FlashPlayer runs a constant loop of so called frames, driving animation, UI and so on. This will create a constant load on the CPU, because the content can change without reloading the webpage holding the Flash content. In contrast, HTML will create a heavy CPU load when initially loading the content and then it becomes static, thereby not using any (almost) CPU cycles. So, what if you where able to create the same content as you can show in the FlashPlayer in say.. HTML and JavaScript. What do you think would happen to the CPU load of that HTML page then? Of course, it would use more CPU cycles.<br />
So, Adobes FlashPlayer is slow, no doubt about it, but this does not make Flash itself a "CPU hog" or anything like that. If Apple wants a faster FlashPlayer.. write one!<br />
<br />
<b>Will Flash die, what might prevent it?</b><br />
Flash will die, or evolve into something else, eventually. But, it won't happen tomorrow, or the next day. Event though Apple does not support Flash in the iPhone and the iPad, almost any other device does or will support it. However, if you're a smart developer you'll use this time to widen your skill set beyond the Flash platform.<br />
<br />
<i>Development time and cost</i><br />
The time spend creating an online application or website will in many cases be the deciding factor in a project, unless you're Google or Apple that is. Using the Flash platform compared to JavaScript/HTML solutions leaves the latter far behind in the dust when it breaks down to actual production time. This factor will no doubt change with the advent of advanced frameworks like JQuery and SproutCore. But still, anything you can do in JS and HTML, Flash can do better and faster from an time and design standpoint... today.<br />
<br />
<i>Dropping legacy support is the way of making a more stable player</i><br />
One of the biggest problems with the Adobe FlashPlayer as I see it, is it's reluctance to get rid of old and bad ways of creating content. If Adobe where to drop support for the old player model, supporting ActionScript 2 and Flash 8 and older, I'll bet money that Flash content around the web would run faster, smoother and crash way less. If they are willing to do this I do believe Flash content might have a future, if not it will be kept alive by the need for banner ads, for a while.<br />
<br />
<b>Why doesn't Apple support Flash content?</b><br />
Well, Steve Jobs allegedly stated that Apple wasn't supporting Flash content on the iPhone and the iPad for reasons dealing in instability, performance and generally bad user experience. If that's all, why not support Microsoft Silverlight?<br />
Flash could be a competitor for Apple, both in the apps section of their business model and in the media consumption part (buying videos from the web (e.g. Hulu) and not the iTunes Store).<br />
This is why, in my opinion, Apple will not support Flash content on their mobile devices. And really, if you think of it, is is such a problem? If you depend on Flash driven web content, don't buy Apple hardware. For me, being both an Apple "fan" and a Flash developer, I don't see the need for Flash content on mobile devices. No matter how you word it, the iPhone and the iPad won't give you the entire web..Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com1tag:blogger.com,1999:blog-7239447129918882627.post-4531415365721518462010-02-13T19:00:00.004+01:002010-06-03T20:29:05.710+02:00Screencast # 3 - iPhone web app Twitter viewerIn this Screencast I create a really simple iPhone Web Application using DashCode, one of the tools provided trough the <a href="http://developer.apple.com/iphone/">iPhone Developer Tools</a>.<br />
I'll show you how to create a simple Twitter viewer, getting started using lists and how to use value transformers in DashCode.<br />
<br />
<object width="420" height="236"><param name="movie" value="http://www.youtube.com/v/s-vE0pJRYGo&hl=en_US&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/s-vE0pJRYGo&hl=en_US&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="420" height="236"></embed></object><br />
<br />
<a href="https://docs.google.com/leaf?id=0B5D35v8KWeRWYzhkYzMwODYtZjUzYy00OTgxLWE2OTMtZDljYWRhNmJjN2Jm&hl=en">Download DashCode Project</a>Anonymoushttp://www.blogger.com/profile/16103353311505266262noreply@blogger.com3