Archive for the ‘JavaScript’ Category

Mobile web developers: let users adjust font size

Many consumer web sites have done a fantastic job of deploying mobile web versions of their sites. However, over the last year I have heard an increasing number of complaints about websites specifically designed for mobile: you simply can’t adjust the font size. Depending on the device’s screen size, this can potentially cause painful choices: either deal with (usually) tiny font sizes and struggle to read content, or go to the full web site and be relegated to panning, zooming and rotating between portrait and landscape mode to try and fit as much content as possible onto a tiny screen.

To me, the solution is easy: allow users to set their own font-size. Here’s an example of settings I’m referring to, specifically setting the viewport’s user-scalable property to ‘no’ is what’s causing the problem:

<meta name="viewport" content="width=device-width, user-scalable=no">

There are certainly use cases, such as mapping applications, were you might want to prevent user scaling because it will affect other components inside the application.  However, if there aren’t any components affected by pinch zoom then you most likely can set the user-scalable property to yes, or simply omit the property.

My first suggestion is provide users with the ability to adjust the font size.  Here is an example that will let the user adjust font size for a specific DIV:

<meta name="viewport" content="width=device-width">
<script>
    var up = 1;
    var down = -1;
    var elementSize = document.getElementById(“someDiv”) .style.fontSize;

    function increaseFont(){
        up++;
        elementSize = up + “px”;
    }

    function decreaseFont(){
        down--;
        elementSize = down + “px”;
    }

    function resetFont(){
        elementSize = “14px”;
    }
</script>

Another option is to combine the above suggestion with media queries to adjust font-size automatically based on screen size, pixel ratio and/or min-resolution. Here is one example:


@media
(-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
    body{
        font-size: 16px;
    }
}

Other examples of media queries can be found here: css-tricks.com.

Tags: , , ,
Posted in JavaScript, Mobile | 2 Comments »

Easily find image type in JavaScript

There are two easy ways to determine an image’s type using JavaScript: using an html Input tag with a type file, and using the DataView API. I’ve put together a github repository that contains all the code shown below. The sample app detects PNG, GIF, JPEG and BMP: https://github.com/andygup/DetectImageType.js

Here’s how to do it with an Input tag:

    <input type="file" id="fileInput" name="file"/>
    <script>
    var fileInput = document.getElementById("fileInput");
    fileInput.addEventListener("change",function(event){
        document.getElementById("name").innerHTML = "NAME: " + event.target.files[0].name;
        document.getElementById("type").innerHTML = "TYPE: " + event.target.files[0].type;
        document.getElementById("size").innerHTML = "SIZE: " + event.target.files[0].size;
    });
    </script>

And, here’s how to do it with the DataView API. The concept is to retrieve the image via an HTTP request with the response type set to “arraybuffer.” And then extract the hexadecimal signature or magic number of the image type. I’ve taken the liberty of only reading the first 2 bytes to get the magic numbers in my example. If you need more precision here’s a great site to use for more information on image signatures: http://www.filesignatures.net/index.php?page=search

  function getImageType(arrayBuffer){
        var type = "";
        var dv = new DataView(arrayBuffer,0,5);
        var nume1 = dv.getUint8(0,true);
        var nume2 = dv.getUint8(1,true);
        var hex = nume1.toString(16) + nume2.toString(16) ;

        switch(hex){
            case "8950":
                type = "image/png";
                break;
            case "4749":
                type = "image/gif";
                break;
            case "424d":
                type = "image/bmp";
                break;
            case "ffd8":
                type = "image/jpeg";
                break;
            default:
                type = null;
                break;
        }
        return type;
    }

The DataView API has really good browser support. The only issues you’ll have, not surprisingly, are with IE 8 and 9. For more info on support of the DataView API go here: http://caniuse.com/#search=dataview

Tags: , , ,
Posted in JavaScript | No Comments »

Using async tokens with JavaScript FileReader

The JavaScript FileReader is a very powerful, efficient and asynchronous way to read the binary content of files or Blobs. Because it’s asynchronous, if you are doing high-volume, in-memory processing there is no guarantee as to the order in which reading events are completed. This can be a challenge if you have a requirement to associate some additional unique information with each file or Blob and persist it all the way thru to the end of the process. The good news is there is an easy way to do this using async tokens.

Using an asynchronous token means you can assign a unique Object, Number or String to each FileReader operation. Once you do that, the order in which the results are returned no longer matters. When each read operation completes you can simply retrieve the token uniquely associated with the original file or Blob.  There really isn’t any magic. Here is a snippet of the coding pattern. You can test out a complete example on github.


function parse(blob,token,callback){

    // Always create a new instance of FileReader every time.
    var reader = new FileReader();

    // Attach the token as a property to the FileReader Object.
    reader.token = token;

    reader.onerror = function (event) {
        console.error(new Error(event.target.error.code).stack);
    }

    reader.onloadend = function (evt) {
        if(this.token != undefined){

            // The reader operation is complete.
            // Now we can retrieve the unique token associated
            // with this instance of FileReader.
            callback(this.result,this.token);
        }
    };
    reader.readAsBinaryString(blob);
}

Note, it is a very bad practice to simply associate the FileReader result object with the token being passed into the parse() function’s closure. Because the results from the onloadend events can be returned in any order, each parsed result could end up being assigned the wrong token. This is an easy mistake to make and it can seriously corrupt your data.

Tags: , , , , ,
Posted in JavaScript | No Comments »

Fastest way to find an item in a JavaScript Array

There are many different ways to find an item in a JavaScript array. With a little bit of testing and tinkering, I found some methodologies were faster than others by close to 200%!

I’ve been doing some performance tweaking on a very CPU intensive JavaScript application and I needed really fast in-memory searching on a temporary array before writing that data to IndexedDB. So I did some testing to decide on an approach with the best search times. My objective was to coax out every last micro-ounce of performance. The tests were completed using a pure JavaScript methodology, and no third party libraries were used, so that I could see exactly what was going on in the code.

I looked at five ways to parse what I’ll call a static Array. This is an array that once it is written you aren’t going to add anything new too it, you simply access its data as needed and when you are done you delete it.

  1. Seek. Create an index Array based exactly on the primary Array. It only contains names or unique ids in the same exact order as the primary. Then search for indexArray.indexOf(“some unique id”) and apply that integer against the primary Array, for example primaryArray[17] to get your result. If this doesn’t make sense take a look at code in my JSFiddle.
  2. Loop. Loop thru every element until I find the matching item, then break out of the loop. This pattern should be the most familiar to everyone.
  3. Filter. Use Array.prototype.filter.
  4. Some. Use Array.prototype.Some.
  5. Object. Create an Object and access it’s key/value pairs directly using an Object pattern such as parsedImage.image1 or parseImage["image1"]. It’s not an Array, per se, but it works with the static access pattern that I need.

I used the Performance Interface to get high precision, sub-millisecond numbers needed for this test. Note, this Interface only works on Chrome 20 and 24+, Firefox 15+ and IE 10. It won’t run on Safari or Chrome on iOS. I bolted in a shim so you can also run these tests on your iPad or iPhone.

My JSFiddle app creates an Array containing many base64 images and then loops thru runs hundreds of tests against it using the five approaches. It performs a random seek on the Array, or Object during each iteration. The offers a better reflection of how the array parse algorithm would work under production conditions. After the loops are finished, it then spits out an average completion time for each approaches.

The results are very interesting in terms of which approach is more efficient. Now, I understand in a typical application you might only loop an Array a few times. In those cases a tenth or even hundredth of a millisecond may not really matter. However if you are doing hundreds or even thousands of manipulations repetitively, then having the most efficient algorithm will start to pay off for your app performance.

Here are some of the test results based on 300 random array seeks against a decent size array that contained 300 elements. It’s actually the same base64 image copied into all 300 elements. You can tweak the JSFiddle and experiment with different size arrays and number of test loops. I saw similar performance between Firefox 29 and Chrome 34 on my MacBook Pro as well as on Windows. Approach #1 SEEK seems to be consistently the fastest on Arrays and Object is by far the fastest of any of the approaches:

OBJECT Average 0.0005933333522989415* (Fastest.~191% less time than LOOP)
SEEK Average 0.0012766665895469487 (181% less time than LOOP)
SOME Average 0.010226666696932321
FILTER Average 0.019943333354603965
LOOP Average 0.02598666658741422 (Slowest)

————–

OBJECT Average 0.0006066666883028423* (Fastest.~191% less time than slowest)
SEEK Average 0.0012900000368244945 (181% less time than LOOP)
SOME Average 0.012076666820018242
FILTER Average 0.020773333349303962
LOOP Average 0.026383333122745777 (Slowest)

As for testing on Android, I used my Android Nexus 4 running 4.4.2. It’s interesting to note that the OBJECT approach was still the fastest, however the LOOP approach (Approach #2) was consistently dead last.

On my iPad 3 Retina using both Safari and Chrome, the OBJECT approach was also the fastest, however the FILTER (Approach #3) seemed to come in dead last.

I wasn’t able to test this on IE 10 at the time I wrote this post and ran out of time.

Conclusion

Some folks have blogged that you should never use Arrays for associative search. I think this depends on exactly what you need to do with the array, for example if you need to do things like slice(), shift() or pop() then sticking to an Array structure will make your life easier. For my requirements where I’m using a static Array pattern, it looks like using the Object pattern has a significant performance advantage. If you do need an actual Array then the SEEK pattern was a close second in terms of speed.

References:

JSFiddle Array Parse tests
Performance Interface

[Updated: May 18, 16:06, fixed incorrect info]

Tags: , , , ,
Posted in JavaScript | 2 Comments »

Calculate size of indexedDB database

IndexedDB has no built-in mechanism for calculating the size of a database. Below is a code snippet that shows how to calculate the ‘approximate’ size if you are storing strings. In my case we are storing Base64 images.

Depending on what data type you are storing here are some suggestions on how to calculate the size:

  • String. The example shown below simply uses the String.length property. You can typically get a one-to-one ratio where each character is equal to one byte. For example, if length equals 20, you can roughly assume that the size of the string is 20 bytes. However, if you have many uncommon characters in your strings those can equal 2 bytes each. For more information see this page on the Mozilla Developer Network.
  • Array. The size of an array depends on the array type and what you are storing in it. If it’s just a plain old Array of strings, such as ["a","test","something"],  you can parse the array for strings and then measure the size of each item within it as I just mentioned. If it’s a typed array you’ll have to take into account if it’s 8-bit, 16-bit, 32-bit or 64-bit. If you have numbers in your array, I believe all JavaScript numbers are 8 bytes each.
  • Blob. Access the Blob.size property.
/**
 * Provides the size of database in bytes
 * @param callback callback(size, null) or callback(null, error)
 */
var size = function(callback){
    if(this._db != null){
        var size = 0;

        var transaction = this._db.transaction(["your_db"])
            .objectStore("your_db")
            .openCursor();

        transaction.onsuccess = function(event){
            var cursor = event.target.result;
            if(cursor){
                var storedObject = cursor.value;
                var json = JSON.stringify(storedObject);
                size += json.length;
                cursor.continue();
            }
            else{
                callback(size,null);
            }
        }.bind(this);
        transaction.onerror = function(err){
            callback(null,err);
        }
    }
    else{
        callback(null,null);
    }
}

Usage

Here’s how you would use this in your application:

getSize(function(size,err){
     if(size > 0){
         console.log("Database size = " + size + " bytes");
     }
     if(err != null){
         console.log("There was a problem getting database size: " + err);
     }
}

Reference

W3C Specification for IndexedDB Database API
MDN – Blog

Tags: ,
Posted in JavaScript | 3 Comments »

What all mobile web devs should know about PhoneGap

If you already building or looking into getting started with mobile web applications you should understand the basics of PhoneGap. The name ‘PhoneGap’ is widely recognized, and perhaps more widely misunderstood.

The nudge to write this article was born out of conversations where we stumbled across concrete limitations to modern responsive JavaScript libraries such as bootstrap and jQuery. Limitations that cannot be overcome by adding more brilliant functionality because some JavaScript capabilities simply do not exist within the browser today. Furthermore, other requirements were imposed by political realities, timeframes and expectations.

That’s where PhoneGap steps in. 

So what, tell me what PhoneGap does?

PhoneGap is owned by Adobe and it has an open source top-level Apache Foundation sister project called Cordova. I won’t bore you with its long and twisted history, you can read about it here if you want.

The bottom line is PhoneGap allows you to develop JavaScript mobile applications that have access to certain aspects of the native device such as writing data to a filesystem. Your web application is wrapped within a native mobile application container that gives you JavaScript access to native operating system capabilities beyond what the browser itself is capable of doing!

By native I mean iOS Objective C, Android Java, WindowsPhone, Windows 8, Blackberry 10, Amazon Fire OS and Tizen. Your JavaScript applications runs in a chrome-less browser that gives you special hooks to the operating system. You can also submit PhoneGap applications to the AppStore, Google Play and others.

Who uses this stuff, well you may be using a PhoneGap app from one of these online stores and not even know it. To mention a few: Southwest Airlines and many others.

What limitations can PhoneGap address that responsive libraries don’t?

If your requirements call for all or most of the following items, then PhoneGap is the correct choice for your project today. That may change as HTML5 continues to rapidly grow, but for now I’m sticking with the following bullet points. Stick with me and read through all of these before starting to throw out counter arguments.

JavaScript skillz. If you are an existing JavaScript shop, then PhoneGap leverages your existing JavaScript skills to access capabilities beyond current browser functionality without the need to have an in-depth understanding of Objective C or Java.

Sure, it’s easy to say you can hire expert contractors to develop iOS and Android applications, along with UX designers and testers. But, if your budget doesn’t include the capital costs for these folks and all you have is JavaScript ninjas on staff then the choice is easy.

Or, maybe you have genius-level developers that could easily and quickly spin up on all your need to know on ObjectiveC and Java Android. If this isn’t the case, and your timeframes and budgets don’t allow for this then you’ll need a fallback plan such as PhoneGap.

Access to camera.  Yes, you can currently access the camera on some web browsers today. However, the support on mobile browsers is still inconsistent, limited or non-existent. On the other hand, native device OS’s are expected to have access to cameras If they didn’t it would be considered a serious oversight. PhoneGap provides cross-platform mobile device access to the camera.

Read/write access to SD Card. Just to reiterate, this is both read and write access to a local storage device. Certainly there is a FileReader API in plain old JavaScript, but as far as I know there isn’t a FileWriter or its equivalent yet. If you need the write access to go along with read capabilities then you should be looking at PhoneGap.

[Correction Jan. 27, 2014] I mis-wrote. The FileWriter API exists however it has limited supported across browsers: http://caniuse.com/#search=filewriter. And, examples of it’s use can be found here.

AppStore or Google Play. If you have a requirement to submit your application to the app store then PhoneGap will help you get there. There is no way today for submitting a stand-alone web application for acceptance on AppStore or Google Play. Period. Some will argue that the need for using these online application stores is going away, but that’s a non-issue if you have been directed to meet this requirement a.s.a.p. and your job depends on it. If that’s the case, then PhoneGap will be your friend.

Is there anything else I should know?

Yes…First, PhoneGap is not perfect, but then again few software projects are perfect. You will need to install and know a few things about the native IDEs you want to support. If you want to deploy Android you’ll need to install Eclipse or IntelliJ. For iOS you’ll need to install XCode. Etc. You still have to compile a native project or you can try your hand at Adobe’s PhoneGap Build, which is a cloud based build system for PhoneGap.

It is confusing that there are two projects that share a common/similar code base: PhoneGap and Cordova. Also, Cordova’s documentation has typically been more up to date that Adobe’s. If you do your research you’ll find various performance complaints and bug issues (like I just said are there any software projects that don’t have these??).  Yet, overall it’s a great starting point if you have the needs listed above, and it’s much better than trying to start from scratch given today’s dramatically shortened delivery expectations.

You can absolutely still use bootstrap, jQuery and other JavaScript libraries within PhoneGap. There are caveats, of course, related to application life-cycle issue, navigation as well as App Store and Google Play user interface acceptance guidelines.

If you want to add functionality to PhoneGap because you find some critical thing is missing that you need for your project, the good news is you can develop a custom plug-in.

Last, I should mention Titanium Studio. It also lets you leverage JavaScript skills, with the primary difference being that it converts JavaScript into native byte code rather than just displaying it in a chrome-less view.  Plus it’s comes with its own IDE and MVC Framework.  I’ve never used Titanium so I can’t judge it, however I know people who do use it successfully and love it. It’s one more thing to consider that you should be aware of.

References

Cordova Documentation

PhoneGap Documentation

PhoneGap Platform Support

Tags: , , , , , , ,
Posted in JavaScript, Mobile, PhoneGap | No Comments »